@matterbridge/core 3.10.8-dev-20260901-c4963a1 → 3.10.8-dev-20260901-971f7bf

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.
@@ -1,3 +1,4 @@
1
+ import { type Timer } from '@matter/general';
1
2
  import { WindowCoveringBaseServer, WindowCoveringServer } from '@matter/node/behaviors/window-covering';
2
3
  import { WindowCovering } from '@matter/types/clusters/window-covering';
3
4
  declare const MatterbridgeWindowCoveringServer_base: import("@matter/node").ClusterBehavior.Type<typeof WindowCoveringServer, import("@matter/types").ClusterType.WithSupportedFeatures<WindowCovering, {
@@ -18,11 +19,14 @@ export declare class MatterbridgeWindowCoveringServer extends MatterbridgeWindow
18
19
  stopMotion(): Promise<void>;
19
20
  goToLiftPercentage(request: WindowCovering.GoToLiftPercentageRequest): Promise<void>;
20
21
  goToTiltPercentage(request: WindowCovering.GoToTiltPercentageRequest): Promise<void>;
22
+ [Symbol.asyncDispose](): Promise<void>;
21
23
  }
22
24
  export declare namespace MatterbridgeWindowCoveringServer {
23
25
  class Internal extends WindowCoveringBaseServer.Internal {
24
- liftMovementTimer?: NodeJS.Timeout;
25
- tiltMovementTimer?: NodeJS.Timeout;
26
+ liftMovementTimer?: Timer;
27
+ liftMovementTarget: number;
28
+ tiltMovementTimer?: Timer;
29
+ tiltMovementTarget: number;
26
30
  }
27
31
  class State extends WindowCoveringBaseServer.State {
28
32
  movementDuration: number;
@@ -1,3 +1,4 @@
1
+ import { Millis, Time } from '@matter/general';
1
2
  import { WindowCoveringBaseServer, WindowCoveringServer } from '@matter/node/behaviors/window-covering';
2
3
  import { WindowCovering } from '@matter/types/clusters/window-covering';
3
4
  import { MatterbridgeServer } from './matterbridgeServer.js';
@@ -35,7 +36,7 @@ export class MatterbridgeWindowCoveringServer extends WindowCoveringServer.with(
35
36
  this.state.operationalStatus.global = lift === WindowCovering.MovementStatus.Stopped ? tilt : lift;
36
37
  }
37
38
  #startLiftMovement(targetPercent100ths) {
38
- clearTimeout(this.internal.liftMovementTimer);
39
+ this.internal.liftMovementTimer?.stop();
39
40
  this.internal.liftMovementTimer = undefined;
40
41
  if (this.state.movementDuration <= 0)
41
42
  return;
@@ -44,19 +45,17 @@ export class MatterbridgeWindowCoveringServer extends WindowCoveringServer.with(
44
45
  this.#updateGlobalOperationalStatus();
45
46
  if (status === WindowCovering.MovementStatus.Stopped)
46
47
  return;
47
- this.internal.liftMovementTimer = setTimeout(() => {
48
- this.internal.liftMovementTimer = undefined;
49
- void this.#completeLiftMovement(targetPercent100ths);
50
- }, this.state.movementDuration);
51
- }
52
- #completeLiftMovement = async (targetPercent100ths) => {
53
- const windowCovering = this.endpoint;
54
- await windowCovering.setAttribute(WindowCovering, 'currentPositionLiftPercent100ths', targetPercent100ths);
55
- const tilt = windowCovering.getAttribute(WindowCovering, 'operationalStatus')?.tilt ?? WindowCovering.MovementStatus.Stopped;
56
- await windowCovering.setAttribute(WindowCovering, 'operationalStatus', { global: tilt, lift: WindowCovering.MovementStatus.Stopped, tilt });
57
- };
48
+ this.internal.liftMovementTarget = targetPercent100ths;
49
+ this.internal.liftMovementTimer = Time.getTimer('WindowCovering lift movement complete', Millis(this.state.movementDuration), this.callback(this.#completeLiftMovement, { lock: true })).start();
50
+ }
51
+ #completeLiftMovement() {
52
+ this.internal.liftMovementTimer = undefined;
53
+ this.state.currentPositionLiftPercent100ths = this.internal.liftMovementTarget;
54
+ this.state.operationalStatus.lift = WindowCovering.MovementStatus.Stopped;
55
+ this.#updateGlobalOperationalStatus();
56
+ }
58
57
  #startTiltMovement(targetPercent100ths) {
59
- clearTimeout(this.internal.tiltMovementTimer);
58
+ this.internal.tiltMovementTimer?.stop();
60
59
  this.internal.tiltMovementTimer = undefined;
61
60
  if (this.state.movementDuration <= 0)
62
61
  return;
@@ -65,17 +64,15 @@ export class MatterbridgeWindowCoveringServer extends WindowCoveringServer.with(
65
64
  this.#updateGlobalOperationalStatus();
66
65
  if (status === WindowCovering.MovementStatus.Stopped)
67
66
  return;
68
- this.internal.tiltMovementTimer = setTimeout(() => {
69
- this.internal.tiltMovementTimer = undefined;
70
- void this.#completeTiltMovement(targetPercent100ths);
71
- }, this.state.movementDuration);
72
- }
73
- #completeTiltMovement = async (targetPercent100ths) => {
74
- const windowCovering = this.endpoint;
75
- await windowCovering.setAttribute(WindowCovering, 'currentPositionTiltPercent100ths', targetPercent100ths);
76
- const lift = windowCovering.getAttribute(WindowCovering, 'operationalStatus')?.lift ?? WindowCovering.MovementStatus.Stopped;
77
- await windowCovering.setAttribute(WindowCovering, 'operationalStatus', { global: lift, lift, tilt: WindowCovering.MovementStatus.Stopped });
78
- };
67
+ this.internal.tiltMovementTarget = targetPercent100ths;
68
+ this.internal.tiltMovementTimer = Time.getTimer('WindowCovering tilt movement complete', Millis(this.state.movementDuration), this.callback(this.#completeTiltMovement, { lock: true })).start();
69
+ }
70
+ #completeTiltMovement() {
71
+ this.internal.tiltMovementTimer = undefined;
72
+ this.state.currentPositionTiltPercent100ths = this.internal.tiltMovementTarget;
73
+ this.state.operationalStatus.tilt = WindowCovering.MovementStatus.Stopped;
74
+ this.#updateGlobalOperationalStatus();
75
+ }
79
76
  async upOrOpen() {
80
77
  const device = this.endpoint.stateOf(MatterbridgeServer);
81
78
  device.log.info(`MatterbridgeWindowCoveringServer: opening cover (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
@@ -127,9 +124,9 @@ export class MatterbridgeWindowCoveringServer extends WindowCoveringServer.with(
127
124
  });
128
125
  device.log.debug(`MatterbridgeWindowCoveringServer: stopMotion called (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
129
126
  await super.stopMotion();
130
- clearTimeout(this.internal.liftMovementTimer);
127
+ this.internal.liftMovementTimer?.stop();
131
128
  this.internal.liftMovementTimer = undefined;
132
- clearTimeout(this.internal.tiltMovementTimer);
129
+ this.internal.tiltMovementTimer?.stop();
133
130
  this.internal.tiltMovementTimer = undefined;
134
131
  if (this.state.movementDuration > 0) {
135
132
  if (this.features.positionAwareLift)
@@ -174,11 +171,20 @@ export class MatterbridgeWindowCoveringServer extends WindowCoveringServer.with(
174
171
  this.#startTiltMovement(this.state.targetPositionTiltPercent100ths);
175
172
  device.log.debug(`MatterbridgeWindowCoveringServer: goToTiltPercentage result target ${this.state.targetPositionTiltPercent100ths} current ${this.state.currentPositionTiltPercent100ths} status global ${this.getMovementStatusLabel(this.state.operationalStatus.global)} lift ${this.getMovementStatusLabel(this.state.operationalStatus.lift)} tilt ${this.getMovementStatusLabel(this.state.operationalStatus.tilt)} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
176
173
  }
174
+ async [Symbol.asyncDispose]() {
175
+ this.internal.liftMovementTimer?.stop();
176
+ this.internal.liftMovementTimer = undefined;
177
+ this.internal.tiltMovementTimer?.stop();
178
+ this.internal.tiltMovementTimer = undefined;
179
+ await super[Symbol.asyncDispose]?.();
180
+ }
177
181
  }
178
182
  (function (MatterbridgeWindowCoveringServer) {
179
183
  class Internal extends WindowCoveringBaseServer.Internal {
180
184
  liftMovementTimer;
185
+ liftMovementTarget = 0;
181
186
  tiltMovementTimer;
187
+ tiltMovementTarget = 0;
182
188
  }
183
189
  MatterbridgeWindowCoveringServer.Internal = Internal;
184
190
  class State extends WindowCoveringBaseServer.State {
@@ -1,6 +1,6 @@
1
1
  import { readFile, writeFile } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
- import { ClosureCoveringTag, ClosurePanelTag, ClosureTag, ClosureWindowTag, CommodityTariffChronologyTag, CommodityTariffCommodityTag, CommodityTariffFlowTag, CommonNumberTag, CommonPositionTag, ElectricalMeasurementTag, PowerSourceTag, RefrigeratorTag, } from '@matter/node';
3
+ import { ClosureCoveringTag, ClosurePanelTag, ClosureTag, ClosureWindowTag, CommodityTariffChronologyTag, CommodityTariffCommodityTag, CommodityTariffFlowTag, CommonNumberTag, CommonPositionTag, ElectricalMeasurementTag, PowerSourceTag, RefrigeratorTag, SwitchesTag, } from '@matter/node';
4
4
  import { AirQuality } from '@matter/types/clusters/air-quality';
5
5
  import { ClosureDimension } from '@matter/types/clusters/closure-dimension';
6
6
  import { DoorLock } from '@matter/types/clusters/door-lock';
@@ -267,8 +267,33 @@ export async function createDemoDevices(matterbridge) {
267
267
  ep = new MatterbridgeEndpoint([getSupportedDeviceType('PumpController'), bridgedNode, powerSource], { id: 'PumpController', number: EndpointNumber(6_05) });
268
268
  ep.createDefaultPowerSourceWiredClusterServer();
269
269
  await registerDevice(ep, 'Pump Controller', 'SWITCH-06-05');
270
- ep = new MatterbridgeEndpoint([getSupportedDeviceType('GenericSwitch'), bridgedNode, powerSource], { id: 'GenericSwitch', number: EndpointNumber(6_06) });
270
+ ep = new MatterbridgeEndpoint([getSupportedDeviceType('Aggregator'), bridgedNode, powerSource], { id: 'GenericSwitch', number: EndpointNumber(6_06) });
271
271
  ep.createDefaultPowerSourceBatteryClusterServer();
272
+ await ep.addFixedLabel('composed', 'GenericSwitch');
273
+ ep.addChildDeviceType('Button1', getSupportedDeviceType('GenericSwitch'), {
274
+ number: EndpointNumber(6_06_1),
275
+ tagList: [getSemtag(SwitchesTag.On), getSemtag(CommonNumberTag.One)],
276
+ })
277
+ .createDefaultMomentarySwitchClusterServer()
278
+ .addRequiredClusters();
279
+ ep.addChildDeviceType('Button2', getSupportedDeviceType('GenericSwitch'), {
280
+ number: EndpointNumber(6_06_2),
281
+ tagList: [getSemtag(SwitchesTag.Off), getSemtag(CommonNumberTag.Two)],
282
+ })
283
+ .createDefaultMomentarySwitchClusterServer()
284
+ .addRequiredClusters();
285
+ ep.addChildDeviceType('Button3', getSupportedDeviceType('GenericSwitch'), {
286
+ number: EndpointNumber(6_06_3),
287
+ tagList: [getSemtag(SwitchesTag.Up), getSemtag(CommonNumberTag.Three)],
288
+ })
289
+ .createDefaultMomentarySwitchClusterServer()
290
+ .addRequiredClusters();
291
+ ep.addChildDeviceType('Button4', getSupportedDeviceType('GenericSwitch'), {
292
+ number: EndpointNumber(6_06_4),
293
+ tagList: [getSemtag(SwitchesTag.Down), getSemtag(CommonNumberTag.Four)],
294
+ })
295
+ .createDefaultMomentarySwitchClusterServer()
296
+ .addRequiredClusters();
272
297
  await registerDevice(ep, 'Generic Switch', 'SWITCH-06-06');
273
298
  ep = new MatterbridgeEndpoint([getSupportedDeviceType('ContactSensor'), bridgedNode, powerSource], { id: 'ContactSensor', number: EndpointNumber(7_01) });
274
299
  ep.createDefaultPowerSourceBatteryClusterServer();
@@ -36,6 +36,8 @@ export declare namespace MatterbridgeClosureControlServer {
36
36
  movementDuration: number;
37
37
  calibrationDuration: number;
38
38
  signaturePosition: number;
39
+ ventilationPosition: number;
40
+ pedestrianPosition: number;
39
41
  }
40
42
  }
41
43
  export interface ClosureOptions {
@@ -51,6 +53,8 @@ export interface ClosureOptions {
51
53
  movementDuration?: number;
52
54
  calibrationDuration?: number;
53
55
  signaturePosition?: number;
56
+ ventilationPosition?: number;
57
+ pedestrianPosition?: number;
54
58
  motionLatching?: boolean;
55
59
  speed?: boolean;
56
60
  ventilation?: boolean;
@@ -64,10 +68,17 @@ export declare class Closure extends MatterbridgeEndpoint {
64
68
  constructor(name: string, serial: string, options?: ClosureOptions);
65
69
  getMainState(): ClosureControl.MainState | undefined;
66
70
  getSignaturePosition(): number | undefined;
71
+ getVentilationPosition(): number | undefined;
72
+ getPedestrianPosition(): number | undefined;
67
73
  setState(currentState: ClosureControl.OverallCurrentState, targetState: ClosureControl.OverallTargetState, mainState?: ClosureControl.MainState, countdownTime?: number, currentErrorList?: ClosureControl.ClosureError[]): Promise<void>;
68
74
  setFullyClosed(): Promise<void>;
69
75
  setFullOpened(): Promise<void>;
70
76
  setPartiallyOpened(): Promise<void>;
77
+ setOpenedAtSignature(): Promise<void>;
78
+ setOpenedForVentilation(): Promise<void>;
79
+ setOpenedForPedestrian(): Promise<void>;
80
+ targetPositionToCurrentPosition(position: ClosureControl.TargetPosition): ClosureControl.CurrentPosition;
81
+ targetPositionToTargetPercent(position: ClosureControl.TargetPosition): number;
71
82
  triggerOperationalError(errorState?: ClosureControl.ClosureError[]): Promise<void>;
72
83
  triggerMovementCompleted(): Promise<void>;
73
84
  triggerSecureStateChanged(secureValue: boolean): Promise<void>;
@@ -175,12 +175,14 @@ export class MatterbridgeClosureControlServer extends MatterbridgeClosureControl
175
175
  movementDuration = 0;
176
176
  calibrationDuration = 0;
177
177
  signaturePosition = 50_00;
178
+ ventilationPosition = 50_00;
179
+ pedestrianPosition = 50_00;
178
180
  }
179
181
  MatterbridgeClosureControlServer.State = State;
180
182
  })(MatterbridgeClosureControlServer || (MatterbridgeClosureControlServer = {}));
181
183
  export class Closure extends MatterbridgeEndpoint {
182
184
  constructor(name, serial, options = {}) {
183
- const { identifyTime = 0, identifyType = Identify.IdentifyType.None, powerSourceType = 'Wired', countdownTime = 0, mainState = ClosureControl.MainState.Stopped, currentErrorList = [], overallCurrentState, overallTargetState, latchControlModes, movementDuration = 0, calibrationDuration = 0, signaturePosition = 50_00, motionLatching = false, speed = false, ventilation = false, pedestrian = false, calibration = false, id, number, tagList = [getSemtag(ClosureTag.Covering)], } = options;
185
+ const { identifyTime = 0, identifyType = Identify.IdentifyType.None, powerSourceType = 'Wired', countdownTime = 0, mainState = ClosureControl.MainState.Stopped, currentErrorList = [], overallCurrentState, overallTargetState, latchControlModes, movementDuration = 0, calibrationDuration = 0, signaturePosition = 50_00, ventilationPosition = 50_00, pedestrianPosition = 50_00, motionLatching = false, speed = false, ventilation = false, pedestrian = false, calibration = false, id, number, tagList = [getSemtag(ClosureTag.Covering)], } = options;
184
186
  super(powerSourceType === 'None' ? [closure] : [closure, powerSource], {
185
187
  id: id ?? `${name.replaceAll(' ', '')}-${serial.replaceAll(' ', '')}`,
186
188
  number,
@@ -223,6 +225,8 @@ export class Closure extends MatterbridgeEndpoint {
223
225
  movementDuration,
224
226
  calibrationDuration,
225
227
  signaturePosition,
228
+ ventilationPosition,
229
+ pedestrianPosition,
226
230
  };
227
231
  this.behaviors.require(MatterbridgeClosureControlServer.with(ClosureControl.Feature.Positioning, ...(motionLatching ? [ClosureControl.Feature.MotionLatching] : []), ...(speed ? [ClosureControl.Feature.Speed] : []), ...(calibration ? [ClosureControl.Feature.Calibration] : []), ...(ventilation ? [ClosureControl.Feature.Ventilation] : []), ...(pedestrian ? [ClosureControl.Feature.Pedestrian] : [])), closureControlOptions);
228
232
  }
@@ -232,23 +236,31 @@ export class Closure extends MatterbridgeEndpoint {
232
236
  getSignaturePosition() {
233
237
  return this.getAttribute(MatterbridgeClosureControlServer, 'signaturePosition');
234
238
  }
239
+ getVentilationPosition() {
240
+ return this.getAttribute(MatterbridgeClosureControlServer, 'ventilationPosition');
241
+ }
242
+ getPedestrianPosition() {
243
+ return this.getAttribute(MatterbridgeClosureControlServer, 'pedestrianPosition');
244
+ }
235
245
  async setState(currentState, targetState, mainState = ClosureControl.MainState.Stopped, countdownTime = 0, currentErrorList = []) {
236
- const featureMap = this.getAttribute(ClosureControl.id, 'featureMap');
237
- const supportsMotionLatching = featureMap?.motionLatching === true;
238
- const supportsSpeed = featureMap?.speed === true;
246
+ const features = this.featuresOf(MatterbridgeClosureControlServer.id);
247
+ const supportsCurrentPosition = (currentState.position !== ClosureControl.CurrentPosition.OpenedForVentilation || features.ventilation) &&
248
+ (currentState.position !== ClosureControl.CurrentPosition.OpenedForPedestrian || features.pedestrian);
249
+ const supportsTargetPosition = (targetState.position !== ClosureControl.TargetPosition.MoveToVentilationPosition || features.ventilation) &&
250
+ (targetState.position !== ClosureControl.TargetPosition.MoveToPedestrianPosition || features.pedestrian);
239
251
  await this.setAttribute(ClosureControl, 'countdownTime', countdownTime);
240
252
  await this.setAttribute(ClosureControl, 'mainState', mainState);
241
253
  await this.setAttribute(ClosureControl, 'currentErrorList', currentErrorList);
242
254
  await this.setAttribute(ClosureControl, 'overallCurrentState', {
243
- position: currentState.position,
244
- ...(supportsMotionLatching ? { latch: currentState.latch } : null),
245
- ...(supportsSpeed ? { speed: currentState.speed } : null),
255
+ ...(supportsCurrentPosition ? { position: currentState.position } : null),
256
+ ...(features.motionLatching ? { latch: currentState.latch } : null),
257
+ ...(features.speed ? { speed: currentState.speed } : null),
246
258
  secureState: currentState.secureState,
247
259
  });
248
260
  await this.setAttribute(ClosureControl, 'overallTargetState', {
249
- position: targetState.position,
250
- ...(supportsMotionLatching ? { latch: targetState.latch } : null),
251
- ...(supportsSpeed ? { speed: targetState.speed } : null),
261
+ ...(supportsTargetPosition ? { position: targetState.position } : null),
262
+ ...(features.motionLatching ? { latch: targetState.latch } : null),
263
+ ...(features.speed ? { speed: targetState.speed } : null),
252
264
  });
253
265
  }
254
266
  async setFullyClosed() {
@@ -287,6 +299,64 @@ export class Closure extends MatterbridgeEndpoint {
287
299
  speed: ThreeLevelAuto.Auto,
288
300
  });
289
301
  }
302
+ async setOpenedAtSignature() {
303
+ await this.setState({
304
+ position: ClosureControl.CurrentPosition.OpenedAtSignature,
305
+ latch: false,
306
+ speed: ThreeLevelAuto.Auto,
307
+ secureState: false,
308
+ }, {
309
+ position: ClosureControl.TargetPosition.MoveToSignaturePosition,
310
+ latch: false,
311
+ speed: ThreeLevelAuto.Auto,
312
+ });
313
+ }
314
+ async setOpenedForVentilation() {
315
+ await this.setState({
316
+ position: ClosureControl.CurrentPosition.OpenedForVentilation,
317
+ latch: false,
318
+ speed: ThreeLevelAuto.Auto,
319
+ secureState: false,
320
+ }, {
321
+ position: ClosureControl.TargetPosition.MoveToVentilationPosition,
322
+ latch: false,
323
+ speed: ThreeLevelAuto.Auto,
324
+ });
325
+ }
326
+ async setOpenedForPedestrian() {
327
+ await this.setState({
328
+ position: ClosureControl.CurrentPosition.OpenedForPedestrian,
329
+ latch: false,
330
+ speed: ThreeLevelAuto.Auto,
331
+ secureState: false,
332
+ }, {
333
+ position: ClosureControl.TargetPosition.MoveToPedestrianPosition,
334
+ latch: false,
335
+ speed: ThreeLevelAuto.Auto,
336
+ });
337
+ }
338
+ targetPositionToCurrentPosition(position) {
339
+ if (position === ClosureControl.TargetPosition.MoveToFullyClosed)
340
+ return ClosureControl.CurrentPosition.FullyClosed;
341
+ if (position === ClosureControl.TargetPosition.MoveToFullyOpen)
342
+ return ClosureControl.CurrentPosition.FullyOpened;
343
+ if (position === ClosureControl.TargetPosition.MoveToPedestrianPosition)
344
+ return ClosureControl.CurrentPosition.OpenedForPedestrian;
345
+ if (position === ClosureControl.TargetPosition.MoveToVentilationPosition)
346
+ return ClosureControl.CurrentPosition.OpenedForVentilation;
347
+ return ClosureControl.CurrentPosition.OpenedAtSignature;
348
+ }
349
+ targetPositionToTargetPercent(position) {
350
+ if (position === ClosureControl.TargetPosition.MoveToFullyOpen)
351
+ return 0;
352
+ if (position === ClosureControl.TargetPosition.MoveToFullyClosed)
353
+ return 100_00;
354
+ if (position === ClosureControl.TargetPosition.MoveToPedestrianPosition)
355
+ return this.getPedestrianPosition() ?? 50_00;
356
+ if (position === ClosureControl.TargetPosition.MoveToVentilationPosition)
357
+ return this.getVentilationPosition() ?? 50_00;
358
+ return this.getSignaturePosition() ?? 50_00;
359
+ }
290
360
  async triggerOperationalError(errorState = []) {
291
361
  await this.setAttribute(ClosureControl, 'mainState', ClosureControl.MainState.Error);
292
362
  await this.setAttribute(ClosureControl, 'currentErrorList', errorState);
@@ -62,6 +62,21 @@ export interface ElectricalEnergyTariffOptions {
62
62
  currentPrice?: CommodityPrice.CommodityPriceStruct | null;
63
63
  localGenerationAvailable?: boolean | null;
64
64
  currentConditions?: ElectricalGridConditions.ElectricalGridConditionsStruct | null;
65
+ startDate?: number | null;
66
+ dayEntries?: CommodityTariff.DayEntry[] | null;
67
+ dayPatterns?: CommodityTariff.DayPattern[] | null;
68
+ calendarPeriods?: CommodityTariff.CalendarPeriod[] | null;
69
+ individualDays?: CommodityTariff.Day[] | null;
70
+ currentDay?: CommodityTariff.Day | null;
71
+ nextDay?: CommodityTariff.Day | null;
72
+ currentDayEntry?: CommodityTariff.DayEntry | null;
73
+ currentDayEntryDate?: number | null;
74
+ nextDayEntry?: CommodityTariff.DayEntry | null;
75
+ nextDayEntryDate?: number | null;
76
+ tariffComponents?: CommodityTariff.TariffComponent[] | null;
77
+ tariffPeriods?: CommodityTariff.TariffPeriod[] | null;
78
+ currentTariffComponents?: CommodityTariff.TariffComponent[] | null;
79
+ nextTariffComponents?: CommodityTariff.TariffComponent[] | null;
65
80
  tagList?: Semtag[];
66
81
  }
67
82
  export declare class ElectricalUtilityMeter extends MatterbridgeEndpoint {
@@ -106,7 +106,7 @@ export class ElectricalUtilityMeter extends MatterbridgeEndpoint {
106
106
  return tariff;
107
107
  }
108
108
  configureElectricalEnergyTariffClusters(endpoint, options) {
109
- const { tariffLabel = null, providerName = null, tariffUnit = TariffUnit.KWh, currency = null, currentPrice = null, localGenerationAvailable = null, currentConditions = null, } = options;
109
+ const { tariffLabel = null, providerName = null, tariffUnit = TariffUnit.KWh, currency = null, currentPrice = null, localGenerationAvailable = null, currentConditions = null, startDate = null, dayEntries = null, dayPatterns = null, calendarPeriods = null, individualDays = null, currentDay = null, nextDay = null, currentDayEntry = null, currentDayEntryDate = null, nextDayEntry = null, nextDayEntryDate = null, tariffComponents = null, tariffPeriods = null, currentTariffComponents = null, nextTariffComponents = null, } = options;
110
110
  endpoint.behaviors.require(MatterbridgeCommodityPriceServer, {
111
111
  tariffUnit,
112
112
  currency,
@@ -125,21 +125,21 @@ export class ElectricalUtilityMeter extends MatterbridgeEndpoint {
125
125
  endpoint.behaviors.require(MatterbridgeCommodityTariffServer, {
126
126
  tariffInfo,
127
127
  tariffUnit: tariffInfo === null ? null : tariffUnit,
128
- startDate: null,
129
- dayEntries: null,
130
- dayPatterns: null,
131
- calendarPeriods: null,
132
- individualDays: null,
133
- tariffComponents: null,
134
- tariffPeriods: null,
135
- currentDay: null,
136
- nextDay: null,
137
- currentDayEntry: null,
138
- currentDayEntryDate: null,
139
- nextDayEntry: null,
140
- nextDayEntryDate: null,
141
- currentTariffComponents: null,
142
- nextTariffComponents: null,
128
+ startDate: tariffInfo === null ? null : startDate,
129
+ dayEntries: tariffInfo === null ? null : dayEntries,
130
+ dayPatterns: tariffInfo === null ? null : dayPatterns,
131
+ calendarPeriods: tariffInfo === null ? null : calendarPeriods,
132
+ individualDays: tariffInfo === null ? null : individualDays,
133
+ tariffComponents: tariffInfo === null ? null : tariffComponents,
134
+ tariffPeriods: tariffInfo === null ? null : tariffPeriods,
135
+ currentDay: tariffInfo === null ? null : currentDay,
136
+ nextDay: tariffInfo === null ? null : nextDay,
137
+ currentDayEntry: tariffInfo === null ? null : currentDayEntry,
138
+ currentDayEntryDate: tariffInfo === null ? null : currentDayEntryDate,
139
+ nextDayEntry: tariffInfo === null ? null : nextDayEntry,
140
+ nextDayEntryDate: tariffInfo === null ? null : nextDayEntryDate,
141
+ currentTariffComponents: tariffInfo === null ? null : currentTariffComponents,
142
+ nextTariffComponents: tariffInfo === null ? null : nextTariffComponents,
143
143
  });
144
144
  endpoint.behaviors.require(ElectricalGridConditionsServer, { localGenerationAvailable, currentConditions });
145
145
  }
@@ -208,7 +208,7 @@ export function featuresFor(endpoint, cluster) {
208
208
  const supportedBehavior = endpoint.behaviors.supported[lowercaseFirstLetter(behaviorId)];
209
209
  if (!supportedBehavior || !ClusterBehavior.isType(supportedBehavior))
210
210
  return {};
211
- return supportedBehavior.features ?? {};
211
+ return supportedBehavior.features;
212
212
  }
213
213
  export async function internalFor(endpoint, cluster) {
214
214
  const behaviorId = getBehavior(endpoint, cluster)?.id;
@@ -9,4 +9,5 @@ export declare function snakeCase(name: string): string;
9
9
  export declare function pascalCase(name: string): string;
10
10
  export declare function camelCase(name: string): string;
11
11
  export declare function getServerBehaviorFromClusterId(clusterId: ClusterId, features?: Record<string, boolean> | string[]): Promise<Behavior.Type | undefined>;
12
+ export declare function getClientBehaviorFromClusterId(clusterId: ClusterId): Promise<Behavior.Type | undefined>;
12
13
  export declare function createClusterServer(endpoint: MatterbridgeEndpoint, clusterId: ClusterId, options?: CreateClusterServerOptions): Promise<MatterbridgeEndpoint>;
@@ -1,4 +1,4 @@
1
- import { ClusterBehavior } from '@matter/node';
1
+ import { ClusterBehavior, isClientBehavior } from '@matter/node';
2
2
  import { getClusterNameById } from '@matter/types/cluster';
3
3
  import { logModuleLoaded } from '@matterbridge/utils/loader';
4
4
  import { db, hk } from 'node-ansi-logger';
@@ -44,7 +44,7 @@ export async function getServerBehaviorFromClusterId(clusterId, features) {
44
44
  return undefined;
45
45
  }
46
46
  const base = mod[`${name}Server`];
47
- if (!base || !ClusterBehavior.isType(base))
47
+ if (!base || !ClusterBehavior.isType(base) || isClientBehavior(base))
48
48
  return undefined;
49
49
  const featureNames = (Array.isArray(features)
50
50
  ? features
@@ -53,6 +53,22 @@ export async function getServerBehaviorFromClusterId(clusterId, features) {
53
53
  .map(([key]) => key)).map((key) => pascalCase(key));
54
54
  return featureNames.length > 0 ? base.with(...featureNames) : base;
55
55
  }
56
+ export async function getClientBehaviorFromClusterId(clusterId) {
57
+ const name = getClusterNameById(clusterId);
58
+ if (name.includes('Unknown cluster'))
59
+ return undefined;
60
+ let mod;
61
+ try {
62
+ mod = (await import(`@matter/node/behaviors/${snakeCase(name)}`));
63
+ }
64
+ catch {
65
+ return undefined;
66
+ }
67
+ const base = mod[`${name}Client`];
68
+ if (!base || !ClusterBehavior.isType(base) || !isClientBehavior(base))
69
+ return undefined;
70
+ return base;
71
+ }
56
72
  export async function createClusterServer(endpoint, clusterId, options) {
57
73
  const type = await getServerBehaviorFromClusterId(clusterId, options?.features);
58
74
  if (!type) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matterbridge/core",
3
- "version": "3.10.8-dev-20260901-c4963a1",
3
+ "version": "3.10.8-dev-20260901-971f7bf",
4
4
  "description": "Matterbridge core library",
5
5
  "author": "https://github.com/Luligu",
6
6
  "homepage": "https://matterbridge.io/",
@@ -132,10 +132,10 @@
132
132
  },
133
133
  "dependencies": {
134
134
  "@matter/main": "0.17.9",
135
- "@matterbridge/dgram": "3.10.8-dev-20260901-c4963a1",
136
- "@matterbridge/thread": "3.10.8-dev-20260901-c4963a1",
137
- "@matterbridge/types": "3.10.8-dev-20260901-c4963a1",
138
- "@matterbridge/utils": "3.10.8-dev-20260901-c4963a1",
135
+ "@matterbridge/dgram": "3.10.8-dev-20260901-971f7bf",
136
+ "@matterbridge/thread": "3.10.8-dev-20260901-971f7bf",
137
+ "@matterbridge/types": "3.10.8-dev-20260901-971f7bf",
138
+ "@matterbridge/utils": "3.10.8-dev-20260901-971f7bf",
139
139
  "escape-html": "1.0.3",
140
140
  "express": "5.2.1",
141
141
  "express-rate-limit": "8.7.0",