bt-sensors-plugin-sk 1.3.6 → 1.3.8-beta1

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
@@ -105,7 +105,7 @@ class BTSensor extends EventEmitter {
105
105
 
106
106
  Object.assign(this,config)
107
107
  Object.assign(this,gattConfig)
108
-
108
+
109
109
  this._state = "UNKNOWN"
110
110
  }
111
111
  /**
@@ -155,7 +155,7 @@ class BTSensor extends EventEmitter {
155
155
  static _test(data, key, config={}){
156
156
  var b = Buffer.from(data.replaceAll(" ",""),"hex")
157
157
  const d = new this(null,config)
158
- d.initMetadata()
158
+ d.initSchema()
159
159
  Object.keys(d.getPaths()).forEach((tag)=>{
160
160
  d.on(tag,(v)=>console.log(`${tag}=${v}`))
161
161
  })
@@ -319,15 +319,17 @@ class BTSensor extends EventEmitter {
319
319
  type: "integer", default:30,
320
320
  minimum: 10,
321
321
  maximum: 600 },
322
- noContactThreshhold: {title: "If no contact (in seconds), raise warning. Set to 0 to disable",
323
- type: "integer",
324
- minimum: 0,
325
- maximum: 600,
326
- default: 2*(this?.discoveryTimeout??30) },
322
+
327
323
  params:{
328
324
  title:`Device parameters`,
329
325
  type:"object",
330
- properties:{}
326
+ properties:{
327
+ noContactThreshold: {title: "If no contact (in seconds), raise warning. Set to 0 to disable",
328
+ type: "integer",
329
+ minimum: 0,
330
+ maximum: 600,
331
+ default: 2*(this?.discoveryTimeout??30) }
332
+ }
331
333
  },
332
334
  paths:{
333
335
  title:"Signalk Paths",
@@ -349,7 +351,13 @@ class BTSensor extends EventEmitter {
349
351
  pollFreq: { type: "number", title: "Polling frequency in seconds"}
350
352
  }
351
353
  }
352
- }
354
+ } else{
355
+ this._schema.properties.params.properties.minUpdateInterval=
356
+ {title: "Minimum update interval in milliseconds (0 to disable rate limiting).",
357
+ type: "integer",
358
+ minimum: 0,
359
+ default: 0 }
360
+ }
353
361
 
354
362
 
355
363
  //create the 'name' parameter
@@ -367,9 +375,8 @@ class BTSensor extends EventEmitter {
367
375
 
368
376
  }
369
377
  async init(){
370
- this.setState("INITIALIZING")
371
-
372
378
  this.currentProperties = await this.constructor.getDeviceProps(this.device)
379
+ this.setState("INITIALIZING");
373
380
  await this.initSchema()
374
381
 
375
382
  this.initListen()
@@ -580,7 +587,7 @@ class BTSensor extends EventEmitter {
580
587
  isError(){
581
588
  return this._error
582
589
  }
583
- deviceConnect(isReconnecting=false, autoReconnect=false) {
590
+ deviceConnect(isReconnecting=false, autoReconnect=false, timeout=30000) {
584
591
 
585
592
  return connectQueue.enqueue( async ()=>{
586
593
  this.debug(`Connecting... ${this.getName()}`)
@@ -595,10 +602,27 @@ class BTSensor extends EventEmitter {
595
602
  this.setConnected(true)
596
603
  })
597
604
  }
598
- await this.device.helper.callMethod('Connect')
605
+ const connectTimeoutID = setTimeout(
606
+ ()=>{
607
+ const e = `Connect timed out. Unable to connect after ${timeout}ms.`
608
+ this.setError(e)
609
+ throw new Error(e)
610
+ }
611
+ ,timeout
612
+ )
613
+ try {
614
+ await this.device.helper.callMethod('Connect')
615
+ } catch (e) {
616
+ this.debug(e)
617
+ throw new Error(e.message)
618
+ }
619
+ finally {
620
+ clearTimeout(connectTimeoutID)
621
+ }
599
622
  this.setConnected(true)
600
-
623
+ this._lastContact = Date.now()
601
624
  this.debug(`Connected to ${this.getName()}`)
625
+
602
626
  if (!isReconnecting) {
603
627
  this.device.helper.on(
604
628
  "PropertiesChanged",
@@ -698,23 +722,24 @@ class BTSensor extends EventEmitter {
698
722
  */
699
723
 
