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

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.
@@ -0,0 +1,7 @@
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": []
7
+ }
package/BTSensor.js CHANGED
@@ -100,7 +100,6 @@ function preparePath(obj, str) {
100
100
  */
101
101
 
102
102
  class BTSensor extends EventEmitter {
103
- //static metadata=new Map()
104
103
 
105
104
  static DEFAULTS = require('./plugin_defaults.json');
106
105
 
@@ -318,6 +317,7 @@ class BTSensor extends EventEmitter {
318
317
 
319
318
  //create the 'name' parameter
320
319
  this.addDefaultParam("name")
320
+ .default=this?.currentProperties?.Name
321
321
 
322
322
  //create the 'location' parameter
323
323
 
@@ -365,13 +365,15 @@ class BTSensor extends EventEmitter {
365
365
  }
366
366
  else
367
367
  await this.initGATTNotifications()
368
+ }).catch((e)=>{
369
+ this.app.debug(`Unable to activate GATT connection for ${this.getName()} (${this.getMacAddress()}): ${e}`)
368
370
  })
369
371
  }
370
372
 
371
373
  /**
372
374
  * Add a metadatum instance to the sensor instance
373
375
  *
374
- * @param {String} tag
376
+ * @param {String} tag
375
377
  * @param {...any} args
376
378
  * @returns {this.Metadatum} the new metadatum instance
377
379
  */
