matterbridge-example-dynamic-platform 3.0.2-dev-20260808-db970b3 → 3.0.2-dev-20260809-1aeac01
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 +5 -3
- package/README.md +4 -1
- package/dist/module.js +86 -6
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -31,14 +31,16 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
31
31
|
|
|
32
32
|
### Breaking changes
|
|
33
33
|
|
|
34
|
-
- [matterbridge]: Require matterbridge v.3.10.
|
|
34
|
+
- [matterbridge]: Require matterbridge v.3.10.5 with matter v.1.6.0.
|
|
35
35
|
|
|
36
36
|
### Added
|
|
37
37
|
|
|
38
38
|
- [chip]: Add chip-test toolchain agents instruction and chip-test runner.
|
|
39
|
+
- [chip]: Add `chipTests.json`/`chipTests.md` with the generic device basic composition, conformance and default warnings tests, and document known CHIP test suite gaps.
|
|
39
40
|
- [frontend]: Add plugin-frontend agents instructions.
|
|
40
|
-
- [platform]: Add `closureGarageDoor` device.
|
|
41
|
-
- [platform]: Add `closureVenetianBlind` device with Lift and Tilt panels.
|
|
41
|
+
- [platform]: Add `closureGarageDoor` device. Thanks Ludovic BOUÉ.
|
|
42
|
+
- [platform]: Add `closureVenetianBlind` device with Lift and Tilt panels. Thanks Ludovic BOUÉ.
|
|
43
|
+
- [platform]: Add a thermostat auto mode with schedules (Weekdays and Weekend schedules) including 2 sub endpoints with temperature and humidity sensors, using `createDefaultSchedulesThermostatClusterServer()`. Thanks Ludovic BOUÉ.
|
|
42
44
|
|
|
43
45
|
### Changed
|
|
44
46
|
|
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
Matterbridge dynamic platform example plugin is a template to develop your own plugin using the dynamic platform.
|
|
25
25
|
|
|
26
|
-
It exposes
|
|
26
|
+
It exposes 73 virtual devices:
|
|
27
27
|
|
|
28
28
|
- a door contact sensor
|
|
29
29
|
- a motion sensor
|
|
@@ -53,6 +53,7 @@ It exposes 72 virtual devices:
|
|
|
53
53
|
and relativeHumidityMeasurement cluster (to show how to create a composed device with sub endpoints)
|
|
54
54
|
- a thermostat with auto mode (i.e. with Auto Heat and Cool features), occupancy and outdoorTemperature
|
|
55
55
|
- a thermostat auto mode with presets (Home, Away, Sleep, Wake, Vacation and GoingToSleep modes) including 3 sub endpoints with flow, temperature and humidity sensors
|
|
56
|
+
- a thermostat auto mode with schedules (Weekdays and Weekend schedules) including 2 sub endpoints with temperature and humidity sensors
|
|
56
57
|
- a thermostat heat only with two external temperature sensors (tagged like Indoor and Outdoor)
|
|
57
58
|
- a thermostat cool only
|
|
58
59
|
- a fan with Off High presets
|
|
@@ -100,6 +101,8 @@ It exposes 72 virtual devices:
|
|
|
100
101
|
|
|
101
102
|
All these devices continuously change their state and position. The plugin also shows how to use all the command handlers (so you can control all the devices), how to subscribe to attributes, and how to trigger events.
|
|
102
103
|
|
|
104
|
+
All devices pass the generic Matter conformance test suite (`TC_DeviceBasicComposition.py`, `TC_DeviceConformance.py` and `TC_DefaultWarnings.py`) run via the CHIP test harness, with one known upstream test-suite gap for the Closure devices — see [chipTests.md](./chipTests.md) for details and how to run the suite against this plugin.
|
|
105
|
+
|
|
103
106
|
If you want to write your own plugin, the easiest way to get started is to clone the [Matterbridge Plugin Template](https://github.com/Luligu/matterbridge-plugin-template). It has **Dev Container support for an instant development environment**, with all tools and extensions (like Node.js, npm, TypeScript, ESLint, Prettier, Jest, and Vitest) already loaded and configured.
|
|
104
107
|
|
|
105
108
|
If you like this project and find it useful, please consider giving it a star on [GitHub](https://github.com/Luligu/matterbridge-example-dynamic-platform) and sponsoring it.
|
package/dist/module.js
CHANGED
|
@@ -61,6 +61,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
61
61
|
thermoAuto;
|
|
62
62
|
thermoAutoOccupancy;
|
|
63
63
|
thermoAutoPresets;
|
|
64
|
+
thermoAutoSchedules;
|
|
64
65
|
thermoHeat;
|
|
65
66
|
thermoCool;
|
|
66
67
|
fanBase;
|
|
@@ -108,8 +109,8 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
108
109
|
constructor(matterbridge, log, config) {
|
|
109
110
|
super(matterbridge, log, config);
|
|
110
111
|
this.config = config;
|
|
111
|
-
if (typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.10.
|
|
112
|
-
throw new Error(`This plugin requires Matterbridge version >= "3.10.
|
|
112
|
+
if (typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.10.5')) {
|
|
113
|
+
throw new Error(`This plugin requires Matterbridge version >= "3.10.5". Please update Matterbridge from ${this.matterbridge.matterbridgeVersion} to the latest version in the frontend.`);
|
|
113
114
|
}
|
|
114
115
|
this.log.info('Initializing platform:', this.config.name);
|
|
115
116
|
}
|
|
@@ -168,7 +169,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
168
169
|
this.flow = await this.addDevice(this.flow);
|
|
169
170
|
this.soil = new SoilSensor('Soil Sensor', 'SOI000067', { soilMoistureMeasuredValue: 45, temperatureMeasuredValue: 3500, batteryPowered: true });
|
|
170
171
|
this.soil = await this.addDevice(this.soil);
|
|
171
|
-
this.irrigation = new IrrigationSystem('Irrigation System', 'IRR000068', {
|
|
172
|
+
this.irrigation = new IrrigationSystem('Irrigation System', 'IRR000068', { batteryPowered: true, flowMeasuredValue: 15 }).addZone(CommonNumberTag.One);
|
|
172
173
|
this.irrigation = (await this.addDevice(this.irrigation));
|
|
173
174
|
this.irrigationSystem = new IrrigationSystem('Irrigation System 4 zones', 'IRR000069', { flowMeasuredValue: 60 })
|
|
174
175
|
.addZone(CommonNumberTag.One)
|
|
@@ -217,8 +218,8 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
217
218
|
this.closureVenetianBlind = new Closure('Venetian Blind', 'VEN000072', {
|
|
218
219
|
tagList: [getSemtag(ClosureTag.Covering), getSemtag(ClosureCoveringTag.Venetian)],
|
|
219
220
|
});
|
|
220
|
-
const closureVenetianBlindLift = this.closureVenetianBlind.addPanel('Lift', [getSemtag(ClosurePanelTag.Lift)]);
|
|
221
|
-
const closureVenetianBlindTilt = this.closureVenetianBlind.addPanel('Tilt', [getSemtag(ClosurePanelTag.Tilt)]);
|
|
221
|
+
const closureVenetianBlindLift = this.closureVenetianBlind.addPanel('Lift', [getSemtag(ClosurePanelTag.Lift)], 'lift');
|
|
222
|
+
const closureVenetianBlindTilt = this.closureVenetianBlind.addPanel('Tilt', [getSemtag(ClosurePanelTag.Tilt)], 'tilt');
|
|
222
223
|
this.closureVenetianBlind = (await this.addDevice(this.closureVenetianBlind));
|
|
223
224
|
const closurePanelTargetPercent = (position) => {
|
|
224
225
|
if (position === ClosureControl.TargetPosition.MoveToFullyOpen)
|
|
@@ -325,9 +326,11 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
325
326
|
this.switch = new MatterbridgeEndpoint([onOffLightSwitch, bridgedNode, powerSource], { id: 'Switch' }, this.config.debug)
|
|
326
327
|
.createDefaultIdentifyClusterServer()
|
|
327
328
|
.createDefaultBridgedDeviceBasicInformationClusterServer('Switch', 'SWI00010', 0xfff1, 'Matterbridge', 'Matterbridge Switch')
|
|
328
|
-
.createDefaultOnOffClusterServer()
|
|
329
329
|
.createDefaultPowerSourceWiredClusterServer()
|
|
330
330
|
.addRequiredClusters();
|
|
331
|
+
if (process.env.MATTERBRIDGE_CHIP_TEST !== '1') {
|
|
332
|
+
this.switch.createDefaultOnOffClusterServer();
|
|
333
|
+
}
|
|
331
334
|
this.switch = await this.addDevice(this.switch);
|
|
332
335
|
this.switch?.addCommandHandler('identify', ({ request: { identifyTime } }) => {
|
|
333
336
|
this.log.info(`Command identify called identifyTime:${identifyTime}`);
|
|
@@ -1075,6 +1078,83 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
1075
1078
|
this.thermoAutoPresets?.subscribeAttribute(Thermostat.id, 'presets', (newValue, oldValue) => {
|
|
1076
1079
|
this.thermoAutoPresets?.log.info(`Subscribe presets called with: ${debugStringify(newValue)} (old value: ${debugStringify(oldValue)})`);
|
|
1077
1080
|
}, this.thermoAutoPresets.log);
|
|
1081
|
+
const schedules_List = [
|
|
1082
|
+
{
|
|
1083
|
+
scheduleHandle: new Uint8Array([0]),
|
|
1084
|
+
systemMode: Thermostat.SystemMode.Auto,
|
|
1085
|
+
name: 'Weekdays',
|
|
1086
|
+
transitions: [
|
|
1087
|
+
{ dayOfWeek: { monday: true, tuesday: true, wednesday: true, thursday: true, friday: true }, transitionTime: 360, heatingSetpoint: 2000, coolingSetpoint: 2400 },
|
|
1088
|
+
{ dayOfWeek: { monday: true, tuesday: true, wednesday: true, thursday: true, friday: true }, transitionTime: 750, heatingSetpoint: 1900, coolingSetpoint: 2500 },
|
|
1089
|
+
{ dayOfWeek: { monday: true, tuesday: true, wednesday: true, thursday: true, friday: true }, transitionTime: 810, heatingSetpoint: 2000, coolingSetpoint: 2400 },
|
|
1090
|
+
{ dayOfWeek: { monday: true, tuesday: true, wednesday: true, thursday: true, friday: true }, transitionTime: 1320, heatingSetpoint: 1800, coolingSetpoint: 2600 },
|
|
1091
|
+
],
|
|
1092
|
+
builtIn: true,
|
|
1093
|
+
},
|
|
1094
|
+
{
|
|
1095
|
+
scheduleHandle: new Uint8Array([1]),
|
|
1096
|
+
systemMode: Thermostat.SystemMode.Auto,
|
|
1097
|
+
name: 'Weekend',
|
|
1098
|
+
transitions: [
|
|
1099
|
+
{ dayOfWeek: { saturday: true, sunday: true }, transitionTime: 480, heatingSetpoint: 2100, coolingSetpoint: 2300 },
|
|
1100
|
+
{ dayOfWeek: { saturday: true, sunday: true }, transitionTime: 1380, heatingSetpoint: 1900, coolingSetpoint: 2500 },
|
|
1101
|
+
],
|
|
1102
|
+
builtIn: true,
|
|
1103
|
+
},
|
|
1104
|
+
];
|
|
1105
|
+
const scheduleTypeDefinitions = [
|
|
1106
|
+
{
|
|
1107
|
+
systemMode: Thermostat.SystemMode.Auto,
|
|
1108
|
+
numberOfSchedules: 10,
|
|
1109
|
+
scheduleTypeFeatures: { supportsSetpoints: true, supportsNames: true },
|
|
1110
|
+
},
|
|
1111
|
+
];
|
|
1112
|
+
this.thermoAutoSchedules = new MatterbridgeEndpoint([thermostat, bridgedNode, powerSource], { id: 'Thermostat (AutoModeSchedules)' }, this.config.debug)
|
|
1113
|
+
.createDefaultIdentifyClusterServer()
|
|
1114
|
+
.createDefaultBridgedDeviceBasicInformationClusterServer('Thermostat (AutoModeSchedules)', 'TAS00059', 0xfff1, 'Matterbridge', 'Matterbridge Thermostat With Schedules')
|
|
1115
|
+
.createDefaultSchedulesThermostatClusterServer(20, 18, 22, 1, 0, 35, 15, 50, undefined, undefined, undefined, undefined, null, schedules_List, scheduleTypeDefinitions, 10, null)
|
|
1116
|
+
.createDefaultPowerSourceWiredClusterServer()
|
|
1117
|
+
.addRequiredClusterServers();
|
|
1118
|
+
if (this.thermoAutoSchedules) {
|
|
1119
|
+
this.thermoAutoSchedules
|
|
1120
|
+
.addChildDeviceType('Temperature', temperatureSensor)
|
|
1121
|
+
.createDefaultTemperatureMeasurementClusterServer(21 * 100)
|
|
1122
|
+
.addRequiredClusterServers();
|
|
1123
|
+
this.thermoAutoSchedules
|
|
1124
|
+
.addChildDeviceType('Humidity', humiditySensor)
|
|
1125
|
+
.createDefaultRelativeHumidityMeasurementClusterServer(50 * 100)
|
|
1126
|
+
.addRequiredClusterServers();
|
|
1127
|
+
this.thermoAutoSchedules = await this.addDevice(this.thermoAutoSchedules);
|
|
1128
|
+
}
|
|
1129
|
+
this.thermoAutoSchedules?.addCommandHandler('identify', ({ request: { identifyTime } }) => {
|
|
1130
|
+
this.thermoAutoSchedules?.log.info(`Command identify called identifyTime ${identifyTime}`);
|
|
1131
|
+
});
|
|
1132
|
+
this.thermoAutoSchedules?.addCommandHandler('triggerEffect', ({ request: { effectIdentifier, effectVariant } }) => {
|
|
1133
|
+
this.thermoAutoSchedules?.log.info(`Command identify called effectIdentifier ${effectIdentifier} effectVariant ${effectVariant}`);
|
|
1134
|
+
});
|
|
1135
|
+
this.thermoAutoSchedules?.addCommandHandler('setpointRaiseLower', ({ request: { mode, amount } }) => {
|
|
1136
|
+
const lookupSetpointAdjustMode = ['Heat', 'Cool', 'Both'];
|
|
1137
|
+
this.thermoAutoSchedules?.log.info(`Command setpointRaiseLower called with mode: ${lookupSetpointAdjustMode[mode]} amount: ${amount / 10}`);
|
|
1138
|
+
});
|
|
1139
|
+
this.thermoAutoSchedules?.addCommandHandler('setActiveScheduleRequest', ({ request: { scheduleHandle } }) => {
|
|
1140
|
+
this.thermoAutoSchedules?.log.info(`Command setActiveScheduleRequest called with scheduleHandle: ${scheduleHandle ? `0x${Buffer.from(scheduleHandle).toString('hex')}` : 'null'}`);
|
|
1141
|
+
});
|
|
1142
|
+
this.thermoAutoSchedules?.subscribeAttribute(Thermostat, 'systemMode', (newValue, oldValue) => {
|
|
1143
|
+
const lookupSystemMode = ['Off', 'Auto', '', 'Cool', 'Heat', 'EmergencyHeat', 'Precooling', 'FanOnly', 'Dry', 'Sleep'];
|
|
1144
|
+
this.thermoAutoSchedules?.log.info(`Subscribe systemMode called with: ${lookupSystemMode[newValue]} (old value: ${lookupSystemMode[oldValue]})`);
|
|
1145
|
+
}, this.thermoAutoSchedules.log);
|
|
1146
|
+
this.thermoAutoSchedules?.subscribeAttribute(Thermostat.id, 'occupiedHeatingSetpoint', (newValue, oldValue) => {
|
|
1147
|
+
this.thermoAutoSchedules?.log.info(`Subscribe occupiedHeatingSetpoint called with: ${newValue / 100} (old value: ${oldValue / 100})`);
|
|
1148
|
+
}, this.thermoAutoSchedules.log);
|
|
1149
|
+
this.thermoAutoSchedules?.subscribeAttribute(Thermostat.id, 'occupiedCoolingSetpoint', (newValue, oldValue) => {
|
|
1150
|
+
this.thermoAutoSchedules?.log.info(`Subscribe occupiedCoolingSetpoint called with: ${newValue / 100} (old value: ${oldValue / 100})`);
|
|
1151
|
+
}, this.thermoAutoSchedules.log);
|
|
1152
|
+
this.thermoAutoSchedules?.subscribeAttribute(Thermostat.id, 'activeScheduleHandle', (newValue, oldValue) => {
|
|
1153
|
+
this.thermoAutoSchedules?.log.info(`Subscribe activeScheduleHandle called with: ${newValue ? `0x${Buffer.from(newValue).toString('hex')}` : 'null'} (old value: ${oldValue ? `0x${Buffer.from(oldValue).toString('hex')}` : 'null'})`);
|
|
1154
|
+
}, this.thermoAutoSchedules.log);
|
|
1155
|
+
this.thermoAutoSchedules?.subscribeAttribute(Thermostat.id, 'schedules', (newValue, oldValue) => {
|
|
1156
|
+
this.thermoAutoSchedules?.log.info(`Subscribe schedules called with: ${debugStringify(newValue)} (old value: ${debugStringify(oldValue)})`);
|
|
1157
|
+
}, this.thermoAutoSchedules.log);
|
|
1078
1158
|
this.thermoHeat = new MatterbridgeEndpoint([thermostat, bridgedNode, powerSource], { id: 'Thermostat (Heat)' }, this.config.debug)
|
|
1079
1159
|
.createDefaultIdentifyClusterServer()
|
|
1080
1160
|
.createDefaultBridgedDeviceBasicInformationClusterServer('Thermostat (Heat)', 'THE00024', 0xfff1, 'Matterbridge', 'Matterbridge Thermostat')
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge-example-dynamic-platform",
|
|
3
|
-
"version": "3.0.2-dev-
|
|
3
|
+
"version": "3.0.2-dev-20260809-1aeac01",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "matterbridge-example-dynamic-platform",
|
|
9
|
-
"version": "3.0.2-dev-
|
|
9
|
+
"version": "3.0.2-dev-20260809-1aeac01",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"node-ansi-logger": "3.3.0",
|
package/package.json
CHANGED