node-switchbot 2.5.0-beta.32 → 2.5.0-beta.34
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/OpenAPI.md +18 -5
- package/dist/advertising.d.ts +3 -3
- package/dist/advertising.d.ts.map +1 -1
- package/dist/advertising.js +26 -25
- package/dist/advertising.js.map +1 -1
- package/dist/device/woblindtilt.d.ts +3 -4
- package/dist/device/woblindtilt.d.ts.map +1 -1
- package/dist/device/woblindtilt.js +7 -3
- package/dist/device/woblindtilt.js.map +1 -1
- package/dist/device/wobulb.d.ts +2 -3
- package/dist/device/wobulb.d.ts.map +1 -1
- package/dist/device/wobulb.js +8 -4
- package/dist/device/wobulb.js.map +1 -1
- package/dist/device/woceilinglight.d.ts +4 -4
- package/dist/device/woceilinglight.d.ts.map +1 -1
- package/dist/device/woceilinglight.js +10 -5
- package/dist/device/woceilinglight.js.map +1 -1
- package/dist/device/wocontact.d.ts +2 -3
- package/dist/device/wocontact.d.ts.map +1 -1
- package/dist/device/wocontact.js +3 -3
- package/dist/device/wocontact.js.map +1 -1
- package/dist/device/wocurtain.d.ts +2 -3
- package/dist/device/wocurtain.d.ts.map +1 -1
- package/dist/device/wocurtain.js +7 -3
- package/dist/device/wocurtain.js.map +1 -1
- package/dist/device/wohand.d.ts +2 -3
- package/dist/device/wohand.d.ts.map +1 -1
- package/dist/device/wohand.js +7 -3
- package/dist/device/wohand.js.map +1 -1
- package/dist/device/wohub2.d.ts +2 -3
- package/dist/device/wohub2.d.ts.map +1 -1
- package/dist/device/wohub2.js +3 -3
- package/dist/device/wohub2.js.map +1 -1
- package/dist/device/wohumi.d.ts +2 -3
- package/dist/device/wohumi.d.ts.map +1 -1
- package/dist/device/wohumi.js +7 -3
- package/dist/device/wohumi.js.map +1 -1
- package/dist/device/woiosensorth.d.ts +2 -3
- package/dist/device/woiosensorth.d.ts.map +1 -1
- package/dist/device/woiosensorth.js +4 -4
- package/dist/device/woiosensorth.js.map +1 -1
- package/dist/device/woplugmini.d.ts +5 -4
- package/dist/device/woplugmini.d.ts.map +1 -1
- package/dist/device/woplugmini.js +13 -7
- package/dist/device/woplugmini.js.map +1 -1
- package/dist/device/wopresence.d.ts +2 -3
- package/dist/device/wopresence.d.ts.map +1 -1
- package/dist/device/wopresence.js +3 -3
- package/dist/device/wopresence.js.map +1 -1
- package/dist/device/wosensorth.d.ts +4 -4
- package/dist/device/wosensorth.d.ts.map +1 -1
- package/dist/device/wosensorth.js +6 -5
- package/dist/device/wosensorth.js.map +1 -1
- package/dist/device/wosmartlock.d.ts +8 -3
- package/dist/device/wosmartlock.d.ts.map +1 -1
- package/dist/device/wosmartlock.js +9 -3
- package/dist/device/wosmartlock.js.map +1 -1
- package/dist/device/wosmartlockpro.d.ts +8 -3
- package/dist/device/wosmartlockpro.d.ts.map +1 -1
- package/dist/device/wosmartlockpro.js +9 -3
- package/dist/device/wosmartlockpro.js.map +1 -1
- package/dist/device/wostrip.d.ts +2 -3
- package/dist/device/wostrip.d.ts.map +1 -1
- package/dist/device/wostrip.js +3 -3
- package/dist/device/wostrip.js.map +1 -1
- package/dist/device.d.ts +9 -1
- package/dist/device.d.ts.map +1 -1
- package/dist/device.js +13 -2
- package/dist/device.js.map +1 -1
- package/dist/switchbot-ble.d.ts.map +1 -1
- package/dist/switchbot-ble.js +2 -2
- package/dist/switchbot-ble.js.map +1 -1
- package/dist/test/advertising.test.js +7 -4
- package/dist/test/advertising.test.js.map +1 -1
- package/dist/test/woblindtilt.test.js +75 -1
- package/dist/test/woblindtilt.test.js.map +1 -1
- package/dist/test/wobulb.test.js +94 -1
- package/dist/test/wobulb.test.js.map +1 -1
- package/dist/test/woceilinglight.test.js +80 -1
- package/dist/test/woceilinglight.test.js.map +1 -1
- package/dist/test/wocontact.test.js +64 -1
- package/dist/test/wocontact.test.js.map +1 -1
- package/dist/test/wocurtain.test.js +74 -1
- package/dist/test/wocurtain.test.js.map +1 -1
- package/dist/test/wohand.test.js +55 -1
- package/dist/test/wohand.test.js.map +1 -1
- package/dist/test/wohub2.test.js +79 -1
- package/dist/test/wohub2.test.js.map +1 -1
- package/dist/test/wohumi.test.js +81 -1
- package/dist/test/wohumi.test.js.map +1 -1
- package/dist/test/woiosensorth.test.js +39 -1
- package/dist/test/woiosensorth.test.js.map +1 -1
- package/dist/test/woplugmini.test.js +113 -1
- package/dist/test/woplugmini.test.js.map +1 -1
- package/dist/test/wopresence.test.js +67 -1
- package/dist/test/wopresence.test.js.map +1 -1
- package/dist/test/wosensorth.test.js +50 -1
- package/dist/test/wosensorth.test.js.map +1 -1
- package/dist/test/wosmartlock.test.js +150 -1
- package/dist/test/wosmartlock.test.js.map +1 -1
- package/dist/test/wosmartlockpro.test.js +150 -1
- package/dist/test/wosmartlockpro.test.js.map +1 -1
- package/dist/test/wostrip.test.js +101 -1
- package/dist/test/wostrip.test.js.map +1 -1
- package/dist/types/types.d.ts +7 -3
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js +6 -2
- package/dist/types/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,2 +1,40 @@
|
|
|
1
|
-
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { WoIOSensorTH } from '../device/woiosensorth.js';
|
|
4
|
+
import { SwitchBotBLEModel, SwitchBotBLEModelFriendlyName, SwitchBotBLEModelName } from '../types/types.js';
|
|
5
|
+
describe('woIOSensorTH', () => {
|
|
6
|
+
describe('parseServiceData', () => {
|
|
7
|
+
const emitLog = vi.fn();
|
|
8
|
+
it('should return parsed data for valid buffers', async () => {
|
|
9
|
+
const serviceData = Buffer.from([0x00, 0x00, 0x64]);
|
|
10
|
+
const manufacturerData = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x2A, 0x50, 0x00]);
|
|
11
|
+
const result = await WoIOSensorTH.parseServiceData(serviceData, manufacturerData, emitLog);
|
|
12
|
+
expect(result).toEqual({
|
|
13
|
+
model: SwitchBotBLEModel.OutdoorMeter,
|
|
14
|
+
modelName: SwitchBotBLEModelName.OutdoorMeter,
|
|
15
|
+
modelFriendlyName: SwitchBotBLEModelFriendlyName.OutdoorMeter,
|
|
16
|
+
celsius: 42.6,
|
|
17
|
+
fahrenheit: 108.7,
|
|
18
|
+
fahrenheit_mode: true,
|
|
19
|
+
humidity: 80,
|
|
20
|
+
battery: 100,
|
|
21
|
+
});
|
|
22
|
+
expect(emitLog).not.toHaveBeenCalled();
|
|
23
|
+
});
|
|
24
|
+
it('should return null for invalid serviceData length', async () => {
|
|
25
|
+
const serviceData = Buffer.from([0x00, 0x00]);
|
|
26
|
+
const manufacturerData = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x2A, 0x50, 0x00]);
|
|
27
|
+
const result = await WoIOSensorTH.parseServiceData(serviceData, manufacturerData, emitLog);
|
|
28
|
+
expect(result).toBeNull();
|
|
29
|
+
expect(emitLog).toHaveBeenCalledWith('error', '[parseServiceDataForWoIOSensorTH] Service Data Buffer length 2 !== 3!');
|
|
30
|
+
});
|
|
31
|
+
it('should return null for invalid manufacturerData length', async () => {
|
|
32
|
+
const serviceData = Buffer.from([0x00, 0x00, 0x64]);
|
|
33
|
+
const manufacturerData = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x2A]);
|
|
34
|
+
const result = await WoIOSensorTH.parseServiceData(serviceData, manufacturerData, emitLog);
|
|
35
|
+
expect(result).toBeNull();
|
|
36
|
+
expect(emitLog).toHaveBeenCalledWith('error', '[parseServiceDataForWoIOSensorTH] Manufacturer Data Buffer length 12 !== 14!');
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
});
|
|
2
40
|
//# sourceMappingURL=woiosensorth.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"woiosensorth.test.js","sourceRoot":"","sources":["../../src/test/woiosensorth.test.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"woiosensorth.test.js","sourceRoot":"","sources":["../../src/test/woiosensorth.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,114 @@
|
|
|
1
|
-
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import sinon from 'sinon';
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
import { WoPlugMini } from '../device/woplugmini.js';
|
|
5
|
+
import { SwitchBotBLEModel } from '../types/types.js';
|
|
6
|
+
describe('woPlugMini', () => {
|
|
7
|
+
let emitLog;
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
emitLog = sinon.spy();
|
|
10
|
+
});
|
|
11
|
+
describe('parseServiceData_US', () => {
|
|
12
|
+
it('should parse valid service data for US model', async () => {
|
|
13
|
+
const manufacturerData = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0, 0, 0, 0]);
|
|
14
|
+
const result = await WoPlugMini.parseServiceData_US(manufacturerData, emitLog);
|
|
15
|
+
expect(result).toEqual({
|
|
16
|
+
model: SwitchBotBLEModel.PlugMiniUS,
|
|
17
|
+
modelName: 'PlugMini',
|
|
18
|
+
modelFriendlyName: 'PlugMini',
|
|
19
|
+
state: 'on',
|
|
20
|
+
delay: false,
|
|
21
|
+
timer: false,
|
|
22
|
+
syncUtcTime: false,
|
|
23
|
+
wifiRssi: 0,
|
|
24
|
+
overload: false,
|
|
25
|
+
currentPower: 0,
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
it('should return null for invalid service data length', async () => {
|
|
29
|
+
const manufacturerData = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
|
30
|
+
const result = await WoPlugMini.parseServiceData_US(manufacturerData, emitLog);
|
|
31
|
+
expect(result).toBeNull();
|
|
32
|
+
expect(emitLog.calledWith('error', '[parseServiceDataForWoPlugMini] Buffer length 10 should be 14')).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
describe('parseServiceData_JP', () => {
|
|
36
|
+
it('should parse valid service data for JP model', async () => {
|
|
37
|
+
const manufacturerData = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0, 0, 0, 0]);
|
|
38
|
+
const result = await WoPlugMini.parseServiceData_JP(manufacturerData, emitLog);
|
|
39
|
+
expect(result).toEqual({
|
|
40
|
+
model: SwitchBotBLEModel.PlugMiniJP,
|
|
41
|
+
modelName: 'PlugMini',
|
|
42
|
+
modelFriendlyName: 'PlugMini',
|
|
43
|
+
state: 'on',
|
|
44
|
+
delay: false,
|
|
45
|
+
timer: false,
|
|
46
|
+
syncUtcTime: false,
|
|
47
|
+
wifiRssi: 0,
|
|
48
|
+
overload: false,
|
|
49
|
+
currentPower: 0,
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
it('should return null for invalid service data length', async () => {
|
|
53
|
+
const manufacturerData = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
|
54
|
+
const result = await WoPlugMini.parseServiceData_JP(manufacturerData, emitLog);
|
|
55
|
+
expect(result).toBeNull();
|
|
56
|
+
expect(emitLog.calledWith('error', '[parseServiceDataForWoPlugMini] Buffer length 10 should be 14')).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
describe('operatePlug', () => {
|
|
60
|
+
let woPlugMini;
|
|
61
|
+
let commandStub;
|
|
62
|
+
beforeEach(() => {
|
|
63
|
+
const peripheral = {};
|
|
64
|
+
woPlugMini = new WoPlugMini(peripheral, emitLog);
|
|
65
|
+
commandStub = sinon.stub(woPlugMini, 'command');
|
|
66
|
+
});
|
|
67
|
+
it('should return true when the plug is turned on', async () => {
|
|
68
|
+
commandStub.resolves([0x57, 0x80]);
|
|
69
|
+
const result = await woPlugMini.operatePlug([0x57, 0x0F, 0x51, 0x01]);
|
|
70
|
+
expect(result).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
it('should return false when the plug is turned off', async () => {
|
|
73
|
+
commandStub.resolves([0x57, 0x00]);
|
|
74
|
+
const result = await woPlugMini.operatePlug([0x57, 0x0F, 0x51, 0x01]);
|
|
75
|
+
expect(result).toBe(false);
|
|
76
|
+
});
|
|
77
|
+
it('should throw an error for invalid response length', async () => {
|
|
78
|
+
commandStub.resolves([0x57]);
|
|
79
|
+
await expect(woPlugMini.operatePlug([0x57, 0x0F, 0x51, 0x01])).rejects.toThrow('Expecting a 2-byte response, got instead: 0x57');
|
|
80
|
+
});
|
|
81
|
+
it('should throw an error for invalid response code', async () => {
|
|
82
|
+
commandStub.resolves([0x57, 0x01]);
|
|
83
|
+
await expect(woPlugMini.operatePlug([0x57, 0x0F, 0x51, 0x01])).rejects.toThrow('The device returned an error: 0x5701');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
describe('state operations', () => {
|
|
87
|
+
let woPlugMini;
|
|
88
|
+
let setStateStub;
|
|
89
|
+
beforeEach(() => {
|
|
90
|
+
const peripheral = {};
|
|
91
|
+
woPlugMini = new WoPlugMini(peripheral, emitLog);
|
|
92
|
+
setStateStub = sinon.stub(woPlugMini, 'setState');
|
|
93
|
+
});
|
|
94
|
+
it('should turn on the plug', async () => {
|
|
95
|
+
setStateStub.resolves(true);
|
|
96
|
+
const result = await woPlugMini.turnOn();
|
|
97
|
+
expect(result).toBe(true);
|
|
98
|
+
expect(setStateStub.calledWith([0x01, 0x80])).toBe(true);
|
|
99
|
+
});
|
|
100
|
+
it('should turn off the plug', async () => {
|
|
101
|
+
setStateStub.resolves(false);
|
|
102
|
+
const result = await woPlugMini.turnOff();
|
|
103
|
+
expect(result).toBe(false);
|
|
104
|
+
expect(setStateStub.calledWith([0x01, 0x00])).toBe(true);
|
|
105
|
+
});
|
|
106
|
+
it('should toggle the plug state', async () => {
|
|
107
|
+
setStateStub.resolves(true);
|
|
108
|
+
const result = await woPlugMini.toggle();
|
|
109
|
+
expect(result).toBe(true);
|
|
110
|
+
expect(setStateStub.calledWith([0x02, 0x80])).toBe(true);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
});
|
|
2
114
|
//# sourceMappingURL=woplugmini.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"woplugmini.test.js","sourceRoot":"","sources":["../../src/test/woplugmini.test.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"woplugmini.test.js","sourceRoot":"","sources":["../../src/test/woplugmini.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,68 @@
|
|
|
1
|
-
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { WoPresence } from '../device/wopresence.js';
|
|
4
|
+
import { SwitchBotBLEModel, SwitchBotBLEModelFriendlyName, SwitchBotBLEModelName } from '../types/types.js';
|
|
5
|
+
describe('woPresence', () => {
|
|
6
|
+
describe('parseServiceData', () => {
|
|
7
|
+
const emitLog = vi.fn();
|
|
8
|
+
it('should return null if buffer length is not 6', async () => {
|
|
9
|
+
const serviceData = Buffer.from([0x01, 0x02, 0x03, 0x04, 0x05]);
|
|
10
|
+
const result = await WoPresence.parseServiceData(serviceData, emitLog);
|
|
11
|
+
expect(result).toBeNull();
|
|
12
|
+
expect(emitLog).toHaveBeenCalledWith('error', '[parseServiceDataForWoPresence] Buffer length 5 !== 6!');
|
|
13
|
+
});
|
|
14
|
+
it('should parse valid service data correctly', async () => {
|
|
15
|
+
const serviceData = Buffer.from([0b10000000, 0b01111111, 0x00, 0x00, 0x00, 0b00101101]);
|
|
16
|
+
const expectedData = {
|
|
17
|
+
model: SwitchBotBLEModel.MotionSensor,
|
|
18
|
+
modelName: SwitchBotBLEModelName.MotionSensor,
|
|
19
|
+
modelFriendlyName: SwitchBotBLEModelFriendlyName.MotionSensor,
|
|
20
|
+
tested: true,
|
|
21
|
+
movement: false,
|
|
22
|
+
battery: 127,
|
|
23
|
+
led: 1,
|
|
24
|
+
iot: 1,
|
|
25
|
+
sense_distance: 3,
|
|
26
|
+
lightLevel: 'unknown',
|
|
27
|
+
is_light: true,
|
|
28
|
+
};
|
|
29
|
+
const result = await WoPresence.parseServiceData(serviceData, emitLog);
|
|
30
|
+
expect(result).toEqual(expectedData);
|
|
31
|
+
});
|
|
32
|
+
it('should handle different light levels correctly', async () => {
|
|
33
|
+
const serviceDataDark = Buffer.from([0b10000000, 0b01111111, 0x00, 0x00, 0x00, 0b00101100]);
|
|
34
|
+
const serviceDataBright = Buffer.from([0b10000000, 0b01111111, 0x00, 0x00, 0x00, 0b00101110]);
|
|
35
|
+
const expectedDataDark = {
|
|
36
|
+
model: SwitchBotBLEModel.MotionSensor,
|
|
37
|
+
modelName: SwitchBotBLEModelName.MotionSensor,
|
|
38
|
+
modelFriendlyName: SwitchBotBLEModelFriendlyName.MotionSensor,
|
|
39
|
+
tested: true,
|
|
40
|
+
movement: false,
|
|
41
|
+
battery: 127,
|
|
42
|
+
led: 1,
|
|
43
|
+
iot: 1,
|
|
44
|
+
sense_distance: 3,
|
|
45
|
+
lightLevel: 'dark',
|
|
46
|
+
is_light: false,
|
|
47
|
+
};
|
|
48
|
+
const expectedDataBright = {
|
|
49
|
+
model: SwitchBotBLEModel.MotionSensor,
|
|
50
|
+
modelName: SwitchBotBLEModelName.MotionSensor,
|
|
51
|
+
modelFriendlyName: SwitchBotBLEModelFriendlyName.MotionSensor,
|
|
52
|
+
tested: true,
|
|
53
|
+
movement: false,
|
|
54
|
+
battery: 127,
|
|
55
|
+
led: 1,
|
|
56
|
+
iot: 1,
|
|
57
|
+
sense_distance: 3,
|
|
58
|
+
lightLevel: 'bright',
|
|
59
|
+
is_light: true,
|
|
60
|
+
};
|
|
61
|
+
const resultDark = await WoPresence.parseServiceData(serviceDataDark, emitLog);
|
|
62
|
+
const resultBright = await WoPresence.parseServiceData(serviceDataBright, emitLog);
|
|
63
|
+
expect(resultDark).toEqual(expectedDataDark);
|
|
64
|
+
expect(resultBright).toEqual(expectedDataBright);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
});
|
|
2
68
|
//# sourceMappingURL=wopresence.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wopresence.test.js","sourceRoot":"","sources":["../../src/test/wopresence.test.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"wopresence.test.js","sourceRoot":"","sources":["../../src/test/wopresence.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,51 @@
|
|
|
1
|
-
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import { WoSensorTH } from '../device/wosensorth.js';
|
|
3
|
+
import { SwitchBotBLEModel, SwitchBotBLEModelFriendlyName, SwitchBotBLEModelName } from '../types/types.js';
|
|
4
|
+
describe('woSensorTH', () => {
|
|
5
|
+
const emitLog = jest.fn();
|
|
6
|
+
describe('parseServiceData', () => {
|
|
7
|
+
it('should return null if buffer length is not 6', async () => {
|
|
8
|
+
const serviceData = Buffer.from([0x01, 0x02, 0x03, 0x04, 0x05]);
|
|
9
|
+
const result = await WoSensorTH.parseServiceData(serviceData, emitLog);
|
|
10
|
+
expect(result).toBeNull();
|
|
11
|
+
expect(emitLog).toHaveBeenCalledWith('error', '[parseServiceDataForWoSensorTH] Buffer length 5 !== 6!');
|
|
12
|
+
});
|
|
13
|
+
it('should parse valid service data correctly', async () => {
|
|
14
|
+
const serviceData = Buffer.from([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
|
|
15
|
+
const result = await WoSensorTH.parseServiceData(serviceData, emitLog);
|
|
16
|
+
expect(result).toEqual({
|
|
17
|
+
model: SwitchBotBLEModel.Meter,
|
|
18
|
+
modelName: SwitchBotBLEModelName.Meter,
|
|
19
|
+
modelFriendlyName: SwitchBotBLEModelFriendlyName.Meter,
|
|
20
|
+
celsius: -0.4,
|
|
21
|
+
fahrenheit: 31.3,
|
|
22
|
+
fahrenheit_mode: false,
|
|
23
|
+
humidity: 6,
|
|
24
|
+
battery: 2,
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
describe('parseServiceData_Plus', () => {
|
|
29
|
+
it('should return null if buffer length is not 6', async () => {
|
|
30
|
+
const serviceData = Buffer.from([0x01, 0x02, 0x03, 0x04, 0x05]);
|
|
31
|
+
const result = await WoSensorTH.parseServiceData_Plus(serviceData, emitLog);
|
|
32
|
+
expect(result).toBeNull();
|
|
33
|
+
expect(emitLog).toHaveBeenCalledWith('error', '[parseServiceDataForWoSensorTHPlus] Buffer length 5 !== 6!');
|
|
34
|
+
});
|
|
35
|
+
it('should parse valid service data correctly', async () => {
|
|
36
|
+
const serviceData = Buffer.from([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
|
|
37
|
+
const result = await WoSensorTH.parseServiceData_Plus(serviceData, emitLog);
|
|
38
|
+
expect(result).toEqual({
|
|
39
|
+
model: SwitchBotBLEModel.MeterPlus,
|
|
40
|
+
modelName: SwitchBotBLEModelName.MeterPlus,
|
|
41
|
+
modelFriendlyName: SwitchBotBLEModelFriendlyName.MeterPlus,
|
|
42
|
+
celsius: -0.4,
|
|
43
|
+
fahrenheit: 31.3,
|
|
44
|
+
fahrenheit_mode: false,
|
|
45
|
+
humidity: 6,
|
|
46
|
+
battery: 2,
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
});
|
|
2
51
|
//# sourceMappingURL=wosensorth.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wosensorth.test.js","sourceRoot":"","sources":["../../src/test/wosensorth.test.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"wosensorth.test.js","sourceRoot":"","sources":["../../src/test/wosensorth.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,151 @@
|
|
|
1
|
-
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { WoSmartLock } from '../device/wosmartlock.js';
|
|
4
|
+
import { WoSmartLockCommands } from '../settings.js';
|
|
5
|
+
import { SwitchBotBLEModel, SwitchBotBLEModelFriendlyName, SwitchBotBLEModelName } from '../types/types.js';
|
|
6
|
+
describe('woSmartLock', () => {
|
|
7
|
+
let mockPeripheral;
|
|
8
|
+
let mockNoble;
|
|
9
|
+
let lock;
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
mockPeripheral = {};
|
|
12
|
+
mockNoble = {};
|
|
13
|
+
lock = new WoSmartLock(mockPeripheral, mockNoble);
|
|
14
|
+
});
|
|
15
|
+
describe('parseServiceData', () => {
|
|
16
|
+
it('should return null if buffer length is not 18', async () => {
|
|
17
|
+
const serviceData = Buffer.alloc(10);
|
|
18
|
+
const manufacturerData = Buffer.alloc(0);
|
|
19
|
+
const emitLog = vi.fn();
|
|
20
|
+
const result = await WoSmartLock.parseServiceData(serviceData, manufacturerData, emitLog);
|
|
21
|
+
expect(result).toBeNull();
|
|
22
|
+
expect(emitLog).toHaveBeenCalledWith('error', '[parseServiceDataForWoStrip] Buffer length 10 !== 18!');
|
|
23
|
+
});
|
|
24
|
+
it('should parse valid service data correctly', async () => {
|
|
25
|
+
const serviceData = Buffer.from([0, 0, 0, 255, 128, 64, 0, 129, 136, 127, 254, 0, 0, 0, 0, 0, 0, 0]);
|
|
26
|
+
const manufacturerData = Buffer.alloc(0);
|
|
27
|
+
const emitLog = vi.fn();
|
|
28
|
+
const result = await WoSmartLock.parseServiceData(serviceData, manufacturerData, emitLog);
|
|
29
|
+
const expected = {
|
|
30
|
+
model: SwitchBotBLEModel.Lock,
|
|
31
|
+
modelName: SwitchBotBLEModelName.Lock,
|
|
32
|
+
modelFriendlyName: SwitchBotBLEModelFriendlyName.Lock,
|
|
33
|
+
battery: 100,
|
|
34
|
+
calibration: true,
|
|
35
|
+
status: 'LOCKED',
|
|
36
|
+
door_open: false,
|
|
37
|
+
update_from_secondary_lock: false,
|
|
38
|
+
double_lock_mode: false,
|
|
39
|
+
unclosed_alarm: false,
|
|
40
|
+
unlocked_alarm: false,
|
|
41
|
+
auto_lock_paused: false,
|
|
42
|
+
night_latch: false,
|
|
43
|
+
};
|
|
44
|
+
expect(result).toEqual(expected);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
it('should initialize with default values', () => {
|
|
48
|
+
expect(lock.iv).toBeNull();
|
|
49
|
+
expect(lock.key_id).toBe('');
|
|
50
|
+
expect(lock.encryption_key).toBeNull();
|
|
51
|
+
});
|
|
52
|
+
it('should set key correctly', async () => {
|
|
53
|
+
const keyId = 'testKeyId';
|
|
54
|
+
const encryptionKey = '0123456789abcdef0123456789abcdef';
|
|
55
|
+
await lock.setKey(keyId, encryptionKey);
|
|
56
|
+
expect(lock.key_id).toBe(keyId);
|
|
57
|
+
expect(lock.encryption_key?.toString('hex')).toBe(encryptionKey);
|
|
58
|
+
});
|
|
59
|
+
it('should validate response correctly', async () => {
|
|
60
|
+
const res = Buffer.from([0x01, 0x00, 0x00]);
|
|
61
|
+
const result = await WoSmartLock.validateResponse(res);
|
|
62
|
+
expect(result).toBe(WoSmartLock.Result.SUCCESS);
|
|
63
|
+
});
|
|
64
|
+
it('should get lock status correctly', () => {
|
|
65
|
+
const status = WoSmartLock.getLockStatus(0b0010000);
|
|
66
|
+
expect(status).toBe('UNLOCKED');
|
|
67
|
+
});
|
|
68
|
+
it('should parse service data correctly', async () => {
|
|
69
|
+
const serviceData = Buffer.from([0x00, 0x00, 0x7F]);
|
|
70
|
+
const manufacturerData = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00]);
|
|
71
|
+
const emitLog = jest.fn();
|
|
72
|
+
const data = await WoSmartLock.parseServiceData(serviceData, manufacturerData, emitLog);
|
|
73
|
+
expect(data).toEqual({
|
|
74
|
+
model: 'Lock',
|
|
75
|
+
modelName: 'Lock',
|
|
76
|
+
modelFriendlyName: 'Lock',
|
|
77
|
+
battery: 127,
|
|
78
|
+
calibration: true,
|
|
79
|
+
status: 'LOCKED',
|
|
80
|
+
update_from_secondary_lock: false,
|
|
81
|
+
door_open: false,
|
|
82
|
+
double_lock_mode: false,
|
|
83
|
+
unclosed_alarm: false,
|
|
84
|
+
unlocked_alarm: false,
|
|
85
|
+
auto_lock_paused: false,
|
|
86
|
+
night_latch: false,
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
it('should unlock the smart lock', async () => {
|
|
90
|
+
jest.spyOn(lock, 'operateLock').mockResolvedValue(Buffer.from([0x01]));
|
|
91
|
+
const result = await lock.unlock();
|
|
92
|
+
expect(result).toBe(WoSmartLock.Result.SUCCESS);
|
|
93
|
+
});
|
|
94
|
+
it('should lock the smart lock', async () => {
|
|
95
|
+
jest.spyOn(lock, 'operateLock').mockResolvedValue(Buffer.from([0x01]));
|
|
96
|
+
const result = await lock.lock();
|
|
97
|
+
expect(result).toBe(WoSmartLock.Result.SUCCESS);
|
|
98
|
+
});
|
|
99
|
+
it('should get lock info', async () => {
|
|
100
|
+
jest.spyOn(lock, 'operateLock').mockResolvedValue(Buffer.from([0x01, 0b10000000, 0b00100000]));
|
|
101
|
+
const info = await lock.info();
|
|
102
|
+
expect(info).toEqual({
|
|
103
|
+
calibration: true,
|
|
104
|
+
status: 'LOCKED',
|
|
105
|
+
door_open: false,
|
|
106
|
+
unclosed_alarm: true,
|
|
107
|
+
unlocked_alarm: false,
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
it('should encrypt data correctly', async () => {
|
|
111
|
+
const keyId = 'testKeyId';
|
|
112
|
+
const encryptionKey = '0123456789abcdef0123456789abcdef';
|
|
113
|
+
await lock.setKey(keyId, encryptionKey);
|
|
114
|
+
lock.iv = Buffer.from('0123456789abcdef', 'hex');
|
|
115
|
+
const encrypted = await lock.encrypt('testdata');
|
|
116
|
+
expect(encrypted).toBe('expectedEncryptedHexString'); // Replace with actual expected encrypted string
|
|
117
|
+
});
|
|
118
|
+
it('should decrypt data correctly', async () => {
|
|
119
|
+
const keyId = 'testKeyId';
|
|
120
|
+
const encryptionKey = '0123456789abcdef0123456789abcdef';
|
|
121
|
+
await lock.setKey(keyId, encryptionKey);
|
|
122
|
+
lock.iv = Buffer.from('0123456789abcdef', 'hex');
|
|
123
|
+
const decrypted = await lock.decrypt(Buffer.from('expectedEncryptedHexString', 'hex')); // Replace with actual encrypted string
|
|
124
|
+
expect(decrypted.toString()).toBe('testdata');
|
|
125
|
+
});
|
|
126
|
+
it('should retrieve IV from the device', async () => {
|
|
127
|
+
jest.spyOn(lock, 'operateLock').mockResolvedValue(Buffer.from([0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04]));
|
|
128
|
+
const iv = await lock.getIv();
|
|
129
|
+
expect(iv.toString('hex')).toBe('01020304');
|
|
130
|
+
});
|
|
131
|
+
it('should send encrypted command to the device', async () => {
|
|
132
|
+
jest.spyOn(lock, 'getIv').mockResolvedValue(Buffer.from('01020304', 'hex'));
|
|
133
|
+
jest.spyOn(lock, 'encrypt').mockResolvedValue('encryptedCommand');
|
|
134
|
+
jest.spyOn(lock, 'command').mockResolvedValue(Buffer.from([0x01, 0x00, 0x00, 0x00, 0x05, 0x06, 0x07, 0x08]));
|
|
135
|
+
const response = await lock.encryptedCommand('testCommand');
|
|
136
|
+
expect(response.toString('hex')).toBe('expectedResponseHexString'); // Replace with actual expected response
|
|
137
|
+
});
|
|
138
|
+
describe('operateLock', () => {
|
|
139
|
+
it('should operate the lock with encryption', async () => {
|
|
140
|
+
jest.spyOn(lock, 'encryptedCommand').mockResolvedValue(Buffer.from([0x01]));
|
|
141
|
+
const response = await lock.operateLock(WoSmartLockCommands.LOCK);
|
|
142
|
+
expect(response).toBeDefined();
|
|
143
|
+
});
|
|
144
|
+
it('should operate the lock without encryption', async () => {
|
|
145
|
+
jest.spyOn(lock, 'command').mockResolvedValue(Buffer.from([0x01, 0x00, 0x00, 0x00]));
|
|
146
|
+
const response = await lock.operateLock(WoSmartLockCommands.LOCK, false);
|
|
147
|
+
expect(response).toBeDefined();
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
});
|
|
2
151
|
//# sourceMappingURL=wosmartlock.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wosmartlock.test.js","sourceRoot":"","sources":["../../src/test/wosmartlock.test.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"wosmartlock.test.js","sourceRoot":"","sources":["../../src/test/wosmartlock.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,151 @@
|
|
|
1
|
-
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import * as Noble from '@stoprocent/noble';
|
|
3
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import { WoSmartLockPro } from '../device/wosmartlockpro.js';
|
|
5
|
+
import { WoSmartLockProCommands } from '../settings.js';
|
|
6
|
+
import { SwitchBotBLEModel, SwitchBotBLEModelFriendlyName, SwitchBotBLEModelName } from '../types/types.js';
|
|
7
|
+
describe('woSmartLockPro', () => {
|
|
8
|
+
let lock;
|
|
9
|
+
let mockPeripheral;
|
|
10
|
+
let mockNoble;
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
mockPeripheral = {};
|
|
13
|
+
mockNoble = Noble;
|
|
14
|
+
lock = new WoSmartLockPro(mockPeripheral, mockNoble);
|
|
15
|
+
});
|
|
16
|
+
describe('parseServiceData', () => {
|
|
17
|
+
it('should return null if buffer length is not 18', async () => {
|
|
18
|
+
const serviceData = Buffer.alloc(10);
|
|
19
|
+
const manufacturerData = Buffer.alloc(0);
|
|
20
|
+
const emitLog = vi.fn();
|
|
21
|
+
const result = await WoSmartLockPro.parseServiceData(serviceData, manufacturerData, emitLog);
|
|
22
|
+
expect(result).toBeNull();
|
|
23
|
+
expect(emitLog).toHaveBeenCalledWith('error', '[parseServiceDataForWoStrip] Buffer length 10 !== 18!');
|
|
24
|
+
});
|
|
25
|
+
it('should parse valid service data correctly', async () => {
|
|
26
|
+
const serviceData = Buffer.from([0, 0, 0, 255, 128, 64, 0, 129, 136, 127, 254, 0, 0, 0, 0, 0, 0, 0]);
|
|
27
|
+
const manufacturerData = Buffer.alloc(0);
|
|
28
|
+
const emitLog = vi.fn();
|
|
29
|
+
const result = await WoSmartLockPro.parseServiceData(serviceData, manufacturerData, emitLog);
|
|
30
|
+
const expected = {
|
|
31
|
+
model: SwitchBotBLEModel.LockPro,
|
|
32
|
+
modelName: SwitchBotBLEModelName.LockPro,
|
|
33
|
+
modelFriendlyName: SwitchBotBLEModelFriendlyName.LockPro,
|
|
34
|
+
battery: 100,
|
|
35
|
+
calibration: true,
|
|
36
|
+
status: 'LOCKED',
|
|
37
|
+
door_open: false,
|
|
38
|
+
update_from_secondary_lock: false,
|
|
39
|
+
double_lock_mode: false,
|
|
40
|
+
unclosed_alarm: false,
|
|
41
|
+
unlocked_alarm: false,
|
|
42
|
+
auto_lock_paused: false,
|
|
43
|
+
night_latch: false,
|
|
44
|
+
};
|
|
45
|
+
expect(result).toEqual(expected);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
describe('validateResponse', () => {
|
|
49
|
+
it('should return SUCCESS for valid response', async () => {
|
|
50
|
+
const res = Buffer.from([0x01, 0x00, 0x00]);
|
|
51
|
+
const result = await WoSmartLockPro.validateResponse(res);
|
|
52
|
+
expect(result).toBe(WoSmartLockPro.Result.SUCCESS);
|
|
53
|
+
});
|
|
54
|
+
it('should return ERROR for invalid response', async () => {
|
|
55
|
+
const res = Buffer.from([0x00, 0x00, 0x00]);
|
|
56
|
+
const result = await WoSmartLockPro.validateResponse(res);
|
|
57
|
+
expect(result).toBe(WoSmartLockPro.Result.ERROR);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
describe('getLockStatus', () => {
|
|
61
|
+
it('should return LOCKED for code 0b0000000', () => {
|
|
62
|
+
const status = WoSmartLockPro.getLockStatus(0b0000000);
|
|
63
|
+
expect(status).toBe('LOCKED');
|
|
64
|
+
});
|
|
65
|
+
it('should return UNKNOWN for unknown code', () => {
|
|
66
|
+
const status = WoSmartLockPro.getLockStatus(0b1111111);
|
|
67
|
+
expect(status).toBe('UNKNOWN');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe('setKey', () => {
|
|
71
|
+
it('should set the key ID and encryption key', async () => {
|
|
72
|
+
await lock.setKey('keyId', 'encryptionKey');
|
|
73
|
+
expect(lock.key_id).toBe('keyId');
|
|
74
|
+
expect(lock.encryption_key).toEqual(Buffer.from('encryptionKey', 'hex'));
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
describe('unlock', () => {
|
|
78
|
+
it('should unlock the lock', async () => {
|
|
79
|
+
jest.spyOn(lock, 'operateLockPro').mockResolvedValue(Buffer.from([0x01]));
|
|
80
|
+
const result = await lock.unlock();
|
|
81
|
+
expect(result).toBe(WoSmartLockPro.Result.SUCCESS);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
describe('lock', () => {
|
|
85
|
+
it('should lock the lock', async () => {
|
|
86
|
+
jest.spyOn(lock, 'operateLockPro').mockResolvedValue(Buffer.from([0x01]));
|
|
87
|
+
const result = await lock.lock();
|
|
88
|
+
expect(result).toBe(WoSmartLockPro.Result.SUCCESS);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
describe('info', () => {
|
|
92
|
+
it('should return lock info', async () => {
|
|
93
|
+
const mockResponse = Buffer.from([0b10000000, 0b00100000]);
|
|
94
|
+
jest.spyOn(lock, 'operateLockPro').mockResolvedValue(mockResponse);
|
|
95
|
+
const info = await lock.info();
|
|
96
|
+
expect(info).toEqual({
|
|
97
|
+
calibration: true,
|
|
98
|
+
status: 'LOCKED',
|
|
99
|
+
door_open: false,
|
|
100
|
+
unclosed_alarm: true,
|
|
101
|
+
unlocked_alarm: false,
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
describe('encrypt', () => {
|
|
106
|
+
it('should encrypt a string', async () => {
|
|
107
|
+
lock.encryption_key = Buffer.from('encryptionKey', 'hex');
|
|
108
|
+
lock.iv = Buffer.from('iv', 'hex');
|
|
109
|
+
const encrypted = await lock.encrypt('test');
|
|
110
|
+
expect(encrypted).toBeDefined();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
describe('decrypt', () => {
|
|
114
|
+
it('should decrypt a buffer', async () => {
|
|
115
|
+
lock.encryption_key = Buffer.from('encryptionKey', 'hex');
|
|
116
|
+
lock.iv = Buffer.from('iv', 'hex');
|
|
117
|
+
const decrypted = await lock.decrypt(Buffer.from('test', 'hex'));
|
|
118
|
+
expect(decrypted).toBeDefined();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
describe('getIv', () => {
|
|
122
|
+
it('should retrieve the IV from the device', async () => {
|
|
123
|
+
const mockResponse = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x01, 0x02]);
|
|
124
|
+
jest.spyOn(lock, 'operateLockPro').mockResolvedValue(mockResponse);
|
|
125
|
+
const iv = await lock.getIv();
|
|
126
|
+
expect(iv).toEqual(Buffer.from([0x01, 0x02]));
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe('encryptedCommand', () => {
|
|
130
|
+
it('should send an encrypted command to the device', async () => {
|
|
131
|
+
jest.spyOn(lock, 'getIv').mockResolvedValue(Buffer.from([0x01, 0x02]));
|
|
132
|
+
jest.spyOn(lock, 'encrypt').mockResolvedValue('encrypted');
|
|
133
|
+
jest.spyOn(lock, 'command').mockResolvedValue(Buffer.from([0x01, 0x00, 0x00, 0x00, 0x01, 0x02]));
|
|
134
|
+
const response = await lock.encryptedCommand('key');
|
|
135
|
+
expect(response).toBeDefined();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
describe('operateLockPro', () => {
|
|
139
|
+
it('should operate the lock with encryption', async () => {
|
|
140
|
+
jest.spyOn(lock, 'encryptedCommand').mockResolvedValue(Buffer.from([0x01]));
|
|
141
|
+
const response = await lock.operateLockPro(WoSmartLockProCommands.LOCK);
|
|
142
|
+
expect(response).toBeDefined();
|
|
143
|
+
});
|
|
144
|
+
it('should operate the lock without encryption', async () => {
|
|
145
|
+
jest.spyOn(lock, 'command').mockResolvedValue(Buffer.from([0x01, 0x00, 0x00, 0x00]));
|
|
146
|
+
const response = await lock.operateLockPro(WoSmartLockProCommands.LOCK, false);
|
|
147
|
+
expect(response).toBeDefined();
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
});
|
|
2
151
|
//# sourceMappingURL=wosmartlockpro.test.js.map
|