matterbridge 3.0.0-edge.13 → 3.0.0-edge.15

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
@@ -51,12 +51,17 @@ Modified clusters:
51
51
  - [deviceTypes]: Added Robotic device type.
52
52
  - [deviceTypes]: Added Appliances device types.
53
53
  - [frontend]: Added the matterbridge aggregator serialNumber in the QRDiv.
54
+ - [frontend]: Added Power column in the Devices panel of the Home page.
55
+ - [frontend]: Added support for appliances and robot in IconView.
56
+ - [parameter]: Added getIntArrayParameter and getStringArrayParameter.
54
57
 
55
58
  ### Changed
56
59
 
57
60
  - [package]: Updated package.
58
61
  - [package]: Updated express to v5.1.0.
59
62
  - [package]: Updated dependencies.
63
+ - [frontend]: Frontend v.2.6.3.
64
+ - [frontend]: Changed icons with mdiIcons in IconView.
60
65
  - [package]: Added tsconfig.jest.json with "isolatedModules": true for ts-jest.
61
66
  - [deviceTypes]: Updated device types to Matter 1.4.
62
67
  - [clusters]: Updated cluster helpers to Matter 1.4.
@@ -67,6 +72,11 @@ Modified clusters:
67
72
  - [matter.js]: Update to 0.13.0-alpha.0-20250415-475996bb5.
68
73
  - [matter.js]: Update to 0.13.0-alpha.0-20250418-8cfc0b832.
69
74
  - [matter.js]: Update to 0.13.0-alpha.0-20250420-9f45e4f77.
75
+ - [matter.js]: Update to 0.13.0-alpha.0-20250422-0d27f26be.
76
+ - [matter.js]: Update to 0.13.0-alpha.0-20250423-8917d1d1d.
77
+ - [matter.js]: Update to 0.13.0-alpha.0-20250424-4760af1f3.
78
+ - [matter.js]: Update to 0.13.0-alpha.0-20250425-94b33ff98.
79
+ - [matter.js]: Update to 0.13.0-alpha.0-20250427-e7df8aa45.
70
80
  - [help]: Updated cli help screen.
71
81
  - [logger]: Improved frontend logger cleaning.
72
82
 
package/README-DOCKER.md CHANGED
@@ -38,7 +38,7 @@ docker exec -it matterbridge curl -v http://localhost:8283/health
38
38
 
39
39
  This will create the required directories in your home directory if they don't exist
40
40
 
41
- ```
41
+ ```bash
42
42
  cd ~
43
43
  mkdir -p ./Matterbridge
44
44
  mkdir -p ./.matterbridge
@@ -51,7 +51,7 @@ You may need to adapt the script to your setup.
51
51
 
52
52
  If you don't want to use sudo with docker commands, run this command:
53
53
 
54
- ```
54
+ ```bash
55
55
  sudo groupadd docker
56
56
  sudo usermod -aG docker $USER
57
57
  ```
@@ -62,7 +62,7 @@ After adding your user to the docker group, you need to log out and log back in
62
62
 
63
63
  The container must have full access to the host network (needed for mdns).
64
64
 
65
- ```
65
+ ```bash
66
66
  sudo docker run --name matterbridge \
67
67
  -v /home/<USER>/Matterbridge:/root/Matterbridge \
68
68
  -v /home/<USER>/.matterbridge:/root/.matterbridge \
@@ -95,55 +95,55 @@ copy it in the home directory or edit the existing one to add the matterbridge s
95
95
 
96
96
  Then start docker compose with:
97
97
 
98
- ```
98
+ ```bash
99
99
  docker compose up -d
100
100
  ```
101
101
 
102
102
  ### Stop with docker compose
103
103
 
104
- ```
104
+ ```bash
105
105
  docker compose down
106
106
  ```
107
107
 
108
108
  ### Update with docker compose
109
109
 
110
- ```
110
+ ```bash
111
111
  docker compose pull
112
112
  ```
113
113
 
114
114
  ### Inspect the container
115
115
 
116
- ```
116
+ ```bash
117
117
  docker container inspect matterbridge
