bt-sensors-plugin-sk 1.2.0-beta.0.0.1.test → 1.2.0-beta.0.0.10
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/.vscode/launch.json +7 -0
- package/BTSensor.js +57 -11
- package/Queue.js +48 -0
- package/README.md +34 -12
- package/classLoader.js +38 -0
- package/index.js +71 -105
- package/package.json +2 -1
- package/plugin_defaults.json +99 -10
- package/public/893.js +1 -1
- package/sensor_classes/ATC.js +5 -3
- package/sensor_classes/Aranet/AranetSensor.js +4 -0
- package/sensor_classes/Aranet2.js +16 -15
- package/sensor_classes/Aranet4.js +23 -17
- package/sensor_classes/GoveeH50xx.js +12 -12
- package/sensor_classes/GoveeH510x.js +4 -5
- package/sensor_classes/IBeacon.js +13 -9
- package/sensor_classes/Inkbird.js +4 -2
- package/sensor_classes/JBDBMS.js +33 -25
- package/sensor_classes/KilovaultHLXPlus.js +33 -16
- package/sensor_classes/LancolVoltageMeter.js +4 -3
- package/sensor_classes/MopekaTankSensor.js +19 -10
- package/sensor_classes/Renogy/RenogySensor.js +1 -1
- package/sensor_classes/RenogyBattery.js +15 -13
- package/sensor_classes/RenogyRoverClient.js +2 -3
- package/sensor_classes/RuuviTag.js +36 -27
- package/sensor_classes/ShellySBHT003C.js +19 -22
- package/sensor_classes/SwitchBotMeterPlus.js +10 -12
- package/sensor_classes/SwitchBotTH.js +13 -16
- package/sensor_classes/UltrasonicWindMeter.js +13 -5
- package/sensor_classes/VictronACCharger.js +19 -8
- package/sensor_classes/VictronBatteryMonitor.js +41 -24
- package/sensor_classes/VictronDCDCConverter.js +14 -5
- package/sensor_classes/VictronDCEnergyMeter.js +26 -7
- package/sensor_classes/VictronGXDevice.js +2 -5
- package/sensor_classes/VictronInverter.js +18 -14
- package/sensor_classes/VictronInverterRS.js +18 -7
- package/sensor_classes/VictronLynxSmartBMS.js +15 -13
- package/sensor_classes/VictronOrionXS.js +15 -3
- package/sensor_classes/VictronSmartBatteryProtect.js +5 -6
- package/sensor_classes/VictronSmartLithium.js +18 -18
- package/sensor_classes/VictronSolarCharger.js +31 -18
- package/sensor_classes/VictronVEBus.js +2 -5
- package/sensor_classes/XiaomiMiBeacon.js +20 -19
- package/src/components/PluginConfigurationPanel.js +52 -27
- package/testqueue.js +64 -0
package/BTSensor.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const { Variant } = require('dbus-next');
|
|
2
2
|
const { log } = require('node:console');
|
|
3
3
|
const EventEmitter = require('node:events');
|
|
4
|
+
const AutoQueue = require("./Queue.js")
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* @author Andrew Gerngross <oh.that.andy@gmail.com>
|
|
@@ -11,6 +12,7 @@ const EventEmitter = require('node:events');
|
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
const BTCompanies = require('./bt_co.json');
|
|
15
|
+
const connectQueue = new AutoQueue()
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* @global A map of company names keyed by their Bluetooth ID
|
|
@@ -98,7 +100,7 @@ function preparePath(obj, str) {
|
|
|
98
100
|
*/
|
|
99
101
|
|
|
100
102
|
class BTSensor extends EventEmitter {
|
|
101
|
-
|
|
103
|
+
|
|
102
104
|
static DEFAULTS = require('./plugin_defaults.json');
|
|
103
105
|
|
|
104
106
|
/**
|
|
@@ -312,23 +314,25 @@ class BTSensor extends EventEmitter {
|
|
|
312
314
|
}
|
|
313
315
|
}
|
|
314
316
|
|
|
315
|
-
}
|
|
316
|
-
async init(){
|
|
317
|
-
this.currentProperties = await this.constructor.getDeviceProps(this.device)
|
|
318
|
-
this.initSchema()
|
|
319
|
-
|
|
320
317
|
|
|
321
318
|
//create the 'name' parameter
|
|
322
319
|
this.addDefaultParam("name")
|
|
320
|
+
.default=this?.currentProperties?.Name
|
|
323
321
|
|
|
324
322
|
//create the 'location' parameter
|
|
325
323
|
|
|
326
|
-
this.addDefaultParam("location")
|
|
324
|
+
//this.addDefaultParam("location")
|
|
327
325
|
|
|
328
326
|
//create the 'RSSI' parameter
|
|
329
327
|
this.addDefaultPath("RSSI","sensors.RSSI")
|
|
330
328
|
this.getPath("RSSI").read=()=>{return this.getRSSI()}
|
|
331
329
|
this.getPath("RSSI").read.bind(this)
|
|
330
|
+
|
|
331
|
+
}
|
|
332
|
+
async init(){
|
|
333
|
+
this.currentProperties = await this.constructor.getDeviceProps(this.device)
|
|
334
|
+
this.initSchema()
|
|
335
|
+
|
|
332
336
|
this.initListen()
|
|
333
337
|
}
|
|
334
338
|
|
|
@@ -361,13 +365,15 @@ class BTSensor extends EventEmitter {
|
|
|
361
365
|
}
|
|
362
366
|
else
|
|
363
367
|
await this.initGATTNotifications()
|
|
368
|
+
}).catch((e)=>{
|
|
369
|
+
this.app.debug(`Unable to activate GATT connection for ${this.getName()} (${this.getMacAddress()}): ${e}`)
|
|
364
370
|
})
|
|
365
371
|
}
|
|
366
372
|
|
|
367
373
|
/**
|
|
368
374
|
* Add a metadatum instance to the sensor instance
|
|
369
375
|
*
|
|
370
|
-
* @param {String} tag
|
|
376
|
+
* @param {String} tag
|
|
371
377
|
* @param {...any} args
|
|
372
378
|
* @returns {this.Metadatum} the new metadatum instance
|
|
373
379
|
*/
|
|
@@ -449,6 +455,39 @@ class BTSensor extends EventEmitter {
|
|
|
449
455
|
throw new Error("::initGATTNotifications() should be implemented by the BTSensor subclass")
|
|
450
456
|
}
|
|
451
457
|
|
|
458
|
+
deviceConnect() {
|
|
459
|
+
|
|
460
|
+
/* CAUTION: HACK AHEAD
|
|
461
|
+
|
|
462
|
+
Bluez for some cockamamie reason (It's 2025 for chrissake.
|
|
463
|
+
BLUETOOTH ISN'T JUST FOR DESKTOPS ANYMORE, BLUEZ DEVS!)
|
|
464
|
+
SUSPENDS scanning while connected to a device.
|
|
465
|
+
|
|
466
|
+
The next line of code gives the scanner a kick in the arse,
|
|
467
|
+
starting it up again so, I dunno, another device might be able
|
|
468
|
+
to connect and sensor classes could maybe get beacon updates.
|
|
469
|
+
|
|
470
|
+
You know, the little things.
|
|
471
|
+
*/
|
|
472
|
+
return connectQueue.enqueue( async ()=>{
|
|
473
|
+
this.debug(`Connecting to ${this.getName()}`)
|
|
474
|
+
await this.device.connect()
|
|
475
|
+
try {
|
|
476
|
+
|
|
477
|
+
await this._adapter.helper.callMethod('StopDiscovery')
|
|
478
|
+
await this._adapter.helper.callMethod('SetDiscoveryFilter', {
|
|
479
|
+
Transport: new Variant('s', this._adapter?._transport??"le")
|
|
480
|
+
})
|
|
481
|
+
await this._adapter.helper.callMethod('StartDiscovery')
|
|
482
|
+
|
|
483
|
+
} catch (e){
|
|
484
|
+
//probably ignorable error. probably.
|
|
485
|
+
console.log(e)
|
|
486
|
+
}
|
|
487
|
+
})
|
|
488
|
+
/* END HACK*/
|
|
489
|
+
}
|
|
490
|
+
|
|
452
491
|
/**
|
|
453
492
|
*
|
|
454
493
|
* Subclasses do NOT need to override this function
|
|
@@ -515,6 +554,9 @@ class BTSensor extends EventEmitter {
|
|
|
515
554
|
getParams(){
|
|
516
555
|
return this._schema.properties.params.properties
|
|
517
556
|
}
|
|
557
|
+
getParameter(param){
|
|
558
|
+
return this.getParams()[param]
|
|
559
|
+
}
|
|
518
560
|
getGATTParams(){
|
|
519
561
|
return this._schema.properties.gattParams.properties
|
|
520
562
|
|
|
@@ -739,12 +781,15 @@ class BTSensor extends EventEmitter {
|
|
|
739
781
|
//End instance utility functions
|
|
740
782
|
|
|
741
783
|
createPaths(config, id){
|
|
784
|
+
// const source = `${this.getName()} (${id})`
|
|
785
|
+
|
|
742
786
|
Object.keys(this.getPaths()).forEach((tag)=>{
|
|
743
787
|
const pathMeta=this.getPath(tag)
|
|
744
788
|
const path = config.paths[tag]
|
|
745
789
|
if (!(path===undefined))
|
|
746
790
|
this.app.handleMessage(id,
|
|
747
791
|
{
|
|
792
|
+
// $source: source,
|
|
748
793
|
updates:
|
|
749
794
|
[{ meta: [{path: preparePath(this, path), value: { units: pathMeta?.unit }}]}]
|
|
750
795
|
})
|
|
@@ -752,6 +797,7 @@ class BTSensor extends EventEmitter {
|
|
|
752
797
|
}
|
|
753
798
|
|
|
754
799
|
initPaths(deviceConfig, id){
|
|
800
|
+
const source = this.getName()
|
|
755
801
|
Object.keys(this.getPaths()).forEach((tag)=>{
|
|
756
802
|
const pathMeta=this.getPath(tag)
|
|
757
803
|
const path = deviceConfig.paths[tag];
|
|
@@ -760,14 +806,14 @@ class BTSensor extends EventEmitter {
|
|
|
760
806
|
if (pathMeta.notify){
|
|
761
807
|
this.app.notify(tag, val, id )
|
|
762
808
|
} else {
|
|
763
|
-
this.updatePath(preparePath(this,path),val,id)
|
|
809
|
+
this.updatePath(preparePath(this,path),val, id, source)
|
|
764
810
|
}
|
|
765
811
|
})
|
|
766
812
|
}
|
|
767
813
|
})
|
|
768
814
|
}
|
|
769
|
-
updatePath(path, val,id){
|
|
770
|
-
this.app.handleMessage(id, {updates: [ { values: [ {path: path, value: val }] } ] })
|
|
815
|
+
updatePath(path, val, id, source){
|
|
816
|
+
this.app.handleMessage(id, {updates: [ { $source: source, values: [ { path: path, value: val }] } ] })
|
|
771
817
|
}
|
|
772
818
|
elapsedTimeSinceLastContact(){
|
|
773
819
|
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/README.md
CHANGED
|
@@ -1,8 +1,35 @@
|
|
|
1
1
|
# Bluetooth Sensors for [Signal K](http://www.signalk.org)
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## What's New
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## 1.2.0-beta-0.0.10
|
|
6
|
+
|
|
7
|
+
Better handling of plugin config screen when Disabled
|
|
8
|
+
|
|
9
|
+
## 1.2.0-beta-0.0.9
|
|
10
|
+
|
|
11
|
+
Fixes to config page RSSI update.
|
|
12
|
+
|
|
13
|
+
## 1.2.0-beta-0.0.8
|
|
14
|
+
|
|
15
|
+
Improved handling of changed state on config page.
|
|
16
|
+
|
|
17
|
+
Several small fixes to various sensor classes.
|
|
18
|
+
|
|
19
|
+
## 1.2.0-beta-0.0.7
|
|
20
|
+
|
|
21
|
+
Added zone config param for environmental sensors. Removed location parameter.
|
|
22
|
+
|
|
23
|
+
## 1.2.0-beta-0.0.6
|
|
24
|
+
Default values for paths for most sensor classes.
|
|
25
|
+
|
|
26
|
+
## 1.2.0-beta-0.0.5
|
|
27
|
+
|
|
28
|
+
Added workaround to support multiple simultaneous GATT connections. Owing to problematic behavior in Bluez where making a GATT connection halted the scanner which made additional updates and connections impossible, added a scanner restart after making each GATT connection.
|
|
29
|
+
|
|
30
|
+
## 1.2.0-beta-0.0.1
|
|
31
|
+
|
|
32
|
+
Dynamic configuration added. List updates when new devices are found by scanner. (No more screen refreshing necessary).
|
|
6
33
|
|
|
7
34
|
## WHAT IT IS
|
|
8
35
|
|
|
@@ -33,13 +60,13 @@ Signalk users with a Linux boat-puter (Windows and MacOS are NOT currently suppo
|
|
|
33
60
|
NOTE: If you're running the 1.0.3 release, you will have to reconfigure your devices.<br>
|
|
34
61
|
|
|
35
62
|
### Signalk Appstore
|
|
36
|
-
The plugin is currently available in the Signalk Appstore. <br>
|
|
63
|
+
The beta plugin is not currently available in the Signalk Appstore. <br>
|
|
37
64
|
|
|
38
65
|
### NPM
|
|
39
66
|
|
|
40
67
|
Go to you signalk home (usually ~/.signalk) and run:
|
|
41
68
|
|
|
42
|
-
npm i bt-sensors-plugin-sk@1.
|
|
69
|
+
npm i bt-sensors-plugin-sk@1.2.0-beta.0.0.7
|
|
43
70
|
|
|
44
71
|
### Linux
|
|
45
72
|
|
|
@@ -48,7 +75,7 @@ If you want to install directly from source (this is mostly of interest to custo
|
|
|
48
75
|
<pre> cd ~/[some_dir]
|
|
49
76
|
git clone https://github.com/naugehyde/bt-sensors-plugin-sk
|
|
50
77
|
cd bt-sensors-plugin-sk
|
|
51
|
-
git switch '1.
|
|
78
|
+
git switch '1.2.0-beta'
|
|
52
79
|
git pull
|
|
53
80
|
npm i
|
|
54
81
|
[sudo] npm link
|
|
@@ -68,16 +95,11 @@ After installing and restarting Signalk you should see a "BT Sensors Plugin" opt
|
|
|
68
95
|
|
|
69
96
|
On initial configuration, wait for your Bluetooth adapter to scan devices. The plugin will scan for new devices at whatever you set the "scan for new devices interval" value to. <br><br>
|
|
70
97
|
|
|
71
|
-
> TIP: Close and re-open the config screen to refresh the screen. The config screen isn't as <i>reactive</i> as it oughtta be.<br><br>
|
|
72
|
-
|
|
73
|
-
Then press the + button to add a sensor. Your screen should look something like this:<br><br>
|
|
74
|
-
<img width="1122" alt="Screenshot 2024-10-13 at 6 52 52 PM" src="https://github.com/user-attachments/assets/0487b8d0-4bc0-4358-85c6-a507bc3c97d2">
|
|
75
|
-
|
|
76
98
|
<br><br>
|
|
77
99
|
|
|
78
|
-
Select the sensor you want Signalk to listen to from the
|
|
100
|
+
Select the sensor you want Signalk to listen to from the list.<br>
|
|
79
101
|
|
|
80
|
-
If you don't see your device and you know that it's on and nearby to the server, it may not be currently supported. But fear not, you can add custom sensor classes yourself. (Check out [the development section](#development).). <br><br>
|
|
102
|
+
If you don't see your device and you know that it's on and nearby to the server, it may not be currently supported (It could also be out of range.) But fear not, you can add custom sensor classes yourself. (Check out [the development section](#development).). <br><br>
|
|
81
103
|
|
|
82
104
|
Now it's a simple matter of associating the data emitted by the sensor with the Signalk path you want it to update. (Also, you can name your sensor so when it appears in logs its easy to recognize.) <br><br>
|
|
83
105
|
|
package/classLoader.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const semver = require('semver')
|
|
4
|
+
|
|
5
|
+
function loadClasses (dir, ext='.js')
|
|
6
|
+
{
|
|
7
|
+
const classMap = new Map()
|
|
8
|
+
const classFiles = fs.readdirSync(dir)
|
|
9
|
+
.filter(file => file.endsWith(ext));
|
|
10
|
+
|
|
11
|
+
classFiles.forEach(file => {
|
|
12
|
+
const filePath = path.join(dir, file);
|
|
13
|
+
const cls = require(filePath);
|
|
14
|
+
classMap.set(cls.name, cls);
|
|
15
|
+
})
|
|
16
|
+
return classMap
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function loadClassMap(app) {
|
|
20
|
+
const _classMap = loadClasses(path.join(__dirname, 'sensor_classes'))
|
|
21
|
+
const classMap = new Map([..._classMap].filter(([k, v]) => !k.startsWith("_") ))
|
|
22
|
+
const libPath = app.config.appPath +(
|
|
23
|
+
semver.gt(app.config.version,"2.13.5")?"dist":"lib"
|
|
24
|
+
)
|
|
25
|
+
import(libPath+"/modules.js").then( (modulesjs)=>{
|
|
26
|
+
const { default:defaultExport} = modulesjs
|
|
27
|
+
const modules = defaultExport.modulesWithKeyword(app.config, "signalk-bt-sensor-class")
|
|
28
|
+
modules.forEach((module)=>{
|
|
29
|
+
module.metadata.classFiles.forEach((classFile)=>{
|
|
30
|
+
const cls = require(module.location+module.module+"/"+classFile);
|
|
31
|
+
classMap.set(cls.name, cls);
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
classMap.get('UNKNOWN').classMap=new Map([...classMap].sort().filter(([k, v]) => !v.isSystem )) // share the classMap with Unknown for configuration purposes
|
|
35
|
+
})
|
|
36
|
+
return classMap
|
|
37
|
+
}
|
|
38
|
+
module.exports=loadClassMap
|