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.
Files changed (45) hide show
  1. package/.vscode/launch.json +7 -0
  2. package/BTSensor.js +57 -11
  3. package/Queue.js +48 -0
  4. package/README.md +34 -12
  5. package/classLoader.js +38 -0
  6. package/index.js +71 -105
  7. package/package.json +2 -1
  8. package/plugin_defaults.json +99 -10
  9. package/public/893.js +1 -1
  10. package/sensor_classes/ATC.js +5 -3
  11. package/sensor_classes/Aranet/AranetSensor.js +4 -0
  12. package/sensor_classes/Aranet2.js +16 -15
  13. package/sensor_classes/Aranet4.js +23 -17
  14. package/sensor_classes/GoveeH50xx.js +12 -12
  15. package/sensor_classes/GoveeH510x.js +4 -5
  16. package/sensor_classes/IBeacon.js +13 -9
  17. package/sensor_classes/Inkbird.js +4 -2
  18. package/sensor_classes/JBDBMS.js +33 -25
  19. package/sensor_classes/KilovaultHLXPlus.js +33 -16
  20. package/sensor_classes/LancolVoltageMeter.js +4 -3
  21. package/sensor_classes/MopekaTankSensor.js +19 -10
  22. package/sensor_classes/Renogy/RenogySensor.js +1 -1
  23. package/sensor_classes/RenogyBattery.js +15 -13
  24. package/sensor_classes/RenogyRoverClient.js +2 -3
  25. package/sensor_classes/RuuviTag.js +36 -27
  26. package/sensor_classes/ShellySBHT003C.js +19 -22
  27. package/sensor_classes/SwitchBotMeterPlus.js +10 -12
  28. package/sensor_classes/SwitchBotTH.js +13 -16
  29. package/sensor_classes/UltrasonicWindMeter.js +13 -5
  30. package/sensor_classes/VictronACCharger.js +19 -8
  31. package/sensor_classes/VictronBatteryMonitor.js +41 -24
  32. package/sensor_classes/VictronDCDCConverter.js +14 -5
  33. package/sensor_classes/VictronDCEnergyMeter.js +26 -7
  34. package/sensor_classes/VictronGXDevice.js +2 -5
  35. package/sensor_classes/VictronInverter.js +18 -14
  36. package/sensor_classes/VictronInverterRS.js +18 -7
  37. package/sensor_classes/VictronLynxSmartBMS.js +15 -13
  38. package/sensor_classes/VictronOrionXS.js +15 -3
  39. package/sensor_classes/VictronSmartBatteryProtect.js +5 -6
  40. package/sensor_classes/VictronSmartLithium.js +18 -18
  41. package/sensor_classes/VictronSolarCharger.js +31 -18
  42. package/sensor_classes/VictronVEBus.js +2 -5
  43. package/sensor_classes/XiaomiMiBeacon.js +20 -19
  44. package/src/components/PluginConfigurationPanel.js +52 -27
  45. 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