118
118
  ```
119
119
 
120
120
  ### Start the Docker container
121
121
 
122
- ```
122
+ ```bash
123
123
  docker start matterbridge
124
124
  ```
125
125
 
126
126
  ### Stop the Docker container
127
127
 
128
- ```
128
+ ```bash
129
129
  docker stop matterbridge
130
130
  ```
131
131
 
132
132
  ### Restart the Docker container
133
133
 
134
- ```
134
+ ```bash
135
135
  docker restart matterbridge
136
136
  ```
137
137
 
138
138
  ### Shows the logs
139
139
 
140
- ```
140
+ ```bash
141
141
  docker logs matterbridge
142
142
  ```
143
143
 
144
144
  ### Shows the logs for a time interval
145
145
 
146
- ```
146
+ ```bash
147
147
  docker logs \
148
148
  --since "2025-04-19T00:00:00" \
149
149
  --until "2025-04-19T00:02:00" \
@@ -152,6 +152,6 @@ docker logs \
152
152
 
153
153
  ### Shows the logs real time (tail)
154
154
 
155
- ```
155
+ ```bash
156
156
  docker logs --tail 1000 -f matterbridge
157
157
  ```
package/README-SERVICE.md CHANGED
@@ -20,7 +20,7 @@
20
20
 
21
21
  This will create the required directories if they don't exist
22
22
 
23
- ```
23
+ ```bash
24
24
  cd ~
25
25
  mkdir -p ./Matterbridge
26
26
  mkdir -p ./.matterbridge
@@ -31,7 +31,7 @@ sudo chown -R $USER:$USER ./Matterbridge ./.matterbridge
31
31
 
32
32
  Create a systemctl configuration file for Matterbridge
33
33
 
34
- ```
34
+ ```bash
35
35
  sudo nano /etc/systemd/system/matterbridge.service
36
36
  ```
37
37
 
@@ -53,8 +53,6 @@ WorkingDirectory=/home/<USER>/Matterbridge
53
53
  StandardOutput=inherit
54
54
  StandardError=inherit
55
55
  Restart=always
56
- RestartSec=10s
57
- TimeoutStopSec=30s
58
56
  User=<USER>
59
57
  Group=<USER>
60
58
 
@@ -70,45 +68,53 @@ add this:
70
68
  AmbientCapabilities=CAP_NET_BIND_SERVICE
71
69
  ```
72
70
 
73
- If you modify it after, then run:
71
+ If you use the matterbridge-bthome plugin add this:
74
72
 
75
73
  ```
74
+ [Service]
75
+ AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_NET_ADMIN
76
+ ```
77
+
78
+ If you modify it after, then run:
79
+
80
+ ```bash
76
81
  sudo systemctl daemon-reload
82
+ sudo systemctl restart matterbridge.service
77
83
  ```
78
84
 
79
85
  ### Start Matterbridge
80
86
 
81
- ```
87
+ ```bash
82
88
  sudo systemctl start matterbridge
83
89
  ```
84
90
 
85
91
  ### Stop Matterbridge
86
92
 
87
- ```
93
+ ```bash
88
94
  sudo systemctl stop matterbridge
89
95
  ```
90
96
 
91
97
  ### Show Matterbridge status
92
98
 
93
- ```
99
+ ```bash
94
100
  sudo systemctl status matterbridge.service
95
101
  ```
96
102
 
97
103
  ### Enable Matterbridge to start automatically on boot
98
104
 
99
- ```
105
+ ```bash
100
106
  sudo systemctl enable matterbridge.service
101
107
  ```
102
108
 
103
109
  ### Disable Matterbridge from starting automatically on boot
104
110
 
105
- ```
111
+ ```bash
106
112
  sudo systemctl disable matterbridge.service
107
113
  ```
108
114
 
109
115
  ### View the log of Matterbridge in real time (this will show the log with colors)
110
116
 
111
- ```
117
+ ```bash
112
118
  sudo journalctl -u matterbridge.service -n 1000 -f --output cat
113
119
  ```
114
120
 
