github.com/simpleiot/simpleiot@v0.18.3/frontend/public/ble.js (about)

     1  const serviceUuid = "5c1b9a0d-b5be-4a40-8f7a-66b36d0a5176";
     2  const charUptimeUuid = "fdcf0000-3fed-4ed2-84e6-04bbb9ae04d4";
     3  const charSignalUuid = "fdcf0001-3fed-4ed2-84e6-04bbb9ae04d4";
     4  const charFreeMemUuid = "fdcf0002-3fed-4ed2-84e6-04bbb9ae04d4";
     5  const charModelUuid = "fdcf0003-3fed-4ed2-84e6-04bbb9ae04d4";
     6  const charWifiSSIDUuid = "fdcf0004-3fed-4ed2-84e6-04bbb9ae04d4";
     7  const charConnectedUuid = "fdcf0005-3fed-4ed2-84e6-04bbb9ae04d4";
     8  const charSetWifiSSIDUuid = "fdcf0006-3fed-4ed2-84e6-04bbb9ae04d4";
     9  const charSetWifiPassUuid = "fdcf0007-3fed-4ed2-84e6-04bbb9ae04d4";
    10  // Const charDeviceNameUuid = "fdcf0008-3fed-4ed2-84e6-04bbb9ae04d4";
    11  const charTimerFireDurationUuid = "fdcf0009-3fed-4ed2-84e6-04bbb9ae04d4";
    12  const charTimerFireUuid = "fdcf000a-3fed-4ed2-84e6-04bbb9ae04d4";
    13  const charCurrentTimeUuid = "fdcf000b-3fed-4ed2-84e6-04bbb9ae04d4";
    14  const charTimerFireTimeUuid = "fdcf000c-3fed-4ed2-84e6-04bbb9ae04d4";
    15  const charTimerFireCountUuid = "fdcf000d-3fed-4ed2-84e6-04bbb9ae04d4";
    16  
    17  export class BLE {
    18    constructor(stateChanged) {
    19      this.resetState();
    20      this.stateChanged = stateChanged;
    21    }
    22  
    23    resetState() {
    24      this.device = null;
    25      this.server = null;
    26      this.service = null;
    27      this.uptime = 0;
    28      this.signal = 0;
    29      this.freeMem = 0;
    30      this.connected = false;
    31      this.currentTime = 0;
    32      this.timerFireCount = 0;
    33    }
    34  
    35    onDisconnected() {
    36      this.resetState();
    37      this.stateChanged();
    38    }
    39  
    40    onCurrentTimeChanged(event) {
    41      let {value} = event.target;
    42      this.currentTime = value.getUint32();
    43      this.stateChanged();
    44    }
    45  
    46    onConnectedChanged(event) {
    47      let {value} = event.target;
    48      this.connected = value.getUint8();
    49      if (this.connected) {
    50        this.connected = true;
    51      } else {
    52        this.connected = false;
    53      }
    54      console.log("onConnectedChanged: ", value.getUint8());
    55      this.stateChanged();
    56    }
    57  
    58    onUptimeChanged(event) {
    59      let {value} = event.target;
    60      this.uptime = value.getInt32();
    61    }
    62  
    63    onSignalChanged(event) {
    64      let {value} = event.target;
    65      this.signal = value.getUint8();
    66    }
    67  
    68    onFreeMemChanged(event) {
    69      let {value} = event.target;
    70      this.freeMem = value.getInt32();
    71      this.stateChanged();
    72    }
    73  
    74    onTimerFireCountChanged(event) {
    75      let {value} = event.target;
    76      this.timerFireCount = value.getInt32();
    77      this.stateChanged();
    78    }
    79  
    80    async configureWifi(config) {
    81      if (!this.device) {
    82        throw "configure GW, no device";
    83      }
    84  
    85      const charSetWifiSSID = await this.service.getCharacteristic(charSetWifiSSIDUuid);
    86      const encoder = new TextEncoder();
    87      charSetWifiSSID.writeValue(encoder.encode(config.wifiSSID));
    88  
    89      const charSetWifiPass = await this.service.getCharacteristic(charSetWifiPassUuid);
    90      charSetWifiPass.writeValue(encoder.encode(config.wifiPass));
    91    }
    92  
    93    async configureTimer(config) {
    94      if (!this.device) {
    95        throw "configure GW timer, no device";
    96      }
    97  
    98      const charTimerFireDuration = await this.service.getCharacteristic(charTimerFireDurationUuid);
    99      charTimerFireDuration.writeValue(Int32Array.of(config.fireDuration));
   100  
   101      const charCurrentTime = await this.service.getCharacteristic(charCurrentTimeUuid);
   102      let d = new Date();
   103      let n = d.getTime();
   104      let k = 1000;
   105      charCurrentTime.writeValue(Int32Array.of(n / k));
   106  
   107      let parts = config.fireTime.split(":");
   108      if (parts.length < 2) {
   109        console.log("Error parsing time");
   110        return;
   111      }
   112  
   113      let fireTimeMin =
   114        Number(parts[0]) * 60 + Number(parts[1]) + d.getTimezoneOffset();
   115  
   116      if (fireTimeMin >= 60 * 24) {
   117        // Roll over into next day
   118        fireTimeMin -= 60 * 24;
   119      }
   120      // The above is localtime, so we need to convert to UTC
   121      let charTimerFireTime = await this.service.getCharacteristic(charTimerFireTimeUuid);
   122      charTimerFireTime.writeValue(Int32Array.of(fireTimeMin));
   123    }
   124  
   125    async fireTimer() {
   126      if (!this.device) {
   127        throw "fire timer, no device";
   128      }
   129  
   130      const charSetWifiSSID = await this.service.getCharacteristic(charTimerFireUuid);
   131      let zero = 0;
   132      charSetWifiSSID.writeValue(Uint8Array.of(zero));
   133    }
   134  
   135    async getState() {
   136      console.log("getState: service: ", this.service);
   137      let ret = {
   138        connected: this.connected,
   139        bleConnected: false,
   140        ssid: "",
   141        pass: "",
   142        model: "",
   143        uptime: this.uptime,
   144        signal: this.signal,
   145        freeMem: this.freeMem,
   146        currentTime: this.currentTime,
   147        timerFireDuration: 0,
   148        timerFireTime: 0,
   149        timerFireCount: this.timerFireCount
   150      };
   151  
   152      if (this.device && this.device.gatt.connected) {
   153        ret.bleConnected = true;
   154      }
   155  
   156      if (!ret.bleConnected) {
   157        // Nothing more to do
   158        return ret;
   159      }
   160  
   161      const modelChar = await this.service.getCharacteristic(charModelUuid);
   162      let buf = await modelChar.readValue();
   163      const decoder = new TextDecoder("utf-8");
   164      ret.model = decoder.decode(buf);
   165  
   166      const ssidChar = await this.service.getCharacteristic(charWifiSSIDUuid);
   167      buf = await ssidChar.readValue();
   168      ret.ssid = decoder.decode(buf);
   169  
   170      const fireDurChar = await this.service.getCharacteristic(charTimerFireDurationUuid);
   171      buf = await fireDurChar.readValue();
   172      ret.timerFireDuration = buf.getUint32();
   173  
   174      const fireTimeChar = await this.service.getCharacteristic(charTimerFireTimeUuid);
   175      buf = await fireTimeChar.readValue();
   176      ret.timerFireTime = buf.getUint32();
   177  
   178      let d = new Date();
   179      ret.timerFireTime -= d.getTimezoneOffset();
   180      if (ret.timerFireTime < 0) {
   181        ret.timerFireTime += 24 * 60;
   182      }
   183  
   184      return ret;
   185    }
   186  
   187    async request() {
   188      let options = {
   189        acceptAllDevices: true,
   190        optionalServices: [serviceUuid]
   191      };
   192      if (navigator.bluetooth == undefined) {
   193        alert("Sorry, Your device does not support Web BLE!");
   194        return;
   195      }
   196  
   197      try {
   198        if (this.device && this.device.gatt.connected) {
   199          await this.device.gatt.disconnect();
   200        }
   201  
   202        this.device = await navigator.bluetooth.requestDevice(options);
   203        if (!this.device) {
   204          throw "No device selected";
   205        }
   206  
   207        this.device.addEventListener(
   208          "gattserverdisconnected",
   209          this.onDisconnected.bind(this)
   210        );
   211  
   212        this.server = await this.device.gatt.connect();
   213        this.service = await this.server.getPrimaryService(serviceUuid);
   214  
   215        console.log("CLIFF: got service");
   216  
   217        const connectedChar = await this.service.getCharacteristic(charConnectedUuid);
   218        let buf = await connectedChar.readValue();
   219        this.connected = buf.getUint8();
   220  
   221        if (this.connected) {
   222          this.connected = true;
   223        } else {
   224          this.connected = false;
   225        }
   226  
   227        const connectChar = await this.service.getCharacteristic(charConnectedUuid);
   228        await connectChar.startNotifications();
   229        connectChar.addEventListener(
   230          "characteristicvaluechanged",
   231          this.onConnectedChanged.bind(this)
   232        );
   233  
   234        /*
   235         * Const uptimeChar = await this.service.getCharacteristic(charUptimeUuid);
   236         * await uptimeChar.startNotifications();
   237         * uptimeChar.addEventListener(
   238         * "characteristicvaluechanged",
   239         * this.onUptimeChanged.bind(this)
   240         * );
   241         */
   242  
   243        const signalChar = await this.service.getCharacteristic(charSignalUuid);
   244        await signalChar.startNotifications();
   245        signalChar.addEventListener(
   246          "characteristicvaluechanged",
   247          this.onSignalChanged.bind(this)
   248        );
   249  
   250        const freeMemChar = await this.service.getCharacteristic(charFreeMemUuid);
   251        await freeMemChar.startNotifications();
   252        freeMemChar.addEventListener(
   253          "characteristicvaluechanged",
   254          this.onFreeMemChanged.bind(this)
   255        );
   256  
   257        try {
   258          const timerFireCountChar = await this.service.getCharacteristic(charTimerFireCountUuid);
   259          await timerFireCountChar.startNotifications();
   260          timerFireCountChar.addEventListener(
   261            "characteristicvaluechanged",
   262            this.onTimerFireCountChanged.bind(this)
   263          );
   264  
   265          buf = await timerFireCountChar.readValue();
   266          this.timerFireCount = buf.getInt32();
   267        } catch (e) {
   268          console.log("Error getting timerCountChar");
   269        }
   270  
   271        const currentTimeChar = await this.service.getCharacteristic(charCurrentTimeUuid);
   272        await currentTimeChar.startNotifications();
   273        currentTimeChar.addEventListener(
   274          "characteristicvaluechanged",
   275          this.onCurrentTimeChanged.bind(this)
   276        );
   277      } catch (e) {
   278        console.log("Error connecting: ", e);
   279        this.resetState();
   280        throw e;
   281      }
   282  
   283      return this.device;
   284    }
   285  
   286    async disconnect() {
   287      if (!this.device) {
   288        this.resetState();
   289        throw "no device";
   290      }
   291  
   292      if (!this.device.gatt.connected) {
   293        this.resetState();
   294        throw "not connected";
   295      }
   296  
   297      try {
   298        await this.device.gatt.disconnect();
   299      } catch (e) {
   300        console.log("Error disconnecting: ", e);
   301      } finally {
   302        this.resetState();
   303      }
   304    }
   305  }