matterbridge 3.3.0-dev-20251004-43d8106 → 3.3.1-dev-20251007-4e5eaac

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
@@ -23,7 +23,35 @@ Advantages:
23
23
  - isolation between threads;
24
24
  - individual plugin isolation in childbridge mode;
25
25
 
26
- ## [3.3.0] - Not released
26
+ ## [3.3.1] - Not released
27
+
28
+ ### Breaking Changes
29
+
30
+ - [frontend]: When a plugin is first installed, it will not be anymore started to allow to configure it before restarting.
31
+ - [index]: Removed old plugin api compatibility since it was changed one year ago.
32
+
33
+ ### Added
34
+
35
+ - [network]: Added getInterfaceDetails() function.
36
+ - [network]: Added getInterfaceName() function.
37
+ - [network]: Optimized code.
38
+ - [matterbridge]: Added SharedMatterbridge readonly type.
39
+ - [thread]: Add BroadcastServer to frontend plugins and devices.
40
+
41
+ ### Changed
42
+
43
+ - [package]: Updated dependencies.
44
+ - [matterbridge]: Removed matterbridgeInformation. It will be recreated when the frontend requires it.
45
+ - [frontend]: Bumped `frontend` version to 3.2.1.
46
+ - [frontend]: Refactored InstallProgressDialog.
47
+ - [spawn]: Refactored spawnCommand for compatibility with InstallProgressDialog.
48
+ - [matter.js]: Bumped `matter.js` to 0.15.5. Thanks matter.js!
49
+
50
+ <a href="https://www.buymeacoffee.com/luligugithub">
51
+ <img src="bmc-button.svg" alt="Buy me a coffee" width="80">
52
+ </a>
53
+
54
+ ## [3.3.0] - 2025-10-03
27
55
 
28
56
  ### Development Breaking Changes Notice
29
57
 
@@ -98,8 +126,6 @@ In this phase (matterbridge `3.4.x`) all plugins will not build and will not run
98
126
  - [package]: Updated dependencies.
99
127
  - [frontend]: General improvements and small bug fixes.
100
128
 
101
- ### Fixed
102
-
103
129
  <a href="https://www.buymeacoffee.com/luligugithub">
104
130
  <img src="bmc-button.svg" alt="Buy me a coffee" width="80">
105
131
  </a>
package/README.md CHANGED
@@ -78,10 +78,14 @@ After follow the guidelines for the [Docker configurations](README-DOCKER.md).
78
78
 
79
79
  I suggest using Docker for its simplicity.
80
80
 
81
- Since as stated in the Matter specifications "Matter aims to build a universal IPv6-based communication protocol for smart home devices", ipv6 should be enabled in the network.
81
+ Since Matter is designed as "a universal IPv6-based communication protocol for smart home devices" (per the Matter specifications), **IPv6 must be enabled on your local network (LAN)**.
82
+
83
+ **Important:** You only need IPv6 on your local network - it doesn't matter if your internet provider doesn't provide IPv6 on the internet side (WAN).
82
84
 
83
85
  Avoid using VLAN and firewall blocking the communications between the controllers and Matterbridge.
84
86
 
87
+ To pair matterbridge, you need a matter enabled controller (Apple Home, Smart Things, Google Home, Alexa, Hose Assistant etc.).
88
+
85
89
  ## Installation
86
90
 
87
91
  Follow these steps to install Matterbridge:
@@ -574,3 +578,7 @@ Click on the badge below to get started:
574
578
  </a>
575
579
 
576
580
  Thank you for your support!
