bt-sensors-plugin-sk 1.2.6-beta-5 → 1.2.6-beta-6a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/BTSensor.js CHANGED
@@ -102,7 +102,7 @@ class BTSensor extends EventEmitter {
102
102
  Object.assign(this,config)
103
103
  Object.assign(this,gattConfig)
104
104
 
105
- this._state = null
105
+ this._state = "UNKNOWN"
106
106
  }
107
107
  /**
108
108
  * @function _test Test sensor parsing
@@ -257,6 +257,9 @@ class BTSensor extends EventEmitter {
257
257
 
258
258
  _debugLog=[]
259
259
  _errorLog=[]
260
+ _error = false
261
+
262
+
260
263
 
261
264
  getErrorLog(){
262
265
  return this._errorLog
@@ -267,22 +270,23 @@ class BTSensor extends EventEmitter {
267
270
 
268
271
  debug(message){
269
272
  if (this._app)
270
- this._app.debug(`${this.getName()}) ${message}`)
273
+ this._app.debug(`(${this.getName()} ${this.getMacAddress()}) ${message}`)
271
274
  else
272
- console.log(`${this.getName()}) ${message}`)
275
+ console.log(`(${this.getName()} ${this.getMacAddress()})) ${message}`)
273
276
  this._debugLog.push({timestamp:Date.now(), message:message})
274
277
  }
275
278
 
276
279
  setError(message){
277
280
  if (this._app){
278
- this._app.debug(`${this.getName()}) ${message}`)
279
- this._app.setPluginError(`${this.getName()}) ${message}`)
281
+ this._app.debug(`(${this.getName()} ${this.getMacAddress()}) ${message}`)
282
+ this._app.setPluginError(`(${this.getName()} ${this.getMacAddress()}) ${message}`)
280
283
  }
281
284
  else
282
- console.log(message)
285
+ console.log(`(${this.getName()} ${this.getMacAddress()}) ${message}`)
283
286
 
284
287
  this._errorLog.push({timestamp:Date.now(), message:message})
285
- this.setState("ERROR")
288
+ this._error=true
289
+ this.emit("error", true)
286
290
  }
287
291
 
288
292
  //Instance Initialization functions
@@ -327,7 +331,7 @@ class BTSensor extends EventEmitter {
327
331
  description: this.getGATTDescription(),
328
332
  type:"object",
329
333
  properties:{
330
- useGATT: {title: "Use GATT connection", type: "boolean", default: false },
334
+ useGATT: {title: "Use GATT connection", type: "boolean", default: true },
331
335
  pollFreq: { type: "number", title: "Polling frequency in seconds"}
332
336
  }
333
337
  }
@@ -349,16 +353,21 @@ class BTSensor extends EventEmitter {
349
353
 
350
354
  }
351
355
  async init(){
356
+ this.setState("INITIALIZING")
357
+
352
358
  this.currentProperties = await this.constructor.getDeviceProps(this.device)
353
359
  await this.initSchema()
354
360
 
355
361
  this.initListen()
362
+ this.setState("DORMANT")
363
+
356
364
  }
357
365
 
358
366
  initListen(){
359
367
  this.listen()
360
368
  }
361
- activate(config, plugin){
369
+ async activate(config, plugin){
370
+ this.setState("ACTIVATING")
362
371
  if (config.paths){
363
372
  this.createPaths(config,plugin.id)
364
373
  this.initPaths(config,plugin.id)
@@ -366,13 +375,16 @@ class BTSensor extends EventEmitter {
366
375
  }
367
376
  if (this.usingGATT()){
368
377
  try {
369
- this.activateGATT()
378
+ await this.activateGATT()
370
379
  } catch (e) {
371
- this.setError(`GATT services unavailable for ${this.getName()}. Reason: ${e}`)
372
- return
380
+ this.setError(`GATT services unavailable.`)
381
+ throw new Error(`GATT services unavailable for ${this.getName()}. Reason: ${e}`)
373
382
  }
383
+ } else {
384
+ this.setState("ACTIVE")
374
385
  }
375
- this.setState("ACTIVE")
386
+ this._active = true
387
+
376
388
  this._propertiesChanged(this.currentProperties)
377
389
 
378
390
  }
@@ -383,23 +395,17 @@ class BTSensor extends EventEmitter {
383
395
  return this._gattServer
384
396
  }
385
397
  async activateGATT(isReconnecting=false){
386
- try{
387
- await this.initGATTConnection(isReconnecting)
388
- await this.emitGATT()
389
- if (this.pollFreq)
390
- this.initGATTInterval()
391
- else
392
- await this.initGATTNotifications()
393
- }
394
- catch(e) {
395
- this.debug(`Unable to activate GATT connection for ${this.getName()} (${this.getMacAddress()}): ${e}`)
396
- }
398
+ this.setState("ACTIVATING GATT")
399
+ await this.initGATTConnection(isReconnecting)
400
+ if (this.pollFreq)
401
+ await this.initGATTInterval()
402
+ else
403
+ await this.initGATTNotifications()
404
+
397
405
  }
398
406
 
399
- async deactivateGATT(){
400
- if (this.device) {
401
- this.debug(`(${this.getName()}) disconnecting from GATT server`)
402
- if (this._gattServer) { //getGATTServer() was called which calls node-ble's Device::gatt() which needs cleaning up after
407
+ async stopAllGATTNotifications(){
408
+ if (this._gattServer) { //getGATTServer() was called which calls node-ble's Device::gatt() which needs cleaning up after
403
409
  (await this._gattServer.services()).forEach(async (uuid) => {
404
410
  await this._gattServer.getPrimaryService(uuid).then(async (service) => {
405
411
  (await service.characteristics()).forEach(async (uuid) => {
@@ -409,8 +415,12 @@ class BTSensor extends EventEmitter {
409
415
  });
410
416
  this._gattServer.helper.removeListeners();
411
417
  });
412
- }
413
- await this.device.disconnect()
418
+ }
419
+ }
420
+ async deactivateGATT(){
421
+ if (this.device) {
422
+ this.debug(`Disconnecting from GATT server...`)
423
+ await this.deviceDisconnect()
414
424
  }
415
425
  }
416
426
 
@@ -528,7 +538,7 @@ class BTSensor extends EventEmitter {
528
538
  for (let attempts = 0; attempts<retries; attempts++) {
529
539
  try
530
540
  {
531
- this.debug( `(${this.getName()}) Trying to connect (attempt # ${attempts +1}) to Bluetooth device.` );
541
+ this.debug( `Trying to connect (attempt # ${attempts +1}) to Bluetooth device.` );
532
542
  await this.deviceConnect(isReconnecting);
533
543
  return this.device
534
544
  }
@@ -536,43 +546,56 @@ class BTSensor extends EventEmitter {
536
546
  catch (e){
537
547
  if (attempts==retries)
538
548
  throw new Error (`(${this.getName}) Unable to connect to Bluetooth device after ${attempts} attempts`)
539
- this.debug(`(${this.getName()}) Error connecting to device. Retrying... `);
549
+ this.debug(`Error connecting to device. Retrying... `);
540
550
  await new Promise((r) => setTimeout(r, retryInterval*1000));
541
551
 
542
552
  }
543
553
  }
544
554
  }
545
555
  setConnected(state){
546
- this._connected=state
547
- this.emit("connected", this._connected)
556
+ this.setState(state?"CONNECTED":"DISCONNECTED")
548
557
  }
549
- deviceConnect(isReconnecting=false, autoReconnect=false) {
550
558
 
559
+ isError(){
560
+ return this._error
561
+ }
562
+ deviceConnect(isReconnecting=false, autoReconnect=false) {
551
563
 
552
564
  return connectQueue.enqueue( async ()=>{
553
565
  this.debug(`Connecting... ${this.getName()}`)
566
+ this.setState("CONNECTING")
567
+ if (!isReconnecting){
568
+ this.device.on("disconnect", () => {
569
+ this.debug("Device disconnected.")
570
+ this.setConnected(false)
571
+ })
572
+ this.device.on("connect", () => {
573
+ this.debug("Device connected.")
574
+ this.setConnected(true)
575
+ })
576
+ }
554
577
  await this.device.helper.callMethod('Connect')
578
+ this.setConnected(true)
555
579
 
556
580
  this.debug(`Connected to ${this.getName()}`)
557
581
  if (!isReconnecting) {
558
582
  this.device.helper.on(
559
- "PropertiesChanged",
560
- (propertiesChanged) => {
561
- if ("Connected" in propertiesChanged) {
562
- const { value } = propertiesChanged.Connected;
563
- if (value) {
564
- this._connected = true;
565
- this.device.emit("connect", { connected: true });
566
- } else {
567
- this._connected = false;
568
- this.device.emit("disconnect", { connected: false });
583
+ "PropertiesChanged",
584
+ (propertiesChanged) => {
585
+ if ("Connected" in propertiesChanged) {
586
+ const { value } = propertiesChanged.Connected;
587
+ if (value) {
588
+ this.device.emit("connect", { connected: true });
589
+ } else {
590
+ this.device.emit("disconnect", { connected: false });
591
+ }
592
+ }
569
593
  }
570
- }
571
- }
572
- );
573
- if (autoReconnect){
574
- this.device.on("disconnect", async () => {
575
- this._connected = false;
594
+ );
595
+
596
+ if (autoReconnect){
597
+ this.device.on("disconnect", async () => {
598
+
576
599
  if (this.isActive()) {
577
600
  this.debug(
578
601
  `Device disconnected. Attempting to reconnect to ${this.getName()}`
@@ -583,16 +606,16 @@ class BTSensor extends EventEmitter {
583
606
  this.debug(`(${this.getName()}) Device reconnected.`);
584
607
  } catch (e) {
585
608
  this.setError(
586
- `Error while reconnecting to ${this.getName()}: ${
609
+ `Error while reconnecting: ${
587
610
  e.message
588
611
  }`
589
612
  );
590
613
  this.debug(
591
- `Error while reconnecting to ${this.getName()}: ${
614
+ `Error while reconnecting: ${
592
615
  e.message
593
616
  }`
594
617
  );
595
- this.debug(e);
618
+ this._app.debug(e);
596
619
  }
597
620
  }
598
621
  });
@@ -628,36 +651,51 @@ class BTSensor extends EventEmitter {
628
651
 
629
652
  })
630
653
 
631
- }
654
+ }
655
+ async deviceDisconnect(){
656
+ await this.stopAllGATTNotifications()
657
+ await this.device.disconnect()
658
+ this.setConnected(false)
659
+
660
+ }
661
+
662
+ async stopGATTNotifications(gattCharacteristic) {
663
+ if (gattCharacteristic){
664
+ gattCharacteristic.removeAllListeners()
632
665
 
666
+ try{
667
+ if (await gattCharacteristic.isNotifying())
668
+ await gattCharacteristic.stopNotifications();
669
+ } catch (e){
670
+ this.debug(`Error stopping notifications: ${e.message}`)
671
+ }
672
+ }
673
+ }
633
674
  /**
634
- *
635
- * Subclasses do NOT need to override this function
636
- * This function is only called when the property pollFreq is set to > 0
637
- * The function calls #emitGATT() at the specified interval then disconnects
638
- * from the device.
675
+ * The function calls #emitGATT() at the specified interval then calls deactivateGATT()
676
+ * which disconnects from the device.
639
677
  */
