bt-sensors-plugin-sk 1.3.1 → 1.3.2-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 +4 -0
- package/README.md +9 -0
- package/VictronSmartBatteryProtect.js +54 -0
- package/VictronSmartBatteryProtect.js.1 +54 -0
- package/index.js +1 -2
- package/package.json +1 -1
- package/sensor_classes/GobiusCTankMeter.js +1 -1
- package/sensor_classes/JBDBMS.js +14 -4
- package/sensor_classes/Renogy/RenogySensor.js +15 -6
- package/sensor_classes/RenogyBattery.js +28 -14
- package/sensor_classes/RenogyInverter.js +17 -3
- package/sensor_classes/RenogyRoverClient.js +9 -18
- package/sensor_classes/ShellySBHT003C.js +2 -2
- package/sensor_classes/ShellySBMO003Z.js +3 -17
- package/sensor_classes/ShenzhenLiOnBMS.js +26 -8
- package/sensor_classes/Victron/VictronConstants.js +699 -103
- package/sensor_classes/Victron/VictronSensor.js +27 -2
- package/sensor_classes/VictronBatteryMonitor.js +6 -8
- package/sensor_classes/VictronDCDCConverter.js +1 -1
- package/sensor_classes/VictronDCEnergyMeter.js +2 -3
- package/sensor_classes/VictronInverter.js +2 -3
- package/sensor_classes/VictronLynxSmartBMS.js +1 -1
- package/sensor_classes/VictronOrionXS.js +3 -1
- package/sensor_classes/VictronSmartBatteryProtect.js +9 -2
- package/testGATT.js +24 -0
package/BTSensor.js
CHANGED
package/README.md
CHANGED
|
@@ -1,7 +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-1
|
|
4
5
|
|
|
6
|
+
- VictronSmartBatteryProtect fix
|
|
7
|
+
- RenogyRoverClient deviceID clarity
|
|
8
|
+
|
|
9
|
+
# Version 1.3.2
|
|
10
|
+
|
|
11
|
+
- Victron Alarm Reason improvements
|
|
12
|
+
- VictronOrionXS offReason text implementation
|
|
13
|
+
- Shelly Blu H&T description changes
|
|
5
14
|
|
|
6
15
|
# Version 1.3.1
|
|
7
16
|
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Smart Battery Protect
|
|
3
|
+
Start
|
|
4
|
+
bit
|
|
5
|
+
Nr of
|
|
6
|
+
bits Meaning Units Range NA
|
|
7
|
+
value Remark
|
|
8
|
+
8 8 Device state 0 .. 0xFE 0xFF VE_REG_DEVICE_STATE
|
|
9
|
+
16 8 Output state 0 .. 0xFE 0xFF VE_REG_DC_OUTPUT_STATUS
|
|
10
|
+
24 8 Error code 0 .. 0xFE 0xFF VE_REG_CHR_ERROR_CODE
|
|
11
|
+
32 16 Alarm reason 0 .. 0xFFFF - VE_REG_ALARM_REASON
|
|
12
|
+
48 16 Warning reason 0 .. 0xFFFF - VE_REG_WARNING_REASON
|
|
13
|
+
64 16 Input voltage 0.01 V 327.68 .. 327.66 V 0x7FFF VE_REG_DC_CHANNEL1_VOLTAGE
|
|
14
|
+
80 16 Output voltage 0.01 V 0 .. 655.34 V 0xFFFF VE_REG_DC_OUTPUT_VOLTAGE
|
|
15
|
+
96 32 Off reason 0 .. 0xFFFFFFFF - VE_REG_DEVICE_OFF_REASON_2
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const VictronSensor = require ("./Victron/VictronSensor.js")
|
|
19
|
+
const VC = require("./Victron/VictronConstants.js")
|
|
20
|
+
class VictronSmartBatteryProtect extends VictronSensor{
|
|
21
|
+
|
|
22
|
+
static ImageFile="VictronSmartBatteryProte.jpg"
|
|
23
|
+
|
|
24
|
+
initSchema(){
|
|
25
|
+
super.initSchema()
|
|
26
|
+
this.addDefaultParam("id")
|
|
27
|
+
this.addMetadatum('deviceState','', 'device state',
|
|
28
|
+
(buff)=>{return VC.OperationMode.get(buff.readUInt8(1))})
|
|
29
|
+
this.addMetadatum('outputStatus','', 'output status', //TODO
|
|
30
|
+
(buff)=>{return (buff.readUInt8(2))})
|
|
31
|
+
|
|
32
|
+
this.addMetadatum('chargerError','', 'charger error',
|
|
33
|
+
(buff)=>{return VC.ChargerError.get(buff.readUInt8(3))})
|
|
34
|
+
this.addMetadatum('alarmReason','', 'alarm reason',
|
|
35
|
+
(buff)=>{return buff.readUInt16LE(4)})
|
|
36
|
+
this.getPath("alarmReason").notify=true
|
|
37
|
+
this.addMetadatum('warningReason','', 'warning reason', //TODO
|
|
38
|
+
(buff)=>{return (buff.readUInt16LE(5))})
|
|
39
|
+
this.addMetadatum('channel1Voltage','V', 'channel one voltage',
|
|
40
|
+
(buff)=>{return this.NaNif(buff.readInt16LE(7),0x7FFF)/100})
|
|
41
|
+
this.addMetadatum('outputVoltage','V', 'output voltage',
|
|
42
|
+
(buff)=>{return this.NaNif(buff.readUInt16LE(9),0xFFFF)/100})
|
|
43
|
+
this.addMetadatum('offReason','', 'off reason',
|
|
44
|
+
(buff)=>{return this.offReasonText(buff.readUInt32LE(11))})
|
|
45
|
+
}
|
|
46
|
+
emitValuesFrom(decData){
|
|
47
|
+
super.emitValuesFrom(decData)
|
|
48
|
+
const alarm = this.getPath("alarmReason").read(decData)
|
|
49
|
+
if (alarm>0)
|
|
50
|
+
this.emitAlarm("alarmReason",alarm)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
module.exports=VictronSmartBatteryProtect
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Smart Battery Protect
|
|
3
|
+
Start
|
|
4
|
+
bit
|
|
5
|
+
Nr of
|
|
6
|
+
bits Meaning Units Range NA
|
|
7
|
+
value Remark
|
|
8
|
+
8 8 Device state 0 .. 0xFE 0xFF VE_REG_DEVICE_STATE
|
|
9
|
+
16 8 Output state 0 .. 0xFE 0xFF VE_REG_DC_OUTPUT_STATUS
|
|
10
|
+
24 8 Error code 0 .. 0xFE 0xFF VE_REG_CHR_ERROR_CODE
|
|
11
|
+
32 16 Alarm reason 0 .. 0xFFFF - VE_REG_ALARM_REASON
|
|
12
|
+
48 16 Warning reason 0 .. 0xFFFF - VE_REG_WARNING_REASON
|
|
13
|
+
64 16 Input voltage 0.01 V 327.68 .. 327.66 V 0x7FFF VE_REG_DC_CHANNEL1_VOLTAGE
|
|
14
|
+
80 16 Output voltage 0.01 V 0 .. 655.34 V 0xFFFF VE_REG_DC_OUTPUT_VOLTAGE
|
|
15
|
+
96 32 Off reason 0 .. 0xFFFFFFFF - VE_REG_DEVICE_OFF_REASON_2
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const VictronSensor = require ("./Victron/VictronSensor.js")
|
|
19
|
+
const VC = require("./Victron/VictronConstants.js")
|
|
20
|
+
class VictronSmartBatteryProtect extends VictronSensor{
|
|
21
|
+
|
|
22
|
+
static ImageFile="VictronSmartBatteryProte.jpg"
|
|
23
|
+
|
|
24
|
+
initSchema(){
|
|
25
|
+
super.initSchema()
|
|
26
|
+
this.addDefaultParam("id")
|
|
27
|
+
this.addMetadatum('deviceState','', 'device state',
|
|
28
|
+
(buff)=>{return VC.OperationMode.get(buff.readUInt8(1))})
|
|
29
|
+
this.addMetadatum('outputStatus','', 'output status', //TODO
|
|
30
|
+
(buff)=>{return (buff.readUInt8(2))})
|
|
31
|
+
|
|
32
|
+
this.addMetadatum('chargerError','', 'charger error',
|
|
33
|
+
(buff)=>{return VC.ChargerError.get(buff.readUInt8(3))})
|
|
34
|
+
this.addMetadatum('alarmReason','', 'alarm reason',
|
|
35
|
+
(buff)=>{return buff.readUInt16LE(4)})
|
|
36
|
+
this.getPath("alarmReason").notify=true
|
|
37
|
+
this.addMetadatum('warningReason','', 'warning reason', //TODO
|
|
38
|
+
(buff)=>{return (buff.readUInt16LE(5))})
|
|
39
|
+
this.addMetadatum('channel1Voltage','V', 'channel one voltage',
|
|
40
|
+
(buff)=>{return this.NaNif(buff.readInt16LE(7),0x7FFF)/100})
|
|
41
|
+
this.addMetadatum('outputVoltage','V', 'output voltage',
|
|
42
|
+
(buff)=>{return this.NaNif(buff.readUInt16LE(9),0xFFFF)/100})
|
|
43
|
+
this.addMetadatum('offReason','', 'off reason',
|
|
44
|
+
(buff)=>{return this.offReasonText(buff.readUInt32LE(11))})
|
|
45
|
+
}
|
|
46
|
+
emitValuesFrom(decData){
|
|
47
|
+
super.emitValuesFrom(decData)
|
|
48
|
+
const alarm = this.getPath("alarmReason").read(decData)
|
|
49
|
+
if (alarm>0)
|
|
50
|
+
this.emitAlarm("alarmReason",alarm)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
module.exports=VictronSmartBatteryProtect
|
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
|
}
|
|
@@ -550,7 +550,6 @@ module.exports = function (app) {
|
|
|
550
550
|
c.debug=app.debug
|
|
551
551
|
|
|
552
552
|
const sensor = new c(device, config?.params, config?.gattParams)
|
|
553
|
-
|
|
554
553
|
sensor._paths=config.paths //this might be a good candidate for refactoring
|
|
555
554
|
sensor._app=app
|
|
556
555
|
sensor._adapter=adapter //HACK!
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bt-sensors-plugin-sk",
|
|
3
|
-
"version": "1.3.1",
|
|
3
|
+
"version": "1.3.2-1",
|
|
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": {
|
package/sensor_classes/JBDBMS.js
CHANGED
|
@@ -84,10 +84,19 @@ class JBDBMS extends BTSensor {
|
|
|
84
84
|
|
|
85
85
|
this.addDefaultPath('SOC','electrical.batteries.capacity.stateOfCharge')
|
|
86
86
|
.read=(buffer)=>{return buffer.readUInt8(23)/100}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
.
|
|
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"
|
|
91
100
|
|
|
92
101
|
await this.deviceConnect()
|
|
93
102
|
const gattServer = await this.device.gatt()
|
|
@@ -188,6 +197,7 @@ class JBDBMS extends BTSensor {
|
|
|
188
197
|
}
|
|
189
198
|
|
|
190
199
|
async initGATTConnection() {
|
|
200
|
+
this.setConnected(await this.device.isConnected())
|
|
191
201
|
return this
|
|
192
202
|
}
|
|
193
203
|
|
|
@@ -3,7 +3,7 @@ ported from https://github.com/cyrils/renogy-bt
|
|
|
3
3
|
*/
|
|
4
4
|
const BTSensor = require("../../BTSensor.js");
|
|
5
5
|
const VC = require('./RenogyConstants.js');
|
|
6
|
-
const crc16Modbus = require('./CRC.js')
|
|
6
|
+
const crc16Modbus = require('./CRC.js');
|
|
7
7
|
class RenogySensor extends BTSensor{
|
|
8
8
|
static Domain=BTSensor.SensorDomains.electrical
|
|
9
9
|
static ALIAS_PREFIX = 'BT-TH'
|
|
@@ -34,20 +34,27 @@ class RenogySensor extends BTSensor{
|
|
|
34
34
|
b.writeUInt16BE(words,4)
|
|
35
35
|
b.writeUInt16BE(crc16Modbus(b.subarray(0,6)),6)
|
|
36
36
|
|
|
37
|
-
await writeCharacteristic.
|
|
37
|
+
await writeCharacteristic.writeValueWithoutResponse(b, 0)
|
|
38
38
|
|
|
39
39
|
}
|
|
40
40
|
static identify(device){
|
|
41
41
|
return null
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
pollFreq=30
|
|
44
44
|
async initSchema(){
|
|
45
45
|
await super.initSchema()
|
|
46
|
-
|
|
46
|
+
this.getGATTParams().pollFreq.default=this.pollFreq
|
|
47
47
|
this.addParameter(
|
|
48
48
|
"deviceID",
|
|
49
49
|
{
|
|
50
|
-
title: 'ID of device'
|
|
50
|
+
title: 'ID of device',
|
|
51
|
+
description: 'only modify if device is in hub mode or daisy chained',
|
|
52
|
+
default:255,
|
|
53
|
+
type: 'number',
|
|
54
|
+
minimum: 0,
|
|
55
|
+
maximum: 255,
|
|
56
|
+
multipleOf:1,
|
|
57
|
+
isRequired: true
|
|
51
58
|
}
|
|
52
59
|
)
|
|
53
60
|
}
|
|
@@ -73,15 +80,17 @@ class RenogySensor extends BTSensor{
|
|
|
73
80
|
}
|
|
74
81
|
|
|
75
82
|
async sendReadFunctionRequest(writeReq, words){
|
|
76
|
-
this.constructor.sendReadFunctionRequest(
|
|
83
|
+
await this.constructor.sendReadFunctionRequest(
|
|
77
84
|
this.writeChar, this.getDeviceID(), writeReq, words)
|
|
78
85
|
}
|
|
79
86
|
|
|
80
87
|
initGATTInterval(){
|
|
88
|
+
this.emitGATT()
|
|
81
89
|
this.intervalID = setInterval(()=>{
|
|
82
90
|
this.emitGATT()
|
|
83
91
|
}, 1000*(this?.pollFreq??60) )
|
|
84
92
|
}
|
|
93
|
+
|
|
85
94
|
emitGATT(){
|
|
86
95
|
this.getAllEmitterFunctions().forEach(async (emitter)=>
|
|
87
96
|
await emitter()
|
|
@@ -12,9 +12,21 @@ class RenogyBattery extends RenogySensor {
|
|
|
12
12
|
this.getAndEmitCellTemperatures.bind(this),
|
|
13
13
|
this.getAndEmitCellVoltages.bind(this)]
|
|
14
14
|
}
|
|
15
|
+
numberOfCells=4
|
|
15
16
|
initSchema(){
|
|
16
|
-
|
|
17
|
-
this.
|
|
17
|
+
this.addDefaultParam("batteryID").default="house"
|
|
18
|
+
this.addParameter(
|
|
19
|
+
"numberOfCells",
|
|
20
|
+
{
|
|
21
|
+
title:"Number of cells",
|
|
22
|
+
type: "number",
|
|
23
|
+
isRequired: true,
|
|
24
|
+
default: this.numberOfCells,
|
|
25
|
+
minimum: 1,
|
|
26
|
+
maximum: 16,
|
|
27
|
+
multipleOf:1
|
|
28
|
+
}
|
|
29
|
+
)
|
|
18
30
|
this.addDefaultPath('current','electrical.batteries.current')
|
|
19
31
|
.read=(buffer)=>{return buffer.readInt16BE(3)/100}
|
|
20
32
|
|
|
@@ -41,31 +53,33 @@ class RenogyBattery extends RenogySensor {
|
|
|
41
53
|
async initGATTConnection() {
|
|
42
54
|
await super.initGATTConnection()
|
|
43
55
|
this.numberOfCells = await this.retrieveNumberOfCells()
|
|
44
|
-
this.deviceID = await this.retrieveDeviceID()
|
|
45
|
-
this.emit('numberOfCells', this.numberOfCells)
|
|
46
56
|
}
|
|
47
57
|
|
|
48
|
-
|
|
49
|
-
|
|
58
|
+
retrieveModelID(){
|
|
50
59
|
return new Promise( async ( resolve, reject )=>{
|
|
51
|
-
await this.sendReadFunctionRequest(0x1388,0x11)
|
|
52
60
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
await this.sendReadFunctionRequest(0x1402,0x08)
|
|
62
|
+
|
|
63
|
+
this.readChar.once('valuechanged', async (buffer) => {
|
|
64
|
+
if (buffer[2]!=0x10)
|
|
65
|
+
reject("Unknown error retrieving model ID") //???
|
|
66
|
+
const model = buffer.subarray(3,17).toString().trim()
|
|
67
|
+
resolve(model)
|
|
57
68
|
})
|
|
69
|
+
})
|
|
58
70
|
}
|
|
59
|
-
|
|
71
|
+
retrieveNumberOfCells(){
|
|
72
|
+
|
|
60
73
|
return new Promise( async ( resolve, reject )=>{
|
|
61
|
-
this.
|
|
74
|
+
await this.sendReadFunctionRequest(0x1388,0x11)
|
|
62
75
|
|
|
63
76
|
const valChanged = async (buffer) => {
|
|
64
|
-
resolve(
|
|
77
|
+
resolve(buffer.readUInt16(3))
|
|
65
78
|
}
|
|
66
79
|
this.readChar.once('valuechanged', valChanged )
|
|
67
80
|
})
|
|
68
81
|
}
|
|
82
|
+
|
|
69
83
|
|
|
70
84
|
getAndEmitBatteryInfo(){
|
|
71
85
|
return new Promise( async ( resolve, reject )=>{
|
|
@@ -54,10 +54,24 @@ class RenogyInverter extends RenogySensor {
|
|
|
54
54
|
})
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
retrieveModelID(){
|
|
58
|
+
return new Promise( async ( resolve, reject )=>{
|
|
59
|
+
|
|
60
|
+
await this.sendReadFunctionRequest(0x10d7,0x08)
|
|
61
|
+
|
|
62
|
+
this.readChar.once('valuechanged', async (buffer) => {
|
|
63
|
+
if (buffer[2]!=0x10)
|
|
64
|
+
reject("Unknown error retrieving model ID") //???
|
|
65
|
+
const model = buffer.subarray(3,17).toString().trim()
|
|
66
|
+
resolve(model)
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
|
|
57
71
|
getAndEmitInverterStats(){
|
|
58
72
|
return new Promise( async ( resolve, reject )=>{
|
|
59
73
|
|
|
60
|
-
await this.sendReadFunctionRequest(0xfa0,
|
|
74
|
+
await this.sendReadFunctionRequest(0xfa0, 0xA)
|
|
61
75
|
|
|
62
76
|
this.readChar.once('valuechanged', (buffer) => {
|
|
63
77
|
["ueiVoltage","ueiCurrent", "voltage", "loadCurrent", "frequency","temperature"].forEach((tag)=>
|
|
@@ -71,7 +85,7 @@ class RenogyInverter extends RenogySensor {
|
|
|
71
85
|
getAndEmitSolarCharging(){
|
|
72
86
|
return new Promise( async ( resolve, reject )=>{
|
|
73
87
|
|
|
74
|
-
await this.sendReadFunctionRequest(0x10e9,
|
|
88
|
+
await this.sendReadFunctionRequest(0x10e9, 0x7)
|
|
75
89
|
|
|
76
90
|
this.readChar.once('valuechanged', (buffer) => {
|
|
77
91
|
["solarVoltage","solarCurrent", "solarPower", "solarChargingStatus", "solarChargingPower"].forEach((tag)=>
|
|
@@ -85,7 +99,7 @@ class RenogyInverter extends RenogySensor {
|
|
|
85
99
|
getAndEmitInverterLoad(){
|
|
86
100
|
return new Promise( async ( resolve, reject )=>{
|
|
87
101
|
|
|
88
|
-
await this.sendReadFunctionRequest(0x113a,
|
|
102
|
+
await this.sendReadFunctionRequest(0x113a, 0x6)
|
|
89
103
|
|
|
90
104
|
this.readChar.once('valuechanged', (buffer) => {
|
|
91
105
|
["loadPower", "chargingCurrent"].forEach((tag)=>
|
|
@@ -34,6 +34,10 @@ class RenogyRoverClient extends RenogySensor {
|
|
|
34
34
|
initSchema(){
|
|
35
35
|
//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']
|
|
36
36
|
super.initSchema()
|
|
37
|
+
|
|
38
|
+
this.addDefaultParam("id")
|
|
39
|
+
.default="solar"
|
|
40
|
+
|
|
37
41
|
this.addMetadatum('batteryType', '', "battery type")
|
|
38
42
|
.default="electrical.chargers.{id}.battery.type"
|
|
39
43
|
this.addMetadatum('batteryPercentage', 'ratio', "battery percentage",
|
|
@@ -118,22 +122,12 @@ class RenogyRoverClient extends RenogySensor {
|
|
|
118
122
|
|
|
119
123
|
}
|
|
120
124
|
|
|
121
|
-
|
|
122
|
-
return new Promise( async ( resolve, reject )=>{
|
|
123
|
-
this.sendReadFunctionRequest(0x1A, 0x1)
|
|
124
|
-
|
|
125
|
-
const valChanged = async (buffer) => {
|
|
126
|
-
resolve((buffer.readUInt8(4)))
|
|
127
|
-
}
|
|
128
|
-
this.readChar.once('valuechanged', valChanged )
|
|
129
|
-
})
|
|
130
|
-
}
|
|
131
|
-
|
|
125
|
+
|
|
132
126
|
retrieveBatteryType(){
|
|
133
127
|
return new Promise( async ( resolve, reject )=>{
|
|
134
128
|
//Buffer(7) [255, 3, 2, 0, 1, 80, 80, buffer: ArrayBuffer(8192), byteLength: 7, byteOffset: 864, length: 7, Symbol(Symbol.toStringTag): 'Uint8Array']
|
|
135
129
|
|
|
136
|
-
this.sendReadFunctionRequest(0xe004, 0x01)
|
|
130
|
+
await this.sendReadFunctionRequest(0xe004, 0x01)
|
|
137
131
|
|
|
138
132
|
const valChanged = async (buffer) => {
|
|
139
133
|
resolve(RC.BATTERY_TYPE[(buffer.readUInt8(4))])
|
|
@@ -157,13 +151,10 @@ class RenogyRoverClient extends RenogySensor {
|
|
|
157
151
|
}
|
|
158
152
|
async initGATTConnection() {
|
|
159
153
|
await super.initGATTConnection()
|
|
160
|
-
if (!this.deviceID)
|
|
161
|
-
this.deviceID = await this.retrieveDeviceID()
|
|
162
|
-
this.modelID=await this.retrieveModelID()
|
|
163
154
|
|
|
155
|
+
this.modelID=await this.retrieveModelID()
|
|
164
156
|
this.batteryType = await this.retrieveBatteryType()
|
|
165
|
-
this.emit('batteryType', this.batteryType)
|
|
166
|
-
|
|
157
|
+
this.emit('batteryType', this.batteryType)
|
|
167
158
|
|
|
168
159
|
}
|
|
169
160
|
|
|
@@ -175,7 +166,7 @@ class RenogyRoverClient extends RenogySensor {
|
|
|
175
166
|
async getAndEmitChargeInfo(){
|
|
176
167
|
return new Promise( async ( resolve, reject )=>{
|
|
177
168
|
try {
|
|
178
|
-
this.sendReadFunctionRequest(0x100, 0x22)
|
|
169
|
+
await this.sendReadFunctionRequest(0x100, 0x22)
|
|
179
170
|
|
|
180
171
|
this.readChar.once('valuechanged', buffer => {
|
|
181
172
|
this.emitValuesFrom(buffer)
|
|
@@ -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
|
|
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
|
|
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"
|
|
@@ -63,11 +71,12 @@ class ShenzhenLiONBMS extends BTSensor{
|
|
|
63
71
|
"numberOfCells",
|
|
64
72
|
{
|
|
65
73
|
title:"Number of cells",
|
|
66
|
-
type: "
|
|
74
|
+
type: "number",
|
|
67
75
|
isRequired: true,
|
|
68
76
|
default: 4,
|
|
69
77
|
minimum: 1,
|
|
70
|
-
maximum: 16
|
|
78
|
+
maximum: 16,
|
|
79
|
+
multipleOf:1
|
|
71
80
|
}
|
|
72
81
|
)
|
|
73
82
|
|
|
@@ -91,6 +100,9 @@ class ShenzhenLiONBMS extends BTSensor{
|
|
|
91
100
|
this.addMetadatum(`cell${cellNum+1}Voltage`,'V', `cell #${cellNum+1} voltage`,
|
|
92
101
|
(buff)=>{return buff.readInt16LE(16+(cellNum*2)) /1000})
|
|
93
102
|
.default=`electrical.batteries.{batteryID}.cells.${cellNum+1}.voltage`
|
|
103
|
+
|
|
104
|
+
this.addMetadatum(`cell${cellNum+1}Balancing`,'', `cell #${cellNum+1} balance state (true=balancing)`)
|
|
105
|
+
.default=`electrical.batteries.{batteryID}.cells.${cellNum+1}.balancing`
|
|
94
106
|
}
|
|
95
107
|
|
|
96
108
|
this.addDefaultPath('current','electrical.batteries.current')
|
|
@@ -119,19 +131,15 @@ class ShenzhenLiONBMS extends BTSensor{
|
|
|
119
131
|
.default="electrical.batteries.{batteryID}.balanceMemoryActive"
|
|
120
132
|
|
|
121
133
|
this.addMetadatum('protectionState','', 'protection state',
|
|
122
|
-
(buff)=>{return buff.
|
|
134
|
+
(buff)=>{return ProtectionStatus[buff.readUInt16LE(76)]??"Normal"})
|
|
123
135
|
.default="electrical.batteries.{batteryID}.protectionState"
|
|
124
136
|
|
|
125
137
|
this.addMetadatum('failureState','', 'failure state',
|
|
126
138
|
(buff)=>{return buff.slice(80,84).reverse().join("").slice(-3)})
|
|
127
139
|
.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
140
|
|
|
133
141
|
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.
|
|
142
|
+
(buff)=>{return (BatteryState[buff.readUInt16LE(88)])??"Unknown"})
|
|
135
143
|
.default="electrical.batteries.{batteryID}.batteryState"
|
|
136
144
|
|
|
137
145
|
this.addMetadatum('dischargeCount','', 'discharge count',
|
|
@@ -148,6 +156,16 @@ class ShenzhenLiONBMS extends BTSensor{
|
|
|
148
156
|
this.getJSONSchema().properties.params.required=["batteryID", "numberOfCells" ]
|
|
149
157
|
}
|
|
150
158
|
|
|
159
|
+
emitValuesFrom(buffer){
|
|
160
|
+
super.emitValuesFrom(buffer)
|
|
161
|
+
const balanceState= buffer.slice(84,88).reverse().join("")
|
|
162
|
+
|
|
163
|
+
for(let cellNum=0; cellNum < this?.numberOfCells??4; cellNum++) {
|
|
164
|
+
this.emit(`cell${cellNum+1}Balancing`, balanceState[cellNum]==='1')
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
}
|
|
168
|
+
|
|
151
169
|
async initGATTConnection(isReconnecting){
|
|
152
170
|
|
|
153
171
|
await super.initGATTConnection(isReconnecting)
|