bt-sensors-plugin-sk 1.2.0-beta.0.0.2 → 1.2.0-beta.0.0.4

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
@@ -1,7 +1,7 @@
1
1
  const { Variant } = require('dbus-next');
2
2
  const { log } = require('node:console');
3
3
  const EventEmitter = require('node:events');
4
- var {exec} = require('child_process');
4
+ const AutoQueue = require("./Queue.js")
5
5
 
6
6
  /**
7
7
  * @author Andrew Gerngross <oh.that.andy@gmail.com>
@@ -12,6 +12,7 @@ var {exec} = require('child_process');
12
12
  */
13
13
 
14
14
  const BTCompanies = require('./bt_co.json');
15
+ const connectQueue = new AutoQueue()
15
16
 
16
17
  /**
17
18
  * @global A map of company names keyed by their Bluetooth ID
@@ -450,8 +451,7 @@ class BTSensor extends EventEmitter {
450
451
  throw new Error("::initGATTNotifications() should be implemented by the BTSensor subclass")
451
452
  }
452
453
 
453
- async deviceConnect() {
454
- await this.device.connect()
454
+ deviceConnect() {
455
455
 
456
456
  /* CAUTION: HACK AHEAD
457
457
 
@@ -465,16 +465,23 @@ class BTSensor extends EventEmitter {
465
465
 
466
466
  You know, the little things.
467
467
  */
468
- try {
469
- await this._adapter.helper.callMethod('SetDiscoveryFilter', {
470
- Transport: new Variant('s', this._adapter?._transport??"le")
471
- })
472
-
473
- } catch (e){
474
- //probably ignorable error. probably.
475
- console.log(e)
476
- }
477
- /* END HACK*/
468
+ return connectQueue.enqueue( async ()=>{
469
+ this.debug(`Connecting to ${this.getName()}`)
470
+ await this.device.connect()
471
+ try {
472
+
473
+ await this._adapter.helper.callMethod('StopDiscovery')
474
+ await this._adapter.helper.callMethod('SetDiscoveryFilter', {
475
+ Transport: new Variant('s', this._adapter?._transport??"le")
476
+ })
477
+ await this._adapter.helper.callMethod('StartDiscovery')
478
+
479
+ } catch (e){
480
+ //probably ignorable error. probably.
481
+ console.log(e)
482
+ }
483
+ })
484
+ /* END HACK*/
478
485
  }
479
486
 
480
487
  /**
@@ -767,12 +774,15 @@ class BTSensor extends EventEmitter {
767
774
  //End instance utility functions
768
775
 
769
776
  createPaths(config, id){
777
+ // const source = `${this.getName()} (${id})`
778
+
770
779
  Object.keys(this.getPaths()).forEach((tag)=>{
771
780
  const pathMeta=this.getPath(tag)
772
781
  const path = config.paths[tag]
773
782
  if (!(path===undefined))
774
783
  this.app.handleMessage(id,
775
784
  {
785
+ // $source: source,
776
786
  updates:
777
787
  [{ meta: [{path: preparePath(this, path), value: { units: pathMeta?.unit }}]}]
778
788
  })
@@ -780,6 +790,7 @@ class BTSensor extends EventEmitter {
780
790
  }
781
791
 
782
792
  initPaths(deviceConfig, id){
793
+ const source = this.getName()
783
794
  Object.keys(this.getPaths()).forEach((tag)=>{
784
795
  const pathMeta=this.getPath(tag)
785
796
  const path = deviceConfig.paths[tag];
@@ -788,14 +799,14 @@ class BTSensor extends EventEmitter {
788
799
  if (pathMeta.notify){
789
800
  this.app.notify(tag, val, id )
790
801
  } else {
791
- this.updatePath(preparePath(this,path),val,id)
802
+ this.updatePath(preparePath(this,path),val, id, source)
792
803
  }
793
804
  })
794
805
  }
795
806
  })
796
807
  }
797
- updatePath(path, val,id){
798
- this.app.handleMessage(id, {updates: [ { values: [ {path: path, value: val }] } ] })
808
+ updatePath(path, val, id, source){
809
+ this.app.handleMessage(id, {updates: [ { $source: source, values: [ { path: path, value: val }] } ] })
799
810
  }
800
811
  elapsedTimeSinceLastContact(){
801
812
  return (Date.now()-this?._lastContact??Date.now())/1000
package/Queue.js ADDED
@@ -0,0 +1,48 @@
1
+ /*
2
+ see: https://stackoverflow.com/questions/53540348/js-async-await-tasks-queue
3
+ */
4
+ class Queue {
5
+ constructor() { this._items = []; }
6
+ enqueue(item) { this._items.push(item); }
7
+ dequeue() { return this._items.shift(); }
8
+ get size() { return this._items.length; }
9
+ }
10
+
11
+ class AutoQueue extends Queue {
12
+ constructor() {
13
+ super();
14
+ this._pendingPromise = false;
15
+ }
16
+
17
+ enqueue(action) {
18
+ return new Promise((resolve, reject) => {
19
+ super.enqueue({ action, resolve, reject });
20
+ this.dequeue();
21
+ });
22
+ }
23
+
24
+ async dequeue() {
25
+ if (this._pendingPromise) return false;
26
+
27
+ let item = super.dequeue();
28
+
29
+ if (!item) return false;
30
+
31
+ try {
32
+ this._pendingPromise = true;
33
+
34
+ let payload = await item.action(this);
35
+
36
+ this._pendingPromise = false;
37
+ item.resolve(payload);
38
+ } catch (e) {
39
+ this._pendingPromise = false;
40
+ item.reject(e);
41
+ } finally {
42
+ this.dequeue();
43
+ }
44
+
45
+ return true;
46
+ }
47
+ }
48
+ module.exports = AutoQueue
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bt-sensors-plugin-sk",
3
- "version": "1.2.0-beta.0.0.2",
3
+ "version": "1.2.0-beta.0.0.4",
4
4
  "description": "Bluetooth Sensors for Signalk -- support for Victron devices, RuuviTag, Xiaomi, ATC and Inkbird, Ultrasonic wind meters, Mopeka tank readers, Renogy Battery and Solar Controllers, Aranet4 environment sensors, SwitchBot temp and humidity sensors, KilovaultHLXPlus smart batteries, and Govee GVH51xx temp sensors",
