matterbridge 3.4.0-dev-20251121-a354bec → 3.4.0-dev-20251123-62db0d7

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.
@@ -88,6 +88,10 @@ export class BroadcastServer extends EventEmitter {
88
88
  this.log.debug(`Fetch response: ${debugStringify(msg)}`);
89
89
  resolve(msg);
90
90
  }
91
+ else if (this.isWorkerResponse(msg, message.type) && msg.id !== message.id) {
92
+ if (this.verbose)
93
+ this.log.debug(`Fetch received unrelated response: ${debugStringify(msg)}`);
94
+ }
91
95
  };
92
96
  this.on('broadcast_message', responseHandler);
93
97
  this.request(message);
@@ -184,7 +184,7 @@ export async function createMatterbridgeEnvironment(name) {
184
184
  matterbridge = await Matterbridge.loadInstance(false);
185
185
  expect(matterbridge).toBeDefined();
186
186
  expect(matterbridge).toBeInstanceOf(Matterbridge);
187
- matterbridge.matterbridgeVersion = '3.3.0';
187
+ matterbridge.matterbridgeVersion = '3.4.0';
188
188
  matterbridge.bridgeMode = 'bridge';
189
189
  matterbridge.rootDirectory = path.join('jest', name);
190
190
  matterbridge.homeDirectory = path.join('jest', name);
@@ -310,6 +310,13 @@ export function createTestEnvironment(name) {
310
310
  new MdnsService(environment);
311
311
  return environment;
312
312
  }
313
+ export async function destroyTestEnvironment() {
314
+ const mdns = environment.get(MdnsService);
315
+ if (mdns && typeof mdns[Symbol.asyncDispose] === 'function')
316
+ await mdns[Symbol.asyncDispose]();
317
+ if (mdns && typeof mdns.close === 'function')
318
+ await mdns.close();
319
+ }
313
320
  export async function flushAsync(ticks = 3, microTurns = 10, pause = 250) {
314
321
  for (let i = 0; i < ticks; i++)
315
322
  await new Promise((resolve) => setImmediate(resolve));
@@ -122,25 +122,13 @@ export class MatterbridgePlatform {
122
122
  this.log.debug(`The plugin ${CYAN}${config.name}${db} doesn't override onConfigChanged. Received new config.`);
123
123
  }
124
124
  saveConfig(config) {
125
- const plugin = this.matterbridge.plugins.get(this.name);
126
- if (!plugin) {
127
- throw new Error(`Plugin ${this.name} not found`);
128
- }
129
- this.matterbridge.plugins.saveConfigFromJson(plugin, config);
125
+ this.#server.request({ type: 'plugins_saveconfigfromjson', src: 'platform', dst: 'plugins', params: { name: this.name, config } });
130
126
  }
131
- getSchema() {
132
- const plugin = this.matterbridge.plugins.get(this.name);
133
- if (!plugin || !isValidObject(plugin.schemaJson)) {
134
- throw new Error(`Plugin ${this.name} not found`);
135
- }
136
- return plugin.schemaJson;
127
+ async getSchema() {
128
+ return (await this.#server.fetch({ type: 'plugins_getschema', src: 'platform', dst: 'plugins', params: { name: this.name } })).response.schema;
137
129
  }
138
130
  setSchema(schema) {
139
- const plugin = this.matterbridge.plugins.get(this.name);
140
- if (!plugin) {
141
- throw new Error(`Plugin ${this.name} not found`);
142
- }
143
- plugin.schemaJson = schema;
131
+ this.#server.request({ type: 'plugins_setschema', src: 'platform', dst: 'plugins', params: { name: this.name, schema } });
144
132
  }
145
133
  wssSendRestartRequired(snackbar = true, fixed = false) {
146
134
  this.#server.request({ type: 'frontend_restartrequired', src: 'platform', dst: 'frontend', params: { snackbar, fixed } });
@@ -183,7 +171,7 @@ export class MatterbridgePlatform {
183
171
  if (this.matterbridge.bridgeMode === 'bridge') {
184
172
  aggregator = this.matterbridge.aggregatorNode;
185
173
  }
186
- else if (this.matterbridge.bridgeMode === 'childbridge') {
174
+ else if (this.matterbridge.bridgeMode === 'childbridge' && this.type === 'DynamicPlatform') {
187
175
  aggregator = this.matterbridge.plugins.get(this.name)?.aggregatorNode;
188
176
  }
189
177
  if (aggregator) {
@@ -197,6 +185,7 @@ export class MatterbridgePlatform {
197
185
  return true;
198
186
  }
199
187
  }
188
+ this.log.warn(`Virtual device ${name} not created. Virtual devices are only supported in bridge mode and childbridge mode with a DynamicPlatform.`);
200
189
  return false;
201
190
  }
202
191
  async registerDevice(device) {
@@ -51,6 +51,7 @@ export class PluginManager extends EventEmitter {
51
51
  this.server.respond({ ...msg, response: { plugin: this.toApiPlugin(plugin) } });
52
52
  }
53
53
  else {
54
+ this.log.debug(`***Plugin ${plg}${msg.params.name}${db} not found in plugins_get`);
54
55
  this.server.respond({ ...msg, response: { plugin: undefined } });
55
56
  }
56
57
  }
@@ -158,6 +159,41 @@ export class PluginManager extends EventEmitter {
158
159
  }
159
160
  }
160
161
  break;
162
+ case 'plugins_getschema':
163
+ {
164
+ const plugin = this.get(msg.params.name);
165
+ if (plugin) {
166
+ this.server.respond({ ...msg, response: { schema: plugin.schemaJson } });
167
+ }
168
+ else {
169
+ this.server.respond({ ...msg, response: { schema: undefined } });
170
+ }
171
+ }
172
+ break;
173
+ case 'plugins_setschema':
174
+ {
175
+ const plugin = this.get(msg.params.name);
176
+ if (plugin) {
177
+ plugin.schemaJson = msg.params.schema;
178
+ this.server.respond({ ...msg, response: { success: true } });
179
+ }
180
+ else {
181
+ this.server.respond({ ...msg, response: { success: false } });
182
+ }
183
+ }
184
+ break;
185
+ case 'plugins_saveconfigfromjson':
186
+ {
187
+ const plugin = this.get(msg.params.name);
188
+ if (plugin) {
189
+ this.saveConfigFromJson(plugin, msg.params.config, msg.params.restartRequired);
190
+ this.server.respond({ ...msg, response: { success: true } });
191
+ }
192
+ else {
193
+ this.server.respond({ ...msg, response: { success: false } });
194
+ }
195
+ }
196
+ break;
161
197
  default:
162
198
  if (this.verbose)
163
199
  this.log.debug(`Unknown broadcast message ${CYAN}${msg.type}${db} from ${CYAN}${msg.src}${db}`);
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.4.0-dev-20251121-a354bec",
3
+ "version": "3.4.0-dev-20251123-62db0d7",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "matterbridge",
9
- "version": "3.4.0-dev-20251121-a354bec",
9
+ "version": "3.4.0-dev-20251123-62db0d7",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@matter/main": "0.15.6",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.4.0-dev-20251121-a354bec",
3
+ "version": "3.4.0-dev-20251123-62db0d7",
4
4
  "description": "Matterbridge plugin manager for Matter",
5
5
  "author": "https://github.com/Luligu",
6
6
  "license": "Apache-2.0",
@@ -11,13 +11,14 @@ import https from 'node:https';
11
11
  * - ZCL_OUT: output path for zcl.json (default: chip/zcl.json)
12
12
  * - ZCL_BRANCH: connectedhomeip branch to fetch from (default: v1.4-branch)
13
13
  */
14
- const OUT_PATH = process.env.ZCL_OUT || 'chip/zcl.json';
15
14
  // Single branch strategy from online only
16
- const BRANCH = process.env.ZCL_BRANCH || 'v1.4-branch';
17
- const ZCL_BASE = `https://raw.githubusercontent.com/project-chip/connectedhomeip/${BRANCH}/src/app/zap-templates/zcl/`;
18
- const ZCL_JSON_URL = ZCL_BASE + 'zcl.json';
19
- const XML_BASE = ZCL_BASE + 'data-model/chip/';
20
- const MANUFACTURERS_URL = ZCL_BASE + 'data-model/manufacturers.xml';
15
+ const BRANCH = process.env.ZCL_BRANCH || 'v1.4.2-branch';
16
+ const OUT_ZCL_PATH = process.env.ZCL_OUT || `chip/${BRANCH}/zcl.json`;
17
+ const OUT_MANUFACTURERS_PATH = process.env.MANUFACTURERS_OUT || `chip/${BRANCH}/manufacturers.xml`;
18
+ const ZCL_BASE_URL = `https://raw.githubusercontent.com/project-chip/connectedhomeip/${BRANCH}/src/app/zap-templates/zcl/`;
19
+ const ZCL_JSON_URL = ZCL_BASE_URL + 'zcl.json';
20
+ const MANUFACTURERS_URL = ZCL_BASE_URL + 'data-model/manufacturers.xml';
21
+ const XML_BASE_URL = ZCL_BASE_URL + 'data-model/chip/';
21
22
 
22
23
  function fetchUrl(url) {
23
24
  return new Promise((resolve, reject) => {
@@ -37,7 +38,7 @@ function fetchUrl(url) {
37
38
  }
38
39
 
39
40
  async function main() {
40
- await mkdir(dirname(OUT_PATH), { recursive: true });
41
+ await mkdir(dirname(OUT_ZCL_PATH), { recursive: true });
41
42
  // Always fetch online from the specified branch
42
43
  const data = await fetchUrl(ZCL_JSON_URL);
43
44
 
@@ -52,15 +53,14 @@ async function main() {
52
53
  process.stderr.write('Warning: zcl.json does not contain expected ZAP ZCL properties (xmlFile). Saving anyway for manual inspection.\n');
53
54
  }
54
55
 
55
- await writeFile(OUT_PATH, JSON.stringify(parsed, null, 2));
56
- process.stderr.write(`Saved ${OUT_PATH}.\n`);
56
+ await writeFile(OUT_ZCL_PATH, JSON.stringify(parsed, null, 2));
57
+ process.stderr.write(`Saved ${OUT_ZCL_PATH}. Branch=${BRANCH}\n`);
57
58
 
58
59
  // Also fetch manufacturers.xml to chip/manufacturers.xml from the same branch
59
60
  try {
60
- const outManu = 'chip/manufacturers.xml';
61
61
  const manuContent = await fetchUrl(MANUFACTURERS_URL);
62
- await writeFile(outManu, manuContent);
63
- process.stderr.write('Saved chip/manufacturers.xml.\n');
62
+ await writeFile(OUT_MANUFACTURERS_PATH, manuContent);
63
+ process.stderr.write(`Saved ${OUT_MANUFACTURERS_PATH}. Branch=${BRANCH}\n`);
64
64
  } catch (e) {
65
65
  process.stderr.write(`Warning: failed to fetch manufacturers.xml (${e.message}).\n`);
66
66
  }
@@ -70,14 +70,14 @@ async function main() {
70
70
  if (xmlFiles.length === 0) {
71
71
  process.stderr.write('No xmlFile entries found; skipping XML fetch.\n');
72
72
  } else {
73
- const outXmlBase = 'chip/xml';
73
+ const outXmlBase = `chip/${BRANCH}/xml`;
74
74
  await mkdir(outXmlBase, { recursive: true });
75
75
  let ok = 0;
76
76
  let fail = 0;
77
77
  for (const fileName of xmlFiles) {
78
78
  const relative = fileName.trim();
79
79
  try {
80
- const url = XML_BASE + relative;
80
+ const url = XML_BASE_URL + relative;
81
81
  const content = await fetchUrl(url);
82
82
  const outPath = pathJoin(outXmlBase, relative.replaceAll('/', pathSep));
83
83
  await mkdir(dirname(outPath), { recursive: true });