matterbridge-example-dynamic-platform 1.4.0 → 2.0.0-dev-20251025-e5cca37

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 CHANGED
@@ -1,3 +1,5 @@
1
+ <!-- markdownlint-disable MD024 MD033 -->
2
+
1
3
  # <img src="matterbridge.svg" alt="Matterbridge Logo" width="64px" height="64px">&nbsp;&nbsp;&nbsp;Matterbridge dynamic platform example plugin changelog
2
4
 
3
5
  [![npm version](https://img.shields.io/npm/v/matterbridge-example-dynamic-platform.svg)](https://www.npmjs.com/package/matterbridge-example-dynamic-platform)
@@ -17,31 +19,45 @@
17
19
 
18
20
  All notable changes to this project will be documented in this file.
19
21
 
20
- If you like this project and find it useful, please consider giving it a star on GitHub at https://github.com/Luligu/matterbridge-example-dynamic-platform and sponsoring it.
22
+ If you like this project and find it useful, please consider giving it a star on GitHub at <https://github.com/Luligu/matterbridge-example-dynamic-platform> and sponsoring it.
21
23
 
22
24
  <a href="https://www.buymeacoffee.com/luligugithub">
23
25
  <img src="bmc-button.svg" alt="Buy me a coffee" width="120">
24
26
  </a>
25
27
 
28
+ ## [1.4.1] - 2025-10-24
29
+
30
+ ### Changed
31
+
32
+ - [package]: Updated dependencies.
33
+ - [package]: Bumped package to automator version 2.0.9
34
+ - [jest]: Updated jestHelpers to v. 1.0.9.
35
+
36
+ <a href="https://www.buymeacoffee.com/luligugithub">
37
+ <img src="bmc-button.svg" alt="Buy me a coffee" width="80">
38
+ </a>
39
+
26
40
  ## [1.4.0] - 2025-10-15
27
41
 
28
42
  ### Added
29
43
 
30
44
  - [jest]: Added jest helper module v. 1.0.6.
31
45
  - [platform]: Added a thermostat with auto mode and occupancy and outdoorTemperature.
32
- - [platform]: Added animation to Heat pump. Thanks Ludovic BOUÉ (https://github.com/Luligu/matterbridge-example-dynamic-platform/pull/35).
33
- - [platform]: Added Toggle thermostatRunningState heat and cool. Thanks Ludovic BOUÉ (https://github.com/Luligu/matterbridge-example-dynamic-platform/pull/36).
46
+ - [platform]: Added animation to Heat pump. Thanks Ludovic BOUÉ (<https://github.com/Luligu/matterbridge-example-dynamic-platform/pull/35>).
47
+ - [platform]: Added Toggle thermostatRunningState heat and cool. Thanks Ludovic BOUÉ (<https://github.com/Luligu/matterbridge-example-dynamic-platform/pull/36>).
34
48
 
35
49
  ### Changed
36
50
 
37
51
  - [package]: Require matterbridge 3.3.0.
38
52
  - [index]: Updated to new signature PlatformMatterbridge.
39
53
  - [platform]: Updated to new signature PlatformMatterbridge.
40
- - [platform]: Added whiteList and blackList.
41
- - [platform]: Typed TestPlatformConfig.
42
54
  - [package]: Updated dependencies.
43
55
  - [package]: Bumped package to automator version 2.0.7
44
- - [workflows]: Ignore any .md anywhere in all workflows.
56
+ - [workflows]: Ignore any .md in build.yaml.
57
+ - [workflows]: Ignore any .md in codeql.yaml.
58
+ - [workflows]: Ignore any .md in codecov.yaml.
59
+ - [template]: Updated bug_report.md.
60
+ - [jest]: Updated jestHelpers to v. 1.0.6.
45
61
 
46
62
  <a href="https://www.buymeacoffee.com/luligugithub">
47
63
  <img src="bmc-button.svg" alt="Buy me a coffee" width="80">
@@ -52,7 +68,7 @@ If you like this project and find it useful, please consider giving it a star on
52
68
  ### Added
53
69
 
54
70
  - [jest]: Added jest helper module v. 1.0.5.
55
- - [rvc]: Added DustBinFull to the Rvc animation (https://github.com/Luligu/matterbridge-example-dynamic-platform/pull/31).
71
+ - [rvc]: Added DustBinFull to the Rvc animation (<https://github.com/Luligu/matterbridge-example-dynamic-platform/pull/31>).
56
72
 
57
73
  ### Changed
58
74
 
@@ -69,7 +85,7 @@ If you like this project and find it useful, please consider giving it a star on
69
85
  ### Changed
70
86
 
71
87
  - [package]: Updated dependencies.
72
- - [platform]: Removed attributes setting when is managed by the Matterbridge servers. This add support for **Apple Home Adaptive Lighting**. See https://github.com/Luligu/matterbridge/discussions/390.
88
+ - [platform]: Removed attributes setting when is managed by the Matterbridge servers. This add support for **Apple Home Adaptive Lighting**. See <https://github.com/Luligu/matterbridge/discussions/390>.
73
89
 
74
90
  <a href="https://www.buymeacoffee.com/luligugithub">
75
91
  <img src="bmc-button.svg" alt="Buy me a coffee" width="80">
@@ -333,7 +349,7 @@ If you like this project and find it useful, please consider giving it a star on
333
349
 
334
350
  ### Added
335
351
 
336
- - [platform]: Added Robot Vacuum Cleaner device (supported by SmartThings, Alexa, Home Assistant and partially by Apple Home). Read carefully the readme please and also https://github.com/Luligu/matterbridge/discussions/264.
352
+ - [platform]: Added Robot Vacuum Cleaner device (supported by SmartThings, Alexa, Home Assistant and partially by Apple Home). Read carefully the readme please and also <https://github.com/Luligu/matterbridge/discussions/264>.
337
353
  - [platform]: Added OnOff Mounted Switch device (supported by SmartThings, Alexa, Home Assistant).
338
354
  - [platform]: Added Dimmer Mounted Switch device (supported by SmartThings, Alexa, Home Assistant).
339
355
  - [platform]: Added Laundry Washer device (supported by SmartThings, Alexa and Home Assistant).
package/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ <!-- markdownlint-disable MD033 -->
2
+
1
3
  # <img src="matterbridge.svg" alt="Matterbridge Logo" width="64px" height="64px">&nbsp;&nbsp;&nbsp;Matterbridge dynamic platform example plugin
2
4
 
3
5
  [![npm version](https://img.shields.io/npm/v/matterbridge-example-dynamic-platform.svg)](https://www.npmjs.com/package/matterbridge-example-dynamic-platform)
@@ -61,7 +63,7 @@ It exposes 58 virtual devices:
61
63
  - an airQuality device with all concentration measurements clusters (supported by Apple Home with the concentration measurements from version 18.5)
62
64
  - a momentary switch composed by three switches with Single Double Long (tagged with One Two Three and Top Middle Bottom) and three switches with Single only.
63
65
  - a latching switch
64
- - a Robot Vacuum Cleaner device (supported by SmartThings, Alexa, Home Assistant and partially by Apple Home). Read also https://github.com/Luligu/matterbridge/discussions/264.
66
+ - a Robot Vacuum Cleaner device (supported by SmartThings, Alexa, Home Assistant and partially by Apple Home). Read also <https://github.com/Luligu/matterbridge/discussions/264>.
65
67
  - a onOff Mounted Switch device (supported by SmartThings, Alexa, Home Assistant)
66
68
  - a dimmer Mounted Switch device (supported by SmartThings, Alexa, Home Assistant)
67
69
  - a laundry Washer device (supported by SmartThings, Alexa and Home Assistant)
@@ -83,7 +85,7 @@ All these devices continuously change state and position. The plugin also shows
83
85
 
84
86
  If you want to write your plugin, the easiest way to start create a new plugin is to clone the [Matterbridge Plugin Template](https://github.com/Luligu/matterbridge-plugin-template) which has **Dev Container support for instant development environment** and all tools and extensions (like Node.js, npm, TypeScript, ESLint, Prettier, Jest and Vitest) already loaded and configured.
85
87
 
86
- If you like this project and find it useful, please consider giving it a star on GitHub at https://github.com/Luligu/matterbridge-example-dynamic-platform and sponsoring it.
88
+ If you like this project and find it useful, please consider giving it a star on GitHub at <https://github.com/Luligu/matterbridge-example-dynamic-platform> and sponsoring it.
87
89
 
88
90
  <a href="https://www.buymeacoffee.com/luligugithub">
89
91
  <img src="bmc-button.svg" alt="Buy me a coffee" width="120">
@@ -5,12 +5,16 @@ import { jest } from '@jest/globals';
5
5
  import { DeviceTypeId, Endpoint, Environment, MdnsService, ServerNode, ServerNodeStore, VendorId, LogFormat as MatterLogFormat, LogLevel as MatterLogLevel, Lifecycle, } from 'matterbridge/matter';
6
6
  import { RootEndpoint, AggregatorEndpoint } from 'matterbridge/matter/endpoints';
7
7
  import { AnsiLogger } from 'matterbridge/logger';
8
+ import { MATTER_STORAGE_NAME, Matterbridge } from 'matterbridge';
8
9
  export let loggerLogSpy;
9
10
  export let consoleLogSpy;
10
11
  export let consoleDebugSpy;
11
12
  export let consoleInfoSpy;
12
13
  export let consoleWarnSpy;
13
14
  export let consoleErrorSpy;
15
+ export const addBridgedEndpointSpy = jest.spyOn(Matterbridge.prototype, 'addBridgedEndpoint');
16
+ export const removeBridgedEndpointSpy = jest.spyOn(Matterbridge.prototype, 'removeBridgedEndpoint');
17
+ export const removeAllBridgedEndpointsSpy = jest.spyOn(Matterbridge.prototype, 'removeAllBridgedEndpoints');
14
18
  export function setupTest(name, debug = false) {
15
19
  expect(name).toBeDefined();
16
20
  expect(typeof name).toBe('string');
@@ -57,20 +61,97 @@ export function setDebug(debug) {
57
61
  consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
58
62
  }
59
63
  }
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 });
64
+ export async function createMatterbridgeEnvironment(name) {
65
+ const matterbridge = await Matterbridge.loadInstance(false);
66
+ expect(matterbridge).toBeDefined();
67
+ expect(matterbridge).toBeInstanceOf(Matterbridge);
68
+ matterbridge.matterbridgeVersion = '3.3.0';
69
+ matterbridge.bridgeMode = 'bridge';
70
+ matterbridge.rootDirectory = path.join('jest', name);
71
+ matterbridge.homeDirectory = path.join('jest', name);
72
+ matterbridge.matterbridgeDirectory = path.join('jest', name, '.matterbridge');
73
+ matterbridge.matterbridgePluginDirectory = path.join('jest', name, 'Matterbridge');
74
+ matterbridge.matterbridgeCertDirectory = path.join('jest', name, '.mattercert');
75
+ matterbridge.environment = createTestEnvironment(name);
76
+ expect(matterbridge.environment).toBeDefined();
77
+ expect(matterbridge.environment).toBeInstanceOf(Environment);
78
+ return matterbridge;
79
+ }
80
+ export async function startMatterbridgeEnvironment(matterbridge, port = 5540) {
81
+ await matterbridge.startMatterStorage();
82
+ expect(matterbridge.matterStorageService).toBeDefined();
83
+ expect(matterbridge.matterStorageManager).toBeDefined();
84
+ expect(matterbridge.matterbridgeContext).toBeDefined();
85
+ const server = await matterbridge.createServerNode(matterbridge.matterbridgeContext, port);
86
+ expect(server).toBeDefined();
87
+ expect(server).toBeDefined();
88
+ expect(server.lifecycle.isReady).toBeTruthy();
89
+ matterbridge.serverNode = server;
90
+ const aggregator = await matterbridge.createAggregatorNode(matterbridge.matterbridgeContext);
91
+ expect(aggregator).toBeDefined();
92
+ matterbridge.aggregatorNode = aggregator;
93
+ expect(await server.add(aggregator)).toBeDefined();
94
+ expect(server.parts.has(aggregator.id)).toBeTruthy();
95
+ expect(server.parts.has(aggregator)).toBeTruthy();
96
+ expect(aggregator.lifecycle.isReady).toBeTruthy();
97
+ expect(server.lifecycle.isOnline).toBeFalsy();
98
+ await new Promise((resolve) => {
99
+ server.lifecycle.online.on(async () => {
100
+ resolve();
101
+ });
102
+ server.start();
103
+ });
104
+ expect(server.lifecycle.isReady).toBeTruthy();
105
+ expect(server.lifecycle.isOnline).toBeTruthy();
106
+ expect(server.lifecycle.isCommissioned).toBeFalsy();
107
+ expect(server.lifecycle.isPartsReady).toBeTruthy();
108
+ expect(server.lifecycle.hasId).toBeTruthy();
109
+ expect(server.lifecycle.hasNumber).toBeTruthy();
110
+ expect(aggregator.lifecycle.isReady).toBeTruthy();
111
+ expect(aggregator.lifecycle.isInstalled).toBeTruthy();
112
+ expect(aggregator.lifecycle.isPartsReady).toBeTruthy();
113
+ expect(aggregator.lifecycle.hasId).toBeTruthy();
114
+ expect(aggregator.lifecycle.hasNumber).toBeTruthy();
115
+ await flushAsync();
116
+ return [server, aggregator];
117
+ }
118
+ export async function stopMatterbridgeEnvironment(matterbridge, server, aggregator) {
119
+ expect(matterbridge).toBeDefined();
120
+ expect(server).toBeDefined();
121
+ expect(aggregator).toBeDefined();
122
+ await flushAllEndpointNumberPersistence(server);
123
+ await assertAllEndpointNumbersPersisted(server);
124
+ expect(server.lifecycle.isReady).toBeTruthy();
125
+ expect(server.lifecycle.isOnline).toBeTruthy();
126
+ await server.close();
127
+ expect(server.lifecycle.isReady).toBeTruthy();
128
+ expect(server.lifecycle.isOnline).toBeFalsy();
129
+ await server.env.get(MdnsService)[Symbol.asyncDispose]();
130
+ await matterbridge.stopMatterStorage();
131
+ expect(matterbridge.matterStorageService).not.toBeDefined();
132
+ expect(matterbridge.matterStorageManager).not.toBeDefined();
133
+ expect(matterbridge.matterbridgeContext).not.toBeDefined();
134
+ await flushAsync();
135
+ }
136
+ export async function destroyMatterbridgeEnvironment(matterbridge) {
137
+ await matterbridge.destroyInstance(10);
138
+ Matterbridge.instance = undefined;
139
+ }
140
+ export function createTestEnvironment(name) {
141
+ expect(name).toBeDefined();
142
+ expect(typeof name).toBe('string');
143
+ expect(name.length).toBeGreaterThanOrEqual(4);
144
+ rmSync(path.join('jest', name), { recursive: true, force: true });
65
145
  const environment = Environment.default;
66
146
  environment.vars.set('log.level', MatterLogLevel.DEBUG);
67
147
  environment.vars.set('log.format', MatterLogFormat.ANSI);
68
- environment.vars.set('path.root', homeDir);
148
+ environment.vars.set('path.root', path.join('jest', name, '.matterbridge', MATTER_STORAGE_NAME));
69
149
  environment.vars.set('runtime.signals', false);
70
150
  environment.vars.set('runtime.exitcode', false);
151
+ new MdnsService(environment);
71
152
  return environment;
72
153
  }
73
- export async function flushAsync(ticks = 3, microTurns = 10, pause = 100) {
154
+ export async function flushAsync(ticks = 3, microTurns = 10, pause = 250) {
74
155
  for (let i = 0; i < ticks; i++)
75
156
  await new Promise((resolve) => setImmediate(resolve));
76
157
  for (let i = 0; i < microTurns; i++)
@@ -113,9 +194,10 @@ export async function assertAllEndpointNumbersPersisted(targetServer) {
113
194
  }
114
195
  return all.length;
115
196
  }
116
- export async function startServerNode(name, port) {
197
+ export async function startServerNode(name, port, environment) {
117
198
  const server = await ServerNode.create({
118
199
  id: name + 'ServerNode',
200
+ environment: environment,
119
201
  productDescription: {
120
202
  name: name + 'ServerNode',
121
203
  deviceType: DeviceTypeId(RootEndpoint.deviceType),
@@ -164,7 +246,7 @@ export async function startServerNode(name, port) {
164
246
  expect(aggregator.lifecycle.isPartsReady).toBeTruthy();
165
247
  expect(aggregator.lifecycle.hasId).toBeTruthy();
166
248
  expect(aggregator.lifecycle.hasNumber).toBeTruthy();
167
- await flushAsync(undefined, undefined, 200);
249
+ await flushAsync();
168
250
  return [server, aggregator];
169
251
  }
170
252
  export async function stopServerNode(server) {
@@ -177,7 +259,7 @@ export async function stopServerNode(server) {
177
259
  expect(server.lifecycle.isReady).toBeTruthy();
178
260
  expect(server.lifecycle.isOnline).toBeFalsy();
179
261
  await server.env.get(MdnsService)[Symbol.asyncDispose]();
180
- await flushAsync(undefined, undefined, 200);
262
+ await flushAsync();
181
263
  }
182
264
  export async function addDevice(owner, device, pause = 10) {
183
265
  expect(owner).toBeDefined();
@@ -201,7 +283,7 @@ export async function addDevice(owner, device, pause = 10) {
201
283
  expect(device.lifecycle.hasId).toBeTruthy();
202
284
  expect(device.lifecycle.hasNumber).toBeTruthy();
203
285
  expect(device.construction.status).toBe(Lifecycle.Status.Active);
204
- await flushAsync(1, 1, pause);
286
+ await flushAsync(undefined, undefined, pause);
205
287
  return true;
206
288
  }
207
289
  export async function deleteDevice(owner, device, pause = 10) {
@@ -226,6 +308,6 @@ export async function deleteDevice(owner, device, pause = 10) {
226
308
  expect(device.lifecycle.hasId).toBeTruthy();
227
309
  expect(device.lifecycle.hasNumber).toBeTruthy();
228
310
  expect(device.construction.status).toBe(Lifecycle.Status.Destroyed);
229
- await flushAsync(1, 1, pause);
311
+ await flushAsync(undefined, undefined, pause);
230
312
  return true;
231
313
  }
@@ -19,6 +19,9 @@ function matterToLux(value) {
19
19
  const lux = Math.pow(10, v / 10000);
20
20
  return Math.round(lux < 0 ? 0 : lux);
21
21
  }
22
+ export default function initializePlugin(matterbridge, log, config) {
23
+ return new ExampleMatterbridgeDynamicPlatform(matterbridge, log, config);
24
+ }
22
25
  export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatform {
23
26
  config;
24
27
  door;
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "matterbridge-example-dynamic-platform",
3
- "version": "1.4.0",
3
+ "version": "2.0.0-dev-20251025-e5cca37",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "matterbridge-example-dynamic-platform",
9
- "version": "1.4.0",
9
+ "version": "2.0.0-dev-20251025-e5cca37",
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": ">=18.0.0 <19.0.0 || >=20.0.0 <21.0.0 || >=22.0.0 <23.0.0 || >=24.0.0 <25.0.0"
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-example-dynamic-platform",
3
- "version": "1.4.0",
3
+ "version": "2.0.0-dev-20251025-e5cca37",
4
4
  "description": "Matterbridge dynamic plugin",
5
5
  "author": "https://github.com/Luligu",
6
6
  "license": "Apache-2.0",
7
7
  "homepage": "https://www.npmjs.com/package/matterbridge-example-dynamic-platform",
8
8
  "type": "module",
9
- "main": "dist/index.js",
9
+ "main": "dist/module.js",
10
10
  "repository": {
11
11
  "type": "git",
12
12
  "url": "git+https://github.com/Luligu/matterbridge-example-dynamic-platform.git"
@@ -31,7 +31,7 @@
31
31
  "virtual devices"
32
32
  ],
33
33
  "engines": {
34
- "node": ">=18.0.0 <19.0.0 || >=20.0.0 <21.0.0 || >=22.0.0 <23.0.0 || >=24.0.0 <25.0.0"
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
@@ -1,4 +0,0 @@
1
- import { ExampleMatterbridgeDynamicPlatform } from './platform.js';
2
- export default function initializePlugin(matterbridge, log, config) {
3
- return new ExampleMatterbridgeDynamicPlatform(matterbridge, log, config);
4
- }