matterbridge-test 1.3.0 → 2.0.0-dev-20251026-dbfaf33
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/CHANGELOG.md +13 -0
- package/dist/{platform.js → module.js} +11 -8
- package/npm-shrinkwrap.json +3 -3
- package/package.json +3 -3
- package/dist/index.js +0 -4
- package/dist/jestHelpers.js +0 -231
package/CHANGELOG.md
CHANGED
|
@@ -23,6 +23,19 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
23
23
|
<img src="bmc-button.svg" alt="Buy me a coffee" width="120">
|
|
24
24
|
</a>
|
|
25
25
|
|
|
26
|
+
## [2.0.0] - 2025-10-24
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- [package]: Bumped platform to v. 2.0.0.
|
|
31
|
+
- [package]: Updated dependencies.
|
|
32
|
+
- [package]: Bumped package to automator v. 2.0.9.
|
|
33
|
+
- [jest]: Updated jestHelpers to v. 1.0.9.
|
|
34
|
+
|
|
35
|
+
<a href="https://www.buymeacoffee.com/luligugithub">
|
|
36
|
+
<img src="bmc-button.svg" alt="Buy me a coffee" width="80">
|
|
37
|
+
</a>
|
|
38
|
+
|
|
26
39
|
## [1.3.0] - 2025-10-15
|
|
27
40
|
|
|
28
41
|
### Changed
|
|
@@ -2,6 +2,9 @@ import { MatterbridgeDynamicPlatform, bridgedNode, electricalSensor, onOffSwitch
|
|
|
2
2
|
import { isValidString, waiter } from 'matterbridge/utils';
|
|
3
3
|
import { CYAN, er, nf } from 'matterbridge/logger';
|
|
4
4
|
import { OnOffCluster, ElectricalPowerMeasurementCluster, ElectricalEnergyMeasurementCluster, ModeSelectCluster, PowerSource, BridgedDeviceBasicInformationCluster, } from 'matterbridge/matter/clusters';
|
|
5
|
+
export default function initializePlugin(matterbridge, log, config) {
|
|
6
|
+
return new TestPlatform(matterbridge, log, config);
|
|
7
|
+
}
|
|
5
8
|
export class TestPlatform extends MatterbridgeDynamicPlatform {
|
|
6
9
|
config;
|
|
7
10
|
interval;
|
|
@@ -179,6 +182,14 @@ export class TestPlatform extends MatterbridgeDynamicPlatform {
|
|
|
179
182
|
this.log.info(`- device ${device.deviceName} with serial ${device.serialNumber}`);
|
|
180
183
|
}
|
|
181
184
|
}
|
|
185
|
+
addPowerSource(device, type) {
|
|
186
|
+
if (type === 'wired')
|
|
187
|
+
device.createDefaultPowerSourceWiredClusterServer(PowerSource.WiredCurrentType.Ac);
|
|
188
|
+
else if (type === 'replaceable')
|
|
189
|
+
device.createDefaultPowerSourceReplaceableBatteryClusterServer(100);
|
|
190
|
+
else if (type === 'rechargeable')
|
|
191
|
+
device.createDefaultPowerSourceRechargeableBatteryClusterServer(100);
|
|
192
|
+
}
|
|
182
193
|
addElectricalMeasurements(device) {
|
|
183
194
|
device.createDefaultPowerTopologyClusterServer();
|
|
184
195
|
device.createDefaultElectricalPowerMeasurementClusterServer(220 * 1000, 2.5 * 1000, 220 * 2.5 * 1000, 50 * 1000);
|
|
@@ -190,14 +201,6 @@ export class TestPlatform extends MatterbridgeDynamicPlatform {
|
|
|
190
201
|
{ label: 'Led OFF', mode: 2, semanticTags: [] },
|
|
191
202
|
], 1, 1);
|
|
192
203
|
}
|
|
193
|
-
addPowerSource(device, type) {
|
|
194
|
-
if (type === 'wired')
|
|
195
|
-
device.createDefaultPowerSourceWiredClusterServer(PowerSource.WiredCurrentType.Ac);
|
|
196
|
-
else if (type === 'replaceable')
|
|
197
|
-
device.createDefaultPowerSourceReplaceableBatteryClusterServer(100);
|
|
198
|
-
else if (type === 'rechargeable')
|
|
199
|
-
device.createDefaultPowerSourceRechargeableBatteryClusterServer(100);
|
|
200
|
-
}
|
|
201
204
|
async onConfigure() {
|
|
202
205
|
await super.onConfigure();
|
|
203
206
|
this.log.info('onConfigure called');
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge-test",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-dev-20251026-dbfaf33",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "matterbridge-test",
|
|
9
|
-
"version": "
|
|
9
|
+
"version": "2.0.0-dev-20251026-dbfaf33",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"node-ansi-logger": "3.1.1",
|
|
13
13
|
"node-persist-manager": "2.0.0"
|
|
14
14
|
},
|
|
15
15
|
"engines": {
|
|
16
|
-
"node": ">=
|
|
16
|
+
"node": ">=20.0.0 <21.0.0 || >=22.0.0 <23.0.0 || >=24.0.0 <25.0.0"
|
|
17
17
|
},
|
|
18
18
|
"funding": {
|
|
19
19
|
"type": "buymeacoffee",
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge-test",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-dev-20251026-dbfaf33",
|
|
4
4
|
"description": "Matterbridge test plugin",
|
|
5
5
|
"author": "https://github.com/Luligu",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"homepage": "https://www.npmjs.com/package/matterbridge-test",
|
|
8
8
|
"type": "module",
|
|
9
|
-
"main": "dist/
|
|
9
|
+
"main": "dist/module.js",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
12
12
|
"url": "git+https://github.com/Luligu/matterbridge-test.git"
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"shelly"
|
|
32
32
|
],
|
|
33
33
|
"engines": {
|
|
34
|
-
"node": ">=
|
|
34
|
+
"node": ">=20.0.0 <21.0.0 || >=22.0.0 <23.0.0 || >=24.0.0 <25.0.0"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"node-ansi-logger": "3.1.1",
|
package/dist/index.js
DELETED
package/dist/jestHelpers.js
DELETED
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
import { rmSync } from 'node:fs';
|
|
2
|
-
import { inspect } from 'node:util';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { jest } from '@jest/globals';
|
|
5
|
-
import { DeviceTypeId, Endpoint, Environment, MdnsService, ServerNode, ServerNodeStore, VendorId, LogFormat as MatterLogFormat, LogLevel as MatterLogLevel, Lifecycle, } from 'matterbridge/matter';
|
|
6
|
-
import { RootEndpoint, AggregatorEndpoint } from 'matterbridge/matter/endpoints';
|
|
7
|
-
import { AnsiLogger } from 'matterbridge/logger';
|
|
8
|
-
export let loggerLogSpy;
|
|
9
|
-
export let consoleLogSpy;
|
|
10
|
-
export let consoleDebugSpy;
|
|
11
|
-
export let consoleInfoSpy;
|
|
12
|
-
export let consoleWarnSpy;
|
|
13
|
-
export let consoleErrorSpy;
|
|
14
|
-
export function setupTest(name, debug = false) {
|
|
15
|
-
expect(name).toBeDefined();
|
|
16
|
-
expect(typeof name).toBe('string');
|
|
17
|
-
expect(name.length).toBeGreaterThanOrEqual(4);
|
|
18
|
-
rmSync(path.join('jest', name), { recursive: true, force: true });
|
|
19
|
-
if (debug) {
|
|
20
|
-
loggerLogSpy = jest.spyOn(AnsiLogger.prototype, 'log');
|
|
21
|
-
consoleLogSpy = jest.spyOn(console, 'log');
|
|
22
|
-
consoleDebugSpy = jest.spyOn(console, 'debug');
|
|
23
|
-
consoleInfoSpy = jest.spyOn(console, 'info');
|
|
24
|
-
consoleWarnSpy = jest.spyOn(console, 'warn');
|
|
25
|
-
consoleErrorSpy = jest.spyOn(console, 'error');
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
loggerLogSpy = jest.spyOn(AnsiLogger.prototype, 'log').mockImplementation(() => { });
|
|
29
|
-
consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
30
|
-
consoleDebugSpy = jest.spyOn(console, 'debug').mockImplementation(() => { });
|
|
31
|
-
consoleInfoSpy = jest.spyOn(console, 'info').mockImplementation(() => { });
|
|
32
|
-
consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => { });
|
|
33
|
-
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
export function setDebug(debug) {
|
|
37
|
-
if (debug) {
|
|
38
|
-
loggerLogSpy.mockRestore();
|
|
39
|
-
consoleLogSpy.mockRestore();
|
|
40
|
-
consoleDebugSpy.mockRestore();
|
|
41
|
-
consoleInfoSpy.mockRestore();
|
|
42
|
-
consoleWarnSpy.mockRestore();
|
|
43
|
-
consoleErrorSpy.mockRestore();
|
|
44
|
-
loggerLogSpy = jest.spyOn(AnsiLogger.prototype, 'log');
|
|
45
|
-
consoleLogSpy = jest.spyOn(console, 'log');
|
|
46
|
-
consoleDebugSpy = jest.spyOn(console, 'debug');
|
|
47
|
-
consoleInfoSpy = jest.spyOn(console, 'info');
|
|
48
|
-
consoleWarnSpy = jest.spyOn(console, 'warn');
|
|
49
|
-
consoleErrorSpy = jest.spyOn(console, 'error');
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
loggerLogSpy = jest.spyOn(AnsiLogger.prototype, 'log').mockImplementation(() => { });
|
|
53
|
-
consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
54
|
-
consoleDebugSpy = jest.spyOn(console, 'debug').mockImplementation(() => { });
|
|
55
|
-
consoleInfoSpy = jest.spyOn(console, 'info').mockImplementation(() => { });
|
|
56
|
-
consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => { });
|
|
57
|
-
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
export function createTestEnvironment(homeDir) {
|
|
61
|
-
expect(homeDir).toBeDefined();
|
|
62
|
-
expect(typeof homeDir).toBe('string');
|
|
63
|
-
expect(homeDir.length).toBeGreaterThanOrEqual(4);
|
|
64
|
-
rmSync(homeDir, { recursive: true, force: true });
|
|
65
|
-
const environment = Environment.default;
|
|
66
|
-
environment.vars.set('log.level', MatterLogLevel.DEBUG);
|
|
67
|
-
environment.vars.set('log.format', MatterLogFormat.ANSI);
|
|
68
|
-
environment.vars.set('path.root', homeDir);
|
|
69
|
-
environment.vars.set('runtime.signals', false);
|
|
70
|
-
environment.vars.set('runtime.exitcode', false);
|
|
71
|
-
return environment;
|
|
72
|
-
}
|
|
73
|
-
export async function flushAsync(ticks = 3, microTurns = 10, pause = 100) {
|
|
74
|
-
for (let i = 0; i < ticks; i++)
|
|
75
|
-
await new Promise((resolve) => setImmediate(resolve));
|
|
76
|
-
for (let i = 0; i < microTurns; i++)
|
|
77
|
-
await Promise.resolve();
|
|
78
|
-
if (pause)
|
|
79
|
-
await new Promise((resolve) => setTimeout(resolve, pause));
|
|
80
|
-
}
|
|
81
|
-
export async function flushAllEndpointNumberPersistence(targetServer, rounds = 2) {
|
|
82
|
-
const nodeStore = targetServer.env.get(ServerNodeStore);
|
|
83
|
-
for (let i = 0; i < rounds; i++) {
|
|
84
|
-
await new Promise((resolve) => setImmediate(resolve));
|
|
85
|
-
await nodeStore.endpointStores.close();
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
function collectAllEndpoints(root) {
|
|
89
|
-
const list = [];
|
|
90
|
-
const walk = (ep) => {
|
|
91
|
-
list.push(ep);
|
|
92
|
-
if (ep.parts) {
|
|
93
|
-
for (const child of ep.parts) {
|
|
94
|
-
walk(child);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
walk(root);
|
|
99
|
-
return list;
|
|
100
|
-
}
|
|
101
|
-
export async function assertAllEndpointNumbersPersisted(targetServer) {
|
|
102
|
-
const nodeStore = targetServer.env.get(ServerNodeStore);
|
|
103
|
-
await nodeStore.endpointStores.close();
|
|
104
|
-
const all = collectAllEndpoints(targetServer);
|
|
105
|
-
for (const ep of all) {
|
|
106
|
-
const store = nodeStore.storeForEndpoint(ep);
|
|
107
|
-
if (ep.maybeNumber === 0) {
|
|
108
|
-
expect(store.number ?? 0).toBe(0);
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
expect(store.number).toBeGreaterThan(0);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return all.length;
|
|
115
|
-
}
|
|
116
|
-
export async function startServerNode(name, port) {
|
|
117
|
-
const server = await ServerNode.create({
|
|
118
|
-
id: name + 'ServerNode',
|
|
119
|
-
productDescription: {
|
|
120
|
-
name: name + 'ServerNode',
|
|
121
|
-
deviceType: DeviceTypeId(RootEndpoint.deviceType),
|
|
122
|
-
vendorId: VendorId(0xfff1),
|
|
123
|
-
productId: 0x8000,
|
|
124
|
-
},
|
|
125
|
-
basicInformation: {
|
|
126
|
-
vendorId: VendorId(0xfff1),
|
|
127
|
-
vendorName: 'Matterbridge',
|
|
128
|
-
productId: 0x8000,
|
|
129
|
-
productName: 'Matterbridge ' + name,
|
|
130
|
-
nodeLabel: name + 'ServerNode',
|
|
131
|
-
hardwareVersion: 1,
|
|
132
|
-
softwareVersion: 1,
|
|
133
|
-
reachable: true,
|
|
134
|
-
},
|
|
135
|
-
network: {
|
|
136
|
-
port,
|
|
137
|
-
},
|
|
138
|
-
});
|
|
139
|
-
expect(server).toBeDefined();
|
|
140
|
-
expect(server.lifecycle.isReady).toBeTruthy();
|
|
141
|
-
const aggregator = new Endpoint(AggregatorEndpoint, {
|
|
142
|
-
id: name + 'AggregatorNode',
|
|
143
|
-
});
|
|
144
|
-
expect(aggregator).toBeDefined();
|
|
145
|
-
await server.add(aggregator);
|
|
146
|
-
expect(server.parts.has(aggregator.id)).toBeTruthy();
|
|
147
|
-
expect(server.parts.has(aggregator)).toBeTruthy();
|
|
148
|
-
expect(aggregator.lifecycle.isReady).toBeTruthy();
|
|
149
|
-
expect(server.lifecycle.isOnline).toBeFalsy();
|
|
150
|
-
await new Promise((resolve) => {
|
|
151
|
-
server.lifecycle.online.on(async () => {
|
|
152
|
-
resolve();
|
|
153
|
-
});
|
|
154
|
-
server.start();
|
|
155
|
-
});
|
|
156
|
-
expect(server.lifecycle.isReady).toBeTruthy();
|
|
157
|
-
expect(server.lifecycle.isOnline).toBeTruthy();
|
|
158
|
-
expect(server.lifecycle.isCommissioned).toBeFalsy();
|
|
159
|
-
expect(server.lifecycle.isPartsReady).toBeTruthy();
|
|
160
|
-
expect(server.lifecycle.hasId).toBeTruthy();
|
|
161
|
-
expect(server.lifecycle.hasNumber).toBeTruthy();
|
|
162
|
-
expect(aggregator.lifecycle.isReady).toBeTruthy();
|
|
163
|
-
expect(aggregator.lifecycle.isInstalled).toBeTruthy();
|
|
164
|
-
expect(aggregator.lifecycle.isPartsReady).toBeTruthy();
|
|
165
|
-
expect(aggregator.lifecycle.hasId).toBeTruthy();
|
|
166
|
-
expect(aggregator.lifecycle.hasNumber).toBeTruthy();
|
|
167
|
-
await flushAsync(undefined, undefined, 200);
|
|
168
|
-
return [server, aggregator];
|
|
169
|
-
}
|
|
170
|
-
export async function stopServerNode(server) {
|
|
171
|
-
await flushAllEndpointNumberPersistence(server);
|
|
172
|
-
await assertAllEndpointNumbersPersisted(server);
|
|
173
|
-
expect(server).toBeDefined();
|
|
174
|
-
expect(server.lifecycle.isReady).toBeTruthy();
|
|
175
|
-
expect(server.lifecycle.isOnline).toBeTruthy();
|
|
176
|
-
await server.close();
|
|
177
|
-
expect(server.lifecycle.isReady).toBeTruthy();
|
|
178
|
-
expect(server.lifecycle.isOnline).toBeFalsy();
|
|
179
|
-
await server.env.get(MdnsService)[Symbol.asyncDispose]();
|
|
180
|
-
await flushAsync(undefined, undefined, 200);
|
|
181
|
-
}
|
|
182
|
-
export async function addDevice(owner, device, pause = 10) {
|
|
183
|
-
expect(owner).toBeDefined();
|
|
184
|
-
expect(device).toBeDefined();
|
|
185
|
-
expect(owner.lifecycle.isReady).toBeTruthy();
|
|
186
|
-
expect(owner.construction.status).toBe(Lifecycle.Status.Active);
|
|
187
|
-
expect(owner.lifecycle.isPartsReady).toBeTruthy();
|
|
188
|
-
try {
|
|
189
|
-
await owner.add(device);
|
|
190
|
-
}
|
|
191
|
-
catch (error) {
|
|
192
|
-
const errorMessage = error instanceof Error ? error.message : error;
|
|
193
|
-
const errorInspect = inspect(error, { depth: 10 });
|
|
194
|
-
console.error(`Error adding device ${device.maybeId}.${device.maybeNumber}: ${errorMessage}\nstack: ${errorInspect}`);
|
|
195
|
-
return false;
|
|
196
|
-
}
|
|
197
|
-
expect(owner.parts.has(device)).toBeTruthy();
|
|
198
|
-
expect(owner.lifecycle.isPartsReady).toBeTruthy();
|
|
199
|
-
expect(device.lifecycle.isReady).toBeTruthy();
|
|
200
|
-
expect(device.lifecycle.isInstalled).toBeTruthy();
|
|
201
|
-
expect(device.lifecycle.hasId).toBeTruthy();
|
|
202
|
-
expect(device.lifecycle.hasNumber).toBeTruthy();
|
|
203
|
-
expect(device.construction.status).toBe(Lifecycle.Status.Active);
|
|
204
|
-
await flushAsync(1, 1, pause);
|
|
205
|
-
return true;
|
|
206
|
-
}
|
|
207
|
-
export async function deleteDevice(owner, device, pause = 10) {
|
|
208
|
-
expect(owner).toBeDefined();
|
|
209
|
-
expect(device).toBeDefined();
|
|
210
|
-
expect(owner.lifecycle.isReady).toBeTruthy();
|
|
211
|
-
expect(owner.construction.status).toBe(Lifecycle.Status.Active);
|
|
212
|
-
expect(owner.lifecycle.isPartsReady).toBeTruthy();
|
|
213
|
-
try {
|
|
214
|
-
await device.delete();
|
|
215
|
-
}
|
|
216
|
-
catch (error) {
|
|
217
|
-
const errorMessage = error instanceof Error ? error.message : error;
|
|
218
|
-
const errorInspect = inspect(error, { depth: 10 });
|
|
219
|
-
console.error(`Error deleting device ${device.maybeId}.${device.maybeNumber}: ${errorMessage}\nstack: ${errorInspect}`);
|
|
220
|
-
return false;
|
|
221
|
-
}
|
|
222
|
-
expect(owner.parts.has(device)).toBeFalsy();
|
|
223
|
-
expect(owner.lifecycle.isPartsReady).toBeTruthy();
|
|
224
|
-
expect(device.lifecycle.isReady).toBeFalsy();
|
|
225
|
-
expect(device.lifecycle.isInstalled).toBeFalsy();
|
|
226
|
-
expect(device.lifecycle.hasId).toBeTruthy();
|
|
227
|
-
expect(device.lifecycle.hasNumber).toBeTruthy();
|
|
228
|
-
expect(device.construction.status).toBe(Lifecycle.Status.Destroyed);
|
|
229
|
-
await flushAsync(1, 1, pause);
|
|
230
|
-
return true;
|
|
231
|
-
}
|