@matterbridge/core 3.5.6-dev-20260226-42f2137 → 3.5.6-dev-20260227-3952eff

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/helpers.js CHANGED
@@ -1,13 +1,15 @@
1
1
  if (process.argv.includes('--loader') || process.argv.includes('-loader'))
2
2
  console.log('\u001B[32mMatterbridge helpers loaded.\u001B[40;0m');
3
3
  import { Endpoint } from '@matter/node';
4
+ import { BindingServer } from '@matter/node/behaviors/binding';
4
5
  import { BridgedDeviceBasicInformationServer } from '@matter/node/behaviors/bridged-device-basic-information';
5
6
  import { DescriptorServer } from '@matter/node/behaviors/descriptor';
6
- import { OnOffBaseServer } from '@matter/node/behaviors/on-off';
7
+ import { OnOffBaseServer, OnOffServer } from '@matter/node/behaviors/on-off';
7
8
  import { MountedOnOffControlDevice } from '@matter/node/devices/mounted-on-off-control';
8
9
  import { OnOffLightDevice } from '@matter/node/devices/on-off-light';
9
10
  import { OnOffLightSwitchDevice } from '@matter/node/devices/on-off-light-switch';
10
11
  import { OnOffPlugInUnitDevice } from '@matter/node/devices/on-off-plug-in-unit';
12
+ import { Identify } from '@matter/types/clusters/identify';
11
13
  import { OnOff } from '@matter/types/clusters/on-off';
12
14
  import { VendorId } from '@matter/types/datatype';
13
15
  import { hasParameter } from '@matterbridge/utils';
@@ -21,7 +23,7 @@ export async function addVirtualDevice(aggregatorEndpoint, name, type, callback)
21
23
  deviceType = OnOffPlugInUnitDevice.with(BridgedDeviceBasicInformationServer);
22
24
  break;
23
25
  case 'switch':
24
- deviceType = OnOffLightSwitchDevice.with(BridgedDeviceBasicInformationServer, OnOffBaseServer);
26
+ deviceType = OnOffLightSwitchDevice.with(BridgedDeviceBasicInformationServer, OnOffServer.with(), BindingServer);
25
27
  break;
26
28
  case 'mounted_switch':
27
29
  deviceType = MountedOnOffControlDevice.with(BridgedDeviceBasicInformationServer);
@@ -29,15 +31,22 @@ export async function addVirtualDevice(aggregatorEndpoint, name, type, callback)
29
31
  }
30
32
  const device = new Endpoint(deviceType, {
31
33
  id: name.replaceAll(' ', '') + ':' + type,
32
- bridgedDeviceBasicInformation: { vendorId: VendorId(0xfff1), vendorName: 'Matterbridge', productName: 'Matterbridge Virtual Device', nodeLabel: name.slice(0, 32) },
33
- onOff: { onOff: false, startUpOnOff: OnOff.StartUpOnOff.Off },
34
+ bridgedDeviceBasicInformation: {
35
+ vendorId: VendorId(0xfff1),
36
+ vendorName: 'Matterbridge',
37
+ productName: 'Matterbridge Virtual Device',
38
+ nodeLabel: name.slice(0, 32),
39
+ softwareVersion: 2000,
40
+ softwareVersionString: '2.0.0',
41
+ },
42
+ onOff: { onOff: false },
34
43
  });
