bt-sensors-plugin-sk 1.3.2 → 1.3.4-beta
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/AI-DEV.md +784 -0
- package/BTSensor.js +10 -7
- package/README.md +17 -0
- package/index.js +36 -14
- package/package.json +2 -2
- package/pairing.md +147 -0
- package/sensor_classes/HumsienkBMS.js +385 -0
- package/sensor_classes/JBDBMS.js +1 -0
- package/sensor_classes/JikongBMS.js +1 -1
- 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/ShenzhenLiOnBMS.js +3 -2
- package/sensor_classes/VictronBatteryMonitor.js +1 -4
- package/sensor_classes/VictronDCEnergyMeter.js +0 -1
- package/sensor_classes/VictronInverter.js +0 -1
- package/sensor_classes/VictronInverterRS.js +0 -1
- package/sensor_classes/VictronSmartBatteryProtect.js +2 -3
- package/sensor_classes/XiaomiMiBeacon.js +52 -24
|
@@ -17,7 +17,6 @@ class VictronInverter extends VictronSensor{
|
|
|
17
17
|
const md = this.addMetadatum('alarmReason','', 'reason for alarm',
|
|
18
18
|
(buff)=>{return buff.readIntU16LE(1)})
|
|
19
19
|
.default="electrical.inverters.{id}.alarm"
|
|
20
|
-
md.notify=true
|
|
21
20
|
|
|
22
21
|
this.addDefaultPath('dcVoltage','electrical.inverters.dc.voltage')
|
|
23
22
|
.read=(buff)=>{return this.NaNif(buff.readInt16LE(3),0x7FFF)/100}
|
|
@@ -18,7 +18,6 @@ class VictronInverterRS extends VictronSensor{
|
|
|
18
18
|
const md = this.addMetadatum('chargerError','', 'charger error',
|
|
19
19
|
(buff)=>{return VC.ChargerError(buff.readIntU8(1))})
|
|
20
20
|
md.default='electrical.inverters.{id}.error'
|
|
21
|
-
md.notify=true
|
|
22
21
|
|
|
23
22
|
this.addMetadatum('batteryVoltage','V', 'battery voltage',
|
|
24
23
|
(buff)=>{return this.NaNif(buff.readInt16LE(2),0x7FFF)/100})
|
|
@@ -33,7 +33,6 @@ class VictronSmartBatteryProtect extends VictronSensor{
|
|
|
33
33
|
(buff)=>{return VC.ChargerError.get(buff.readUInt8(3))})
|
|
34
34
|
this.addMetadatum('alarmReason','', 'alarm reason',
|
|
35
35
|
(buff)=>{return buff.readUInt16LE(4)})
|
|
36
|
-
this.getPath("alarmReason").notify=true
|
|
37
36
|
this.addMetadatum('warningReason','', 'warning reason', //TODO
|
|
38
37
|
(buff)=>{return (buff.readUInt16LE(5))})
|
|
39
38
|
this.addMetadatum('channel1Voltage','V', 'channel one voltage',
|
|
@@ -45,9 +44,9 @@ class VictronSmartBatteryProtect extends VictronSensor{
|
|
|
45
44
|
}
|
|
46
45
|
emitValuesFrom(decData){
|
|
47
46
|
super.emitValuesFrom(decData)
|
|
48
|
-
const alarm = this.getPath("
|
|
47
|
+
const alarm = this.getPath("alarmReason").read(decData)
|
|
49
48
|
if (alarm>0)
|
|
50
|
-
this.emitAlarm("
|
|
49
|
+
this.emitAlarm("alarmReason",alarm)
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
}
|
|
@@ -100,7 +100,7 @@ class XiaomiMiBeacon extends BTSensor{
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
getDescription(){
|
|
103
|
-
return `<div><p><img src="../bt-sensors-plugin-sk/images/LYWSD03MMC-Device.jpg" alt=LYWSD03MMC image" style="float: left; margin-right: 10px;" /> The LYWSD03MMC temperature and humidity sensor is an inexpensive environmental sensor from Xiaomi Inc. <p>
|
|
103
|
+
return `<div><p><img src="../bt-sensors-plugin-sk/images/LYWSD03MMC-Device.jpg" alt=LYWSD03MMC image" style="float: left; margin-right: 10px;" /> The LYWSD03MMC temperature and humidity sensor is an inexpensive environmental sensor from Xiaomi Inc. <p> Follow the instructions <a href=https://github.com/PiotrMachowski/Xiaomi-cloud-tokens-extractor/?tab=readme-ov-file#linux--home-assistant-in-ssh--web-terminal target="_blank">here</a> to get your device's encryption key.<div>`
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
getManufacturer(){
|
|
@@ -131,19 +131,18 @@ class XiaomiMiBeacon extends BTSensor{
|
|
|
131
131
|
})
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
decryptV2and3(data){
|
|
134
|
+
decryptV2and3(data, index=11){
|
|
135
135
|
const encryptedPayload = data.subarray(-4);
|
|
136
|
-
const
|
|
137
|
-
const nonce = Buffer.concat([data.subarray(0, 5), data.subarray(-4,-1), xiaomi_mac.subarray(-1)]);
|
|
136
|
+
const nonce = Buffer.concat([data.subarray(0, 5), data.subarray(-4,-1), (this._mac_reversed)]);
|
|
138
137
|
const cipher = crypto.createDecipheriv('aes-128-ccm', Buffer.from(this.encryptionKey,"hex"), nonce, { authTagLength: 4});
|
|
139
138
|
cipher.setAAD(Buffer.from('11', 'hex'), { plaintextLength: encryptedPayload.length });
|
|
140
139
|
|
|
141
140
|
return cipher.update(encryptedPayload)
|
|
142
141
|
}
|
|
143
|
-
decryptV4and5(data){
|
|
144
|
-
|
|
145
|
-
const
|
|
146
|
-
const nonce = Buffer.concat([
|
|
142
|
+
decryptV4and5(data, index=11){
|
|
143
|
+
|
|
144
|
+
const encryptedPayload = data.subarray(index,-7);
|
|
145
|
+
const nonce = Buffer.concat([(this._mac_reversed), data.subarray(2, 5), data.subarray(-7,-4)]);
|
|
147
146
|
const cipher = crypto.createDecipheriv('aes-128-ccm', Buffer.from(this.encryptionKey,"hex"), nonce, { authTagLength: 4});
|
|
148
147
|
cipher.setAAD(Buffer.from('11', 'hex'), { plaintextLength: encryptedPayload.length });
|
|
149
148
|
cipher.setAuthTag(data.subarray(-4))
|
|
@@ -151,7 +150,7 @@ class XiaomiMiBeacon extends BTSensor{
|
|
|
151
150
|
}
|
|
152
151
|
|
|
153
152
|
hasGATT(){
|
|
154
|
-
return
|
|
153
|
+
return false
|
|
155
154
|
}
|
|
156
155
|
|
|
157
156
|
propertiesChanged(props){
|
|
@@ -160,35 +159,64 @@ class XiaomiMiBeacon extends BTSensor{
|
|
|
160
159
|
if (!props.hasOwnProperty("ServiceData")) return
|
|
161
160
|
|
|
162
161
|
const data = this.getServiceData(this.constructor.SERVICE_MIBEACON)
|
|
163
|
-
|
|
162
|
+
if (data.length<12) return
|
|
163
|
+
|
|
164
|
+
let dec=[]
|
|
165
|
+
let dataIndex=5
|
|
166
|
+
|
|
167
|
+
const frameControl = data.readUInt16LE(0)
|
|
168
|
+
const isEncrypted = (frameControl >> 3) & 1
|
|
169
|
+
const encryptionVersion = frameControl >> 12
|
|
170
|
+
const mesh = (frameControl >> 7) & 1; // mesh device
|
|
171
|
+
const authMode = (frameControl >> 10) & 3;
|
|
172
|
+
const solicited = (frameControl >> 9) & 1;
|
|
173
|
+
const registered = (frameControl >> 8) & 1;
|
|
174
|
+
const objectInclude = (frameControl >> 6) & 1; // object/payload data present
|
|
175
|
+
const capabilityInclude = (frameControl >> 5) & 1; // capability byte present
|
|
176
|
+
const macInclude = (frameControl >> 4) & 1; // MAC address included in payload
|
|
177
|
+
const requestTiming = frameControl & 1;
|
|
178
|
+
|
|
164
179
|
if (!this.encryptionKey){
|
|
165
180
|
throw new Error(`${this.getNameAndAddress()} requires an encryption key.`)
|
|
166
181
|
}
|
|
167
|
-
if (
|
|
168
|
-
dec = this.decryptV4and5(data)
|
|
182
|
+
if (encryptionVersion >= 4) {
|
|
183
|
+
dec = this.decryptV4and5(data, macInclude?11:5)
|
|
169
184
|
} else {
|
|
170
|
-
if(
|
|
171
|
-
dec=this.decryptV2and3(data)
|
|
185
|
+
if(encryptionVersion>=2){
|
|
186
|
+
dec=this.decryptV2and3(data, macInclude?11:5)
|
|
172
187
|
}
|
|
173
188
|
}
|
|
174
189
|
if (dec.length==0)
|
|
175
190
|
throw new Error(`${this.getNameAndAddress()} received empty decrypted packet. Check that the bind/encryption key in config is correct.`)
|
|
176
191
|
|
|
177
|
-
|
|
178
|
-
|
|
192
|
+
const objCode = dec.readUInt16LE(0)
|
|
193
|
+
|
|
194
|
+
switch(objCode){
|
|
195
|
+
case 0x100D:
|
|
179
196
|
this.emitData("temp",dec,3)
|
|
180
197
|
this.emitData("humidity",dec,5)
|
|
181
198
|
break
|
|
182
199
|
|
|
183
|
-
case
|
|
200
|
+
case 0x100A:
|
|
184
201
|
this.emitData("batteryStrength",dec,3)
|
|
185
202
|
break
|
|
186
|
-
case
|
|
203
|
+
case 0x1004:
|
|
187
204
|
this.emitData("temp",dec,3)
|
|
188
205
|
break
|
|
189
|
-
case
|
|
206
|
+
case 0x1006:
|
|
190
207
|
this.emitData("humidity",dec,3)
|
|
191
208
|
break
|
|
209
|
+
case 0x4C01:
|
|
210
|
+
this.emit("temp",dec.readFloatLE(3)+273.15)
|
|
211
|
+
break
|
|
212
|
+
|
|
213
|
+
case 0x4C02:
|
|
214
|
+
this.emit("humidity",dec[3]/100)
|
|
215
|
+
break
|
|
216
|
+
case 0x4C03:
|
|
217
|
+
this.emit("batteryStrength",dec[3]/100)
|
|
218
|
+
break
|
|
219
|
+
|
|
192
220
|
default:
|
|
193
221
|
throw new Error(`${this.getNameAndAddress()} unable to parse decrypted service data (${util.inspect(dec)})`)
|
|
194
222
|
|
|
@@ -198,13 +226,13 @@ class XiaomiMiBeacon extends BTSensor{
|
|
|
198
226
|
async init(){
|
|
199
227
|
|
|
200
228
|
await super.init()
|
|
229
|
+
this._mac_reversed = (Buffer.from(this.getMacAddress().replaceAll(":",""), "hex")).reverse()
|
|
201
230
|
const data = this.getServiceData(this.constructor.SERVICE_MIBEACON)
|
|
202
231
|
if (!data || data.length<4)
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
this.encryptionVersion = frameControl >> 12
|
|
232
|
+
this.setError(`Service Data ${this.constructor.SERVICE_MIBEACON} not available for ${this.getName()}`)
|
|
233
|
+
else
|
|
234
|
+
this.deviceID = data[2] + (data[3] << 8)
|
|
235
|
+
|
|
208
236
|
}
|
|
209
237
|
initSchema(){
|
|
210
238
|
super.initSchema()
|