bt-sensors-plugin-sk 1.2.6-beta-3 → 1.2.6-beta-5
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 +165 -62
- package/README.md +10 -1
- package/classLoader.js +9 -2
- package/development/FakeBTDevice.js +4 -1
- package/index.js +116 -59
- package/package.json +1 -1
- package/plugin_defaults.json +9 -0
- package/public/847.js +1 -1
- package/public/images/EcoWorthyBW2.webp +0 -0
- package/public/images/JikongBMS.jpg +0 -0
- package/sensor_classes/{EcoWorthy.js → EcoWorthyBW02.js} +20 -8
- package/sensor_classes/Inkbird.js +1 -1
- package/sensor_classes/JBDBMS.js +3 -0
- package/sensor_classes/JikongBMS.js +506 -0
- package/sensor_classes/RemoranWave3.js +3 -4
- package/sensor_classes/RuuviTag.js +1 -0
- package/sensor_classes/ShellySBMO003Z.js +5 -0
- package/sensor_classes/TestData/Jikong.json +36 -0
- package/sensor_classes/XiaomiMiBeacon.js +12 -14
- package/src/components/PluginConfigurationPanel.js +6 -1
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
const { ThemeProvider } = require("react-bootstrap");
|
|
2
|
+
const BTSensor = require("../BTSensor");
|
|
3
|
+
let FakeDevice,FakeGATTService,FakeGATTCharacteristic;
|
|
4
|
+
|
|
5
|
+
// Dynamically import FakeBTDevice.js for node<= 20
|
|
6
|
+
import('../development/FakeBTDevice.js')
|
|
7
|
+
.then(module => {
|
|
8
|
+
FakeDevice = module.FakeDevice;
|
|
9
|
+
FakeGATTService= module.FakeGATTService
|
|
10
|
+
FakeGATTCharacteristic=module.FakeGATTCharacteristic
|
|
11
|
+
|
|
12
|
+
})
|
|
13
|
+
.catch(error => {
|
|
14
|
+
console.error('Error loading FakeBTDevice:', error);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
function sumByteArray(byteArray) {
|
|
18
|
+
let sum = 0;
|
|
19
|
+
for (let i = 0; i < byteArray.length; i++) {
|
|
20
|
+
sum += byteArray[i];
|
|
21
|
+
}
|
|
22
|
+
return sum;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const countSetBits=(n)=> {return (n == 0)?0:(n & 1) + countSetBits(n >> 1)};
|
|
26
|
+
class JikongBMS extends BTSensor {
|
|
27
|
+
static Domain = BTSensor.SensorDomains.electrical;
|
|
28
|
+
|
|
29
|
+
static RX_SERVICE = "0000ffe0-0000-1000-8000-00805f9b34fb";
|
|
30
|
+
static RX_CHAR_UUID = "0000ffe1-0000-1000-8000-00805f9b34fb";
|
|
31
|
+
static validResponseHeader = 0x55aaeb90;
|
|
32
|
+
static validAcknowledgeHeader = 0xaa5590eb;
|
|
33
|
+
|
|
34
|
+
static commandResponse = {
|
|
35
|
+
0x96: 0x02,
|
|
36
|
+
0x97: 0x03,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
static async test(datafile) {
|
|
40
|
+
const data = require(datafile);
|
|
41
|
+
const device = new FakeDevice([
|
|
42
|
+
new FakeGATTService(this.RX_SERVICE, [
|
|
43
|
+
new FakeGATTCharacteristic(
|
|
44
|
+
this.RX_CHAR_UUID,
|
|
45
|
+
data.data["0x96"],
|
|
46
|
+
data.delay
|
|
47
|
+
),
|
|
48
|
+
]),
|
|
49
|
+
]);
|
|
50
|
+
const obj = new JikongBMS(device, { offset: 16, dischargeFloor: 0.1 });
|
|
51
|
+
obj.currentProperties = { Name: "Fake JKBMS", Address: "<mac>" };
|
|
52
|
+
obj.debug = (m) => {
|
|
53
|
+
console.log(m);
|
|
54
|
+
};
|
|
55
|
+
obj.deviceConnect = () => {};
|
|
56
|
+
|
|
57
|
+
await obj.initSchema();
|
|
58
|
+
await obj.initGATTInterval();
|
|
59
|
+
for (const [tag, path] of Object.entries(
|
|
60
|
+
obj._schema.properties.paths.properties
|
|
61
|
+
)) {
|
|
62
|
+
obj.on(tag, (val) => {
|
|
63
|
+
console.log(`${tag} => ${val} `);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
static identify(device) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
static ImageFile = "JikongBMS.jpg";
|
|
71
|
+
connections = 0;
|
|
72
|
+
|
|
73
|
+
jikongCommand(command) {
|
|
74
|
+
var result = [
|
|
75
|
+
0xaa,
|
|
76
|
+
0x55,
|
|
77
|
+
0x90,
|
|
78
|
+
0xeb,
|
|
79
|
+
command,
|
|
80
|
+
0x00,
|
|
81
|
+
0x00,
|
|
82
|
+
0x00,
|
|
83
|
+
0x00,
|
|
84
|
+
0x00,
|
|
85
|
+
0x00,
|
|
86
|
+
0x00,
|
|
87
|
+
0x00,
|
|
88
|
+
0x00,
|
|
89
|
+
0x00,
|
|
90
|
+
0x00,
|
|
91
|
+
0x00,
|
|
92
|
+
0x00,
|
|
93
|
+
0x00,
|
|
94
|
+
];
|
|
95
|
+
result.push(Buffer.from([sumByteArray(result)])[0]);
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async sendReadFunctionRequest(command) {
|
|
100
|
+
this.debug(`sending ${command} for ${this.getName()}`);
|
|
101
|
+
try {
|
|
102
|
+
return await this.rxChar.writeValueWithoutResponse(
|
|
103
|
+
Buffer.from(this.jikongCommand(command))
|
|
104
|
+
);
|
|
105
|
+
} catch (e) {
|
|
106
|
+
this.debug(
|
|
107
|
+
`Error rec'd writing data: ${e.message} for ${this.getName()}`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
pollFreq=20
|
|
113
|
+
async initSchema() {
|
|
114
|
+
super.initSchema();
|
|
115
|
+
this.addDefaultParam("batteryID");
|
|
116
|
+
this.addParameter("offset", {
|
|
117
|
+
description: "Data offset",
|
|
118
|
+
type: "number",
|
|
119
|
+
isRequired: true,
|
|
120
|
+
default: 16,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
this.addParameter("dischargeFloor", {
|
|
124
|
+
description: "Discharge floor ratio ",
|
|
125
|
+
isRequired: true,
|
|
126
|
+
type: "number",
|
|
127
|
+
default: 0.1,
|
|
128
|
+
minimum: 0,
|
|
129
|
+
max: 0.99,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
if (this.numberOfCells == undefined) {
|
|
133
|
+
try {
|
|
134
|
+
await this.initGATTConnection();
|
|
135
|
+
this.numberOfCells = await this.getNumberOfCells()
|
|
136
|
+
}
|
|
137
|
+
catch(e){
|
|
138
|
+
this.numberOfCells = 4;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
this.addParameter("numberOfCells", {
|
|
143
|
+
description: "Number of cells",
|
|
144
|
+
type: "number",
|
|
145
|
+
isRequired: true,
|
|
146
|
+
default: this.numberOfCells,
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
for (let i = 0; i < this?.numberOfCells ?? 4; i++) {
|
|
150
|
+
this.addMetadatum(
|
|
151
|
+
`cell${i}Voltage`,
|
|
152
|
+
"V",
|
|
153
|
+
`Cell ${i + 1} voltage`,
|
|
154
|
+
(buffer) => {
|
|
155
|
+
if (i == 0) {
|
|
156
|
+
this.currentProperties._totalCellVoltage = 0;
|
|
157
|
+
this.currentProperties._maxCellVoltage = 0;
|
|
158
|
+
this.currentProperties._minCellVoltage = 0;
|
|
159
|
+
}
|
|
160
|
+
const v = buffer.readUInt16LE(6 + i * 2) / 1000;
|
|
161
|
+
this.currentProperties._totalCellVoltage += v;
|
|
162
|
+
if (v > this.currentProperties._maxCellVoltage)
|
|
163
|
+
this.currentProperties._maxCellVoltage = v;
|
|
164
|
+
if (
|
|
165
|
+
this.currentProperties._minCellVoltage == 0 ||
|
|
166
|
+
v < this.currentProperties._minCellVoltage
|
|
167
|
+
)
|
|
168
|
+
this.currentProperties._minCellVoltage = v;
|
|
169
|
+
return v;
|
|
170
|
+
}
|
|
171
|
+
).default = `electrical.batteries.{batteryID}.cell${i}.voltage`;
|
|
172
|
+
|
|
173
|
+
this.addMetadatum(
|
|
174
|
+
`cell${i}Resistance`,
|
|
175
|
+
"ohm",
|
|
176
|
+
`Cell ${i + 1} resistance in ohms`,
|
|
177
|
+
(buffer) => {
|
|
178
|
+
return buffer.readUInt16LE(i * 2 + 64 + this.offset) / 1000;
|
|
179
|
+
}
|
|
180
|
+
).default = `electrical.batteries.{batteryID}.cell${i}.resistance`;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
this.addMetadatum(
|
|
184
|
+
"avgCellVoltage",
|
|
185
|
+
"number",
|
|
186
|
+
"Average Cell Voltage",
|
|
187
|
+
() => {
|
|
188
|
+
return this.currentProperties._totalCellVoltage / this.numberOfCells;
|
|
189
|
+
}
|
|
190
|
+
).default = "electrical.batteries.{batteryID}.avgCellVoltage";
|
|
191
|
+
|
|
192
|
+
this.addMetadatum(
|
|
193
|
+
"deltaCellVoltage",
|
|
194
|
+
"number",
|
|
195
|
+
"Delta Cell Voltage",
|
|
196
|
+
() => {
|
|
197
|
+
return (
|
|
198
|
+
this.currentProperties._maxCellVoltage -
|
|
199
|
+
this.currentProperties._minCellVoltage
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
).default = "electrical.batteries.{batteryID}.deltaCellVoltage";
|
|
203
|
+
|
|
204
|
+
this.addDefaultPath("voltage", "electrical.batteries.voltage").read = (
|
|
205
|
+
buffer
|
|
206
|
+
) => {
|
|
207
|
+
return buffer.readUInt16LE(118 + this.offset * 2) / 1000;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
this.addDefaultPath("power", "electrical.batteries.power", (buffer) => {
|
|
211
|
+
return buffer.readInt16LE(122 + this.offset * 2) / 1000;
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
this.addDefaultPath("current", "electrical.batteries.current").read = (
|
|
215
|
+
buffer
|
|
216
|
+
) => {
|
|
217
|
+
this.currentProperties._current =
|
|
218
|
+
buffer.readInt16LE(126 + this.offset * 2) / 1000;
|
|
219
|
+
return this.currentProperties._current;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
this.addDefaultPath(
|
|
223
|
+
"remainingCapacity",
|
|
224
|
+
"electrical.batteries.capacity.remaining"
|
|
225
|
+
).read = (buffer) => {
|
|
226
|
+
this.currentProperties._capacityRemaining =
|
|
227
|
+
(buffer.readUInt32LE(142 + this.offset * 2) / 1000) * 3600;
|
|
228
|
+
return this.currentProperties._capacityRemaining;
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
this.addDefaultPath(
|
|
232
|
+
"capacity",
|
|
233
|
+
"electrical.batteries.capacity.actual"
|
|
234
|
+
).read = (buffer) => {
|
|
235
|
+
this.currentProperties._capacityActual =
|
|
236
|
+
(buffer.readUInt32LE(146 + this.offset * 2) / 1000) * 3600;
|
|
237
|
+
return this.currentProperties._capacityActual;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
this.addDefaultPath(
|
|
241
|
+
"timeRemaining",
|
|
242
|
+
"electrical.batteries.capacity.timeRemaining"
|
|
243
|
+
).read = (buffer) => {
|
|
244
|
+
return Math.abs(
|
|
245
|
+
(this.currentProperties._capacityActual * this.dischargeFloor) /
|
|
246
|
+
this.currentProperties._current
|
|
247
|
+
);
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
this.addDefaultPath("cycles", "electrical.batteries.cycles").read = (
|
|
251
|
+
buffer
|
|
252
|
+
) => {
|
|
253
|
+
return buffer.readUInt32LE(150 + this.offset * 2);
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
this.addMetadatum("cycleCapacity", "number", "Cycle capacity", (buffer) => {
|
|
257
|
+
return buffer.readUInt32LE(154 + this.offset * 2) / 1000;
|
|
258
|
+
}).default = "electrical.batteries.{batteryID}.discharging";
|
|
259
|
+
|
|
260
|
+
this.addMetadatum(
|
|
261
|
+
"balanceAction",
|
|
262
|
+
"",
|
|
263
|
+
"Balancing action (0=off 1=Charging Balance, 2=Discharging Balance",
|
|
264
|
+
(buffer) => {
|
|
265
|
+
return buffer[140 + this.offset * 2];
|
|
266
|
+
}
|
|
267
|
+
).default = "electrical.batteries.{batteryID}.balanceAction";
|
|
268
|
+
|
|
269
|
+
this.addMetadatum("balancingCurrent", "", "Balancing current", (buffer) => {
|
|
270
|
+
return buffer.readUInt16LE(138 + this.offset * 2) / 1000;
|
|
271
|
+
}).default = "electrical.batteries.{batteryID}.balance";
|
|
272
|
+
|
|
273
|
+
this.addDefaultPath(
|
|
274
|
+
"SOC",
|
|
275
|
+
"electrical.batteries.capacity.stateOfCharge"
|
|
276
|
+
).read = (buffer) => {
|
|
277
|
+
return buffer[141 + this.offset * 2] / 100;
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
this.addDefaultPath(
|
|
281
|
+
"SOH",
|
|
282
|
+
"electrical.batteries.capacity.stateOfHealth"
|
|
283
|
+
).read = (buffer) => {
|
|
284
|
+
return buffer[158 + this.offset * 2] / 100;
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
this.addMetadatum("runtime", "s", "Total runtime in seconds", (buffer) => {
|
|
288
|
+
return buffer.readUInt32LE(162 + this.offset * 2);
|
|
289
|
+
}).default = "electrical.batteries.{batteryID}.runtime";
|
|
290
|
+
|
|
291
|
+
this.addMetadatum(
|
|
292
|
+
"timeEmergency",
|
|
293
|
+
"s",
|
|
294
|
+
"Time emergency in seconds",
|
|
295
|
+
(buffer) => {
|
|
296
|
+
return buffer.readUInt16LE(186 + this.offset * 2);
|
|
297
|
+
}
|
|
298
|
+
).default = "electrical.batteries.{batteryID}.timeEmergency";
|
|
299
|
+
|
|
300
|
+
this.addMetadatum(
|
|
301
|
+
"charging",
|
|
302
|
+
"bool",
|
|
303
|
+
"MOSFET Charging enable",
|
|
304
|
+
(buffer) => {
|
|
305
|
+
return buffer[166 + this.offset * 2] == 1;
|
|
306
|
+
}
|
|
307
|
+
).default = "electrical.batteries.{batteryID}.charging";
|
|
308
|
+
|
|
309
|
+
this.addMetadatum(
|
|
310
|
+
"discharging",
|
|
311
|
+
"bool",
|
|
312
|
+
"MOSFET Disharging enable",
|
|
313
|
+
(buffer) => {
|
|
314
|
+
return buffer[167 + this.offset * 2] == 1;
|
|
315
|
+
}
|
|
316
|
+
).default = "electrical.batteries.{batteryID}.discharging";
|
|
317
|
+
|
|
318
|
+
this.addMetadatum("temp1", "K", "Temperature 1 in K", (buffer) => {
|
|
319
|
+
return 273.15 + buffer.readInt16LE(130 + this.offset * 2) / 10;
|
|
320
|
+
}).default = "electrical.batteries.{batteryID}.temperature1";
|
|
321
|
+
|
|
322
|
+
this.addMetadatum("temp2", "K", "Temperature 2 in K", (buffer) => {
|
|
323
|
+
return 273.15 + buffer.readInt16LE(132 + this.offset * 2) / 10;
|
|
324
|
+
}).default = "electrical.batteries.{batteryID}.temperature2";
|
|
325
|
+
|
|
326
|
+
this.addMetadatum("mosTemp", "K", "MOS Temperature in K", (buffer) => {
|
|
327
|
+
return 273.15 + buffer.readInt16LE(112 + this.offset * 2) / 10;
|
|
328
|
+
}).default = "electrical.batteries.{batteryID}.mosTemperature";
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
hasGATT() {
|
|
332
|
+
return true;
|
|
333
|
+
}
|
|
334
|
+
async initGATTNotifications() {
|
|
335
|
+
this.debug(`${this.getName()}::initGATTNotifications`);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
async emitGATT() {
|
|
339
|
+
await this.getAndEmitBatteryInfo();
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
async getNumberOfCells() {
|
|
343
|
+
this.debug(`${this.getName()}::getNumberOfCells`);
|
|
344
|
+
|
|
345
|
+
const b = await this.getBuffer(0x96);
|
|
346
|
+
return countSetBits(b.readUInt32BE(70));
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
getBuffer(command) {
|
|
350
|
+
return new Promise(async (resolve, reject) => {
|
|
351
|
+
const r = await this.sendReadFunctionRequest(command);
|
|
352
|
+
let datasize = 300;
|
|
353
|
+
let result = Buffer.alloc(datasize);
|
|
354
|
+
let offset = 0;
|
|
355
|
+
|
|
356
|
+
const timer = setTimeout(() => {
|
|
357
|
+
this.rxChar.removeAllListeners();
|
|
358
|
+
clearTimeout(timer);
|
|
359
|
+
reject(
|
|
360
|
+
new Error(
|
|
361
|
+
`Response timed out (+30s) getting results for command ${command} from JikongBMS device ${this.getName()}.`
|
|
362
|
+
)
|
|
363
|
+
);
|
|
364
|
+
}, 30000);
|
|
365
|
+
|
|
366
|
+
const valChanged = async (buffer) => {
|
|
367
|
+
if (
|
|
368
|
+
offset == 0 && //first packet
|
|
369
|
+
(buffer.length < 5 ||
|
|
370
|
+
buffer.readUInt32BE(0) !== this.constructor.validResponseHeader)
|
|
371
|
+
) {
|
|
372
|
+
if (
|
|
373
|
+
buffer.readUInt32BE(0) !== this.constructor.validAcknowledgeHeader
|
|
374
|
+
)
|
|
375
|
+
this.debug(
|
|
376
|
+
`Invalid buffer ${JSON.stringify(
|
|
377
|
+
buffer
|
|
378
|
+
)}from ${this.getName()}, not processing.`
|
|
379
|
+
);
|
|
380
|
+
} else {
|
|
381
|
+
buffer.copy(result, offset);
|
|
382
|
+
if (offset + buffer.length == datasize) {
|
|
383
|
+
if (result[4] == this.constructor.commandResponse[command]) {
|
|
384
|
+
this.rxChar.removeAllListeners();
|
|
385
|
+
clearTimeout(timer);
|
|
386
|
+
this.debug(
|
|
387
|
+
`Rec'd command in buffer ${JSON.stringify(
|
|
388
|
+
result
|
|
389
|
+
)} for ${this.getName()}`
|
|
390
|
+
);
|
|
391
|
+
resolve(result);
|
|
392
|
+
} else {
|
|
393
|
+
offset = 0;
|
|
394
|
+
result = Buffer.alloc(datasize);
|
|
395
|
+
}
|
|
396
|
+
} else {
|
|
397
|
+
offset += buffer.length;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
this.rxChar.on("valuechanged", valChanged);
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
usingGATT() {
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
async getAndEmitBatteryInfo() {
|
|
410
|
+
const buffer = await this.getBuffer(0x96);
|
|
411
|
+
[
|
|
412
|
+
"current",
|
|
413
|
+
"voltage",
|
|
414
|
+
"remainingCapacity",
|
|
415
|
+
"capacity",
|
|
416
|
+
"cycles",
|
|
417
|
+
"charging",
|
|
418
|
+
"discharging",
|
|
419
|
+
"balanceAction",
|
|
420
|
+
"timeRemaining",
|
|
421
|
+
"balancingCurrent",
|
|
422
|
+
"cycleCapacity",
|
|
423
|
+
"timeEmergency",
|
|
424
|
+
"SOC",
|
|
425
|
+
"SOH",
|
|
426
|
+
"runtime",
|
|
427
|
+
"temp1",
|
|
428
|
+
"temp2",
|
|
429
|
+
"mosTemp",
|
|
430
|
+
].forEach((tag) => this.emitData(tag, buffer));
|
|
431
|
+
for (let i = 0; i < this.numberOfCells; i++) {
|
|
432
|
+
this.emitData(`cell${i}Voltage`, buffer);
|
|
433
|
+
this.emitData(`cell${i}Resistance`, buffer);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
["deltaCellVoltage", "avgCellVoltage"].forEach((tag) => this.emitData(tag));
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
async deactivateGATT() {
|
|
440
|
+
this.debug(`${this.getName()}::deactivateGATT`);
|
|
441
|
+
if (this.rxChar) {
|
|
442
|
+
try {
|
|
443
|
+
await this.rxChar.stopNotifications();
|
|
444
|
+
} catch (e) {
|
|
445
|
+
this.debug(
|
|
446
|
+
`(${this.getName()}) Error stopping notifications for rxChar`
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
await super.deactivateGATT();
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
async initGATTConnection(isReconnecting = false) {
|
|
454
|
+
this.debug(`${this.getName()}::initGATTConnection`);
|
|
455
|
+
|
|
456
|
+
await super.initGATTConnection(isReconnecting);
|
|
457
|
+
const gattServer = await this.getGATTServer();
|
|
458
|
+
|
|
459
|
+
this.rxService = await gattServer.getPrimaryService(
|
|
460
|
+
this.constructor.RX_SERVICE
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
if (this.rxChar)
|
|
464
|
+
try {
|
|
465
|
+
await this.rxChar.stopNotifications()
|
|
466
|
+
}
|
|
467
|
+
catch(e){
|
|
468
|
+
this.rxChar.removeAllListeners()
|
|
469
|
+
|
|
470
|
+
this.debug(`error while stopping notifications`)
|
|
471
|
+
this.debug(e)
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
this.rxChar = await this.rxService.getCharacteristic(
|
|
475
|
+
this.constructor.RX_CHAR_UUID
|
|
476
|
+
);
|
|
477
|
+
|
|
478
|
+
await this.rxChar.startNotifications();
|
|
479
|
+
try {
|
|
480
|
+
await this.getBuffer(0x97)
|
|
481
|
+
} catch (e) {
|
|
482
|
+
this.setError(e.message)
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
//this.debug(`(${this.getName()}) Connections: ${this.connections++}`)
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
activate(config, plugin) {
|
|
489
|
+
super.activate(config, plugin);
|
|
490
|
+
this.initGATTConnection().then(async () => {
|
|
491
|
+
try {
|
|
492
|
+
await this.getAndEmitBatteryInfo();
|
|
493
|
+
} catch(e) {
|
|
494
|
+
this.setError(e.message)
|
|
495
|
+
}
|
|
496
|
+
this.intervalID = setInterval(async () => {
|
|
497
|
+
if (!(await this.device.isConnected())) {
|
|
498
|
+
await this.initGATTConnection(true);
|
|
499
|
+
}
|
|
500
|
+
await this.getAndEmitBatteryInfo();
|
|
501
|
+
}, this.pollFreq * 1000);
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
module.exports = JikongBMS;
|
|
@@ -56,7 +56,7 @@ const BTSensor = require("../BTSensor");
|
|
|
56
56
|
}
|
|
57
57
|
emitInfo1Data(buffer){
|
|
58
58
|
if (buffer.length < 20) {
|
|
59
|
-
|
|
59
|
+
this.debug(`Bad buffer size ${buffer.length}. Buffer size must be 20 bytes or more.`)
|
|
60
60
|
return
|
|
61
61
|
}
|
|
62
62
|
this.emit("versionNumber", buffer.readUInt8(0))
|
|
@@ -85,7 +85,7 @@ const BTSensor = require("../BTSensor");
|
|
|
85
85
|
emitInfo2Data(buffer){
|
|
86
86
|
|
|
87
87
|
if (buffer.size < 12) {
|
|
88
|
-
|
|
88
|
+
this.setError(`Bad buffer size ${buffer.length}. Buffer size must be 12 bytes or more.`)
|
|
89
89
|
return
|
|
90
90
|
}
|
|
91
91
|
this.emit("versionNumber", buffer.readUInt8(0))
|
|
@@ -96,8 +96,7 @@ const BTSensor = require("../BTSensor");
|
|
|
96
96
|
}
|
|
97
97
|
emitEventData(buffer){
|
|
98
98
|
if (buffer.length < 14) {
|
|
99
|
-
this.debug(buffer)
|
|
100
|
-
app.debug(`Bad buffer size ${buffer.length}. Buffer size must be 14 bytes or more.`)
|
|
99
|
+
this.debug(`Bad buffer size ${buffer.length}. Buffer size must be 14 bytes or more.`)
|
|
101
100
|
return
|
|
102
101
|
}
|
|
103
102
|
const eventType = buffer.readUInt16LE(8)
|
|
@@ -61,6 +61,7 @@ class ShellySBMO003Z extends AbstractBTHomeSensor {
|
|
|
61
61
|
)
|
|
62
62
|
.default="sensors.{macAndName}.button"
|
|
63
63
|
|
|
64
|
+
|
|
64
65
|
/*
|
|
65
66
|
this.addMetadatum(
|
|
66
67
|
"packetID",
|
|
@@ -72,6 +73,10 @@ class ShellySBMO003Z extends AbstractBTHomeSensor {
|
|
|
72
73
|
*/
|
|
73
74
|
|
|
74
75
|
}
|
|
76
|
+
getState() {
|
|
77
|
+
|
|
78
|
+
return super.getState()
|
|
79
|
+
}
|
|
75
80
|
}
|
|
76
81
|
|
|
77
82
|
module.exports = ShellySBMO003Z;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"delay":100,
|
|
3
|
+
"data":
|
|
4
|
+
{
|
|
5
|
+
"0x96": [
|
|
6
|
+
"55 aa eb 90 01 de 58 02 00 00 f0 0a 00 00 54 0b 00 00 10 0e 00 00 de 0d 00 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f6 09 00 00 f0 49 02 00 1e 00 00 00 3c 00 00 00 40 0d 03 00 1e 00 00 00 3c 00 00 00 3c 00 00 00 d0 07 00 00 f4 01 00 00 c2 01 00 00 f4 01 00 00 c2 01 00 00 00 00 00 00 1e 00 00 00 84 03 00 00 20 03 00 00 04 00 00 00 01 00 00 00 01 00 00 00 01 00",
|
|
7
|
+
"00 00 e0 93 04 00 dc 05 00 00 48 0d 00 00 00 00 00 00 00 00 00 00",
|
|
8
|
+
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00",
|
|
9
|
+
"b0 71 0b 00 08 00 00 00 00 7c f8 ff ff 1f 0d 00 00 00 00 00 00 2a",
|
|
10
|
+
"55 aa eb 90 02 de 02 0d 02 0d 02 0d 02 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0f 00 00 00 02 0d 00 00 00 00 2e 00 31 00 34 00 28 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
|
|
11
|
+
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 cb 00 00 00 00 00",
|
|
12
|
+
"06 34 00 00 e9 1d 00 00 c1 fd ff ff ac 00 ac 00 00 00 00 00 00 00 00 2a 5b f4 01 00 e0 93 04 00 40 00 00 00 bd 30 29 01 64 00 00 00 19 95 c1 03 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff 00 01 00 00 00 bf 03 01 00 03 00 12 5b 3f 40 00 00 00 00 33 05 39 1b 00 01 00 01 00 05 00 00 c0 2c df 00 00 00 00 00 cb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
|
|
13
|
+
"00 00 00 00 00 00 00 00 00 fe ff 7f dc 0f 01 00 00 00 00 00 00 f1",
|
|
14
|
+
"55 aa eb 90 02 de 02 0d 02 0d 02 0d 02 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0f 00 00 00 02 0d 00 00 00 00 2e 00 31 00 34 00 28 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
|
|
15
|
+
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 cb 00 00 00 00 00",
|
|
16
|
+
"06 34 00 00 e9 1d 00 00 c1 fd ff ff ac 00 ac 00 00 00 00 00 00 00 00 2a 5b f4 01 00 e0 93 04 00 40 00 00 00 bd 30 29 01 64 00 00 00 19 95 c1 03 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff 00 01 00 00 00 bf 03 01 00 03 00 12 5b 3f 40 00 00 00 00 33 05 39 1b 00 01 00 01 00 05 00 00 c0 2c df 00 00 00 00 00 cb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
|
|
17
|
+
"00 00 00 00 00 00 00 00 00 fe ff 7f dc 0f 01 00 00 00 00 00 00 f1",
|
|
18
|
+
"55 aa eb 90 01 de 58 02 00 00 f0 0a 00 00 54 0b 00 00 10 0e 00 00 de 0d 00 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f6 09 00 00 f0 49 02 00 1e 00 00 00 3c 00 00 00 40 0d 03 00 1e 00 00 00 3c 00 00 00 3c 00 00 00 d0 07 00 00 f4 01 00 00 c2 01 00 00 f4 01 00 00 c2 01 00 00 00 00 00 00 1e 00 00 00 84 03 00 00 20 03 00 00 04 00 00 00 01 00 00 00 01 00 00 00 01 00",
|
|
19
|
+
"00 00 e0 93 04 00 dc 05 00 00 48 0d 00 00 00 00 00 00 00 00 00 00",
|
|
20
|
+
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00",
|
|
21
|
+
"b0 71 0b 00 08 00 00 00 00 7c f8 ff ff 1f 0d 00 00 00 00 00 00 2a",
|
|
22
|
+
"aa bb cc dd ee ff",
|
|
23
|
+
"aa bb cc",
|
|
24
|
+
"55 aa eb 90 02 de 02 0d 02 0d 02 0d 02 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0f 00 00 00 02 0d 00 00 00 00 2e 00 31 00 34 00 28 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
|
|
25
|
+
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 cb 00 00 00 00 00",
|
|
26
|
+
"06 34 00 00 e9 1d 00 00 c1 fd ff ff ac 00 ac 00 00 00 00 00 00 00 00 2a 5b f4 01 00 e0 93 04 00 40 00 00 00 bd 30 29 01 64 00 00 00 19 95 c1 03 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff 00 01 00 00 00 bf 03 01 00 03 00 12 5b 3f 40 00 00 00 00 33 05 39 1b 00 01 00 01 00 05 00 00 c0 2c df 00 00 00 00 00 cb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
|
|
27
|
+
"00 00 00 00 00 00 00 00 00 fe ff 7f dc 0f 01 00 00 00 00 00 00 f1"
|
|
28
|
+
],
|
|
29
|
+
"0x97":[
|
|
30
|
+
"55 aa eb 90 03 c4 4a 4b 5f 42 32 41 38 53 32 30 50 00 00 00 00 00 31 31 2e 58 57 00 00 00 31 31 2e 32 36 31 00 00 68 96 c1 03 18 00 00 00 48 42 31 5f 42 34 00 00 00 00 00 00 00 00 00 00 31 32 33 34 00 00 00 00 00 00 00 00 00 00 00 00 32 33 30 38 31 34 00 00 33 30 32 32 38 34 34 32 36 37 00 30 30 30 30 00 49 6e 70 75 74 20 55 73 65 72 64 61 74 61 00 00 31 32 33 33 32 31 00 00 00 00",
|
|
31
|
+
"00 00 00 00 00 00 49 6e 70 75 74 20 55 73 65 72 64 61 74 61 00 00",
|
|
32
|
+
"7c f8 ff ff 1f 0d 00 00 00 00 00 00 90 0f 00 00 00 00 c0 d8 03 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
|
|
33
|
+
"00 00 00 00 00 00 00 00 00 fe 2f 00 00 00 00 00 00 00 00 00 00 bf"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -113,11 +113,9 @@ class XiaomiMiBeacon extends BTSensor{
|
|
|
113
113
|
initGATTConnection(){
|
|
114
114
|
return new Promise((resolve,reject )=>{
|
|
115
115
|
this.deviceConnect().then(async ()=>{
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
this.gattCharacteristic = await this.gattService.getCharacteristic("ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6")
|
|
120
|
-
}
|
|
116
|
+
const gatt = await this.getGATTServer()
|
|
117
|
+
this.gattService = await gatt.getPrimaryService("ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6")
|
|
118
|
+
this.gattCharacteristic = await this.gattService.getCharacteristic("ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6")
|
|
121
119
|
resolve(this)
|
|
122
120
|
})
|
|
123
121
|
.catch((e)=>{
|
|
@@ -128,7 +126,9 @@ class XiaomiMiBeacon extends BTSensor{
|
|
|
128
126
|
|
|
129
127
|
emitGATT(){
|
|
130
128
|
this.gattCharacteristic.readValue()
|
|
131
|
-
.then(
|
|
129
|
+
.then(
|
|
130
|
+
(buffer)=>this.emitValues(buffer)
|
|
131
|
+
)
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
async initGATTNotifications() {
|
|
@@ -247,19 +247,17 @@ class XiaomiMiBeacon extends BTSensor{
|
|
|
247
247
|
|
|
248
248
|
}
|
|
249
249
|
|
|
250
|
+
async deactivateGATT(){
|
|
251
|
+
await this.disconnectGATTCharacteristic()
|
|
252
|
+
await super.deactivateGATT()
|
|
253
|
+
}
|
|
254
|
+
|
|
250
255
|
async disconnectGATTCharacteristic(){
|
|
251
256
|
if (this.gattCharacteristic && await this.gattCharacteristic.isNotifying()) {
|
|
257
|
+
this.gattCharacteristic.removeAllListeners()
|
|
252
258
|
await this.gattCharacteristic.stopNotifications()
|
|
253
259
|
this.gattCharacteristic=null
|
|
254
260
|
}
|
|
255
261
|
}
|
|
256
|
-
async stopListening(){
|
|
257
|
-
super.stopListening()
|
|
258
|
-
await this.disconnectGATTCharacteristic()
|
|
259
|
-
|
|
260
|
-
if (await this.device.isConnected()){
|
|
261
|
-
await this.device.disconnect()
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
262
|
}
|
|
265
263
|
module.exports=XiaomiMiBeacon
|
|
@@ -228,7 +228,7 @@ async function fetchJSONData(path, data = {}) {
|
|
|
228
228
|
function sensorChangedEvent(event){
|
|
229
229
|
console.log("sensorchanged")
|
|
230
230
|
const json = JSON.parse(event.data)
|
|
231
|
-
|
|
231
|
+
console.log(json)
|
|
232
232
|
setSensorMap( (_sm) => {
|
|
233
233
|
const sensor = _sm.get(json.mac)
|
|
234
234
|
if (sensor)
|
|
@@ -385,12 +385,17 @@ function createListGroupItem(sensor){
|
|
|
385
385
|
}>
|
|
386
386
|
<div class="d-flex justify-content-between align-items-center" style={config?{fontWeight:"normal"}:{fontStyle:"italic"}}>
|
|
387
387
|
{`${sensor._changesMade?"*":""}${sensor.info.name} MAC: ${sensor.info.mac} RSSI: ${ifNullNaN(sensor.info.RSSI)}` }
|
|
388
|
+
<div class="d-flex justify-content-between ">
|
|
389
|
+
{
|
|
390
|
+
sensor.info.state
|
|
391
|
+
}
|
|
388
392
|
<div class="d-flex justify-content-between ">
|
|
389
393
|
{
|
|
390
394
|
signalStrengthIcon(sensor)
|
|
391
395
|
}
|
|
392
396
|
</div>
|
|
393
397
|
</div>
|
|
398
|
+
</div>
|
|
394
399
|
</ListGroupItem>
|
|
395
400
|
}
|
|
396
401
|
|