@@ -116,13 +122,13 @@ sudo journalctl -u matterbridge.service -n 1000 -f --output cat
116
122
 
117
123
  Check the space used
118
124
 
119
- ```
125
+ ```bash
120
126
  sudo journalctl --disk-usage
121
127
  ```
122
128
 
123
129
  remove all log older then 3 days
124
130
 
125
- ```
131
+ ```bash
126
132
  sudo journalctl --rotate
127
133
  sudo journalctl --vacuum-time=3d
128
134
  ```
@@ -131,13 +137,13 @@ sudo journalctl --vacuum-time=3d
131
137
 
132
138
  If you want to make the setting permanent to prevent the journal logs to grow too much, run
133
139
 
134
- ```
140
+ ```bash
135
141
  sudo nano /etc/systemd/journald.conf
136
142
  ```
137
143
 
138
144
  add
139
145
 
140
- ```
146
+ ```bash
141
147
  Compress=yes # Compress logs
142
148
  MaxRetentionSec=3days # Keep logs for a maximum of 3 days.
143
149
  MaxFileSec=1day # Rotate logs daily within the 3-day retention period.
@@ -148,7 +154,7 @@ RuntimeMaxUse=100M # Limit runtime logs in /run/log/journal to 100 MB.
148
154
 
149
155
  save it and run
150
156
 
151
- ```
157
+ ```bash
152
158
  sudo systemctl restart systemd-journald
153
159
  ```
154
160
 
@@ -156,7 +162,7 @@ sudo systemctl restart systemd-journald
156
162
 
157
163
  Run the following command to verify if you can install Matterbridge globally without being prompted for a password:
158
164
 
159
- ```
165
+ ```bash
160
166
  sudo npm install -g matterbridge
161
167
  ```
162
168
 
@@ -164,7 +170,7 @@ If you are not prompted for a password, no further action is required.
164
170
 
165
171
  If that is not the case, open the sudoers file for editing using visudo
166
172
 
167
- ```
173
+ ```bash
168
174
  sudo visudo
169
175
  ```
170
176
 
@@ -176,8 +182,8 @@ verify the presence of of a line
176
182
 
177
183
  exit and create a configuration file for sudoers
178
184
 
179
- ```
180
- sudo nano /etc/sudoers.d/matterbridge
185
+ ```bash
186
+ sudo nano /etc/sudoers.d/matterbridge
181
187
  ```
182
188
 
183
189
  add this line replacing USER with your user name (e.g. radxa ALL=(ALL) NOPASSWD: ALL)
@@ -194,6 +200,6 @@ or if you prefers to only give access to npm without password try with (e.g. rad
194
200
 
195
201
  save the file and reload the settings with:
196
202
 
197
- ```
203
+ ```bash
198
204
  sudo visudo -c
199
205
  ```
