matterbridge 3.2.3-dev-20250813-34745fd → 3.2.3-dev-20250816-3639b16
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 +6 -3
- package/README-DEV.md +51 -0
- package/dist/devices/cooktop.js +21 -0
- package/dist/devices/dishwasher.js +3 -20
- package/dist/devices/export.js +2 -0
- package/dist/devices/laundryDryer.js +3 -20
- package/dist/devices/oven.js +1 -0
- package/dist/devices/refrigerator.js +55 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -12,9 +12,12 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
12
12
|
|
|
13
13
|
### Added
|
|
14
14
|
|
|
15
|
-
- [Oven]: Added Oven class and Jest test. It is not supported by the Home app.
|
|
16
|
-
- [MicrowaveOven]: Added MicrowaveOven class and Jest test. It is not supported by the Home app.
|
|
17
|
-
- [
|
|
15
|
+
- [Oven]: Added Oven() class and Jest test. It is not supported by the Home app.
|
|
16
|
+
- [MicrowaveOven]: Added MicrowaveOven() class and Jest test. It is not supported by the Home app.
|
|
17
|
+
- [Cooktop]: Added Cooktop() class and Jest test. It is not supported by the Home app.
|
|
18
|
+
- [Refrigerator]: Added Refrigerator() class and Jest test. It is not supported by the Home app.
|
|
19
|
+
- [Pages]: Added first draft of https://luligu.github.io/matterbridge.
|
|
20
|
+
- [Matter]: Added Matter Specification Version 1.0, 1.1, 1.2, 1.3, 1.4 and 1.4.1 pdf files.
|
|
18
21
|
|
|
19
22
|
### Changed
|
|
20
23
|
|
package/README-DEV.md
CHANGED
|
@@ -357,6 +357,57 @@ The schema file is loaded from the root of the plugin package. The file must be
|
|
|
357
357
|
|
|
358
358
|
The properties of the schema file shall correspond to the properties of the config file.
|
|
359
359
|
|
|
360
|
+
# Frequently asked questions
|
|
361
|
+
|
|
362
|
+
## Why plugins cannot install matterbridge as a dependency, devDependency or peerDependency
|
|
363
|
+
|
|
364
|
+
There must be one and only one instance of Matterbridge and matter.js in the node_modules directory.
|
|
365
|
+
|
|
366
|
+
### What happens when matterbridge or matter.js are present like a devDependencies
|
|
367
|
+
|
|
368
|
+
The plugins can be globally installed in different ways:
|
|
369
|
+
|
|
370
|
+
- from npm (all devDependencies are installed in node_modules if the plugin is not correctly published)
|
|
371
|
+
- from a tarball (all devDependencies are installed in node_modules if the tarball is not correctly built)
|
|
372
|
+
- from a local path (devDependencies are always installed in node_modules!)
|
|
373
|
+
|
|
374
|
+
In all these cases the devDependencies are always installed by npm and show up in the plugins `node_modules`:
|
|
375
|
+
|
|
376
|
+
- npm install -g ./yourplugin
|
|
377
|
+
- npm install -g git+https://github.com/you/yourplugin.git
|
|
378
|
+
- npm install -g yourplugin
|
|
379
|
+
|
|
380
|
+
In the first 2 cases the devDependeincies are always installed in node_modules!
|
|
381
|
+
|
|
382
|
+
In the last (most dangerous case) they are installed when the user forgets to add --omit=dev or doesn't have NODE_ENV=production.
|
|
383
|
+
|
|
384
|
+
This is also the reason why to be safe 100% all official plugins are published for production removing also devDependencies from package.json.
|
|
385
|
+
|
|
386
|
+
I also lock the dependencies with npm shrinkwrap cause npm installs always the latest versions that mach your range in package.json but sometimes this just breaks the plugin. This permits to be sure that the user host machine has exactly the same dependencies you coded your plugin with.
|
|
387
|
+
|
|
388
|
+
### The technical reason we cannot have matterbridge or @matter in the plugin node_modules.
|
|
389
|
+
|
|
390
|
+
Module Resolution in Matterbridge Plugin System.
|
|
391
|
+
When Matterbridge loads plugins on demand as ESM modules, the module resolution follows Node.js's standard module resolution algorithm. Here's how it works:
|
|
392
|
+
|
|
393
|
+
**1. Plugin Loading Process**
|
|
394
|
+
From the code in pluginManager.ts (lines 628-632), Matterbridge:
|
|
395
|
+
|
|
396
|
+
Resolves the plugin's main entry point from its package.json
|
|
397
|
+
Converts the file path to a URL using pathToFileURL()
|
|
398
|
+
Uses dynamic import: await import(pluginUrl.href)
|
|
399
|
+
|
|
400
|
+
**2. Module Resolution Priority**
|
|
401
|
+
When the plugin code runs import statements, Node.js follows this resolution order:
|
|
402
|
+
|
|
403
|
+
Plugin's local node_modules - Checked first
|
|
404
|
+
Parent directories - Walks up the directory tree looking for node_modules
|
|
405
|
+
Matterbridge's node_modules - Only reached if not found in plugin's dependencies
|
|
406
|
+
|
|
407
|
+
**3. Key Behavior**
|
|
408
|
+
Plugin's node_modules takes precedence - If a package exists in the plugin's own node_modules, that version will be used.
|
|
409
|
+
Matterbridge's node_modules is used as fallback.
|
|
410
|
+
|
|
360
411
|
# Contribution Guidelines
|
|
361
412
|
|
|
362
413
|
Thank you for your interest in contributing to my project!
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { cookSurface, cooktop, powerSource } from '../matterbridgeDeviceTypes.js';
|
|
2
|
+
import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
|
|
3
|
+
import { createLevelTemperatureControlClusterServer } from './temperatureControl.js';
|
|
4
|
+
export class Cooktop extends MatterbridgeEndpoint {
|
|
5
|
+
constructor(name, serial) {
|
|
6
|
+
super([cooktop, powerSource], { uniqueStorageKey: `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}` }, true);
|
|
7
|
+
this.createDefaultIdentifyClusterServer();
|
|
8
|
+
this.createDefaultBasicInformationClusterServer(name, serial, 0xfff1, 'Matterbridge', 0x8000, 'Cooktop');
|
|
9
|
+
this.createDefaultPowerSourceWiredClusterServer();
|
|
10
|
+
this.createOffOnlyOnOffClusterServer(true);
|
|
11
|
+
this.addFixedLabel('composed', 'Cooktop');
|
|
12
|
+
}
|
|
13
|
+
addSurface(name, tagList, selectedTemperatureLevel = 2, supportedTemperatureLevels = ['Level 1', 'Level 2', 'Level 3', 'Level 4', 'Level 5']) {
|
|
14
|
+
const surface = this.addChildDeviceType(name, cookSurface, { tagList }, true);
|
|
15
|
+
surface.log.logName = name;
|
|
16
|
+
createLevelTemperatureControlClusterServer(surface, selectedTemperatureLevel, supportedTemperatureLevels);
|
|
17
|
+
surface.createDefaultTemperatureMeasurementClusterServer(2000);
|
|
18
|
+
surface.createOffOnlyOnOffClusterServer(true);
|
|
19
|
+
return surface;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { TemperatureControl } from '@matter/main/clusters/temperature-control';
|
|
2
1
|
import { ModeBase } from '@matter/main/clusters/mode-base';
|
|
3
2
|
import { DishwasherModeServer } from '@matter/main/behaviors/dishwasher-mode';
|
|
4
3
|
import { DishwasherAlarmServer } from '@matter/main/behaviors/dishwasher-alarm';
|
|
@@ -6,7 +5,7 @@ import { DishwasherMode } from '@matter/main/clusters/dishwasher-mode';
|
|
|
6
5
|
import { dishwasher, powerSource } from '../matterbridgeDeviceTypes.js';
|
|
7
6
|
import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
|
|
8
7
|
import { MatterbridgeOnOffServer, MatterbridgeServer } from '../matterbridgeBehaviors.js';
|
|
9
|
-
import {
|
|
8
|
+
import { createLevelTemperatureControlClusterServer, createNumberTemperatureControlClusterServer } from './temperatureControl.js';
|
|
10
9
|
export class Dishwasher extends MatterbridgeEndpoint {
|
|
11
10
|
constructor(name, serial, currentMode, supportedModes, selectedTemperatureLevel, supportedTemperatureLevels, temperatureSetpoint, minTemperature, maxTemperature, step, operationalState) {
|
|
12
11
|
super([dishwasher, powerSource], { uniqueStorageKey: `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}` }, true);
|
|
@@ -17,27 +16,11 @@ export class Dishwasher extends MatterbridgeEndpoint {
|
|
|
17
16
|
this.createDefaultDishwasherModeClusterServer(currentMode, supportedModes);
|
|
18
17
|
this.createDefaultDishwasherAlarmClusterServer();
|
|
19
18
|
if (temperatureSetpoint)
|
|
20
|
-
|
|
19
|
+
createNumberTemperatureControlClusterServer(this, temperatureSetpoint, minTemperature, maxTemperature, step);
|
|
21
20
|
else
|
|
22
|
-
|
|
21
|
+
createLevelTemperatureControlClusterServer(this, selectedTemperatureLevel, supportedTemperatureLevels);
|
|
23
22
|
this.createDefaultOperationalStateClusterServer(operationalState);
|
|
24
23
|
}
|
|
25
|
-
createLevelTemperatureControlClusterServer(selectedTemperatureLevel = 1, supportedTemperatureLevels = ['Cold', 'Warm', 'Hot', '30°', '40°', '60°', '80°']) {
|
|
26
|
-
this.behaviors.require(MatterbridgeLevelTemperatureControlServer.with(TemperatureControl.Feature.TemperatureLevel), {
|
|
27
|
-
selectedTemperatureLevel,
|
|
28
|
-
supportedTemperatureLevels,
|
|
29
|
-
});
|
|
30
|
-
return this;
|
|
31
|
-
}
|
|
32
|
-
createNumberTemperatureControlClusterServer(temperatureSetpoint = 40 * 100, minTemperature = 30 * 100, maxTemperature = 60 * 100, step = 10 * 100) {
|
|
33
|
-
this.behaviors.require(MatterbridgeNumberTemperatureControlServer.with(TemperatureControl.Feature.TemperatureNumber, TemperatureControl.Feature.TemperatureStep), {
|
|
34
|
-
temperatureSetpoint,
|
|
35
|
-
minTemperature,
|
|
36
|
-
maxTemperature,
|
|
37
|
-
step,
|
|
38
|
-
});
|
|
39
|
-
return this;
|
|
40
|
-
}
|
|
41
24
|
createDefaultDishwasherModeClusterServer(currentMode = 2, supportedModes = [
|
|
42
25
|
{ label: 'Light', mode: 1, modeTags: [{ value: DishwasherMode.ModeTag.Light }] },
|
|
43
26
|
{ label: 'Normal', mode: 2, modeTags: [{ value: DishwasherMode.ModeTag.Normal }] },
|
package/dist/devices/export.js
CHANGED
|
@@ -4,6 +4,8 @@ export * from './extractorHood.js';
|
|
|
4
4
|
export * from './dishwasher.js';
|
|
5
5
|
export * from './microwaveOven.js';
|
|
6
6
|
export * from './oven.js';
|
|
7
|
+
export * from './cooktop.js';
|
|
8
|
+
export * from './refrigerator.js';
|
|
7
9
|
export * from './waterHeater.js';
|
|
8
10
|
export * from './evse.js';
|
|
9
11
|
export * from './solarPower.js';
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { LaundryWasherMode } from '@matter/main/clusters/laundry-washer-mode';
|
|
2
|
-
import { TemperatureControl } from '@matter/main/clusters/temperature-control';
|
|
3
2
|
import { LaundryDryerControls } from '@matter/main/clusters/laundry-dryer-controls';
|
|
4
3
|
import { LaundryDryerControlsServer } from '@matter/main/behaviors/laundry-dryer-controls';
|
|
5
4
|
import { laundryDryer, powerSource } from '../matterbridgeDeviceTypes.js';
|
|
6
5
|
import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
|
|
7
6
|
import { MatterbridgeLaundryWasherModeServer } from './laundryWasher.js';
|
|
8
|
-
import {
|
|
7
|
+
import { createLevelTemperatureControlClusterServer, createNumberTemperatureControlClusterServer } from './temperatureControl.js';
|
|
9
8
|
export class LaundryDryer extends MatterbridgeEndpoint {
|
|
10
9
|
constructor(name, serial, currentMode, supportedModes, selectedTemperatureLevel, supportedTemperatureLevels, temperatureSetpoint, minTemperature, maxTemperature, step, operationalState) {
|
|
11
10
|
super([laundryDryer, powerSource], { uniqueStorageKey: `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}` }, true);
|
|
@@ -16,9 +15,9 @@ export class LaundryDryer extends MatterbridgeEndpoint {
|
|
|
16
15
|
this.createDefaultLaundryWasherModeClusterServer(currentMode, supportedModes);
|
|
17
16
|
this.createDefaultLaundryDryerControlsClusterServer(1);
|
|
18
17
|
if (temperatureSetpoint)
|
|
19
|
-
|
|
18
|
+
createNumberTemperatureControlClusterServer(this, temperatureSetpoint, minTemperature, maxTemperature, step);
|
|
20
19
|
else
|
|
21
|
-
|
|
20
|
+
createLevelTemperatureControlClusterServer(this, selectedTemperatureLevel, supportedTemperatureLevels);
|
|
22
21
|
this.createDefaultOperationalStateClusterServer(operationalState);
|
|
23
22
|
}
|
|
24
23
|
createDefaultLaundryWasherModeClusterServer(currentMode = 2, supportedModes = [
|
|
@@ -40,20 +39,4 @@ export class LaundryDryer extends MatterbridgeEndpoint {
|
|
|
40
39
|
});
|
|
41
40
|
return this;
|
|
42
41
|
}
|
|
43
|
-
createLevelTemperatureControlClusterServer(selectedTemperatureLevel = 1, supportedTemperatureLevels = ['Cold', 'Warm', 'Hot', '30°', '40°', '60°', '80°']) {
|
|
44
|
-
this.behaviors.require(MatterbridgeLevelTemperatureControlServer.with(TemperatureControl.Feature.TemperatureLevel), {
|
|
45
|
-
selectedTemperatureLevel,
|
|
46
|
-
supportedTemperatureLevels,
|
|
47
|
-
});
|
|
48
|
-
return this;
|
|
49
|
-
}
|
|
50
|
-
createNumberTemperatureControlClusterServer(temperatureSetpoint = 40 * 100, minTemperature = 30 * 100, maxTemperature = 60 * 100, step = 10 * 100) {
|
|
51
|
-
this.behaviors.require(MatterbridgeNumberTemperatureControlServer.with(TemperatureControl.Feature.TemperatureNumber, TemperatureControl.Feature.TemperatureStep), {
|
|
52
|
-
temperatureSetpoint,
|
|
53
|
-
minTemperature,
|
|
54
|
-
maxTemperature,
|
|
55
|
-
step,
|
|
56
|
-
});
|
|
57
|
-
return this;
|
|
58
|
-
}
|
|
59
42
|
}
|
package/dist/devices/oven.js
CHANGED
|
@@ -13,6 +13,7 @@ export class Oven extends MatterbridgeEndpoint {
|
|
|
13
13
|
this.createDefaultIdentifyClusterServer();
|
|
14
14
|
this.createDefaultBasicInformationClusterServer(name, serial, 0xfff1, 'Matterbridge', 0x8000, 'Oven');
|
|
15
15
|
this.createDefaultPowerSourceWiredClusterServer();
|
|
16
|
+
this.addFixedLabel('composed', 'Oven');
|
|
16
17
|
}
|
|
17
18
|
addCabinet(name, tagList, currentMode = 2, supportedModes = [
|
|
18
19
|
{ label: 'Bake', mode: 1, modeTags: [{ value: OvenMode.ModeTag.Bake }] },
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { ModeBase } from '@matter/main/clusters/mode-base';
|
|
2
|
+
import { RefrigeratorAndTemperatureControlledCabinetModeServer } from '@matter/main/behaviors/refrigerator-and-temperature-controlled-cabinet-mode';
|
|
3
|
+
import { RefrigeratorAndTemperatureControlledCabinetMode } from '@matter/main/clusters/refrigerator-and-temperature-controlled-cabinet-mode';
|
|
4
|
+
import { oven, powerSource, temperatureControlledCabinetCooler } from '../matterbridgeDeviceTypes.js';
|
|
5
|
+
import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
|
|
6
|
+
import { MatterbridgeServer } from '../matterbridgeBehaviors.js';
|
|
7
|
+
import { createLevelTemperatureControlClusterServer } from './temperatureControl.js';
|
|
8
|
+
export class Refrigerator extends MatterbridgeEndpoint {
|
|
9
|
+
constructor(name, serial) {
|
|
10
|
+
super([oven, powerSource], { uniqueStorageKey: `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}` }, true);
|
|
11
|
+
this.createDefaultIdentifyClusterServer();
|
|
12
|
+
this.createDefaultBasicInformationClusterServer(name, serial, 0xfff1, 'Matterbridge', 0x8000, 'Refrigerator');
|
|
13
|
+
this.createDefaultPowerSourceWiredClusterServer();
|
|
14
|
+
this.addFixedLabel('composed', 'Refrigerator');
|
|
15
|
+
}
|
|
16
|
+
addCabinet(name, tagList, currentMode = 1, supportedModes = [
|
|
17
|
+
{ label: 'Auto', mode: 1, modeTags: [{ value: RefrigeratorAndTemperatureControlledCabinetMode.ModeTag.Auto }] },
|
|
18
|
+
{ label: 'RapidCool', mode: 2, modeTags: [{ value: RefrigeratorAndTemperatureControlledCabinetMode.ModeTag.RapidCool }] },
|
|
19
|
+
{ label: 'RapidFreeze', mode: 3, modeTags: [{ value: RefrigeratorAndTemperatureControlledCabinetMode.ModeTag.RapidFreeze }] },
|
|
20
|
+
], selectedTemperatureLevel = 2, supportedTemperatureLevels = ['Level 1', 'Level 2', 'Level 3', 'Level 4', 'Level 5'], currentTemperature = 1000) {
|
|
21
|
+
const cabinet = this.addChildDeviceType(name, temperatureControlledCabinetCooler, { tagList }, true);
|
|
22
|
+
cabinet.log.logName = name;
|
|
23
|
+
cabinet.createDefaultIdentifyClusterServer();
|
|
24
|
+
createLevelTemperatureControlClusterServer(cabinet, selectedTemperatureLevel, supportedTemperatureLevels);
|
|
25
|
+
this.createDefaultRefrigeratorAndTemperatureControlledCabinetModeClusterServer(cabinet, currentMode, supportedModes);
|
|
26
|
+
cabinet.createDefaultTemperatureMeasurementClusterServer(currentTemperature);
|
|
27
|
+
return cabinet;
|
|
28
|
+
}
|
|
29
|
+
createDefaultRefrigeratorAndTemperatureControlledCabinetModeClusterServer(endpoint, currentMode, supportedModes) {
|
|
30
|
+
endpoint.behaviors.require(MatterbridgeRefrigeratorAndTemperatureControlledCabinetModeServer, {
|
|
31
|
+
supportedModes,
|
|
32
|
+
currentMode,
|
|
33
|
+
});
|
|
34
|
+
return endpoint;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export class MatterbridgeRefrigeratorAndTemperatureControlledCabinetModeServer extends RefrigeratorAndTemperatureControlledCabinetModeServer {
|
|
38
|
+
initialize() {
|
|
39
|
+
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
40
|
+
device.log.info('MatterbridgeRefrigeratorAndTemperatureControlledCabinetModeServer initialized');
|
|
41
|
+
}
|
|
42
|
+
changeToMode(request) {
|
|
43
|
+
const device = this.endpoint.stateOf(MatterbridgeServer);
|
|
44
|
+
const supportedMode = this.state.supportedModes.find((supportedMode) => supportedMode.mode === request.newMode);
|
|
45
|
+
if (supportedMode) {
|
|
46
|
+
device.log.info(`MatterbridgeRefrigeratorAndTemperatureControlledCabinetModeServer: changeToMode (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber}) called with mode ${supportedMode.mode} = ${supportedMode.label}`);
|
|
47
|
+
this.state.currentMode = request.newMode;
|
|
48
|
+
return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Success' };
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
device.log.error(`MatterbridgeRefrigeratorAndTemperatureControlledCabinetModeServer: changeToMode (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber}) called with invalid mode ${request.newMode}`);
|
|
52
|
+
return { status: ModeBase.ModeChangeStatus.InvalidInMode, statusText: 'Invalid mode' };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge",
|
|
3
|
-
"version": "3.2.3-dev-
|
|
3
|
+
"version": "3.2.3-dev-20250816-3639b16",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "matterbridge",
|
|
9
|
-
"version": "3.2.3-dev-
|
|
9
|
+
"version": "3.2.3-dev-20250816-3639b16",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@matter/main": "0.15.3",
|
package/package.json
CHANGED