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 }