matterbridge-example-dynamic-platform 2.0.14 → 2.0.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 +23 -0
- package/README.md +2 -1
- package/dist/module.js +45 -14
- package/matterbridge-example-dynamic-platform.schema.json +4 -4
- package/npm-shrinkwrap.json +3 -3
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -26,6 +26,29 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
26
26
|
|
|
27
27
|
<a href="https://www.buymeacoffee.com/luligugithub"><img src="https://matterbridge.io/assets/bmc-button.svg" alt="Buy me a coffee" width="120"></a>
|
|
28
28
|
|
|
29
|
+
## [2.0.15] - 2026-04-08
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- [DoorLock]: Add a doorLock device with User and Pin features.
|
|
34
|
+
- [Fan]: Implement Auto >>> percentSetting = null rule. Thanks Ludovic BOUÉ (https://github.com/Luligu/matterbridge-example-dynamic-platform/issues/54).
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- [package]: Bump package to `automator` v.3.1.5.
|
|
39
|
+
- [package]: Bump `eslint` to v.10.2.0.
|
|
40
|
+
- [package]: Bump `typescript` to v.6.0.2.
|
|
41
|
+
- [package]: Bump `typescript-eslint` to v.8.58.1.
|
|
42
|
+
- [devcontainer]: Fix pull of new image.
|
|
43
|
+
- [devcontainer]: Update VS Code settings.
|
|
44
|
+
- [devcontainer]: Leave matterbridge scripts in the cloned repo.
|
|
45
|
+
- [scripts]: Update mb-run script.
|
|
46
|
+
- [scripts]: Update package watch script.
|
|
47
|
+
- [scripts]: Add prune-releases script.
|
|
48
|
+
- [package]: Add `CODE_OF_CONDUCT.md`.
|
|
49
|
+
|
|
50
|
+
<a href="https://www.buymeacoffee.com/luligugithub"><img src="https://matterbridge.io/assets/bmc-button.svg" alt="Buy me a coffee" width="80"></a>
|
|
51
|
+
|
|
29
52
|
## [2.0.14] - 2026-03-20
|
|
30
53
|
|
|
31
54
|
### Changed
|
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
Matterbridge dynamic platform example plugin is a template to develop your own plugin using the dynamic platform.
|
|
26
26
|
|
|
27
|
-
It exposes
|
|
27
|
+
It exposes 70 virtual devices:
|
|
28
28
|
|
|
29
29
|
- a door contact sensor
|
|
30
30
|
- a motion sensor
|
|
@@ -95,6 +95,7 @@ It exposes 68 virtual devices:
|
|
|
95
95
|
- a speaker device (supported by SmartThings)
|
|
96
96
|
- a soil sensor (Matter 1.5.0)
|
|
97
97
|
- an irrigation system (Matter 1.5.0)
|
|
98
|
+
- an irrigation system with four zones (Matter 1.5.0)
|
|
98
99
|
|
|
99
100
|
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.
|
|
100
101
|
|
package/dist/module.js
CHANGED
|
@@ -3,7 +3,7 @@ import { AirConditioner, BasicVideoPlayer, BatteryStorage, Cooktop, Dishwasher,
|
|
|
3
3
|
import { debugStringify } from 'matterbridge/logger';
|
|
4
4
|
import { AreaNamespaceTag, LocationTag, NumberTag, PositionTag, RefrigeratorTag, SwitchesTag, UINT16_MAX, UINT32_MAX } from 'matterbridge/matter';
|
|
5
5
|
import { AirQuality, BooleanState, BridgedDeviceBasicInformation, CarbonDioxideConcentrationMeasurement, CarbonMonoxideConcentrationMeasurement, ColorControl, Descriptor, DeviceEnergyManagement, DoorLock, ElectricalEnergyMeasurement, ElectricalPowerMeasurement, EnergyEvse, EnergyEvseMode, FanControl, FlowMeasurement, FormaldehydeConcentrationMeasurement, Identify, IlluminanceMeasurement, LevelControl, NitrogenDioxideConcentrationMeasurement, OccupancySensing, OnOff, OnOffCluster, OperationalState, OvenMode, OzoneConcentrationMeasurement, Pm1ConcentrationMeasurement, Pm10ConcentrationMeasurement, Pm25ConcentrationMeasurement, PowerSource, PressureMeasurement, RadonConcentrationMeasurement, RelativeHumidityMeasurement, RelativeHumidityMeasurementCluster, RvcCleanMode, RvcOperationalState, RvcRunMode, SmokeCoAlarm, TemperatureMeasurement, Thermostat, ThermostatCluster, TotalVolatileOrganicCompoundsConcentrationMeasurement, WindowCovering, } from 'matterbridge/matter/clusters';
|
|
6
|
-
import { isValidBoolean, isValidNumber, isValidObject, isValidString } from 'matterbridge/utils';
|
|
6
|
+
import { getEnumDescription, isValidBoolean, isValidNumber, isValidObject, isValidString } from 'matterbridge/utils';
|
|
7
7
|
function luxToMatter(lux) {
|
|
8
8
|
if (!Number.isFinite(lux) || lux <= 0)
|
|
9
9
|
return 0;
|
|
@@ -55,6 +55,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
55
55
|
coverLift;
|
|
56
56
|
coverLiftTilt;
|
|
57
57
|
lock;
|
|
58
|
+
userPinLock;
|
|
58
59
|
thermoAuto;
|
|
59
60
|
thermoAutoOccupancy;
|
|
60
61
|
thermoAutoPresets;
|
|
@@ -105,8 +106,8 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
105
106
|
constructor(matterbridge, log, config) {
|
|
106
107
|
super(matterbridge, log, config);
|
|
107
108
|
this.config = config;
|
|
108
|
-
if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.7.
|
|
109
|
-
throw new Error(`This plugin requires Matterbridge version >= "3.7.
|
|
109
|
+
if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.7.2')) {
|
|
110
|
+
throw new Error(`This plugin requires Matterbridge version >= "3.7.2". Please update Matterbridge from ${this.matterbridge.matterbridgeVersion} to the latest version in the frontend.`);
|
|
110
111
|
}
|
|
111
112
|
this.log.info('Initializing platform:', this.config.name);
|
|
112
113
|
}
|
|
@@ -700,22 +701,44 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
700
701
|
.createDefaultPowerSourceRechargeableBatteryClusterServer(30)
|
|
701
702
|
.addRequiredClusterServers();
|
|
702
703
|
this.lock = await this.addDevice(this.lock);
|
|
703
|
-
this.lock?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
|
|
704
|
+
this.lock?.addCommandHandler('Identify.identify', async ({ request: { identifyTime } }) => {
|
|
704
705
|
this.lock?.log.info(`Command identify called identifyTime:${identifyTime}`);
|
|
705
706
|
});
|
|
706
|
-
this.lock?.addCommandHandler('lockDoor', async () => {
|
|
707
|
+
this.lock?.addCommandHandler('DoorLock.lockDoor', async () => {
|
|
707
708
|
this.lock?.log.info('Command lockDoor called');
|
|
708
709
|
});
|
|
709
|
-
this.lock?.addCommandHandler('unlockDoor', async () => {
|
|
710
|
+
this.lock?.addCommandHandler('DoorLock.unlockDoor', async () => {
|
|
710
711
|
this.lock?.log.info('Command unlockDoor called');
|
|
711
712
|
});
|
|
712
713
|
await this.lock?.subscribeAttribute(DoorLock.Cluster.id, 'operatingMode', (value) => {
|
|
713
|
-
|
|
714
|
-
this.lock?.log.info('Subscribe operatingMode called with:', lookupOperatingMode[value]);
|
|
715
|
-
const actuatorEnabled = value !== DoorLock.OperatingMode.NoRemoteLockUnlock;
|
|
716
|
-
this.lock?.setAttribute(DoorLock.Cluster.id, 'actuatorEnabled', actuatorEnabled);
|
|
717
|
-
this.lock?.log.info(`actuatorEnabled set to ${actuatorEnabled}`);
|
|
714
|
+
this.lock?.log.info(`Subscribe operatingMode called with: ${getEnumDescription(DoorLock.OperatingMode, value)}`);
|
|
718
715
|
}, this.lock.log);
|
|
716
|
+
this.userPinLock = new MatterbridgeEndpoint([doorLockDevice, bridgedNode, powerSource], { id: 'UserPinLock' }, this.config.debug)
|
|
717
|
+
.createDefaultIdentifyClusterServer()
|
|
718
|
+
.createDefaultBridgedDeviceBasicInformationClusterServer('Lock with User and Pin', 'LUP00070', 0xfff1, 'Matterbridge', 'Matterbridge Lock')
|
|
719
|
+
.createUserPinDoorLockClusterServer()
|
|
720
|
+
.createDefaultPowerSourceRechargeableBatteryClusterServer(95)
|
|
721
|
+
.addRequiredClusterServers();
|
|
722
|
+
this.userPinLock = await this.addDevice(this.userPinLock);
|
|
723
|
+
await this.userPinLock?.setAttribute(PowerSource.Cluster.with(PowerSource.Feature.Rechargeable, PowerSource.Feature.Battery), 'batChargeState', PowerSource.BatChargeState.IsCharging);
|
|
724
|
+
this.userPinLock?.addCommandHandler('Identify.identify', async ({ request: { identifyTime } }) => {
|
|
725
|
+
this.userPinLock?.log.info(`Command identify called identifyTime:${identifyTime}`);
|
|
726
|
+
});
|
|
727
|
+
this.userPinLock?.addCommandHandler('DoorLock.lockDoor', async () => {
|
|
728
|
+
this.userPinLock?.log.info('Command lockDoor called');
|
|
729
|
+
});
|
|
730
|
+
this.userPinLock?.addCommandHandler('DoorLock.unlockDoor', async () => {
|
|
731
|
+
this.userPinLock?.log.info('Command unlockDoor called');
|
|
732
|
+
});
|
|
733
|
+
await this.userPinLock?.subscribeAttribute(DoorLock.Cluster, 'operatingMode', (value) => {
|
|
734
|
+
this.userPinLock?.log.info(`Subscribe operatingMode called with: ${getEnumDescription(DoorLock.OperatingMode, value)}`);
|
|
735
|
+
}, this.userPinLock.log);
|
|
736
|
+
await this.userPinLock?.subscribeAttribute(DoorLock.Complete, 'wrongCodeEntryLimit', (value) => {
|
|
737
|
+
this.userPinLock?.log.info(`Subscribe wrongCodeEntryLimit called with: ${value}`);
|
|
738
|
+
}, this.userPinLock.log);
|
|
739
|
+
await this.userPinLock?.subscribeAttribute(DoorLock.Complete, 'userCodeTemporaryDisableTime', (value) => {
|
|
740
|
+
this.userPinLock?.log.info(`Subscribe userCodeTemporaryDisableTime called with: ${value}`);
|
|
741
|
+
}, this.userPinLock.log);
|
|
719
742
|
this.thermoAuto = new MatterbridgeEndpoint([thermostatDevice, bridgedNode, powerSource], { id: 'Thermostat (AutoMode)' }, this.config.debug)
|
|
720
743
|
.createDefaultIdentifyClusterServer()
|
|
721
744
|
.createDefaultBridgedDeviceBasicInformationClusterServer('Thermostat (Auto)', 'TAU00023', 0xfff1, 'Matterbridge', 'Matterbridge Thermostat')
|
|
@@ -1093,11 +1116,12 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
1093
1116
|
this.fanDefault?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 100, this.fanDefault?.log);
|
|
1094
1117
|
}
|
|
1095
1118
|
else if (newValue === FanControl.FanMode.On) {
|
|
1119
|
+
this.fanDefault?.setAttribute(FanControl.Cluster.id, 'fanMode', FanControl.FanMode.High, this.fanDefault?.log);
|
|
1096
1120
|
this.fanDefault?.setAttribute(FanControl.Cluster.id, 'percentSetting', 100, this.fanDefault?.log);
|
|
1097
1121
|
this.fanDefault?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 100, this.fanDefault?.log);
|
|
1098
1122
|
}
|
|
1099
1123
|
else if (newValue === FanControl.FanMode.Auto) {
|
|
1100
|
-
this.fanDefault?.setAttribute(FanControl.Cluster.id, 'percentSetting',
|
|
1124
|
+
this.fanDefault?.setAttribute(FanControl.Cluster.id, 'percentSetting', null, this.fanDefault?.log);
|
|
1101
1125
|
this.fanDefault?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 50, this.fanDefault?.log);
|
|
1102
1126
|
}
|
|
1103
1127
|
}, this.fanDefault.log);
|
|
@@ -1135,11 +1159,12 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
1135
1159
|
this.fanBase?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 100, this.fanBase?.log);
|
|
1136
1160
|
}
|
|
1137
1161
|
else if (newValue === FanControl.FanMode.On) {
|
|
1162
|
+
this.fanBase?.setAttribute(FanControl.Cluster.id, 'fanMode', FanControl.FanMode.High, this.fanBase?.log);
|
|
1138
1163
|
this.fanBase?.setAttribute(FanControl.Cluster.id, 'percentSetting', 100, this.fanBase?.log);
|
|
1139
1164
|
this.fanBase?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 100, this.fanBase?.log);
|
|
1140
1165
|
}
|
|
1141
1166
|
else if (newValue === FanControl.FanMode.Auto) {
|
|
1142
|
-
this.fanBase?.setAttribute(FanControl.Cluster.id, 'percentSetting',
|
|
1167
|
+
this.fanBase?.setAttribute(FanControl.Cluster.id, 'percentSetting', null, this.fanBase?.log);
|
|
1143
1168
|
this.fanBase?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 50, this.fanBase?.log);
|
|
1144
1169
|
}
|
|
1145
1170
|
}, this.fanBase.log);
|
|
@@ -1168,6 +1193,11 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
1168
1193
|
this.fanOnHigh?.setAttribute(FanControl.Cluster.id, 'percentSetting', 100, this.fanOnHigh?.log);
|
|
1169
1194
|
this.fanOnHigh?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 100, this.fanOnHigh?.log);
|
|
1170
1195
|
}
|
|
1196
|
+
else if (newValue === FanControl.FanMode.On) {
|
|
1197
|
+
this.fanBase?.setAttribute(FanControl.Cluster.id, 'fanMode', FanControl.FanMode.High, this.fanBase?.log);
|
|
1198
|
+
this.fanBase?.setAttribute(FanControl.Cluster.id, 'percentSetting', 100, this.fanBase?.log);
|
|
1199
|
+
this.fanBase?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 100, this.fanBase?.log);
|
|
1200
|
+
}
|
|
1171
1201
|
}, this.fanOnHigh.log);
|
|
1172
1202
|
await this.fanOnHigh?.subscribeAttribute(FanControl.Cluster.id, 'percentSetting', (newValue, oldValue, context) => {
|
|
1173
1203
|
this.fanOnHigh?.log.info(`Percent setting changed from ${oldValue} to ${newValue} context: ${context.offline === true ? 'offline' : 'online'}`);
|
|
@@ -1207,11 +1237,12 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
1207
1237
|
this.fanComplete?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 100, this.fanComplete?.log);
|
|
1208
1238
|
}
|
|
1209
1239
|
else if (newValue === FanControl.FanMode.On) {
|
|
1240
|
+
this.fanComplete?.setAttribute(FanControl.Cluster.id, 'fanMode', FanControl.FanMode.High, this.fanComplete?.log);
|
|
1210
1241
|
this.fanComplete?.setAttribute(FanControl.Cluster.id, 'percentSetting', 100, this.fanComplete?.log);
|
|
1211
1242
|
this.fanComplete?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 100, this.fanComplete?.log);
|
|
1212
1243
|
}
|
|
1213
1244
|
else if (newValue === FanControl.FanMode.Auto) {
|
|
1214
|
-
this.fanComplete?.setAttribute(FanControl.Cluster.id, 'percentSetting',
|
|
1245
|
+
this.fanComplete?.setAttribute(FanControl.Cluster.id, 'percentSetting', null, this.fanComplete?.log);
|
|
1215
1246
|
this.fanComplete?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 50, this.fanComplete?.log);
|
|
1216
1247
|
}
|
|
1217
1248
|
}, this.fanComplete?.log);
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
"required": [],
|
|
6
6
|
"properties": {
|
|
7
7
|
"name": {
|
|
8
|
-
"description": "Plugin
|
|
8
|
+
"description": "Plugin Name",
|
|
9
9
|
"type": "string",
|
|
10
10
|
"readOnly": true,
|
|
11
11
|
"ui:widget": "hidden"
|
|
12
12
|
},
|
|
13
13
|
"type": {
|
|
14
|
-
"description": "Plugin
|
|
14
|
+
"description": "Plugin Type",
|
|
15
15
|
"type": "string",
|
|
16
16
|
"readOnly": true,
|
|
17
17
|
"ui:widget": "hidden"
|
|
@@ -49,13 +49,13 @@
|
|
|
49
49
|
"default": true
|
|
50
50
|
},
|
|
51
51
|
"debug": {
|
|
52
|
-
"title": "Debug",
|
|
52
|
+
"title": "Enable Debug",
|
|
53
53
|
"description": "Enable the debug for the plugin (development only)",
|
|
54
54
|
"type": "boolean",
|
|
55
55
|
"default": false
|
|
56
56
|
},
|
|
57
57
|
"unregisterOnShutdown": {
|
|
58
|
-
"title": "Unregister
|
|
58
|
+
"title": "Unregister On Shutdown",
|
|
59
59
|
"description": "Unregister all devices on shutdown (development only)",
|
|
60
60
|
"type": "boolean",
|
|
61
61
|
"default": false
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge-example-dynamic-platform",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.15",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "matterbridge-example-dynamic-platform",
|
|
9
|
-
"version": "2.0.
|
|
9
|
+
"version": "2.0.15",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"node-ansi-logger": "3.2.0",
|
|
13
13
|
"node-persist-manager": "2.0.1"
|
|
14
14
|
},
|
|
15
15
|
"engines": {
|
|
16
|
-
"node": ">=20.
|
|
16
|
+
"node": ">=20.19.0 <21.0.0 || >=22.13.0 <23.0.0 || >=24.0.0 <25.0.0"
|
|
17
17
|
},
|
|
18
18
|
"funding": {
|
|
19
19
|
"type": "buymeacoffee",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge-example-dynamic-platform",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.15",
|
|
4
4
|
"description": "Matterbridge dynamic plugin",
|
|
5
5
|
"author": "https://github.com/Luligu",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"ewelink"
|
|
57
57
|
],
|
|
58
58
|
"engines": {
|
|
59
|
-
"node": ">=20.
|
|
59
|
+
"node": ">=20.19.0 <21.0.0 || >=22.13.0 <23.0.0 || >=24.0.0 <25.0.0"
|
|
60
60
|
},
|
|
61
61
|
"files": [
|
|
62
62
|
"bin",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"node-persist-manager": "2.0.1"
|
|
72
72
|
},
|
|
73
73
|
"overrides": {
|
|
74
|
-
"eslint": "10.
|
|
74
|
+
"eslint": "10.2.0",
|
|
75
75
|
"@eslint/js": "10.0.1"
|
|
76
76
|
}
|
|
77
77
|
}
|