matterbridge 1.2.0 → 1.2.2

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
@@ -2,6 +2,27 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [1.2.2] - 2024-03-26
6
+
7
+ ### Added
8
+
9
+ - [MatterbridgeDevice]: Added Cluster DoorLock and command handler.
10
+
11
+ ## [1.2.1] - 2024-03-25
12
+
13
+ ### Added
14
+
15
+ - [frontend]: Remove plugin from frontend.
16
+ - [frontend]: Add plugin from frontend.
17
+ - [workflow]: All packages now have a workflow on GitHub.
18
+ - [frontend]: Frontend got updated to 0.8.4.
19
+
20
+ ### Fixed
21
+
22
+ - [frontend]: Fixed the restart needed message.
23
+ - [matterbridge]: Fixed the delay of loading from the cli.
24
+ - [matterbridge]: Fixed the count of devices removed.
25
+
5
26
  ## [1.2.0] - 2024-03-23
6
27
 
7
28
  ### Breaking change on plugin default entry point and platform constructor!
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/matterbridge.svg)](https://www.npmjs.com/package/matterbridge)
4
4
  [![npm downloads](https://img.shields.io/npm/dt/matterbridge.svg)](https://www.npmjs.com/package/matterbridge)
5
+ ![Node.js CI](https://github.com/Luligu/matterbridge/actions/workflows/build.yml/badge.svg)
6
+
5
7
 
6
8
  [![power by](https://img.shields.io/badge/powered%20by-matter--history-blue)](https://www.npmjs.com/package/matter-history)
7
9
  [![power by](https://img.shields.io/badge/powered%20by-node--ansi--logger-blue)](https://www.npmjs.com/package/node-ansi-logger)
@@ -33,12 +35,12 @@ A special thank to Apollon77 for his incredible work.
33
35
  Follow these steps to install Matterbridge:
34
36
 
35
37
  on Windows:
36
- ``` powershell
38
+ ```
37
39
  npm install -g matterbridge
38
40
  ```
39
41
 
40
42
  on Linux (you need the necessary permissions):
41
- ``` bash
43
+ ```
42
44
  sudo npm install -g matterbridge
43
45
  ```
44
46
 
@@ -46,6 +48,7 @@ Test the installation with:
46
48
  ```
47
49
  matterbridge -bridge
48
50
  ```
51
+
49
52
  Now it is possible to open the frontend at the link provided (default: http://localhost:3000)
50
53
 
51
54
  ## Usage
@@ -87,10 +90,10 @@ matterbridge -childbridge -frontend [port number]
87
90
  ```
88
91
 
89
92
  Home page:
90
- ![See the screenshot here](https://github.com/Luligu/matterbridge/blob/main/Screenshot%20home%20page.png)
93
+ ![See the screenshot here](https://github.com/Luligu/matterbridge/blob/main/Screenshot%20home.jpg)
91
94
 
92
95
  Devices page:
93
- ![See the screenshot here](https://github.com/Luligu/matterbridge/blob/main/Screenshot%20devices%20page.png)
96
+ ![See the screenshot here](https://github.com/Luligu/matterbridge/blob/main/Screenshot%20devices.jpg)
94
97
 
95
98
  ## Plugins
96
99
 
@@ -130,6 +133,10 @@ Matterbridge can run as many plugins as you want.
130
133
 
131
134
  [Room plugin with history](https://github.com/Luligu/matterbridge-eve-room)
132
135
 
136
+ ### Production-level plugins
137
+
138
+ [zigbee2mqtt](https://github.com/Luligu/matterbridge-zigbee2mqtt)
139
+
133
140
  ## How to install and register a production-level plugin (from npm)
134
141
 
135
142
  To install i.e. https://github.com/Luligu/matterbridge-zigbee2mqtt
@@ -148,7 +155,7 @@ sudo npm install -g matterbridge-zigbee2mqtt
148
155
  matterbridge -add matterbridge-zigbee2mqtt
149
156
  ```
150
157
 
151
- ## How to install and register a plugin for development (from git)
158
+ ## How to install and register a plugin for development (from github)
152
159
 
153
160
  To install i.e. https://github.com/Luligu/matterbridge-example-accessory-platform
154
161
 
@@ -162,15 +169,16 @@ On linux:
162
169
  cd ~/Matterbridge
163
170
  ```
164
171
 
165
- then
172
+ then clone the plugin
166
173
 
167
174
  ```
168
175
  git clone https://github.com/Luligu/matterbridge-example-accessory-platform
169
176
  cd matterbridge-example-accessory-platform
170
177
  npm install
178
+ npm run build
171
179
  ```
172
180
 
173
- Then add the plugin to Matterbridge
181
+ then add the plugin to Matterbridge
174
182
  ```
175
183
  matterbridge -add .\
176
184
  ```
@@ -221,7 +229,8 @@ The plugin name.
221
229
  The plugin platform type.
222
230
 
223
231
  ### config: object
224
- The plugin config (loaded before onStart() is called and saved after onShutdown() is called).
232
+ The plugin config (loaded before the platform constructor is called and saved after onShutdown() is called).
233
+ Here you can store your plugin configuration (see matterbridge-zigbee2mqtt for example)
225
234
 
226
235
  ### async onStart(reason?: string)
227
236
  The method onStart() is where you have to create your MatterbridgeDevice and add all needed clusters and command handlers.
@@ -253,3 +262,37 @@ It can be useful to call this method from onShutdown() if you don't want to keep
253
262
 
254
263
  ## MatterbridgeDevice api
255
264
 
265
+
266
+ # Contribution Guidelines
267
+
268
+ Thank you for your interest in contributing to my project!
269
+
270
+ I warmly welcome contributions to this project! Whether it's reporting bugs, proposing new features, updating documentation, or writing code, your help is greatly appreciated.
271
+
272
+ ## Getting Started
273
+
274
+ - Fork this repository to your own GitHub account and clone it to your local device.
275
+ - Make the necessary changes and test them out
276
+ - Commit your changes and push to your forked repository
277
+
278
+ ## Submitting Changes
279
+
280
+ - Create a new pull request from my repository and I'll be glad to check it out
281
+ - Be sure to follow the existing code style
282
+ - Add unit tests for any new or changed functionality if possible
283
+ - In your pull request, do describe what your changes do and how they work
284
+
285
+ ## Code of Conduct
286
+
287
+ We believe in a welcoming and respectful community for all. Please make sure to follow our [Code of Conduct](LINK_TO_CODE_OF_CONDUCT) in all your interactions with the project.
288
+
289
+ ## Support
290
+
291
+ If you find this project helpful and you wish to support the ongoing development, you can do so by buying me a coffee.
292
+ Click on the badge below to get started:
293
+
294
+ <a href="https://www.buymeacoffee.com/luligugithub">
295
+ <img src="./yellow-button.png" alt="Buy me a coffee" width="120">
296
+ </a>
297
+
298
+ Thank you for your support!
@@ -1 +1 @@
1
- {"version":3,"file":"matterbridge.d.ts","sourceRoot":"","sources":["../src/matterbridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"matterbridge.d.ts","sourceRoot":"","sources":["../src/matterbridge.ts"],"names":[],"mappings":"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"}
@@ -31,11 +31,11 @@ import express from 'express';
31
31
  import os from 'os';
32
32
  import path from 'path';
33
33
  import { CommissioningController, CommissioningServer, MatterServer } from '@project-chip/matter-node.js';
34
- import { BasicInformationCluster, BridgedDeviceBasicInformationCluster, ClusterServer } from '@project-chip/matter-node.js/cluster';
34
+ import { BasicInformationCluster, BridgedDeviceBasicInformationCluster, ClusterServer, GeneralCommissioning, PowerSourceCluster, ThreadNetworkDiagnosticsCluster, } from '@project-chip/matter-node.js/cluster';
35
35
  import { DeviceTypeId, VendorId } from '@project-chip/matter-node.js/datatype';
36
- import { Aggregator, DeviceTypes } from '@project-chip/matter-node.js/device';
36
+ import { Aggregator, DeviceTypes, NodeStateInformation } from '@project-chip/matter-node.js/device';
37
37
  import { Format, Level, Logger } from '@project-chip/matter-node.js/log';
38
- import { QrCodeSchema } from '@project-chip/matter-node.js/schema';
38
+ import { ManualPairingCodeCodec, QrCodeSchema } from '@project-chip/matter-node.js/schema';
39
39
  import { StorageBackendDisk, StorageBackendJsonFile, StorageManager } from '@project-chip/matter-node.js/storage';
40
40
  import { requireMinNodeVersion, getParameter, getIntParameter, hasParameter } from '@project-chip/matter-node.js/util';
41
41
  import { CryptoNode } from '@project-chip/matter-node.js/crypto';
@@ -109,15 +109,11 @@ export class Matterbridge extends EventEmitter {
109
109
  static async loadInstance(initialize = false) {
110
110
  if (!Matterbridge.instance) {
111
111
  // eslint-disable-next-line no-console
112
- console.log('Matterbridge instance does not exists');
112
+ console.log(wr + 'Matterbridge instance does not exists!', initialize ? 'Initializing...' : 'Not initializing...', rs);
113
113
  Matterbridge.instance = new Matterbridge();
114
114
  if (initialize)
115
115
  await Matterbridge.instance.initialize();
116
116
  }
117
- else {
118
- // eslint-disable-next-line no-console
119
- console.log('Matterbridge instance already exists');
120
- }
121
117
  return Matterbridge.instance;
122
118
  }
123
119
  /**
@@ -152,28 +148,19 @@ export class Matterbridge extends EventEmitter {
152
148
  - disable [plugin name]: disable the globally installed plugin with the given name\n`);
153
149
  process.exit(0);
154
150
  }
155
- // set Matterbridge logger
151
+ // Set Matterbridge logger
156
152
  if (hasParameter('debug'))
157
153
  this.debugEnabled = true;
158
154
  this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logDebug: this.debugEnabled });
159
155
  this.log.debug('Matterbridge is starting...');
160
- // log system info and create .matterbridge directory
161
- await this.logNodeAndSystemInfo();
162
- this.log.info(
163
- // eslint-disable-next-line max-len
164
- `Matterbridge version ${this.matterbridgeVersion} mode ${hasParameter('bridge') ? 'bridge' : ''}${hasParameter('childbridge') ? 'childbridge' : ''}${hasParameter('controller') ? 'controller' : ''} running on ${this.systemInformation.osType} ${this.systemInformation.osRelease} ${this.systemInformation.osPlatform} ${this.systemInformation.osArch}`);
165
- // check node version and throw error
166
- requireMinNodeVersion(18);
167
- // register SIGINT SIGTERM signal handlers
168
- this.registerSignalHandlers();
169
- // set matter.js logger level and format
170
- Logger.defaultLogLevel = this.debugEnabled ? Level.DEBUG : Level.INFO;
171
- Logger.format = Format.ANSI;
172
156
  // Initialize NodeStorage
157
+ this.homeDirectory = os.homedir();
158
+ this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
173
159
  this.log.debug('Creating node storage manager');
174
160
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, 'storage'), logging: false });
175
161
  this.log.debug('Creating node storage context for matterbridge');
176
162
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
163
+ // Get the plugins from node storage
177
164
  this.registeredPlugins = await this.nodeContext.get('plugins', []);
178
165
  for (const plugin of this.registeredPlugins) {
179
166
  this.log.debug(`Creating node storage context for plugin ${plugin.name}`);
@@ -185,6 +172,43 @@ export class Matterbridge extends EventEmitter {
185
172
  await plugin.nodeContext.set('description', plugin.description);
186
173
  await plugin.nodeContext.set('author', plugin.author);
187
174
  }
175
+ if (hasParameter('logstorage')) {
176
+ await this.nodeContext.logStorage();
177
+ for (const plugin of this.registeredPlugins) {
178
+ await plugin.nodeContext?.logStorage();
179
+ }
180
+ }
181
+ // Log system info and create .matterbridge directory
182
+ await this.logNodeAndSystemInfo();
183
+ this.log.info(
184
+ // eslint-disable-next-line max-len
185
+ `Matterbridge version ${this.matterbridgeVersion} mode ${hasParameter('bridge') ? 'bridge' : ''}${hasParameter('childbridge') ? 'childbridge' : ''}${hasParameter('controller') ? 'controller' : ''} running on ${this.systemInformation.osType} ${this.systemInformation.osRelease} ${this.systemInformation.osPlatform} ${this.systemInformation.osArch}`);
186
+ // Check node version and throw error
187
+ requireMinNodeVersion(18);
188
+ // Register SIGINT SIGTERM signal handlers
189
+ this.registerSignalHandlers();
190
+ // Set matter.js logger level and format
191
+ Logger.defaultLogLevel = this.debugEnabled ? Level.DEBUG : Level.INFO;
192
+ Logger.format = Format.ANSI;
193
+ // Initialize NodeStorage
194
+ /*
195
+ this.log.debug('Creating node storage manager');
196
+ this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, 'storage'), logging: false });
197
+ this.log.debug('Creating node storage context for matterbridge');
198
+ this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
199
+ // Get the plugins from node storage
200
+ this.registeredPlugins = await this.nodeContext.get<RegisteredPlugin[]>('plugins', []);
201
+ for (const plugin of this.registeredPlugins) {
202
+ this.log.debug(`Creating node storage context for plugin ${plugin.name}`);
203
+ plugin.nodeContext = await this.nodeStorage.createStorage(plugin.name);
204
+ await plugin.nodeContext.set<string>('name', plugin.name);
205
+ await plugin.nodeContext.set<string>('type', plugin.type);
206
+ await plugin.nodeContext.set<string>('path', plugin.path);
207
+ await plugin.nodeContext.set<string>('version', plugin.version);
208
+ await plugin.nodeContext.set<string>('description', plugin.description);
209
+ await plugin.nodeContext.set<string>('author', plugin.author);
210
+ }
211
+ */
188
212
  // Parse command line
189
213
  this.parseCommandLine();
190
214
  }
@@ -475,10 +499,16 @@ export class Matterbridge extends EventEmitter {
475
499
  process.removeAllListeners('SIGTERM');
476
500
  // Calling the shutdown functions with a reason
477
501
  for (const plugin of this.registeredPlugins) {
502
+ if (!plugin.enabled)
503
+ continue;
504
+ this.log.info(`*Shutting down plugin ${plg}${plugin.name}${nf}`);
478
505
  if (plugin.platform) {
479
506
  await plugin.platform.onShutdown('Matterbridge is closing: ' + message);
480
507
  await this.savePluginConfig(plugin);
481
508
  }
509
+ else {
510
+ this.log.warn(`Plugin ${plg}${plugin.name}${er} platform not found`);
511
+ }
482
512
  }
483
513
  // Set reachability to false
484
514
  /*
@@ -491,7 +521,6 @@ export class Matterbridge extends EventEmitter {
491
521
  }
492
522
  this.log.debug(`*-- device: ${dev}${registeredDevice.device.name}${db} plugin ${plg}${registeredDevice.plugin}${db} type ${GREEN}${plugin.type}${db}`);
493
523
  if (this.bridgeMode === 'bridge') registeredDevice.device.setBridgedDeviceReachability(false);
494
- if (this.bridgeMode === 'childbridge' && plugin.type === 'DynamicPlatform') plugin.aggregator?.removeBridgedDevice(registeredDevice.device);
495
524
  if (this.bridgeMode === 'childbridge') plugin.commissioningServer?.setReachability(false);
496
525
  if (this.bridgeMode === 'childbridge' && plugin.type === 'AccessoryPlatform') this.setReachableAttribute(registeredDevice.device, false);
497
526
  if (this.bridgeMode === 'childbridge' && plugin.type === 'DynamicPlatform') registeredDevice.device.setBridgedDeviceReachability(false);
@@ -599,7 +628,7 @@ export class Matterbridge extends EventEmitter {
599
628
  this.registeredDevices.push({ plugin: pluginName, device, added: false });
600
629
  if (plugin.registeredDevices !== undefined)
601
630
  plugin.registeredDevices++;
602
- this.log.info(`Registered device ${dev}${device.deviceName}${nf} (${dev}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
631
+ this.log.info(`Registered device (${plugin.registeredDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
603
632
  }
604
633
  }
605
634
  /**
@@ -635,7 +664,7 @@ export class Matterbridge extends EventEmitter {
635
664
  this.registeredDevices.push({ plugin: pluginName, device, added: false });
636
665
  if (plugin.registeredDevices !== undefined)
637
666
  plugin.registeredDevices++;
638
- this.log.info(`Registered bridged device ${dev}${device.deviceName}${nf} (${dev}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
667
+ this.log.info(`Registered bridged device (${plugin.registeredDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
639
668
  }
640
669
  }
641
670
  /**
@@ -661,7 +690,7 @@ export class Matterbridge extends EventEmitter {
661
690
  return;
662
691
  }
663
692
  if (this.bridgeMode === 'childbridge' && !plugin.connected) {
664
- this.log.warn(`Not removing bridged device ${dev}${device.deviceName}${wr} (${dev}${device.name}${wr}) plugin ${plg}${pluginName}${wr} not connected`);
693
+ this.log.warn(`Removing bridged device ${dev}${device.deviceName}${wr} (${dev}${device.name}${wr}) plugin ${plg}${pluginName}${wr} not connected`);
665
694
  return;
666
695
  }
667
696
  // Register and add the device to matterbridge aggregator in bridge mode
@@ -673,11 +702,11 @@ export class Matterbridge extends EventEmitter {
673
702
  return;
674
703
  }
675
704
  });
705
+ this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
676
706
  if (plugin.registeredDevices !== undefined)
677
707
  plugin.registeredDevices--;
678
708
  if (plugin.addedDevices !== undefined)
679
709
  plugin.addedDevices--;
680
- this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
681
710
  }
682
711
  // Only register the device in childbridge mode
683
712
  if (this.bridgeMode === 'childbridge') {
@@ -1073,6 +1102,11 @@ export class Matterbridge extends EventEmitter {
1073
1102
  return;
1074
1103
  }
1075
1104
  if (this.bridgeMode === 'controller') {
1105
+ if (!this.mattercontrollerContext) {
1106
+ this.log.error('No matter controller context initialized');
1107
+ await this.cleanup('No matter controller context initialized');
1108
+ return;
1109
+ }
1076
1110
  this.log.info('Creating matter commissioning controller');
1077
1111
  this.commissioningController = new CommissioningController({
1078
1112
  autoConnect: false,
@@ -1082,15 +1116,124 @@ export class Matterbridge extends EventEmitter {
1082
1116
  this.log.info('Starting matter server');
1083
1117
  await this.matterServer.start();
1084
1118
  this.log.info('Matter server started');
1119
+ if (hasParameter('pairingcode')) {
1120
+ const pairingCode = getParameter('pairingcode');
1121
+ const ip = this.mattercontrollerContext.has('ip') ? this.mattercontrollerContext.get('ip') : undefined;
1122
+ const port = this.mattercontrollerContext.has('port') ? this.mattercontrollerContext.get('port') : undefined;
1123
+ let longDiscriminator, setupPin, shortDiscriminator;
1124
+ if (pairingCode !== undefined) {
1125
+ const pairingCodeCodec = ManualPairingCodeCodec.decode(pairingCode);
1126
+ shortDiscriminator = pairingCodeCodec.shortDiscriminator;
1127
+ longDiscriminator = undefined;
1128
+ setupPin = pairingCodeCodec.passcode;
1129
+ this.log.info(`Data extracted from pairing code: ${Logger.toJSON(pairingCodeCodec)}`);
1130
+ }
1131
+ else {
1132
+ longDiscriminator = this.mattercontrollerContext.get('longDiscriminator', 3840);
1133
+ if (longDiscriminator > 4095)
1134
+ throw new Error('Discriminator value must be less than 4096');
1135
+ setupPin = this.mattercontrollerContext.get('pin', 20202021);
1136
+ }
1137
+ if ((shortDiscriminator === undefined && longDiscriminator === undefined) || setupPin === undefined) {
1138
+ throw new Error('Please specify the longDiscriminator of the device to commission with -longDiscriminator or provide a valid passcode with -passcode');
1139
+ }
1140
+ const commissioningOptions = {
1141
+ regulatoryLocation: GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor,
1142
+ regulatoryCountryCode: 'XX',
1143
+ };
1144
+ const options = {
1145
+ commissioning: commissioningOptions,
1146
+ discovery: {
1147
+ knownAddress: ip !== undefined && port !== undefined ? { ip, port, type: 'udp' } : undefined,
1148
+ identifierData: longDiscriminator !== undefined ? { longDiscriminator } : shortDiscriminator !== undefined ? { shortDiscriminator } : {},
1149
+ },
1150
+ passcode: setupPin,
1151
+ };
1152
+ //this.log.info(`Commissioning ... ${JSON.stringify(options)}`);
1153
+ this.log.info('Commissioning ...', options);
1154
+ const nodeId = await this.commissioningController.commissionNode(options);
1155
+ this.mattercontrollerContext.set('nodeId', nodeId.nodeId);
1156
+ this.log.info(`Commissioning successfully done with nodeId: ${nodeId.nodeId}`);
1157
+ // eslint-disable-next-line no-console
1158
+ this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1159
+ } // (hasParameter('pairingcode'))
1085
1160
  if (hasParameter('discover')) {
1086
1161
  //const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1087
1162
  //console.log(discover);
1088
1163
  }
1089
- this.log.info(`Commissioning controller is already commisioned: ${this.commissioningController.isCommissioned()}`);
1090
- const nodes = this.commissioningController.getCommissionedNodes();
1091
- nodes.forEach(async (nodeId) => {
1092
- this.log.warn(`Connecting to commissioned node: ${nodeId}`);
1093
- });
1164
+ const nodeIds = this.commissioningController.getCommissionedNodes();
1165
+ this.log.info(`***Commissioning controller has ${nodeIds.length} nodes commisioned: ${this.commissioningController.isCommissioned()}`);
1166
+ for (const nodeId of nodeIds) {
1167
+ this.log.info(`***Connecting to commissioned node: ${nodeId}`);
1168
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1169
+ const node = await this.commissioningController.connectNode(nodeId, {
1170
+ attributeChangedCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, attributeName }, value }) => this.log.info(`***mattributeChangedCallback ${peerNodeId}: Attribute ${nodeId}/${endpointId}/${clusterId}/${attributeName} changed to ${Logger.toJSON(value)}`),
1171
+ eventTriggeredCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, eventName }, events }) => this.log.info(`***eventTriggeredCallback ${peerNodeId}: Event ${nodeId}/${endpointId}/${clusterId}/${eventName} triggered with ${Logger.toJSON(events)}`),
1172
+ stateInformationCallback: (peerNodeId, info) => {
1173
+ switch (info) {
1174
+ case NodeStateInformation.Connected:
1175
+ this.log.info(`***stateInformationCallback ${peerNodeId}: Node ${nodeId} connected`);
1176
+ break;
1177
+ case NodeStateInformation.Disconnected:
1178
+ this.log.info(`***stateInformationCallback ${peerNodeId}: Node ${nodeId} disconnected`);
1179
+ break;
1180
+ case NodeStateInformation.Reconnecting:
1181
+ this.log.info(`***stateInformationCallback ${peerNodeId}: Node ${nodeId} reconnecting`);
1182
+ break;
1183
+ case NodeStateInformation.WaitingForDeviceDiscovery:
1184
+ this.log.info(`***stateInformationCallback ${peerNodeId}: Node ${nodeId} waiting for device discovery`);
1185
+ break;
1186
+ case NodeStateInformation.StructureChanged:
1187
+ this.log.info(`***stateInformationCallback ${peerNodeId}: Node ${nodeId} structure changed`);
1188
+ break;
1189
+ case NodeStateInformation.Decommissioned:
1190
+ this.log.info(`***stateInformationCallback ${peerNodeId}: Node ${nodeId} decommissioned`);
1191
+ break;
1192
+ default:
1193
+ this.log.info(`***stateInformationCallback ${peerNodeId}: Node ${nodeId} NodeStateInformation.${info}`);
1194
+ break;
1195
+ }
1196
+ },
1197
+ });
1198
+ node.logStructure();
1199
+ // Get the interaction client
1200
+ const interactionClient = await node.getInteractionClient();
1201
+ let cluster;
1202
+ let attributes;
1203
+ // Log BasicInformationCluster
1204
+ cluster = BasicInformationCluster;
1205
+ attributes = await interactionClient.getMultipleAttributes({
1206
+ attributes: [{ clusterId: cluster.id }],
1207
+ });
1208
+ this.log.warn(`Cluster: ${cluster.name} attributes:`);
1209
+ attributes.forEach((attribute) => {
1210
+ this.log.info(
1211
+ // eslint-disable-next-line max-len
1212
+ `- endpoint: ${attribute.path.endpointId} clusterId: ${attribute.path.clusterId} id: ${attribute.path.attributeId} name: ${attribute.path.attributeName}: ${typeof attribute.value === 'object' ? stringify(attribute.value) : attribute.value}`);
1213
+ });
1214
+ // Log PowerSourceCluster
1215
+ cluster = PowerSourceCluster;
1216
+ attributes = await interactionClient.getMultipleAttributes({
1217
+ attributes: [{ clusterId: cluster.id }],
1218
+ });
1219
+ this.log.warn(`Cluster: ${cluster.name} attributes:`);
1220
+ attributes.forEach((attribute) => {
1221
+ this.log.info(
1222
+ // eslint-disable-next-line max-len
1223
+ `- endpoint: ${attribute.path.endpointId} clusterId: ${attribute.path.clusterId} id: ${attribute.path.attributeId} name: ${attribute.path.attributeName}: ${typeof attribute.value === 'object' ? stringify(attribute.value) : attribute.value}`);
1224
+ });
1225
+ // Log ThreadNetworkDiagnostics
1226
+ cluster = ThreadNetworkDiagnosticsCluster;
1227
+ attributes = await interactionClient.getMultipleAttributes({
1228
+ attributes: [{ clusterId: cluster.id }],
1229
+ });
1230
+ this.log.warn(`Cluster: ${cluster.name} attributes:`);
1231
+ attributes.forEach((attribute) => {
1232
+ this.log.info(
1233
+ // eslint-disable-next-line max-len
1234
+ `- endpoint: ${attribute.path.endpointId} clusterId: ${attribute.path.clusterId} id: ${attribute.path.attributeId} name: ${attribute.path.attributeName}: ${typeof attribute.value === 'object' ? stringify(attribute.value) : attribute.value}`);
1235
+ });
1236
+ }
1094
1237
  }
1095
1238
  if (this.bridgeMode === 'bridge') {
1096
1239
  // Plugins are loaded by loadPlugin on startup and plugin.loaded is set to true
@@ -1643,9 +1786,24 @@ export class Matterbridge extends EventEmitter {
1643
1786
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
1644
1787
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
1645
1788
  // Global node_modules directory
1789
+ /*
1646
1790
  this.globalModulesDirectory = await this.getGlobalNodeModules();
1647
1791
  this.matterbridgeInformation.globalModulesDirectory = this.globalModulesDirectory;
1648
1792
  this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
1793
+ */
1794
+ if (this.nodeContext)
1795
+ this.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
1796
+ this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
1797
+ this.getGlobalNodeModules()
1798
+ .then(async (globalModulesDirectory) => {
1799
+ this.globalModulesDirectory = globalModulesDirectory;
1800
+ this.matterbridgeInformation.globalModulesDirectory = this.globalModulesDirectory;
1801
+ this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
1802
+ await this.nodeContext?.set('globalModulesDirectory', this.globalModulesDirectory);
1803
+ })
1804
+ .catch((error) => {
1805
+ this.log.error(`Error getting global node_modules directory: ${error}`);
1806
+ });
1649
1807
  // Create the data directory .matterbridge in the home directory
1650
1808
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
1651
1809
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
@@ -1699,12 +1857,28 @@ export class Matterbridge extends EventEmitter {
1699
1857
  this.matterbridgeVersion = packageJson.version;
1700
1858
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeVersion;
1701
1859
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
1860
+ // Matterbridge latest version
1861
+ /*
1702
1862
  this.matterbridgeLatestVersion = await this.getLatestVersion('matterbridge');
1703
1863
  this.matterbridgeInformation.matterbridgeLatestVersion = this.matterbridgeLatestVersion;
1704
1864
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
1705
- if (this.matterbridgeVersion !== this.matterbridgeLatestVersion) {
1706
- this.log.warn(`Matterbridge is out of date. Current version: ${this.matterbridgeVersion}, Latest version: ${this.matterbridgeLatestVersion}`);
1707
- }
1865
+ */
1866
+ if (this.nodeContext)
1867
+ this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', '');
1868
+ this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
1869
+ this.getLatestVersion('matterbridge')
1870
+ .then(async (matterbridgeLatestVersion) => {
1871
+ this.matterbridgeLatestVersion = matterbridgeLatestVersion;
1872
+ this.matterbridgeInformation.matterbridgeLatestVersion = this.matterbridgeLatestVersion;
1873
+ this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
1874
+ await this.nodeContext?.set('matterbridgeLatestVersion', this.matterbridgeLatestVersion);
1875
+ if (this.matterbridgeVersion !== this.matterbridgeLatestVersion) {
1876
+ this.log.warn(`Matterbridge is out of date. Current version: ${this.matterbridgeVersion}, Latest version: ${this.matterbridgeLatestVersion}`);
1877
+ }
1878
+ })
1879
+ .catch((error) => {
1880
+ this.log.error(`Error getting Matterbridge latest version: ${error}`);
1881
+ });
1708
1882
  // Current working directory
1709
1883
  const currentDir = process.cwd();
1710
1884
  this.log.debug(`Current Working Directory: ${currentDir}`);
@@ -1876,7 +2050,7 @@ export class Matterbridge extends EventEmitter {
1876
2050
  // Endpoint to receive commands
1877
2051
  this.expressApp.post('/api/command/:command/:param', async (req, res) => {
1878
2052
  const command = req.params.command;
1879
- const param = req.params.param;
2053
+ let param = req.params.param;
1880
2054
  this.log.debug(`The frontend sent /api/command/${command}/${param}`);
1881
2055
  if (!command) {
1882
2056
  res.status(400).json({ error: 'No command provided' });
@@ -1912,9 +2086,55 @@ export class Matterbridge extends EventEmitter {
1912
2086
  if (command === 'update') {
1913
2087
  this.log.warn(`The /api/command/${command} is not yet implemented`);
1914
2088
  }
1915
- // Handle the command addplugin from Header
2089
+ // Handle the command addplugin from Home C:\Users\lligu\GitHub\matterbridge-example-accessory-platform
1916
2090
  if (command === 'addplugin') {
1917
- this.log.warn(`The /api/command/${command}/${param} is not yet implemented`);
2091
+ param = param.replace(/\*/g, '\\');
2092
+ if (this.registeredPlugins.find((plugin) => plugin.name === param)) {
2093
+ this.log.warn(`Plugin ${plg}${param}${wr} already added to matterbridge`);
2094
+ res.json({ message: 'Command received' });
2095
+ return;
2096
+ }
2097
+ const packageJsonPath = await this.resolvePluginName(param);
2098
+ if (!packageJsonPath) {
2099
+ this.log.error(`Error resolving plugin ${plg}${param}${er}`);
2100
+ res.json({ message: 'Command received' });
2101
+ return;
2102
+ }
2103
+ this.log.debug(`Loading plugin from ${plg}${packageJsonPath}${db}`);
2104
+ try {
2105
+ // Load the package.json of the plugin
2106
+ const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
2107
+ const plugin = { path: packageJsonPath, type: '', name: packageJson.name, version: packageJson.version, description: packageJson.description, author: packageJson.author, enabled: true };
2108
+ if (await this.loadPlugin(plugin)) {
2109
+ this.registeredPlugins.push(plugin);
2110
+ await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
2111
+ this.log.info(`Plugin ${plg}${packageJsonPath}${nf} type ${plugin.type} added to matterbridge. Restart required.`);
2112
+ }
2113
+ else {
2114
+ this.log.error(`Error adding plugin ${plg}${packageJsonPath}${er}`);
2115
+ }
2116
+ }
2117
+ catch (error) {
2118
+ this.log.error(`Error adding plugin ${plg}${packageJsonPath}${er}`);
2119
+ res.json({ message: 'Command received' });
2120
+ return;
2121
+ }
2122
+ }
2123
+ // Handle the command removeplugin from Home
2124
+ if (command === 'removeplugin') {
2125
+ const index = this.registeredPlugins.findIndex((registeredPlugin) => registeredPlugin.name === param);
2126
+ if (index !== -1) {
2127
+ if (this.registeredPlugins[index].platform) {
2128
+ await this.registeredPlugins[index].platform?.onShutdown('The plugin has been removed.');
2129
+ await this.savePluginConfig(this.registeredPlugins[index]);
2130
+ }
2131
+ this.registeredPlugins.splice(index, 1);
2132
+ await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
2133
+ this.log.info(`Plugin ${plg}${param}${nf} removed from matterbridge`);
2134
+ }
2135
+ else {
2136
+ this.log.warn(`Plugin ${plg}${param}${wr} not registered in matterbridge`);
2137
+ }
1918
2138
  }
1919
2139
  // Handle the command enableplugin from Home
1920
2140
  if (command === 'enableplugin') {
@@ -1977,10 +2197,12 @@ export class Matterbridge extends EventEmitter {
1977
2197
  attributes += `Position: ${clusterServer.getCurrentPositionAttribute()} `;
1978
2198
  if (clusterServer.name === 'WindowCovering')
1979
2199
  attributes += `Cover position: ${clusterServer.attributes.currentPositionLiftPercent100ths.getLocal() / 100}% `;
2200
+ if (clusterServer.name === 'DoorLock')
2201
+ attributes += `State: ${clusterServer.attributes.lockState.getLocal() === 1 ? 'Locked' : 'Not locked'} `;
1980
2202
  if (clusterServer.name === 'LevelControl')
1981
2203
  attributes += `Level: ${clusterServer.getCurrentLevelAttribute()}% `;
1982
2204
  if (clusterServer.name === 'ColorControl')
1983
- attributes += `Hue: ${clusterServer.getCurrentHueAttribute()} Saturation: ${clusterServer.getCurrentSaturationAttribute()}% `;
2205
+ attributes += `Hue: ${Math.round(clusterServer.getCurrentHueAttribute())} Saturation: ${Math.round(clusterServer.getCurrentSaturationAttribute())}% `;
1984
2206
  if (clusterServer.name === 'BooleanState')
1985
2207
  attributes += `Contact: ${clusterServer.getStateValueAttribute()} `;
1986
2208
  if (clusterServer.name === 'OccupancySensing')