700
724
  async initGATTInterval(){
701
- await this.deviceDisconnect()
702
-
725
+ async function _emitGATT() {
726
+ try {
727
+ await this.initGATTConnection(true);
728
+ await this.emitGATT();
729
+ } catch (error) {
730
+ this.debug(error);
731
+ this.setError(`Unable to emit values for device: ${error.message}`);
732
+ } finally {
733
+ await this.deactivateGATT().catch((e) => {
734
+ this.debug(`Error deactivating GATT Connection: ${e.message}`);
735
+ });
736
+ this.setState("WAITING");
737
+ }
738
+ }
739
+ _emitGATT = _emitGATT.bind(this);
740
+ _emitGATT()
703
741
  this.intervalID = setInterval( async () => {
704
- try {
705
- await this.initGATTConnection(true)
706
- await this.emitGATT()
707
- }
708
- catch(error) {
709
- this.debug(error)
710
- this.setError(`Unable to emit values for device: ${error.message}`)
711
- }
712
- finally{
713
- await this.deactivateGATT().catch( (e)=>{
714
- this.debug(`Error deactivating GATT Connection: ${e.message}`)
715
- })
716
- this.setState("WAITING")
717
- }
742
+ await _emitGATT()
718
743
  }
719
744
  , this.pollFreq*1000)
720
745
  }