- plugin.registerWithRouter = function(router) {
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('/sendSensorData', async (req, res) => {
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().then(()=>
212
- initConfiguredDevice(req.body)
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, async () => {
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('/sendBaseData', async (req, res) => {
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('/base', (req, res) => {
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('/sensors', (req, res) => {
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('/progress', (req, res) => {
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('/sendPluginState', async (req, res) => {
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
- if (sensor.getName()=="vent")
308
- debugger
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: sensor. elapsedTimeSinceLastContact()
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
- async function addSensorToList(sensor){
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
- async function createSensor(adapter, config) {
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.discoveryTimeout*1000)
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
- updateSensor(s)
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
- const c = classMap.get(config.params.sensorClass)
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
- sensor = new (classMap.get('UNKNOWN'))(device)
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
- if (sensor.elapsedTimeSinceLastContact()> dt)
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
- }, minTimeout*1000)
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, options.discoveryInterval)
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.1.test",
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": {
@@ -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.{location}.temperature"
27
+ "default": "environment.{zone}.temperature"
16
28
  },
17
29
  "humidity":
18
30
  {
19
31
  "unit":"ratio",
20
- "default":"environment.{location}.humidity"
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
- "current":{
25
- "unit": "A",
26
- "default":"electrical.batteries.0.current"
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
- "voltage":
29
- {
30
- "unit": "V",
31
- "default": "electrical.batteries.0.voltage"
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),d=n(9676),m=n(7041),f=n(3657),g=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,A]=(0,o.useState)({}),[$,k]=(0,o.useState)({"ui:submitButtonOptions":{props:{disabled:!1,className:"btn btn-info"},norender:!0,submitText:"Submit"}}),[x,D]=(0,o.useState)([]),[C,T]=(0,o.useState)(),[j,_]=(0,o.useState)(new Map),[O,N]=(0,o.useState)({progress:0,maxTimeout:100,deviceCount:0,totalDevices:0}),[M,J]=(0,o.useState)("unknown"),[L,U]=(0,o.useState)();function B(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 H(e){return console.log(`fetching ${e}`),fetch(`/plugins/bt-sensors-plugin-sk/${e}`,{credentials:"include"})}async function I(){const e=await H("progress");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 P(){console.log("refreshing sensor map"),async function(){const e=await H("sensors");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=>{_(new Map(e.map((e=>[e.info.mac,e]))))})).catch((e=>{U(e)}))}return(0,o.useEffect)((()=>{H("sendPluginState").then((async e=>{const t=await e.json();J(t.state),console.log("Setting up eventsource");const n=new EventSource("/plugins/bt-sensors-plugin-sk/sse");return n.addEventListener("newsensor",(e=>{let t=JSON.parse(e.data);S.has(t.info.mac)||(console.log(`New sensor: ${t.info.mac}`),_(new Map(S.set(t.info.mac,t))))})),n.addEventListener("sensorchanged",(e=>{let t=JSON.parse(e.data);if(S.has(t.mac)){let e=S.get(t.mac);Object.assign(e.info,t),_(new Map(S))}})),n.addEventListener("progress",(e=>{const t=JSON.parse(e.data);N(t),console.log(t)})),n.addEventListener("pluginstate",(e=>{const t=JSON.parse(e.data);J(t.state)})),()=>n.close()})).catch((e=>{U(e)}))}),[]),(0,o.useEffect)((()=>{"started"==M?(P(),async function(){const e=await H("base");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=>{U(e)})),I().then((e=>{N(e)})).catch((e=>{U(e)}))):(_(new Map),n({}),b({}))}),[M]),(0,o.useEffect)((()=>{console.log(L)}),[L]),(0,o.useEffect)((()=>{S=j,D(Array.from(j.entries()).map((e=>{const t=j.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],A(t.schema),T(n))}},r().createElement("div",{class:"d-flex justify-content-between align-items-center",style:a?{fontWeight:"normal"}:{fontStyle:"italic"}},`${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(d.A,null):e.info.signalStrength>40?r().createElement(m.A,null):e.info.signalStrength>20?r().createElement(f.A,null):r().createElement(g.A,null)}(t))));var s})))}),[j]),"stopped"==M?r().createElement("h1",null,"Enable plugin to see configuration"):r().createElement("div",null,L?r().createElement("h2",{style:"color: red;"},L.message):"",r().createElement(a.Ay,{schema:t,validator:s.Ay,onChange:e=>b(e.formData),onSubmit:({formData:e},t)=>{T(null),B("sendBaseData",e).then((e=>{200!=e.status?U(new Error(`Unable to update base data: ${e.statusText} (${e.status})`)):(I().then((e=>{N(e)})).catch((e=>{U(e)})),P())}))},onError:w("errors"),formData:v}),r().createElement("p",null),r().createElement("p",null),O.deviceCount<O.totalDevices?r().createElement(E.A,{max:O.maxTimeout,now:O.progress}):"",r().createElement("h2",null,j.size>0?" Bluetooth Devices click to configure":""),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"}},x),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:$,onChange:e=>T(e.formData),onSubmit:({formData:e},t)=>{var n;console.log(e),B("sendSensorData",n=e).then((e=>{if(200!=e.status)throw new Error(e.statusText);j.get(n.mac_address).config=n})),A({}),alert("Changes saved")},onError:w("errors"),formData:C},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=C.mac_address,T(j.get(e).config)}},"Undo"),r().createElement(c.A,{variant:"contained",color:"secondary",onClick:e=>{return t=C.mac_address,void(window.confirm(`Delete configuration for ${t}?`)&&function(e){try{B("removeSensorData",{mac_address:e}).then((e=>{if(200!=e.status)throw new Error(e.statusText)})),S.delete(e),_(new Map(S)),A({})}catch{}}(t));var t}},"Delete")))))))}}}]);
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")))))))}}}]);
@@ -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
- initMetadata(){
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)}
@@ -19,6 +19,10 @@ class AranetSensor extends BTSensor{
19
19
 
20
20
  return null
21
21
  }
22
+ initSchema(){
23
+ super.initSchema()
24
+ this.addDefaultParam("zone")
25
+ }
22
26
 
23
27
  }
24
28
  module.exports=AranetSensor
@@ -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
- initMetadata(){
22
- this.addMetadatum('c02', '', 'c02 concentration',
17
+ initSchema(){
18
+ super.initSchema()
19
+
20
+ this.addMetadatum('co2', 'ppm', 'co2 concentration in zone',
23
21
  (buff)=>{return ((buff.readUInt16LE(8)))})
24
- this.addMetadatum('temp','K', 'temperature',
25
- (buff)=>{return parseFloat((273.15+(buff.readInt16LBE(15))/1000).toFixed(2))})
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.addMetadatum("pressure","","atmospheric pressure",
28
- (buff)=>{return ((buff.readUInt16LE(13)))/10})
29
- this.addMetadatum('batteryStrength', 'ratio', 'sensor battery strength',
30
- (buff)=>{return ((buff.readUInt8(12))/100)})
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)