bt-sensors-plugin-sk 1.1.0 → 1.2.0-beta.0.0.1.test
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 +257 -107
- package/README.md +8 -10
- package/definitions.json +941 -0
- package/index.js +401 -317
- package/package.json +51 -6
- package/plugin_defaults.json +57 -0
- package/public/159.js +2 -0
- package/public/159.js.LICENSE.txt +14 -0
- package/public/30.js +8 -0
- package/public/30.js.LICENSE.txt +65 -0
- package/public/540.js +2 -0
- package/public/540.js.LICENSE.txt +8 -0
- package/public/893.js +1 -0
- package/public/main.js +1 -0
- package/public/remoteEntry.js +1 -0
- package/sensor_classes/ATC.js +30 -20
- package/sensor_classes/BlackListedDevice.js +4 -0
- package/sensor_classes/DEVELOPMENT.md +1 -6
- package/sensor_classes/GoveeH510x.js +3 -3
- package/sensor_classes/IBeacon.js +2 -3
- package/sensor_classes/Inkbird.js +4 -4
- package/sensor_classes/MopekaTankSensor.js +13 -6
- package/sensor_classes/Renogy/RenogySensor.js +14 -5
- package/sensor_classes/UNKNOWN.js +8 -4
- package/sensor_classes/Victron/VictronSensor.js +6 -2
- package/sensor_classes/VictronBatteryMonitor.js +8 -6
- package/sensor_classes/VictronDCEnergyMeter.js +1 -1
- package/sensor_classes/VictronInverter.js +1 -1
- package/sensor_classes/VictronInverterRS.js +1 -1
- package/sensor_classes/XiaomiMiBeacon.js +17 -8
- package/spec/electrical.json +688 -0
- package/spec/environment.json +401 -0
- package/spec/sensors.json +39 -0
- package/spec/tanks.json +115 -0
- package/src/components/PluginConfigurationPanel.js +368 -0
- package/src/index.js +0 -0
- package/webpack.config.js +71 -0
package/BTSensor.js
CHANGED
|
@@ -10,7 +10,8 @@ const EventEmitter = require('node:events');
|
|
|
10
10
|
* {@link module:node-ble}
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
const BTCompanies = require('./bt_co.json')
|
|
13
|
+
const BTCompanies = require('./bt_co.json');
|
|
14
|
+
|
|
14
15
|
/**
|
|
15
16
|
* @global A map of company names keyed by their Bluetooth ID
|
|
16
17
|
* {@link ./sensor_classes/bt_co.json} file derived from bluetooth-sig source:
|
|
@@ -51,6 +52,38 @@ function signalQualityPercentQuad(rssi, perfect_rssi=-20, worst_rssi=-85) {
|
|
|
51
52
|
}
|
|
52
53
|
return Math.ceil(signal_quality);
|
|
53
54
|
}
|
|
55
|
+
function preparePath(obj, str) {
|
|
56
|
+
const regex = /\{([^}]+)\}/g;
|
|
57
|
+
let match;
|
|
58
|
+
let resultString = "";
|
|
59
|
+
let lastIndex = 0;
|
|
60
|
+
|
|
61
|
+
while ((match = regex.exec(str)) !== null) {
|
|
62
|
+
const fullMatch = match[0];
|
|
63
|
+
const keyToAccess = match[1].trim();
|
|
64
|
+
|
|
65
|
+
// Append the text before the current curly braces
|
|
66
|
+
resultString += str.substring(lastIndex, match.index);
|
|
67
|
+
lastIndex = regex.lastIndex;
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
let evalResult = obj[keyToAccess];
|
|
71
|
+
if (typeof evalResult === 'function'){
|
|
72
|
+
evalResult= evalResult.call(obj)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
resultString += evalResult !== undefined ? evalResult : `${keyToAccess}_value_undefined`;
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error(`Error accessing key '${keyToAccess}':`, error);
|
|
78
|
+
resultString += fullMatch; // Keep the original curly braces on error
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Append any remaining text after the last curly braces
|
|
83
|
+
resultString += str.substring(lastIndex);
|
|
84
|
+
|
|
85
|
+
return resultString || str; // Return original string if no replacements were made
|
|
86
|
+
}
|
|
54
87
|
|
|
55
88
|
/**
|
|
56
89
|
* @classdesc Class that all sensor classes should inherit from. Sensor subclasses
|
|
@@ -65,8 +98,9 @@ function signalQualityPercentQuad(rssi, perfect_rssi=-20, worst_rssi=-85) {
|
|
|
65
98
|
*/
|
|
66
99
|
|
|
67
100
|
class BTSensor extends EventEmitter {
|
|
68
|
-
static metadata=new Map()
|
|
69
|
-
|
|
101
|
+
//static metadata=new Map()
|
|
102
|
+
static DEFAULTS = require('./plugin_defaults.json');
|
|
103
|
+
|
|
70
104
|
/**
|
|
71
105
|
*
|
|
72
106
|
* @param {module:node-ble/Device} device
|
|
@@ -77,13 +111,11 @@ class BTSensor extends EventEmitter {
|
|
|
77
111
|
super()
|
|
78
112
|
|
|
79
113
|
this.device=device
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
this
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
this.Metadatum = this.constructor.Metadatum
|
|
86
|
-
this.metadata = new Map()
|
|
114
|
+
|
|
115
|
+
Object.assign(this,config)
|
|
116
|
+
Object.assign(this,gattConfig)
|
|
117
|
+
|
|
118
|
+
this._state = null
|
|
87
119
|
}
|
|
88
120
|
/**
|
|
89
121
|
* @function _test Test sensor parsing
|
|
@@ -133,7 +165,7 @@ class BTSensor extends EventEmitter {
|
|
|
133
165
|
var b = Buffer.from(data.replaceAll(" ",""),"hex")
|
|
134
166
|
const d = new this(null,config)
|
|
135
167
|
d.initMetadata()
|
|
136
|
-
d.
|
|
168
|
+
Object.keys(d.getPaths()).forEach((tag)=>{
|
|
137
169
|
d.on(tag,(v)=>console.log(`${tag}=${v}`))
|
|
138
170
|
})
|
|
139
171
|
if (key) {
|
|
@@ -145,38 +177,7 @@ class BTSensor extends EventEmitter {
|
|
|
145
177
|
d.removeAllListeners()
|
|
146
178
|
|
|
147
179
|
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* @class encapsulates a sensor's metadata
|
|
151
|
-
* @todo refactor and/or just plain rethink constructor parameters
|
|
152
|
-
*/
|
|
153
|
-
class Metadatum{
|
|
154
|
-
|
|
155
|
-
constructor(tag, unit, description, read, gatt=null, type){
|
|
156
|
-
this.tag = tag
|
|
157
|
-
this.unit = unit
|
|
158
|
-
this.description = description
|
|
159
|
-
this.read = read
|
|
160
|
-
this.gatt = gatt
|
|
161
|
-
this.type = type //schema type e.g. 'number'
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
*
|
|
165
|
-
* @returns A JSON object passed by plugin to the plugin's schema
|
|
166
|
-
* dynamically updated at runtime upon discovery and interrogation
|
|
167
|
-
* of the device
|
|
168
|
-
*/
|
|
169
|
-
asJSONSchema(){
|
|
170
|
-
return {
|
|
171
|
-
type:this?.type??'string',
|
|
172
|
-
title: this?.description,
|
|
173
|
-
unit: this?.unit,
|
|
174
|
-
enum: this?.enum,
|
|
175
|
-
default: this?.default
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
+
|
|
180
181
|
//static utility Functions
|
|
181
182
|
/**
|
|
182
183
|
*
|
|
@@ -274,28 +275,93 @@ class BTSensor extends EventEmitter {
|
|
|
274
275
|
*
|
|
275
276
|
*/
|
|
276
277
|
|
|
278
|
+
initSchema(){
|
|
279
|
+
this._schema = {
|
|
280
|
+
properties:{
|
|
281
|
+
active: {title: "Active", type: "boolean", default: true },
|
|
282
|
+
discoveryTimeout: {title: "Device discovery timeout (in seconds)",
|
|
283
|
+
type: "integer", default:30,
|
|
284
|
+
minimum: 10,
|
|
285
|
+
maximum: 600 },
|
|
286
|
+
|
|
287
|
+
params:{
|
|
288
|
+
title:`Device parameters`,
|
|
289
|
+
description: this.getDescription(),
|
|
290
|
+
type:"object",
|
|
291
|
+
properties:{}
|
|
292
|
+
},
|
|
293
|
+
paths:{
|
|
294
|
+
title:"Signalk Paths",
|
|
295
|
+
description: `Signalk paths to be updated when ${this.getName()}'s values change`,
|
|
296
|
+
type:"object",
|
|
297
|
+
properties:{}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (this.hasGATT()){
|
|
303
|
+
|
|
304
|
+
this._schema.properties.gattParams={
|
|
305
|
+
title:`GATT Specific device parameters`,
|
|
306
|
+
description: this.getGATTDescription(),
|
|
307
|
+
type:"object",
|
|
308
|
+
properties:{
|
|
309
|
+
useGATT: {title: "Use GATT connection", type: "boolean", default: false },
|
|
310
|
+
pollFreq: { type: "number", title: "Polling frequency in seconds"}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
}
|
|
277
316
|
async init(){
|
|
317
|
+
this.currentProperties = await this.constructor.getDeviceProps(this.device)
|
|
318
|
+
this.initSchema()
|
|
319
|
+
|
|
320
|
+
|
|
278
321
|
//create the 'name' parameter
|
|
279
|
-
|
|
280
|
-
|
|
322
|
+
this.addDefaultParam("name")
|
|
323
|
+
|
|
324
|
+
//create the 'location' parameter
|
|
325
|
+
|
|
326
|
+
this.addDefaultParam("location")
|
|
327
|
+
|
|
281
328
|
//create the 'RSSI' parameter
|
|
282
|
-
this.
|
|
283
|
-
this.
|
|
284
|
-
this.
|
|
285
|
-
this.
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
md.isParam=true
|
|
297
|
-
md.isGATT=true
|
|
329
|
+
this.addDefaultPath("RSSI","sensors.RSSI")
|
|
330
|
+
this.getPath("RSSI").read=()=>{return this.getRSSI()}
|
|
331
|
+
this.getPath("RSSI").read.bind(this)
|
|
332
|
+
this.initListen()
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
initListen(){
|
|
336
|
+
Promise.resolve(this.listen())
|
|
337
|
+
}
|
|
338
|
+
activate(config, plugin){
|
|
339
|
+
if (config.paths){
|
|
340
|
+
this.createPaths(config,plugin.id)
|
|
341
|
+
this.initPaths(config,plugin.id)
|
|
342
|
+
this.debug(`Paths activated for ${this.getDisplayName()}`);
|
|
298
343
|
}
|
|
344
|
+
if (this.usingGATT()){
|
|
345
|
+
try {
|
|
346
|
+
this.activateGATT()
|
|
347
|
+
} catch (e) {
|
|
348
|
+
this.debug(`GATT services unavailable for ${this.getName()}. Reason: ${e}`)
|
|
349
|
+
this._state="ERROR"
|
|
350
|
+
return
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
this._state="ACTIVE"
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
activateGATT(){
|
|
357
|
+
this.initGATTConnection().then(async ()=>{
|
|
358
|
+
this.emitGATT()
|
|
359
|
+
if (this.pollFreq){
|
|
360
|
+
this.initGATTInterval()
|
|
361
|
+
}
|
|
362
|
+
else
|
|
363
|
+
await this.initGATTNotifications()
|
|
364
|
+
})
|
|
299
365
|
}
|
|
300
366
|
|
|
301
367
|
/**
|
|
@@ -307,9 +373,55 @@ class BTSensor extends EventEmitter {
|
|
|
307
373
|
*/
|
|
308
374
|
|
|
309
375
|
addMetadatum(tag, ...args){
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
376
|
+
|
|
377
|
+
const md = {}
|
|
378
|
+
if (args[0]) md.unit = args[0]
|
|
379
|
+
if (args[1]) md.title = args[1]
|
|
380
|
+
if (args[2]) md.read = args[2]
|
|
381
|
+
if (args[3]) md.gatt = args[3]
|
|
382
|
+
if (args[4]) md.type = args[4]
|
|
383
|
+
|
|
384
|
+
return this.addPath(tag,md)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
addParameter(tag, param){
|
|
388
|
+
|
|
389
|
+
if (!param.type)
|
|
390
|
+
param.type="string"
|
|
391
|
+
|
|
392
|
+
this._schema.properties.params.properties[tag]=param
|
|
393
|
+
return this._schema.properties.params.properties[tag]
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
addPath(tag, path){
|
|
397
|
+
if (!path.type)
|
|
398
|
+
path.type="string"
|
|
399
|
+
|
|
400
|
+
if (!path.pattern)
|
|
401
|
+
path.pattern="^(?:[^{}\\s]*\\{[a-zA-Z0-9]+\\}[^{}\\s]*|[^{}\\s]*)$"
|
|
402
|
+
this._schema.properties.paths.properties[tag]=path
|
|
403
|
+
return this._schema.properties.paths.properties[tag]
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
addGATTParameter(tag, param){
|
|
407
|
+
|
|
408
|
+
if (!param.type)
|
|
409
|
+
param.type="string"
|
|
410
|
+
|
|
411
|
+
return this._schema.properties.gattParams.properties[tag]=param
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
addDefaultPath(tag,defaultPath){
|
|
415
|
+
const path = eval(`BTSensor.DEFAULTS.${defaultPath}`)
|
|
416
|
+
return this.addPath(tag,Object.assign({}, path))
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
addDefaultParam(tag){
|
|
420
|
+
return this.addParameter(tag,Object.assign({}, BTSensor.DEFAULTS.params[tag]))
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
getJSONSchema(){
|
|
424
|
+
return this._schema
|
|
313
425
|
}
|
|
314
426
|
|
|
315
427
|
//GATT Initialization functions
|
|
@@ -376,12 +488,12 @@ class BTSensor extends EventEmitter {
|
|
|
376
488
|
*/
|
|
377
489
|
initPropertiesChanged(){
|
|
378
490
|
|
|
379
|
-
this.
|
|
491
|
+
this._propertiesChanged.bind(this)
|
|
380
492
|
this.device.helper._prepare()
|
|
381
493
|
this.device.helper.on("PropertiesChanged",
|
|
382
494
|
((props)=> {
|
|
383
495
|
try{
|
|
384
|
-
this.
|
|
496
|
+
this._propertiesChanged(props)
|
|
385
497
|
}
|
|
386
498
|
catch(error){
|
|
387
499
|
this.debug(`Error occured on ${this.getNameAndAddress()}: ${error?.message??error}`)
|
|
@@ -392,30 +504,20 @@ class BTSensor extends EventEmitter {
|
|
|
392
504
|
//END instance initialization functions
|
|
393
505
|
|
|
394
506
|
//Metadata functions
|
|
395
|
-
getMetadata(){
|
|
396
|
-
if (this.metadata==undefined)
|
|
397
|
-
this.metadata= new Map(this.constructor.getMetadata())
|
|
398
|
-
return this.metadata
|
|
399
|
-
}
|
|
400
507
|
|
|
401
|
-
|
|
402
|
-
return this.
|
|
508
|
+
getPath(tag){
|
|
509
|
+
return this._schema.properties.paths.properties[tag]
|
|
403
510
|
}
|
|
404
511
|
|
|
405
|
-
|
|
406
|
-
return
|
|
407
|
-
[...this.getMetadata().entries()].filter(([key,value]) => !(value?.isParam??false))
|
|
408
|
-
)
|
|
512
|
+
getPaths(){
|
|
513
|
+
return this._schema.properties.paths.properties
|
|
409
514
|
}
|
|
410
|
-
|
|
411
|
-
return
|
|
412
|
-
[...this.getMetadata().entries()].filter(([key,value]) => (value?.isParam??false) && !(value?.isGATT??false))
|
|
413
|
-
)
|
|
515
|
+
getParams(){
|
|
516
|
+
return this._schema.properties.params.properties
|
|
414
517
|
}
|
|
415
|
-
|
|
416
|
-
return
|
|
417
|
-
|
|
418
|
-
)
|
|
518
|
+
getGATTParams(){
|
|
519
|
+
return this._schema.properties.gattParams.properties
|
|
520
|
+
|
|
419
521
|
}
|
|
420
522
|
//End metadata functions
|
|
421
523
|
|
|
@@ -429,9 +531,13 @@ class BTSensor extends EventEmitter {
|
|
|
429
531
|
return `${this.getName()} from ${this.getManufacturer()}`
|
|
430
532
|
}
|
|
431
533
|
getName(){
|
|
432
|
-
|
|
433
|
-
|
|
534
|
+
const name = this?.name??this.currentProperties.Name
|
|
535
|
+
return name?name:"Unknown"
|
|
434
536
|
|
|
537
|
+
}
|
|
538
|
+
macAndName(){
|
|
539
|
+
return `${this.getName().replaceAll(':', '-').replaceAll(" ","_")}-${this.getMacAddress().replaceAll(':', '-')}`
|
|
540
|
+
}
|
|
435
541
|
getNameAndAddress(){
|
|
436
542
|
return `${this.getName()} at ${this.getMacAddress()}`
|
|
437
543
|
}
|
|
@@ -475,6 +581,8 @@ class BTSensor extends EventEmitter {
|
|
|
475
581
|
else
|
|
476
582
|
return null
|
|
477
583
|
}
|
|
584
|
+
|
|
585
|
+
|
|
478
586
|
//END Device property functions
|
|
479
587
|
|
|
480
588
|
//Sensor RSSI state functions
|
|
@@ -490,6 +598,13 @@ class BTSensor extends EventEmitter {
|
|
|
490
598
|
return signalQualityPercentQuad(rssi)
|
|
491
599
|
}
|
|
492
600
|
|
|
601
|
+
getState(){
|
|
602
|
+
return this._state
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
isActive(){
|
|
606
|
+
return this._state=="ACTIVE"
|
|
607
|
+
}
|
|
493
608
|
getBars(){
|
|
494
609
|
const ss = this.getSignalStrength()
|
|
495
610
|
var bars = ""
|
|
@@ -532,7 +647,8 @@ class BTSensor extends EventEmitter {
|
|
|
532
647
|
* @param {*} props which contains ManufacturerData and ServiceData (where the sensor's data resides)
|
|
533
648
|
* set up by BTSensor::initPropertiesChanged()
|
|
534
649
|
*/
|
|
535
|
-
|
|
650
|
+
_propertiesChanged(props){
|
|
651
|
+
this._lastContact=Date.now()
|
|
536
652
|
|
|
537
653
|
if (props.RSSI) {
|
|
538
654
|
this.currentProperties.RSSI=this.valueIfVariant(props.RSSI)
|
|
@@ -543,8 +659,13 @@ class BTSensor extends EventEmitter {
|
|
|
543
659
|
|
|
544
660
|
if (props.ManufacturerData)
|
|
545
661
|
this.currentProperties.ManufacturerData=this.valueIfVariant(props.ManufacturerData)
|
|
662
|
+
if (this.isActive())
|
|
663
|
+
this.propertiesChanged(props)
|
|
546
664
|
|
|
547
665
|
}
|
|
666
|
+
propertiesChanged(props){
|
|
667
|
+
//implemented by subclass
|
|
668
|
+
}
|
|
548
669
|
|
|
549
670
|
/**
|
|
550
671
|
*
|
|
@@ -555,14 +676,18 @@ class BTSensor extends EventEmitter {
|
|
|
555
676
|
}
|
|
556
677
|
|
|
557
678
|
emitData(tag, buffer, ...args){
|
|
558
|
-
|
|
679
|
+
const md = this.getPath(tag)
|
|
680
|
+
if (md && md.read)
|
|
681
|
+
this.emit(tag, md.read(buffer, ...args))
|
|
682
|
+
|
|
683
|
+
|
|
559
684
|
}
|
|
560
685
|
|
|
561
686
|
emitValuesFrom(buffer){
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
687
|
+
Object.keys(this.getPaths())
|
|
688
|
+
.forEach(
|
|
689
|
+
(tag)=>this.emitData(tag,buffer)
|
|
690
|
+
)
|
|
566
691
|
}
|
|
567
692
|
|
|
568
693
|
/**
|
|
@@ -576,21 +701,10 @@ class BTSensor extends EventEmitter {
|
|
|
576
701
|
listen(){
|
|
577
702
|
try{
|
|
578
703
|
this.initPropertiesChanged()
|
|
579
|
-
this.
|
|
704
|
+
this._propertiesChanged(this.currentProperties)
|
|
580
705
|
} catch(e){
|
|
581
706
|
this.debug(e)
|
|
582
707
|
}
|
|
583
|
-
if (this.usingGATT()){
|
|
584
|
-
this.initGATTConnection().then(async ()=>{
|
|
585
|
-
this.emitGATT()
|
|
586
|
-
if (this.pollFreq){
|
|
587
|
-
this.initGATTInterval()
|
|
588
|
-
}
|
|
589
|
-
else
|
|
590
|
-
await this.initGATTNotifications()
|
|
591
|
-
})
|
|
592
|
-
.catch((e)=>this.debug(`GATT services unavailable for ${this.getName()}. Reason: ${e}`))
|
|
593
|
-
}
|
|
594
708
|
return this
|
|
595
709
|
}
|
|
596
710
|
|
|
@@ -601,12 +715,13 @@ class BTSensor extends EventEmitter {
|
|
|
601
715
|
* Called automatically by Plugin::plugin.stop()
|
|
602
716
|
*/
|
|
603
717
|
|
|
604
|
-
stopListening(){
|
|
718
|
+
async stopListening(){
|
|
605
719
|
this.removeAllListeners()
|
|
606
720
|
this.device.helper.removeListeners()
|
|
607
721
|
if (this.intervalID){
|
|
608
722
|
clearInterval(this.intervalID)
|
|
609
|
-
}
|
|
723
|
+
}
|
|
724
|
+
this._state="ASLEEP"
|
|
610
725
|
}
|
|
611
726
|
//END Sensor listen-to-changes functions
|
|
612
727
|
|
|
@@ -622,6 +737,41 @@ class BTSensor extends EventEmitter {
|
|
|
622
737
|
|
|
623
738
|
}
|
|
624
739
|
//End instance utility functions
|
|
740
|
+
|
|
741
|
+
createPaths(config, id){
|
|
742
|
+
Object.keys(this.getPaths()).forEach((tag)=>{
|
|
743
|
+
const pathMeta=this.getPath(tag)
|
|
744
|
+
const path = config.paths[tag]
|
|
745
|
+
if (!(path===undefined))
|
|
746
|
+
this.app.handleMessage(id,
|
|
747
|
+
{
|
|
748
|
+
updates:
|
|
749
|
+
[{ meta: [{path: preparePath(this, path), value: { units: pathMeta?.unit }}]}]
|
|
750
|
+
})
|
|
751
|
+
})
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
initPaths(deviceConfig, id){
|
|
755
|
+
Object.keys(this.getPaths()).forEach((tag)=>{
|
|
756
|
+
const pathMeta=this.getPath(tag)
|
|
757
|
+
const path = deviceConfig.paths[tag];
|
|
758
|
+
if (!(path === undefined)) {
|
|
759
|
+
this.on(tag, (val)=>{
|
|
760
|
+
if (pathMeta.notify){
|
|
761
|
+
this.app.notify(tag, val, id )
|
|
762
|
+
} else {
|
|
763
|
+
this.updatePath(preparePath(this,path),val,id)
|
|
764
|
+
}
|
|
765
|
+
})
|
|
766
|
+
}
|
|
767
|
+
})
|
|
768
|
+
}
|
|
769
|
+
updatePath(path, val,id){
|
|
770
|
+
this.app.handleMessage(id, {updates: [ { values: [ {path: path, value: val }] } ] })
|
|
771
|
+
}
|
|
772
|
+
elapsedTimeSinceLastContact(){
|
|
773
|
+
return (Date.now()-this?._lastContact??Date.now())/1000
|
|
774
|
+
}
|
|
625
775
|
}
|
|
626
776
|
|
|
627
777
|
module.exports = BTSensor
|
package/README.md
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
# Bluetooth Sensors for [Signal K](http://www.signalk.org)
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Beta 1.0.0
|
|
4
|
+
|
|
5
|
+
Dynamic configuration added (no more screen refreshing necessary).
|
|
4
6
|
|
|
5
7
|
## WHAT IT IS
|
|
6
8
|
|
|
7
9
|
BT Sensors Plugin for Signalk is a lightweight BLE (Bluetooth Low Energy) framework for listening and connecting to Bluetooth sensors on your boat and sending deltas to Signalk paths with the values the sensors reports. <br>
|
|
8
10
|
|
|
9
|
-
The Plugin currently supports every documented Victron device (AC Charger, Battery Monitor, DC-DC Converter, DC Energy Meter, GX Device, Inverter, Inverter RS, Lynx Smart BMS, Orion XS, Smart Battery Protect, Smart Lithium and VE Bus), [Lancol Battery Meters ](https://www.lancol.com/product/12v-bluetooth-4-0-battery-tester-micro-10-c/), [Kilovault HLX+ smart batteries ](https://sunwatts.com/content/manual/KiloVault_HLX_PLUS_Datasheet_06252021%20%281%29.pdf?srsltid=AfmBOooY-cGnC_Qm6V1T9Vg5oZzBCJurS0AOGoWqWeyy-dwz2vA-l1Jb), Xiaomi devices, [ATC devices](https://github.com/atc1441/ATC_MiThermometer), RuuviTags, Renogy BMS, Ultrasonic Wind Meters, SwitchBotTH and Meterplus, Aranet 2/4 environmental sensors, Govee 50/51xx sensors,
|
|
10
|
-
[JBD/Jiabaida/Xiaoxiang Battery management systems](https://jiabaida-bms.com/), IBeacon and clone devices, and Inkbird thermometers.
|
|
11
|
+
The Plugin currently supports every documented Victron device (AC Charger, Battery Monitor, DC-DC Converter, DC Energy Meter, GX Device, Inverter, Inverter RS, Lynx Smart BMS, Orion XS, Smart Battery Protect, Smart Lithium and VE Bus), [Lancol Battery Meters ](https://www.lancol.com/product/12v-bluetooth-4-0-battery-tester-micro-10-c/), [Kilovault HLX+ smart batteries ](https://sunwatts.com/content/manual/KiloVault_HLX_PLUS_Datasheet_06252021%20%281%29.pdf?srsltid=AfmBOooY-cGnC_Qm6V1T9Vg5oZzBCJurS0AOGoWqWeyy-dwz2vA-l1Jb), Xiaomi devices, [ATC devices](https://github.com/atc1441/ATC_MiThermometer), RuuviTags, Renogy BMS, Ultrasonic Wind Meters, SwitchBotTH and Meterplus, Aranet 2/4 environmental sensors, Govee 50/51xx sensors, and Inkbird thermometers.
|
|
11
12
|
|
|
12
13
|
A typical use case is a Bluetooth thermometer like the Xiaomi LYWSD03MMC, an inexpensive Bluetooth thermometer that runs on a 3V watch battery that can report the current temperature and humidity in your refrigerator or cabin or wherever you want to stick it (no judgement.) <br>
|
|
13
14
|
|
|
@@ -15,12 +16,6 @@ The reported temperature can then be displayed on a Signalk app like Kip, Wilhel
|
|
|
15
16
|
|
|
16
17
|
It's pretty easy to write and deploy your own sensor class for any currently unsupported sensor. More on that in [the development README](./sensor_classes/DEVELOPMENT.md).
|
|
17
18
|
|
|
18
|
-
### RENOGY NOTES
|
|
19
|
-
|
|
20
|
-
The class of Renogy Devices cannot be reliably identified from their Bluetooth advertisements. <br>
|
|
21
|
-
|
|
22
|
-
On the plugin config page, You will need to select the device from the Device dropdown, then select the appropriate class from the Class dropdown. After that, you will need to hit the Submit button. On restart of the plugin, the plugin should recognize the device. If you've selected the appropriate class (RenogyRoverClient for example), you should see configs for paths. <br>
|
|
23
|
-
|
|
24
19
|
## WHO IS IT FOR
|
|
25
20
|
|
|
26
21
|
Signalk users with a Linux boat-puter (Windows and MacOS are NOT currently supported) and Bluetooth sensors they'd like to integrate into their Signalk datastream.
|
|
@@ -35,8 +30,9 @@ Signalk users with a Linux boat-puter (Windows and MacOS are NOT currently suppo
|
|
|
35
30
|
|
|
36
31
|
## INSTALLATION
|
|
37
32
|
|
|
38
|
-
|
|
33
|
+
NOTE: If you're running the 1.0.3 release, you will have to reconfigure your devices.<br>
|
|
39
34
|
|
|
35
|
+
### Signalk Appstore
|
|
40
36
|
The plugin is currently available in the Signalk Appstore. <br>
|
|
41
37
|
|
|
42
38
|
### NPM
|
|
@@ -52,6 +48,8 @@ If you want to install directly from source (this is mostly of interest to custo
|
|
|
52
48
|
<pre> cd ~/[some_dir]
|
|
53
49
|
git clone https://github.com/naugehyde/bt-sensors-plugin-sk
|
|
54
50
|
cd bt-sensors-plugin-sk
|
|
51
|
+
git switch '1.1.0'
|
|
52
|
+
git pull
|
|
55
53
|
npm i
|
|
56
54
|
[sudo] npm link
|
|
57
55
|
cd [signalk_home]
|