@switchbot/homebridge-switchbot 5.0.0-beta.22 → 5.0.0-beta.24
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/dist/platform-matter.d.ts.map +1 -1
- package/dist/platform-matter.js +71 -6
- package/dist/platform-matter.js.map +1 -1
- package/dist/test/devices-matter/baseMatterAccessory.test.d.ts.map +1 -0
- package/dist/{devices-matter → test/devices-matter}/baseMatterAccessory.test.js +1 -1
- package/dist/test/devices-matter/baseMatterAccessory.test.js.map +1 -0
- package/dist/test/helpers/platform-fixtures.d.ts +9 -0
- package/dist/test/helpers/platform-fixtures.d.ts.map +1 -0
- package/dist/test/helpers/platform-fixtures.js +30 -0
- package/dist/test/helpers/platform-fixtures.js.map +1 -0
- package/dist/test/platform-matter.additional.test.d.ts +2 -0
- package/dist/test/platform-matter.additional.test.d.ts.map +1 -0
- package/dist/test/platform-matter.additional.test.js +35 -0
- package/dist/test/platform-matter.additional.test.js.map +1 -0
- package/dist/test/platform-matter.bleparse.test.d.ts +2 -0
- package/dist/test/platform-matter.bleparse.test.d.ts.map +1 -0
- package/dist/test/platform-matter.bleparse.test.js +43 -0
- package/dist/test/platform-matter.bleparse.test.js.map +1 -0
- package/dist/test/platform-matter.cleanup.test.d.ts.map +1 -0
- package/dist/{platform-matter.cleanup.test.js → test/platform-matter.cleanup.test.js} +13 -28
- package/dist/test/platform-matter.cleanup.test.js.map +1 -0
- package/dist/test/platform-matter.keepstale.test.d.ts +2 -0
- package/dist/test/platform-matter.keepstale.test.d.ts.map +1 -0
- package/dist/test/platform-matter.keepstale.test.js +27 -0
- package/dist/test/platform-matter.keepstale.test.js.map +1 -0
- package/dist/test/platform-matter.mapping.test.d.ts.map +1 -0
- package/dist/{platform-matter.mapping.test.js → test/platform-matter.mapping.test.js} +16 -23
- package/dist/test/platform-matter.mapping.test.js.map +1 -0
- package/dist/test/platform-matter.openapi-mapping.test.d.ts +2 -0
- package/dist/test/platform-matter.openapi-mapping.test.d.ts.map +1 -0
- package/dist/test/platform-matter.openapi-mapping.test.js +84 -0
- package/dist/test/platform-matter.openapi-mapping.test.js.map +1 -0
- package/dist/test/platform-matter.test.d.ts.map +1 -0
- package/dist/{platform-matter.test.js → test/platform-matter.test.js} +9 -19
- package/dist/test/platform-matter.test.js.map +1 -0
- package/dist/test/platform-matter.unregister.test.d.ts.map +1 -0
- package/dist/{platform-matter.unregister.test.js → test/platform-matter.unregister.test.js} +4 -11
- package/dist/test/platform-matter.unregister.test.js.map +1 -0
- package/docs/variables/default.html +1 -1
- package/package.json +1 -1
- package/src/platform-matter.ts +64 -6
- package/src/{devices-matter → test/devices-matter}/baseMatterAccessory.test.ts +1 -1
- package/src/test/helpers/platform-fixtures.ts +33 -0
- package/src/test/platform-matter.additional.test.ts +44 -0
- package/src/test/platform-matter.bleparse.test.ts +47 -0
- package/src/{platform-matter.cleanup.test.ts → test/platform-matter.cleanup.test.ts} +14 -29
- package/src/test/platform-matter.keepstale.test.ts +37 -0
- package/src/{platform-matter.mapping.test.ts → test/platform-matter.mapping.test.ts} +22 -25
- package/src/test/platform-matter.openapi-mapping.test.ts +109 -0
- package/src/{platform-matter.test.ts → test/platform-matter.test.ts} +9 -20
- package/src/{platform-matter.unregister.test.ts → test/platform-matter.unregister.test.ts} +4 -13
- package/dist/devices-matter/baseMatterAccessory.test.d.ts.map +0 -1
- package/dist/devices-matter/baseMatterAccessory.test.js.map +0 -1
- package/dist/platform-matter.cleanup.test.d.ts.map +0 -1
- package/dist/platform-matter.cleanup.test.js.map +0 -1
- package/dist/platform-matter.mapping.test.d.ts.map +0 -1
- package/dist/platform-matter.mapping.test.js.map +0 -1
- package/dist/platform-matter.test.d.ts.map +0 -1
- package/dist/platform-matter.test.js.map +0 -1
- package/dist/platform-matter.unregister.test.d.ts.map +0 -1
- package/dist/platform-matter.unregister.test.js.map +0 -1
- /package/dist/{devices-matter → test/devices-matter}/baseMatterAccessory.test.d.ts +0 -0
- /package/dist/{platform-matter.cleanup.test.d.ts → test/platform-matter.cleanup.test.d.ts} +0 -0
- /package/dist/{platform-matter.mapping.test.d.ts → test/platform-matter.mapping.test.d.ts} +0 -0
- /package/dist/{platform-matter.test.d.ts → test/platform-matter.test.d.ts} +0 -0
- /package/dist/{platform-matter.unregister.test.d.ts → test/platform-matter.unregister.test.d.ts} +0 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { SwitchBotMatterPlatform } from '../platform-matter.js';
|
|
3
|
+
import { makeApiStub, makeLogStub } from './helpers/platform-fixtures.js';
|
|
4
|
+
describe('platform-matter BLE advertisement parser', () => {
|
|
5
|
+
it('parses extended serviceData fields correctly', () => {
|
|
6
|
+
const updateAccessoryState = vi.fn();
|
|
7
|
+
const api = makeApiStub({ updateAccessoryState });
|
|
8
|
+
const log = makeLogStub();
|
|
9
|
+
const platform = new SwitchBotMatterPlatform(log, {}, api);
|
|
10
|
+
const dev = { deviceId: 'DEV-TEST' };
|
|
11
|
+
const sd = {
|
|
12
|
+
temp: 22.3,
|
|
13
|
+
humid: 45,
|
|
14
|
+
pm25: 12,
|
|
15
|
+
pm10: 34,
|
|
16
|
+
voc: 120,
|
|
17
|
+
co2: 420,
|
|
18
|
+
motion: 1,
|
|
19
|
+
open: 0,
|
|
20
|
+
leak: 0,
|
|
21
|
+
position: 30,
|
|
22
|
+
fanSpeed: 75,
|
|
23
|
+
battery: 88,
|
|
24
|
+
rgb: '255:128:64',
|
|
25
|
+
};
|
|
26
|
+
const parsed = platform.parseAdvertisementForDevice(dev, sd);
|
|
27
|
+
expect(parsed).toBeTruthy();
|
|
28
|
+
expect(parsed.temperature).toBeCloseTo(22.3);
|
|
29
|
+
expect(parsed.humidity).toBe(45);
|
|
30
|
+
expect(parsed.pm25).toBe(12);
|
|
31
|
+
expect(parsed.pm10).toBe(34);
|
|
32
|
+
expect(parsed.voc).toBe(120);
|
|
33
|
+
expect(parsed.co2).toBe(420);
|
|
34
|
+
expect(parsed.motion).toBeTruthy();
|
|
35
|
+
expect(parsed.contact).toBeDefined();
|
|
36
|
+
expect(parsed.leak).toBeFalsy();
|
|
37
|
+
expect(parsed.position).toBe(30);
|
|
38
|
+
expect(parsed.fanSpeed).toBe(75);
|
|
39
|
+
expect(parsed.battery).toBe(88);
|
|
40
|
+
expect(parsed.color).toEqual({ r: 255, g: 128, b: 64 });
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
//# sourceMappingURL=platform-matter.bleparse.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-matter.bleparse.test.js","sourceRoot":"","sources":["../../src/test/platform-matter.bleparse.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAEjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAA;AAEzE,QAAQ,CAAC,0CAA0C,EAAE,GAAG,EAAE;IACxD,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,oBAAoB,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;QACpC,MAAM,GAAG,GAAQ,WAAW,CAAC,EAAE,oBAAoB,EAAE,CAAC,CAAA;QAEtD,MAAM,GAAG,GAAQ,WAAW,EAAE,CAAA;QAC9B,MAAM,QAAQ,GAAG,IAAI,uBAAuB,CAAC,GAAU,EAAE,EAAS,EAAE,GAAG,CAAC,CAAA;QAExE,MAAM,GAAG,GAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAA;QACzC,MAAM,EAAE,GAAG;YACT,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,EAAE;YACT,IAAI,EAAE,EAAE;YACR,IAAI,EAAE,EAAE;YACR,GAAG,EAAE,GAAG;YACR,GAAG,EAAE,GAAG;YACR,MAAM,EAAE,CAAC;YACT,IAAI,EAAE,CAAC;YACP,IAAI,EAAE,CAAC;YACP,QAAQ,EAAE,EAAE;YACZ,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,EAAE;YACX,GAAG,EAAE,YAAY;SAClB,CAAA;QAED,MAAM,MAAM,GAAI,QAAgB,CAAC,2BAA2B,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;QACrE,MAAM,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,CAAA;QAC3B,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;QAC5C,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAChC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC5B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC5B,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAC5B,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAC5B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,CAAA;QAClC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAA;QACpC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,CAAA;QAC/B,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAChC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAChC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC/B,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-matter.cleanup.test.d.ts","sourceRoot":"","sources":["../../src/test/platform-matter.cleanup.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,23 +1,16 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { SwitchBotMatterPlatform } from '
|
|
3
|
-
import { formatDeviceIdAsMac } from '
|
|
2
|
+
import { SwitchBotMatterPlatform } from '../platform-matter.js';
|
|
3
|
+
import { formatDeviceIdAsMac } from '../utils.js';
|
|
4
|
+
import { makeApiStub, makeLogStub } from './helpers/platform-fixtures.js';
|
|
4
5
|
describe('platform-matter lifecycle cleanup', () => {
|
|
5
6
|
it('clearDeviceResources removes timers, instances and BLE handler entries', async () => {
|
|
6
7
|
// Setup stubbed API and logs
|
|
7
8
|
const handlers = {};
|
|
8
|
-
const api = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
clusterNames: { OnOff: 'OnOff' },
|
|
14
|
-
},
|
|
15
|
-
isMatterAvailable: () => true,
|
|
16
|
-
isMatterEnabled: () => true,
|
|
17
|
-
on: (ev, fn) => { handlers[ev] = fn; },
|
|
18
|
-
_handlers: handlers,
|
|
19
|
-
};
|
|
20
|
-
const log = { info: vi.fn(), debug: vi.fn(), warn: vi.fn(), error: vi.fn(), success: vi.fn() };
|
|
9
|
+
const api = makeApiStub({ registerPlatformAccessories: vi.fn(), unregisterPlatformAccessories: vi.fn(), clusterNames: { OnOff: 'OnOff' } });
|
|
10
|
+
api._handlers = handlers;
|
|
11
|
+
// keep api.on as a single-statement arrow to satisfy lint
|
|
12
|
+
api.on = (ev, fn) => (handlers[ev] = fn);
|
|
13
|
+
const log = makeLogStub();
|
|
21
14
|
const platform = new SwitchBotMatterPlatform(log, {}, api);
|
|
22
15
|
// Insert a fake timer, accessory instance, and BLE handler
|
|
23
16
|
const deviceId = 'AA:BB:CC:11:22:33';
|
|
@@ -39,19 +32,11 @@ describe('platform-matter lifecycle cleanup', () => {
|
|
|
39
32
|
it('shutdown handler clears all timers and handlers when invoked', async () => {
|
|
40
33
|
// Setup stubbed API and logs
|
|
41
34
|
const handlers = {};
|
|
42
|
-
const api = {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
clusterNames: { OnOff: 'OnOff' },
|
|
48
|
-
},
|
|
49
|
-
isMatterAvailable: () => true,
|
|
50
|
-
isMatterEnabled: () => true,
|
|
51
|
-
on: (ev, fn) => { handlers[ev] = fn; },
|
|
52
|
-
_handlers: handlers,
|
|
53
|
-
};
|
|
54
|
-
const log = { info: vi.fn(), debug: vi.fn(), warn: vi.fn(), error: vi.fn(), success: vi.fn() };
|
|
35
|
+
const api = makeApiStub({ registerPlatformAccessories: vi.fn(), unregisterPlatformAccessories: vi.fn(), clusterNames: { OnOff: 'OnOff' } });
|
|
36
|
+
api._handlers = handlers;
|
|
37
|
+
// keep api.on as a single-statement arrow to satisfy lint
|
|
38
|
+
api.on = (ev, fn) => (handlers[ev] = fn);
|
|
39
|
+
const log = makeLogStub();
|
|
55
40
|
const platform = new SwitchBotMatterPlatform(log, {}, api);
|
|
56
41
|
// Add two timers to the platform (using normalized ids)
|
|
57
42
|
const ids = ['devA', 'devB'];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-matter.cleanup.test.js","sourceRoot":"","sources":["../../src/test/platform-matter.cleanup.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-matter.keepstale.test.d.ts","sourceRoot":"","sources":["../../src/test/platform-matter.keepstale.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { SwitchBotMatterPlatform } from '../platform-matter.js';
|
|
3
|
+
import { makeApiStub, makeLogStub } from './helpers/platform-fixtures.js';
|
|
4
|
+
describe('keepStaleAccessories config flag behavior', () => {
|
|
5
|
+
it('keeps previously-registered accessories when options.keepStaleAccessories=true', async () => {
|
|
6
|
+
const unregister = vi.fn();
|
|
7
|
+
const register = vi.fn();
|
|
8
|
+
const api = makeApiStub({ unregisterPlatformAccessories: unregister, registerPlatformAccessories: register });
|
|
9
|
+
const log = makeLogStub();
|
|
10
|
+
// Create platform with keepStaleAccessories = true
|
|
11
|
+
const platform = new SwitchBotMatterPlatform(log, { options: { keepStaleAccessories: true } }, api);
|
|
12
|
+
platform.discoveredDevices = [{ deviceId: 'DEV1', deviceType: 'Plug', deviceName: 'Device 1' }];
|
|
13
|
+
// Insert a stale accessory into matterAccessories
|
|
14
|
+
const staleUuid = api.matter.uuid.generate('stale-device');
|
|
15
|
+
const staleAcc = { uuid: staleUuid, displayName: 'Stale', context: { deviceId: 'STALE_DEVICE' } };
|
|
16
|
+
platform.matterAccessories.set(staleUuid, staleAcc);
|
|
17
|
+
// Mock createAccessoryFromDevice to return a simple accessory for DEV1
|
|
18
|
+
vi.spyOn(platform, 'createAccessoryFromDevice').mockResolvedValue({ displayName: 'Device 1', uuid: 'uuid-DEV1', context: { deviceId: 'DEV1' } });
|
|
19
|
+
// Run registration which includes stale-removal logic
|
|
20
|
+
await platform.registerMatterAccessories();
|
|
21
|
+
// Expect unregister NOT called (we kept stale accessory)
|
|
22
|
+
expect(unregister).not.toHaveBeenCalled();
|
|
23
|
+
// Stale accessory should still be present in matterAccessories
|
|
24
|
+
expect(platform.matterAccessories.get(staleUuid)).toBeDefined();
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
//# sourceMappingURL=platform-matter.keepstale.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-matter.keepstale.test.js","sourceRoot":"","sources":["../../src/test/platform-matter.keepstale.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAEjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAA;AAEzE,QAAQ,CAAC,2CAA2C,EAAE,GAAG,EAAE;IACzD,EAAE,CAAC,gFAAgF,EAAE,KAAK,IAAI,EAAE;QAC9F,MAAM,UAAU,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;QAC1B,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;QACxB,MAAM,GAAG,GAAQ,WAAW,CAAC,EAAE,6BAA6B,EAAE,UAAU,EAAE,2BAA2B,EAAE,QAAQ,EAAE,CAAC,CAAA;QAElH,MAAM,GAAG,GAAQ,WAAW,EAAE,CAAA;QAE9B,mDAAmD;QACnD,MAAM,QAAQ,GAAG,IAAI,uBAAuB,CAAC,GAAU,EAAE,EAAE,OAAO,EAAE,EAAE,oBAAoB,EAAE,IAAI,EAAE,EAAS,EAAE,GAAG,CAAC,CAGhH;QAAC,QAAgB,CAAC,iBAAiB,GAAG,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAA;QAEzG,kDAAkD;QAClD,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAA;QAC1D,MAAM,QAAQ,GAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE,EAAE,CACrG;QAAC,QAAgB,CAAC,iBAAiB,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;QAE7D,uEAAuE;QACvE,EAAE,CAAC,KAAK,CAAC,QAAe,EAAE,2BAA2B,CAAC,CAAC,iBAAiB,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAS,CAAC,CAAA;QAE9J,sDAAsD;QACtD,MAAO,QAAgB,CAAC,yBAAyB,EAAE,CAAA;QAEnD,yDAAyD;QACzD,MAAM,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAA;QAEzC,+DAA+D;QAC/D,MAAM,CAAE,QAAgB,CAAC,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;IAC1E,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-matter.mapping.test.d.ts","sourceRoot":"","sources":["../../src/test/platform-matter.mapping.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { SwitchBotMatterPlatform } from '
|
|
2
|
+
import { SwitchBotMatterPlatform } from '../platform-matter.js';
|
|
3
|
+
import { makeApiStub, makeLogStub } from './helpers/platform-fixtures.js';
|
|
3
4
|
describe('platform-matter mapping helper', () => {
|
|
4
5
|
it('prefers accessory instance update methods for battery and falls back to api.matter.updateAccessoryState', async () => {
|
|
5
6
|
const updateAccessoryState = vi.fn();
|
|
6
|
-
const api = {
|
|
7
|
-
|
|
8
|
-
uuid: { generate: (s) => `uuid-${s}` },
|
|
9
|
-
updateAccessoryState,
|
|
10
|
-
clusterNames: { OnOff: 'OnOff', LevelControl: 'LevelControl', ColorControl: 'ColorControl', PowerSource: 'powerSource' },
|
|
11
|
-
},
|
|
12
|
-
isMatterAvailable: () => true,
|
|
13
|
-
isMatterEnabled: () => true,
|
|
14
|
-
on: () => { },
|
|
15
|
-
};
|
|
16
|
-
const log = { info: vi.fn(), warn: vi.fn(), debug: vi.fn(), error: vi.fn() };
|
|
7
|
+
const api = makeApiStub({ updateAccessoryState, clusterNames: { OnOff: 'OnOff', LevelControl: 'LevelControl', ColorControl: 'ColorControl', PowerSource: 'powerSource' } });
|
|
8
|
+
const log = makeLogStub();
|
|
17
9
|
const platform = new SwitchBotMatterPlatform(log, {}, api);
|
|
18
10
|
// Create a fake accessory instance with updateBatteryPercentage
|
|
19
11
|
const deviceId = 'DEV123';
|
|
@@ -29,22 +21,23 @@ describe('platform-matter mapping helper', () => {
|
|
|
29
21
|
});
|
|
30
22
|
it('handles temperature and humidity synonyms', async () => {
|
|
31
23
|
const updateAccessoryState = vi.fn();
|
|
32
|
-
const api = {
|
|
33
|
-
|
|
34
|
-
uuid: { generate: (s) => `uuid-${s}` },
|
|
35
|
-
updateAccessoryState,
|
|
36
|
-
clusterNames: {},
|
|
37
|
-
},
|
|
38
|
-
isMatterAvailable: () => true,
|
|
39
|
-
isMatterEnabled: () => true,
|
|
40
|
-
on: () => { },
|
|
41
|
-
};
|
|
42
|
-
const log = { info: vi.fn(), warn: vi.fn(), debug: vi.fn(), error: vi.fn() };
|
|
24
|
+
const api = makeApiStub({ updateAccessoryState });
|
|
25
|
+
const log = makeLogStub();
|
|
43
26
|
const platform = new SwitchBotMatterPlatform(log, {}, api);
|
|
44
27
|
const deviceId = 'DEV-TEMP';
|
|
45
28
|
await platform.applyStatusToAccessory('uuid-temp', { deviceId }, { temp: 21.5, humid: 48 });
|
|
46
29
|
// Expect updateAccessoryState to have been called for temperature and humidity
|
|
47
30
|
expect(updateAccessoryState).toHaveBeenCalled();
|
|
48
31
|
});
|
|
32
|
+
it('applies VOC and PM10 mappings when present', async () => {
|
|
33
|
+
const updateAccessoryState = vi.fn();
|
|
34
|
+
const api = makeApiStub({ updateAccessoryState });
|
|
35
|
+
const log = makeLogStub();
|
|
36
|
+
const platform = new SwitchBotMatterPlatform(log, {}, api);
|
|
37
|
+
const deviceId = 'DEV-AQ';
|
|
38
|
+
await platform.applyStatusToAccessory('uuid-aq', { deviceId }, { voc: 123, pm10: 56 });
|
|
39
|
+
// Expect updateAccessoryState (or safeUpdate fallback) to have been called for voc and pm10
|
|
40
|
+
expect(updateAccessoryState).toHaveBeenCalled();
|
|
41
|
+
});
|
|
49
42
|
});
|
|
50
43
|
//# sourceMappingURL=platform-matter.mapping.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-matter.mapping.test.js","sourceRoot":"","sources":["../../src/test/platform-matter.mapping.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-matter.openapi-mapping.test.d.ts","sourceRoot":"","sources":["../../src/test/platform-matter.openapi-mapping.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { SwitchBotMatterPlatform } from '../platform-matter.js';
|
|
3
|
+
import { makeApiStub, makeLogStub } from './helpers/platform-fixtures.js';
|
|
4
|
+
describe('platform-matter OpenAPI -> Matter mapping', () => {
|
|
5
|
+
it('maps light OpenAPI status (on/off, brightness, color, battery) to accessory instance helpers', async () => {
|
|
6
|
+
const api = makeApiStub();
|
|
7
|
+
const log = makeLogStub();
|
|
8
|
+
const platform = new SwitchBotMatterPlatform(log, {}, api);
|
|
9
|
+
const deviceId = 'LIGHT-1';
|
|
10
|
+
const nid = platform.normalizeDeviceId(deviceId);
|
|
11
|
+
const instance = {
|
|
12
|
+
updateOnOffState: vi.fn(),
|
|
13
|
+
updateBrightness: vi.fn(),
|
|
14
|
+
updateHueSaturation: vi.fn(),
|
|
15
|
+
updateBatteryPercentage: vi.fn(),
|
|
16
|
+
};
|
|
17
|
+
platform.accessoryInstances.set(nid, instance);
|
|
18
|
+
const status = { power: true, brightness: 80, color: '255:128:64', battery: 92 };
|
|
19
|
+
await platform.applyStatusToAccessory('uuid-light', { deviceId }, status);
|
|
20
|
+
expect(instance.updateOnOffState).toHaveBeenCalled();
|
|
21
|
+
expect(instance.updateBrightness).toHaveBeenCalled();
|
|
22
|
+
expect(instance.updateHueSaturation).toHaveBeenCalled();
|
|
23
|
+
expect(instance.updateBatteryPercentage).toHaveBeenCalled();
|
|
24
|
+
});
|
|
25
|
+
it('maps MeterPro OpenAPI status (temp, humid, co2, pm25, voc) to accessory instance helpers', async () => {
|
|
26
|
+
const api = makeApiStub();
|
|
27
|
+
const log = makeLogStub();
|
|
28
|
+
const platform = new SwitchBotMatterPlatform(log, {}, api);
|
|
29
|
+
const deviceId = 'METERPRO-1';
|
|
30
|
+
const nid = platform.normalizeDeviceId(deviceId);
|
|
31
|
+
const instance = {
|
|
32
|
+
updateTemperature: vi.fn(),
|
|
33
|
+
updateHumidity: vi.fn(),
|
|
34
|
+
updateCO2: vi.fn(),
|
|
35
|
+
updatePM25: vi.fn(),
|
|
36
|
+
updateVOC: vi.fn(),
|
|
37
|
+
};
|
|
38
|
+
platform.accessoryInstances.set(nid, instance);
|
|
39
|
+
const status = { temp: 21.4, humid: 45, co2: 410, pm25: 12, voc: 85 };
|
|
40
|
+
await platform.applyStatusToAccessory('uuid-meter', { deviceId }, status);
|
|
41
|
+
expect(instance.updateTemperature).toHaveBeenCalled();
|
|
42
|
+
expect(instance.updateHumidity).toHaveBeenCalled();
|
|
43
|
+
expect(instance.updateCO2).toHaveBeenCalled();
|
|
44
|
+
expect(instance.updatePM25).toHaveBeenCalled();
|
|
45
|
+
expect(instance.updateVOC).toHaveBeenCalled();
|
|
46
|
+
});
|
|
47
|
+
it('maps lock OpenAPI status to lock helper', async () => {
|
|
48
|
+
const api = makeApiStub();
|
|
49
|
+
const log = makeLogStub();
|
|
50
|
+
const platform = new SwitchBotMatterPlatform(log, {}, api);
|
|
51
|
+
const deviceId = 'LOCK-1';
|
|
52
|
+
const nid = platform.normalizeDeviceId(deviceId);
|
|
53
|
+
const instance = { updateLockState: vi.fn() };
|
|
54
|
+
platform.accessoryInstances.set(nid, instance);
|
|
55
|
+
const status = { lock: true };
|
|
56
|
+
await platform.applyStatusToAccessory('uuid-lock', { deviceId }, status);
|
|
57
|
+
expect(instance.updateLockState).toHaveBeenCalled();
|
|
58
|
+
});
|
|
59
|
+
it('maps curtain position synonyms to lift position helper', async () => {
|
|
60
|
+
const api = makeApiStub();
|
|
61
|
+
const log = makeLogStub();
|
|
62
|
+
const platform = new SwitchBotMatterPlatform(log, {}, api);
|
|
63
|
+
const deviceId = 'CURTAIN-1';
|
|
64
|
+
const nid = platform.normalizeDeviceId(deviceId);
|
|
65
|
+
const instance = { updateLiftPosition: vi.fn() };
|
|
66
|
+
platform.accessoryInstances.set(nid, instance);
|
|
67
|
+
await platform.applyStatusToAccessory('uuid-cur', { deviceId, deviceType: 'Curtain' }, { position: 25 });
|
|
68
|
+
await platform.applyStatusToAccessory('uuid-cur', { deviceId, deviceType: 'Curtain' }, { slidePosition: 75 });
|
|
69
|
+
expect(instance.updateLiftPosition).toHaveBeenCalled();
|
|
70
|
+
});
|
|
71
|
+
it('maps robot vacuum run state / on to updateRunMode or updateOperationalState', async () => {
|
|
72
|
+
const api = makeApiStub();
|
|
73
|
+
const log = makeLogStub();
|
|
74
|
+
const platform = new SwitchBotMatterPlatform(log, {}, api);
|
|
75
|
+
const deviceId = 'RVC-1';
|
|
76
|
+
const nid = platform.normalizeDeviceId(deviceId);
|
|
77
|
+
const instance = { updateRunMode: vi.fn(), updateOperationalState: vi.fn() };
|
|
78
|
+
platform.accessoryInstances.set(nid, instance);
|
|
79
|
+
await platform.applyStatusToAccessory('uuid-rvc', { deviceId, deviceType: 'K10+' }, { runState: 'cleaning', power: true });
|
|
80
|
+
const calls = (instance.updateRunMode.mock?.calls?.length || 0) + (instance.updateOperationalState.mock?.calls?.length || 0);
|
|
81
|
+
expect(calls).toBeGreaterThan(0);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=platform-matter.openapi-mapping.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-matter.openapi-mapping.test.js","sourceRoot":"","sources":["../../src/test/platform-matter.openapi-mapping.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-matter.test.d.ts","sourceRoot":"","sources":["../../src/test/platform-matter.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,26 +1,16 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { SwitchBotMatterPlatform } from '
|
|
3
|
-
import { PLATFORM_NAME, PLUGIN_NAME } from '
|
|
2
|
+
import { SwitchBotMatterPlatform } from '../platform-matter.js';
|
|
3
|
+
import { PLATFORM_NAME, PLUGIN_NAME } from '../settings.js';
|
|
4
|
+
import { makeApiStub, makeLogStub } from './helpers/platform-fixtures.js';
|
|
4
5
|
describe('platform-matter discovered devices', () => {
|
|
5
6
|
it('uses discovered devices and registers them (platform + robotic)', async () => {
|
|
6
7
|
const mockRegister = vi.fn();
|
|
7
|
-
const api = {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
},
|
|
14
|
-
isMatterAvailable: () => true,
|
|
15
|
-
isMatterEnabled: () => true,
|
|
16
|
-
on: () => { },
|
|
17
|
-
};
|
|
18
|
-
const log = {
|
|
19
|
-
info: vi.fn(),
|
|
20
|
-
warn: vi.fn(),
|
|
21
|
-
debug: vi.fn(),
|
|
22
|
-
error: vi.fn(),
|
|
23
|
-
};
|
|
8
|
+
const api = makeApiStub({
|
|
9
|
+
registerPlatformAccessories: mockRegister,
|
|
10
|
+
clusterNames: { OnOff: 'OnOff', LevelControl: 'LevelControl', ColorControl: 'ColorControl' },
|
|
11
|
+
deviceTypes: { RoboticVacuumCleaner: 'rvc' },
|
|
12
|
+
});
|
|
13
|
+
const log = makeLogStub();
|
|
24
14
|
const config = {};
|
|
25
15
|
const platform = new SwitchBotMatterPlatform(log, config, api);
|
|
26
16
|
platform.discoveredDevices = [
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-matter.test.js","sourceRoot":"","sources":["../../src/test/platform-matter.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-matter.unregister.test.d.ts","sourceRoot":"","sources":["../../src/test/platform-matter.unregister.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { SwitchBotMatterPlatform } from '
|
|
2
|
+
import { SwitchBotMatterPlatform } from '../platform-matter.js';
|
|
3
|
+
import { makeApiStub, makeLogStub } from './helpers/platform-fixtures.js';
|
|
3
4
|
describe('removeDisabledAccessories and unregister edge cases', () => {
|
|
4
5
|
it('clears resources and unregisters accessory even with invalid timer and non-MAC deviceId', async () => {
|
|
5
6
|
// Prepare API stub
|
|
6
7
|
const unregister = vi.fn();
|
|
7
|
-
const api = {
|
|
8
|
-
|
|
9
|
-
uuid: { generate: (s) => `uuid-${s}` },
|
|
10
|
-
unregisterPlatformAccessories: unregister,
|
|
11
|
-
},
|
|
12
|
-
isMatterAvailable: () => true,
|
|
13
|
-
isMatterEnabled: () => true,
|
|
14
|
-
on: () => { },
|
|
15
|
-
};
|
|
16
|
-
const log = { info: vi.fn(), warn: vi.fn(), debug: vi.fn(), error: vi.fn(), success: vi.fn() };
|
|
8
|
+
const api = makeApiStub({ unregisterPlatformAccessories: unregister });
|
|
9
|
+
const log = makeLogStub();
|
|
17
10
|
const platform = new SwitchBotMatterPlatform(log, { enableOnOffLight: false }, api);
|
|
18
11
|
// Build a fake serialized accessory matching the generated UUID for OnOff Light
|
|
19
12
|
const uuid = api.matter.uuid.generate('matter-onoff-light');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-matter.unregister.test.js","sourceRoot":"","sources":["../../src/test/platform-matter.unregister.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAEjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAA;AAEzE,QAAQ,CAAC,qDAAqD,EAAE,GAAG,EAAE;IACnE,EAAE,CAAC,yFAAyF,EAAE,KAAK,IAAI,EAAE;QACvG,mBAAmB;QACnB,MAAM,UAAU,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;QAC1B,MAAM,GAAG,GAAQ,WAAW,CAAC,EAAE,6BAA6B,EAAE,UAAU,EAAE,CAAC,CAAA;QAC3E,MAAM,GAAG,GAAQ,WAAW,EAAE,CAAA;QAC9B,MAAM,QAAQ,GAAG,IAAI,uBAAuB,CAAC,GAAU,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAS,EAAE,GAAG,CAAC,CAAA;QAEjG,gFAAgF;QAChF,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAA;QAC3D,MAAM,SAAS,GAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,CAAA;QAE/F,wEAAwE;QACxE,MAAM,GAAG,GAAI,QAAgB,CAAC,iBAAiB,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAC1E;QAAC,QAAgB,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,IAAW,CAAC,CACrD;QAAC,QAAgB,CAAC,kBAAkB,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAG9D;QAAC,QAAgB,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QAEzD,8BAA8B;QAC9B,MAAM,QAAQ,GAAG,EAAE,CAAC,KAAK,CAAC,QAAe,EAAE,sBAAsB,CAAC,CAAA;QAElE,0CAA0C;QAC1C,MAAO,QAAgB,CAAC,yBAAyB,EAAE,CAAA;QAEnD,6DAA6D;QAC7D,MAAM,CAAC,UAAU,CAAC,CAAC,gBAAgB,EAAE,CAAA;QACrC,MAAM,CAAE,QAAgB,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,CAAA;QAErE,2EAA2E;QAC3E,MAAM,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IACnE,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>default | @switchbot/homebridge-switchbot</title><meta name="description" content="Documentation for @switchbot/homebridge-switchbot"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">@switchbot/homebridge-switchbot</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">default</a></li></ul><h1>Variable default</h1></div><div class="tsd-signature"><span class="tsd-kind-variable">default</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span> <span class="tsd-signature-symbol">=></span> <span class="tsd-signature-type">void</span></div><div class="tsd-type-declaration"><h4>Type Declaration</h4><ul class="tsd-parameters"><li class="tsd-parameter-signature"><ul class="tsd-signatures"><li class="tsd-signature" id="__type"><span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">void</span></li><li class="tsd-description"><div class="tsd-parameters"><h4 class="tsd-parameters-title">Parameters</h4><ul class="tsd-parameter-list"><li><span><span class="tsd-kind-parameter">api</span>: <span class="tsd-signature-type">API</span></span></li></ul></div><h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4></li></ul></li></ul></div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/OpenWonderLabs/homebridge-switchbot/blob/
|
|
1
|
+
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>default | @switchbot/homebridge-switchbot</title><meta name="description" content="Documentation for @switchbot/homebridge-switchbot"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">@switchbot/homebridge-switchbot</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">default</a></li></ul><h1>Variable default</h1></div><div class="tsd-signature"><span class="tsd-kind-variable">default</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span> <span class="tsd-signature-symbol">=></span> <span class="tsd-signature-type">void</span></div><div class="tsd-type-declaration"><h4>Type Declaration</h4><ul class="tsd-parameters"><li class="tsd-parameter-signature"><ul class="tsd-signatures"><li class="tsd-signature" id="__type"><span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">void</span></li><li class="tsd-description"><div class="tsd-parameters"><h4 class="tsd-parameters-title">Parameters</h4><ul class="tsd-parameter-list"><li><span><span class="tsd-kind-parameter">api</span>: <span class="tsd-signature-type">API</span></span></li></ul></div><h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4></li></ul></li></ul></div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/OpenWonderLabs/homebridge-switchbot/blob/01dadecbae96cbcec5c8d3103de61e6cd1c65274/src/index.ts#L13">index.ts:13</a></li></ul></aside></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">@switchbot/homebridge-switchbot</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer></footer><div class="overlay"></div></body></html>
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@switchbot/homebridge-switchbot",
|
|
3
3
|
"displayName": "SwitchBot",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "5.0.0-beta.
|
|
5
|
+
"version": "5.0.0-beta.24",
|
|
6
6
|
"description": "The SwitchBot plugin allows you to access your SwitchBot device(s) from HomeKit.",
|
|
7
7
|
"author": "SwitchBot <support@wondertechlabs.com> (https://github.com/SwitchBot)",
|
|
8
8
|
"contributors": [
|
package/src/platform-matter.ts
CHANGED
|
@@ -660,6 +660,12 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
660
660
|
// First try model-specific / normalized parsing of BLE advertisement
|
|
661
661
|
try {
|
|
662
662
|
const parsed = this.parseAdvertisementForDevice(dev, serviceData)
|
|
663
|
+
try {
|
|
664
|
+
const _p = JSON.stringify(parsed)
|
|
665
|
+
this.debugLog(`BLE advertisement parsed for ${dev.deviceId}: ${_p}`)
|
|
666
|
+
} catch (e) {
|
|
667
|
+
this.debugLog(`BLE advertisement parsed for ${dev.deviceId}: [unstringifiable parse result]`)
|
|
668
|
+
}
|
|
663
669
|
if (parsed) {
|
|
664
670
|
// Power
|
|
665
671
|
if (parsed.power !== undefined) {
|
|
@@ -821,11 +827,17 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
821
827
|
}
|
|
822
828
|
try {
|
|
823
829
|
const { response, statusCode } = await this.switchBotAPI.getDeviceStatus(dev.deviceId, this.config.credentials?.token, this.config.credentials?.secret)
|
|
830
|
+
const respAny: any = response
|
|
831
|
+
const body = respAny?.body ?? respAny
|
|
832
|
+
try {
|
|
833
|
+
const s = JSON.stringify(body)
|
|
834
|
+
this.debugLog(`OpenAPI getDeviceStatus for ${dev.deviceId} returned statusCode=${statusCode} body=${s}`)
|
|
835
|
+
} catch (e) {
|
|
836
|
+
this.debugLog(`OpenAPI getDeviceStatus for ${dev.deviceId} returned statusCode=${statusCode} (body not stringifiable)`)
|
|
837
|
+
}
|
|
824
838
|
if (!(statusCode === 100 || statusCode === 200)) {
|
|
825
839
|
return
|
|
826
840
|
}
|
|
827
|
-
const respAny: any = response
|
|
828
|
-
const body = respAny?.body ?? respAny
|
|
829
841
|
const status = body?.status ?? body
|
|
830
842
|
|
|
831
843
|
// Use centralized mapper which prefers accessory instance update helpers
|
|
@@ -854,9 +866,15 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
854
866
|
;(async () => {
|
|
855
867
|
try {
|
|
856
868
|
const { response, statusCode } = await this.switchBotAPI!.getDeviceStatus(dev.deviceId, this.config.credentials?.token, this.config.credentials?.secret)
|
|
869
|
+
const respAny: any = response
|
|
870
|
+
const body = respAny?.body ?? respAny
|
|
871
|
+
try {
|
|
872
|
+
const s = JSON.stringify(body)
|
|
873
|
+
this.debugLog(`Initial OpenAPI refresh for ${dev.deviceId} returned statusCode=${statusCode} body=${s}`)
|
|
874
|
+
} catch (e) {
|
|
875
|
+
this.debugLog(`Initial OpenAPI refresh for ${dev.deviceId} returned statusCode=${statusCode} (body not stringifiable)`)
|
|
876
|
+
}
|
|
857
877
|
if (statusCode === 100 || statusCode === 200) {
|
|
858
|
-
const respAny: any = response
|
|
859
|
-
const body = respAny?.body ?? respAny
|
|
860
878
|
const status = body?.status ?? body
|
|
861
879
|
await this.applyStatusToAccessory(uuid, dev, status)
|
|
862
880
|
}
|
|
@@ -868,9 +886,15 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
868
886
|
const timer = setInterval(async () => {
|
|
869
887
|
try {
|
|
870
888
|
const { response, statusCode } = await this.switchBotAPI!.getDeviceStatus(dev.deviceId, this.config.credentials?.token, this.config.credentials?.secret)
|
|
889
|
+
const respAny: any = response
|
|
890
|
+
const body = respAny?.body ?? respAny
|
|
891
|
+
try {
|
|
892
|
+
const s = JSON.stringify(body)
|
|
893
|
+
this.debugLog(`Periodic OpenAPI refresh for ${dev.deviceId} returned statusCode=${statusCode} body=${s}`)
|
|
894
|
+
} catch (e) {
|
|
895
|
+
this.debugLog(`Periodic OpenAPI refresh for ${dev.deviceId} returned statusCode=${statusCode} (body not stringifiable)`)
|
|
896
|
+
}
|
|
871
897
|
if (statusCode === 100 || statusCode === 200) {
|
|
872
|
-
const respAny: any = response
|
|
873
|
-
const body = respAny?.body ?? respAny
|
|
874
898
|
const status = body?.status ?? body
|
|
875
899
|
await this.applyStatusToAccessory(uuid, dev, status)
|
|
876
900
|
}
|
|
@@ -1125,6 +1149,40 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
1125
1149
|
await safeUpdate(this.api.matter.clusterNames.OnOff, { onOff: on }, 'updateOnOffState')
|
|
1126
1150
|
}
|
|
1127
1151
|
|
|
1152
|
+
// Robot vacuum: some OpenAPI responses use 'runState' or similar textual
|
|
1153
|
+
// fields to indicate cleaning/mapping/idle. Map common textual values to
|
|
1154
|
+
// the numeric run mode values expected by the RoboticVacuumAccessory and
|
|
1155
|
+
// prefer calling accessory helpers when present.
|
|
1156
|
+
if (status?.runState !== undefined || status?.run_state !== undefined || status?.run !== undefined) {
|
|
1157
|
+
try {
|
|
1158
|
+
const raw = status?.runState ?? status?.run_state ?? status?.run
|
|
1159
|
+
let mode: number | undefined
|
|
1160
|
+
if (typeof raw === 'number') {
|
|
1161
|
+
mode = Number(raw)
|
|
1162
|
+
} else if (typeof raw === 'string') {
|
|
1163
|
+
const s = raw.toLowerCase()
|
|
1164
|
+
if (s.includes('clean')) {
|
|
1165
|
+
mode = 1 // Cleaning
|
|
1166
|
+
} else if (s.includes('map')) {
|
|
1167
|
+
mode = 2 // Mapping
|
|
1168
|
+
} else if (s.includes('idle') || s.includes('stop') || s.includes('dock') || s.includes('charge') || s.includes('docked')) {
|
|
1169
|
+
mode = 0 // Idle
|
|
1170
|
+
} else {
|
|
1171
|
+
const n = Number(raw)
|
|
1172
|
+
if (!Number.isNaN(n)) {
|
|
1173
|
+
mode = n
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
if (mode !== undefined) {
|
|
1179
|
+
await safeUpdate('rvcRunMode', { currentMode: Number(mode) }, 'updateRunMode')
|
|
1180
|
+
}
|
|
1181
|
+
} catch (e: any) {
|
|
1182
|
+
this.debugLog(`Failed to apply runState for ${dev.deviceId}: ${e?.message ?? e}`)
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1128
1186
|
// Brightness
|
|
1129
1187
|
if (status?.brightness !== undefined) {
|
|
1130
1188
|
const level = Math.round((Number(status.brightness) / 100) * 254)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest'
|
|
2
2
|
|
|
3
|
-
import { BaseMatterAccessory } from '
|
|
3
|
+
import { BaseMatterAccessory } from '../../devices-matter/BaseMatterAccessory.js'
|
|
4
4
|
|
|
5
5
|
// Minimal concrete subclass for testing
|
|
6
6
|
class TestAccessory extends BaseMatterAccessory {
|