bt-sensors-plugin-sk 1.2.2 → 1.2.4-1

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
@@ -107,6 +107,7 @@ class BTSensor extends EventEmitter {
107
107
  unknown: { name: "unknown", description: "Unknown sensor domain "},
108
108
  environmental: { name: "environmental", description: "Sensors that measure environmental conditions - air temperature, humidity etc."},
109
109
  electrical: { name: "electrical", description: "Electrical sensor - chargers, batteries, inverters etc."},
110
+ propulsion: { name: "propulsion", description: "Sensors that measure engine state"},
110
111
  tanks: { name: "tanks", description: "Sensors that measure level in tanks (gas, propane, water etc.) "}
111
112
  }
112
113
  static Domain = this.SensorDomains.unknown
@@ -465,13 +466,41 @@ class BTSensor extends EventEmitter {
465
466
  throw new Error("::initGATTNotifications() should be implemented by the BTSensor subclass")
466
467
  }
467
468
 
468
- deviceConnect() {
469
+ deviceConnect(reconnect=false) {
469
470
 
470
471
 
471
472
  return connectQueue.enqueue( async ()=>{
472
473
  this.debug(`Connecting... ${this.getName()}`)
473
- await this.device.connect()
474
+ await this.device.helper.callMethod('Connect')
475
+
474
476
  this.debug(`Connected to ${this.getName()}`)
477
+ if (!reconnect) {
478
+ this.device.helper.on('PropertiesChanged', (propertiesChanged) => {
479
+ if ('Connected' in propertiesChanged) {
480
+ const { value } = propertiesChanged.Connected
481
+ if (value) {
482
+ this.device.emit('connect', { connected: true })
483
+ } else {
484
+ this.device.emit('disconnect', { connected: false })
485
+ }
486
+ }
487
+ })
488
+ this.device.on("disconnect", ()=>{
489
+ if (this.isActive()) {
490
+ this.debug(`Device disconnected. Attempting to reconnect to ${this.getName()}`)
491
+ try {
492
+ this.deviceConnect(true).then(()=>{
493
+ this.debug(`Device reconnected -- ${this.getName()}`)
494
+ })
495
+ }
496
+ catch (e) {
497
+ this.setPluginError( `Error while reconnecting to ${this.getName()}: ${e.message}`)
498
+ this.debug( `Error while reconnecting to ${this.getName()}: ${e.message}`)
499
+ this.debug(e)
500
+ }
501
+ }
502
+ })
503
+ }
475
504
 
476
505
  try {
477
506
 
package/README.md CHANGED
@@ -1,13 +1,25 @@
1
1
  # Bluetooth Sensors for [Signal K](http://www.signalk.org)
2
- # Version 1.2.2
2
+ # Version 1.2.4-1
3
3
 
4
- ## WHAT'S NEW SINCE VERSION 1.2.1
4
+ ## WHAT'S NEW
5
+
6
+ - **NEW SENSOR** [Bank Manager](https://marinedcac.com/pages/bankmanager) (tested)
7
+ - **NEW SENSOR** [Mercury Smartcraft](https://www.mercurymarine.com/us/en/gauges-and-controls/displays/smartcraft-connect) (untested)
8
+ - Fixed Govee 5075 parsing
9
+ - Added defaults for Renogy Rover Client
10
+ - Automatic reconnect for GATT connected devices
11
+
12
+ ### Version 1.2.3
13
+
14
+ Bug fixes Remoran Wave.3, JunctekBMS, and ShenzhenLiOn
15
+
16
+ ### Version 1.2.2
5
17
 
6
18
  - Junctek BMS and Remoran Wave 3 support (Note: both are not currently field tested)
7
19
 
8
20
  - Fixes to ShenzhenLiOn BMS, Victron Orion XS, Victron DC DC Converter, Victron Smart Lithium Classes
9
21
 
10
- ## WHAT'S NEW SINCE VERSION 1.1.x
22
+ ### Version 1.2.1
11
23
 
12
24
  - Dynamic configuration screen. The Device list automatically updates when new devices are found by the BT scanner. (No more annoying screen refresh necessary!).
13
25
 
@@ -53,7 +65,7 @@ It's pretty easy to write and deploy your own sensor class for any currently uns
53
65
  |[Lancol](www.Lancol.com)| [Micro 10C 12V Car Battery Monitor](https://www.lancol.com/product/12v-bluetooth-4-0-battery-tester-micro-10-c/)|
54
66
  |[Junctek](https://www.junteks.com)|[Junctek BMS](https://www.junteks.com/pages/product/index) |
55
67
  |[Remoran](https://remoran.eu)| [Remoran Wave.3](https://remoran.eu/wave.html)|
56
-
68
+ |[AC DC Systems](https://marinedcac.com) | [Bank Manager] hybrid (Pb and Li) charger(https://marinedcac.com/pages/bankmanager)|
57
69
 
58
70
  ### Environmental
59
71
  | Manufacturer | Devices |
@@ -76,6 +88,13 @@ It's pretty easy to write and deploy your own sensor class for any currently uns
76
88
  | [Gobius](https://gobiusc.com/) | Gobius-C Tank level sensor|
77
89
  | [Mopeka](https://www.mopeka.com) | [Mopeka Pro Chek](https://mopeka.com/product-category/recreational-sensors-rv-bbq-etc/) ultrasonic tank level sensor |
78
90
 
91
+ ### Propulsion
92
+ | Manufacturer | Devices |
93
+ |--------------|----------|
94
+ | [Mercury](https://www.mercurymarine.com)| [Mercury Smartcraft](https://www.mercurymarine.com/us/en/gauges-and-controls/displays/smartcraft-connect) connect engine sensor|
95
+
96
+
97
+
79
98
 
80
99
  ## WHO IT'S FOR
81
100
 
@@ -132,16 +151,27 @@ Finally, restart SK. Plugin should appear in your server plugins list.<br>
132
151
 
133
152
  ## KNOWN ISSUES
134
153
 
154
+ ### Connected Devices on Raspberry Pi platform (4/4b/5/CM400/CM500)
155
+
156
+ Onboard Raspberry Pi WiFi can cause interference with the onboard Bluetooth resulting in lost connections to GATT connected devices (Renogy, JBD, etc. )
157
+
158
+ One simple solution is to install a USB BT adapter like the [Tp-link UB500-Plus](https://www.tp-link.com/us/home-networking/usb-adapter/ub500-plus/)
159
+
160
+ ### USB 3.0 and HDMI interference
161
+
162
+ Poorly shielded USB 3.0 and HDMI (5ghz) can interfere with BT transmission (2.4ghz).
163
+
135
164
  ### Configuration Panel
136
165
 
137
166
  - Safari 18.1 on OsX produces errors on load that kill the configuration screen. No known cause. Upgrade to most recent Safari or use Chrome.
138
167
  - Unsaved sensor configuration changes are lost after selecting a different sensor. Be sure to Save changes for now.
139
- - Renogy Rover Client, Victron GX, Victron Smart Battery Protect, and Victron VE Bus sensor classes have no default paths currently. Users will need to manually input.
168
+ - Victron GX, Victron Smart Battery Protect, and Victron VE Bus sensor classes have no default paths currently. Users will need to manually input.
140
169
 
141
170
  ### Runtime
142
171
 
143
172
  - IMPORTANT Set `Scan for new devices interval` to `0` after configuration is complete. The plugin will run but in Bluetooth-rich environments, or if you have a long range BT 5.3 device, the system Bluetooth stack may fail after 4 hours or so.
144
173
  - There's no way that I know of to remove a SK Path without restarting the server. So if any active paths are changed by the plugin, you'll still see them hanging around in the data browser growing stale until you restart the server.
174
+ - RPi 3/4/5/CM400s when running an Access Point on the on board Wifi can cause a problem connecting to devices through the onboard BT. The only known fix is to disable the onboard Bluetooth and use a USB BT adapter. Alternatively, you can use a USB WiFi adapter. NOTE: This only applies to _connected_ devices like Renogy devices, LiTime batteries etc.
145
175
 
146
176
  ## CONFIGURATION
147
177
 
package/index.js CHANGED
@@ -409,8 +409,10 @@ module.exports = function (app) {
409
409
  try{
410
410
  const c = await getClassFor(device,config)
411
411
  c.debug=app.debug
412
+
412
413
  const sensor = new c(device, config?.params, config?.gattParams)
413
414
  sensor.debug=app.debug
415
+ sensor.setPluginError=app.setPluginError
414
416
  sensor.app=app
415
417
  sensor._adapter=adapter //HACK!
416
418
  await sensor.init()
@@ -420,7 +422,8 @@ module.exports = function (app) {
420
422
  const msg = `Unable to instantiate ${await BTSensor.getDeviceProp(device,"Address")}: ${error.message} `
421
423
  app.debug(msg)
422
424
  app.debug(error)
423
- app.setPluginError(msg)
425
+ if (config.active)
426
+ app.setPluginError(msg)
424
427
  return null
425
428
  }
426
429
 
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.4-1",
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",
Binary file
@@ -0,0 +1,96 @@
1
+ const BTSensor = require("../BTSensor");
2
+
3
+ class BankManager extends BTSensor{
4
+
5
+ static Domain = BTSensor.SensorDomains.electrical
6
+ static async identify(device){
7
+
8
+ const name = await this.getDeviceProp(device,"Name")
9
+ const regex = /^BankManager*[0-9]{2}/
10
+
11
+ if (name && name.match(regex))
12
+ return this
13
+ else
14
+ return null
15
+
16
+ }
17
+ initSchema(){
18
+ super.initSchema()
19
+
20
+ this.addDefaultParam("id")
21
+ .default="bankManager"
22
+
23
+ this.addMetadatum('liVoltage','V','Lithium Voltage')
24
+ .default="electrical.batteries.{id}.voltage.lithium"
25
+ this.addMetadatum('pbVoltage','V','Lead Voltage')
26
+ .default="electrical.batteries.{id}.voltage.lead"
27
+ this.addMetadatum('current','A','total current')
28
+ .default="electrical.batteries.{id}.current"
29
+ this.addMetadatum('soc','ratio','state of charge')
30
+ .default="electrical.batteries.{id}.soc"
31
+ this.addMetadatum('connectionStatus','','Connection Status')
32
+ .default="electrical.batteries.{id}.connectionStatus"
33
+
34
+ }
35
+
36
+ getManufacturer(){
37
+ return "Bank Manager"
38
+ }
39
+ hasGATT(){
40
+ return false
41
+ }
42
+ usingGATT(){
43
+ return true
44
+ }
45
+ emitDataFrom(buffer){
46
+ let data=buffer.toString().split(",")
47
+ this.emit("liVoltage", parseFloat(data[1]))
48
+ this.emit("pbVoltage", parseFloat(data[2]))
49
+ this.emit("current", parseFloat(data[3]))
50
+ this.emit("soc", parseFloat(data[4])/100)
51
+ this.emit("connectionStatus", parseInt(data[5]))
52
+
53
+ }
54
+ emitGATT(){
55
+
56
+ }
57
+
58
+
59
+ initGATTConnection(){
60
+ return new Promise((resolve,reject )=>{ this.deviceConnect().then(async ()=>{
61
+ if (!this.gattServer) {
62
+ this.gattServer = await this.device.gatt()
63
+ this.service = await this.gattServer.getPrimaryService("0000ffe0-0000-1000-8000-00805f9b34fb")
64
+ this.characteristic = await this.service.getCharacteristic("0000ffe1-0000-1000-8000-00805f9b34fb")
65
+ }
66
+ resolve(this)
67
+ }) .catch((e)=>{ reject(e.message) }) })
68
+ }
69
+
70
+ initGATTNotifications() {
71
+ Promise.resolve(this.characteristic.startNotifications().then(()=>{
72
+ let data = null
73
+ this.characteristic.on('valuechanged', buffer => {
74
+ if (buffer.length>0 && buffer[0]==0x23) {
75
+ data = Buffer.from(buffer)
76
+ } else if (data && buffer.indexOf(0x0d0a)!==-1) {
77
+ data=Buffer.concat([data,buffer.subarray(0,buffer.indexOf(0x0d0a)-1)], data.length+buffer.indexOf(0x0d0a)-1)
78
+ this.emitDataFrom(data)
79
+ data=null
80
+ }
81
+ })
82
+ }))
83
+
84
+ }
85
+
86
+ async stopListening(){
87
+ super.stopListening()
88
+ if (this.characteristic && await this.characteristic.isNotifying()) {
89
+ await this.characteristic.stopNotifications()
90
+ }
91
+ if (await this.device.isConnected()){
92
+ await this.device.disconnect()
93
+ }
94
+ }
95
+ }
96
+ module.exports=BankManager
@@ -338,19 +338,7 @@ class GobiusCTankMeter extends BTSensor{
338
338
  this.service = await this.gattServer.getPrimaryService("0000ffe0-0000-1000-8000-00805f9b34fb")
339
339
  this.characteristic = await this.service.getCharacteristic("0000ffe9-0000-1000-8000-00805f9b34fb")
340
340
  }
341
- this.device.on("disconnect", ()=>{
342
- if (this.isActive()) {
343
- this.debug(`Device disconnected. Attempting to reconnect to ${this.getName()}`)
344
- try {
345
- this.deviceConnect().then(()=>{
346
- this.debug(`Device reconnected -- ${this.getName()}`)
347
- })
348
- }
349
- catch (e) {
350
- this.debug(`Error while reconnecting to ${this.getName()}`)
351
- }
352
- }
353
- })
341
+
354
342
 
355
343
  resolve(this)
356
344
  }).catch((e)=>{ reject(e.message) }) })
@@ -0,0 +1,47 @@
1
+ const BTSensor = require("../../BTSensor");
2
+
3
+ class GoveeSensor extends BTSensor {
4
+ static Domain = this.SensorDomains.environmental
5
+ static ManufacturerUUID = '0000ec88-0000-1000-8000-00805f9b34fb'
6
+ static async identify(device){
7
+
8
+ const regex = /^Govee_H5075_[a-f,A-F,0-9]{4}$/
9
+ const name = await this.getDeviceProp(device,"Name")
10
+ const uuids = await this.getDeviceProp(device,'UUIDs')
11
+
12
+ if (name && name.match(this.getIDRegex()) &&
13
+ uuids && uuids.length > 0 &&
14
+ uuids[0] == this.ManufacturerUUID)
15
+ return this
16
+ else
17
+ return null
18
+
19
+ }
20
+
21
+ getManufacturer(){
22
+ return "Govee"
23
+ }
24
+ getPackedTempAndHumidity(buffer, beg )
25
+ {
26
+ const negative=buffer[beg]&0x80
27
+ return {
28
+ packedValue: ((buffer.readIntBE(beg,3))&0xFFFFFF) ^ (negative?0x800000:0x000000),
29
+ tempIsNegative: negative
30
+ }
31
+ }
32
+ emitTemperatureAndHumidity(packedValue, tempIsNegative ){
33
+ this.emit("temp", 273.15+((((Math.trunc(packedValue/1000))/10))*(tempIsNegative?-1:1)))
34
+ this.emit("humidity", (packedValue % 1000) / 1000)
35
+
36
+ }
37
+ async propertiesChanged(props){
38
+ super.propertiesChanged(props)
39
+ if (!props.hasOwnProperty("ManufacturerData")) return
40
+
41
+ const buffer = this.getManufacturerData(0xec88)
42
+ if (buffer) {
43
+ this.emitValuesFrom(buffer)
44
+ }
45
+ }
46
+ }
47
+ module.exports=GoveeSensor
@@ -0,0 +1,23 @@
1
+ const GoveeSensor = require("./Govee/GoveeSensor");
2
+
3
+ class GoveeH5074 extends GoveeSensor {
4
+ static getIDRegex() {
5
+ return /^Govee_H5074_[a-f,A-F,0-9]{4}$/
6
+ }
7
+ initSchema(){
8
+ super.initSchema()
9
+ this.addDefaultParam("zone")
10
+
11
+ this.addDefaultPath("temp","environment.temperature")
12
+ .read= (buffer)=>{return 273.15+(buffer.readUInt16LE(1)/100) }
13
+
14
+ this.addDefaultPath("humidity", "environment.humidity")
15
+ .read = (buffer)=>{return buffer.readUInt16LE(3)/10000}
16
+
17
+ this.addDefaultPath("battery","sensors.batteryStrength")
18
+ .read = (buffer)=>{return buffer.readUInt8(5)/100}
19
+ }
20
+
21
+
22
+ }
23
+ module.exports=GoveeH5074
@@ -0,0 +1,37 @@
1
+ const GoveeSensor = require("./Govee/GoveeSensor");
2
+
3
+ class GoveeH5075 extends GoveeSensor {
4
+ static getIDRegex(){
5
+ return /^Govee_H5075_[a-f,A-F,0-9]{4}$/
6
+ }
7
+ static test(){
8
+ const sensor = new GoveeH5075()
9
+ sensor.getName=()=>{return "Govee H5075 fake"}
10
+ sensor.initSchema()
11
+ sensor.on("temp", (t)=>{console.log(`temp => ${t}`)})
12
+ sensor.on("humidity", (t)=>{console.log(`humidity => ${t}`)})
13
+ sensor.on("battery", (t)=>{console.log(`battery => ${t}`)})
14
+ sensor.emitValuesFrom(Buffer.from([0x00, 0x81, 0xc2 ,0x89 ,0x64 ,0x00]))
15
+ sensor.emitValuesFrom(Buffer.from([0x00,0x03,0xbb,0x94,0x64,0x00]))
16
+
17
+ }
18
+ initSchema(){
19
+ super.initSchema()
20
+ this.addDefaultParam("zone")
21
+
22
+ this.addDefaultPath("temp","environment.temperature")
23
+ this.addDefaultPath("humidity", "environment.humidity")
24
+ this.addDefaultPath("battery","sensors.batteryStrength")
25
+ }
26
+
27
+ emitValuesFrom(buffer){
28
+ if (buffer.length<6) {
29
+ this.debug(`Invalid buffer received. Cannot parse buffer ${buffer} for ${this.getMacAndName()}`)
30
+ return
31
+ }
32
+ const val = this.getPackedTempAndHumidity(buffer,1)
33
+ this.emitTemperatureAndHumidity(val.packedValue, val.tempIsNegative)
34
+ this.emit("battery", buffer[4]/100)
35
+ }
36
+ }
37
+ module.exports=GoveeH5075
@@ -1,37 +1,19 @@
1
- const BTSensor = require("../BTSensor");
2
- function decodeTempHumid(tempHumidBytes) {
3
- // Convert the bytes to a 24-bit integer
4
- const baseNum = (tempHumidBytes[0] << 16) + (tempHumidBytes[1] << 8) + tempHumidBytes[2];
5
-
6
- // Check if the temperature is negative
7
- const isNegative = (baseNum & 0x800000) !== 0;
8
-
9
- // Extract the temperature and humidity values
10
- const tempAsInt = baseNum & 0x7FFFFF;
11
- const tempAsFloat = (tempAsInt / 1000) / 10.0;
12
- const humid = (tempAsInt % 1000) / 10.0;
13
-
14
- // Apply the negative sign if necessary
15
- if (isNegative) {
16
- return {t:-tempAsFloat, h: humid};
17
- } else {
18
- return {t: tempAsFloat, h: humid};
1
+ const GoveeSensor = require("./Govee/GoveeSensor");
2
+
3
+ class GoveeH510x extends GoveeSensor{
4
+ static getIDRegex(){
5
+ return /^GVH510[0-9]_[a-f,A-F,0-9]{4}$/
19
6
  }
20
- }
21
- class GoveeH510x extends BTSensor{
22
- static Domain = this.SensorDomains.environmental
23
- static async identify(device){
24
- const regex = /^GVH510[0-9]_[a-f,A-F,0-9]{4}$/
25
- const name = await this.getDeviceProp(device,"Name")
26
- const uuids = await this.getDeviceProp(device,'UUIDs')
27
7
 
28
- if (name && name.match(regex) &&
29
- uuids && uuids.length > 0 &&
30
- uuids[0] == '0000ec88-0000-1000-8000-00805f9b34fb')
31
- return this
32
- else
33
- return null
34
-
8
+ static test(){
9
+ const sensor = new GoveeH510x()
10
+ sensor.getName=()=>{return "Govee H510x fake"}
11
+ sensor.initSchema()
12
+ sensor.on("temp", (t)=>{console.log(`temp => ${t}`)})
13
+ sensor.on("humidity", (t)=>{console.log(`humidity => ${t}`)})
14
+ sensor.on("battery", (t)=>{console.log(`battery => ${t}`)})
15
+ sensor.emitValuesFrom(Buffer.from([0x01,0x01,0x03,0x6d,0xcc,0x5c]))
16
+
35
17
  }
36
18
 
37
19
  initSchema(){
@@ -44,23 +26,16 @@ class GoveeH510x extends BTSensor{
44
26
  }
45
27
 
46
28
  emitValuesFrom(buffer){
47
- const th = decodeTempHumid(buffer.subarray(2,5))
48
- this.emit("temp", parseFloat((273.15+th.t).toFixed(2))) ;
49
- this.emit("humidity", th.h/100 )
50
- this.emit('battery', buffer[5]/100)
51
- }
29
+ if (buffer.length<6) {
30
+ this.debug(`Invalid buffer received. Cannot parse buffer ${buffer} for ${this.getMacAndName()}`)
31
+ return
32
+ }
33
+ const val = this.getPackedTempAndHumidity(buffer,2)
34
+ this.emitTemperatureAndHumidity(val.packedValue, val.tempIsNegative)
35
+ this.emit("battery", buffer[5]/100)
52
36
 
53
- getManufacturer(){
54
- return "Govee"
55
37
  }
56
- async propertiesChanged(props){
57
- super.propertiesChanged(props)
58
- if (!props.hasOwnProperty("ManufacturerData")) return
59
38
 
60
- const buffer = this.getManufacturerData(0x0001)
61
- if (buffer) {
62
- this.emitValuesFrom(buffer)
63
- }
64
- }
39
+
65
40
  }
66
41
  module.exports=GoveeH510x
@@ -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,8 @@ async getAndEmitCellVoltages(){
196
195
  }
197
196
 
198
197
  initGATTInterval(){
198
+
199
+ this.emitGATT()
199
200
  this.initGATTNotifications()
200
201
  }
201
202
 
@@ -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
  }
@@ -0,0 +1,126 @@
1
+ /*
2
+ Service UUID Characteristic UUID Type Param Convertion Unit SignalK Path Comment
3
+ 00000000-0000-1000-8000-ec55f9f5b963 (Unknown) 00000001-0000-1000-8000-ec55f9f5b963 write / indicate SDP - - - Enable or disable data stream. To enable write 0x0D 0x01; To disable write 0x0D 0x00.
4
+ 00000100-0000-1000-8000-ec55f9f5b963 (L2CAP) 00000101-0000-1000-8000-ec55f9f5b963 read ? - - ? Returns: Value: 1.1.0 (raw: 312e312e30)
5
+ 00000100-0000-1000-8000-ec55f9f5b963 (L2CAP) 00000102-0000-1000-8000-ec55f9f5b963 write / notify ENGINE_RPM_UUID value / 60 Hz propulsion.p0.revolutions
6
+ 00000100-0000-1000-8000-ec55f9f5b963 (L2CAP) 00000103-0000-1000-8000-ec55f9f5b963 write / notify COOLANT_TEMPERATURE_UUID value + 273.15 Kelvin propulsion.p0.temperature
7
+ 00000100-0000-1000-8000-ec55f9f5b963 (L2CAP) 00000104-0000-1000-8000-ec55f9f5b963 write / notify BATTERY_VOLTAGE_UUID value / 1000 Volts propulsion.p0.alternatorVoltage
8
+ 00000100-0000-1000-8000-ec55f9f5b963 (L2CAP) 00000105-0000-1000-8000-ec55f9f5b963 write / notify UNK_105_UUID ? ? ? Need longer data to figure out what is it. Value around 17384.
9
+ 00000100-0000-1000-8000-ec55f9f5b963 (L2CAP) 00000106-0000-1000-8000-ec55f9f5b963 write / notify ENGINE_RUNTIME_UUID value * 60 Seconds propulsion.p0.runTime
10
+ 00000100-0000-1000-8000-ec55f9f5b963 (L2CAP) 00000107-0000-1000-8000-ec55f9f5b963 write / notify CURRENT_FUEL_FLOW_UUID value / 100000 m3 / hour propulsion.p0.fuel.rate
11
+ 00000100-0000-1000-8000-ec55f9f5b963 (L2CAP) 00000108-0000-1000-8000-ec55f9f5b963 write / notify FUEL_TANK_PCT_UUID value / 100 % propulsion.p0.fuel.tank Maybe there is a more appropriate name for the Signalk path
12
+ 00000100-0000-1000-8000-ec55f9f5b963 (L2CAP) 00000109-0000-1000-8000-ec55f9f5b963 write / notify UNK_109_UUID ? ? ? Need longer data to figure out what is it. Raw data varied from 102701 to 102700.
13
+ 00000100-0000-1000-8000-ec55f9f5b963 (L2CAP) 0000010a-0000-1000-8000-ec55f9f5b963 write / notify OIL_PRESSURE_UUID value / 100 kPascal propulsion.p0.oilPressure
14
+ 00000100-0000-1000-8000-ec55f9f5b963 (L2CAP) 0000010b-0000-1000-8000-ec55f9f5b963 write / notify UNK_10B_UUID ? ? ? Always zero. To investigate with more data.
15
+ */
16
+ const BTSensor = require("../BTSensor");
17
+ class MercurySmartcraft extends BTSensor{
18
+ static Domain = BTSensor.SensorDomains.propulsion
19
+
20
+ static async identify(device){
21
+
22
+ const name = await this.getDeviceProp(device,"Name")
23
+ const address = await this.getDeviceProp(device,"Address")
24
+ if (name == `VVM_${address.replace(":","")}`)
25
+ return this
26
+ else
27
+ return null
28
+ }
29
+
30
+
31
+
32
+ hasGATT(){
33
+ return false
34
+ }
35
+ usingGATT(){
36
+ return true
37
+ }
38
+ emitGATT(){
39
+ }
40
+ initSchema(){
41
+ const bo = 0
42
+
43
+ super.initSchema()
44
+ this.addParameter(
45
+ "id",
46
+ {
47
+ "title": "Engine ID",
48
+ "examples": ["port","starboard","p0","p1"]
49
+ }
50
+ )
51
+ _schema.properties.params.required=["id"]
52
+
53
+ this.addMetadatum("rpm","Hz","engine revolutions per sec",
54
+ (buffer)=>{return buffer.readUInt16LE(bo)/60}
55
+ ).default='propulsion.{id}.revolutions'
56
+
57
+ this.addMetadatum("coolant","K","temperature of engine coolant in K",
58
+ (buffer)=>{return buffer.readUInt16LE(bo)+273.15}
59
+ ).default='propulsion.{id}.coolantTemperature'
60
+
61
+ this.addMetadatum("alternatorVoltage","V","voltage of alternator",
62
+ (buffer)=>{return buffer.readUInt16LE(bo)/1000}
63
+ ).default='propulsion.{id}.alternatorVoltage'
64
+
65
+ this.addMetadatum("runtime","s","Total running time for engine (Engine Hours in seconds)",
66
+ (buffer)=>{return buffer.readUInt16LE(bo)*60}
67
+ ).default='propulsion.{id}.runTime'
68
+
69
+ this.addMetadatum("rate","m3/s","Fuel rate of consumption (cubic meters per second)",
70
+ (buffer)=>{return buffer.readUInt16LE(bo)/10000}
71
+ ).default='propulsion.{id}.fuel.rate'
72
+
73
+ this.addMetadatum("pressure","Pa","Fuel pressure",
74
+ (buffer)=>{return buffer.readUInt16LE(bo)/100}
75
+ ).default='propulsion.{id}.pressure'
76
+
77
+ this.addMetadatum("level","ratio","Level of fluid in tank 0-100%",
78
+ (buffer)=>{return buffer.readUInt16LE(bo)/100}
79
+ ).default='tanks.petrol.currentLevel'
80
+ }
81
+
82
+ initGATTConnection(){
83
+ return new Promise((resolve,reject )=>{ this.deviceConnect().then(async ()=>{
84
+ if (!this.gattServer) {
85
+ this.gattServer = await this.device.gatt()
86
+ this.sdpService = await this.gattServer.getPrimaryService("00000000-0000-1000-8000-ec55f9f5b963")
87
+ this.sdpCharacteristic = await this.sdpService.getCharacteristic("00000001-0000-1000-8000-ec55f9f5b963")
88
+ this.dataService = await this.gattServer.getPrimaryService("00000100-0000-1000-8000-ec55f9f5b963")
89
+ this.dataCharacteristics = {
90
+ rpm: await this.dataService.getCharacteristic("00000102-0000-1000-8000-ec55f9f5b963"),
91
+ coolant: await this.dataService.getCharacteristic("00000103-0000-1000-8000-ec55f9f5b963"),
92
+ alternatorVoltage: await this.dataService.getCharacteristic("00000104-0000-1000-8000-ec55f9f5b963"),
93
+ runtime: await this.dataService.getCharacteristic("00000106-0000-1000-8000-ec55f9f5b963"),
94
+ rate: await this.dataService.getCharacteristic("00000107-0000-1000-8000-ec55f9f5b963"),
95
+ level: await this.dataService.getCharacteristic("00000108-0000-1000-8000-ec55f9f5b963"),
96
+ pressure: await this.dataService.getCharacteristic("0000010a-0000-1000-8000-ec55f9f5b963")
97
+ }
98
+ }
99
+ resolve(this)
100
+ }) .catch((e)=>{ reject(e.message) }) })
101
+ }
102
+ async initGATTNotifications() {
103
+ await this.sdpCharacteristic.writeDataWithoutResponse(Buffer.from([0x0D,0x01]))
104
+ for (const c in this.dataCharacteristics){
105
+ Promise.resolve(this.dataCharacteristics[c].startNotifications().then(()=>{
106
+ this.dataCharacteristics[c].on('valuechanged', buffer => {
107
+ this.emitData(c,buffer)
108
+ })
109
+ }))
110
+ }
111
+ }
112
+
113
+ async stopListening(){
114
+ super.stopListening()
115
+ for (const c in this.dataCharacteristics){
116
+ if (this.dataCharacteristics[c] && await this.dataCharacteristics[char].isNotifying()) {
117
+ await this.dataCharacteristics[c].stopNotifications()
118
+ }
119
+ }
120
+
121
+ if (await this.device.isConnected()){
122
+ await this.device.disconnect()
123
+ }
124
+ }
125
+ }
126
+ module.exports=MercurySmartcraft
@@ -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
 
@@ -57,53 +57,61 @@ const BTSensor = require("../BTSensor");
57
57
  app.debug(`Bad buffer size ${buffer.length}. Buffer size must be 20 bytes or more.`)
58
58
  return
59
59
  }
60
- emitData("versionNumber", buffer.readUInt8(0))
60
+ this.emit("versionNumber", buffer.readUInt8(0))
61
61
  const errors = buffer.readUInt8(2)
62
62
  const errorState = []
63
63
  for (var i = 0; i < 8; ++i) {
64
64
  var c = 1 << i;
65
- r & c && errorState.push(errors[i])
65
+ errors & c && errorState.push(errors[i])
66
66
  }
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))
67
+ this.emit("errors", errorState)
68
+ this.emit("state", states[buffer.readUInt8(3)])
69
+ this.emit("rpm", buffer.readUInt32LE(4))
70
+ this.emit( "voltage" , buffer.readFloatLE(8))
71
+ this.emit("current", buffer.readFloatLE(12))
72
+ this.emit( "power", buffer.readFloatLE(16))
73
73
 
74
74
  if (buffer.length > 23) {
75
- emitData( "temp", buffer.readFloatLE(20).toFixed(1))
76
- emitData( "uptime", buffer.readUInt32(24))
75
+ this.emit( "temp", ((buffer.readFloatLE(20))+273.15))
76
+ this.emit( "uptime", buffer.readUInt32LE(24))
77
77
  if (versionNumber>1 && buffer.size > 31) {
78
- emitData("energy", buffer.readFloatLE(32).toFixed(1))
78
+ this.emit("energy", buffer.readFloatLE(32))
79
79
  }
80
80
  }
81
81
 
82
82
  }
83
83
  emitInfo2Data(buffer){
84
+
84
85
  if (buffer.size < 12) {
85
86
  app.debug(`Bad buffer size ${buffer.length}. Buffer size must be 12 bytes or more.`)
86
87
  return
87
88
  }
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))
89
+ this.emit("versionNumber", buffer.readUInt8(0))
90
+ this.emit("temp", ((buffer.readFloatLE(4))+273.15))
91
+ this.emit("uptime", buffer.readUInt32LE(8))
92
+ this.emit("lastBootTime", arduinoDateDecode(buffer.readUInt32LE(12)))
93
+ this.emit("energy", buffer.readFloatLE(16))
93
94
  }
94
95
  emitEventData(buffer){
95
- if (buffer.size < 14) {
96
+ if (buffer.length < 14) {
97
+ this.debug(buffer)
96
98
  app.debug(`Bad buffer size ${buffer.length}. Buffer size must be 14 bytes or more.`)
97
99
  return
98
100
  }
99
- this.emitData("event",
101
+ const eventType = buffer.readUInt16LE(8)
102
+ var eventDesc = eventType.toString()
103
+ if (Object.hasOwn(eventTypes,eventType))
104
+ eventDesc = eventTypes[eventType]
105
+
106
+
107
+ this.emit("event",
100
108
  {
101
109
  firstDate: arduinoDateDecode(buffer.readUInt32LE(0)),
102
110
  lastDate: arduinoDateDecode(buffer.readUInt32LE(4)),
103
- eventType: buffer.readUInt16LE(8),
111
+ eventType: eventType,
104
112
  count: buffer.readUInt16LE(10),
105
113
  index: buffer.readUInt16LE(12),
106
- eventDesc: eventTypes[i]
114
+ eventDesc: eventDesc
107
115
  }
108
116
  )
109
117
  }
@@ -174,10 +182,10 @@ const BTSensor = require("../BTSensor");
174
182
  this.gattServer = await this.device.gatt()
175
183
  this.service = await this.gattServer.getPrimaryService(this.serviceUUID)
176
184
  this.info1Characteristic = await this.service.getCharacteristic(this.info1CharUUID)
177
- this.info2Characteristic = await this.service.getPrimaryService(this.info2CharUUID)
185
+ this.info2Characteristic = await this.service.getCharacteristic(this.info2CharUUID)
178
186
  this.eventCharacteristic = await this.service.getCharacteristic(this.eventUUID)
179
187
  resolve(this)
180
- }}) .catch((e)=>{ reject(e.message) }) })
188
+ }}) .catch((e)=>{ this.debug(e); reject(e.message) }) })
181
189
  }
182
190
 
183
191
  initGATTNotifications() {
@@ -205,9 +213,9 @@ const BTSensor = require("../BTSensor");
205
213
  }
206
214
  async stopListening(){
207
215
  super.stopListening()
208
- await stopNotifations(this.info1Characteristic)
209
- await stopNotifations(this.info2Characteristic)
210
- await stopNotifations(this.eventCharacteristic)
216
+ await this.stopNotifications(this?.info1Characteristic)
217
+ await this.stopNotifications(this?.info2Characteristic)
218
+ await this.stopNotifications(this?.eventCharacteristic)
211
219
  if (await this.device.isConnected()){
212
220
  await this.device.disconnect()
213
221
  }
@@ -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: {
@@ -42,13 +42,7 @@ class RenogySensor extends BTSensor{
42
42
 
43
43
  async initSchema(){
44
44
  await super.initSchema()
45
- this.addParameter(
46
- "refreshInterval",
47
- {
48
- title: 'refresh interval',
49
- type: 'number'
50
- }
51
- )
45
+
52
46
  this.addParameter(
53
47
  "deviceID",
54
48
  {
@@ -57,9 +51,6 @@ class RenogySensor extends BTSensor{
57
51
  )
58
52
  }
59
53
 
60
- emitGATT(){
61
- }
62
-
63
54
  getModelName(){
64
55
  return this?.modelID??`${this.constructor.name} Unknown model`
65
56
  }
@@ -86,7 +77,6 @@ class RenogySensor extends BTSensor{
86
77
  }
87
78
 
88
79
  initGATTInterval(){
89
- this.emitGATT()
90
80
  this.intervalID = setInterval(()=>{
91
81
  this.emitGATT()
92
82
  }, 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(){
@@ -160,7 +160,9 @@ class ShenzhenLiONBMS extends BTSensor{
160
160
  async initGATTInterval(){
161
161
  await this.initGATTNotifications()
162
162
  }
163
-
163
+ emitGATT(){
164
+
165
+ }
164
166
  async initGATTNotifications() {
165
167
  await this.rxCharacteristic.startNotifications()
166
168
  this.rxCharacteristic.on('valuechanged', buffer => {
@@ -1,47 +0,0 @@
1
- const BTSensor = require("../BTSensor");
2
-
3
- class GoveeH50xx extends BTSensor {
4
- static Domain = this.SensorDomains.environmental
5
- static async identify(device){
6
- const regex = /^Govee_H50[0-9]{2}_[a-f,A-F,0-9]{4}$/
7
- //this.getManufacturer()
8
- const name = await this.getDeviceProp(device,"Name")
9
- const uuids = await this.getDeviceProp(device,'UUIDs')
10
-
11
- if (name && name.match(regex) &&
12
- uuids && uuids.length > 0 &&
13
- uuids[0] == '0000ec88-0000-1000-8000-00805f9b34fb')
14
- return this
15
- else
16
- return null
17
- t
18
- }
19
-
20
- initSchema(){
21
- super.initSchema()
22
- this.addDefaultParam("zone")
23
-
24
- this.addDefaultPath("temp","environment.temperature")
25
- .read= (buffer)=>{return 273.15+(buffer.readUInt16LE(1)/100) }
26
-
27
- this.addDefaultPath("humidity", "environment.humidity")
28
- .read = (buffer)=>{return buffer.readUInt16LE(3)/10000}
29
-
30
- this.addDefaultPath("battery","sensors.batteryStrength")
31
- .read = (buffer)=>{return buffer.readUInt8(5)/100}
32
- }
33
-
34
- getManufacturer(){
35
- return "Govee"
36
- }
37
- async propertiesChanged(props){
38
- super.propertiesChanged(props)
39
- if (!props.hasOwnProperty("ManufacturerData")) return
40
-
41
- const buffer = this.getManufacturerData(0xec88)
42
- if (buffer) {
43
- this.emitValuesFrom(buffer)
44
- }
45
- }
46
- }
47
- module.exports=GoveeH50xx