matterbridge-example-dynamic-platform 3.0.3-dev-20260830-a347a26 → 3.0.4-dev-20260901-796d818
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 +12 -2
- package/dist/module.js +64 -171
- package/npm-shrinkwrap.json +10 -10
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -29,12 +29,20 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
29
29
|
|
|
30
30
|
<a href="https://www.buymeacoffee.com/luligugithub"><img src="https://matterbridge.io/assets/bmc-button.svg" alt="Buy me a coffee" width="120"></a>
|
|
31
31
|
|
|
32
|
-
## [3.0.
|
|
32
|
+
## [3.0.4] - Dev branch
|
|
33
|
+
|
|
34
|
+
### Breaking changes
|
|
35
|
+
|
|
36
|
+
- [matterbridge]: Require matterbridge v.3.10.8 with matter v.1.6.0.
|
|
37
|
+
|
|
38
|
+
<a href="https://www.buymeacoffee.com/luligugithub"><img src="https://matterbridge.io/assets/bmc-button.svg" alt="Buy me a coffee" width="80"></a>
|
|
39
|
+
|
|
40
|
+
## [3.0.3] - 2026-08-30
|
|
33
41
|
|
|
34
42
|
### Breaking changes
|
|
35
43
|
|
|
36
44
|
- [matterbridge]: Require matterbridge v.3.10.7 with matter v.1.6.0.
|
|
37
|
-
- [fanControl]: Matterbridge v.3.10.
|
|
45
|
+
- [fanControl]: Matterbridge v.3.10.7 now manages the compliant FanControl `fanMode` and `percentSetting` synchronization; plugins now only update `percentCurrent` as physical device feedback from `fanMode` and `percentSetting`.
|
|
38
46
|
|
|
39
47
|
### Added
|
|
40
48
|
|
|
@@ -48,6 +56,8 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
48
56
|
- [package]: Bump `@types/node` to v.26.4.0.
|
|
49
57
|
- [package]: Bump `oxfmt` to v.0.65.0.
|
|
50
58
|
- [package]: Bump `oxlint` to v.1.80.0.
|
|
59
|
+
- [package]: Bump `node-ansi-logger` to v.3.3.1.
|
|
60
|
+
- [package]: Bump `node-persist-manager` to v.2.1.1.
|
|
51
61
|
|
|
52
62
|
### Fixed
|
|
53
63
|
|
package/dist/module.js
CHANGED
|
@@ -1,22 +1,9 @@
|
|
|
1
|
-
import { aggregator, airPurifier, airQualitySensor, bridgedNode,
|
|
2
|
-
import { AirConditioner, BasicVideoPlayer, BatteryStorage, Closure, Cooktop, Dishwasher, Evse, ExtractorHood, HeatPump, IrrigationSystem, LaundryDryer, LaundryWasher,
|
|
1
|
+
import { aggregator, airPurifier, airQualitySensor, bridgedNode, colorTemperatureLight, contactSensor, windowCovering, dimmableLight, mountedDimmableLoadControl, dimmablePlugInUnit, doorLock, electricalSensor, extendedColorLight, fan, flowSensor, genericSwitch, getSemtag, humiditySensor, lightSensor, MatterbridgeDynamicPlatform, MatterbridgeEndpoint, modeSelect, occupancySensor, onOffLight, mountedOnOffControl, onOffPlugInUnit, onOffLightSwitch, powerSource, pressureSensor, pump, rainSensor, smokeCoAlarm, temperatureSensor, thermostat, waterFreezeDetector, waterLeakDetector, waterValve, } from 'matterbridge';
|
|
2
|
+
import { AirConditioner, BasicVideoPlayer, BatteryStorage, Closure, Cooktop, Dishwasher, Evse, ExtractorHood, HeatPump, IrrigationSystem, LaundryDryer, LaundryWasher, MicrowaveOven, Oven, Refrigerator, RoboticVacuumCleaner, SoilSensor, SolarPower, Speaker, WaterHeater, } from 'matterbridge/devices';
|
|
3
3
|
import { debugStringify } from 'matterbridge/logger';
|
|
4
4
|
import { ClosureCoveringTag, ClosurePanelTag, ClosureTag, ClosureWindowTag, CommonAreaNamespaceTag, CommonLocationTag, CommonNumberTag, CommonPositionTag, RefrigeratorTag, SwitchesTag, UINT16_MAX, UINT32_MAX, } from 'matterbridge/matter';
|
|
5
5
|
import { AirQuality, BooleanState, BridgedDeviceBasicInformation, CarbonDioxideConcentrationMeasurement, CarbonMonoxideConcentrationMeasurement, ClosureControl, ClosureDimension, ColorControl, DeviceEnergyManagement, DoorLock, ElectricalEnergyMeasurement, ElectricalPowerMeasurement, EnergyEvse, EnergyEvseMode, FanControl, FlowMeasurement, FormaldehydeConcentrationMeasurement, Identify, IlluminanceMeasurement, LevelControl, NitrogenDioxideConcentrationMeasurement, OccupancySensing, OnOff, OperationalState, OvenMode, OzoneConcentrationMeasurement, Pm1ConcentrationMeasurement, Pm10ConcentrationMeasurement, Pm25ConcentrationMeasurement, PowerSource, PressureMeasurement, RadonConcentrationMeasurement, RelativeHumidityMeasurement, RvcCleanMode, RvcOperationalState, RvcRunMode, SmokeCoAlarm, TemperatureMeasurement, Thermostat, TotalVolatileOrganicCompoundsConcentrationMeasurement, WindowCovering, } from 'matterbridge/matter/clusters';
|
|
6
|
-
import {
|
|
7
|
-
import { fireAndForget, getEnumDescription, isValidBoolean, isValidNumber, isValidObject, isValidString, parseVersionString } from 'matterbridge/utils';
|
|
8
|
-
function luxToMatter(lux) {
|
|
9
|
-
if (!Number.isFinite(lux) || lux < 1)
|
|
10
|
-
return 0;
|
|
11
|
-
const encoded = Math.round(10000 * Math.log10(lux) + 1);
|
|
12
|
-
return Math.min(encoded, 0xfffe);
|
|
13
|
-
}
|
|
14
|
-
function matterToLux(value) {
|
|
15
|
-
if (!Number.isFinite(value) || value <= 0)
|
|
16
|
-
return 0;
|
|
17
|
-
const v = Math.min(value, 0xfffe);
|
|
18
|
-
return Math.round(Math.pow(10, (v - 1) / 10000));
|
|
19
|
-
}
|
|
6
|
+
import { fireAndForget, getEnumDescription, isValidBoolean, isValidNumber, isValidObject, isValidString, luxToMatter, matterToLux, parseVersionString } from 'matterbridge/utils';
|
|
20
7
|
export default function initializePlugin(matterbridge, log, config) {
|
|
21
8
|
return new ExampleMatterbridgeDynamicPlatform(matterbridge, log, config);
|
|
22
9
|
}
|
|
@@ -110,8 +97,8 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
110
97
|
constructor(matterbridge, log, config) {
|
|
111
98
|
super(matterbridge, log, config);
|
|
112
99
|
this.config = config;
|
|
113
|
-
if (typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.10.
|
|
114
|
-
throw new Error(`This plugin requires Matterbridge version >= "3.10.
|
|
100
|
+
if (typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.10.8')) {
|
|
101
|
+
throw new Error(`This plugin requires Matterbridge version >= "3.10.8". Please update Matterbridge from ${this.matterbridge.matterbridgeVersion} to the latest version in the frontend.`);
|
|
115
102
|
}
|
|
116
103
|
this.log.info('Initializing platform:', this.config.name);
|
|
117
104
|
}
|
|
@@ -180,41 +167,42 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
180
167
|
this.irrigationSystem = await this.addDevice(this.irrigationSystem);
|
|
181
168
|
this.closureGarageDoor = new Closure('Garage Door', 'GAR000071', {
|
|
182
169
|
tagList: [getSemtag(ClosureTag.GarageDoor)],
|
|
170
|
+
movementDuration: 2000,
|
|
183
171
|
});
|
|
184
172
|
this.closureGarageDoor = await this.addDevice(this.closureGarageDoor);
|
|
185
|
-
|
|
186
|
-
function closureTargetToCurrentPosition(position) {
|
|
187
|
-
if (position === ClosureControl.TargetPosition.MoveToFullyClosed)
|
|
188
|
-
return ClosureControl.CurrentPosition.FullyClosed;
|
|
189
|
-
if (position === ClosureControl.TargetPosition.MoveToFullyOpen)
|
|
190
|
-
return ClosureControl.CurrentPosition.FullyOpened;
|
|
191
|
-
if (position === ClosureControl.TargetPosition.MoveToPedestrianPosition)
|
|
192
|
-
return ClosureControl.CurrentPosition.OpenedForPedestrian;
|
|
193
|
-
if (position === ClosureControl.TargetPosition.MoveToVentilationPosition)
|
|
194
|
-
return ClosureControl.CurrentPosition.OpenedForVentilation;
|
|
195
|
-
return ClosureControl.CurrentPosition.OpenedAtSignature;
|
|
196
|
-
}
|
|
197
|
-
this.closureGarageDoor?.addCommandHandler('ClosureControl.moveTo', ({ request: { position, latch, speed }, attributes }) => {
|
|
173
|
+
this.closureGarageDoor?.addCommandHandler('ClosureControl.moveTo', ({ request: { position, latch, speed } }) => {
|
|
198
174
|
this.closureGarageDoor?.log.info(`Command moveTo called position:${position} latch:${latch} speed:${speed}`);
|
|
199
|
-
attributes.countdownTime = 1;
|
|
200
|
-
closureGarageDoorMoveTimeout = setTimeout(() => {
|
|
201
|
-
const targetState = this.closureGarageDoor?.getAttribute(ClosureControl, 'overallTargetState');
|
|
202
|
-
if (targetState === undefined || targetState === null || targetState.position === undefined || targetState.position === null)
|
|
203
|
-
return;
|
|
204
|
-
void this.closureGarageDoor?.setState({
|
|
205
|
-
position: closureTargetToCurrentPosition(targetState.position),
|
|
206
|
-
latch: targetState.latch,
|
|
207
|
-
speed: targetState.speed,
|
|
208
|
-
secureState: targetState.position === ClosureControl.TargetPosition.MoveToFullyClosed && targetState.latch === true,
|
|
209
|
-
}, targetState, ClosureControl.MainState.Stopped, 0, []);
|
|
210
|
-
void this.closureGarageDoor?.triggerMovementCompleted();
|
|
211
|
-
}, 1000).unref();
|
|
212
175
|
});
|
|
213
|
-
this.closureGarageDoor?.addCommandHandler('ClosureControl.stop', (
|
|
176
|
+
this.closureGarageDoor?.addCommandHandler('ClosureControl.stop', () => {
|
|
214
177
|
this.closureGarageDoor?.log.info('Command stop called');
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
178
|
+
});
|
|
179
|
+
this.closureSlidingGate = new Closure('Sliding Gate', 'GAT000073', {
|
|
180
|
+
tagList: [getSemtag(ClosureTag.Gate)],
|
|
181
|
+
movementDuration: 2000,
|
|
182
|
+
motionLatching: true,
|
|
183
|
+
speed: true,
|
|
184
|
+
pedestrian: true,
|
|
185
|
+
});
|
|
186
|
+
this.closureSlidingGate = await this.addDevice(this.closureSlidingGate);
|
|
187
|
+
this.closureSlidingGate?.addCommandHandler('ClosureControl.moveTo', ({ request: { position, latch, speed } }) => {
|
|
188
|
+
this.closureSlidingGate?.log.info(`Command moveTo called position:${position} latch:${latch} speed:${speed}`);
|
|
189
|
+
});
|
|
190
|
+
this.closureSlidingGate?.addCommandHandler('ClosureControl.stop', () => {
|
|
191
|
+
this.closureSlidingGate?.log.info('Command stop called');
|
|
192
|
+
});
|
|
193
|
+
this.closureRoofWindow = new Closure('Roof Window', 'ROO000074', {
|
|
194
|
+
tagList: [getSemtag(ClosureTag.Window), getSemtag(ClosureWindowTag.Roof)],
|
|
195
|
+
movementDuration: 2000,
|
|
196
|
+
motionLatching: true,
|
|
197
|
+
speed: true,
|
|
198
|
+
ventilation: true,
|
|
199
|
+
});
|
|
200
|
+
this.closureRoofWindow = await this.addDevice(this.closureRoofWindow);
|
|
201
|
+
this.closureRoofWindow?.addCommandHandler('ClosureControl.moveTo', ({ request: { position, latch, speed } }) => {
|
|
202
|
+
this.closureRoofWindow?.log.info(`Command moveTo called position:${position} latch:${latch} speed:${speed}`);
|
|
203
|
+
});
|
|
204
|
+
this.closureRoofWindow?.addCommandHandler('ClosureControl.stop', () => {
|
|
205
|
+
this.closureRoofWindow?.log.info('Command stop called');
|
|
218
206
|
});
|
|
219
207
|
this.closureVenetianBlind = new Closure('Venetian Blind', 'VEN000072', {
|
|
220
208
|
tagList: [getSemtag(ClosureTag.Covering), getSemtag(ClosureCoveringTag.Venetian)],
|
|
@@ -222,13 +210,6 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
222
210
|
const closureVenetianBlindLift = this.closureVenetianBlind.addPanel('Lift', [getSemtag(ClosurePanelTag.Lift)], 'lift');
|
|
223
211
|
const closureVenetianBlindTilt = this.closureVenetianBlind.addPanel('Tilt', [getSemtag(ClosurePanelTag.Tilt)], 'tilt');
|
|
224
212
|
this.closureVenetianBlind = await this.addDevice(this.closureVenetianBlind);
|
|
225
|
-
const closurePanelTargetPercent = (position) => {
|
|
226
|
-
if (position === ClosureControl.TargetPosition.MoveToFullyOpen)
|
|
227
|
-
return 0;
|
|
228
|
-
if (position === ClosureControl.TargetPosition.MoveToFullyClosed)
|
|
229
|
-
return 10000;
|
|
230
|
-
return 5000;
|
|
231
|
-
};
|
|
232
213
|
const closurePanelReachTimeouts = new Map();
|
|
233
214
|
let closureVenetianBlindMoveTimeout;
|
|
234
215
|
const clearClosureVenetianBlindTimeouts = () => {
|
|
@@ -253,7 +234,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
253
234
|
? ClosureControl.CurrentPosition.FullyClosed
|
|
254
235
|
: ClosureControl.CurrentPosition.PartiallyOpened;
|
|
255
236
|
void this.closureVenetianBlind?.setAttribute(ClosureControl, 'mainState', ClosureControl.MainState.Stopped, this.closureVenetianBlind.log);
|
|
256
|
-
void this.closureVenetianBlind?.setAttribute(ClosureControl, 'overallCurrentState', { position: overallPosition,
|
|
237
|
+
void this.closureVenetianBlind?.setAttribute(ClosureControl, 'overallCurrentState', { position: overallPosition, secureState: liftCurrent.position === 10000 }, this.closureVenetianBlind?.log);
|
|
257
238
|
};
|
|
258
239
|
const simulateClosurePanelReachingTarget = (panel) => {
|
|
259
240
|
clearTimeout(closurePanelReachTimeouts.get(panel));
|
|
@@ -268,8 +249,8 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
268
249
|
}, 1000).unref();
|
|
269
250
|
closurePanelReachTimeouts.set(panel, currentStateTimeout);
|
|
270
251
|
};
|
|
271
|
-
const moveClosurePanelTo = (panel, position
|
|
272
|
-
void panel.setAttribute(ClosureDimension, 'targetState', { position
|
|
252
|
+
const moveClosurePanelTo = (panel, position) => {
|
|
253
|
+
void panel.setAttribute(ClosureDimension, 'targetState', { position }, panel.log);
|
|
273
254
|
simulateClosurePanelReachingTarget(panel);
|
|
274
255
|
};
|
|
275
256
|
this.closureVenetianBlind?.addCommandHandler('ClosureControl.moveTo', ({ request: { position, latch, speed }, attributes }) => {
|
|
@@ -282,9 +263,11 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
282
263
|
const targetState = this.closureVenetianBlind?.getAttribute(ClosureControl, 'overallTargetState');
|
|
283
264
|
if (targetState === undefined || targetState === null || targetState.position === undefined || targetState.position === null)
|
|
284
265
|
return;
|
|
285
|
-
const panelPercent =
|
|
286
|
-
|
|
287
|
-
|
|
266
|
+
const panelPercent = this.closureVenetianBlind?.targetPositionToTargetPercent(targetState.position);
|
|
267
|
+
if (panelPercent === undefined)
|
|
268
|
+
return;
|
|
269
|
+
moveClosurePanelTo(closureVenetianBlindLift, panelPercent);
|
|
270
|
+
moveClosurePanelTo(closureVenetianBlindTilt, panelPercent);
|
|
288
271
|
}, 1000).unref();
|
|
289
272
|
});
|
|
290
273
|
this.closureVenetianBlind?.addCommandHandler('ClosureControl.stop', () => {
|
|
@@ -307,96 +290,6 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
307
290
|
};
|
|
308
291
|
addClosurePanelStepSimulation(closureVenetianBlindLift);
|
|
309
292
|
addClosurePanelStepSimulation(closureVenetianBlindTilt);
|
|
310
|
-
this.closureSlidingGate = new MatterbridgeEndpoint([closure, powerSource], {
|
|
311
|
-
id: 'SlidingGate-GAT000073',
|
|
312
|
-
tagList: [getSemtag(ClosureTag.Gate)],
|
|
313
|
-
}, this.config.debug)
|
|
314
|
-
.createDefaultIdentifyClusterServer()
|
|
315
|
-
.createDefaultBasicInformationClusterServer('Sliding Gate', 'GAT000073', 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Closure')
|
|
316
|
-
.createDefaultPowerSourceWiredClusterServer();
|
|
317
|
-
this.closureSlidingGate.behaviors.require(MatterbridgeClosureControlServer.with(ClosureControl.Feature.Positioning, ClosureControl.Feature.MotionLatching, ClosureControl.Feature.Speed, ClosureControl.Feature.Pedestrian), {
|
|
318
|
-
countdownTime: 0,
|
|
319
|
-
mainState: ClosureControl.MainState.Stopped,
|
|
320
|
-
currentErrorList: [],
|
|
321
|
-
overallCurrentState: { position: ClosureControl.CurrentPosition.FullyClosed, latch: true, speed: ThreeLevelAuto.Auto, secureState: true },
|
|
322
|
-
overallTargetState: { position: ClosureControl.TargetPosition.MoveToFullyClosed, latch: true, speed: ThreeLevelAuto.Auto },
|
|
323
|
-
latchControlModes: { remoteLatching: true, remoteUnlatching: true },
|
|
324
|
-
});
|
|
325
|
-
this.closureSlidingGate = await this.addDevice(this.closureSlidingGate);
|
|
326
|
-
let closureSlidingGateMoveTimeout;
|
|
327
|
-
this.closureSlidingGate?.addCommandHandler('ClosureControl.moveTo', ({ request: { position, latch, speed }, attributes }) => {
|
|
328
|
-
this.closureSlidingGate?.log.info(`Command moveTo called position:${position} latch:${latch} speed:${speed}`);
|
|
329
|
-
attributes.countdownTime = 1;
|
|
330
|
-
closureSlidingGateMoveTimeout = setTimeout(() => {
|
|
331
|
-
void (async () => {
|
|
332
|
-
const targetState = this.closureSlidingGate?.getAttribute(ClosureControl, 'overallTargetState');
|
|
333
|
-
if (targetState === undefined || targetState === null || targetState.position === undefined || targetState.position === null)
|
|
334
|
-
return;
|
|
335
|
-
await this.closureSlidingGate?.setAttribute(ClosureControl, 'countdownTime', 0, this.closureSlidingGate.log);
|
|
336
|
-
await this.closureSlidingGate?.setAttribute(ClosureControl, 'mainState', ClosureControl.MainState.Stopped, this.closureSlidingGate.log);
|
|
337
|
-
await this.closureSlidingGate?.setAttribute(ClosureControl, 'currentErrorList', [], this.closureSlidingGate.log);
|
|
338
|
-
await this.closureSlidingGate?.setAttribute(ClosureControl, 'overallCurrentState', {
|
|
339
|
-
position: closureTargetToCurrentPosition(targetState.position),
|
|
340
|
-
latch: targetState.latch,
|
|
341
|
-
speed: targetState.speed,
|
|
342
|
-
secureState: targetState.position === ClosureControl.TargetPosition.MoveToFullyClosed && targetState.latch === true,
|
|
343
|
-
}, this.closureSlidingGate.log);
|
|
344
|
-
await this.closureSlidingGate?.setAttribute(ClosureControl, 'overallTargetState', targetState, this.closureSlidingGate.log);
|
|
345
|
-
await this.closureSlidingGate?.triggerEvent(ClosureControl, 'movementCompleted', undefined, this.closureSlidingGate.log);
|
|
346
|
-
})();
|
|
347
|
-
}, 1000).unref();
|
|
348
|
-
});
|
|
349
|
-
this.closureSlidingGate?.addCommandHandler('ClosureControl.stop', ({ attributes }) => {
|
|
350
|
-
this.closureSlidingGate?.log.info('Command stop called');
|
|
351
|
-
attributes.countdownTime = 0;
|
|
352
|
-
clearTimeout(closureSlidingGateMoveTimeout);
|
|
353
|
-
closureSlidingGateMoveTimeout = undefined;
|
|
354
|
-
});
|
|
355
|
-
this.closureRoofWindow = new MatterbridgeEndpoint([closure, powerSource], {
|
|
356
|
-
id: 'RoofWindow-ROO000074',
|
|
357
|
-
tagList: [getSemtag(ClosureTag.Window), getSemtag(ClosureWindowTag.Roof)],
|
|
358
|
-
}, this.config.debug)
|
|
359
|
-
.createDefaultIdentifyClusterServer()
|
|
360
|
-
.createDefaultBasicInformationClusterServer('Roof Window', 'ROO000074', 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Closure')
|
|
361
|
-
.createDefaultPowerSourceWiredClusterServer();
|
|
362
|
-
this.closureRoofWindow.behaviors.require(MatterbridgeClosureControlServer.with(ClosureControl.Feature.Positioning, ClosureControl.Feature.MotionLatching, ClosureControl.Feature.Speed, ClosureControl.Feature.Ventilation), {
|
|
363
|
-
countdownTime: 0,
|
|
364
|
-
mainState: ClosureControl.MainState.Stopped,
|
|
365
|
-
currentErrorList: [],
|
|
366
|
-
overallCurrentState: { position: ClosureControl.CurrentPosition.FullyClosed, latch: true, speed: ThreeLevelAuto.Auto, secureState: true },
|
|
367
|
-
overallTargetState: { position: ClosureControl.TargetPosition.MoveToFullyClosed, latch: true, speed: ThreeLevelAuto.Auto },
|
|
368
|
-
latchControlModes: { remoteLatching: true, remoteUnlatching: true },
|
|
369
|
-
});
|
|
370
|
-
this.closureRoofWindow = await this.addDevice(this.closureRoofWindow);
|
|
371
|
-
let closureRoofWindowMoveTimeout;
|
|
372
|
-
this.closureRoofWindow?.addCommandHandler('ClosureControl.moveTo', ({ request: { position, latch, speed }, attributes }) => {
|
|
373
|
-
this.closureRoofWindow?.log.info(`Command moveTo called position:${position} latch:${latch} speed:${speed}`);
|
|
374
|
-
attributes.countdownTime = 1;
|
|
375
|
-
closureRoofWindowMoveTimeout = setTimeout(() => {
|
|
376
|
-
void (async () => {
|
|
377
|
-
const targetState = this.closureRoofWindow?.getAttribute(ClosureControl, 'overallTargetState');
|
|
378
|
-
if (targetState === undefined || targetState === null || targetState.position === undefined || targetState.position === null)
|
|
379
|
-
return;
|
|
380
|
-
await this.closureRoofWindow?.setAttribute(ClosureControl, 'countdownTime', 0, this.closureRoofWindow.log);
|
|
381
|
-
await this.closureRoofWindow?.setAttribute(ClosureControl, 'mainState', ClosureControl.MainState.Stopped, this.closureRoofWindow.log);
|
|
382
|
-
await this.closureRoofWindow?.setAttribute(ClosureControl, 'currentErrorList', [], this.closureRoofWindow.log);
|
|
383
|
-
await this.closureRoofWindow?.setAttribute(ClosureControl, 'overallCurrentState', {
|
|
384
|
-
position: closureTargetToCurrentPosition(targetState.position),
|
|
385
|
-
latch: targetState.latch,
|
|
386
|
-
speed: targetState.speed,
|
|
387
|
-
secureState: targetState.position === ClosureControl.TargetPosition.MoveToFullyClosed && targetState.latch === true,
|
|
388
|
-
}, this.closureRoofWindow.log);
|
|
389
|
-
await this.closureRoofWindow?.setAttribute(ClosureControl, 'overallTargetState', targetState, this.closureRoofWindow.log);
|
|
390
|
-
await this.closureRoofWindow?.triggerEvent(ClosureControl, 'movementCompleted', undefined, this.closureRoofWindow.log);
|
|
391
|
-
})();
|
|
392
|
-
}, 1000).unref();
|
|
393
|
-
});
|
|
394
|
-
this.closureRoofWindow?.addCommandHandler('ClosureControl.stop', ({ attributes }) => {
|
|
395
|
-
this.closureRoofWindow?.log.info('Command stop called');
|
|
396
|
-
attributes.countdownTime = 0;
|
|
397
|
-
clearTimeout(closureRoofWindowMoveTimeout);
|
|
398
|
-
closureRoofWindowMoveTimeout = undefined;
|
|
399
|
-
});
|
|
400
293
|
this.climate = new MatterbridgeEndpoint([bridgedNode, powerSource], { id: 'Climate' }, this.config.debug)
|
|
401
294
|
.createDefaultBridgedDeviceBasicInformationClusterServer('Climate', 'CLI00008', 0xfff1, 'Matterbridge', 'Matterbridge Climate')
|
|
402
295
|
.createDefaultPowerSourceReplaceableBatteryClusterServer(90, PowerSource.BatChargeLevel.Ok, 2990, '2 x AA', 2, PowerSource.BatReplaceability.UserReplaceable)
|
|
@@ -1313,16 +1206,16 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
1313
1206
|
const lookupSystemMode = ['Off', 'Auto', '', 'Cool', 'Heat', 'EmergencyHeat', 'Precooling', 'FanOnly', 'Dry', 'Sleep'];
|
|
1314
1207
|
this.thermoAutoSchedules?.log.info(`Subscribe systemMode called with: ${lookupSystemMode[newValue]} (old value: ${lookupSystemMode[oldValue]})`);
|
|
1315
1208
|
}, this.thermoAutoSchedules.log);
|
|
1316
|
-
this.thermoAutoSchedules?.subscribeAttribute(Thermostat
|
|
1209
|
+
this.thermoAutoSchedules?.subscribeAttribute(Thermostat, 'occupiedHeatingSetpoint', (newValue, oldValue) => {
|
|
1317
1210
|
this.thermoAutoSchedules?.log.info(`Subscribe occupiedHeatingSetpoint called with: ${newValue / 100} (old value: ${oldValue / 100})`);
|
|
1318
1211
|
}, this.thermoAutoSchedules.log);
|
|
1319
|
-
this.thermoAutoSchedules?.subscribeAttribute(Thermostat
|
|
1212
|
+
this.thermoAutoSchedules?.subscribeAttribute(Thermostat, 'occupiedCoolingSetpoint', (newValue, oldValue) => {
|
|
1320
1213
|
this.thermoAutoSchedules?.log.info(`Subscribe occupiedCoolingSetpoint called with: ${newValue / 100} (old value: ${oldValue / 100})`);
|
|
1321
1214
|
}, this.thermoAutoSchedules.log);
|
|
1322
|
-
this.thermoAutoSchedules?.subscribeAttribute(Thermostat
|
|
1215
|
+
this.thermoAutoSchedules?.subscribeAttribute(Thermostat, 'activeScheduleHandle', (newValue, oldValue) => {
|
|
1323
1216
|
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'})`);
|
|
1324
1217
|
}, this.thermoAutoSchedules.log);
|
|
1325
|
-
this.thermoAutoSchedules?.subscribeAttribute(Thermostat
|
|
1218
|
+
this.thermoAutoSchedules?.subscribeAttribute(Thermostat, 'schedules', (newValue, oldValue) => {
|
|
1326
1219
|
this.thermoAutoSchedules?.log.info(`Subscribe schedules called with: ${debugStringify(newValue)} (old value: ${debugStringify(oldValue)})`);
|
|
1327
1220
|
}, this.thermoAutoSchedules.log);
|
|
1328
1221
|
this.thermoHeat = new MatterbridgeEndpoint([thermostat, bridgedNode, powerSource], { id: 'Thermostat (Heat)' }, this.config.debug)
|
|
@@ -1360,7 +1253,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
1360
1253
|
const lookupSystemMode = ['Off', 'Auto', '', 'Cool', 'Heat', 'EmergencyHeat', 'Precooling', 'FanOnly', 'Dry', 'Sleep'];
|
|
1361
1254
|
this.thermoHeat?.log.info('Subscribe systemMode called with:', lookupSystemMode[value]);
|
|
1362
1255
|
}, this.thermoHeat.log);
|
|
1363
|
-
this.thermoHeat?.subscribeAttribute(Thermostat
|
|
1256
|
+
this.thermoHeat?.subscribeAttribute(Thermostat, 'occupiedHeatingSetpoint', (value) => {
|
|
1364
1257
|
this.thermoHeat?.log.info('Subscribe occupiedHeatingSetpoint called with:', value / 100);
|
|
1365
1258
|
}, this.thermoHeat.log);
|
|
1366
1259
|
this.thermoCool = new MatterbridgeEndpoint([thermostat, bridgedNode, powerSource], { id: 'Thermostat (Cool)' }, this.config.debug)
|
|
@@ -1380,7 +1273,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
1380
1273
|
const lookupSystemMode = ['Off', 'Auto', '', 'Cool', 'Heat', 'EmergencyHeat', 'Precooling', 'FanOnly', 'Dry', 'Sleep'];
|
|
1381
1274
|
this.thermoCool?.log.info('Subscribe systemMode called with:', lookupSystemMode[value]);
|
|
1382
1275
|
}, this.thermoCool.log);
|
|
1383
|
-
this.thermoCool?.subscribeAttribute(Thermostat
|
|
1276
|
+
this.thermoCool?.subscribeAttribute(Thermostat, 'occupiedCoolingSetpoint', (value) => {
|
|
1384
1277
|
this.thermoCool?.log.info('Subscribe occupiedCoolingSetpoint called with:', value / 100);
|
|
1385
1278
|
}, this.thermoCool.log);
|
|
1386
1279
|
this.airPurifier = new MatterbridgeEndpoint([airPurifier, bridgedNode, powerSource], { id: 'Air purifier' }, this.config.debug)
|
|
@@ -1405,10 +1298,10 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
1405
1298
|
this.airPurifier?.addCommandHandler('identify', ({ request: { identifyTime } }) => {
|
|
1406
1299
|
this.airPurifier?.log.info(`Command identify called identifyTime:${identifyTime}`);
|
|
1407
1300
|
});
|
|
1408
|
-
this.airPurifier?.subscribeAttribute(FanControl
|
|
1301
|
+
this.airPurifier?.subscribeAttribute(FanControl, 'fanMode', (newValue, oldValue, context) => {
|
|
1409
1302
|
this.airPurifier?.log.info(`Fan mode changed from ${this.fanModeLookup[oldValue]} to ${this.fanModeLookup[newValue]} context: ${context.fabric === undefined ? 'offline' : 'online'}`);
|
|
1410
1303
|
}, this.airPurifier.log);
|
|
1411
|
-
this.airPurifier?.subscribeAttribute(FanControl
|
|
1304
|
+
this.airPurifier?.subscribeAttribute(FanControl, 'percentSetting', (newValue, oldValue, context) => void (async () => {
|
|
1412
1305
|
this.airPurifier?.log.info(`Percent setting changed from ${oldValue} to ${newValue} context: ${context.fabric === undefined ? 'offline' : 'online'}`);
|
|
1413
1306
|
if (context.fabric === undefined)
|
|
1414
1307
|
return;
|
|
@@ -1935,10 +1828,10 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
1935
1828
|
await this.airConditioner?.setAttribute(RelativeHumidityMeasurement.id, 'measuredValue', null, this.airConditioner?.log);
|
|
1936
1829
|
await this.airConditioner?.setAttribute(FanControl.id, 'percentSetting', 0, this.airConditioner?.log);
|
|
1937
1830
|
});
|
|
1938
|
-
this.airConditioner?.subscribeAttribute(FanControl
|
|
1831
|
+
this.airConditioner?.subscribeAttribute(FanControl, 'fanMode', (newValue, oldValue, context) => {
|
|
1939
1832
|
this.airConditioner?.log.info(`Fan mode changed from ${this.fanModeLookup[oldValue]} to ${this.fanModeLookup[newValue]} context: ${context.fabric === undefined ? 'offline' : 'online'}`);
|
|
1940
1833
|
}, this.airConditioner?.log);
|
|
1941
|
-
this.airConditioner?.subscribeAttribute(FanControl
|
|
1834
|
+
this.airConditioner?.subscribeAttribute(FanControl, 'percentSetting', (newValue, oldValue, context) => void (async () => {
|
|
1942
1835
|
this.airConditioner?.log.info(`Percent setting changed from ${oldValue} to ${newValue} context: ${context.fabric === undefined ? 'offline' : 'online'}`);
|
|
1943
1836
|
if (context.fabric === undefined)
|
|
1944
1837
|
return;
|
|
@@ -2558,18 +2451,18 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
2558
2451
|
if (this.config.useInterval) {
|
|
2559
2452
|
this.addInterval(async () => {
|
|
2560
2453
|
let mode = this.fanDefault?.getAttribute(FanControl, 'fanMode', this.fanDefault.log);
|
|
2561
|
-
let
|
|
2562
|
-
if (isValidNumber(mode, FanControl.FanMode.Off, FanControl.FanMode.Auto) && mode === FanControl.FanMode.Auto && isValidNumber(
|
|
2563
|
-
|
|
2564
|
-
await this.fanDefault?.setAttribute(FanControl, 'percentCurrent',
|
|
2565
|
-
this.fanDefault?.log.info(`Set fan percentCurrent to ${
|
|
2454
|
+
let current = this.fanDefault?.getAttribute(FanControl, 'percentCurrent', this.fanDefault.log);
|
|
2455
|
+
if (isValidNumber(mode, FanControl.FanMode.Off, FanControl.FanMode.Auto) && mode === FanControl.FanMode.Auto && isValidNumber(current, 0, 100)) {
|
|
2456
|
+
current = current + 10 >= 100 ? 0 : current + 10;
|
|
2457
|
+
await this.fanDefault?.setAttribute(FanControl, 'percentCurrent', current, this.fanDefault.log);
|
|
2458
|
+
this.fanDefault?.log.info(`Set fan percentCurrent to ${current}`);
|
|
2566
2459
|
}
|
|
2567
2460
|
mode = this.fanComplete?.getAttribute(FanControl, 'fanMode', this.fanComplete.log);
|
|
2568
|
-
|
|
2569
|
-
if (isValidNumber(mode, FanControl.FanMode.Off, FanControl.FanMode.Auto) && mode === FanControl.FanMode.Auto && isValidNumber(
|
|
2570
|
-
|
|
2571
|
-
await this.fanComplete?.setAttribute(FanControl, 'percentCurrent',
|
|
2572
|
-
this.fanComplete?.log.info(`Set fan percentCurrent to ${
|
|
2461
|
+
current = this.fanComplete?.getAttribute(FanControl, 'percentCurrent', this.fanComplete.log);
|
|
2462
|
+
if (isValidNumber(mode, FanControl.FanMode.Off, FanControl.FanMode.Auto) && mode === FanControl.FanMode.Auto && isValidNumber(current, 0, 100)) {
|
|
2463
|
+
current = current + 10 >= 100 ? 0 : current + 10;
|
|
2464
|
+
await this.fanComplete?.setAttribute(FanControl, 'percentCurrent', current, this.fanComplete.log);
|
|
2465
|
+
this.fanComplete?.log.info(`Set fan percentCurrent to ${current}`);
|
|
2573
2466
|
}
|
|
2574
2467
|
}, 60 * 1000 + 700);
|
|
2575
2468
|
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge-example-dynamic-platform",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.4-dev-20260901-796d818",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "matterbridge-example-dynamic-platform",
|
|
9
|
-
"version": "3.0.
|
|
9
|
+
"version": "3.0.4-dev-20260901-796d818",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"node-ansi-logger": "3.3.
|
|
13
|
-
"node-persist-manager": "2.1.
|
|
12
|
+
"node-ansi-logger": "3.3.1",
|
|
13
|
+
"node-persist-manager": "2.1.1"
|
|
14
14
|
},
|
|
15
15
|
"engines": {
|
|
16
16
|
"node": ">=20.19.0 <21.0.0 || >=22.13.0 <23.0.0 || >=24.0.0 <25.0.0 || >=26.0.0 <27.0.0"
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"node_modules/node-ansi-logger": {
|
|
24
|
-
"version": "3.3.
|
|
25
|
-
"resolved": "https://registry.npmjs.org/node-ansi-logger/-/node-ansi-logger-3.3.
|
|
26
|
-
"integrity": "sha512-
|
|
24
|
+
"version": "3.3.1",
|
|
25
|
+
"resolved": "https://registry.npmjs.org/node-ansi-logger/-/node-ansi-logger-3.3.1.tgz",
|
|
26
|
+
"integrity": "sha512-JjkQHtVKgyd5Ua4AkYCFsZZiUYMrPsj/S9k2VY8/FjYuFJFRjDawsuxMwaThhWu4oU7zwuqvDG2uoDnjUyApVw==",
|
|
27
27
|
"hasShrinkwrap": true,
|
|
28
28
|
"license": "Apache-2.0",
|
|
29
29
|
"engines": {
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
"node_modules/node-persist-manager": {
|
|
38
|
-
"version": "2.1.
|
|
39
|
-
"resolved": "https://registry.npmjs.org/node-persist-manager/-/node-persist-manager-2.1.
|
|
40
|
-
"integrity": "sha512-
|
|
38
|
+
"version": "2.1.1",
|
|
39
|
+
"resolved": "https://registry.npmjs.org/node-persist-manager/-/node-persist-manager-2.1.1.tgz",
|
|
40
|
+
"integrity": "sha512-cAqF2spTnzDSAQeORHy/OYdD1VROGZ6UiLjmq/gVxQ4EglB0Ro0QX83U+xHEh2G6b7HTvGFqjS/R9LTOGkcayw==",
|
|
41
41
|
"hasShrinkwrap": true,
|
|
42
42
|
"license": "Apache-2.0",
|
|
43
43
|
"dependencies": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge-example-dynamic-platform",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.4-dev-20260901-796d818",
|
|
4
4
|
"description": "Matterbridge dynamic plugin",
|
|
5
5
|
"author": "https://github.com/Luligu",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"*.schema.json"
|
|
69
69
|
],
|
|
70
70
|
"dependencies": {
|
|
71
|
-
"node-ansi-logger": "3.3.
|
|
72
|
-
"node-persist-manager": "2.1.
|
|
71
|
+
"node-ansi-logger": "3.3.1",
|
|
72
|
+
"node-persist-manager": "2.1.1"
|
|
73
73
|
}
|
|
74
74
|
}
|