matterbridge 3.0.3-dev-20250518-e0f532c → 3.0.3-dev-20250519-6aad062
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 +13 -0
- package/README.md +9 -0
- package/dist/index.js +1 -0
- package/dist/matterbridge.js +21 -15
- package/dist/matterbridgeBehaviors.js +39 -0
- package/dist/roboticVacuumCleaner.js +5 -5
- package/dist/waterHeater.js +45 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -10,10 +10,22 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
10
10
|
|
|
11
11
|
## [3.0.3] - 2025-05-18
|
|
12
12
|
|
|
13
|
+
### New plugins
|
|
14
|
+
|
|
15
|
+
[Dyson robot](https://github.com/thoukydides/matterbridge-dyson-robot)
|
|
16
|
+
|
|
17
|
+
A Matterbridge plugin that connects Dyson robot vacuums and air treatment devices.
|
|
18
|
+
to the Matter smart home ecosystem via their local MQTT APIs.
|
|
19
|
+
|
|
20
|
+
[Aeg robot](https://github.com/thoukydides/matterbridge-aeg-robot)
|
|
21
|
+
|
|
22
|
+
AEG RX 9 / Electrolux Pure i9 robot vacuum plugin for Matterbridge.
|
|
23
|
+
|
|
13
24
|
### Added
|
|
14
25
|
|
|
15
26
|
- [virtual] Added virtual devices configuration mode in the Matterbridge Settings: 'Disabled', 'Light', 'Outlet', 'Switch', 'Mounted_switch'. Switch is not supported by Alexa. Mounted Switch is not supported by Apple.
|
|
16
27
|
- [deviceTypes] Added evse, waterHeater, solarPower, batteryStorage and heatPump device type.
|
|
28
|
+
- [waterHeater] Added WaterHeater class to create a Water Heater Device Type in one line of code (thanks https://github.com/lboue).
|
|
17
29
|
|
|
18
30
|
### Changed
|
|
19
31
|
|
|
@@ -21,6 +33,7 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
21
33
|
- [export]: Removed long deprecated Matter exports from matterbridge. Use matterbridge/matter.
|
|
22
34
|
- [matterbridge]: Refactored initialize() and cleanup() methods.
|
|
23
35
|
- [matterbridge]: Updated -help informations.
|
|
36
|
+
- [rvc]: Added the parameters in the RoboticVacuumCleaner class constructor.
|
|
24
37
|
|
|
25
38
|
### Fixed
|
|
26
39
|
|
package/README.md
CHANGED
|
@@ -353,6 +353,15 @@ The Eve app only shows the history when the plugins run like an AccessoryPlatfor
|
|
|
353
353
|
|
|
354
354
|
A matterbridge plugin that allows connecting Loxone devices to Matter.
|
|
355
355
|
|
|
356
|
+
### [Dyson robot](https://github.com/thoukydides/matterbridge-dyson-robot)
|
|
357
|
+
|
|
358
|
+
A Matterbridge plugin that connects Dyson robot vacuums and air treatment devices.
|
|
359
|
+
to the Matter smart home ecosystem via their local MQTT APIs.
|
|
360
|
+
|
|
361
|
+
### [Aeg robot](https://github.com/thoukydides/matterbridge-aeg-robot)
|
|
362
|
+
|
|
363
|
+
AEG RX 9 / Electrolux Pure i9 robot vacuum plugin for Matterbridge.
|
|
364
|
+
|
|
356
365
|
## How to install and add a plugin with the frontend (best option)
|
|
357
366
|
|
|
358
367
|
Just open the frontend on the link provided in the log, select a plugin and click install.
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ export * from './matterbridgePlatform.js';
|
|
|
11
11
|
export * from './matterbridgeAccessoryPlatform.js';
|
|
12
12
|
export * from './matterbridgeDynamicPlatform.js';
|
|
13
13
|
export * from './roboticVacuumCleaner.js';
|
|
14
|
+
export * from './waterHeater.js';
|
|
14
15
|
export { addVirtualDevice } from './helpers.js';
|
|
15
16
|
const log = new AnsiLogger({ logName: 'Main', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
|
|
16
17
|
async function main() {
|
package/dist/matterbridge.js
CHANGED
|
@@ -289,7 +289,15 @@ export class Matterbridge extends EventEmitter {
|
|
|
289
289
|
await fs.access(pairingFilePath, fs.constants.R_OK);
|
|
290
290
|
const pairingFileContent = await fs.readFile(pairingFilePath, 'utf8');
|
|
291
291
|
const pairingFileJson = JSON.parse(pairingFileContent);
|
|
292
|
-
if (pairingFileJson.
|
|
292
|
+
if (isValidNumber(pairingFileJson.vendorId))
|
|
293
|
+
this.aggregatorVendorId = VendorId(pairingFileJson.vendorId);
|
|
294
|
+
if (isValidString(pairingFileJson.vendorName, 3))
|
|
295
|
+
this.aggregatorVendorName = pairingFileJson.vendorName;
|
|
296
|
+
if (isValidNumber(pairingFileJson.productId))
|
|
297
|
+
this.aggregatorProductId = VendorId(pairingFileJson.productId);
|
|
298
|
+
if (isValidString(pairingFileJson.productName, 3))
|
|
299
|
+
this.aggregatorProductName = pairingFileJson.productName;
|
|
300
|
+
if (isValidNumber(pairingFileJson.passcode) && isValidNumber(pairingFileJson.discriminator)) {
|
|
293
301
|
this.passcode = pairingFileJson.passcode;
|
|
294
302
|
this.discriminator = pairingFileJson.discriminator;
|
|
295
303
|
this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using passcode ${CYAN}${this.passcode}${nf} and discriminator ${CYAN}${this.discriminator}${nf} from pairing file.`);
|
|
@@ -1072,8 +1080,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1072
1080
|
await this.matterbridgeContext?.clearAll();
|
|
1073
1081
|
this.log.info('Matter storage reset done! Remove the bridge from the controller.');
|
|
1074
1082
|
}
|
|
1075
|
-
await
|
|
1076
|
-
await
|
|
1083
|
+
await this.stopMatterStorage();
|
|
1084
|
+
await this.frontend.stop();
|
|
1077
1085
|
try {
|
|
1078
1086
|
Logger.removeLogger('matterfilelogger');
|
|
1079
1087
|
}
|
|
@@ -1923,23 +1931,21 @@ export class Matterbridge extends EventEmitter {
|
|
|
1923
1931
|
async createDirectory(path, name) {
|
|
1924
1932
|
try {
|
|
1925
1933
|
await fs.access(path);
|
|
1934
|
+
this.log.debug(`Directory ${name} already exists at path: ${path}`);
|
|
1926
1935
|
}
|
|
1927
1936
|
catch (err) {
|
|
1928
|
-
if (err
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
await fs.mkdir(path, { recursive: true });
|
|
1933
|
-
this.log.info(`Created ${name}: ${path}`);
|
|
1934
|
-
}
|
|
1935
|
-
catch (err) {
|
|
1936
|
-
this.log.error(`Error creating dir ${name} path ${path}: ${err}`);
|
|
1937
|
-
}
|
|
1937
|
+
if (err.code === 'ENOENT') {
|
|
1938
|
+
try {
|
|
1939
|
+
await fs.mkdir(path, { recursive: true });
|
|
1940
|
+
this.log.info(`Created ${name}: ${path}`);
|
|
1938
1941
|
}
|
|
1939
|
-
|
|
1940
|
-
this.log.error(`Error
|
|
1942
|
+
catch (err) {
|
|
1943
|
+
this.log.error(`Error creating dir ${name} path ${path}: ${err}`);
|
|
1941
1944
|
}
|
|
1942
1945
|
}
|
|
1946
|
+
else {
|
|
1947
|
+
this.log.error(`Error accessing dir ${name} path ${path}: ${err}`);
|
|
1948
|
+
}
|
|
1943
1949
|
}
|
|
1944
1950
|
}
|
|
1945
1951
|
}
|
|
@@ -12,6 +12,7 @@ import { ModeBase } from '@matter/main/clusters/mode-base';
|
|
|
12
12
|
import { RvcRunMode } from '@matter/main/clusters/rvc-run-mode';
|
|
13
13
|
import { RvcOperationalState } from '@matter/main/clusters/rvc-operational-state';
|
|
14
14
|
import { ServiceArea } from '@matter/main/clusters/service-area';
|
|
15
|
+
import { WaterHeaterManagement } from '@matter/main/clusters/water-heater-management';
|
|
15
16
|
import { IdentifyServer } from '@matter/main/behaviors/identify';
|
|
16
17
|
import { OnOffServer } from '@matter/main/behaviors/on-off';
|
|
17
18
|
import { LevelControlServer } from '@matter/main/behaviors/level-control';
|
|
@@ -29,6 +30,8 @@ import { RvcRunModeServer } from '@matter/main/behaviors/rvc-run-mode';
|
|
|
29
30
|
import { RvcCleanModeServer } from '@matter/main/behaviors/rvc-clean-mode';
|
|
30
31
|
import { RvcOperationalStateServer } from '@matter/main/behaviors/rvc-operational-state';
|
|
31
32
|
import { ServiceAreaServer } from '@matter/main/behaviors/service-area';
|
|
33
|
+
import { WaterHeaterModeServer } from '@matter/main/behaviors/water-heater-mode';
|
|
34
|
+
import { WaterHeaterManagementServer } from '@matter/main/behaviors/water-heater-management';
|
|
32
35
|
export class MatterbridgeServerDevice {
|
|
33
36
|
log;
|
|
34
37
|
commandHandler;
|
|
@@ -174,6 +177,14 @@ export class MatterbridgeServerDevice {
|
|
|
174
177
|
this.log.info(`Selecting areas ${newAreas} (endpoint ${this.endpointId}.${this.endpointNumber})`);
|
|
175
178
|
this.commandHandler.executeHandler('selectAreas', { request: { newAreas }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
|
|
176
179
|
}
|
|
180
|
+
boost({ boostInfo }) {
|
|
181
|
+
this.log.info(`Boost (endpoint ${this.endpointId}.${this.endpointNumber})`);
|
|
182
|
+
this.commandHandler.executeHandler('boost', { request: { boostInfo }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
|
|
183
|
+
}
|
|
184
|
+
cancelBoost() {
|
|
185
|
+
this.log.info(`Cancel boost (endpoint ${this.endpointId}.${this.endpointNumber})`);
|
|
186
|
+
this.commandHandler.executeHandler('cancelBoost', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
|
|
187
|
+
}
|
|
177
188
|
}
|
|
178
189
|
export class MatterbridgeServer extends Behavior {
|
|
179
190
|
static id = 'matterbridge';
|
|
@@ -538,3 +549,31 @@ export class MatterbridgeServiceAreaServer extends ServiceAreaServer {
|
|
|
538
549
|
return { status: ServiceArea.SelectAreasStatus.Success, statusText: 'Succesfully selected new areas' };
|
|
539
550
|
}
|
|
540
551
|
}
|
|
552
|
+
export class MatterbridgeWaterHeaterManagementServer extends WaterHeaterManagementServer {
|
|
553
|
+
boost({ boostInfo }) {
|
|
554
|
+
const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
|
|
555
|
+
device.boost({ boostInfo });
|
|
556
|
+
device.log.info(`MatterbridgeWaterHeaterManagementServer boost called with: ${JSON.stringify(boostInfo)}`);
|
|
557
|
+
this.state.boostState = WaterHeaterManagement.BoostState.Active;
|
|
558
|
+
}
|
|
559
|
+
cancelBoost() {
|
|
560
|
+
const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
|
|
561
|
+
device.cancelBoost();
|
|
562
|
+
device.log.info(`MatterbridgeWaterHeaterManagementServer cancelBoost called`);
|
|
563
|
+
this.state.boostState = WaterHeaterManagement.BoostState.Inactive;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
export class MatterbridgeWaterHeaterModeServer extends WaterHeaterModeServer {
|
|
567
|
+
changeToMode({ newMode }) {
|
|
568
|
+
const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
|
|
569
|
+
const supported = this.state.supportedModes.find((mode) => mode.mode === newMode);
|
|
570
|
+
if (!supported) {
|
|
571
|
+
device.log.error(`MatterbridgeWaterHeaterModeServer changeToMode called with unsupported newMode: ${newMode}`);
|
|
572
|
+
return { status: ModeBase.ModeChangeStatus.UnsupportedMode, statusText: 'Unsupported mode' };
|
|
573
|
+
}
|
|
574
|
+
device.changeToMode({ newMode });
|
|
575
|
+
this.state.currentMode = newMode;
|
|
576
|
+
device.log.info(`MatterbridgeWaterHeaterModeServer changeToMode called with newMode ${newMode} => ${supported.label}`);
|
|
577
|
+
return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Success' };
|
|
578
|
+
}
|
|
579
|
+
}
|
|
@@ -3,15 +3,15 @@ import { roboticVacuumCleaner } from './matterbridgeDeviceTypes.js';
|
|
|
3
3
|
import { MatterbridgeRvcCleanModeServer, MatterbridgeRvcOperationalStateServer, MatterbridgeRvcRunModeServer, MatterbridgeServiceAreaServer } from './matterbridgeBehaviors.js';
|
|
4
4
|
import { PowerSource, RvcRunMode, RvcCleanMode, RvcOperationalState } from '@matter/main/clusters';
|
|
5
5
|
export class RoboticVacuumCleaner extends MatterbridgeEndpoint {
|
|
6
|
-
constructor(name, serial) {
|
|
6
|
+
constructor(name, serial, currentRunMode, supportedRunModes, currentCleanMode, supportedCleanModes, currentPhase = null, phaseList = null, operationalState, operationalStateList, supportedAreas, selectedAreas, currentArea) {
|
|
7
7
|
super(roboticVacuumCleaner, { uniqueStorageKey: `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}` }, true);
|
|
8
8
|
this.createDefaultIdentifyClusterServer()
|
|
9
9
|
.createDefaultBasicInformationClusterServer(name, serial, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Robot Vacuum Cleaner')
|
|
10
10
|
.createDefaultPowerSourceRechargeableBatteryClusterServer(80, PowerSource.BatChargeLevel.Ok, 5900)
|
|
11
|
-
.createDefaultRvcRunModeClusterServer()
|
|
12
|
-
.createDefaultRvcCleanModeClusterServer()
|
|
13
|
-
.createDefaultRvcOperationalStateClusterServer()
|
|
14
|
-
.createDefaultServiceAreaClusterServer();
|
|
11
|
+
.createDefaultRvcRunModeClusterServer(currentRunMode, supportedRunModes)
|
|
12
|
+
.createDefaultRvcCleanModeClusterServer(currentCleanMode, supportedCleanModes)
|
|
13
|
+
.createDefaultRvcOperationalStateClusterServer(phaseList, currentPhase, operationalStateList, operationalState)
|
|
14
|
+
.createDefaultServiceAreaClusterServer(supportedAreas, selectedAreas, currentArea);
|
|
15
15
|
}
|
|
16
16
|
createDefaultRvcRunModeClusterServer(currentMode, supportedModes) {
|
|
17
17
|
this.behaviors.require(MatterbridgeRvcRunModeServer, {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
|
|
2
|
+
import { waterHeater } from './matterbridgeDeviceTypes.js';
|
|
3
|
+
import { MatterbridgeWaterHeaterManagementServer, MatterbridgeWaterHeaterModeServer } from './matterbridgeBehaviors.js';
|
|
4
|
+
import { WaterHeaterManagement, WaterHeaterMode } from '@matter/main/clusters';
|
|
5
|
+
export class WaterHeater extends MatterbridgeEndpoint {
|
|
6
|
+
constructor(name, serial, waterTemperature = 50, minHeatSetpointLimit = 20, maxHeatSetpointLimit = 80, heaterTypes = { immersionElement1: true }) {
|
|
7
|
+
super(waterHeater, { uniqueStorageKey: `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}` }, true);
|
|
8
|
+
this.createDefaultIdentifyClusterServer()
|
|
9
|
+
.createDefaultBasicInformationClusterServer(name, serial, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Water Heater')
|
|
10
|
+
.createDefaultPowerSourceWiredClusterServer()
|
|
11
|
+
.createDefaultHeatingThermostatClusterServer(waterTemperature, waterTemperature, minHeatSetpointLimit, maxHeatSetpointLimit)
|
|
12
|
+
.createDefaultWaterHeaterManagementClusterServer(heaterTypes)
|
|
13
|
+
.createDefaultWaterHeaterModeClusterServer();
|
|
14
|
+
}
|
|
15
|
+
createDefaultWaterHeaterManagementClusterServer(heaterTypes, heatDemand, tankPercentage, boostState) {
|
|
16
|
+
this.behaviors.require(MatterbridgeWaterHeaterManagementServer.with(WaterHeaterManagement.Feature.TankPercent), {
|
|
17
|
+
heaterTypes: heaterTypes ?? { immersionElement1: true },
|
|
18
|
+
heatDemand: heatDemand ?? {},
|
|
19
|
+
tankPercentage: tankPercentage ?? 100,
|
|
20
|
+
boostState: boostState ?? WaterHeaterManagement.BoostState.Inactive,
|
|
21
|
+
});
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
createDefaultWaterHeaterModeClusterServer(currentMode, supportedModes) {
|
|
25
|
+
this.behaviors.require(MatterbridgeWaterHeaterModeServer, {
|
|
26
|
+
supportedModes: supportedModes ?? [
|
|
27
|
+
{ label: 'Auto', mode: 1, modeTags: [{ value: WaterHeaterMode.ModeTag.Auto }] },
|
|
28
|
+
{ label: 'Quick', mode: 2, modeTags: [{ value: WaterHeaterMode.ModeTag.Quick }] },
|
|
29
|
+
{ label: 'Quiet', mode: 3, modeTags: [{ value: WaterHeaterMode.ModeTag.Quiet }] },
|
|
30
|
+
{ label: 'LowNoise', mode: 4, modeTags: [{ value: WaterHeaterMode.ModeTag.LowNoise }] },
|
|
31
|
+
{ label: 'LowEnergy', mode: 5, modeTags: [{ value: WaterHeaterMode.ModeTag.LowEnergy }] },
|
|
32
|
+
{ label: 'Vacation', mode: 6, modeTags: [{ value: WaterHeaterMode.ModeTag.Vacation }] },
|
|
33
|
+
{ label: 'Min', mode: 7, modeTags: [{ value: WaterHeaterMode.ModeTag.Min }] },
|
|
34
|
+
{ label: 'Max', mode: 8, modeTags: [{ value: WaterHeaterMode.ModeTag.Max }] },
|
|
35
|
+
{ label: 'Night', mode: 9, modeTags: [{ value: WaterHeaterMode.ModeTag.Night }] },
|
|
36
|
+
{ label: 'Day', mode: 10, modeTags: [{ value: WaterHeaterMode.ModeTag.Day }] },
|
|
37
|
+
{ label: 'Off', mode: 11, modeTags: [{ value: WaterHeaterMode.ModeTag.Off }] },
|
|
38
|
+
{ label: 'Manual', mode: 12, modeTags: [{ value: WaterHeaterMode.ModeTag.Manual }] },
|
|
39
|
+
{ label: 'Timed', mode: 13, modeTags: [{ value: WaterHeaterMode.ModeTag.Timed }] },
|
|
40
|
+
],
|
|
41
|
+
currentMode: currentMode ?? 1,
|
|
42
|
+
});
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge",
|
|
3
|
-
"version": "3.0.3-dev-
|
|
3
|
+
"version": "3.0.3-dev-20250519-6aad062",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "matterbridge",
|
|
9
|
-
"version": "3.0.3-dev-
|
|
9
|
+
"version": "3.0.3-dev-20250519-6aad062",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@matter/main": "0.13.0",
|
package/package.json
CHANGED