package/README.md CHANGED
@@ -250,6 +250,20 @@ It is the ideal companion of the official [Matterbridge Home Assistant Add-on](h
250
250
 
251
251
  Matterbridge Webhooks plugin allows you to expose any webhooks to Matter..
252
252
 
253
+ ### BTHome
254
+
255
+ <a href="https://github.com/Luligu/matterbridge-webhooks">
256
+ <img src="frontend/public/matterbridge.svg" alt="Matterbridge logo" width="100" />
257
+ </a>
258
+
259
+ Matterbridge BTHome allows you to expose any BTHome device to Matter using the native bluetooth of the host machine.
260
+
261
+ Features:
262
+
263
+ - The bluetooth works correctly on all platforms and is based on the @stoprocent fork of noble.
264
+ - The discovered BTHome devices are stored with all attributes to easily restart the plugin.
265
+ - The plugin has also a command line to test and verify the bluetooth adapter and the ble network.
266
+
253
267
  ### Accessory platform example
254
268
 
255
269
  This is an example of an accessory platform plugin.
@@ -310,6 +324,12 @@ The history works in both bridge and childbridge mode.
310
324
 
311
325
  The Eve app only shows the history when the plugins run like an AccessoryPlatform in childbridge mode (this means the plugin is paired directly).
312
326
 
327
+ ## Third-party plugins
328
+
329
+ ### [Loxone](https://github.com/andrasg/matterbridge-loxone)
330
+
331
+ A matterbridge plugin that allows connecting Loxone devices to Matter.
332
+
313
333
  ## How to install and add a plugin with the frontend (best option)
314
334
 
315
335
  Just open the frontend on the link provided in the log, select a plugin and click install.
package/dist/frontend.js CHANGED
@@ -11,7 +11,7 @@ import { AnsiLogger, stringify, debugStringify, CYAN, db, er, nf, rs, UNDERLINE,
11
11
  import { createZip, deepCopy, isValidArray, isValidNumber, isValidObject, isValidString } from './utils/export.js';
12
12
  import { plg } from './matterbridgeTypes.js';
13
13
  import { hasParameter } from './utils/export.js';
14
- import { BridgedDeviceBasicInformation } from '@matter/main/clusters';
14
+ import { BridgedDeviceBasicInformation, PowerSource } from '@matter/main/clusters';
15
15
  export const WS_ID_LOG = 0;
16
16
  export const WS_ID_REFRESH_NEEDED = 1;
17
17
  export const WS_ID_RESTART_NEEDED = 2;
@@ -918,6 +918,28 @@ export class Frontend {
918
918
  return true;
919
919
  return false;
920
920
  }
921
+ getPowerSource(device) {
922
+ if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
923
+ return undefined;
924
+ const powerSource = (device) => {
925
+ const featureMap = device.getAttribute(PowerSource.Cluster.id, 'featureMap');
926
+ if (featureMap.wired) {
927
+ const wiredCurrentType = device.getAttribute(PowerSource.Cluster.id, 'wiredCurrentType');
928
+ return ['ac', 'dc'][wiredCurrentType];
929
+ }
930
+ if (featureMap.battery) {
931
+ const batChargeLevel = device.getAttribute(PowerSource.Cluster.id, 'batChargeLevel');
932
+ return ['ok', 'warning', 'critical'][batChargeLevel];
933
+ }
934
+ return;
935
+ };
936
+ if (device.hasClusterServer(PowerSource.Cluster.id))
937
+ return powerSource(device);
938
+ for (const child of device.getChildEndpoints()) {
939
+ if (child.hasClusterServer(PowerSource.Cluster.id))
940
+ return powerSource(child);
941
+ }
942
+ }
921
943
  getClusterTextFromDevice(device) {
922
944
  if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
923
945
  return '';
@@ -957,6 +979,7 @@ export class Frontend {
957
979
  return '';
958
980
  };
959
981
  let attributes = '';
982
+ let supportedModes = [];
960
983
  device.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
961
984
  if (typeof attributeValue === 'undefined')
962
985
  return;
@@ -974,6 +997,20 @@ export class Frontend {
974
997
  attributes += `Heat to: ${attributeValue / 100}°C `;
975
998
  if (clusterName === 'thermostat' && attributeName === 'occupiedCoolingSetpoint' && isValidNumber(attributeValue))
976
999
  attributes += `Cool to: ${attributeValue / 100}°C `;
1000
+ const modeClusters = ['modeSelect', 'rvcRunMode', 'rvcCleanMode', 'laundryWasherMode', 'ovenMode', 'microwaveOvenMode'];
1001
+ if (modeClusters.includes(clusterName) && attributeName === 'supportedModes') {
1002
+ supportedModes = attributeValue;
1003
+ }
1004
+ if (modeClusters.includes(clusterName) && attributeName === 'currentMode') {
1005
+ const supportedMode = supportedModes.find((mode) => mode.mode === attributeValue);
1006
+ if (supportedMode)
1007
+ attributes += `Mode: ${supportedMode.label} `;
1008
+ else
1009
+ attributes += `Mode: ${attributeValue} `;
1010
+ }
1011
+ const operationalStateClusters = ['operationalState', 'rvcOperationalState'];
1012
+ if (operationalStateClusters.includes(clusterName) && attributeName === 'operationalState')
1013
+ attributes += `OpState: ${attributeValue} `;
977
1014
  if (clusterName === 'pumpConfigurationAndControl' && attributeName === 'operationMode')
978
1015
  attributes += `Mode: ${attributeValue} `;
979
1016
  if (clusterName === 'valveConfigurationAndControl' && attributeName === 'currentState')
@@ -1243,6 +1280,7 @@ export class Frontend {
1243
1280
  configUrl: device.configUrl,
1244
1281
  uniqueId: device.uniqueId,
1245
1282
  reachable: this.getReachability(device),
1283
+ powerSource: this.getPowerSource(device),
1246
1284
  cluster: cluster,
1247
1285
  });
1248
1286
  });
@@ -399,6 +399,20 @@ export function getAttributeId(endpoint, cluster, attribute) {
399
399
  else if (attribute === 'levelValue')
400
400
  return 0xa;
401
401
  }
402
+ if (endpoint.behaviors.supported[lowercaseFirstLetter(cluster)]?.schema?.type === 'OperationalState') {
403
+ if (attribute === 'phaseList')
404
+ return 0x0;
405
+ else if (attribute === 'currentPhase')
406
+ return 0x1;
407
+ else if (attribute === 'countdownTime')
408
+ return 0x2;
409
+ else if (attribute === 'operationalStateList')
410
+ return 0x3;
411
+ else if (attribute === 'operationalState')
412
+ return 0x4;
413
+ else if (attribute === 'operationalError')
414
+ return 0x5;
415
+ }
402
416
  return endpoint.behaviors.supported[lowercaseFirstLetter(cluster)]?.schema?.children?.find((child) => child.name === capitalizeFirstLetter(attribute))?.id;
403
417
  }