@@ -552,6 +554,9 @@ class BTSensor extends EventEmitter {
552
554
  getParams(){
553
555
  return this._schema.properties.params.properties
554
556
  }
557
+ getParameter(param){
558
+ return this.getParams()[param]
559
+ }
555
560
  getGATTParams(){
556
561
  return this._schema.properties.gattParams.properties
557
562
 
package/README.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## What's New
4
4
 
5
+ ## 1.2.0-beta-0.0.9
6
+
7
+ Fixes to config page RSSI update.
8
+
9
+ ## 1.2.0-beta-0.0.8
10
+
11
+ Improved handling of changed state on config page.
12
+
13
+ Several small fixes to various sensor classes.
14
+
5
15
  ## 1.2.0-beta-0.0.7
6
16
 
7
17
  Added zone config param for environmental sensors. Removed location parameter.
package/index.js CHANGED
@@ -21,15 +21,13 @@ class MissingSensor {
21
21
  this.addPath=BTSensor.prototype.addPath.bind(this)
22
22
  this.addParameter=BTSensor.prototype.addParameter.bind(this)
23
23
  this.addDefaultPath=BTSensor.prototype.addDefaultPath.bind(this)
24
- this.addDefaultParam=BTSensor.prototype.addDefaultPath.bind(this)
25
- this.addDefaultParam=BTSensor.prototype.addDefaultPath.bind(this)
24
+ this.addDefaultParam=BTSensor.prototype.addDefaultParam.bind(this)
26
25
  this.getPath=BTSensor.prototype.getPath.bind(this)
27
26
 
28
27
  this.getJSONSchema = BTSensor.prototype.getJSONSchema.bind(this)
29
28
  this.initSchema = BTSensor.prototype.initSchema.bind(this)
30
29
 
31
30
  this.initSchema()
32
-
33
31
  var keys = Object.keys(config?.paths??{})
34
32
 
35
33
  keys.forEach((key)=>{
@@ -321,13 +319,13 @@ module.exports = function (app) {
321
319
  }
322
320
 
323
321
  function getSensorInfo(sensor){
324
- if (sensor.getName()=="vent")
325
- debugger
322
+
323
+ const etslc = sensor.elapsedTimeSinceLastContact()
326
324
  return { mac: sensor.getMacAddress(),
327
325
  name: sensor.getName(),
328
326
  RSSI: sensor.getRSSI(),
329
327
  signalStrength: sensor.getSignalStrength(),
330
- lastContactDelta: sensor. elapsedTimeSinceLastContact()
328
+ lastContactDelta: etslc
331
329
  }
332
330
  }
333
331
 
@@ -390,7 +388,6 @@ module.exports = function (app) {
390
388
  adapter.waitDevice(config.mac_address,(config?.discoveryTimeout??30)*1000)
391
389
  .then(async (device)=> {
392
390
  if (startNumber != starts ) {
393
- debugger
394
391
  return
395
392
  }
396
393
  //app.debug(`Found ${config.mac_address}`)
@@ -400,8 +397,14 @@ module.exports = function (app) {
400
397
  reject ( `Device is blacklisted (${s.reasonForBlacklisting()}).`)
401
398
  else{
402
399
  addSensorToList(s)
400
+ s._lastRSSI=-1*Infinity
403
401
  s.on("RSSI",(()=>{
404
- updateSensor(s)
402
+ if (Date.now()-s._lastRSSI > 20000) { //only update RSSI on client every five seconds
403
+ //app.debug(`${s.getMacAddress()} ${Date.now()-s._lastRSSI}`)
404
+ s._lastRSSI=Date.now()
405
+ updateSensor(s)
406
+ }
407
+
405
408
  }))
406
409
  resolve(s)
407
410
  }
@@ -443,7 +446,7 @@ module.exports = function (app) {
443
446
  app.setPluginError(msg)
444
447
  }
445
448
  //if we're here ain't got no class for the device
446
- var sensor
449
+ var sensor
447
450
  if (config.params?.sensorClass){
448
451
  var c = classMap.get(config.params.sensorClass)
449
452
  } else{
@@ -636,15 +639,18 @@ module.exports = function (app) {
636
639
  }
637
640
  }
638
641
  const minTimeout=Math.min(...deviceConfigs.map((dc)=>dc?.discoveryTimeout??options.discoveryTimeout))
639
-
642
+ const intervalTimeout = ((minTimeout==Infinity)?(options?.discoveryTimeout??plugin.schema.properties.discoveryTimeout.default):minTimeout)*1000
640
643
  deviceHealthID = setInterval( ()=> {
641
644
  sensorMap.forEach((sensor)=>{
642
645
  const config = getDeviceConfig(sensor.getMacAddress())
643
646
  const dt = config?.discoveryTimeout??options.discoveryTimeout
644
- if (sensor.elapsedTimeSinceLastContact()> dt)
647
+ const lc=sensor.elapsedTimeSinceLastContact()
648
+ if (lc > dt) {
649
+ app.debug(`${sensor.getMacAddress()} not heard from in ${lc} seconds`)
645
650
  channel.broadcast(getSensorInfo(sensor), "sensorchanged")
651
+ }
646
652
  })
647
- }, (minTimeout==Infinity)?(options?.discoveryTimeout??plugin.schema.properties.discoveryTimeout.default):minTimeout)
653
+ }, intervalTimeout)
648
654
 
649
655
  if (!options.hasOwnProperty("discoveryInterval" )) //no config -- first run
650
656
  options.discoveryInterval = plugin.schema.properties.discoveryInterval.default
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.7",
3
+ "version": "1.2.0-beta.0.0.9",
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": {
@@ -22,6 +22,7 @@
22
22
  "environment":{
23
23
  "temperature":
24
24
  {
25
+ "title":"Current zone's temperature",
25
26
  "unit":"K",
26
27
  "default": "environment.{zone}.temperature"
27
28
  },
@@ -32,15 +33,15 @@
32
33
  },
33
34
  "relativeHumidity":
34
35
  {
35
- "title":"Current relative humidity",
36
+ "title":"Current zone's relative humidity",
36
37
  "unit":"ratio",
37
- "default":"environment.{zone}.humidity"
38
+ "default":"environment.{zone}.relativeHumidity"
38
39
  },
39
40
  "pressure":
40
41
  {
41
- "title": "Current outside air ambient pressure",
42
+ "title": "Current zone's ambient air pressure",
42
43
  "unit":"Pa",
43
- "default":"environment.{zone}.humidity"
44
+ "default":"environment.{zone}.pressure"
44
45
  }
45
46
  },
46
47
  "electrical":{
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 s=n(3490),a=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("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 H(){console.log("refreshing sensor map"),async function(){console.log("getSensorData");const e=await P("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=>{M(new Map(e.map((e=>[e.info.mac,e]))))})).catch((e=>{L(e)}))}return(0,o.useEffect)((()=>{console.log("useEffect([])"),P("sendPluginState").then((async e=>{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("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=>{L(e)})),z().then((e=>{O(e)})).catch((e=>{L(e)}))):(M(new Map),n({}),b({}))}),[N]),(0,o.useEffect)((()=>{console.log("useEffect([error])"),console.log(J)}),[J]),(0,o.useEffect)((()=>{console.log("useEffect([sensorMap])"),S=T,k(Array.from(T.entries()).map((e=>{const t=T.get(e[0]),n=t.config,s=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:s?{fontWeight:"normal"}:{fontStyle:"italic"}},`${t._changesMade?"*":""}${t.info.name} MAC: ${t.info.mac} RSSI: ${a=t.info.RSSI,null==a?NaN:a}`,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 a})))}),[T]),"stopped"==N?r().createElement("h1",null,"Enable plugin to see configuration"):r().createElement("div",null,J?r().createElement("h2",{style:"color: red;"},J.message):"",r().createElement(s.Ay,{schema:t,validator:a.Ay,onChange:e=>b(e.formData),onSubmit:({formData:e},t)=>{var n;C(null),n=e,console.log("updateBaseData"),U("sendBaseData",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 click to configure":""),r().createElement("h2",null,T.size>0?"(* means 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"}},_),r().createElement("div",{style:{paddingLeft:10,paddingTop:10,display:0==Object.keys(y).length?"none":""}},r().createElement(s.Ay,{schema:y,validator:a.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("sendSensorData",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")))))))}}}]);
@@ -31,7 +31,7 @@ class Aranet4 extends AranetSensor{
31
31
  this.addDefaultPath("pressure","environment.pressure")
32
32
  .read=(buff)=>{return ((buff.readUInt16LE(12)))/10}
33
33
 
34
- this.addDefaultPath('relativeHumidity','environment.relative')
34
+ this.addDefaultPath('relativeHumidity','environment.relativeHumidity')
35
35
  .read=(buff)=>{return ((buff.readUInt8(14))/100)}
36
36
 
37
37
  this.addMetadatum('color', '', 'Warning color (G Y R)',
@@ -19,6 +19,8 @@ class GoveeH50xx extends BTSensor {
19
19
 
20
20
  initSchema(){
21
21
  super.initSchema()
22
+ this.addDefaultParam("zone")
23
+
22
24
  this.addDefaultPath("temp","environment.temperature")
23
25
  .read= (buffer)=>{return 273.15+(buffer.readUInt16LE(1)/100) }
24
26
 
@@ -335,8 +335,8 @@ class MopekaTankSensor extends BTSensor{
335
335
  if (this.name)
336
336
  return this.name
337
337
 
338
- const _name = MopekaDevice.get(this?.modelID??0x0).name
339
- return _name?_name:MopekaDevice.get(0x0).name
338
+ const _name = MopekaDevices.get(this?.modelID??0x0).name
339
+ return _name?_name:MopekaDevices.get(0x0).name
340
340
 
341
341
  }
342
342
  }
@@ -12,6 +12,9 @@ class UltrasonicWindMeter extends BTSensor{
12
12
  hasGATT(){
13
13
  return true
14
14
  }
15
+ usingGATT(){
16
+ return true
17
+ }
15
18
  emitGATT(){
16
19
  this.battCharacteristic.readValue()
17
20
  .then((buffer)=>
@@ -29,6 +32,7 @@ class UltrasonicWindMeter extends BTSensor{
29
32
  }
30
33
  initSchema(){
31
34
  super.initSchema()
35
+ this.getGATTParams()["useGATT"].default=true
32
36
  this.addDefaultPath("batt",'sensors.batteryStrength')
33
37
  .read=(buffer)=>{return (buffer.readUInt8())/100}
34
38
 
@@ -26,6 +26,7 @@ class VictronSmartBatteryProtect extends VictronSensor{
26
26
 
27
27
  initSchema(){
28
28
  super.initSchema()
29
+ this.addDefaultParam("id")
29
30
  this.addMetadatum('deviceState','', 'device state',
30
31
  (buff)=>{return VC.OperationMode.get(buff.readUInt8(1))})
31
32
  this.addMetadatum('outputStatus','', 'output status', //TODO
@@ -5,8 +5,7 @@ import {useEffect, useState} from 'react'
5
5
 
6
6
  import {Button, Grid} from '@material-ui/core';
7
7
 
8
-
9
- import { SignalCellular0Bar, SignalCellular1Bar, SignalCellular2Bar, SignalCellular3Bar, SignalCellular4Bar, SignalCellularConnectedNoInternet0Bar } from '@material-ui/icons';
8
+ import { SignalCellular0Bar, SignalCellular1Bar, SignalCellular2Bar, SignalCellular3Bar, SignalCellular4Bar, SignalCellularConnectedNoInternet0Bar } from '@material-ui/icons';
10
9
 
11
10
  const log = (type) => console.log.bind(console, type);
12
11
 
@@ -74,7 +73,7 @@ export default (props) => {
74
73
  }
75
74
 
76
75
  async function getSensorData(){
77
-
76
+ console.log("getSensorData")
78
77
  const response = await fetchJSONData("sensors")
79
78
  if (response.status!=200){
80
79
  throw new Error(`Unable get sensor data: ${response.statusText} (${response.status}) `)
@@ -86,7 +85,7 @@ export default (props) => {
86
85
  }
87
86
 
88
87
  async function getBaseData(){
89
-
88
+ console.log("getBaseData")
90
89
  const response = await fetchJSONData("base")
91
90
  if (response.status!=200){
92
91
  throw new Error(`Unable get base data: ${response.statusText} (${response.status}) `)
@@ -96,7 +95,7 @@ export default (props) => {
96
95
  return json
97
96
  }
98
97
  async function getProgress(){
99
-
98
+ console.log("getProgress")
100
99
  const response = await fetchJSONData("progress")
101
100
  if (response.status!=200){
102
101
  throw new Error(`Unable get progres: ${response.statusText} (${response.status}) `)
@@ -107,21 +106,26 @@ export default (props) => {
107
106
  }
108
107
 
109
108
  function updateSensorData(data){
109
+ console.log("updateSensorData")
110
110
  sendJSONData("sendSensorData", data).then((response)=>{
111
111
  if (response.status != 200) {
112
112
  throw new Error(response.statusText)
113
113
  }
114
- debugger
114
+ sensorMap.get(data.mac_address)._changesMade=false
115
115
  sensorMap.get(data.mac_address).config = data
116
116
 
117
117
  })
118
- }
118
+ }
119
119
 
120
120
  function undoChanges(mac) {
121
+ console.log("undoChanges")
122
+ sensorMap.get(mac)._changesMade = false
121
123
  setSensorData( sensorMap.get(mac).config )
122
124
  }
123
125
 
124
126
  function removeSensorData(mac){
127
+ console.log("removeSensorData")
128
+
125
129
  try{
126
130
 
127
131
  sendJSONData("removeSensorData", {mac_address:mac} ).then((response)=>{
@@ -142,6 +146,8 @@ export default (props) => {
142
146
 
143
147
 
144
148
  function updateBaseData(data){
149
+ console.log("updateBaseData")
150
+
145
151
  sendJSONData("sendBaseData", data).then( (response )=>{
146
152
  if (response.status != 200) {
147
153
  setError(new Error(`Unable to update base data: ${response.statusText} (${response.status})`))
@@ -170,7 +176,7 @@ export default (props) => {
170
176
 
171
177
 
172
178
  useEffect(()=>{
173
-
179
+ console.log("useEffect([])")
174
180
  fetchJSONData("sendPluginState").then( async (response)=> {
175
181
  const json = await response.json()
176
182
  setPluginState(json.state)
@@ -178,6 +184,7 @@ export default (props) => {
178
184
  const eventSource = new EventSource("/plugins/bt-sensors-plugin-sk/sse")
179
185
 
180
186
  eventSource.addEventListener("newsensor", (event) => {
187
+ console.log("newsensor")
181
188
  let json = JSON.parse(event.data)
182
189
 
183
190
  if (!_sensorMap.has(json.info.mac)) {
@@ -187,7 +194,9 @@ export default (props) => {
187
194
  });
188
195
 
189
196
  eventSource.addEventListener("sensorchanged", (event) => {
190
- let json = JSON.parse(event.data)
197
+ let json = JSON.parse(event.data)
198
+ console.log("sensorchanged")
199
+ console.log(json)
191
200
 
192
201
  if (_sensorMap.has(json.mac)) {
193
202
  let sensor = _sensorMap.get(json.mac)
@@ -196,12 +205,14 @@ export default (props) => {
196
205
  }
197
206
  });
198
207
  eventSource.addEventListener("progress", (event) => {
208
+ console.log("progress")
199
209
  const json = JSON.parse(event.data)
200
210
  setProgress(json)
201
211
  console.log(json)
202
212
  });
203
213
 
204
214
  eventSource.addEventListener("pluginstate", (event) => {
215
+ console.log("pluginstate")
205
216
  const json = JSON.parse(event.data)
206
217
  setPluginState(json.state)
207
218
  });
@@ -215,6 +226,7 @@ export default (props) => {
215
226
  },[])
216
227
 
217
228
  useEffect(()=>{
229
+ console.log("useEffect([pluginState])")
218
230
  if (pluginState=="started"){
219
231
  refreshSensors()
220
232
 
@@ -240,6 +252,7 @@ useEffect(()=>{
240
252
  },[pluginState])
241
253
 
242
254
  useEffect(()=>{
255
+ console.log("useEffect([error])")
243
256
  console.log(error)
244
257
  },[error])
245
258
 
@@ -269,6 +282,8 @@ function signalStrengthIcon(sensor){
269
282
 
270
283
  }
271
284
  useEffect(()=>{
285
+ console.log("useEffect([sensorMap])")
286
+
272
287
  _sensorMap = sensorMap
273
288
 
274
289
  setSensorList(
@@ -289,7 +304,7 @@ useEffect(()=>{
289
304
  }
290
305
  }>
291
306
  <div class="d-flex justify-content-between align-items-center" style={hasConfig?{fontWeight:"normal"}:{fontStyle:"italic"}}>
292
- {`${sensor.info.name} MAC: ${sensor.info.mac} RSSI: ${ifNullNaN(sensor.info.RSSI)}` }
307
+ {`${sensor._changesMade?"*":""}${sensor.info.name} MAC: ${sensor.info.mac} RSSI: ${ifNullNaN(sensor.info.RSSI)}` }
293
308
  <div class="d-flex justify-content-between ">
294
309
  {
295
310
  signalStrengthIcon(sensor)
@@ -329,7 +344,8 @@ useEffect(()=>{
329
344
  now={progress.progress}
330
345
  />:""
331
346
  }
332
- <h2>{`${sensorMap.size>0?" Bluetooth Devices click to configure":""}`}</h2>
347
+ <h2>{`${sensorMap.size>0?"Bluetooth Devices click to configure" :""}`}</h2>
348
+ <h2>{`${sensorMap.size>0?"(* means sensor has unsaved changes)" :""}`}</h2>
333
349
  <p></p>
334
350
  <div style={{paddingBottom: 20}} class="d-flex flex-wrap justify-content-start align-items-start">
335
351
  <ListGroup style={{ maxHeight: '300px', overflowY: 'auto' }}>
@@ -340,7 +356,14 @@ useEffect(()=>{
340
356
  schema={schema}
341
357
  validator={validator}
342
358
  uiSchema={uiSchema}
343
- onChange={(e) => setSensorData(e.formData)}
359
+ onChange={(e) => {
360
+ const s = sensorMap.get(e.formData.mac_address)
361
+ s._changesMade=true
362
+ //s.config = e.formData;
363
+
364
+ setSensorData(e.formData)
365
+ }
366
+ }
344
367
  onSubmit={({ formData }, e) => {
345
368
  console.log(formData)
346
369
  updateSensorData(formData)