bt-sensors-plugin-sk 1.2.2 → 1.2.3

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
@@ -465,13 +465,26 @@ class BTSensor extends EventEmitter {
465
465
  throw new Error("::initGATTNotifications() should be implemented by the BTSensor subclass")
466
466
  }
467
467
 
468
- deviceConnect() {
468
+ deviceConnect(reconnect=false) {
469
469
 
470
470
 
471
471
  return connectQueue.enqueue( async ()=>{
472
472
  this.debug(`Connecting... ${this.getName()}`)
473
- await this.device.connect()
473
+ await this.device.helper.callMethod('Connect')
474
+
474
475
  this.debug(`Connected to ${this.getName()}`)
476
+ if (!reconnect) {
477
+ this.device.helper.on('PropertiesChanged', (propertiesChanged) => {
478
+ if ('Connected' in propertiesChanged) {
479
+ const { value } = propertiesChanged.Connected
480
+ if (value) {
481
+ this.device.emit('connect', { connected: true })
482
+ } else {
483
+ this.device.emit('disconnect', { connected: false })
484
+ }
485
+ }
486
+ })
487
+ }
475
488
 
476
489
  try {
477
490
 
package/README.md CHANGED
@@ -1,4 +1,10 @@
1
1
  # Bluetooth Sensors for [Signal K](http://www.signalk.org)
2
+ # Version 1.2.3
3
+
4
+ ## WHAT'S NEW SINCE VERSION 1.2.2
5
+
6
+ Bug fixes Remoran Wave.3, JunctekBMS, and ShenzhenLiOn
7
+
2
8
  # Version 1.2.2
3
9
 
4
10
  ## WHAT'S NEW SINCE VERSION 1.2.1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bt-sensors-plugin-sk",
3
- "version": "1.2.2",
4
- "description": "Bluetooth Sensors for Signalk - see https://www.npmjs.com/package/bt-sensors-plugin-sk for a list of supported classes",
3
+ "version": "1.2.3",
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": {
7
7
  "@rjsf/bootstrap-4": "^5.24.11",
@@ -52,10 +52,10 @@ class JBDBMS extends BTSensor {
52
52
  (buffer)=>{return buffer.readInt16BE(6) / 100}
53
53
 
54
54
  this.addDefaultPath('remainingCapacity','electrical.batteries.capacity.remaining')
55
- .read=(buffer)=>{return buffer.readUInt16BE(8) / 100}
55
+ .read=(buffer)=>{return (buffer.readUInt16BE(8) / 100)*3600}
56
56
 
57
57
  this.addDefaultPath('capacity','electrical.batteries.capacity.actual')
58
- .read=(buffer)=>{return buffer.readUInt16BE(10) / 100}
58
+ .read=(buffer)=>{return (buffer.readUInt16BE(10) / 100)*3600}
59
59
 
60
60
  this.addDefaultPath('cycles','electrical.batteries.cycles' )
61
61
  .read=(buffer)=>{return buffer.readUInt16BE(12)}
@@ -139,7 +139,7 @@ class JBDBMS extends BTSensor {
139
139
  let datasize = -1
140
140
  const timer = setTimeout(() => {
141
141
  clearTimeout(timer)
142
- reject(new Error(`Response timed out from JBDBMS device ${this.getName()}. `));
142
+ reject(new Error(`Response timed out (+30s) from JBDBMS device ${this.getName()}. `));
143
143
  }, 30000);
144
144
 
145
145
  const valChanged = async (buffer) => {
@@ -147,13 +147,12 @@ class JBDBMS extends BTSensor {
147
147
  if (buffer[0]!==0xDD || buffer.length < 5 || buffer[1] !== command)
148
148
  reject(`Invalid buffer from ${this.getName()}, not processing.`)
149
149
  else
150
- datasize=buffer[2]
150
+ datasize=buffer[3]
151
151
  }
152
152
  buffer.copy(result,offset)
153
- if (buffer[buffer.length-1]==0x77 && offset+buffer.length-6==datasize){
153
+ if (buffer[buffer.length-1]==0x77 && offset+buffer.length-7==datasize){
154
154
 
155
155
  result = Uint8Array.prototype.slice.call(result, 0, offset+buffer.length)
156
- this.debug(result)
157
156
  this.rxChar.removeAllListeners()
158
157
  clearTimeout(timer)
159
158
  if (!checkSum(result))
@@ -196,6 +195,20 @@ async getAndEmitCellVoltages(){
196
195
  }
197
196
 
198
197
  initGATTInterval(){
198
+ this.device.on("disconnect", ()=>{
199
+ if (this.isActive()) {
200
+ this.debug(`Device disconnected. Attempting to reconnect to ${this.getName()}`)
201
+ try {
202
+ this.deviceConnect(true).then(()=>{
203
+ this.debug(`Device reconnected -- ${this.getName()}`)
204
+ })
205
+ }
206
+ catch (e) {
207
+ this.debug(`Error while reconnecting to ${this.getName()}`)
208
+ }
209
+ }
210
+ })
211
+ this.emitGATT()
199
212
  this.initGATTNotifications()
200
213
  }
201
214
 
@@ -69,10 +69,10 @@ class JunctekBMS extends BTSensor{
69
69
  const v = parseInt(bytesToBase10String(value))
70
70
  switch (byte){
71
71
  case 0xC0:{
72
- emitData("voltage",v/100)
72
+ emit("voltage",v/100)
73
73
  }
74
74
  case 0xC1:{
75
- emitData("current",(v/100)*chargeDirection)
75
+ emit("current",(v/100)*chargeDirection)
76
76
  }
77
77
 
78
78
  case 0xD1:{
@@ -81,29 +81,29 @@ class JunctekBMS extends BTSensor{
81
81
  }
82
82
 
83
83
  case 0xD2:{
84
- emitData("remainingAh",v/1000)
84
+ emit("remainingAh",v/1000)
85
85
  }
86
86
 
87
87
  case 0xD3:{
88
- emitData("discharge",v/100000)
88
+ emit("discharge",v/100000)
89
89
  }
90
90
  case 0xD4:{
91
- emitData("charge",v/100000)
91
+ emit("charge",v/100000)
92
92
  }
93
93
  case 0xD6:{
94
- emitData("timeRemaining",v*60)
94
+ emit("timeRemaining",v*60)
95
95
  }
96
96
  case 0xD7:{
97
- emitData("impedance",v/100)
97
+ emit("impedance",v/100)
98
98
  }
99
99
  case 0xD8:{
100
- emitData("power",(v/100)*chargeDirection)
100
+ emit("power",(v/100)*chargeDirection)
101
101
  }
102
102
  case 0xD9:{
103
- emitData("temperature",v + 173.15) //assume C not F
103
+ emit("temperature",v + 173.15) //assume C not F
104
104
  }
105
105
  case 0xB1:{
106
- emitData("capacityActual",v /10 )
106
+ emit("capacityActual",v /10 )
107
107
  }
108
108
  }
109
109
  }
@@ -33,10 +33,10 @@ const states= ["Charging Needed", "Charging", "Floating", "Idle"]
33
33
  const BTSensor = require("../BTSensor");
34
34
  class RemoranWave3 extends BTSensor{
35
35
  static Domain = BTSensor.SensorDomains.electrical
36
- serviceUUID = "81D08DF0-C0F8-422A-9D9D-E4379BB1EA3B"
37
- info1CharUUID = "62C91222-FAFE-4F6E-95F0-AFC02BD19F2E"
36
+ serviceUUID = "81d08df0-c0f8-422a-9d9d-e4379bb1ea3b"
37
+ info1CharUUID = "62c91222-fafe-4f6e-95f0-afc02bd19f2e"
38
38
  info2CharUUID = "f5d12d34-4390-486c-b906-24ea8906af71"
39
- eventUuid = "f12a8e25-59f7-42f2-b7ae-ba96fb25c13c"
39
+ eventUUID = "f12a8e25-59f7-42f2-b7ae-ba96fb25c13c"
40
40
 
41
41
  static async identify(device){
42
42
 
@@ -53,57 +53,68 @@ const BTSensor = require("../BTSensor");
53
53
  return true
54
54
  }
55
55
  emitInfo1Data(buffer){
56
+ this.debug(`emitting info 1 data`)
56
57
  if (buffer.length < 20) {
57
58
  app.debug(`Bad buffer size ${buffer.length}. Buffer size must be 20 bytes or more.`)
58
59
  return
59
60
  }
60
- emitData("versionNumber", buffer.readUInt8(0))
61
+ this.emit("versionNumber", buffer.readUInt8(0))
61
62
  const errors = buffer.readUInt8(2)
62
63
  const errorState = []
63
64
  for (var i = 0; i < 8; ++i) {
64
65
  var c = 1 << i;
65
- r & c && errorState.push(errors[i])
66
+ errors & c && errorState.push(errors[i])
66
67
  }
67
- emitData("errors", errorState)
68
- emitData("state", states[buffer.readUInt8(3)])
69
- emitData("rpm", buffer.readUInt32LE(4))
70
- emitData( "voltage" , buffer.readFloatLE(8))
71
- emitData("current", buffer.readFloatLE(12))
72
- emitData( "power", buffer.readFloatLE(16))
68
+ this.emit("errors", errorState)
69
+ this.emit("state", states[buffer.readUInt8(3)])
70
+ this.emit("rpm", buffer.readUInt32LE(4))
71
+ this.emit( "voltage" , buffer.readFloatLE(8))
72
+ this.emit("current", buffer.readFloatLE(12))
73
+ this.emit( "power", buffer.readFloatLE(16))
73
74
 
74
75
  if (buffer.length > 23) {
75
- emitData( "temp", buffer.readFloatLE(20).toFixed(1))
76
- emitData( "uptime", buffer.readUInt32(24))
76
+ this.emit( "temp", ((buffer.readFloatLE(20))+273.15))
77
+ this.emit( "uptime", buffer.readUInt32LE(24))
77
78
  if (versionNumber>1 && buffer.size > 31) {
78
- emitData("energy", buffer.readFloatLE(32).toFixed(1))
79
+ this.emit("energy", buffer.readFloatLE(32))
79
80
  }
80
81
  }
81
82
 
82
83
  }
83
84
  emitInfo2Data(buffer){
85
+ this.debug(`emitting info 2 data`)
86
+
84
87
  if (buffer.size < 12) {
85
88
  app.debug(`Bad buffer size ${buffer.length}. Buffer size must be 12 bytes or more.`)
86
89
  return
87
90
  }
88
- emitData("versionNumber", buffer.getUint8(0))
89
- emitData("temp", buffer.readFloat32LE(4))
90
- emitData("uptime", buffer.readUInt32(8))
91
- emitData("lastBootTime", arduinoDateDecode(buffer.getUInt32LE(12)))
92
- emitData("energy", buffer.readFloat32LE(16))
91
+ this.emit("versionNumber", buffer.readUInt8(0))
92
+ this.emit("temp", ((buffer.readFloatLE(4))+273.15))
93
+ this.emit("uptime", buffer.readUInt32LE(8))
94
+ this.emit("lastBootTime", arduinoDateDecode(buffer.readUInt32LE(12)))
95
+ this.emit("energy", buffer.readFloatLE(16))
93
96
  }
94
97
  emitEventData(buffer){
95
- if (buffer.size < 14) {
98
+ this.debug(`emitting event data`)
99
+ if (buffer.length < 14) {
100
+ this.debug(buffer)
96
101
  app.debug(`Bad buffer size ${buffer.length}. Buffer size must be 14 bytes or more.`)
97
102
  return
98
103
  }
99
- this.emitData("event",
104
+ const eventType = buffer.readUInt16LE(8)
105
+ var eventDesc = eventType.toString()
106
+ if (Object.hasOwn(eventTypes,eventType))
107
+ eventDesc = eventTypes[eventType]
108
+
109
+
110
+ this.emit("event",
100
111
  {
101
112
  firstDate: arduinoDateDecode(buffer.readUInt32LE(0)),
102
113
  lastDate: arduinoDateDecode(buffer.readUInt32LE(4)),
103
- eventType: buffer.readUInt16LE(8),
114
+ eventType: eventType,
104
115
  count: buffer.readUInt16LE(10),
105
116
  index: buffer.readUInt16LE(12),
106
- eventDesc: eventTypes[i]
117
+ eventDesc: eventDesc
107
118
  }
108
119
  )
109
120
  }
@@ -174,10 +185,10 @@ const BTSensor = require("../BTSensor");
174
185
  this.gattServer = await this.device.gatt()
175
186
  this.service = await this.gattServer.getPrimaryService(this.serviceUUID)
176
187
  this.info1Characteristic = await this.service.getCharacteristic(this.info1CharUUID)
177
- this.info2Characteristic = await this.service.getPrimaryService(this.info2CharUUID)
188
+ this.info2Characteristic = await this.service.getCharacteristic(this.info2CharUUID)
178
189
  this.eventCharacteristic = await this.service.getCharacteristic(this.eventUUID)
179
190
  resolve(this)
180
- }}) .catch((e)=>{ reject(e.message) }) })
191
+ }}) .catch((e)=>{ this.debug(e); reject(e.message) }) })
181
192
  }
182
193
 
183
194
  initGATTNotifications() {
@@ -205,9 +216,9 @@ const BTSensor = require("../BTSensor");
205
216
  }
206
217
  async stopListening(){
207
218
  super.stopListening()
208
- await stopNotifations(this.info1Characteristic)
209
- await stopNotifations(this.info2Characteristic)
210
- await stopNotifations(this.eventCharacteristic)
219
+ await this.stopNotifications(this?.info1Characteristic)
220
+ await this.stopNotifications(this?.info2Characteristic)
221
+ await this.stopNotifications(this?.eventCharacteristic)
211
222
  if (await this.device.isConnected()){
212
223
  await this.device.disconnect()
213
224
  }
@@ -13,7 +13,8 @@ CHARGING_STATE:
13
13
  3: 'Equalizing',
14
14
  4: 'Boost',
15
15
  5: 'Floating',
16
- 6: 'Current limiting'
16
+ 6: 'Current limiting',
17
+ 8: 'Not charging'
17
18
  },
18
19
 
19
20
  LOAD_STATE: {
@@ -57,9 +57,6 @@ class RenogySensor extends BTSensor{
57
57
  )
58
58
  }
59
59
 
60
- emitGATT(){
61
- }
62
-
63
60
  getModelName(){
64
61
  return this?.modelID??`${this.constructor.name} Unknown model`
65
62
  }
@@ -86,7 +83,6 @@ class RenogySensor extends BTSensor{
86
83
  }
87
84
 
88
85
  initGATTInterval(){
89
- this.emitGATT()
90
86
  this.intervalID = setInterval(()=>{
91
87
  this.emitGATT()
92
88
  }, 1000*(this?.pollFreq??60) )
@@ -6,53 +6,113 @@ const RenogySensor = require("./Renogy/RenogySensor.js");
6
6
  const RC=require("./Renogy/RenogyConstants.js")
7
7
 
8
8
  class RenogyRoverClient extends RenogySensor {
9
-
9
+ /*
10
+ "batteryType": "electrical.charger.battery.type",
11
+ "batteryPercentage": "electrical.charger.battery.charge",
12
+ "batteryVoltage": "electrical.charger.battery.voltage",
13
+ "batteryCurrent": "electrical.charger.battery.current",
14
+ "controllerTemperature": "electrical.charger.temperature",
15
+ "batteryTemperature": "electrical.charger.battery.temperature",
16
+ "loadVoltage": "electrical.charger.load.voltage",
17
+ "loadCurrent": "electrical.charger.load.current",
18
+ "loadPower": "electrical.charger.load.power",
19
+ "pvVoltage": "electrical.charger.solar.voltage",
20
+ "pvCurrent": "electrical.charger.solar.current",
21
+ "pvPower": "electrical.charger.solar.power",
22
+ "maxChargingPowerToday": "electrical.charger.today.max",
23
+ "maxDischargingPowerToday": "electrical.charger.discharging.maximum",
24
+ "chargingAmpHoursToday": "electrical.charger.charged.today",
25
+ "powerGenerationToday": "electrical.charger.power.today",
26
+ "powerGenerationTotal": "electrical.charger.power.total",
27
+ "loadStatus": "electrical.charger.load.status",
28
+ "chargingStatus": "electrical.charger.status"
29
+ */
10
30
 
11
31
  initSchema(){
12
32
  //Buffer(73) [1, 3, 68, 32, 32, 82, 78, 71, 45, 67, 84, 82, 76, 45, 87, 78, 68, 51, 48, 7, 140, 0, 132, 0, 126, 0, 120, 0, 111, 0, 106, 100, 50, 0, 5, 0, 120, 0, 120, 0, 28, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 5, 0, 5, 2, 148, 0, 5, 206, 143, 34, 228, buffer: ArrayBuffer(8192), byteLength: 73, byteOffset: 6144, length: 73, Symbol(Symbol.toStringTag): 'Uint8Array']
13
33
  super.initSchema()
14
34
  this.addMetadatum('batteryType', '', "battery type")
35
+ .default="electrical.chargers.{id}.battery.type"
15
36
  this.addMetadatum('batteryPercentage', 'ratio', "battery percentage",
16
37
  (buffer)=>{return buffer.readUInt16BE(3) })
38
+ .default="electrical.chargers.{id}.battery.soc"
39
+
17
40
  this.addMetadatum('batteryVoltage', 'V', "battery voltage",
18
41
  (buffer)=>{return buffer.readUInt16BE((5))/10})
42
+ .default="electrical.chargers.{id}.battery.voltage"
43
+
19
44
  this.addMetadatum('batteryCurrent', 'A', 'battery current',
20
45
  (buffer)=>{return buffer.readUInt16BE((7))/100})
46
+ .default="electrical.chargers.{id}.battery.current"
47
+
21
48
  this.addMetadatum('controllerTemperature', 'K', 'controller temperature',
22
49
  (buffer)=>{return buffer.readInt8((9))+273.15})
50
+ .default="electrical.chargers.{id}.controller.temperature"
51
+
23
52
  this.addMetadatum('batteryTemperature', 'K', 'battery temperature',
24
53
  (buffer)=>{return buffer.readInt8((10))+273.15})
54
+ .default="electrical.chargers.{id}.battery.temperature"
55
+
25
56
  this.addMetadatum('loadVoltage', 'V', 'load voltage',
26
57
  (buffer)=>{return buffer.readUInt16BE((11))/10})
58
+ .default="electrical.chargers.{id}.load.voltage"
59
+
27
60
  this.addMetadatum('loadCurrent', 'A', 'load current',
28
61
  (buffer)=>{return buffer.readUInt16BE((13))/100})
62
+ .default="electrical.chargers.{id}.load.current"
29
63
  this.addMetadatum('loadPower', 'W', 'load power',
30
64
  (buffer)=>{return buffer.readUInt16BE((15))})
65
+ .default="electrical.chargers.{id}.load.power"
31
66
  this.addMetadatum('pvVoltage', 'V', 'pv voltage',
32
67
  (buffer)=>{return buffer.readUInt16BE((17))/10})
68
+ .default="electrical.chargers.{id}.solar.voltage"
33
69
  this.addMetadatum('pvCurrent', 'A', 'pv current',
34
70
  (buffer)=>{return buffer.readUInt16BE((19))/100})
71
+ .default="electrical.chargers.{id}.solar.current"
35
72
  this.addMetadatum('pvPower', 'W', 'pv power',
36
73
  (buffer)=>{return buffer.readUInt16BE(21)})
74
+ .default="electrical.chargers.{id}.solar.power"
37
75
  this.addMetadatum('maxChargingPowerToday', 'W', 'max charging power today',
38
76
  (buffer)=>{return buffer.readUInt16BE(33)})
77
+ .default="electrical.chargers.{id}.charge.max.today"
39
78
  this.addMetadatum('maxDischargingPowerToday', 'W', 'max discharging power today',
40
79
  (buffer)=>{return buffer.readUInt16BE(35)})
80
+ .default="electrical.chargers.{id}.discharge.max.today"
41
81
  this.addMetadatum('chargingAmpHoursToday', 'Ah', 'charging amp hours today',
42
82
  (buffer)=>{return buffer.readUInt16BE(37)})
83
+ .default="electrical.chargers.{id}.charge.ampHours.today"
84
+
43
85
  this.addMetadatum('dischargingAmpHoursToday', 'Ah', 'discharging amp hours today',
44
86
  (buffer)=>{return buffer.readUInt16BE(39)})
87
+ .default="electrical.chargers.{id}.discharge.ampHours.today"
88
+
45
89
  this.addMetadatum('powerGenerationToday', 'W', 'power generation today',
46
90
  (buffer)=>{return buffer.readUInt16BE(41)})
91
+ .default="electrical.chargers.{id}.power.generated.today"
92
+
47
93
  this.addMetadatum('powerConsumptionToday', 'W', 'power consumption today',
48
94
  (buffer)=>{return buffer.readUInt16BE(43)})
95
+ .default="electrical.chargers.{id}.power.consumed.today"
96
+
49
97
  this.addMetadatum('powerGenerationTotal', 'W', 'power generation total',
50
98
  (buffer)=>{return buffer.readUInt32BE(59)})
99
+ .default="electrical.chargers.{id}.power.generated.total"
100
+
51
101
  this.addMetadatum('loadStatus', '', 'load status',
52
102
  (buffer)=>{return RC.LOAD_STATE[buffer.readUInt8(67)>>7]})
103
+ .default="electrical.chargers.{id}.load.status"
53
104
 
54
105
  this.addMetadatum('chargingStatus', '', 'charging status',
55
- (buffer)=>{return RC.CHARGING_STATE[buffer.readUInt8(68)]})
106
+ (buffer)=>{
107
+ const cs = buffer.readUInt8(68)
108
+ if (Object.hasOwn(RC.CHARGING_STATE,cs))
109
+ return RC.CHARGING_STATE[cs]
110
+ else
111
+ return null
112
+ })
113
+
114
+ .default="electrical.chargers.{id}.charge.status"
115
+
56
116
  }
57
117
 
58
118
  retrieveDeviceID(){