640
678
 
641
- initGATTInterval(){
642
- this.device.disconnect().then(()=>{
643
- this.intervalID = setInterval( async () => {
644
- try {
645
- await this.initGATTConnection()
646
- await this.emitGATT()
647
- }
648
- catch(error) {
649
- this.debug(error)
650
- throw new Error(`unable to emit values for device ${this.getName()}:${error}`)
651
- }
652
- finally{
653
- this.deactivateGATT().catch(
654
- (e)=>{
655
- this.debug(`(${this.getName()}) Error deactivating GATT Connection: ${e.message}`)
656
- })
657
- }
679
+ async initGATTInterval(){
680
+ await this.deviceDisconnect()
681
+
682
+ this.intervalID = setInterval( async () => {
683
+ try {
684
+ await this.initGATTConnection(true)
685
+ await this.emitGATT()
658
686
  }
659
- , this.pollFreq*1000)
660
- })
687
+ catch(error) {
688
+ this.debug(error)
689
+ this.setError(`Unable to emit values for device: ${error.message}`)
690
+ }
691
+ finally{
692
+ await this.deactivateGATT().catch( (e)=>{
693
+ this.debug(`Error deactivating GATT Connection: ${e.message}`)
694
+ })
695
+ this.setState("WAITING")
696
+ }
697
+ }
698
+ , this.pollFreq*1000)
661
699
  }
662
700
 
663
701
  /**
@@ -828,7 +866,7 @@ class BTSensor extends EventEmitter {
828
866
  }
829
867
 
830
868
  isActive(){
831
- return this._state=="ACTIVE"
869
+ return this?._active??false
832
870
  }
833
871
  getBars(){
834
872
  const ss = this.getSignalStrength()
@@ -903,9 +941,7 @@ class BTSensor extends EventEmitter {
903
941
  emitData(tag, buffer, ...args){
904
942
  const md = this.getPath(tag)
905
943
  if (md && md.read)
906
- this.emit(tag, md.read(buffer, ...args))
907
-
908
-
944
+ this.emit(tag, md.read(buffer, ...args))
909
945
  }
910
946
 
911
947
  emitValuesFrom(buffer){
@@ -963,12 +999,11 @@ class BTSensor extends EventEmitter {
963
999
  this.device.helper.removeListeners()
964
1000
 
965
1001
  if (this.intervalID){
966
- this.debug(`${this.getName()}::stopListening called clearInterval()`)
967
1002
  clearInterval(this.intervalID)
968
1003
  }
969
1004
  if( this.usingGATT() )
970
1005
  await this.deactivateGATT()
971
- this.setState("ASLEEP")
1006
+ this.setState("DORMANT")
972
1007
  }
973
1008
  //END Sensor listen-to-changes functions
974
1009
 
package/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Bluetooth Sensors for [Signal K](http://www.signalk.org)
2
2
 
3
3
  ## WHAT'S NEW
4
+
5
+ # Version 1.2.6-beta-6
6
+ - Funny you should ask...
7
+
4
8
  # Version 1.2.6-beta-5
5
9
 
6
10
  - JikongBMS fixes
package/index.js CHANGED
@@ -256,9 +256,9 @@ module.exports = function (app) {
256
256
  options, async () => {
257
257
  res.status(200).json({message: "Sensor updated"})
258
258
  if (sensor) {
259
- removeSensorFromList(sensor)
260
259
  if (sensor.isActive())
261
260
  await sensor.stopListening()
261
+ removeSensorFromList(sensor)
262
262
  }
263
263
  initConfiguredDevice(req.body)
264
264
  }
@@ -364,6 +364,7 @@ module.exports = function (app) {
364
364
  class: sensor.constructor.name,
365
365
  domain: sensor.getDomain().name,
366
366
  state: sensor.getState(),
367
+ error: sensor.isError(),
367
368
  errorLog: sensor.getErrorLog(),
368
369
  debugLog: sensor.getDebugLog(),
369
370
  RSSI: sensor.getRSSI(),
@@ -415,12 +416,29 @@ module.exports = function (app) {
415
416
  }
416
417
 
417
418
  function removeSensorFromList(sensor){
419
+ sensor.removeAllListeners("state")
420
+ sensor.removeAllListeners("connected")
421
+ sensor.removeAllListeners("error")
422
+ sensor.removeAllListeners("debug")
423
+
418
424
  sensorMap.delete(sensor.getMacAddress())
419
425
  channel.broadcast({mac:sensor.getMacAddress()},"removesensor")
420
426
  }
421
427
 
422
428
  function addSensorToList(sensor){
423
429
  sensorMap.set(sensor.getMacAddress(),sensor)
430
+ sensor.on("state", (state)=>{
431
+ updateSensor(sensor)
432
+ })
433
+ sensor.on("connected", (state)=>{
434
+ updateSensor(sensor)
435
+ })
436
+ sensor.on("error",(error)=>{
437
+ updateSensor(sensor)
438
+ })
439
+ sensor.on("debug", ()=>{
440
+ updateSensor(sensor)
441
+ })
424
442
  channel.broadcast(sensorToJSON(sensor),"newsensor");
425
443
  }
426
444
  function deviceNameAndAddress(config){
@@ -469,19 +487,10 @@ module.exports = function (app) {
469
487
  device.once("deviceFound",async (device)=>{
470
488
  s.device=device
471
489
  s.listen()
472
- s.activate(config, plugin)
490
+ await s.activate(config, plugin)
473
491
  removeSensorFromList(s)
474
492
  addSensorToList(s)
475
493
  })
476
- s.on("state", (state)=>{
477
- channel.broadcast(getSensorInfo(s), "sensorchanged")
478
- })
479
- s.on("error",(error)=>{
480
- channel.broadcast(getSensorInfo(s), "sensorchanged")
481
- })
482
- s.on("debug", ()=>{
483
- channel.broadcast(getSensorInfo(s), "sensorchanged")
484
- })
485
494
  addSensorToList(s)
486
495
  resolve(s)
487
496
  }
@@ -537,11 +546,13 @@ module.exports = function (app) {
537
546
  return sensor
538
547
  }
539
548
  catch(error){
540
- const msg = `Unable to instantiate ${await BTSensor.getDeviceProp(device,"Address")}: ${error.message} `
541
- plugin.debug(msg)
542
- plugin.debug(error)
543
- if (config.active)
544
- plugin.setError(msg)
549
+ if (!config.unconfigured) {
550
+ const msg = `Unable to instantiate ${await BTSensor.getDeviceProp(device,"Address")}: ${error.message} `
551
+ plugin.debug(msg)
552
+ plugin.debug(error)
553
+ if (config.active)
554
+ plugin.setError(msg)
555
+ }
545
556
  return null
546
557
  }
547
558
 
@@ -552,19 +563,23 @@ module.exports = function (app) {
552
563
  plugin.setStatusText(`Initializing ${deviceNameAndAddress(deviceConfig)}`);
553
564
  if (!deviceConfig.discoveryTimeout)
554
565
  deviceConfig.discoveryTimeout = options.discoveryTimeout
555
- createSensor(adapter, deviceConfig).then((sensor)=>{
566
+ createSensor(adapter, deviceConfig).then(async (sensor)=>{
556
567
  if (startNumber != starts ) {
557
568
  return
558
569
  }
559
570
  if (deviceConfig.active && !(sensor.device instanceof OutOfRangeDevice) ) {
560
571
  plugin.setStatusText(`Listening to ${++foundConfiguredDevices} sensors.`);
561
- sensor.activate(deviceConfig, plugin)
572
+ try {
573
+ await sensor.activate(deviceConfig, plugin)
574
+ } catch (e){
575
+ sensor.setError(`Unable to activate sensor. Reason: ${e.message}`)
576
+ }
562
577
  }
563
578
 
564
579
  })
565
580
  .catch((error)=>
566
581
  {
567
- if (deviceConfig.unconfigured) return
582
+ if (deviceConfig?.unconfigured??false) return
568
583
  if (startNumber != starts ) {
569
584
  return
570
585
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bt-sensors-plugin-sk",
3
- "version": "1.2.6-beta-5",
3
+ "version": "1.2.6-beta-6a",
4
4
  "description": "Bluetooth Sensors for Signalk - see https://www.npmjs.com/package/bt-sensors-plugin-sk#supported-sensors for a list of supported sensors",
5
5
  "main": "index.js",
6
6
  "dependencies": {
@@ -10,7 +10,7 @@
10
10
  "@rjsf/validator-ajv8": "^5.24.11",
11
11
  "better-sse": "^0.14.1",
12
12
  "buffer": "^6.0.3",
13
- "dbus-next": "^0.10.2",
13
+ "@jellybrick/dbus-next": "^0.10.3",
14
14
  "int24": "^0.0.1",
15
15
  "kaitai-struct": "^0.10.0",
16
16
  "node-ble": "^1.13.0",
package/public/847.js CHANGED
@@ -1 +1 @@
1
- (self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[]).push([[847],{9337:()=>{},62995:(e,t,n)=>{"use strict";n.r(t),n.d(t,{BTConfig:()=>k,default:()=>C});var a=n(73490),s=n(74810),r=n(40334),o=n(86528),c=n.n(o),i=n(11363),l=n(97493),u=n(27606),m=n(82096),d=n(3768),g=n(71431),f=n(39676),h=n(47041),p=n(86038),E=n(95027),w=n(43540),y=n(38250),S=n(31008),b=n(20455),v=n(23399);const A=e=>console.log.bind(console,e);function k(e){const t=(0,m.A)((e=>({root:{"& > *":{margin:e.spacing(1)}}}))),[n,k]=(0,o.useState)({}),[C,D]=(0,o.useState)({}),[_,$]=(0,o.useState)({}),[x,N]=(0,o.useState)({"ui:options":{label:!1},paths:{enableMarkdownInDescription:!0},title:{"ui:widget":"hidden"}}),[O,T]=(0,o.useState)(),[j,M]=(0,o.useState)(!1),[U,J]=(0,o.useState)(!0),[L,I]=(0,o.useState)(new Map),[P,K]=(0,o.useState)({progress:0,maxTimeout:100,deviceCount:0,totalDevices:0}),[R,B]=(0,o.useState)("unknown"),[G,W]=(0,o.useState)(),[F,H]=(0,o.useState)(!1),[z,Y]=(0,o.useState)(""),q=t();function Q(e,t){const n=new Headers;return n.append("Content-Type","application/json"),fetch(`/plugins/bt-sensors-plugin-sk/${e}`,{credentials:"include",method:"POST",body:JSON.stringify(t),headers:n})}async function V(e,t={}){let n;try{const a=Object.keys(t).length?"?"+new URLSearchParams(t).toString():"";n=await fetch(`/plugins/bt-sensors-plugin-sk/${e}${a}`,{credentials:"include",method:"GET"})}catch(e){n={status:500,statusText:e.toString()}}return n}function X(e){return Object.keys(e.configCopy).length>0}function Z(e){const t=X(e);return c().createElement(b.A,{action:!0,onClick:()=>{e.config.mac_address=e.info.mac,$(e.schema),T(e.config)}},c().createElement("div",{class:"d-flex justify-content-between align-items-center",style:t?{fontWeight:"normal"}:{fontStyle:"italic"}},`${e._changesMade?"*":""}${e.info.name} MAC: ${e.info.mac} RSSI: ${n=e.info.RSSI,null==n?NaN:n}`,c().createElement("div",{class:"d-flex justify-content-between "},e.info.state,c().createElement("div",{class:"d-flex justify-content-between "},function(e){return null==e.info.lastContactDelta||e.info.lastContactDelta>e.config.discoveryTimeout?c().createElement(d.A,null):e.info.signalStrength>80?c().createElement(g.A,null):e.info.signalStrength>60?c().createElement(f.A,null):e.info.signalStrength>40?c().createElement(h.A,null):e.info.signalStrength>20?c().createElement(p.A,null):c().createElement(E.A,null)}(e)))));var n}function ee(e){window.open(e,"_blank","noreferrer")}return(0,o.useEffect)((()=>{let e=null;return V("getPluginState").then((async t=>{if(404==t.status)throw B("unknown"),new Error("unable to get plugin state");const n=await t.json();e=new EventSource("/plugins/bt-sensors-plugin-sk/sse",{withCredentials:!0}),e.addEventListener("newsensor",(e=>{!function(e){let t=JSON.parse(e.data);console.log(`New sensor: ${t.info.mac}`),I((e=>(e.set(t.info.mac,t),new Map(e))))}(e)})),e.addEventListener("sensorchanged",(e=>{!function(e){console.log("sensorchanged");const t=JSON.parse(e.data);console.log(t),I((e=>{const n=e.get(t.mac);return n&&Object.assign(n.info,t),new Map(e)}))}(e)})),e.addEventListener("progress",(e=>{const t=JSON.parse(e.data);K(t)})),e.addEventListener("pluginstate",(e=>{const t=JSON.parse(e.data);B(t.state)})),B(n.state),(async()=>{const e=await async function(){const e=await V("getSensors");if(200!=e.status)throw new Error(`Unable get sensor data: ${e.statusText} (${e.status}) `);return await e.json()}();I(new Map(e.map((e=>[e.info.mac,e]))))})()})).catch((e=>{W(e.message)})),()=>{console.log("Closing connection to SSE"),e.close()}}),[]),(0,o.useEffect)((()=>{if(!j)return;if(!O||!L)return;const e=L.get(O.mac_address);e&&_&&O&&Object.hasOwn(O,"params")&&"UNKNOWN"==e.info.class&&O.params.sensorClass&&"UNKNOWN"!=O.params.sensorClass&&(J(!1),Y(`Please wait. Fetching schema for ${O.params.sensorClass}...`),async function(e,t){const n=await V("getSensorInfo",{mac_address:e,class:t});if(200!=n.status)throw new Error(`Unable get sensor info: ${n.statusText} (${n.status}) `);return await n.json()}(O.mac_address,O.params.sensorClass).then((e=>{$(e.schema)})).catch((e=>{alert(e.message)})).finally((()=>{Y(""),J(!0),M(!1)})))}),[j]),(0,o.useEffect)((()=>{H(""!=z)}),[z]),(0,o.useEffect)((()=>{"started"==R?(async function(){const e=await V("getBaseData");if(200!=e.status)throw new Error(`Unable to get base data: ${e.statusText} (${e.status}) `);const t=await e.json();return t.schema.htmlDescription=c().createElement("div",null,(0,r.Ay)(t.schema.htmlDescription),c().createElement("p",null)),t}().then((e=>{k(e.schema),D(e.data)})).catch((e=>{W(e.message)})),async function(){const e=await V("getProgress");if(200!=e.status)throw new Error(`Unable to get progress: ${e.statusText} (${e.status}) `);return await e.json()}().then((e=>{K(e)})).catch((e=>{W(e.message)}))):(k({}),D({}))}),[R]),"stopped"==R||"unknown"==R?c().createElement("h3",null,"Enable plugin to see configuration"):c().createElement("div",null,c().createElement(i.A,{anchorOrigin:{horizontal:"center",vertical:"bottom"},onClose:()=>H(!1),open:F,message:z,key:"snackbar"}),c().createElement("div",{className:q.root},c().createElement(l.A,{variant:"contained",onClick:()=>{ee("https://github.com/naugehyde/bt-sensors-plugin-sk/tree/1.2.0-beta#configuration")}},"Documentation"),c().createElement(l.A,{variant:"contained",onClick:()=>{ee("https://github.com/naugehyde/bt-sensors-plugin-sk/issues/new/choose")}},"Report Issue"),c().createElement(l.A,{variant:"contained",onClick:()=>{ee("https://discord.com/channels/1170433917761892493/1295425963466952725")}},"Discord Thread"),c().createElement("p",null),c().createElement("p",null)),c().createElement("hr",{style:{width:"100%",height:"1px",color:"gray","background-color":"gray","text-align":"left","margin-left":0}}),G?c().createElement("h2",{style:{color:"red"}},G):"",c().createElement(a.Ay,{schema:n,validator:s.Ay,uiSchema:{"ui:field":"LayoutGridField","ui:layoutGrid":{"ui:row":[{"ui:row":{className:"row",children:[{"ui:columns":{className:"col-xs-4",children:["adapter","transport","duplicateData","discoveryTimeout","discoveryInterval"]}}]}}]}},onChange:e=>D(e.formData),onSubmit:({formData:e},t)=>{var n;n=e,I(new Map),Q("updateBaseData",n).then((e=>{200!=e.status&&W(`Unable to update base data: ${e.statusText} (${e.status})`)})),$({})},onError:A("errors"),formData:C}),c().createElement("hr",{style:{width:"100%",height:"1px",color:"gray","background-color":"gray","text-align":"left","margin-left":0}}),c().createElement("p",null),c().createElement("p",null),P.deviceCount<P.totalDevices?c().createElement(v.A,{max:P.maxTimeout,now:P.progress}):"",c().createElement("p",null),c().createElement(y.A,{defaultActiveKey:"_configured",id:"domain-tabs",className:"mb-3"},function(){const e=[...new Set(L.entries().map((e=>e[1].info.domain)))].sort(),t=Array.from(L.entries()).filter((e=>X(e[1])));let n={};return n._configured=0==t.length?"Select a device from its domain tab (Electrical etc.) and configure it.":t.map((e=>Z(L.get(e[0])))),e.forEach((e=>{var t;n[e]=(t=e,Array.from(L.entries()).filter((e=>e[1].info.domain===t))).map((e=>Z(L.get(e[0]))))})),Object.keys(n).map((e=>function(e,t){let n=e.slice("_"===e.charAt(0)?1:0);return c().createElement(S.A,{eventKey:e,title:`${n.charAt(0).toUpperCase()}${n.slice(1)}${"string"==typeof t?"":" ("+t.length+")"}`},c().createElement(w.A,{style:{maxHeight:"300px",overflowY:"auto"}},t))}(e,n[e])))}()),c().createElement("div",{style:{paddingLeft:10,paddingTop:10,display:0==Object.keys(_).length?"none":""}},c().createElement(u.A,{container:!0,direction:"column",style:{spacing:5}},c().createElement(u.A,{item:!0},c().createElement("h2",null,_?.title),c().createElement("p",null)),c().createElement(u.A,{item:!0},(0,r.Ay)(_?.htmlDescription))),c().createElement("fieldset",{disabled:!U},c().createElement(a.Ay,{schema:_,validator:s.Ay,uiSchema:x,onChange:(e,t)=>{const n=L.get(e.formData.mac_address);n&&(n._changesMade=!0,n.config=e.formData,T(e.formData)),"root_params_sensorClass"==t&&M(!0)},onSubmit:({formData:e},t)=>{var n;Q("updateSensorData",n=e).then((e=>{if(200!=e.status)throw new Error(e.statusText);I((e=>(e.delete(n.mac_address),new Map(e)))),$({})})),alert("Changes saved")},onError:A("errors"),formData:O},c().createElement("div",{className:q.root},c().createElement(l.A,{type:"submit",color:"primary",variant:"contained"},"Save"),c().createElement(l.A,{variant:"contained",onClick:()=>{var e;e=O.mac_address,L.get(e)._changesMade=!1,L.get(e).config=JSON.parse(JSON.stringify(L.get(e).configCopy)),T(L.get(e).config)}},"Undo"),c().createElement(l.A,{variant:"contained",color:"secondary",onClick:e=>function(e){const t=L.get(e);(!X(t)||window.confirm(`Delete configuration for ${t.info.name}?`))&&function(e){try{Q("removeSensorData",{mac_address:e}).then((e=>{if(200!=e.status)throw new Error(e.statusText)})),I((t=>(t.delete(e),new Map(t)))),$({})}catch{}}(e)}(O.mac_address)},"Delete"))))))}const C=k}}]);
1
+ (self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[]).push([[847],{9337:()=>{},62995:(e,t,n)=>{"use strict";n.r(t),n.d(t,{BTConfig:()=>k,default:()=>C});var a=n(73490),s=n(74810),r=n(40334),o=n(86528),c=n.n(o),i=n(11363),l=n(97493),u=n(27606),m=n(82096),d=n(3768),g=n(71431),f=n(39676),h=n(47041),p=n(86038),E=n(95027),w=n(43540),y=n(38250),S=n(31008),b=n(20455),v=n(23399);const A=e=>console.log.bind(console,e);function k(e){const t=(0,m.A)((e=>({root:{"& > *":{margin:e.spacing(1)}}}))),[n,k]=(0,o.useState)({}),[C,D]=(0,o.useState)({}),[$,_]=(0,o.useState)({}),[x,N]=(0,o.useState)({"ui:options":{label:!1},paths:{enableMarkdownInDescription:!0},title:{"ui:widget":"hidden"}}),[O,T]=(0,o.useState)(),[j,M]=(0,o.useState)(!1),[U,J]=(0,o.useState)(!0),[L,R]=(0,o.useState)(new Map),[I,P]=(0,o.useState)({progress:0,maxTimeout:100,deviceCount:0,totalDevices:0}),[K,B]=(0,o.useState)("unknown"),[G,W]=(0,o.useState)(),[F,H]=(0,o.useState)(!1),[z,Y]=(0,o.useState)(""),q=t();function Q(e,t){const n=new Headers;return n.append("Content-Type","application/json"),fetch(`/plugins/bt-sensors-plugin-sk/${e}`,{credentials:"include",method:"POST",body:JSON.stringify(t),headers:n})}async function V(e,t={}){let n;try{const a=Object.keys(t).length?"?"+new URLSearchParams(t).toString():"";n=await fetch(`/plugins/bt-sensors-plugin-sk/${e}${a}`,{credentials:"include",method:"GET"})}catch(e){n={status:500,statusText:e.toString()}}return n}function X(e){return Object.keys(e.configCopy).length>0}function Z(e){const t=X(e);return c().createElement(b.A,{action:!0,onClick:()=>{e.config.mac_address=e.info.mac,_(e.schema),T(e.config)}},c().createElement("div",{class:"d-flex justify-content-between align-items-center",style:t?{fontWeight:"normal"}:{fontStyle:"italic"}},`${e._changesMade?"*":""}${e.info.name} MAC: ${e.info.mac} RSSI: ${n=e.info.RSSI,null==n?NaN:n}`,c().createElement("div",{class:"d-flex justify-content-between "},`${e.info.state} ${e.info.error?" (ERROR)":""}`,c().createElement("div",{class:"d-flex justify-content-between "},function(e){return null==e.info.lastContactDelta||e.info.lastContactDelta>e.config.discoveryTimeout?c().createElement(d.A,null):e.info.signalStrength>80?c().createElement(g.A,null):e.info.signalStrength>60?c().createElement(f.A,null):e.info.signalStrength>40?c().createElement(h.A,null):e.info.signalStrength>20?c().createElement(p.A,null):c().createElement(E.A,null)}(e)))));var n}function ee(e){window.open(e,"_blank","noreferrer")}return(0,o.useEffect)((()=>{let e=null;return V("getPluginState").then((async t=>{if(404==t.status)throw B("unknown"),new Error("unable to get plugin state");const n=await t.json();e=new EventSource("/plugins/bt-sensors-plugin-sk/sse",{withCredentials:!0}),e.addEventListener("newsensor",(e=>{!function(e){let t=JSON.parse(e.data);console.log(`New sensor: ${t.info.mac}`),R((e=>(e.set(t.info.mac,t),new Map(e))))}(e)})),e.addEventListener("sensorchanged",(e=>{!function(e){console.log("sensorchanged");const t=JSON.parse(e.data);console.log(t),R((e=>{const n=e.get(t.mac);return n&&Object.assign(n.info,t),new Map(e)}))}(e)})),e.addEventListener("progress",(e=>{const t=JSON.parse(e.data);P(t)})),e.addEventListener("pluginstate",(e=>{const t=JSON.parse(e.data);B(t.state)})),B(n.state),(async()=>{const e=await async function(){const e=await V("getSensors");if(200!=e.status)throw new Error(`Unable get sensor data: ${e.statusText} (${e.status}) `);return await e.json()}();R(new Map(e.map((e=>[e.info.mac,e]))))})()})).catch((e=>{W(e.message)})),()=>{console.log("Closing connection to SSE"),e.close()}}),[]),(0,o.useEffect)((()=>{if(!j)return;if(!O||!L)return;const e=L.get(O.mac_address);e&&$&&O&&Object.hasOwn(O,"params")&&"UNKNOWN"==e.info.class&&O.params.sensorClass&&"UNKNOWN"!=O.params.sensorClass&&(J(!1),Y(`Please wait. Fetching schema for ${O.params.sensorClass}...`),async function(e,t){const n=await V("getSensorInfo",{mac_address:e,class:t});if(200!=n.status)throw new Error(`Unable get sensor info: ${n.statusText} (${n.status}) `);return await n.json()}(O.mac_address,O.params.sensorClass).then((e=>{_(e.schema)})).catch((e=>{alert(e.message)})).finally((()=>{Y(""),J(!0),M(!1)})))}),[j]),(0,o.useEffect)((()=>{H(""!=z)}),[z]),(0,o.useEffect)((()=>{"started"==K?(async function(){const e=await V("getBaseData");if(200!=e.status)throw new Error(`Unable to get base data: ${e.statusText} (${e.status}) `);const t=await e.json();return t.schema.htmlDescription=c().createElement("div",null,(0,r.Ay)(t.schema.htmlDescription),c().createElement("p",null)),t}().then((e=>{k(e.schema),D(e.data)})).catch((e=>{W(e.message)})),async function(){const e=await V("getProgress");if(200!=e.status)throw new Error(`Unable to get progress: ${e.statusText} (${e.status}) `);return await e.json()}().then((e=>{P(e)})).catch((e=>{W(e.message)}))):(k({}),D({}))}),[K]),"stopped"==K||"unknown"==K?c().createElement("h3",null,"Enable plugin to see configuration"):c().createElement("div",null,c().createElement(i.A,{anchorOrigin:{horizontal:"center",vertical:"bottom"},onClose:()=>H(!1),open:F,message:z,key:"snackbar"}),c().createElement("div",{className:q.root},c().createElement(l.A,{variant:"contained",onClick:()=>{ee("https://github.com/naugehyde/bt-sensors-plugin-sk/tree/1.2.0-beta#configuration")}},"Documentation"),c().createElement(l.A,{variant:"contained",onClick:()=>{ee("https://github.com/naugehyde/bt-sensors-plugin-sk/issues/new/choose")}},"Report Issue"),c().createElement(l.A,{variant:"contained",onClick:()=>{ee("https://discord.com/channels/1170433917761892493/1295425963466952725")}},"Discord Thread"),c().createElement("p",null),c().createElement("p",null)),c().createElement("hr",{style:{width:"100%",height:"1px",color:"gray","background-color":"gray","text-align":"left","margin-left":0}}),G?c().createElement("h2",{style:{color:"red"}},G):"",c().createElement(a.Ay,{schema:n,validator:s.Ay,uiSchema:{"ui:field":"LayoutGridField","ui:layoutGrid":{"ui:row":[{"ui:row":{className:"row",children:[{"ui:columns":{className:"col-xs-4",children:["adapter","transport","duplicateData","discoveryTimeout","discoveryInterval"]}}]}}]}},onChange:e=>D(e.formData),onSubmit:({formData:e},t)=>{var n;n=e,R(new Map),Q("updateBaseData",n).then((e=>{200!=e.status&&W(`Unable to update base data: ${e.statusText} (${e.status})`)})),_({})},onError:A("errors"),formData:C}),c().createElement("hr",{style:{width:"100%",height:"1px",color:"gray","background-color":"gray","text-align":"left","margin-left":0}}),c().createElement("p",null),c().createElement("p",null),I.deviceCount<I.totalDevices?c().createElement(v.A,{max:I.maxTimeout,now:I.progress}):"",c().createElement("p",null),c().createElement(y.A,{defaultActiveKey:"_configured",id:"domain-tabs",className:"mb-3"},function(){const e=[...new Set(L.entries().map((e=>e[1].info.domain)))].sort(),t=Array.from(L.entries()).filter((e=>X(e[1])));let n={};return n._configured=0==t.length?"Select a device from its domain tab (Electrical etc.) and configure it.":t.map((e=>Z(L.get(e[0])))),e.forEach((e=>{var t;n[e]=(t=e,Array.from(L.entries()).filter((e=>e[1].info.domain===t))).map((e=>Z(L.get(e[0]))))})),Object.keys(n).map((e=>function(e,t){let n=e.slice("_"===e.charAt(0)?1:0);return c().createElement(S.A,{eventKey:e,title:`${n.charAt(0).toUpperCase()}${n.slice(1)}${"string"==typeof t?"":" ("+t.length+")"}`},c().createElement(w.A,{style:{maxHeight:"300px",overflowY:"auto"}},t))}(e,n[e])))}()),c().createElement("div",{style:{paddingLeft:10,paddingTop:10,display:0==Object.keys($).length?"none":""}},c().createElement(u.A,{container:!0,direction:"column",style:{spacing:5}},c().createElement(u.A,{item:!0},c().createElement("h2",null,$?.title),c().createElement("p",null)),c().createElement(u.A,{item:!0},(0,r.Ay)($?.htmlDescription))),c().createElement("fieldset",{disabled:!U},c().createElement(a.Ay,{schema:$,validator:s.Ay,uiSchema:x,onChange:(e,t)=>{const n=L.get(e.formData.mac_address);n&&(n._changesMade=!0,n.config=e.formData,T(e.formData)),"root_params_sensorClass"==t&&M(!0)},onSubmit:({formData:e},t)=>{var n;Q("updateSensorData",n=e).then((e=>{if(200!=e.status)throw new Error(e.statusText);R((e=>(e.delete(n.mac_address),new Map(e)))),_({})})),alert("Changes saved")},onError:A("errors"),formData:O},c().createElement("div",{className:q.root},c().createElement(l.A,{type:"submit",color:"primary",variant:"contained"},"Save"),c().createElement(l.A,{variant:"contained",onClick:()=>{var e;e=O.mac_address,L.get(e)._changesMade=!1,L.get(e).config=JSON.parse(JSON.stringify(L.get(e).configCopy)),T(L.get(e).config)}},"Undo"),c().createElement(l.A,{variant:"contained",color:"secondary",onClick:e=>function(e){const t=L.get(e);(!X(t)||window.confirm(`Delete configuration for ${t.info.name}?`))&&function(e){try{Q("removeSensorData",{mac_address:e}).then((e=>{if(200!=e.status)throw new Error(e.statusText)})),R((t=>(t.delete(e),new Map(t)))),_({})}catch{}}(e)}(O.mac_address)},"Delete"))))))}const C=k}}]);
@@ -36,9 +36,7 @@ class BankManager extends BTSensor{
36
36
  getManufacturer(){
37
37
  return "Bank Manager"
38
38
  }
39
- hasGATT(){
40
- return false
41
- }
39
+
42
40
  usingGATT(){
43
41
  return true
44
42
  }
@@ -49,48 +47,38 @@ class BankManager extends BTSensor{
49
47
  this.emit("current", parseFloat(data[3]))
50
48
  this.emit("soc", parseFloat(data[4])/100)
51
49
  this.emit("connectionStatus", parseInt(data[5]))
52
-
53
50
  }
51
+
54
52
  emitGATT(){
55
53
 
56
54
  }
57
55
  ImageFile = "BankManager.webp"
58
56
 
59
- initGATTConnection(){
60
- return new Promise((resolve,reject )=>{ this.deviceConnect().then(async ()=>{
61
- if (!this.gattServer) {
62
- this.gattServer = await this.device.gatt()
63
- this.service = await this.gattServer.getPrimaryService("0000ffe0-0000-1000-8000-00805f9b34fb")
64
- this.characteristic = await this.service.getCharacteristic("0000ffe1-0000-1000-8000-00805f9b34fb")
65
- }
66
- resolve(this)
67
- }) .catch((e)=>{ reject(e.message) }) })
57
+ async initGATTConnection(isReconnecting){
58
+ await super.initGATTConnection(isReconnecting)
59
+ const gattServer= await this.getGATTServer()
60
+ const service = await gattServer.getPrimaryService("0000ffe0-0000-1000-8000-00805f9b34fb")
61
+ this.characteristic = await service.getCharacteristic("0000ffe1-0000-1000-8000-00805f9b34fb")
68
62
  }
69
63
 
70
- initGATTNotifications() {
71
- Promise.resolve(this.characteristic.startNotifications().then(()=>{
72
- let data = null
73
- this.characteristic.on('valuechanged', buffer => {
74
- if (buffer.length>0 && buffer[0]==0x23) {
75
- data = Buffer.from(buffer)
76
- } else if (data && buffer.indexOf(0x0d0a)!==-1) {
77
- data=Buffer.concat([data,buffer.subarray(0,buffer.indexOf(0x0d0a)-1)], data.length+buffer.indexOf(0x0d0a)-1)
78
- this.emitDataFrom(data)
79
- data=null
80
- }
81
- })
82
- }))
83
-
64
+ async initGATTNotifications() {
65
+ await this.characteristic.startNotifications()
66
+ let data = null
67
+ this.characteristic.on('valuechanged', buffer => {
68
+ if (buffer.length>0 && buffer[0]==0x23) {
69
+ data = Buffer.from(buffer)
70
+ } else if (data && buffer.indexOf(0x0d0a)!==-1) {
71
+ data=Buffer.concat([data,buffer.subarray(0,buffer.indexOf(0x0d0a)-1)], data.length+buffer.indexOf(0x0d0a)-1)
72
+ this.emitDataFrom(data)
73
+ data=null
74
+ }
75
+ })
84
76
  }
85
77
 
86
- async stopListening(){
87
- super.stopListening()
88
- if (this.characteristic && await this.characteristic.isNotifying()) {
89
- await this.characteristic.stopNotifications()
90
- }
91
- if (await this.device.isConnected()){
92
- await this.device.disconnect()
93
- }
78
+
79
+ async deactivateGATT(){
80
+ await this.stopGATTNotifications(this.characteristic)
81
+ await this.deactivateGATT()
94
82
  }
95
83
  }
96
84
  module.exports=BankManager
@@ -1,7 +1,7 @@
1
1
  const AbstractBeaconMixin = require("./AbstractBeaconMixin")
2
2
 
3
3
  function getTxPower(){
4
- return (this.app.getSelfPath(this._txPowerPath)?.value??0)-41
4
+ return (this._app.getSelfPath(this._txPowerPath)?.value??0)-41
5
5
  }
6
6
 
7
7
 
@@ -1,6 +1,6 @@
1
1
  const AbstractBeaconMixin = require('./AbstractBeaconMixin')
2
2
  function getTxPower(){
3
- return (this.app.getSelfPath(this._txPowerPath)?.value??0)
3
+ return (this._app.getSelfPath(this._txPowerPath)?.value??0)
4
4
  }
5
5
 
6
6
  class iBeacon extends AbstractBeaconMixin {