bt-sensors-plugin-sk 1.3.0 → 1.3.2

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
@@ -856,6 +856,10 @@ class BTSensor extends EventEmitter {
856
856
  return this.currentProperties?.RSSI??NaN
857
857
  }
858
858
 
859
+ isPaired(){
860
+ return this.currentProperties?.Paired??false
861
+ }
862
+
859
863
  getSignalStrength(){
860
864
  const rssi = this.getRSSI()
861
865
  if (!rssi)
package/README.md CHANGED
@@ -1,6 +1,16 @@
1
1
  # Bluetooth Sensors for [Signal K](http://www.signalk.org)
2
2
 
3
3
  ## WHAT'S NEW
4
+ # Version 1.3.2
5
+
6
+ - Victron Alarm Reason improvements
7
+ - VictronOrionXS offReason text implementation
8
+ - Shelly Blu H&T description changes
9
+
10
+ # Version 1.3.1
11
+
12
+ - JBD Protection status
13
+ - SensorPush devices (untested)
4
14
 
5
15
  # Version 1.3.0
6
16
 
@@ -112,7 +122,7 @@ It's pretty easy to write and deploy your own sensor class for any currently uns
112
122
  |[Jikong](https://jikongbms.com/)| https://jikongbms.com/product/ |
113
123
  |[Junctek](https://www.junteks.com)|[Junctek BMS](https://www.junteks.com/pages/product/index) |
114
124
  |[Remoran](https://remoran.eu)| [Remoran Wave.3](https://remoran.eu/wave.html)|
115
- |[AC DC Systems](https://marinedcac.com) | [Bank Manager] hybrid (Pb and Li) charger(https://marinedcac.com/pages/bankmanager)|
125
+ |[AC DC Systems](https://marinedcac.com) | [Bank Manager](https://marinedcac.com/pages/bankmanager) hybrid (Pb and Li) charger|
116
126
  |[Ective](https://ective.de/)| Also Topband(?), Skanbatt and others |
117
127
 
118
128
  ### Environmental
@@ -128,6 +138,7 @@ It's pretty easy to write and deploy your own sensor class for any currently uns
128
138
  |[Govee](http://www.govee.com)| Govee H50xx and H510x Temperature and humidity sensors |
129
139
  |[BTHome](https://bthome.io/)| NOTE: Framework for IOT sensor devices. |
130
140
  |[Inkbird](https://inkbird.com/)| TH-2 Temp and Humidity Sensor |
141
+ |[SensorPush](https://www.sensorpush.com/)| Temperature, Humidity and Atmospheric Pressure sensor|
131
142
 
132
143
 
133
144
  ### Tanks
package/index.js CHANGED
@@ -110,7 +110,7 @@ class MissingSensor {
110
110
  on(){
111
111
 
112
112
  }
113
-
113
+ stopNotifications(){}
114
114
  isError(){
115
115
  return true
116
116
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bt-sensors-plugin-sk",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
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": {
Binary file
@@ -348,7 +348,7 @@ class GobiusCTankMeter extends BTSensor{
348
348
  }
349
349
 
350
350
  async deactivateGATT(){
351
- await this.stopNotifications(this.characteristic)
351
+ await this.stopGATTNotifications(this.characteristic)
352
352
  await super.deactivateGATT()
353
353
  }
354
354
 
@@ -62,15 +62,41 @@ class JBDBMS extends BTSensor {
62
62
  .read=(buffer)=>{return buffer.readUInt16BE(12)}
63
63
 
64
64
  this.addMetadatum('protectionStatus', '', 'Protection Status',
65
- (buffer)=>{return buffer.readUInt16BE(20)} )
65
+ (buffer)=>{
66
+ const bits = buffer.readUInt16BE(20).toString(2)
67
+ return {
68
+ singleCellOvervolt: bits[0]=='1',
69
+ singleCellUndervolt: bits[1]=='1',
70
+ packOvervolt: (bits[2]=='1'),
71
+ packUndervolt: bits[3]=='1',
72
+ chargeOvertemp:bits[4]=='1',
73
+ chargeUndertemp:bits[5]=='1',
74
+ dischargeOvertemp:bits[6]=='1',
75
+ dischargeUndertemp:bits[7]=='1',
76
+ chargeOvercurrent:bits[8]=='1',
77
+ dischargeOvercurrent:bits[9]=='1',
78
+ shortCircut:bits[10]=='1',
79
+ frontEndDetectionICError:bits[11]=='1',
80
+ softwareLockMOS:bits[12]=='1',
81
+ }
82
+ })
66
83
  .default="electrical.batteries.{batteryID}.protectionStatus"
67
84
 
68
85
  this.addDefaultPath('SOC','electrical.batteries.capacity.stateOfCharge')
69
86
  .read=(buffer)=>{return buffer.readUInt8(23)/100}
70
-
71
- this.addMetadatum('FET', '', 'FET Control',
72
- (buffer)=>{return buffer.readUInt8(24)} )
73
- .default="electrical.batteries.{batteryID}.FETControl"
87
+
88
+
89
+ this.addMetadatum('FET', '', 'FET On/Off Status',
90
+ (buffer)=>{return buffer.readUInt8(24) !=0 } )
91
+ .default="electrical.batteries.{batteryID}.FETStatus"
92
+
93
+ this.addMetadatum('FETCharging', '', 'FET Status Charging',
94
+ (buffer)=>{return (buffer.readUInt8(24) & 0x1) !=0 })
95
+ .default="electrical.batteries.{batteryID}.FETStatus.charging"
96
+
97
+ this.addMetadatum('FETDischarging', '', 'FET Status Discharging',
98
+ (buffer)=>{return (buffer.readUInt8(24) & 0x2) !=0 })
99
+ .default="electrical.batteries.{batteryID}.FETStatus.discharging"
74
100
 
75
101
  await this.deviceConnect()
76
102
  const gattServer = await this.device.gatt()
@@ -0,0 +1,123 @@
1
+ const BTSensor = require("../BTSensor");
2
+ class SensorPush extends BTSensor{
3
+ static Domain = BTSensor.SensorDomains.environmental
4
+
5
+ static async identify(device){
6
+
7
+ const name = await this.getDeviceProp(device,"Name")
8
+ const regex= /^SensorPush\s(HT|HTP)\s[0-9a-fA-F]{4}$/
9
+ if (name && name.match(regex))
10
+ return this
11
+ else
12
+ return null
13
+ }
14
+ static ImageFile="SensorPush.webp"
15
+ static Manufacturer="Cousins & Sears - Creative Technologists - Brooklyn, NY USA"
16
+ static ServiceUUID = "EF090000-11D6-42BA-93B8-9DD7EC090AB0"
17
+ static Characteristics =
18
+ {
19
+ tx: "EF090003-11D6-42BA-93B8-9DD7EC090AA9",
20
+ adv: "EF090005-11D6-42BA-93B8-9DD7EC090AA9",
21
+ batt: "EF090007-11D6-42BA-93B8-9DD7EC090AA9",
22
+ LED: "EF09000C-11D6-42BA-93B8-9DD7EC090AA9",
23
+ temp: "EF090080-11D6-42BA-93B8-9DD7EC090AA9",
24
+ hum: "EF090081-11D6-42BA-93B8-9DD7EC090AA9",
25
+ bar: "EF090082-11D6-42BA-93B8-9DD7EC090AA9"
26
+ }
27
+ pollFreq=30
28
+ hasGATT(){
29
+ return true
30
+ }
31
+ usingGATT(){
32
+ return true
33
+ }
34
+
35
+
36
+ async emitGATT(){
37
+ this.characteristics.temp.writeValue(0x01000000).then(async ()=>{
38
+ this.emitData("temp", await this.characteristics.temp.readValue())
39
+ this.emitData("hum", await this.characteristics.temp.readValue())
40
+ })
41
+ this.characteristics.bar.writeValue(0x01000000).then(async ()=>{
42
+ this.emitData("bar", await this.characteristics.bar.readValue())
43
+ })
44
+ }
45
+
46
+ initSchema(){
47
+ super.initSchema()
48
+ this.getGATTParams()["useGATT"].default=true
49
+
50
+ this.addDefaultParam("zone")
51
+
52
+ this.addParameter(
53
+ "tx",
54
+ {
55
+ title:'transmission rate in db',
56
+ type: 'number',
57
+ enum: [-21, -18, -15, -12, -9, -6, -3, 0, 1, 2, 3, 4, 5],
58
+ default: -3,
59
+ isRequired: true
60
+ }
61
+ )
62
+ this.addParameter(
63
+ "adv",
64
+ {
65
+ title:'advertising interval in ms',
66
+ type: 'number',
67
+ default: 1285,
68
+ minimum: Math.round((32*625)/1000),
69
+ maximum: Math.round((32767*625)/1000),
70
+ isRequired: true
71
+ }
72
+ )
73
+
74
+ this.addParameter(
75
+ "LED",
76
+ {
77
+ type: 'number',
78
+ title:'LED flashes per second (0=off, 1-127, 128=once every second',
79
+ default: 0,
80
+ minimum: 0,
81
+ maximum: 128,
82
+ isRequired: true
83
+ }
84
+ )
85
+
86
+ this.addDefaultPath("batt","sensors.batteryVoltage")
87
+ .read=(buffer)=>{ return buffer.readUInt16LE()/100}
88
+
89
+ this.addDefaultPath("temp","environment.temperature")
90
+ .read=(buffer)=>{ return buffer.readInt32E()/100}
91
+
92
+ this.addDefaultPath("humidity","environment.humidity")
93
+ .read=(buffer)=>{ return buffer.readInt32E()/10000}
94
+
95
+ this.addDefaultPath("pressure","environment.pressure")
96
+ .read=(buffer)=>{ return buffer.readInt32E()/100}
97
+
98
+ }
99
+
100
+ async initGATTConnection(isReconnecting){
101
+ await super.initGATTConnection(isReconnecting)
102
+ const gattServer = await this.getGATTServer()
103
+ const service = await gattServer.getPrimaryService(this.constructor.ServiceUUID)
104
+ this.characteristics={}
105
+ for (const c in this.constructor.Characteristics) {
106
+ this.characteristics[c] = await service.getCharacteristic(this.constructor.Characteristics[c])
107
+ }
108
+ if (this.tx) this.characteristics.tx.writeValueWithoutResponse(this.tx)
109
+ if (this.LED) this.characteristics.LED.writeValueWithoutResponse(this.LED)
110
+ if (this.adv) this.characteristics.tx.writeValueWithoutResponse(Math.round((this.adv/625)*1000))
111
+ }
112
+ async initGATTNotifications() {
113
+
114
+ }
115
+
116
+ async deactivateGATT(){
117
+ for (const c in this.characteristics) {
118
+ await this.stopGATTNotifications(this.characteristics[c])
119
+ }
120
+ await super.deactivateGATT()
121
+ }
122
+ }
123
+ module.exports=SensorPush
@@ -20,10 +20,10 @@ class ShellySBHT003C extends AbstractBTHomeSensor {
20
20
 
21
21
 
22
22
  getTextDescription(){
23
- return `NOTE: Device must be paired with SignalK server machine to operate properly. For more information about the sensor go here: <a href=https://us.shelly.com/products/shelly-blu-h-t-black target="_blank">Shelly Blu H&T</a>.`
23
+ return `NOTE: Device must be paired with SignalK server machine or you won't see updates (see: <a href=https://shelly-api-docs.shelly.cloud/docs-ble/common#pairing target="_blank">https://shelly-api-docs.shelly.cloud/docs-ble/common#pairing</a> ). For more information about the sensor go here: <a href=https://us.shelly.com/blogs/documentation/shelly-blu-h-t target="_blank">Shelly Blu H&T</a>.<br><br>Alternatively you can edit your /etc/bluetooth/main.conf file and set "TemporaryTimeout = 90" in the [General] section, then restart the bluetooth service.`
24
24
  }
25
25
 
26
- initSchema() {
26
+ initSchema() {
27
27
  super.initSchema()
28
28
  this.addDefaultParam("zone")
29
29
 
@@ -20,11 +20,11 @@ class ShellySBMO003Z extends AbstractBTHomeSensor {
20
20
  * @type {string}
21
21
  */
22
22
  static LOCAL_NAME="Shelly BLU Motion";
23
- static ImageFile="ShellyBLUMotion.webp"
23
+ static ImageFile="ShellyBLUMotion.webp"
24
24
 
25
25
  getTextDescription(){
26
- return `NOTE: Device must be paired with SignalK server machine to operate properly. For more information about the sensor go here: <a href=https://us.shelly.com/products/shelly-blu-motion target="_blank">Shelly Blu Motion</a>.`
27
- }
26
+ return `${!this.isPaired()?"NOTE: Device must be paired with SignalK server machine to operate properly (see: <a href=https://shelly-api-docs.shelly.cloud/docs-ble/common#pairing target=\"_blank\">https://shelly-api-docs.shelly.cloud/docs-ble/common#pairing</a> ":"Device is paired."}).<br><br>For more information about the sensor click here: <a href=https://us.shelly.com/products/shelly-blu-motion target="_blank">Shelly Blu Motion</a>.`
27
+ }
28
28
 
29
29
  initSchema() {
30
30
  super.initSchema()
@@ -62,20 +62,6 @@ class ShellySBMO003Z extends AbstractBTHomeSensor {
62
62
  .default="sensors.{macAndName}.button"
63
63
 
64
64
 
65
- /*
66
- this.addMetadatum(
67
- "packetID",
68
- null,
69
- "packetID from sensor",
70
- this.parsePacketID.bind(this)
71
- )
72
- .default="sensors.{macAndName}.packetID"
73
- */
74
-
75
- }
76
- getState() {
77
-
78
- return super.getState()
79
65
  }
80
66
  }
81
67
 
@@ -18,6 +18,14 @@ const ProtectionStatus = {
18
18
  0x4000: "Short Circuit Protection"
19
19
  }
20
20
 
21
+ const BatteryState = {
22
+ 0: "Discharging/Idle",
23
+ 1: "Charging",
24
+ 2: "Discharging",
25
+ 4: "Charge Disabled"
26
+
27
+ }
28
+
21
29
  class ShenzhenLiONBMS extends BTSensor{
22
30
  static Domain = BTSensor.SensorDomains.electrical
23
31
  static ImageFile = "LiTimeLiFePo4Battery.avif"
@@ -91,6 +99,9 @@ class ShenzhenLiONBMS extends BTSensor{
91
99
  this.addMetadatum(`cell${cellNum+1}Voltage`,'V', `cell #${cellNum+1} voltage`,
92
100
  (buff)=>{return buff.readInt16LE(16+(cellNum*2)) /1000})
93
101
  .default=`electrical.batteries.{batteryID}.cells.${cellNum+1}.voltage`
102
+
103
+ this.addMetadatum(`cell${cellNum+1}Balancing`,'', `cell #${cellNum+1} balance state (true=balancing)`)
104
+ .default=`electrical.batteries.{batteryID}.cells.${cellNum+1}.balancing`
94
105
  }
95
106
 
96
107
  this.addDefaultPath('current','electrical.batteries.current')
@@ -119,19 +130,15 @@ class ShenzhenLiONBMS extends BTSensor{
119
130
  .default="electrical.batteries.{batteryID}.balanceMemoryActive"
120
131
 
121
132
  this.addMetadatum('protectionState','', 'protection state',
122
- (buff)=>{return buff.slice(76,80).reverse().join("")})
133
+ (buff)=>{return ProtectionStatus[buff.readUInt16LE(76)]??"Normal"})
123
134
  .default="electrical.batteries.{batteryID}.protectionState"
124
135
 
125
136
  this.addMetadatum('failureState','', 'failure state',
126
137
  (buff)=>{return buff.slice(80,84).reverse().join("").slice(-3)})
127
138
  .default="electrical.batteries.{batteryID}.failureState"
128
-
129
- this.addMetadatum('balanceState','', '1 = cell at offset is balancing',
130
- (buff)=>{return buff.slice(84,88).reverse().join("")})
131
- .default="electrical.batteries.{batteryID}.balanceState"
132
139
 
133
140
  this.addMetadatum('batteryState','', 'charge disabled = "0004", charging = "0001" (when charging active app will show estimated time untill fully charged), discharging/idle: "0000", unkown = "0002"',
134
- (buff)=>{return buff.slice(88,90).reverse().join("")})
141
+ (buff)=>{return (BatteryState[buff.readUInt16LE(88)])??"Unknown"})
135
142
  .default="electrical.batteries.{batteryID}.batteryState"
136
143
 
137
144
  this.addMetadatum('dischargeCount','', 'discharge count',
@@ -148,6 +155,16 @@ class ShenzhenLiONBMS extends BTSensor{
148
155
  this.getJSONSchema().properties.params.required=["batteryID", "numberOfCells" ]
149
156
  }
150
157
 
158
+ emitValuesFrom(buffer){
159
+ super.emitValuesFrom(buffer)
160
+ const balanceState= buffer.slice(84,88).reverse().join("")
161
+
162
+ for(let cellNum=0; cellNum < this?.numberOfCells??4; cellNum++) {
163
+ this.emit(`cell${cellNum+1}Balancing`, balanceState[cellNum]==='1')
164
+ }
165
+
166
+ }
167
+
151
168
  async initGATTConnection(isReconnecting){
152
169
 
153
170
  await super.initGATTConnection(isReconnecting)