5
5
  "main": "index.js",
6
6
  "dependencies": {
@@ -73,15 +73,13 @@ class JBDBMS extends BTSensor {
73
73
  hasGATT(){
74
74
  return true
75
75
  }
76
- initCharacteristics(){
77
- return new Promise( async (resolve,reject )=>{
76
+ async initCharacteristics(){
78
77
  const gattServer = await this.device.gatt()
79
78
  const txRxService= await gattServer.getPrimaryService(this.constructor.TX_RX_SERVICE)
80
79
  this.rxChar = await txRxService.getCharacteristic(this.constructor.NOTIFY_CHAR_UUID)
81
80
  this.txChar = await txRxService.getCharacteristic(this.constructor.WRITE_CHAR_UUID)
82
81
  await this.rxChar.startNotifications()
83
- resolve(this)
84
- .catch((e)=>{ reject(e.message) }) })
82
+ return this
85
83
  }
86
84
 
87
85
  async initGATTNotifications(){
@@ -92,7 +90,7 @@ class JBDBMS extends BTSensor {
92
90
 
93
91
  emitGATT(){
94
92
  this.getAndEmitBatteryInfo()
95
- setTimeout(()=>{this.getAndEmitCellVoltages()}, 5000)
93
+ setTimeout(()=>{this.getAndEmitCellVoltages()}, 10000)
96
94
  }
97
95
 
98
96
  async getNumberOfCellsAndTemps(){
package/testqueue.js ADDED
@@ -0,0 +1,64 @@
1
+
2
+
3
+ import {createBluetooth} from 'node-ble'
4
+
5
+ import {AutoQueue} from "./Queue.js"
6
+ import {Variant} from 'dbus-next'
7
+
8
+ const {bluetooth, destroy} = createBluetooth()
9
+ const connectQueue = new AutoQueue()
10
+ const adapter = await bluetooth.getAdapter("hci0")
11
+ await adapter.startDiscovery()
12
+
13
+ function deviceConnect(mac) {
14
+
15
+ /* CAUTION: HACK AHEAD
16
+
17
+ Bluez for some cockamamie reason (It's 2025 for chrissake.
18
+ BLUETOOTH ISN'T JUST FOR DESKTOPS ANYMORE, BLUEZ DEVS!)
19
+ SUSPENDS scanning while connected to a device.
20
+
21
+ The next line of code gives the scanner a kick in the arse,
22
+ starting it up again so, I dunno, another device might be able
23
+ to connect and sensor classes could maybe get beacon updates.
24
+
25
+ You know, the little things.
26
+ */
27
+ adapter.waitDevice(mac,(30000)).then((device) =>{
28
+
29
+ return connectQueue.enqueue( async ()=>{
30
+ console.log("Connecting to "+mac)
31
+ try {await device.connect()} catch {(e)=>console.log(e)}
32
+ try {
33
+ console.log("Connected to "+mac)
34
+ console.log("Stopping discovery for "+mac)
35
+
36
+ await adapter.helper.callMethod('StopDiscovery')
37
+ console.log("Discovery stopped for "+mac)
38
+ await adapter.helper.callMethod('SetDiscoveryFilter', {
39
+ Transport: new Variant('s', "le")
40
+ })
41
+ console.log("Starting discovery for "+mac)
42
+ await adapter.helper.callMethod('StartDiscovery')
43
+ console.log("Discovery started for "+mac)
44
+
45
+ } catch (e){
46
+ //probably ignorable error. probably.
47
+ console.log(e)
48
+ }
49
+ })
50
+ })
51
+ /* END HACK*/
52
+ }
53
+ setInterval( ()=>{
54
+ deviceConnect("D1:06:00:C6:16:4A")
55
+ }, 5000)
56
+ setInterval( ()=>{
57
+
58
+ for (const mac of (["D1:06:01:46:49:39","A4:C1:38:3E:7E:94"])){
59
+ try { deviceConnect(mac) } catch { (e)=>console.log(e) }
60
+ }
61
+ }, 10000)
62
+
63
+
64
+