bt-sensors-plugin-sk 1.3.0 → 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 +17 -1
- package/VictronSmartBatteryProtect.js +54 -0
- package/VictronSmartBatteryProtect.js.1 +54 -0
- package/index.js +1 -1
- package/package.json +1 -1
- package/public/images/SensorPush.webp +0 -0
- package/sensor_classes/GobiusCTankMeter.js +1 -1
- package/sensor_classes/JBDBMS.js +32 -5
- 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/SensorPush.js +123 -0
- 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,6 +1,21 @@
|
|
|
1
1
|
# Bluetooth Sensors for [Signal K](http://www.signalk.org)
|
|
2
2
|
|
|
3
3
|
## WHAT'S NEW
|
|
4
|
+
# Version 1.3.2-1
|
|
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
|
|
14
|
+
|
|
15
|
+
# Version 1.3.1
|
|
16
|
+
|
|
17
|
+
- JBD Protection status
|
|
18
|
+
- SensorPush devices (untested)
|
|
4
19
|
|
|
5
20
|
# Version 1.3.0
|
|
6
21
|
|
|
@@ -112,7 +127,7 @@ It's pretty easy to write and deploy your own sensor class for any currently uns
|
|
|
112
127
|
|[Jikong](https://jikongbms.com/)| https://jikongbms.com/product/ |
|
|
113
128
|
|[Junctek](https://www.junteks.com)|[Junctek BMS](https://www.junteks.com/pages/product/index) |
|
|
114
129
|
|[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
|
|
130
|
+
|[AC DC Systems](https://marinedcac.com) | [Bank Manager](https://marinedcac.com/pages/bankmanager) hybrid (Pb and Li) charger|
|
|
116
131
|
|[Ective](https://ective.de/)| Also Topband(?), Skanbatt and others |
|
|
117
132
|
|
|
118
133
|
### Environmental
|
|
@@ -128,6 +143,7 @@ It's pretty easy to write and deploy your own sensor class for any currently uns
|
|
|
128
143
|
|[Govee](http://www.govee.com)| Govee H50xx and H510x Temperature and humidity sensors |
|
|
129
144
|
|[BTHome](https://bthome.io/)| NOTE: Framework for IOT sensor devices. |
|
|
130
145
|
|[Inkbird](https://inkbird.com/)| TH-2 Temp and Humidity Sensor |
|
|
146
|
+
|[SensorPush](https://www.sensorpush.com/)| Temperature, Humidity and Atmospheric Pressure sensor|
|
|
131
147
|
|
|
132
148
|
|
|
133
149
|
### Tanks
|
|
@@ -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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bt-sensors-plugin-sk",
|
|
3
|
-
"version": "1.3.
|
|
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": {
|
|
Binary file
|
package/sensor_classes/JBDBMS.js
CHANGED
|
@@ -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)=>{
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
.
|
|
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()
|
|
@@ -171,6 +197,7 @@ class JBDBMS extends BTSensor {
|
|
|
171
197
|
}
|
|
172
198
|
|
|
173
199
|
async initGATTConnection() {
|
|
200
|
+
this.setConnected(await this.device.isConnected())
|
|
174
201
|
return this
|
|
175
202
|
}
|
|
176
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)
|
|
@@ -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
|
|
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
|
|