581
+
582
+ # Licensing
583
+
584
+ Matterbridge is licensed under the [Apache License 2.0](./LICENSE).
@@ -0,0 +1,73 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { BroadcastChannel } from 'node:worker_threads';
3
+ import { debugStringify } from 'node-ansi-logger';
4
+ export class BroadcastServer extends EventEmitter {
5
+ name;
6
+ log;
7
+ channel;
8
+ broadcastChannel;
9
+ constructor(name, log, channel = 'broadcast-channel') {
10
+ super();
11
+ this.name = name;
12
+ this.log = log;
13
+ this.channel = channel;
14
+ this.broadcastChannel = new BroadcastChannel(this.channel);
15
+ this.broadcastChannel.onmessage = this.broadcastMessageHandler.bind(this);
16
+ }
17
+ close() {
18
+ this.broadcastChannel.onmessage = null;
19
+ this.broadcastChannel.close();
20
+ }
21
+ getUniqueId() {
22
+ return Math.floor(Math.random() * (999999 - 100000 + 1)) + 100000;
23
+ }
24
+ isWorkerRequest(msg, type) {
25
+ return typeof msg === 'object' && msg !== null && 'id' in msg && 'type' in msg && msg.type === type && !('response' in msg) && 'src' in msg && 'dst' in msg;
26
+ }
27
+ isWorkerResponse(msg, type) {
28
+ return typeof msg === 'object' && msg !== null && 'id' in msg && 'type' in msg && msg.type === type && 'response' in msg && 'src' in msg && 'dst' in msg;
29
+ }
30
+ broadcastMessageHandler(event) {
31
+ const data = event.data;
32
+ this.log.debug(`*Received broadcast message: ${debugStringify(data)}`);
33
+ this.emit('broadcast_message', data);
34
+ }
35
+ request(message) {
36
+ if (message.id === undefined) {
37
+ message.id = this.getUniqueId();
38
+ }
39
+ if (!this.isWorkerRequest(message, message.type)) {
40
+ this.log.error(`Invalid request message format for broadcast: ${debugStringify(message)}`);
41
+ return;
42
+ }
43
+ this.log.debug(`*Broadcasting message: ${debugStringify(message)}`);
44
+ this.broadcastChannel.postMessage(message);
45
+ }
46
+ respond(message) {
47
+ if (!this.isWorkerResponse(message, message.type)) {
48
+ this.log.error(`Invalid response message format for broadcast: ${debugStringify(message)}`);
49
+ return;
50
+ }
51
+ this.log.debug(`*Broadcasting message: ${debugStringify(message)}`);
52
+ this.broadcastChannel.postMessage(message);
53
+ }
54
+ async fetch(message) {
55
+ this.log.debug(`*Fetching message: ${debugStringify(message)}`);
56
+ return new Promise((resolve, reject) => {
57
+ const responseHandler = (msg) => {
58
+ if (this.isWorkerResponse(msg, message.type) && msg.id === message.id) {
59
+ clearTimeout(timeoutId);
60
+ this.off('broadcast_message', responseHandler);
61
+ this.log.debug(`*Fetch response: ${debugStringify(msg)}`);
62
+ resolve(msg);
63
+ }
64
+ };
65
+ this.on('broadcast_message', responseHandler);
66
+ this.request(message);
67
+ const timeoutId = setTimeout(() => {
68
+ this.off('broadcast_message', responseHandler);
69
+ reject(new Error(`Fetch timeout after 100ms for message id ${message.id}`));
70
+ }, 100);
71
+ });
72
+ }
73
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,13 +1,52 @@
1
- import { AnsiLogger, BLUE, er } from 'node-ansi-logger';
1
+ import { AnsiLogger, BLUE, CYAN, db, debugStringify, er, wr } from 'node-ansi-logger';
2
2
  import { dev } from './matterbridgeTypes.js';
3
+ import { BroadcastServer } from './broadcastServer.js';
3
4
  export class DeviceManager {
4
5
  _devices = new Map();
5
- matterbridge;
6
6
  log;
7
- constructor(matterbridge) {
8
- this.matterbridge = matterbridge;
9
- this.log = new AnsiLogger({ logName: 'DeviceManager', logTimestampFormat: 4, logLevel: matterbridge.log.logLevel });
7
+ server;
8
+ constructor() {
9
+ this.log = new AnsiLogger({ logName: 'DeviceManager', logTimestampFormat: 4, logLevel: "info" });
10
10
  this.log.debug('Matterbridge device manager starting...');
11
+ this.server = new BroadcastServer('devices', this.log);
12
+ this.server.on('broadcast_message', this.msgHandler.bind(this));
13
+ this.log.debug('Matterbridge device manager started');
14
+ }
15
+ destroy() {
16
+ this.server.close();
17
+ }
18
+ async msgHandler(msg) {
19
+ if (!this.server.isWorkerRequest(msg, msg.type))
20
+ return;
21
+ if (!msg.id || (msg.dst !== 'all' && msg.dst !== 'devices'))
22
+ return;
23
+ this.log.debug(`**Received request message ${CYAN}${msg.type}${db} from ${CYAN}${msg.src}${db}: ${debugStringify(msg)}${db}`);
24
+ switch (msg.type) {
25
+ case 'devices_length':
26
+ this.server.respond({ ...msg, id: msg.id, response: { length: this.length } });
27
+ break;
28
+ case 'devices_size':
29
+ this.server.respond({ ...msg, id: msg.id, response: { size: this.size } });
30
+ break;
31
+ case 'devices_has':
32
+ this.server.respond({ ...msg, id: msg.id, response: { has: this.has(msg.params.uniqueId) } });
33
+ break;
34
+ case 'devices_get':
35
+ this.server.respond({ ...msg, id: msg.id, response: { device: this.get(msg.params.uniqueId) } });
36
+ break;
37
+ case 'devices_set':
38
+ this.server.respond({ ...msg, id: msg.id, response: { device: this.set(msg.params.device) } });
39
+ break;
40
+ case 'devices_remove':
41
+ this.server.respond({ ...msg, id: msg.id, response: { success: this.remove(msg.params.device) } });
42
+ break;
43
+ case 'devices_clear':
44
+ this.clear();
45
+ this.server.respond({ ...msg, id: msg.id, response: { success: true } });
46
+ break;
47
+ default:
48
+ this.log.warn(`Unknown broadcast message ${CYAN}${msg.type}${wr} from ${CYAN}${msg.src}${wr}`);
49
+ }
11
50
  }
12
51
  get length() {
13
52
  return this._devices.size;