404
418
  }
package/dist/update.js CHANGED
@@ -35,14 +35,15 @@ async function getMatterbridgeLatestVersion(matterbridge) {
35
35
  }
36
36
  async function getMatterbridgeDevVersion(matterbridge) {
37
37
  const { getNpmPackageVersion } = await import('./utils/network.js');
38
- getNpmPackageVersion('matterbridge', 'edge')
38
+ getNpmPackageVersion('matterbridge', 'dev')
39
39
  .then(async (version) => {
40
40
  matterbridge.matterbridgeDevVersion = version;
41
41
  matterbridge.matterbridgeInformation.matterbridgeDevVersion = version;
42
42
  await matterbridge.nodeContext?.set('matterbridgeDevVersion', version);
43
- if (matterbridge.matterbridgeVersion.includes('-edge.') && matterbridge.matterbridgeVersion !== version) {
43
+ if (matterbridge.matterbridgeVersion.includes('-dev.') && matterbridge.matterbridgeVersion !== version) {
44
44
  matterbridge.log.notice(`Matterbridge@dev is out of date. Current version: ${matterbridge.matterbridgeVersion}. Latest dev version: ${matterbridge.matterbridgeDevVersion}.`);
45
45
  matterbridge.frontend.wssSendRefreshRequired('matterbridgeDevVersion');
46
+ matterbridge.frontend.wssSendUpdateRequired();
46
47
  }
47
48
  })
48
49
  .catch((error) => {
@@ -1,3 +1,10 @@
1
+ export function hasParameter(name) {
2
+ const commandArguments = process.argv.slice(2);
3
+ let markerIncluded = commandArguments.includes(`-${name}`);
4
+ if (!markerIncluded)
5
+ markerIncluded = commandArguments.includes(`--${name}`);
6
+ return markerIncluded;
7
+ }
1
8
  import { isValidNumber } from './export.js';
2
9
  export function getParameter(name) {
3
10
  const commandArguments = process.argv.slice(2);
@@ -8,13 +15,6 @@ export function getParameter(name) {
8
15
  return undefined;
9
16
  return commandArguments[markerIndex + 1];
10
17
  }
11
- export function hasParameter(name) {
12
- const commandArguments = process.argv.slice(2);
13
- let markerIncluded = commandArguments.includes(`-${name}`);
14
- if (!markerIncluded)
15
- markerIncluded = commandArguments.includes(`--${name}`);
16
- return markerIncluded;
17
- }
18
18
  export function getIntParameter(name) {
19
19
  const value = getParameter(name);
20
20
  if (value === undefined)
@@ -24,3 +24,35 @@ export function getIntParameter(name) {
24
24
  return undefined;
25
25
  return intValue;
26
26
  }
27
+ export function getIntArrayParameter(name) {
28
+ const commandArguments = process.argv.slice(2);
29
+ let markerIndex = commandArguments.indexOf(`--${name}`);
30
+ if (markerIndex < 0)
31
+ markerIndex = commandArguments.indexOf(`-${name}`);
32
+ if (markerIndex < 0)
33
+ return undefined;
34
+ const intValues = [];
35
+ for (let i = markerIndex + 1; i < commandArguments.length && !commandArguments[i].startsWith('-'); i++) {
36
+ const intValue = parseInt(commandArguments[i], 10);
37
+ if (isValidNumber(intValue))
38
+ intValues.push(intValue);
39
+ }
40
+ if (intValues.length === 0)
41
+ return undefined;
42
+ return intValues;
43
+ }
44
+ export function getStringArrayParameter(name) {
45
+ const commandArguments = process.argv.slice(2);
46
+ let markerIndex = commandArguments.indexOf(`--${name}`);
47
+ if (markerIndex < 0)
48
+ markerIndex = commandArguments.indexOf(`-${name}`);
49
+ if (markerIndex < 0)
50
+ return undefined;
51
+ const values = [];
52
+ for (let i = markerIndex + 1; i < commandArguments.length && !commandArguments[i].startsWith('-'); i++) {
53
+ values.push(commandArguments[i]);
54
+ }
55
+ if (values.length === 0)
56
+ return undefined;
57
+ return values;
58
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "files": {
3
3
  "main.css": "./static/css/main.944b63c3.css",
4
- "main.js": "./static/js/main.cf5d7dfe.js",
4
+ "main.js": "./static/js/main.32273640.js",
5
5
  "static/js/453.d855a71b.chunk.js": "./static/js/453.d855a71b.chunk.js",
6
6
  "static/media/roboto-latin-700-normal.woff2": "./static/media/roboto-latin-700-normal.c4d6cab43bec89049809.woff2",
7
7
  "static/media/roboto-latin-500-normal.woff2": "./static/media/roboto-latin-500-normal.599f66a60bdf974e578e.woff2",
@@ -77,11 +77,11 @@
77
77
  "static/media/roboto-greek-ext-300-normal.woff": "./static/media/roboto-greek-ext-300-normal.60729cafbded24073dfb.woff",
78
78
  "index.html": "./index.html",
79
79
  "main.944b63c3.css.map": "./static/css/main.944b63c3.css.map",
80
- "main.cf5d7dfe.js.map": "./static/js/main.cf5d7dfe.js.map",
80
+ "main.32273640.js.map": "./static/js/main.32273640.js.map",
81
81
  "453.d855a71b.chunk.js.map": "./static/js/453.d855a71b.chunk.js.map"
82
82
  },
83
83
  "entrypoints": [
84
84
  "static/css/main.944b63c3.css",
85
- "static/js/main.cf5d7dfe.js"
85
+ "static/js/main.32273640.js"
86
86
  ]
87
87
  }
@@ -1 +1 @@
1
- <!doctype html><html lang="en"><head><meta charset="utf-8"/><base href="./"><link rel="icon" href="./matterbridge 32x32.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>Matterbridge</title><link rel="manifest" href="./manifest.json"/><script defer="defer" src="./static/js/main.cf5d7dfe.js"></script><link href="./static/css/main.944b63c3.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
1
+ <!doctype html><html lang="en"><head><meta charset="utf-8"/><base href="./"><link rel="icon" href="./matterbridge 32x32.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>Matterbridge</title><link rel="manifest" href="./manifest.json"/><script defer="defer" src="./static/js/main.32273640.js"></script><link href="./static/css/main.944b63c3.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>