@@ -726,13 +751,20 @@ class BTSensor extends EventEmitter {
726
751
  * DBUS connection stays alive, doesn't tax resources and doesn't spit out spurious errors.
727
752
  */
728
753
  initPropertiesChanged(){
729
-
754
+ let lastPropsChanged = -1
730
755
  this._propertiesChanged.bind(this)
731
756
  this.device.helper._prepare()
732
757
  this.device.helper.on("PropertiesChanged",
733
758
  ((props)=> {
759
+ if ( this.minUpdateInterval &&
760
+ lastPropsChanged>0 &&
761
+ (Date.now() - lastPropsChanged) < this.minUpdateInterval) {
762
+ this.debug(`Ignoring properties changed. Last update was ${Date.now() - lastPropsChanged} ms ago.`)
763
+ return
764
+ }
734
765
  try{
735
766
  this._propertiesChanged(props)
767
+ lastPropsChanged = Date.now()
736
768
  }
737
769
  catch(error){
738
770
  this.debug(`Error occured on ${this.getNameAndAddress()}: ${error?.message??error}`)
@@ -766,7 +798,7 @@ class BTSensor extends EventEmitter {
766
798
  //Sensor description functions
767
799
 
768
800
  getMacAddress(){
769
- return this.currentProperties.Address
801
+ return this.currentProperties?.Address??"Unknown MAC"
770
802
  }
771
803
 
772
804
  static ImageFile = "bluetooth-logo.png"
@@ -849,7 +881,7 @@ class BTSensor extends EventEmitter {
849
881
  }
850
882
 
851
883
  getManufacturerData(key=null){
852
- if (this.currentProperties.ManufacturerData)
884
+ if (this.currentProperties?.ManufacturerData)
853
885
  if (key)
854
886
  return this.valueIfVariant (this.currentProperties.ManufacturerData[key])
855
887
  else
@@ -949,8 +981,8 @@ class BTSensor extends EventEmitter {
949
981
  this.currentProperties.ManufacturerData=this.valueIfVariant(props.ManufacturerData)
950
982
  if (this.isActive())
951
983
  this.propertiesChanged(props)
952
-
953
984
  }
985
+
954
986
  propertiesChanged(props){
955
987
  //implemented by subclass
956
988
  }
@@ -971,8 +1003,11 @@ class BTSensor extends EventEmitter {
971
1003
  this._currentValues[tag]=value
972
1004
  }
973
1005
 
974
- emit(tag, value){
1006
+ _emit(tag, value){
975
1007
  super.emit(tag, value)
1008
+ if (this.usingGATT()) //update last contact time only for GATT devices
1009
+ //which do not receive propertyChanged events when connected
1010
+ this._lastContact=Date.now()
976
1011
  this.setCurrentValue(tag,value)
977
1012
  }
978
1013
 
@@ -1069,7 +1104,7 @@ class BTSensor extends EventEmitter {
1069
1104
  this._app.handleMessage(id,
1070
1105
  {
1071
1106
  updates:
1072
- [{ meta: [{path: this.preparePath(path), value: { units: pathMeta?.unit, zones:pathMeta?.zones } }]}]
1107
+ [{ meta: [{path: this.preparePath(path), value: { units: pathMeta?.unit, zones:pathMeta?.zones, renderer:pathMeta?.renderer } }]}]
1073
1108
  })
1074
1109
  }
1075
1110
  })
@@ -1089,8 +1124,10 @@ class BTSensor extends EventEmitter {
1089
1124
  })
1090
1125
  }
1091
1126
  updatePath(path, val, id, source){
1127
+
1092
1128
  this._app.handleMessage(id, {updates: [ { $source: source, values: [ { path: path, value: val }] } ] })
1093
1129
  }
1130
+
1094
1131
  elapsedTimeSinceLastContact(){
1095
1132
  if (this.device instanceof OutOfRangeDevice)
1096
1133
  return Infinity
@@ -1,5 +1,4 @@
1
1
 
2
- const { toPathSchema } = require('@rjsf/utils');
3
2
  const EventEmitter = require('node:events');
4
3
 
5
4
  class OutOfRangeDevice extends EventEmitter{
package/README.md CHANGED
@@ -2,6 +2,34 @@
2
2
 
3
3
  ## WHAT'S NEW
4
4
 
5
+ # Version 1.3.8-beta1
6
+
7
+ ## New sensors
8
+
9
+ - MicrotikTag
10
+ - SensorPush
11
+
12
+ ## New features
13
+
14
+ - Rate limiter
15
+
16
+ # Version 1.3.7
17
+
18
+ ### Issues Addressed
19
+
20
+ - https://github.com/naugehyde/bt-sensors-plugin-sk/issues/113
21
+ - https://github.com/naugehyde/bt-sensors-plugin-sk/issues/108
22
+ - https://github.com/naugehyde/bt-sensors-plugin-sk/issues/107
23
+ - https://github.com/naugehyde/bt-sensors-plugin-sk/issues/106
24
+ - https://github.com/naugehyde/bt-sensors-plugin-sk/issues/103
25
+
26
+ ### Pull Requests included
27
+
28
+ - https://github.com/naugehyde/bt-sensors-plugin-sk/pull/97
29
+ - https://github.com/naugehyde/bt-sensors-plugin-sk/pull/104
30
+ - https://github.com/naugehyde/bt-sensors-plugin-sk/pull/111
31
+ - https://github.com/naugehyde/bt-sensors-plugin-sk/pull/114
32
+
5
33
  # Version 1.3.6
6
34
 
7
35
  - New sensor parameter: no contact threshhold.
@@ -153,6 +181,8 @@ It's pretty easy to write and deploy your own sensor class for any currently uns
153
181
  |[Remoran](https://remoran.eu)| [Remoran Wave.3](https://remoran.eu/wave.html)|
154
182
  |[AC DC Systems](https://marinedcac.com) | [Bank Manager](https://marinedcac.com/pages/bankmanager) hybrid (Pb and Li) charger|
155
183
  |[Ective](https://ective.de/)| Also Topband(?), Skanbatt and others |
184
+ |[Leagend](https://leagend.com)| BM 2/6/7 Battery Monitors aka Alcel BM200 and others. See: https://leagend.com/products/bm6|
185
+
156
186
 
157
187
  ### Environmental
158
188
  | Manufacturer | Devices |
package/classLoader.js CHANGED
@@ -15,7 +15,7 @@ const semver = require('semver')
15
15
  classMap.set(cls.name, cls);
16
16
  }
17
17
  catch (e) {
18
- console.log(`Unable to load class (${cls?.name}): ${e.message}`)
18
+ console.log(`Unable to load classfile (${file}): ${e.message}`)
19
19
  console.log(e)
20
20
  }
21
21
 
@@ -38,7 +38,7 @@ const semver = require('semver')
38
38
  const cls = require(module.location+module.module+"/"+classFile);
39
39
  classMap.set(cls.name, cls);
40
40
  } catch (e) {
41
- console.log(`Unable to load class (${cls.name}): ${e.message}`)
41
+ console.log(`Unable to load classfile (${file}): ${e.message}`)
42
42
  console.log(e)
43
43
  }
44
44
  })
package/index.js CHANGED
@@ -589,7 +589,9 @@ module.exports = function (app) {
589
589
  }
590
590
 
591
591
  }
592
-
592
+ function activeDevices(){
593
+ return Array.from(sensorMap.values()).filter(s=>s.isActive()).length
594
+ }
593
595
  function initConfiguredDevice(deviceConfig){
594
596
  const startNumber=starts
595
597
  plugin.setStatusText(`Initializing ${deviceNameAndAddress(deviceConfig)}`);
@@ -600,9 +602,10 @@ module.exports = function (app) {
600
602
  return
601
603
  }
602
604
  if (deviceConfig.active && !(sensor.device instanceof OutOfRangeDevice) ) {
603
- plugin.setStatusText(`Listening to ${++foundConfiguredDevices} sensors.`);
604
605
  try {
605
606
  await sensor.activate(deviceConfig, plugin)
607
+ plugin.setStatusText(`Listening to ${activeDevices()} sensors.`);
608
+
606
609
  } catch (e){
607
610
  sensor.setError(`Unable to activate sensor. Reason: ${e.message}`)
608
611
  }
@@ -788,7 +791,7 @@ module.exports = function (app) {
788
791
  if (lc > dt) {
789
792
  updateSensor(sensor)
790
793
  }
791
- if (sensor.noContactThreshhold && lc>sensor.noContactThreshold){
794
+ if (sensor.noContactThreshold && lc>sensor.noContactThreshold){
792
795
  if (sensor.isActive())
793
796
  sensor.notifyNoContact()
794
797
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bt-sensors-plugin-sk",
3
- "version": "1.3.6",
3
+ "version": "1.3.8-beta1",
4
4
  "description": "Bluetooth Sensors for Signalk - see https://www.npmjs.com/package/bt-sensors-plugin-sk#supported-sensors for a list of supported sensors",
5
5
  "main": "index.js",
6
6
  "dependencies": {
@@ -24,7 +24,7 @@
24
24
  }
25
25
  },
26
26
  "environment":{
27
- "temperature":
27
+ "temperature":
28
28
  {
29
29
  "title": "Temperature",
30
30
  "description":"Current zone's temperature",
@@ -51,6 +51,29 @@
51
51
  "default":"environment.{zone}.pressure"
52
52
  }
53
53
  },
54
+ "navigation": {
55
+ "attitude": {
56
+ "pitch":
57
+ {
58
+ "description":"Current pitch",
59
+ "unit":"rad",
60
+ "default":"navigation.attitude.pitch"
61
+ },
62
+ "roll":
63
+ {
64
+ "description":"Current pitch",
65
+ "unit":"rad",
66
+ "default":"navigation.attitude.roll"
67
+ },
68
+ "yaw":
69
+ {
70
+ "description":"Current pitch",
71
+ "unit":"rad",
72
+ "default":"navigation.attitude.yaw"
73
+ }
74
+
75
+ }
76
+ },
54
77
  "electrical":{
55
78
  "inverters":{
56
79
  "ac":{
@@ -59,17 +82,17 @@
59
82
  "default":"electrical.inverters.{id}.ac.current"
60
83
  },
61
84
  "voltage":
62
- {
85
+ {
63
86
  "unit": "V",
64
87
  "default":"electrical.inverters.{id}.ac.voltage"
65
88
  },
66
89
  "power":
67
- {
90
+ {
68
91
  "unit": "W",
69
92
  "default":"electrical.inverters.{id}.ac.power"
70
93
  }
71
-
72
-
94
+
95
+
73
96
  },
74
97
  "dc":{
75
98
  "current":{
@@ -77,7 +100,7 @@
77
100
  "default":"electrical.inverters.{id}.dc.current"
78
101
  },
79
102
  "voltage":
80
- {
103
+ {
81
104
  "unit": "V",
82
105
  "default":"electrical.inverters.{id}.dc.voltage"
83
106
  }
@@ -91,19 +114,19 @@
91
114
  "default":"electrical.batteries.{batteryID}.current"
92
115
  },
93
116
  "voltage":
94
- {
117
+ {
95
118
  "unit": "V",
96
119
  "default": "electrical.batteries.{batteryID}.voltage"
97
120
  },
98
-
121
+
99
122
  "power":
100
- {
123
+ {
101
124
  "unit": "W",
102
125
  "default": "electrical.batteries.{batteryID}.power"
103
126
  },
104
-
127
+
105
128
  "impedance":
106
- {
129
+ {
107
130
  "unit": "Ohm",
108
131
  "default": "electrical.batteries.{batteryID}.impedance"
109
132
  },
@@ -136,23 +159,23 @@
136
159
  "stateOfCharge":{
137
160
  "description": "Battery's state of charge as ratio",
138
161
  "unit":"ratio",
139
- "default": "electrical.batteries.{batteryID}.capacity.stateOfCharge"
162
+ "default": "electrical.batteries.{batteryID}.capacity.stateOfCharge"
140
163
  },
141
164
  "stateOfHealth":{
142
165
  "description": "Battery's state of health as ratio",
143
166
  "unit":"ratio",
144
- "default": "electrical.batteries.{batteryID}.capacity.stateOfHealth"
167
+ "default": "electrical.batteries.{batteryID}.capacity.stateOfHealth"
145
168
  },
146
-
169
+
147
170
  "timeRemaining":{
148
171
  "description": "Time in seconds until battery reaches its discharge floor at current usage",
149
172
 
150
173
  "unit":"s",
151
- "default": "electrical.batteries.{batteryID}.capacity.timeRemaining"
152
-
174
+ "default": "electrical.batteries.{batteryID}.capacity.timeRemaining"
175
+
153
176
  }
154
177
  }
155
-
178
+
156
179
  }
157
180
  },
158
181
  "sensors":{
@@ -178,11 +201,11 @@
178
201
  "lower": 0,
179
202
  "state": "warn",
180
203
  "message": "Battery very low - change now"
181
- }
204
+ }
182
205
  ],
183
- "description":"Sensor battery strength"
206
+ "description":"Sensor battery strength"
184
207
  },
185
-
208
+
186
209
  "batteryVoltage":
187
210
  {
188
211
  "title":"Battery Voltage",
Binary file
Binary file