35
44
  device.events.onOff.onOff$Changed.on((value) => {
36
45
  if (value) {
37
46
  callback();
38
47
  process.nextTick(async () => {
39
48
  try {
40
- await device.setStateOf(OnOffBaseServer, { onOff: false });
49
+ await device.setStateOf(OnOffServer, { onOff: false });
41
50
  }
42
51
  catch (_error) {
43
52
  }
@@ -46,6 +55,12 @@ export async function addVirtualDevice(aggregatorEndpoint, name, type, callback)
46
55
  });
47
56
  await aggregatorEndpoint.add(device);
48
57
  await device.construction.ready;
58
+ if (type === 'switch') {
59
+ await device.act(async (agent) => {
60
+ const descriptor = await agent.load(DescriptorServer);
61
+ descriptor.state.clientList.push(Identify.Cluster.id, OnOff.Cluster.id);
62
+ });
63
+ }
49
64
  if (type === 'mounted_switch') {
50
65
  await device.act(async (agent) => {
51
66
  const descriptor = await agent.load(DescriptorServer);
@@ -72,11 +72,11 @@ export declare function setupTest(name: string, debug?: boolean): Promise<void>;
72
72
  export declare function setDebug(debug: boolean): Promise<void>;
73
73
  export declare function startMatterbridge(bridgeMode?: 'bridge' | 'childbridge' | 'controller' | '', frontendPort?: number, matterPort?: number, passcode?: number, discriminator?: number, pluginSize?: number, devicesSize?: number): Promise<Matterbridge>;
74
74
  export declare function stopMatterbridge(cleanupPause?: number, destroyPause?: number): Promise<void>;
75
- export declare function createMatterbridgeEnvironment(name: string): Promise<Matterbridge>;
76
- export declare function startMatterbridgeEnvironment(port?: number): Promise<[ServerNode<ServerNode.RootEndpoint>, Endpoint<AggregatorEndpoint>]>;
75
+ export declare function createMatterbridgeEnvironment(name: string, createOnly?: boolean): Promise<Matterbridge>;
76
+ export declare function startMatterbridgeEnvironment(port?: number, createOnly?: boolean): Promise<[ServerNode<ServerNode.RootEndpoint>, Endpoint<AggregatorEndpoint>]>;
77
77
  export declare function addMatterbridgePlatform(platform: MatterbridgePlatform, name?: string): void;
78
- export declare function stopMatterbridgeEnvironment(): Promise<void>;
79
- export declare function destroyMatterbridgeEnvironment(cleanupPause?: number, destroyPause?: number): Promise<void>;
78
+ export declare function stopMatterbridgeEnvironment(createOnly?: boolean): Promise<void>;
79
+ export declare function destroyMatterbridgeEnvironment(cleanupPause?: number, destroyPause?: number, closeMdns?: boolean): Promise<void>;
80
80
  export declare function destroyInstance(matterbridge: Matterbridge, cleanupPause?: number, destroyPause?: number): Promise<void>;
81
81
  export declare function closeMdnsInstance(matterbridge: Matterbridge): Promise<void>;
82
82
  export declare function createTestEnvironment(name: string, createOnly?: boolean): Environment;
@@ -250,7 +250,7 @@ export async function startMatterbridge(bridgeMode = 'bridge', frontendPort = 82
250
250
  export async function stopMatterbridge(cleanupPause = 10, destroyPause = 250) {
251
251
  await destroyMatterbridgeEnvironment(cleanupPause, destroyPause);
252
252
  }
253
- export async function createMatterbridgeEnvironment(name) {
253
+ export async function createMatterbridgeEnvironment(name, createOnly = false) {
254
254
  log = new AnsiLogger({ logName: name, logTimestampFormat: 4, logLevel: "debug" });
255
255
  matterbridge = await Matterbridge.loadInstance(false);
256
256
  expect(matterbridge).toBeDefined();
@@ -266,12 +266,12 @@ export async function createMatterbridgeEnvironment(name) {
266
266
  frontend = matterbridge.frontend;
267
267
  plugins = matterbridge.plugins;
268
268
  devices = matterbridge.devices;
269
- matterbridge.environment = createTestEnvironment(name);
269
+ matterbridge.environment = createTestEnvironment(name, createOnly);
270
270
  expect(matterbridge.environment).toBeDefined();
271
271
  expect(matterbridge.environment).toBeInstanceOf(Environment);
272
272
  return matterbridge;
273
273
  }
274
- export async function startMatterbridgeEnvironment(port = 5540) {
274
+ export async function startMatterbridgeEnvironment(port = 5540, createOnly = false) {
275
275
  matterbridge.nodeStorage = new NodeStorageManager({
276
276
  dir: path.join(matterbridge.matterbridgeDirectory, NODE_STORAGE_DIR),
277
277
  writeQueue: false,
@@ -295,6 +295,10 @@ export async function startMatterbridgeEnvironment(port = 5540) {
295
295
  expect(server.parts.has(aggregator.id)).toBeTruthy();
296
296
  expect(server.parts.has(aggregator)).toBeTruthy();
297
297
  expect(aggregator.lifecycle.isReady).toBeTruthy();
298
+ if (createOnly) {
299
+ await flushAsync();
300
+ return [server, aggregator];
301
+ }
298
302
  expect(server.lifecycle.isOnline).toBeFalsy();
299
303
  await new Promise((resolve) => {
300
304
  server.lifecycle.online.on(async () => {
@@ -339,14 +343,16 @@ export function addMatterbridgePlatform(platform, name) {
339
343
  });
340
344
  platform['name'] = platform.config.name;
341
345
  }
342
- export async function stopMatterbridgeEnvironment() {
346
+ export async function stopMatterbridgeEnvironment(createOnly = false) {
343
347
  expect(matterbridge).toBeDefined();
344
348
  expect(server).toBeDefined();
345
349
  expect(aggregator).toBeDefined();
346
350
  await flushAllEndpointNumberPersistence(server);
347
351
  await assertAllEndpointNumbersPersisted(server);
348
352
  expect(server.lifecycle.isReady).toBeTruthy();
349
- expect(server.lifecycle.isOnline).toBeTruthy();
353
+ if (!createOnly) {
354
+ expect(server.lifecycle.isOnline).toBeTruthy();
355
+ }
350
356
  await server.close();
351
357
  expect(server.lifecycle.isReady).toBeFalsy();
352
358
  expect(server.lifecycle.isOnline).toBeFalsy();
@@ -360,9 +366,11 @@ export async function stopMatterbridgeEnvironment() {
360
366
  matterbridge.nodeStorage = undefined;
361
367
  await flushAsync();
362
368
  }
363
- export async function destroyMatterbridgeEnvironment(cleanupPause = 10, destroyPause = 250) {
369
+ export async function destroyMatterbridgeEnvironment(cleanupPause = 10, destroyPause = 250, closeMdns = true) {
364
370
  await destroyInstance(matterbridge, cleanupPause, destroyPause);
365
- await closeMdnsInstance(matterbridge);
371
+ if (closeMdns) {
372
+ await closeMdnsInstance(matterbridge);
373
+ }
366
374
  Matterbridge.instance = undefined;
367
375
  }
368
376
  export async function destroyInstance(matterbridge, cleanupPause = 10, destroyPause = 250) {
@@ -218,11 +218,11 @@ export class Matterbridge extends EventEmitter {
218
218
  await this.nodeContext?.set('globalModulesDirectory', msg.params.prefix);
219
219
  this.server.respond({ ...msg, result: { success: true } });
220
220
  break;
221
- case 'matterbridge_sys_update':
221
+ case 'matterbridge_shelly_sys_update':
222
222
  this.shellySysUpdate = true;
223
223
  this.server.respond({ ...msg, result: { success: true } });
224
224
  break;
225
- case 'matterbridge_main_update':
225
+ case 'matterbridge_shelly_main_update':
226
226
  this.shellyMainUpdate = true;
227
227
  this.server.respond({ ...msg, result: { success: true } });
228
228
  break;
@@ -1584,6 +1584,7 @@ export class Matterbridge extends EventEmitter {
1584
1584
  this.matterStorageService = undefined;
1585
1585
  this.matterStorageManager = undefined;
1586
1586
  this.matterbridgeContext = undefined;
1587
+ this.controllerContext = undefined;
1587
1588
  this.log.info('Matter node storage closed');
1588
1589
  }
1589
1590
  async createServerNodeContext(storeId, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber, uniqueId) {
@@ -1681,15 +1682,17 @@ export class Matterbridge extends EventEmitter {
1681
1682
  },
1682
1683
  });
1683
1684
  serverNode.lifecycle.commissioned.on(() => {
1684
- this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`);
1685
+ this.log.notice(`Server node for ${storeId} commissioned successfully!`);
1685
1686
  this.advertisingNodes.delete(storeId);
1686
1687
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
1688
+ this.frontend.wssSendSnackbarMessage(`Server node for ${storeId} commissioned successfully!`, 5, 'success');
1687
1689
  });
1688
1690
  serverNode.lifecycle.decommissioned.on(() => {
1689
- this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`);
1691
+ this.log.notice(`Server node for ${storeId} fully decommissioned successfully!`);
1690
1692
  this.advertisingNodes.delete(storeId);
1691
1693
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
1692
1694
  this.frontend.wssSendSnackbarMessage(`${storeId} is offline`, 5, 'warning');
1695
+ this.frontend.wssSendSnackbarMessage(`Server node for ${storeId} fully decommissioned successfully!`, 5, 'success');
1693
1696
  });
1694
1697
  serverNode.lifecycle.online.on(async () => {
1695
1698
  this.log.notice(`Server node for ${storeId} is online`);
@@ -0,0 +1,15 @@
1
+ import { BindingBehavior } from '@matter/main/behaviors/binding';
2
+ import { ClusterId } from '@matter/main/types';
3
+ export declare class MatterbridgeBindingServer extends BindingBehavior {
4
+ protected internal: MatterbridgeBindingServer.Internal;
5
+ state: MatterbridgeBindingServer.State;
6
+ initialize(): Promise<void>;
7
+ }
8
+ export declare namespace MatterbridgeBindingServer {
9
+ class Internal {
10
+ bound: boolean;
11
+ }
12
+ class State extends BindingBehavior.State {
13
+ clientList: ClusterId[];
14
+ }
15
+ }
@@ -0,0 +1,25 @@
1
+ import { BindingBehavior } from '@matter/main/behaviors/binding';
2
+ import { DescriptorServer } from '@matter/main/behaviors/descriptor';
3
+ import { MatterbridgeServer } from './matterbridgeBehaviors.js';
4
+ export class MatterbridgeBindingServer extends BindingBehavior {
5
+ async initialize() {
6
+ const device = this.endpoint.stateOf(MatterbridgeServer);
7
+ device.log.info(`Initializing MatterbridgeBindingServer (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber}) with clientList: ${this.state.clientList.join(', ')}`);
8
+ (await this.agent.load(DescriptorServer)).state.clientList.push(...this.state.clientList);
9
+ this.reactTo(this.events.binding$Changed, (value) => {
10
+ this.internal.bound = value.length > 0;
11
+ device.log.notice(`MatterbridgeBindingServer (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber}) binding changed: ${value}, bound: ${this.internal.bound}`);
12
+ });
13
+ await super.initialize();
14
+ }
15
+ }
16
+ (function (MatterbridgeBindingServer) {
17
+ class Internal {
18
+ bound = false;
19
+ }
20
+ MatterbridgeBindingServer.Internal = Internal;
21
+ class State extends BindingBehavior.State {
22
+ clientList = [];
23
+ }
24
+ MatterbridgeBindingServer.State = State;
25
+ })(MatterbridgeBindingServer || (MatterbridgeBindingServer = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matterbridge/core",
3
- "version": "3.5.6-dev-20260226-42f2137",
3
+ "version": "3.5.6-dev-20260227-3952eff",
4
4
  "description": "Matterbridge core library",
5
5
  "author": "https://github.com/Luligu",
6
6
  "homepage": "https://matterbridge.io/",
@@ -122,10 +122,10 @@
122
122
  ],
123
123
  "dependencies": {
124
124
  "@matter/main": "0.16.10",
125
- "@matterbridge/dgram": "3.5.6-dev-20260226-42f2137",
126
- "@matterbridge/thread": "3.5.6-dev-20260226-42f2137",
127
- "@matterbridge/types": "3.5.6-dev-20260226-42f2137",
128
- "@matterbridge/utils": "3.5.6-dev-20260226-42f2137",
125
+ "@matterbridge/dgram": "3.5.6-dev-20260227-3952eff",
126
+ "@matterbridge/thread": "3.5.6-dev-20260227-3952eff",
127
+ "@matterbridge/types": "3.5.6-dev-20260227-3952eff",
128
+ "@matterbridge/utils": "3.5.6-dev-20260227-3952eff",
129
129
  "archiver": "7.0.1",
130
130
  "express": "5.2.1",
131
131
  "glob": "13.0.6",