bt-sensors-plugin-sk 1.2.0-beta.0.0.9 → 1.2.0-beta.0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/BTSensor.js CHANGED
@@ -102,7 +102,14 @@ function preparePath(obj, str) {
102
102
  class BTSensor extends EventEmitter {
103
103
 
104
104
  static DEFAULTS = require('./plugin_defaults.json');
105
-
105
+
106
+ static SensorDomains={
107
+ unknown: { name: "unknown", description: "Unknown sensor domain "},
108
+ environmental: { name: "environmental", description: "Sensors that measure environmental conditions - air temperature, humidity etc."},
109
+ electrical: { name: "electrical", description: "Electrical sensor - chargers, batteries, inverters etc."},
110
+ tanks: { name: "tanks", description: "Sensors that measure level in tanks (gas, propane, water etc.) "}
111
+ }
112
+ static Domain = this.SensorDomains.unknown
106
113
  /**
107
114
  *
108
115
  * @param {module:node-ble/Device} device
@@ -404,7 +411,8 @@ class BTSensor extends EventEmitter {
404
411
  path.type="string"
405
412
 
406
413
  if (!path.pattern)
407
- path.pattern="^(?:[^{}\\s]*\\{[a-zA-Z0-9]+\\}[^{}\\s]*|[^{}\\s]*)$"
414
+ path.pattern=//"^(?:[^{}\\s]*\\{[a-zA-Z0-9]+\\}[^{}\\s]*|[^{}\\s]*)$"
415
+ "^((\\{[a-zA-Z0-9]+\\}|[a-zA-Z0-9]+))(\\.(\\{[a-zA-Z0-9]+\\}|[a-zA-Z0-9]+))*$"
408
416
  this._schema.properties.paths.properties[tag]=path
409
417
  return this._schema.properties.paths.properties[tag]
410
418
  }
@@ -644,6 +652,10 @@ class BTSensor extends EventEmitter {
644
652
  return this._state
645
653
  }
646
654
 
655
+ getDomain(){
656
+ return this.constructor.Domain
657
+ }
658
+
647
659
  isActive(){
648
660
  return this._state=="ACTIVE"
649
661
  }
package/README.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## What's New
4
4
 
5
+ ## 1.2.0-beta-0.1.0
6
+
7
+ Sensors on config page appear under tabs indicating their domain (Environmental, Electrical etc.)
8
+
9
+ Gobius C tank meter support added.
10
+
11
+ ## 1.2.0-beta-0.0.10
12
+
13
+ Better handling of plugin config screen when Disabled
14
+
5
15
  ## 1.2.0-beta-0.0.9
6
16
 
7
17
  Fixes to config page RSSI update.
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
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,10 +8,10 @@ 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
 
18
-
19
15
  constructor(config){
20
16
  this.config=config
21
17
  this.addPath=BTSensor.prototype.addPath.bind(this)
@@ -27,6 +23,7 @@ class MissingSensor {
27
23
  this.getJSONSchema = BTSensor.prototype.getJSONSchema.bind(this)
28
24
  this.initSchema = BTSensor.prototype.initSchema.bind(this)
29
25
 
26
+
30
27
  this.initSchema()
31
28
  var keys = Object.keys(config?.paths??{})
32
29
 
@@ -62,6 +59,9 @@ class MissingSensor {
62
59
  getMacAddress(){
63
60
  return this.mac_address
64
61
  }
62
+ getDomain(){
63
+ return BTSensor.SensorDomains.unknown
64
+ }
65
65
  getDescription(){
66
66
  return ""
67
67
  }
@@ -88,66 +88,14 @@ class MissingSensor {
88
88
 
89
89
  }
90
90
  module.exports = function (app) {
91
- var adapterID = 'hci0'
92
-
93
-
94
91
  var deviceConfigs
95
92
  var starts=0
96
- var classMap
97
-
98
- var utilities_sk
99
93
 
100
94
  var plugin = {};
101
95
  plugin.id = 'bt-sensors-plugin-sk';
102
96
  plugin.name = 'BT Sensors plugin';
103
97
  plugin.description = 'Plugin to communicate with and update paths to BLE Sensors in Signalk';
104
98
 
105
- //Try and load utilities-sk NOTE: should be installed from App Store--
106
- //But there's a fail safe because I'm a reasonable man.
107
-
108
- utilities_sk = {
109
- loadClasses: function(dir, ext='.js')
110
- {
111
- const classMap = new Map()
112
- const classFiles = fs.readdirSync(dir)
113
- .filter(file => file.endsWith(ext));
114
-
115
- classFiles.forEach(file => {
116
- const filePath = path.join(dir, file);
117
- const cls = require(filePath);
118
- classMap.set(cls.name, cls);
119
- })
120
- return classMap
121
- }
122
- }
123
-
124
- function sleep(x) {
125
- return new Promise((resolve) => {
126
- setTimeout(() => {
127
- resolve(x);
128
- }, x);
129
- });
130
- }
131
-
132
- function loadClassMap() {
133
- const _classMap = utilities_sk.loadClasses(path.join(__dirname, 'sensor_classes'))
134
- classMap = new Map([..._classMap].filter(([k, v]) => !k.startsWith("_") ))
135
- const libPath = app.config.appPath +(
136
- semver.gt(app.config.version,"2.13.5")?"dist":"lib"
137
- )
138
- import(libPath+"/modules.js").then( (modulesjs)=>{
139
- const { default:defaultExport} = modulesjs
140
- const modules = defaultExport.modulesWithKeyword(app.config, "signalk-bt-sensor-class")
141
- modules.forEach((module)=>{
142
- module.metadata.classFiles.forEach((classFile)=>{
143
- const cls = require(module.location+module.module+"/"+classFile);
144
- classMap.set(cls.name, cls);
145
- })
146
- })
147
- classMap.get('UNKNOWN').classMap=new Map([...classMap].sort().filter(([k, v]) => !v.isSystem )) // share the classMap with Unknown for configuration purposes
148
- })
149
- }
150
-
151
99
  app.debug(`Loading plugin ${packageInfo.version}`)
152
100
 
153
101
  plugin.schema = {
@@ -171,17 +119,17 @@ module.exports = function (app) {
171
119
  }
172
120
  }
173
121
 
174
- const sensorMap=new Map()
175
122
 
176
123
  plugin.started=false
177
-
178
- loadClassMap()
124
+
179
125
  var discoveryIntervalID, progressID, progressTimeoutID, deviceHealthID
180
126
  var adapter
181
- var adapterPower
182
127
  const channel = createChannel()
128
+ const classMap = loadClassMap(app)
129
+ const sensorMap=new Map()
183
130
 
184
- plugin.registerWithRouter = function(router) {
131
+
132
+ /* plugin.registerWithRouter = function(router) {
185
133
  router.get('/sendPluginState', async (req, res) => {
186
134
 
187
135
  res.status(200).json({
@@ -193,15 +141,16 @@ module.exports = function (app) {
193
141
  channel.register(session)
194
142
  });
195
143
 
196
- }
144
+ }*/
197
145
 
198
146
  plugin.start = async function (options, restartPlugin) {
199
147
  plugin.started=true
200
148
  var adapterID=options.adapter
201
149
  var foundConfiguredDevices=0
150
+
202
151
  plugin.registerWithRouter = function(router) {
203
152
 
204
- router.post('/sendSensorData', async (req, res) => {
153
+ router.post('/updateSensorData', async (req, res) => {
205
154
  app.debug(req.body)
206
155
  const i = deviceConfigs.findIndex((p)=>p.mac_address==req.body.mac_address)
207
156
  if (i<0){
@@ -222,13 +171,9 @@ module.exports = function (app) {
222
171
  const sensor = sensorMap.get(req.body.mac_address)
223
172
  if (sensor) {
224
173
  removeSensorFromList(sensor)
225
- if (sensor.isActive()) {
226
- sensor.stopListening().then(()=>
227
- initConfiguredDevice(req.body)
228
- )
229
- } else {
230
- initConfiguredDevice(req.body)
231
- }
174
+ if (sensor.isActive())
175
+ await sensor.stopListening()
176
+ initConfiguredDevice(req.body)
232
177
  }
233
178
 
234
179
  }
@@ -244,7 +189,7 @@ module.exports = function (app) {
244
189
  if (sensorMap.has(req.body.mac_address))
245
190
  sensorMap.delete(req.body.mac_address)
246
191
  app.savePluginOptions(
247
- options, async () => {
192
+ options, () => {
248
193
  app.debug('Plugin options saved')
249
194
  res.status(200).json({message: "Sensor updated"})
250
195
  channel.broadcast({},"resetSensors")
@@ -253,7 +198,7 @@ module.exports = function (app) {
253
198
 
254
199
  });
255
200
 
256
- router.post('/sendBaseData', async (req, res) => {
201
+ router.post('/updateBaseData', async (req, res) => {
257
202
 
258
203
  app.debug(req.body)
259
204
  Object.assign(options,req.body)
@@ -266,9 +211,14 @@ module.exports = function (app) {
266
211
  }
267
212
  )
268
213
  });
214
+ router.get('/getDomains', (req, res) => {
215
+
216
+ res.status(200).json(
217
+ BTSensor.SensorDomains
218
+ );
219
+ })
269
220
 
270
-
271
- router.get('/base', (req, res) => {
221
+ router.get('/getBaseData', (req, res) => {
272
222
 
273
223
  res.status(200).json(
274
224
  {
@@ -282,13 +232,13 @@ module.exports = function (app) {
282
232
  }
283
233
  );
284
234
  })
285
- router.get('/sensors', (req, res) => {
235
+ router.get('/getSensors', (req, res) => {
286
236
  app.debug("Sending sensors")
287
237
  const t = sensorsToJSON()
288
238
  res.status(200).json(t)
289
239
  });
290
240
 
291
- router.get('/progress', (req, res) => {
241
+ router.get('/getProgress', (req, res) => {
292
242
  app.debug("Sending progress")
293
243
  const json = {"progress":foundConfiguredDevices/deviceConfigs.length, "maxTimeout": 1,
294
244
  "deviceCount":foundConfiguredDevices,
@@ -297,7 +247,7 @@ module.exports = function (app) {
297
247
 
298
248
  });
299
249
 
300
- router.get('/sendPluginState', async (req, res) => {
250
+ router.get('/getPluginState', async (req, res) => {
301
251
 
302
252
  res.status(200).json({
303
253
  "state":(plugin.started?"started":"stopped")
@@ -320,12 +270,12 @@ module.exports = function (app) {
320
270
 
321
271
  function getSensorInfo(sensor){
322
272
 
323
- const etslc = sensor.elapsedTimeSinceLastContact()
324
273
  return { mac: sensor.getMacAddress(),
325
274
  name: sensor.getName(),
275
+ domain: sensor.getDomain().name,
326
276
  RSSI: sensor.getRSSI(),
327
277
  signalStrength: sensor.getSignalStrength(),
328
- lastContactDelta: etslc
278
+ lastContactDelta: sensor.elapsedTimeSinceLastContact()
329
279
  }
330
280
  }
331
281
 
@@ -335,7 +285,6 @@ module.exports = function (app) {
335
285
  info: getSensorInfo(sensor),
336
286
  schema: sensor.getJSONSchema(),
337
287
  config: config?config:{}
338
-
339
288
  }
340
289
  }
341
290
  async function startScanner(transport) {
@@ -369,7 +318,7 @@ module.exports = function (app) {
369
318
  channel.broadcast({mac:sensor.getMacAddress()},"removesensor")
370
319
  }
371
320
 
372
- async function addSensorToList(sensor){
321
+ function addSensorToList(sensor){
373
322
  app.debug(`adding sensor to list ${sensor.getMacAddress()}`)
374
323
  if (sensorMap.has(sensor.getMacAddress()) )
375
324
  debugger
@@ -380,7 +329,7 @@ module.exports = function (app) {
380
329
  return `${config?.name??""}${config.name?" at ":""}${config.mac_address}`
381
330
  }
382
331
 
383
- async function createSensor(adapter, config) {
332
+ function createSensor(adapter, config) {
384
333
  return new Promise( ( resolve, reject )=>{
385
334
  var s
386
335
  const startNumber=starts
@@ -531,14 +480,15 @@ module.exports = function (app) {
531
480
  setInterval( findDevices, discoveryInterval*1000, discoveryTimeout)
532
481
  }
533
482
 
534
-
483
+ channel.broadcast({state:"started"},"pluginstate")
484
+
485
+
535
486
  if (!adapterID || adapterID=="")
536
487
  adapterID = "hci0"
537
488
  //Check if Adapter has changed since last start()
538
489
  if (adapter) {
539
- const n = await adapter.getName()
540
- if (n!=adapterID) {
541
- adapter.helper.removeAllListeners()
490
+ if (adapter.adapter!=adapterID) {
491
+ adapter.helper._propsProxy.removeAllListeners()
542
492
  adapter=null
543
493
  }
544
494
  }
@@ -568,12 +518,10 @@ module.exports = function (app) {
568
518
  if (!await adapter.isPowered()) {
569
519
  app.debug(`Bluetooth Adapter ${adapterID} not powered on.`)
570
520
  app.setPluginError(`Bluetooth Adapter ${adapterID} not powered on.`)
571
- adapterPower=false
572
521
  await plugin.stop()
573
522
  return
574
523
  }
575
524
  }
576
- adapterPower=true
577
525
 
578
526
  sensorMap.clear()
579
527
  if (channel)
@@ -581,9 +529,6 @@ module.exports = function (app) {
581
529
  deviceConfigs=options?.peripherals??[]
582
530
 
583
531
  if (plugin.stopped) {
584
- //await sleep(5000) //Make sure plugin.stop() completes first
585
- //plugin.start is called asynchronously for some reason
586
- //and does not wait for plugin.stop to complete
587
532
  plugin.stopped=false
588
533
  }
589
534
 
@@ -689,17 +634,20 @@ module.exports = function (app) {
689
634
  }
690
635
  }
691
636
  sensorMap.clear()
692
- if (adapter && await adapter.isDiscovering())
637
+
638
+ if (adapter) {
639
+ adapter.helper._propsProxy.removeAllListeners()
640
+ if( await adapter.isDiscovering())
693
641
  try{
694
642
  await adapter.stopDiscovery()
695
643
  app.debug('Scan stopped')
696
644
  } catch (e){
697
645
  app.debug(`Error stopping scan: ${e.message}`)
698
646
  }
699
-
647
+ }
700
648
  app.debug('BT Sensors plugin stopped')
701
649
 
702
650
  }
703
651
 
704
652
  return plugin;
705
- }
653
+ }
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.9",
3
+ "version": "1.2.0-beta.0.1.0",
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": {
@@ -12,6 +12,7 @@
12
12
  "int24": "^0.0.1",
13
13
  "kaitai-struct": "^0.10.0",
14
14
  "node-ble": "^1.13.0",
15
+ "rimraf": "^6.0.1",
15
16
  "semver": "^7.7.1"
16
17
  },
17
18
  "devDependencies": {
package/public/159.js CHANGED
@@ -1,2 +1 @@
1
- /*! For license information please see 159.js.LICENSE.txt */
2
- "use strict";(self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[]).push([[159,540],{5228:e=>{var r=Object.getOwnPropertySymbols,t=Object.prototype.hasOwnProperty,n=Object.prototype.propertyIsEnumerable;e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var r={},t=0;t<10;t++)r["_"+String.fromCharCode(t)]=t;if("0123456789"!==Object.getOwnPropertyNames(r).map((function(e){return r[e]})).join(""))return!1;var n={};return"abcdefghijklmnopqrst".split("").forEach((function(e){n[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},n)).join("")}catch(e){return!1}}()?Object.assign:function(e,o){for(var u,c,f=function(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}(e),l=1;l<arguments.length;l++){for(var i in u=Object(arguments[l]))t.call(u,i)&&(f[i]=u[i]);if(r){c=r(u);for(var a=0;a<c.length;a++)n.call(u,c[a])&&(f[c[a]]=u[c[a]])}}return f}},5287:(e,r,t)=>{var n=t(5228),o="function"==typeof Symbol&&Symbol.for,u=o?Symbol.for("react.element"):60103,c=o?Symbol.for("react.portal"):60106,f=o?Symbol.for("react.fragment"):60107,l=o?Symbol.for("react.strict_mode"):60108,i=o?Symbol.for("react.profiler"):60114,a=o?Symbol.for("react.provider"):60109,s=o?Symbol.for("react.context"):60110,p=o?Symbol.for("react.forward_ref"):60112,y=o?Symbol.for("react.suspense"):60113,d=o?Symbol.for("react.memo"):60115,h=o?Symbol.for("react.lazy"):60116,b="function"==typeof Symbol&&Symbol.iterator;function v(e){for(var r="https://reactjs.org/docs/error-decoder.html?invariant="+e,t=1;t<arguments.length;t++)r+="&args[]="+encodeURIComponent(arguments[t]);return"Minified React error #"+e+"; visit "+r+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var m={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},_={};function g(e,r,t){this.props=e,this.context=r,this.refs=_,this.updater=t||m}function S(){}function k(e,r,t){this.props=e,this.context=r,this.refs=_,this.updater=t||m}g.prototype.isReactComponent={},g.prototype.setState=function(e,r){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error(v(85));this.updater.enqueueSetState(this,e,r,"setState")},g.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},S.prototype=g.prototype;var w=k.prototype=new S;w.constructor=k,n(w,g.prototype),w.isPureReactComponent=!0;var j={current:null},O=Object.prototype.hasOwnProperty,C={key:!0,ref:!0,__self:!0,__source:!0};function $(e,r,t){var n,o={},c=null,f=null;if(null!=r)for(n in void 0!==r.ref&&(f=r.ref),void 0!==r.key&&(c=""+r.key),r)O.call(r,n)&&!C.hasOwnProperty(n)&&(o[n]=r[n]);var l=arguments.length-2;if(1===l)o.children=t;else if(1<l){for(var i=Array(l),a=0;a<l;a++)i[a]=arguments[a+2];o.children=i}if(e&&e.defaultProps)for(n in l=e.defaultProps)void 0===o[n]&&(o[n]=l[n]);return{$$typeof:u,type:e,key:c,ref:f,props:o,_owner:j.current}}function E(e){return"object"==typeof e&&null!==e&&e.$$typeof===u}var P=/\/+/g,x=[];function R(e,r,t,n){if(x.length){var o=x.pop();return o.result=e,o.keyPrefix=r,o.func=t,o.context=n,o.count=0,o}return{result:e,keyPrefix:r,func:t,context:n,count:0}}function A(e){e.result=null,e.keyPrefix=null,e.func=null,e.context=null,e.count=0,10>x.length&&x.push(e)}function I(e,r,t,n){var o=typeof e;"undefined"!==o&&"boolean"!==o||(e=null);var f=!1;if(null===e)f=!0;else switch(o){case"string":case"number":f=!0;break;case"object":switch(e.$$typeof){case u:case c:f=!0}}if(f)return t(n,e,""===r?"."+U(e,0):r),1;if(f=0,r=""===r?".":r+":",Array.isArray(e))for(var l=0;l<e.length;l++){var i=r+U(o=e[l],l);f+=I(o,i,t,n)}else if("function"==typeof(i=null===e||"object"!=typeof e?null:"function"==typeof(i=b&&e[b]||e["@@iterator"])?i:null))for(e=i.call(e),l=0;!(o=e.next()).done;)f+=I(o=o.value,i=r+U(o,l++),t,n);else if("object"===o)throw t=""+e,Error(v(31,"[object Object]"===t?"object with keys {"+Object.keys(e).join(", ")+"}":t,""));return f}function q(e,r,t){return null==e?0:I(e,"",r,t)}function U(e,r){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var r={"=":"=0",":":"=2"};return"$"+(""+e).replace(/[=:]/g,(function(e){return r[e]}))}(e.key):r.toString(36)}function F(e,r){e.func.call(e.context,r,e.count++)}function L(e,r,t){var n=e.result,o=e.keyPrefix;e=e.func.call(e.context,r,e.count++),Array.isArray(e)?M(e,n,t,(function(e){return e})):null!=e&&(E(e)&&(e=function(e,r){return{$$typeof:u,type:e.type,key:r,ref:e.ref,props:e.props,_owner:e._owner}}(e,o+(!e.key||r&&r.key===e.key?"":(""+e.key).replace(P,"$&/")+"/")+t)),n.push(e))}function M(e,r,t,n,o){var u="";null!=t&&(u=(""+t).replace(P,"$&/")+"/"),q(e,L,r=R(r,u,n,o)),A(r)}var N={current:null};function D(){var e=N.current;if(null===e)throw Error(v(321));return e}var T={ReactCurrentDispatcher:N,ReactCurrentBatchConfig:{suspense:null},ReactCurrentOwner:j,IsSomeRendererActing:{current:!1},assign:n};r.Children={map:function(e,r,t){if(null==e)return e;var n=[];return M(e,n,null,r,t),n},forEach:function(e,r,t){if(null==e)return e;q(e,F,r=R(null,null,r,t)),A(r)},count:function(e){return q(e,(function(){return null}),null)},toArray:function(e){var r=[];return M(e,r,null,(function(e){return e})),r},only:function(e){if(!E(e))throw Error(v(143));return e}},r.Component=g,r.Fragment=f,r.Profiler=i,r.PureComponent=k,r.StrictMode=l,r.Suspense=y,r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=T,r.cloneElement=function(e,r,t){if(null==e)throw Error(v(267,e));var o=n({},e.props),c=e.key,f=e.ref,l=e._owner;if(null!=r){if(void 0!==r.ref&&(f=r.ref,l=j.current),void 0!==r.key&&(c=""+r.key),e.type&&e.type.defaultProps)var i=e.type.defaultProps;for(a in r)O.call(r,a)&&!C.hasOwnProperty(a)&&(o[a]=void 0===r[a]&&void 0!==i?i[a]:r[a])}var a=arguments.length-2;if(1===a)o.children=t;else if(1<a){i=Array(a);for(var s=0;s<a;s++)i[s]=arguments[s+2];o.children=i}return{$$typeof:u,type:e.type,key:c,ref:f,props:o,_owner:l}},r.createContext=function(e,r){return void 0===r&&(r=null),(e={$$typeof:s,_calculateChangedBits:r,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null}).Provider={$$typeof:a,_context:e},e.Consumer=e},r.createElement=$,r.createFactory=function(e){var r=$.bind(null,e);return r.type=e,r},r.createRef=function(){return{current:null}},r.forwardRef=function(e){return{$$typeof:p,render:e}},r.isValidElement=E,r.lazy=function(e){return{$$typeof:h,_ctor:e,_status:-1,_result:null}},r.memo=function(e,r){return{$$typeof:d,type:e,compare:void 0===r?null:r}},r.useCallback=function(e,r){return D().useCallback(e,r)},r.useContext=function(e,r){return D().useContext(e,r)},r.useDebugValue=function(){},r.useEffect=function(e,r){return D().useEffect(e,r)},r.useImperativeHandle=function(e,r,t){return D().useImperativeHandle(e,r,t)},r.useLayoutEffect=function(e,r){return D().useLayoutEffect(e,r)},r.useMemo=function(e,r){return D().useMemo(e,r)},r.useReducer=function(e,r,t){return D().useReducer(e,r,t)},r.useRef=function(e){return D().useRef(e)},r.useState=function(e){return D().useState(e)},r.version="16.14.0"},6540:(e,r,t)=>{e.exports=t(5287)}}]);
1
+ "use strict";(self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[]).push([[159],{2995:(e,t,n)=>{n.r(t),n.d(t,{default:()=>A});var a=n(3490),s=n(4810),o=n(4147),r=n.n(o),l=n(7606),c=n(6452),i=n(3768),u=n(1431),g=n(9676),d=n(7041),m=n(3657),f=n(5027),p=n(3540),h=n(4712),E=n(5056),w=n(6890),S=n(3399);const v=e=>console.log.bind(console,e);var y,b={};const A=e=>{const[t,n]=(0,o.useState)({}),[A,D]=(0,o.useState)({}),[$,_]=(0,o.useState)({}),[k,x]=(0,o.useState)({"ui:submitButtonOptions":{props:{disabled:!1,className:"btn btn-info"},norender:!0,submitText:"Submit"}}),[C,T]=(0,o.useState)([]),[j,M]=(0,o.useState)(),[O,N]=(0,o.useState)(new Map),[B,U]=(0,o.useState)({progress:0,maxTimeout:100,deviceCount:0,totalDevices:0}),[J,L]=(0,o.useState)("unknown"),[P,K]=(0,o.useState)();function z(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(){console.log("getProgress");const e=await H("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 R(){console.log("refreshing sensor map"),async function(){console.log("getSensors");const e=await H("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=>{N(new Map(e.map((e=>[e.info.mac,e]))))})).catch((e=>{K(e)}))}function W(e){return Object.keys(e.config).length>0}function Y(e){const t=W(e);return r().createElement(w.A,{action:!0,onClick:()=>{e.config.mac_address=e.info.mac,_(e.schema),M(e.config)}},r().createElement("div",{class:"d-flex justify-content-between align-items-center",style:t?{fontWeight:"normal"}:{fontStyle:"italic"}},`${e._changesMade?"*":""}${e.info.name} MAC: ${e.info.mac} RSSI: ${n=e.info.RSSI,null==n?NaN:n}`,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)}(e))));var n}return(0,o.useEffect)((()=>{console.log("useEffect([])"),H("getPluginState").then((async e=>{if(404==e.status)throw L("unknown"),new Error("unable to get plugin state");const t=await e.json();L(t.state),await async function(){console.log("getDomains");const e=await H("getDomains");if(200!=e.status)throw new Error(`Unable get domain data: ${e.statusText} (${e.status}) `);const t=await e.json();return console.log(t),t}(),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);y.has(t.info.mac)||(console.log(`New sensor: ${t.info.mac}`),N(new Map(y.set(t.info.mac,t))))})),n.addEventListener("sensorchanged",(e=>{let t=JSON.parse(e.data);if(console.log("sensorchanged"),console.log(t),y.has(t.mac)){let e=y.get(t.mac);Object.assign(e.info,t),N(new Map(y))}})),n.addEventListener("progress",(e=>{console.log("progress");const t=JSON.parse(e.data);U(t),console.log(t)})),n.addEventListener("pluginstate",(e=>{console.log("pluginstate");const t=JSON.parse(e.data);L(t.state)})),()=>n.close()})).catch((e=>{K(e)}))}),[]),(0,o.useEffect)((()=>{console.log("useEffect([pluginState])"),"started"==J?(R(),async function(){console.log("getBaseData");const e=await H("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),D(e.data)})).catch((e=>{K(e)})),I().then((e=>{U(e)})).catch((e=>{K(e)}))):(N(new Map),n({}),D({}))}),[J]),(0,o.useEffect)((()=>{console.log("useEffect([sensorMap])"),y=O;const e=new Set(O.entries().map((e=>e[1].info.domain))),t={_configured:Array.from(O.entries()).filter((e=>W(e[1]))).map((e=>Y(O.get(e[0]))))};e.forEach((e=>{var n;t[e]=(n=e,Array.from(O.entries()).filter((e=>e[1].info.domain===n))).map((e=>Y(O.get(e[0]))))})),b=t}),[O]),"stopped"==J||"unknown"==J?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,P?r().createElement("h2",{style:"color: red;"},P):"",r().createElement(a.Ay,{schema:t,validator:s.Ay,onChange:e=>D(e.formData),onSubmit:({formData:e},t)=>{var n;n=e,console.log("updateBaseData"),z("updateBaseData",n).then((e=>{200!=e.status?K(new Error(`Unable to update base data: ${e.statusText} (${e.status})`)):(I().then((e=>{U(e)})).catch((e=>{K(e)})),R())})),_({})},onError:v("errors"),formData:A}),r().createElement("p",null),r().createElement("p",null),B.deviceCount<B.totalDevices?r().createElement(S.A,{max:B.maxTimeout,now:B.progress}):"",r().createElement("h2",null,O.size>0?"Bluetooth Devices - Select to configure":""),r().createElement("h2",null,O.size>0?"(* = sensor has unsaved changes)":""),r().createElement("p",null),r().createElement(h.A,{defaultActiveKey:"_configured",id:"domain-tabs",className:"mb-3"},Object.keys(b).map((e=>{return n=(t=e).slice("_"===t.charAt(0)?1:0),r().createElement(E.A,{eventKey:t,title:n.charAt(0).toUpperCase()+n.slice(1)},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"}},function(e){return b[e]}(t)),r().createElement("div",{style:{paddingLeft:10,paddingTop:10,display:0==Object.keys($).length?"none":""}},r().createElement(a.Ay,{schema:$,validator:s.Ay,uiSchema:k,onChange:e=>{O.get(e.formData.mac_address)._changesMade=!0,M(e.formData)},onSubmit:({formData:e},t)=>{var n;console.log(e),n=e,console.log("updateSensorData"),z("updateSensorData",n).then((e=>{if(200!=e.status)throw new Error(e.statusText);O.get(n.mac_address)._changesMade=!1,O.get(n.mac_address).config=n})),_({}),alert("Changes saved")},onError:v("errors"),formData:j},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=j.mac_address,console.log("undoChanges"),O.get(e)._changesMade=!1,M(O.get(e).config)}},"Undo"),r().createElement(c.A,{variant:"contained",color:"secondary",onClick:e=>{return t=j.mac_address,void(window.confirm(`Delete configuration for ${t}?`)&&function(e){console.log("removeSensorData");try{z("removeSensorData",{mac_address:e}).then((e=>{if(200!=e.status)throw new Error(e.statusText)})),y.delete(e),N(new Map(y)),_({})}catch{}}(t));var t}},"Delete")))))));var t,n}))))}}}]);