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 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.3] - Dev branch
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.6 now manages the compliant FanControl `fanMode` and `percentSetting` synchronization; plugin examples now only update `percentCurrent` as physical device feedback.
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, closure, 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, MatterbridgeClosureControlServer, MicrowaveOven, Oven, Refrigerator, RoboticVacuumCleaner, SoilSensor, SolarPower, Speaker, WaterHeater, } from 'matterbridge/devices';
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 { ThreeLevelAuto } from 'matterbridge/matter/types';
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.7')) {
114
- throw new Error(`This plugin requires Matterbridge version >= "3.10.7". Please update Matterbridge from ${this.matterbridge.matterbridgeVersion} to the latest version in the frontend.`);
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
- let closureGarageDoorMoveTimeout;
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', ({ attributes }) => {
176
+ this.closureGarageDoor?.addCommandHandler('ClosureControl.stop', () => {
214
177
  this.closureGarageDoor?.log.info('Command stop called');
215
- attributes.countdownTime = 0;
216
- clearTimeout(closureGarageDoorMoveTimeout);
217
- closureGarageDoorMoveTimeout = undefined;
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, latch: liftCurrent.latch ?? true, speed: liftCurrent.speed, secureState: liftCurrent.position === 10000 && liftCurrent.latch === true }, this.closureVenetianBlind?.log);
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, latch, speed) => {
272
- void panel.setAttribute(ClosureDimension, 'targetState', { position, latch: latch ?? true, speed }, panel.log);
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 = closurePanelTargetPercent(targetState.position);
286
- moveClosurePanelTo(closureVenetianBlindLift, panelPercent, targetState.latch, targetState.speed);
287
- moveClosurePanelTo(closureVenetianBlindTilt, panelPercent, targetState.latch, targetState.speed);
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.id, 'occupiedHeatingSetpoint', (newValue, oldValue) => {
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.id, 'occupiedCoolingSetpoint', (newValue, oldValue) => {
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.id, 'activeScheduleHandle', (newValue, oldValue) => {
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.id, 'schedules', (newValue, oldValue) => {
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.id, 'occupiedHeatingSetpoint', (value) => {
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.id, 'occupiedCoolingSetpoint', (value) => {
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.id, 'fanMode', (newValue, oldValue, context) => {
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.id, 'percentSetting', (newValue, oldValue, context) => void (async () => {
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.id, 'fanMode', (newValue, oldValue, context) => {
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.id, 'percentSetting', (newValue, oldValue, context) => void (async () => {
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 value = this.fanDefault?.getAttribute(FanControl, 'percentCurrent', this.fanDefault.log);
2562
- if (isValidNumber(mode, FanControl.FanMode.Off, FanControl.FanMode.Auto) && mode === FanControl.FanMode.Auto && isValidNumber(value, 0, 100)) {
2563
- value = value + 10 >= 100 ? 0 : value + 10;
2564
- await this.fanDefault?.setAttribute(FanControl, 'percentCurrent', value, this.fanDefault.log);
2565
- this.fanDefault?.log.info(`Set fan percentCurrent to ${value}`);
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
- value = this.fanComplete?.getAttribute(FanControl, 'percentCurrent', this.fanComplete.log);
2569
- if (isValidNumber(mode, FanControl.FanMode.Off, FanControl.FanMode.Auto) && mode === FanControl.FanMode.Auto && isValidNumber(value, 0, 100)) {
2570
- value = value + 10 >= 100 ? 0 : value + 10;
2571
- await this.fanComplete?.setAttribute(FanControl, 'percentCurrent', value, this.fanComplete.log);
2572
- this.fanComplete?.log.info(`Set fan percentCurrent to ${value}`);
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
  }
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "matterbridge-example-dynamic-platform",
3
- "version": "3.0.3-dev-20260830-a347a26",
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.3-dev-20260830-a347a26",
9
+ "version": "3.0.4-dev-20260901-796d818",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
- "node-ansi-logger": "3.3.0",
13
- "node-persist-manager": "2.1.0"
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.0",
25
- "resolved": "https://registry.npmjs.org/node-ansi-logger/-/node-ansi-logger-3.3.0.tgz",
26
- "integrity": "sha512-ZW77lbZkA8h3r2HA2rcE5RjTIcwRDNB072RkZVyimGQpmEorJT8ajZ7UDhkHGoh0JRrCJL0iUKBE8q4oU8MHMg==",
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.0",
39
- "resolved": "https://registry.npmjs.org/node-persist-manager/-/node-persist-manager-2.1.0.tgz",
40
- "integrity": "sha512-LJze/Fcd8LijM4OMPnp0AQ+Z1e9mFMkjOEDw08xHA2HSRd2+N5s0uyH5ogYmXPC68f0sc4GrdKMpAcsHuO3PKA==",
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-dev-20260830-a347a26",
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.0",
72
- "node-persist-manager": "2.1.0"
71
+ "node-ansi-logger": "3.3.1",
72
+ "node-persist-manager": "2.1.1"
73
73
  }
74
74
  }