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/index.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
const fs = require('fs')
|
|
2
|
-
const util = require('util')
|
|
3
|
-
const path = require('path')
|
|
4
|
-
const semver = require('semver')
|
|
5
1
|
const packageInfo = require("./package.json")
|
|
6
2
|
|
|
7
3
|
const {createBluetooth} = require('node-ble')
|
|
@@ -12,6 +8,7 @@ const BTSensor = require('./BTSensor.js')
|
|
|
12
8
|
const BLACKLISTED = require('./sensor_classes/BlackListedDevice.js')
|
|
13
9
|
const { createChannel, createSession } = require("better-sse");
|
|
14
10
|
const { clearTimeout } = require('timers')
|
|
11
|
+
const loadClassMap = require('./classLoader.js')
|
|
15
12
|
|
|
16
13
|
class MissingSensor {
|
|
17
14
|
|
|
@@ -20,12 +17,14 @@ class MissingSensor {
|
|
|
20
17
|
this.config=config
|
|
21
18
|
this.addPath=BTSensor.prototype.addPath.bind(this)
|
|
22
19
|
this.addParameter=BTSensor.prototype.addParameter.bind(this)
|
|
20
|
+
this.addDefaultPath=BTSensor.prototype.addDefaultPath.bind(this)
|
|
21
|
+
this.addDefaultParam=BTSensor.prototype.addDefaultParam.bind(this)
|
|
22
|
+
this.getPath=BTSensor.prototype.getPath.bind(this)
|
|
23
23
|
|
|
24
24
|
this.getJSONSchema = BTSensor.prototype.getJSONSchema.bind(this)
|
|
25
25
|
this.initSchema = BTSensor.prototype.initSchema.bind(this)
|
|
26
26
|
|
|
27
27
|
this.initSchema()
|
|
28
|
-
|
|
29
28
|
var keys = Object.keys(config?.paths??{})
|
|
30
29
|
|
|
31
30
|
keys.forEach((key)=>{
|
|
@@ -47,6 +46,13 @@ class MissingSensor {
|
|
|
47
46
|
hasGATT(){
|
|
48
47
|
return this.config.gattParams
|
|
49
48
|
}
|
|
49
|
+
initGATTConnection(){
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
getGATTDescription(){
|
|
54
|
+
return ""
|
|
55
|
+
}
|
|
50
56
|
getMetadata(){
|
|
51
57
|
return this.metadata
|
|
52
58
|
}
|
|
@@ -79,66 +85,14 @@ class MissingSensor {
|
|
|
79
85
|
|
|
80
86
|
}
|
|
81
87
|
module.exports = function (app) {
|
|
82
|
-
var adapterID = 'hci0'
|
|
83
|
-
|
|
84
|
-
|
|
85
88
|
var deviceConfigs
|
|
86
89
|
var starts=0
|
|
87
|
-
var classMap
|
|
88
|
-
|
|
89
|
-
var utilities_sk
|
|
90
90
|
|
|
91
91
|
var plugin = {};
|
|
92
92
|
plugin.id = 'bt-sensors-plugin-sk';
|
|
93
93
|
plugin.name = 'BT Sensors plugin';
|
|
94
94
|
plugin.description = 'Plugin to communicate with and update paths to BLE Sensors in Signalk';
|
|
95
95
|
|
|
96
|
-
//Try and load utilities-sk NOTE: should be installed from App Store--
|
|
97
|
-
//But there's a fail safe because I'm a reasonable man.
|
|
98
|
-
|
|
99
|
-
utilities_sk = {
|
|
100
|
-
loadClasses: function(dir, ext='.js')
|
|
101
|
-
{
|
|
102
|
-
const classMap = new Map()
|
|
103
|
-
const classFiles = fs.readdirSync(dir)
|
|
104
|
-
.filter(file => file.endsWith(ext));
|
|
105
|
-
|
|
106
|
-
classFiles.forEach(file => {
|
|
107
|
-
const filePath = path.join(dir, file);
|
|
108
|
-
const cls = require(filePath);
|
|
109
|
-
classMap.set(cls.name, cls);
|
|
110
|
-
})
|
|
111
|
-
return classMap
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function sleep(x) {
|
|
116
|
-
return new Promise((resolve) => {
|
|
117
|
-
setTimeout(() => {
|
|
118
|
-
resolve(x);
|
|
119
|
-
}, x);
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function loadClassMap() {
|
|
124
|
-
const _classMap = utilities_sk.loadClasses(path.join(__dirname, 'sensor_classes'))
|
|
125
|
-
classMap = new Map([..._classMap].filter(([k, v]) => !k.startsWith("_") ))
|
|
126
|
-
const libPath = app.config.appPath +(
|
|
127
|
-
semver.gt(app.config.version,"2.13.5")?"dist":"lib"
|
|
128
|
-
)
|
|
129
|
-
import(libPath+"/modules.js").then( (modulesjs)=>{
|
|
130
|
-
const { default:defaultExport} = modulesjs
|
|
131
|
-
const modules = defaultExport.modulesWithKeyword(app.config, "signalk-bt-sensor-class")
|
|
132
|
-
modules.forEach((module)=>{
|
|
133
|
-
module.metadata.classFiles.forEach((classFile)=>{
|
|
134
|
-
const cls = require(module.location+module.module+"/"+classFile);
|
|
135
|
-
classMap.set(cls.name, cls);
|
|
136
|
-
})
|
|
137
|
-
})
|
|
138
|
-
classMap.get('UNKNOWN').classMap=new Map([...classMap].sort().filter(([k, v]) => !v.isSystem )) // share the classMap with Unknown for configuration purposes
|
|
139
|
-
})
|
|
140
|
-
}
|
|
141
|
-
|
|
142
96
|
app.debug(`Loading plugin ${packageInfo.version}`)
|
|
143
97
|
|
|
144
98
|
plugin.schema = {
|
|
@@ -162,17 +116,17 @@ module.exports = function (app) {
|
|
|
162
116
|
}
|
|
163
117
|
}
|
|
164
118
|
|
|
165
|
-
const sensorMap=new Map()
|
|
166
119
|
|
|
167
120
|
plugin.started=false
|
|
168
|
-
|
|
169
|
-
loadClassMap()
|
|
121
|
+
|
|
170
122
|
var discoveryIntervalID, progressID, progressTimeoutID, deviceHealthID
|
|
171
123
|
var adapter
|
|
172
|
-
var adapterPower
|
|
173
124
|
const channel = createChannel()
|
|
125
|
+
const classMap = loadClassMap(app)
|
|
126
|
+
const sensorMap=new Map()
|
|
174
127
|
|
|
175
|
-
|
|
128
|
+
|
|
129
|
+
/* plugin.registerWithRouter = function(router) {
|
|
176
130
|
router.get('/sendPluginState', async (req, res) => {
|
|
177
131
|
|
|
178
132
|
res.status(200).json({
|
|
@@ -184,18 +138,25 @@ module.exports = function (app) {
|
|
|
184
138
|
channel.register(session)
|
|
185
139
|
});
|
|
186
140
|
|
|
187
|
-
}
|
|
141
|
+
}*/
|
|
188
142
|
|
|
189
143
|
plugin.start = async function (options, restartPlugin) {
|
|
190
144
|
plugin.started=true
|
|
191
145
|
var adapterID=options.adapter
|
|
192
146
|
var foundConfiguredDevices=0
|
|
147
|
+
|
|
193
148
|
plugin.registerWithRouter = function(router) {
|
|
194
149
|
|
|
195
|
-
router.post('/
|
|
150
|
+
router.post('/updateSensorData', async (req, res) => {
|
|
196
151
|
app.debug(req.body)
|
|
197
152
|
const i = deviceConfigs.findIndex((p)=>p.mac_address==req.body.mac_address)
|
|
198
153
|
if (i<0){
|
|
154
|
+
if (!options.peripherals){
|
|
155
|
+
if (!options.hasOwnProperty("peripherals"))
|
|
156
|
+
options.peripherals=[]
|
|
157
|
+
|
|
158
|
+
options.peripherals=[]
|
|
159
|
+
}
|
|
199
160
|
options.peripherals.push(req.body)
|
|
200
161
|
} else {
|
|
201
162
|
options.peripherals[i] = req.body
|
|
@@ -207,13 +168,9 @@ module.exports = function (app) {
|
|
|
207
168
|
const sensor = sensorMap.get(req.body.mac_address)
|
|
208
169
|
if (sensor) {
|
|
209
170
|
removeSensorFromList(sensor)
|
|
210
|
-
if (sensor.isActive())
|
|
211
|
-
sensor.stopListening()
|
|
212
|
-
|
|
213
|
-
)
|
|
214
|
-
} else {
|
|
215
|
-
initConfiguredDevice(req.body)
|
|
216
|
-
}
|
|
171
|
+
if (sensor.isActive())
|
|
172
|
+
await sensor.stopListening()
|
|
173
|
+
initConfiguredDevice(req.body)
|
|
217
174
|
}
|
|
218
175
|
|
|
219
176
|
}
|
|
@@ -229,7 +186,7 @@ module.exports = function (app) {
|
|
|
229
186
|
if (sensorMap.has(req.body.mac_address))
|
|
230
187
|
sensorMap.delete(req.body.mac_address)
|
|
231
188
|
app.savePluginOptions(
|
|
232
|
-
options,
|
|
189
|
+
options, () => {
|
|
233
190
|
app.debug('Plugin options saved')
|
|
234
191
|
res.status(200).json({message: "Sensor updated"})
|
|
235
192
|
channel.broadcast({},"resetSensors")
|
|
@@ -238,7 +195,7 @@ module.exports = function (app) {
|
|
|
238
195
|
|
|
239
196
|
});
|
|
240
197
|
|
|
241
|
-
router.post('/
|
|
198
|
+
router.post('/updateBaseData', async (req, res) => {
|
|
242
199
|
|
|
243
200
|
app.debug(req.body)
|
|
244
201
|
Object.assign(options,req.body)
|
|
@@ -253,7 +210,7 @@ module.exports = function (app) {
|
|
|
253
210
|
});
|
|
254
211
|
|
|
255
212
|
|
|
256
|
-
router.get('/
|
|
213
|
+
router.get('/getBaseData', (req, res) => {
|
|
257
214
|
|
|
258
215
|
res.status(200).json(
|
|
259
216
|
{
|
|
@@ -267,13 +224,13 @@ module.exports = function (app) {
|
|
|
267
224
|
}
|
|
268
225
|
);
|
|
269
226
|
})
|
|
270
|
-
router.get('/
|
|
227
|
+
router.get('/getSensors', (req, res) => {
|
|
271
228
|
app.debug("Sending sensors")
|
|
272
229
|
const t = sensorsToJSON()
|
|
273
230
|
res.status(200).json(t)
|
|
274
231
|
});
|
|
275
232
|
|
|
276
|
-
router.get('/
|
|
233
|
+
router.get('/getProgress', (req, res) => {
|
|
277
234
|
app.debug("Sending progress")
|
|
278
235
|
const json = {"progress":foundConfiguredDevices/deviceConfigs.length, "maxTimeout": 1,
|
|
279
236
|
"deviceCount":foundConfiguredDevices,
|
|
@@ -282,7 +239,7 @@ module.exports = function (app) {
|
|
|
282
239
|
|
|
283
240
|
});
|
|
284
241
|
|
|
285
|
-
router.get('/
|
|
242
|
+
router.get('/getPluginState', async (req, res) => {
|
|
286
243
|
|
|
287
244
|
res.status(200).json({
|
|
288
245
|
"state":(plugin.started?"started":"stopped")
|
|
@@ -304,13 +261,13 @@ module.exports = function (app) {
|
|
|
304
261
|
}
|
|
305
262
|
|
|
306
263
|
function getSensorInfo(sensor){
|
|
307
|
-
|
|
308
|
-
|
|
264
|
+
|
|
265
|
+
const etslc = sensor.elapsedTimeSinceLastContact()
|
|
309
266
|
return { mac: sensor.getMacAddress(),
|
|
310
267
|
name: sensor.getName(),
|
|
311
268
|
RSSI: sensor.getRSSI(),
|
|
312
269
|
signalStrength: sensor.getSignalStrength(),
|
|
313
|
-
lastContactDelta:
|
|
270
|
+
lastContactDelta: etslc
|
|
314
271
|
}
|
|
315
272
|
}
|
|
316
273
|
|
|
@@ -354,7 +311,7 @@ module.exports = function (app) {
|
|
|
354
311
|
channel.broadcast({mac:sensor.getMacAddress()},"removesensor")
|
|
355
312
|
}
|
|
356
313
|
|
|
357
|
-
|
|
314
|
+
function addSensorToList(sensor){
|
|
358
315
|
app.debug(`adding sensor to list ${sensor.getMacAddress()}`)
|
|
359
316
|
if (sensorMap.has(sensor.getMacAddress()) )
|
|
360
317
|
debugger
|
|
@@ -365,15 +322,14 @@ module.exports = function (app) {
|
|
|
365
322
|
return `${config?.name??""}${config.name?" at ":""}${config.mac_address}`
|
|
366
323
|
}
|
|
367
324
|
|
|
368
|
-
|
|
325
|
+
function createSensor(adapter, config) {
|
|
369
326
|
return new Promise( ( resolve, reject )=>{
|
|
370
327
|
var s
|
|
371
328
|
const startNumber=starts
|
|
372
329
|
//app.debug(`Waiting on ${deviceNameAndAddress(config)}`)
|
|
373
|
-
adapter.waitDevice(config.mac_address,config
|
|
330
|
+
adapter.waitDevice(config.mac_address,(config?.discoveryTimeout??30)*1000)
|
|
374
331
|
.then(async (device)=> {
|
|
375
332
|
if (startNumber != starts ) {
|
|
376
|
-
debugger
|
|
377
333
|
return
|
|
378
334
|
}
|
|
379
335
|
//app.debug(`Found ${config.mac_address}`)
|
|
@@ -382,10 +338,15 @@ module.exports = function (app) {
|
|
|
382
338
|
if (s instanceof BLACKLISTED)
|
|
383
339
|
reject ( `Device is blacklisted (${s.reasonForBlacklisting()}).`)
|
|
384
340
|
else{
|
|
385
|
-
|
|
386
341
|
addSensorToList(s)
|
|
342
|
+
s._lastRSSI=-1*Infinity
|
|
387
343
|
s.on("RSSI",(()=>{
|
|
388
|
-
|
|
344
|
+
if (Date.now()-s._lastRSSI > 20000) { //only update RSSI on client every five seconds
|
|
345
|
+
//app.debug(`${s.getMacAddress()} ${Date.now()-s._lastRSSI}`)
|
|
346
|
+
s._lastRSSI=Date.now()
|
|
347
|
+
updateSensor(s)
|
|
348
|
+
}
|
|
349
|
+
|
|
389
350
|
}))
|
|
390
351
|
resolve(s)
|
|
391
352
|
}
|
|
@@ -413,6 +374,8 @@ module.exports = function (app) {
|
|
|
413
374
|
const sensor = new c(device,config?.params, config?.gattParams)
|
|
414
375
|
sensor.debug=app.debug
|
|
415
376
|
sensor.app=app
|
|
377
|
+
sensor._adapter=adapter //HACK!
|
|
378
|
+
|
|
416
379
|
await sensor.init()
|
|
417
380
|
//app.debug(`instantiated ${await BTSensor.getDeviceProp(device,"Address")}`)
|
|
418
381
|
|
|
@@ -425,17 +388,17 @@ module.exports = function (app) {
|
|
|
425
388
|
app.setPluginError(msg)
|
|
426
389
|
}
|
|
427
390
|
//if we're here ain't got no class for the device
|
|
428
|
-
var sensor
|
|
391
|
+
var sensor
|
|
429
392
|
if (config.params?.sensorClass){
|
|
430
|
-
|
|
431
|
-
c.debug=app.debug
|
|
432
|
-
sensor = new c(device,config?.params, config?.gattParams)
|
|
433
|
-
sensor.debug=app.debug
|
|
434
|
-
sensor.app=app
|
|
393
|
+
var c = classMap.get(config.params.sensorClass)
|
|
435
394
|
} else{
|
|
436
|
-
|
|
437
|
-
sensor.app=app
|
|
395
|
+
c = classMap.get('UNKNOWN')
|
|
438
396
|
}
|
|
397
|
+
c.debug=app.debug
|
|
398
|
+
sensor = new c(device,config?.params, config?.gattParams)
|
|
399
|
+
sensor.debug=app.debug
|
|
400
|
+
sensor.app=app
|
|
401
|
+
|
|
439
402
|
await sensor.init()
|
|
440
403
|
return sensor
|
|
441
404
|
}
|
|
@@ -510,7 +473,9 @@ module.exports = function (app) {
|
|
|
510
473
|
setInterval( findDevices, discoveryInterval*1000, discoveryTimeout)
|
|
511
474
|
}
|
|
512
475
|
|
|
513
|
-
|
|
476
|
+
channel.broadcast({state:"started"},"pluginstate")
|
|
477
|
+
|
|
478
|
+
|
|
514
479
|
if (!adapterID || adapterID=="")
|
|
515
480
|
adapterID = "hci0"
|
|
516
481
|
//Check if Adapter has changed since last start()
|
|
@@ -547,12 +512,10 @@ module.exports = function (app) {
|
|
|
547
512
|
if (!await adapter.isPowered()) {
|
|
548
513
|
app.debug(`Bluetooth Adapter ${adapterID} not powered on.`)
|
|
549
514
|
app.setPluginError(`Bluetooth Adapter ${adapterID} not powered on.`)
|
|
550
|
-
adapterPower=false
|
|
551
515
|
await plugin.stop()
|
|
552
516
|
return
|
|
553
517
|
}
|
|
554
518
|
}
|
|
555
|
-
adapterPower=true
|
|
556
519
|
|
|
557
520
|
sensorMap.clear()
|
|
558
521
|
if (channel)
|
|
@@ -560,9 +523,6 @@ module.exports = function (app) {
|
|
|
560
523
|
deviceConfigs=options?.peripherals??[]
|
|
561
524
|
|
|
562
525
|
if (plugin.stopped) {
|
|
563
|
-
//await sleep(5000) //Make sure plugin.stop() completes first
|
|
564
|
-
//plugin.start is called asynchronously for some reason
|
|
565
|
-
//and does not wait for plugin.stop to complete
|
|
566
526
|
plugin.stopped=false
|
|
567
527
|
}
|
|
568
528
|
|
|
@@ -618,19 +578,25 @@ module.exports = function (app) {
|
|
|
618
578
|
}
|
|
619
579
|
}
|
|
620
580
|
const minTimeout=Math.min(...deviceConfigs.map((dc)=>dc?.discoveryTimeout??options.discoveryTimeout))
|
|
621
|
-
|
|
581
|
+
const intervalTimeout = ((minTimeout==Infinity)?(options?.discoveryTimeout??plugin.schema.properties.discoveryTimeout.default):minTimeout)*1000
|
|
622
582
|
deviceHealthID = setInterval( ()=> {
|
|
623
583
|
sensorMap.forEach((sensor)=>{
|
|
624
584
|
const config = getDeviceConfig(sensor.getMacAddress())
|
|
625
585
|
const dt = config?.discoveryTimeout??options.discoveryTimeout
|
|
626
|
-
|
|
586
|
+
const lc=sensor.elapsedTimeSinceLastContact()
|
|
587
|
+
if (lc > dt) {
|
|
588
|
+
app.debug(`${sensor.getMacAddress()} not heard from in ${lc} seconds`)
|
|
627
589
|
channel.broadcast(getSensorInfo(sensor), "sensorchanged")
|
|
590
|
+
}
|
|
628
591
|
})
|
|
629
|
-
},
|
|
592
|
+
}, intervalTimeout)
|
|
630
593
|
|
|
594
|
+
if (!options.hasOwnProperty("discoveryInterval" )) //no config -- first run
|
|
595
|
+
options.discoveryInterval = plugin.schema.properties.discoveryInterval.default
|
|
596
|
+
|
|
631
597
|
if (options.discoveryInterval && !discoveryIntervalID)
|
|
632
|
-
findDeviceLoop(options.discoveryTimeout,
|
|
633
|
-
|
|
598
|
+
findDeviceLoop(options?.discoveryTimeout??plugin.schema.properties.discoveryTimeout.default,
|
|
599
|
+
options.discoveryInterval)
|
|
634
600
|
}
|
|
635
601
|
plugin.stop = async function () {
|
|
636
602
|
app.debug("Stopping plugin")
|
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.
|
|
3
|
+
"version": "1.2.0-beta.0.0.10",
|
|
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": {
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"signalk-category-hardware",
|
|
66
66
|
"signalk-plugin-configurator"
|
|
67
67
|
],
|
|
68
|
+
"signalk-plugin-enabled-by-default": true,
|
|
68
69
|
"author": "Andrew Gerngross",
|
|
69
70
|
"license": "ISC",
|
|
70
71
|
"bugs": {
|
package/plugin_defaults.json
CHANGED
|
@@ -6,29 +6,118 @@
|
|
|
6
6
|
"location":{
|
|
7
7
|
"description": "Sensor location",
|
|
8
8
|
"examples": ["inside", "outside", "galley", "freezer", "refrigerator", "head", "cabin", "engine", "deck", "cockpit"]
|
|
9
|
+
},
|
|
10
|
+
"zone":{
|
|
11
|
+
"description": "Zone where sensor operates on boat AKA location ",
|
|
12
|
+
"examples": ["inside", "outside", "galley", "freezer", "refrigerator", "head", "cabin", "engine", "deck", "cockpit"]
|
|
13
|
+
},
|
|
14
|
+
"batteryID":{
|
|
15
|
+
"description": "Battery ID",
|
|
16
|
+
"examples": ["starter", "house"]
|
|
17
|
+
},
|
|
18
|
+
"id":{
|
|
19
|
+
"description": "Sensor ID"
|
|
9
20
|
}
|
|
10
21
|
},
|
|
11
22
|
"environment":{
|
|
12
|
-
"temperature":
|
|
23
|
+
"temperature":
|
|
13
24
|
{
|
|
25
|
+
"title":"Current zone's temperature",
|
|
14
26
|
"unit":"K",
|
|
15
|
-
"default": "environment.{
|
|
27
|
+
"default": "environment.{zone}.temperature"
|
|
16
28
|
},
|
|
17
29
|
"humidity":
|
|
18
30
|
{
|
|
19
31
|
"unit":"ratio",
|
|
20
|
-
"default":"environment.{
|
|
32
|
+
"default":"environment.{zone}.humidity"
|
|
33
|
+
},
|
|
34
|
+
"relativeHumidity":
|
|
35
|
+
{
|
|
36
|
+
"title":"Current zone's relative humidity",
|
|
37
|
+
"unit":"ratio",
|
|
38
|
+
"default":"environment.{zone}.relativeHumidity"
|
|
39
|
+
},
|
|
40
|
+
"pressure":
|
|
41
|
+
{
|
|
42
|
+
"title": "Current zone's ambient air pressure",
|
|
43
|
+
"unit":"Pa",
|
|
44
|
+
"default":"environment.{zone}.pressure"
|
|
21
45
|
}
|
|
22
46
|
},
|
|
23
47
|
"electrical":{
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
|
|
48
|
+
"inverters":{
|
|
49
|
+
"ac":{
|
|
50
|
+
"current":{
|
|
51
|
+
"unit": "A",
|
|
52
|
+
"default":"electrical.inverters.{id}.ac.current"
|
|
53
|
+
},
|
|
54
|
+
"voltage":
|
|
55
|
+
{
|
|
56
|
+
"unit": "V",
|
|
57
|
+
"default":"electrical.inverters.{id}.ac.voltage"
|
|
58
|
+
},
|
|
59
|
+
"power":
|
|
60
|
+
{
|
|
61
|
+
"unit": "W",
|
|
62
|
+
"default":"electrical.inverters.{id}.ac.power"
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
},
|
|
67
|
+
"dc":{
|
|
68
|
+
"current":{
|
|
69
|
+
"unit": "A",
|
|
70
|
+
"default":"electrical.inverters.{id}.dc.current"
|
|
71
|
+
},
|
|
72
|
+
"voltage":
|
|
73
|
+
{
|
|
74
|
+
"unit": "V",
|
|
75
|
+
"default":"electrical.inverters.{id}.dc.voltage"
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
}
|
|
27
79
|
},
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
|
|
80
|
+
"batteries":{
|
|
81
|
+
|
|
82
|
+
"current":{
|
|
83
|
+
"unit": "A",
|
|
84
|
+
"default":"electrical.batteries.{batteryID}.current"
|
|
85
|
+
},
|
|
86
|
+
"voltage":
|
|
87
|
+
{
|
|
88
|
+
"unit": "V",
|
|
89
|
+
"default": "electrical.batteries.{batteryID}.voltage"
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
"temperature":{
|
|
93
|
+
"unit": "K",
|
|
94
|
+
"default": "electrical.batteries.{batteryID}.temperature"
|
|
95
|
+
},
|
|
96
|
+
"cycles":{
|
|
97
|
+
"unit": "",
|
|
98
|
+
"default": "electrical.batteries.{batteryID}.cycles"
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
"capacity":{
|
|
102
|
+
"remaining":{
|
|
103
|
+
"unit":"Ah",
|
|
104
|
+
"default": "electrical.batteries.{batteryID}.capacity.remaining"
|
|
105
|
+
},
|
|
106
|
+
"actual":{
|
|
107
|
+
"unit":"Ah",
|
|
108
|
+
"default": "electrical.batteries.{batteryID}.capacity.actual"
|
|
109
|
+
},
|
|
110
|
+
"stateOfCharge":{
|
|
111
|
+
"unit":"ratio",
|
|
112
|
+
"default": "electrical.batteries.{batteryID}.capacity.stateOfCharge"
|
|
113
|
+
},
|
|
114
|
+
"timeRemaining":{
|
|
115
|
+
"unit":"s",
|
|
116
|
+
"default": "electrical.batteries.{batteryID}.capacity.timeRemaining"
|
|
117
|
+
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
32
121
|
}
|
|
33
122
|
},
|
|
34
123
|
"sensors":{
|
package/public/893.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";(self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[]).push([[893],{2995:(e,t,n)=>{n.r(t),n.d(t,{default:()=>v});var a=n(3490),s=n(4810),o=n(4147),r=n.n(o),l=n(7606),c=n(4952),i=n(3768),u=n(1431),
|
|
1
|
+
"use strict";(self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[]).push([[893],{2995:(e,t,n)=>{n.r(t),n.d(t,{default:()=>v});var a=n(3490),s=n(4810),o=n(4147),r=n.n(o),l=n(7606),c=n(4952),i=n(3768),u=n(1431),g=n(9676),d=n(7041),m=n(3657),f=n(5027),p=n(7265),h=n(6890),E=n(8207);const w=e=>console.log.bind(console,e);var S;const v=e=>{const[t,n]=(0,o.useState)({}),[v,b]=(0,o.useState)({}),[y,D]=(0,o.useState)({}),[A,$]=(0,o.useState)({"ui:submitButtonOptions":{props:{disabled:!1,className:"btn btn-info"},norender:!0,submitText:"Submit"}}),[k,_]=(0,o.useState)([]),[x,C]=(0,o.useState)(),[T,M]=(0,o.useState)(new Map),[j,O]=(0,o.useState)({progress:0,maxTimeout:100,deviceCount:0,totalDevices:0}),[N,B]=(0,o.useState)("unknown"),[J,L]=(0,o.useState)();function U(e,t){console.log(`sending ${e}`),console.log(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 P(e){return console.log(`fetching ${e}`),fetch(`/plugins/bt-sensors-plugin-sk/${e}`,{credentials:"include"})}async function z(){console.log("getProgress");const e=await P("getProgress");if(200!=e.status)throw new Error(`Unable get progres: ${e.statusText} (${e.status}) `);const t=await e.json();return console.log(t),t}function H(){console.log("refreshing sensor map"),async function(){console.log("getSensors");const e=await P("getSensors");if(200!=e.status)throw new Error(`Unable get sensor data: ${e.statusText} (${e.status}) `);const t=await e.json();return console.log(t),t}().then((e=>{M(new Map(e.map((e=>[e.info.mac,e]))))})).catch((e=>{L(e)}))}return(0,o.useEffect)((()=>{console.log("useEffect([])"),P("getPluginState").then((async e=>{if(404==e.status)throw B("unknown"),new Error("unable to get plugin state");const t=await e.json();B(t.state),console.log("Setting up eventsource");const n=new EventSource("/plugins/bt-sensors-plugin-sk/sse");return n.addEventListener("newsensor",(e=>{console.log("newsensor");let t=JSON.parse(e.data);S.has(t.info.mac)||(console.log(`New sensor: ${t.info.mac}`),M(new Map(S.set(t.info.mac,t))))})),n.addEventListener("sensorchanged",(e=>{let t=JSON.parse(e.data);if(console.log("sensorchanged"),console.log(t),S.has(t.mac)){let e=S.get(t.mac);Object.assign(e.info,t),M(new Map(S))}})),n.addEventListener("progress",(e=>{console.log("progress");const t=JSON.parse(e.data);O(t),console.log(t)})),n.addEventListener("pluginstate",(e=>{console.log("pluginstate");const t=JSON.parse(e.data);B(t.state)})),()=>n.close()})).catch((e=>{L(e)}))}),[]),(0,o.useEffect)((()=>{console.log("useEffect([pluginState])"),"started"==N?(H(),async function(){console.log("getBaseData");const e=await P("getBaseData");if(200!=e.status)throw new Error(`Unable get base data: ${e.statusText} (${e.status}) `);const t=await e.json();return console.log(t),t}().then((e=>{n(e.schema),b(e.data)})).catch((e=>{L(e)})),z().then((e=>{O(e)})).catch((e=>{L(e)}))):(M(new Map),n({}),b({}))}),[N]),(0,o.useEffect)((()=>{console.log("useEffect([sensorMap])"),S=T,_(Array.from(T.entries()).map((e=>{const t=T.get(e[0]),n=t.config,a=Object.keys(n).length>0;return r().createElement(h.A,{action:!0,onClick:()=>{t&&(n.mac_address=e[0],D(t.schema),C(n))}},r().createElement("div",{class:"d-flex justify-content-between align-items-center",style:a?{fontWeight:"normal"}:{fontStyle:"italic"}},`${t._changesMade?"*":""}${t.info.name} MAC: ${t.info.mac} RSSI: ${s=t.info.RSSI,null==s?NaN:s}`,r().createElement("div",{class:"d-flex justify-content-between "},function(e){return null==e.info.lastContactDelta||e.info.lastContactDelta>e.config.discoveryTimeout?r().createElement(i.A,null):e.info.signalStrength>80?r().createElement(u.A,null):e.info.signalStrength>60?r().createElement(g.A,null):e.info.signalStrength>40?r().createElement(d.A,null):e.info.signalStrength>20?r().createElement(m.A,null):r().createElement(f.A,null)}(t))));var s})))}),[T]),"stopped"==N||"unknown"==N?r().createElement("h1",null,"Enable plugin to see configuration (if plugin is Enabled and you're seeing this message, restart SignalK)"):r().createElement("div",null,J?r().createElement("h2",{style:"color: red;"},J):"",r().createElement(a.Ay,{schema:t,validator:s.Ay,onChange:e=>b(e.formData),onSubmit:({formData:e},t)=>{var n;C(null),n=e,console.log("updateBaseData"),U("updateBaseData",n).then((e=>{200!=e.status?L(new Error(`Unable to update base data: ${e.statusText} (${e.status})`)):(z().then((e=>{O(e)})).catch((e=>{L(e)})),H())}))},onError:w("errors"),formData:v}),r().createElement("p",null),r().createElement("p",null),j.deviceCount<j.totalDevices?r().createElement(E.A,{max:j.maxTimeout,now:j.progress}):"",r().createElement("h2",null,T.size>0?"Bluetooth Devices - Select to configure":""),r().createElement("h2",null,T.size>0?"(* = sensor has unsaved changes)":""),r().createElement("p",null),r().createElement("div",{style:{paddingBottom:20},class:"d-flex flex-wrap justify-content-start align-items-start"},r().createElement(p.A,{style:{maxHeight:"300px",overflowY:"auto"}},k),r().createElement("div",{style:{paddingLeft:10,paddingTop:10,display:0==Object.keys(y).length?"none":""}},r().createElement(a.Ay,{schema:y,validator:s.Ay,uiSchema:A,onChange:e=>{T.get(e.formData.mac_address)._changesMade=!0,C(e.formData)},onSubmit:({formData:e},t)=>{var n;console.log(e),n=e,console.log("updateSensorData"),U("updateSensorData",n).then((e=>{if(200!=e.status)throw new Error(e.statusText);T.get(n.mac_address)._changesMade=!1,T.get(n.mac_address).config=n})),D({}),alert("Changes saved")},onError:w("errors"),formData:x},r().createElement("div",null,r().createElement(l.A,{direction:"row",style:{spacing:5}},r().createElement(c.A,{type:"submit",color:"primary",variant:"contained"},"Save"),r().createElement(c.A,{variant:"contained",onClick:()=>{var e;e=x.mac_address,console.log("undoChanges"),T.get(e)._changesMade=!1,C(T.get(e).config)}},"Undo"),r().createElement(c.A,{variant:"contained",color:"secondary",onClick:e=>{return t=x.mac_address,void(window.confirm(`Delete configuration for ${t}?`)&&function(e){console.log("removeSensorData");try{U("removeSensorData",{mac_address:e}).then((e=>{if(200!=e.status)throw new Error(e.statusText)})),S.delete(e),M(new Map(S)),D({})}catch{}}(t));var t}},"Delete")))))))}}}]);
|
package/sensor_classes/ATC.js
CHANGED
|
@@ -23,15 +23,17 @@ class ATC extends BTSensor{
|
|
|
23
23
|
{
|
|
24
24
|
title:'data parsing strategy',
|
|
25
25
|
type: 'string',
|
|
26
|
-
enum:["ATC-LE","ATC-BE"]
|
|
26
|
+
enum:["ATC-LE","ATC-BE"],
|
|
27
|
+
default: ["ATC-LE"]
|
|
27
28
|
}
|
|
28
29
|
)
|
|
29
30
|
if (!this.parser){
|
|
30
31
|
this.parser="ATC-LE"
|
|
31
32
|
}
|
|
32
|
-
this.initMetadata()
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
initSchema(){
|
|
35
|
+
super.initSchema()
|
|
36
|
+
this.addDefaultParam("zone")
|
|
35
37
|
|
|
36
38
|
this.addDefaultPath('batteryStrength','sensors.batteryStrength')
|
|
37
39
|
.read=(buff)=>{return ((buff.readUInt8(12))/100)}
|
|
@@ -13,25 +13,26 @@ class Aranet2 extends AranetSensor{
|
|
|
13
13
|
return null //not supported for now
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
async init() {
|
|
17
|
-
await super.init()
|
|
18
|
-
this.initMetadata()
|
|
19
|
-
}
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
initSchema(){
|
|
18
|
+
super.initSchema()
|
|
19
|
+
|
|
20
|
+
this.addMetadatum('co2', 'ppm', 'co2 concentration in zone',
|
|
23
21
|
(buff)=>{return ((buff.readUInt16LE(8)))})
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
.default="environment.{zone}.co2"
|
|
23
|
+
|
|
24
|
+
this.addDefaultPath('temp', 'environment.temperature')
|
|
25
|
+
.read=(buff)=>{return parseFloat((273.15+(buff.readInt16LBE(15))/1000).toFixed(2))}
|
|
26
26
|
|
|
27
|
-
this.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
this.addDefaultPath('pressure', 'environment.pressure')
|
|
28
|
+
.read= (buff)=>{return ((buff.readUInt16LE(13)))/10}
|
|
29
|
+
|
|
30
|
+
this.addDefaultPath('relativeHumidity','environment.relativeHumidity')
|
|
31
|
+
.read=(buff)=>{return ((buff.readUInt16LE(8))/10000)}
|
|
32
|
+
|
|
33
|
+
this.addDefaultPath("battery","sensors.batteryStrength")
|
|
34
|
+
.read=(buff)=>{return ((buff.readUInt8(12))/100)}
|
|
31
35
|
|
|
32
|
-
this.addMetadatum('humidity','ratio', 'humidity',
|
|
33
|
-
(buff)=>{return ((buff.readUInt16LE(8))/10000)})
|
|
34
|
-
|
|
35
36
|
}
|
|
36
37
|
propertiesChanged(props){
|
|
37
38
|
super.propertiesChanged(props)
|