@matterbridge/core 3.10.8-dev-20260903-4ab4a0f → 3.10.8-dev-20260903-014e30e

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.
@@ -19,6 +19,7 @@ export * from './pumpConfigurationAndControlServer.js';
19
19
  export * from './serviceAreaServer.js';
20
20
  export * from './smokeCoAlarmServer.js';
21
21
  export * from './switchServer.js';
22
+ export * from './temperatureAlarmServer.js';
22
23
  export * from './thermostatServer.js';
23
24
  export * from './valveConfigurationAndControlServer.js';
24
25
  export * from './waterTankLevelMonitoringServer.js';
@@ -19,6 +19,7 @@ export * from './pumpConfigurationAndControlServer.js';
19
19
  export * from './serviceAreaServer.js';
20
20
  export * from './smokeCoAlarmServer.js';
21
21
  export * from './switchServer.js';
22
+ export * from './temperatureAlarmServer.js';
22
23
  export * from './thermostatServer.js';
23
24
  export * from './valveConfigurationAndControlServer.js';
24
25
  export * from './waterTankLevelMonitoringServer.js';
@@ -0,0 +1,26 @@
1
+ import type { MaybePromise } from '@matter/general';
2
+ import { TemperatureAlarmServer } from '@matter/node/behaviors/temperature-alarm';
3
+ import { TemperatureAlarm } from '@matter/types/clusters/temperature-alarm';
4
+ declare class TemperatureAlarmBaseServer extends TemperatureAlarmServer {
5
+ static readonly schema: import("@matter/model").ClusterModel;
6
+ }
7
+ declare const MatterbridgeTemperatureAlarmServer_base: import("@matter/node").ClusterBehavior.Type<typeof TemperatureAlarmBaseServer, import("@matter/types").ClusterType.WithSupportedFeatures<TemperatureAlarm, {
8
+ majorThreshold: false;
9
+ minorThreshold: false;
10
+ overCriticalAdjustable: false;
11
+ overMajorAdjustable: false;
12
+ overMinorAdjustable: false;
13
+ overTemperature: true;
14
+ reset: true;
15
+ underCriticalAdjustable: false;
16
+ underMajorAdjustable: false;
17
+ underMinorAdjustable: false;
18
+ underTemperature: true;
19
+ }>, import("@matter/types").ClusterType.Concrete, new () => {}, "temperatureAlarm">;
20
+ export declare class MatterbridgeTemperatureAlarmServer extends MatterbridgeTemperatureAlarmServer_base {
21
+ #private;
22
+ initialize(): MaybePromise;
23
+ reset(request: TemperatureAlarm.ResetRequest): Promise<void>;
24
+ modifyEnabledAlarms(request: TemperatureAlarm.ModifyEnabledAlarmsRequest): Promise<void>;
25
+ }
26
+ export {};
@@ -0,0 +1,96 @@
1
+ import { AttributeElement, CommandElement, EventElement, FieldElement } from '@matter/model';
2
+ import { TemperatureAlarmServer } from '@matter/node/behaviors/temperature-alarm';
3
+ import { Status, StatusResponseError } from '@matter/types';
4
+ import { TemperatureAlarm } from '@matter/types/clusters/temperature-alarm';
5
+ import { debugStringify, nf } from 'node-ansi-logger';
6
+ import { MatterbridgeServer } from './matterbridgeServer.js';
7
+ const MatterbridgeTemperatureAlarmSchema = TemperatureAlarmServer.schema.extend({}, AttributeElement({ name: 'Mask', id: 0x0000, type: 'AlarmBitmap', access: 'R V', conformance: 'M' }), AttributeElement({ name: 'Latch', id: 0x0001, type: 'AlarmBitmap', access: 'R V', conformance: 'RESET', quality: 'F' }), AttributeElement({ name: 'State', id: 0x0002, type: 'AlarmBitmap', access: 'R V', conformance: 'M' }), AttributeElement({ name: 'Supported', id: 0x0003, type: 'AlarmBitmap', access: 'R V', conformance: 'M', quality: 'F' }), CommandElement({ name: 'Reset', id: 0x0000, access: 'O', conformance: 'RESET', direction: 'request', response: 'status' }, FieldElement({ name: 'Alarms', id: 0x0000, type: 'AlarmBitmap', conformance: 'M' })), CommandElement({ name: 'ModifyEnabledAlarms', id: 0x0001, access: 'O', conformance: 'O', direction: 'request', response: 'status' }, FieldElement({ name: 'Mask', id: 0x0000, type: 'AlarmBitmap', conformance: 'M' })), EventElement({ name: 'Notify', id: 0x0000, access: 'V', conformance: 'M', priority: 'info' }, FieldElement({ name: 'Active', id: 0x0000, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'Inactive', id: 0x0001, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'State', id: 0x0002, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'Mask', id: 0x0003, type: 'AlarmBitmap', conformance: 'M' })));
8
+ class TemperatureAlarmBaseServer extends TemperatureAlarmServer {
9
+ static schema = MatterbridgeTemperatureAlarmSchema;
10
+ }
11
+ export class MatterbridgeTemperatureAlarmServer extends TemperatureAlarmBaseServer.with(TemperatureAlarm.Feature.Reset, TemperatureAlarm.Feature.OverTemperature, TemperatureAlarm.Feature.UnderTemperature) {
12
+ initialize() {
13
+ this.reactTo(this.events.state$Changed, this.#emitNotify);
14
+ }
15
+ #emitNotify(state, oldState) {
16
+ const active = {
17
+ criticalOverTemperatureAlarm: Boolean(state.criticalOverTemperatureAlarm && !oldState.criticalOverTemperatureAlarm),
18
+ majorOverTemperatureAlarm: Boolean(state.majorOverTemperatureAlarm && !oldState.majorOverTemperatureAlarm),
19
+ minorOverTemperatureAlarm: Boolean(state.minorOverTemperatureAlarm && !oldState.minorOverTemperatureAlarm),
20
+ minorUnderTemperatureAlarm: Boolean(state.minorUnderTemperatureAlarm && !oldState.minorUnderTemperatureAlarm),
21
+ majorUnderTemperatureAlarm: Boolean(state.majorUnderTemperatureAlarm && !oldState.majorUnderTemperatureAlarm),
22
+ criticalUnderTemperatureAlarm: Boolean(state.criticalUnderTemperatureAlarm && !oldState.criticalUnderTemperatureAlarm),
23
+ };
24
+ const inactive = {
25
+ criticalOverTemperatureAlarm: Boolean(!state.criticalOverTemperatureAlarm && oldState.criticalOverTemperatureAlarm),
26
+ majorOverTemperatureAlarm: Boolean(!state.majorOverTemperatureAlarm && oldState.majorOverTemperatureAlarm),
27
+ minorOverTemperatureAlarm: Boolean(!state.minorOverTemperatureAlarm && oldState.minorOverTemperatureAlarm),
28
+ minorUnderTemperatureAlarm: Boolean(!state.minorUnderTemperatureAlarm && oldState.minorUnderTemperatureAlarm),
29
+ majorUnderTemperatureAlarm: Boolean(!state.majorUnderTemperatureAlarm && oldState.majorUnderTemperatureAlarm),
30
+ criticalUnderTemperatureAlarm: Boolean(!state.criticalUnderTemperatureAlarm && oldState.criticalUnderTemperatureAlarm),
31
+ };
32
+ this.events.notify.emit({ active, inactive, state, mask: this.state.mask }, this.context);
33
+ }
34
+ #assertAlarmsSupported(alarms, status) {
35
+ const unsupported = {
36
+ criticalOverTemperatureAlarm: Boolean(alarms.criticalOverTemperatureAlarm && !this.state.supported.criticalOverTemperatureAlarm),
37
+ majorOverTemperatureAlarm: Boolean(alarms.majorOverTemperatureAlarm && !this.state.supported.majorOverTemperatureAlarm),
38
+ minorOverTemperatureAlarm: Boolean(alarms.minorOverTemperatureAlarm && !this.state.supported.minorOverTemperatureAlarm),
39
+ minorUnderTemperatureAlarm: Boolean(alarms.minorUnderTemperatureAlarm && !this.state.supported.minorUnderTemperatureAlarm),
40
+ majorUnderTemperatureAlarm: Boolean(alarms.majorUnderTemperatureAlarm && !this.state.supported.majorUnderTemperatureAlarm),
41
+ criticalUnderTemperatureAlarm: Boolean(alarms.criticalUnderTemperatureAlarm && !this.state.supported.criticalUnderTemperatureAlarm),
42
+ };
43
+ if (Object.values(unsupported).some(Boolean)) {
44
+ throw new StatusResponseError(`MatterbridgeTemperatureAlarmServer: requested alarm is not supported (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`, status);
45
+ }
46
+ }
47
+ #clearAlarms(alarms) {
48
+ return {
49
+ criticalOverTemperatureAlarm: Boolean(this.state.state.criticalOverTemperatureAlarm && !alarms.criticalOverTemperatureAlarm),
50
+ majorOverTemperatureAlarm: Boolean(this.state.state.majorOverTemperatureAlarm && !alarms.majorOverTemperatureAlarm),
51
+ minorOverTemperatureAlarm: Boolean(this.state.state.minorOverTemperatureAlarm && !alarms.minorOverTemperatureAlarm),
52
+ minorUnderTemperatureAlarm: Boolean(this.state.state.minorUnderTemperatureAlarm && !alarms.minorUnderTemperatureAlarm),
53
+ majorUnderTemperatureAlarm: Boolean(this.state.state.majorUnderTemperatureAlarm && !alarms.majorUnderTemperatureAlarm),
54
+ criticalUnderTemperatureAlarm: Boolean(this.state.state.criticalUnderTemperatureAlarm && !alarms.criticalUnderTemperatureAlarm),
55
+ };
56
+ }
57
+ #applyMaskToState(mask) {
58
+ return {
59
+ criticalOverTemperatureAlarm: Boolean(this.state.state.criticalOverTemperatureAlarm && mask.criticalOverTemperatureAlarm),
60
+ majorOverTemperatureAlarm: Boolean(this.state.state.majorOverTemperatureAlarm && mask.majorOverTemperatureAlarm),
61
+ minorOverTemperatureAlarm: Boolean(this.state.state.minorOverTemperatureAlarm && mask.minorOverTemperatureAlarm),
62
+ minorUnderTemperatureAlarm: Boolean(this.state.state.minorUnderTemperatureAlarm && mask.minorUnderTemperatureAlarm),
63
+ majorUnderTemperatureAlarm: Boolean(this.state.state.majorUnderTemperatureAlarm && mask.majorUnderTemperatureAlarm),
64
+ criticalUnderTemperatureAlarm: Boolean(this.state.state.criticalUnderTemperatureAlarm && mask.criticalUnderTemperatureAlarm),
65
+ };
66
+ }
67
+ async reset(request) {
68
+ const device = this.endpoint.stateOf(MatterbridgeServer);
69
+ device.log.info(`MatterbridgeTemperatureAlarmServer: resetting alarms ${debugStringify(request.alarms)}${nf} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
70
+ await device.commandHandler.executeHandler('TemperatureAlarm.reset', {
71
+ command: 'reset',
72
+ request,
73
+ cluster: MatterbridgeTemperatureAlarmServer.id,
74
+ attributes: this.state,
75
+ endpoint: this.endpoint,
76
+ context: this.context,
77
+ });
78
+ this.#assertAlarmsSupported(request.alarms, Status.Failure);
79
+ this.state.state = this.#clearAlarms(request.alarms);
80
+ }
81
+ async modifyEnabledAlarms(request) {
82
+ const device = this.endpoint.stateOf(MatterbridgeServer);
83
+ device.log.info(`MatterbridgeTemperatureAlarmServer: modifying enabled alarms ${debugStringify(request.mask)}${nf} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
84
+ await device.commandHandler.executeHandler('TemperatureAlarm.modifyEnabledAlarms', {
85
+ command: 'modifyEnabledAlarms',
86
+ request,
87
+ cluster: MatterbridgeTemperatureAlarmServer.id,
88
+ attributes: this.state,
89
+ endpoint: this.endpoint,
90
+ context: this.context,
91
+ });
92
+ this.#assertAlarmsSupported(request.mask, Status.InvalidCommand);
93
+ this.state.mask = request.mask;
94
+ this.state.state = this.#applyMaskToState(request.mask);
95
+ }
96
+ }
@@ -32,7 +32,8 @@ export class MatterbridgeWindowCoveringServer extends WindowCoveringServer.with(
32
32
  return current < target ? WindowCovering.MovementStatus.Closing : WindowCovering.MovementStatus.Opening;
33
33
  }
34
34
  #updateGlobalOperationalStatus() {
35
- const { lift, tilt } = this.state.operationalStatus;
35
+ const lift = this.state.operationalStatus.lift ?? WindowCovering.MovementStatus.Stopped;
36
+ const tilt = this.state.operationalStatus.tilt ?? WindowCovering.MovementStatus.Stopped;
36
37
  this.state.operationalStatus.global = lift === WindowCovering.MovementStatus.Stopped ? tilt : lift;
37
38
  }
38
39
  #startLiftMovement(targetPercent100ths) {
package/dist/chipTests.js CHANGED
@@ -24,7 +24,6 @@ import { SmokeCoAlarm } from '@matter/types/clusters/smoke-co-alarm';
24
24
  import { TariffPriceType, TariffUnit } from '@matter/types/globals';
25
25
  import { MatterbridgeOccupancySensingServer } from './behaviors/occupancySensingServer.js';
26
26
  import { cliEmitter } from './cliEmitter.js';
27
- import { MatterbridgeRefrigeratorAlarmServer } from './devices/refrigerator.js';
28
27
  import { MatterbridgeRvcOperationalStateServer, MatterbridgeRvcRunModeServer } from './devices/roboticVacuumCleaner.js';
29
28
  import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
30
29
  const chipTestAppPipePath = '/tmp/matterbridge-chip-test-app-pipe';
@@ -1019,14 +1018,7 @@ async function handleChipTestAppPipeCommand(matterbridge, command) {
1019
1018
  return;
1020
1019
  case 'SetRefrigeratorDoorStatus': {
1021
1020
  const doorOpen = Boolean(command.DoorOpen);
1022
- const wasDoorOpen = Boolean(endpoint.stateOf(MatterbridgeRefrigeratorAlarmServer).state.doorOpen);
1023
1021
  await endpoint.setCluster(RefrigeratorAlarm, { state: { doorOpen } }, matterbridge.log);
1024
- await endpoint.triggerEvent('RefrigeratorAlarm', 'notify', {
1025
- active: { doorOpen: doorOpen && !wasDoorOpen },
1026
- inactive: { doorOpen: !doorOpen && wasDoorOpen },
1027
- state: { doorOpen },
1028
- mask: endpoint.stateOf(MatterbridgeRefrigeratorAlarmServer).mask,
1029
- }, matterbridge.log);
1030
1022
  matterbridge.log.info(`CHIP test app pipe set RefrigeratorAlarm.State.DoorOpen to ${doorOpen} on endpoint ${endpointId}`);
1031
1023
  return;
1032
1024
  }
@@ -372,6 +372,10 @@ export async function createDemoDevices(matterbridge) {
372
372
  ep.createDefaultPowerSourceBatteryClusterServer();
373
373
  ep.createUserPinDoorLockClusterServer(DoorLock.LockState.Locked, DoorLock.LockType.DeadBolt, 0, 4, 10, 2, 3, 4);
374
374
  await registerDevice(ep, 'Door Lock User PIN Schedules', 'ENTRY-08-01-2');
375
+ ep = new MatterbridgeEndpoint([getSupportedDeviceType('DoorLock'), bridgedNode, powerSource], { id: 'DoorLockUserPinExpiring', number: EndpointNumber(8_01_3) });
376
+ ep.createDefaultPowerSourceBatteryClusterServer();
377
+ ep.createUserPinDoorLockClusterServer(DoorLock.LockState.Locked, DoorLock.LockType.DeadBolt, 0, 4, 10, undefined, undefined, undefined, 10);
378
+ await registerDevice(ep, 'Door Lock User PIN Expiring', 'ENTRY-08-01-3');
375
379
  ep = new MatterbridgeEndpoint([getSupportedDeviceType('DoorLockController'), bridgedNode, powerSource], { id: 'DoorLockController', number: EndpointNumber(8_02) });
376
380
  await registerDevice(ep, 'Door Lock Controller', 'ENTRY-08-02');
377
381
  ep = new MatterbridgeEndpoint([getSupportedDeviceType('WindowCovering'), bridgedNode, powerSource], { id: 'WindowCoveringLift', number: EndpointNumber(8_03) });
@@ -1,6 +1,8 @@
1
+ import type { MaybePromise } from '@matter/general';
1
2
  import { DishwasherAlarmServer } from '@matter/node/behaviors/dishwasher-alarm';
2
3
  import { DishwasherModeServer } from '@matter/node/behaviors/dishwasher-mode';
3
- import type { EndpointNumber } from '@matter/types';
4
+ import { type EndpointNumber } from '@matter/types';
5
+ import { DishwasherAlarm } from '@matter/types/clusters/dishwasher-alarm';
4
6
  import { DishwasherMode } from '@matter/types/clusters/dishwasher-mode';
5
7
  import { ModeBase } from '@matter/types/clusters/mode-base';
6
8
  import type { OperationalState } from '@matter/types/clusters/operational-state';
@@ -32,6 +34,16 @@ export declare class MatterbridgeDishwasherModeServer extends DishwasherModeServ
32
34
  protected handleOnOffChange(onOff: boolean): void;
33
35
  changeToMode(request: ModeBase.ChangeToModeRequest): Promise<ModeBase.ChangeToModeResponse>;
34
36
  }
35
- export declare class MatterbridgeDishwasherAlarmServer extends DishwasherAlarmServer {
37
+ declare class DishwasherAlarmBaseServer extends DishwasherAlarmServer {
36
38
  static readonly schema: import("@matter/model").ClusterModel;
37
39
  }
40
+ declare const MatterbridgeDishwasherAlarmServer_base: import("@matter/node").ClusterBehavior.Type<typeof DishwasherAlarmBaseServer, import("@matter/types").ClusterType.WithSupportedFeatures<DishwasherAlarm, {
41
+ reset: true;
42
+ }>, import("@matter/types").ClusterType.Concrete, new () => {}, "dishwasherAlarm">;
43
+ export declare class MatterbridgeDishwasherAlarmServer extends MatterbridgeDishwasherAlarmServer_base {
44
+ #private;
45
+ initialize(): MaybePromise;
46
+ reset(request: DishwasherAlarm.ResetRequest): Promise<void>;
47
+ modifyEnabledAlarms(request: DishwasherAlarm.ModifyEnabledAlarmsRequest): Promise<void>;
48
+ }
49
+ export {};
@@ -1,9 +1,12 @@
1
- import { AttributeElement, EventElement, FieldElement } from '@matter/model';
1
+ import { AttributeElement, CommandElement, EventElement, FieldElement } from '@matter/model';
2
2
  import { DishwasherAlarmServer } from '@matter/node/behaviors/dishwasher-alarm';
3
3
  import { DishwasherModeServer } from '@matter/node/behaviors/dishwasher-mode';
4
+ import { Status, StatusResponseError } from '@matter/types';
5
+ import { DishwasherAlarm } from '@matter/types/clusters/dishwasher-alarm';
4
6
  import { DishwasherMode } from '@matter/types/clusters/dishwasher-mode';
5
7
  import { ModeBase } from '@matter/types/clusters/mode-base';
6
8
  import { OnOff } from '@matter/types/clusters/on-off';
9
+ import { debugStringify, nf } from 'node-ansi-logger';
7
10
  import { MatterbridgeServer } from '../behaviors/matterbridgeServer.js';
8
11
  import { MatterbridgeOnOffServer } from '../behaviors/onOffServer.js';
9
12
  import { dishwasher, powerSource } from '../matterbridgeDeviceTypes.js';
@@ -56,6 +59,7 @@ export class Dishwasher extends MatterbridgeEndpoint {
56
59
  createDefaultDishwasherAlarmClusterServer() {
57
60
  this.behaviors.require(MatterbridgeDishwasherAlarmServer, {
58
61
  mask: { inflowError: false, drainError: false, doorError: true, tempTooLow: false, tempTooHigh: false, waterLevelError: false },
62
+ latch: { inflowError: false, drainError: false, doorError: false, tempTooLow: false, tempTooHigh: false, waterLevelError: false },
59
63
  state: { inflowError: false, drainError: false, doorError: false, tempTooLow: false, tempTooHigh: false, waterLevelError: false },
60
64
  supported: { inflowError: false, drainError: false, doorError: true, tempTooLow: false, tempTooHigh: false, waterLevelError: false },
61
65
  });
@@ -98,7 +102,93 @@ export class MatterbridgeDishwasherModeServer extends DishwasherModeServer {
98
102
  }
99
103
  }
100
104
  }
101
- const MatterbridgeDishwasherAlarmSchema = DishwasherAlarmServer.schema.extend({}, AttributeElement({ name: 'Mask', id: 0x0000, type: 'AlarmBitmap', access: 'R V', conformance: 'M' }), AttributeElement({ name: 'State', id: 0x0002, type: 'AlarmBitmap', access: 'R V', conformance: 'M' }), AttributeElement({ name: 'Supported', id: 0x0003, type: 'AlarmBitmap', access: 'R V', conformance: 'M', quality: 'F' }), EventElement({ name: 'Notify', id: 0x0000, access: 'V', conformance: 'M', priority: 'info' }, FieldElement({ name: 'Active', id: 0x0000, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'Inactive', id: 0x0001, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'State', id: 0x0002, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'Mask', id: 0x0003, type: 'AlarmBitmap', conformance: 'M' })));
102
- export class MatterbridgeDishwasherAlarmServer extends DishwasherAlarmServer {
105
+ const MatterbridgeDishwasherAlarmSchema = DishwasherAlarmServer.schema.extend({}, AttributeElement({ name: 'Mask', id: 0x0000, type: 'AlarmBitmap', access: 'R V', conformance: 'M' }), AttributeElement({ name: 'Latch', id: 0x0001, type: 'AlarmBitmap', access: 'R V', conformance: 'RESET', quality: 'F' }), AttributeElement({ name: 'State', id: 0x0002, type: 'AlarmBitmap', access: 'R V', conformance: 'M' }), AttributeElement({ name: 'Supported', id: 0x0003, type: 'AlarmBitmap', access: 'R V', conformance: 'M', quality: 'F' }), CommandElement({ name: 'Reset', id: 0x0000, access: 'O', conformance: 'RESET', direction: 'request', response: 'status' }, FieldElement({ name: 'Alarms', id: 0x0000, type: 'AlarmBitmap', conformance: 'M' })), CommandElement({ name: 'ModifyEnabledAlarms', id: 0x0001, access: 'O', conformance: 'O', direction: 'request', response: 'status' }, FieldElement({ name: 'Mask', id: 0x0000, type: 'AlarmBitmap', conformance: 'M' })), EventElement({ name: 'Notify', id: 0x0000, access: 'V', conformance: 'M', priority: 'info' }, FieldElement({ name: 'Active', id: 0x0000, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'Inactive', id: 0x0001, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'State', id: 0x0002, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'Mask', id: 0x0003, type: 'AlarmBitmap', conformance: 'M' })));
106
+ class DishwasherAlarmBaseServer extends DishwasherAlarmServer {
103
107
  static schema = MatterbridgeDishwasherAlarmSchema;
104
108
  }
109
+ export class MatterbridgeDishwasherAlarmServer extends DishwasherAlarmBaseServer.with(DishwasherAlarm.Feature.Reset) {
110
+ initialize() {
111
+ this.reactTo(this.events.state$Changed, this.#emitNotify);
112
+ }
113
+ #emitNotify(state, oldState) {
114
+ const active = {
115
+ inflowError: Boolean(state.inflowError && !oldState.inflowError),
116
+ drainError: Boolean(state.drainError && !oldState.drainError),
117
+ doorError: Boolean(state.doorError && !oldState.doorError),
118
+ tempTooLow: Boolean(state.tempTooLow && !oldState.tempTooLow),
119
+ tempTooHigh: Boolean(state.tempTooHigh && !oldState.tempTooHigh),
120
+ waterLevelError: Boolean(state.waterLevelError && !oldState.waterLevelError),
121
+ };
122
+ const inactive = {
123
+ inflowError: Boolean(!state.inflowError && oldState.inflowError),
124
+ drainError: Boolean(!state.drainError && oldState.drainError),
125
+ doorError: Boolean(!state.doorError && oldState.doorError),
126
+ tempTooLow: Boolean(!state.tempTooLow && oldState.tempTooLow),
127
+ tempTooHigh: Boolean(!state.tempTooHigh && oldState.tempTooHigh),
128
+ waterLevelError: Boolean(!state.waterLevelError && oldState.waterLevelError),
129
+ };
130
+ this.events.notify.emit({ active, inactive, state, mask: this.state.mask }, this.context);
131
+ }
132
+ #assertAlarmsSupported(alarms, status) {
133
+ const unsupported = {
134
+ inflowError: Boolean(alarms.inflowError && !this.state.supported.inflowError),
135
+ drainError: Boolean(alarms.drainError && !this.state.supported.drainError),
136
+ doorError: Boolean(alarms.doorError && !this.state.supported.doorError),
137
+ tempTooLow: Boolean(alarms.tempTooLow && !this.state.supported.tempTooLow),
138
+ tempTooHigh: Boolean(alarms.tempTooHigh && !this.state.supported.tempTooHigh),
139
+ waterLevelError: Boolean(alarms.waterLevelError && !this.state.supported.waterLevelError),
140
+ };
141
+ if (Object.values(unsupported).some(Boolean)) {
142
+ throw new StatusResponseError(`MatterbridgeDishwasherAlarmServer: requested alarm is not supported (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`, status);
143
+ }
144
+ }
145
+ #clearAlarms(alarms) {
146
+ return {
147
+ inflowError: Boolean(this.state.state.inflowError && !alarms.inflowError),
148
+ drainError: Boolean(this.state.state.drainError && !alarms.drainError),
149
+ doorError: Boolean(this.state.state.doorError && !alarms.doorError),
150
+ tempTooLow: Boolean(this.state.state.tempTooLow && !alarms.tempTooLow),
151
+ tempTooHigh: Boolean(this.state.state.tempTooHigh && !alarms.tempTooHigh),
152
+ waterLevelError: Boolean(this.state.state.waterLevelError && !alarms.waterLevelError),
153
+ };
154
+ }
155
+ #applyMaskToState(mask) {
156
+ return {
157
+ inflowError: Boolean(this.state.state.inflowError && mask.inflowError),
158
+ drainError: Boolean(this.state.state.drainError && mask.drainError),
159
+ doorError: Boolean(this.state.state.doorError && mask.doorError),
160
+ tempTooLow: Boolean(this.state.state.tempTooLow && mask.tempTooLow),
161
+ tempTooHigh: Boolean(this.state.state.tempTooHigh && mask.tempTooHigh),
162
+ waterLevelError: Boolean(this.state.state.waterLevelError && mask.waterLevelError),
163
+ };
164
+ }
165
+ async reset(request) {
166
+ const device = this.endpoint.stateOf(MatterbridgeServer);
167
+ device.log.info(`MatterbridgeDishwasherAlarmServer: resetting alarms ${debugStringify(request.alarms)}${nf} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
168
+ await device.commandHandler.executeHandler('DishwasherAlarm.reset', {
169
+ command: 'reset',
170
+ request,
171
+ cluster: MatterbridgeDishwasherAlarmServer.id,
172
+ attributes: this.state,
173
+ endpoint: this.endpoint,
174
+ context: this.context,
175
+ });
176
+ this.#assertAlarmsSupported(request.alarms, Status.Failure);
177
+ this.state.state = this.#clearAlarms(request.alarms);
178
+ }
179
+ async modifyEnabledAlarms(request) {
180
+ const device = this.endpoint.stateOf(MatterbridgeServer);
181
+ device.log.info(`MatterbridgeDishwasherAlarmServer: modifying enabled alarms ${debugStringify(request.mask)}${nf} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
182
+ await device.commandHandler.executeHandler('DishwasherAlarm.modifyEnabledAlarms', {
183
+ command: 'modifyEnabledAlarms',
184
+ request,
185
+ cluster: MatterbridgeDishwasherAlarmServer.id,
186
+ attributes: this.state,
187
+ endpoint: this.endpoint,
188
+ context: this.context,
189
+ });
190
+ this.#assertAlarmsSupported(request.mask, Status.InvalidCommand);
191
+ this.state.mask = request.mask;
192
+ this.state.state = this.#applyMaskToState(request.mask);
193
+ }
194
+ }
@@ -38,5 +38,7 @@ export declare class MatterbridgeRefrigeratorAndTemperatureControlledCabinetMode
38
38
  changeToMode(request: ModeBase.ChangeToModeRequest): MaybePromise<ModeBase.ChangeToModeResponse>;
39
39
  }
40
40
  export declare class MatterbridgeRefrigeratorAlarmServer extends RefrigeratorAlarmServer {
41
+ #private;
41
42
  static readonly schema: import("@matter/model").ClusterModel;
43
+ initialize(): MaybePromise;
42
44
  }
@@ -100,4 +100,12 @@ export class MatterbridgeRefrigeratorAndTemperatureControlledCabinetModeServer e
100
100
  const MatterbridgeRefrigeratorAlarmSchema = RefrigeratorAlarmServer.schema.extend({}, AttributeElement({ name: 'Mask', id: 0x0000, type: 'AlarmBitmap', access: 'R V', conformance: 'M' }), AttributeElement({ name: 'State', id: 0x0002, type: 'AlarmBitmap', access: 'R V', conformance: 'M' }), AttributeElement({ name: 'Supported', id: 0x0003, type: 'AlarmBitmap', access: 'R V', conformance: 'M', quality: 'F' }), EventElement({ name: 'Notify', id: 0x0000, access: 'V', conformance: 'M', priority: 'info' }, FieldElement({ name: 'Active', id: 0x0000, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'Inactive', id: 0x0001, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'State', id: 0x0002, type: 'AlarmBitmap', conformance: 'M' }), FieldElement({ name: 'Mask', id: 0x0003, type: 'AlarmBitmap', conformance: 'M' })));
101
101
  export class MatterbridgeRefrigeratorAlarmServer extends RefrigeratorAlarmServer {
102
102
  static schema = MatterbridgeRefrigeratorAlarmSchema;
103
+ initialize() {
104
+ this.reactTo(this.events.state$Changed, this.#emitNotify);
105
+ }
106
+ #emitNotify(state, oldState) {
107
+ const active = { doorOpen: Boolean(state.doorOpen && !oldState.doorOpen) };
108
+ const inactive = { doorOpen: Boolean(!state.doorOpen && oldState.doorOpen) };
109
+ this.events.notify.emit({ active, inactive, state, mask: this.state.mask }, this.context);
110
+ }
103
111
  }
package/dist/export.d.ts CHANGED
@@ -19,6 +19,7 @@ export * from './behaviors/smokeCoAlarmServer.js';
19
19
  export * from './behaviors/switchServer.js';
20
20
  export * from './behaviors/thermostatServer.js';
21
21
  export * from './behaviors/valveConfigurationAndControlServer.js';
22
+ export * from './behaviors/temperatureAlarmServer.js';
22
23
  export * from './behaviors/waterTankLevelMonitoringServer.js';
23
24
  export * from './behaviors/windowCoveringServer.js';
24
25
  export { addVirtualDevice } from './helpers.js';
package/dist/export.js CHANGED
@@ -21,6 +21,7 @@ export * from './behaviors/smokeCoAlarmServer.js';
21
21
  export * from './behaviors/switchServer.js';
22
22
  export * from './behaviors/thermostatServer.js';
23
23
  export * from './behaviors/valveConfigurationAndControlServer.js';
24
+ export * from './behaviors/temperatureAlarmServer.js';
24
25
  export * from './behaviors/waterTankLevelMonitoringServer.js';
25
26
  export * from './behaviors/windowCoveringServer.js';
26
27
  export { addVirtualDevice } from './helpers.js';
package/dist/frontend.js CHANGED
@@ -1202,6 +1202,8 @@ export class Frontend extends EventEmitter {
1202
1202
  attributes += `Carbon filter: ${attributeValue}% `;
1203
1203
  if (clusterName === 'waterTankLevelMonitoring' && attributeName === 'condition')
1204
1204
  attributes += `Water tank: ${attributeValue}% `;
1205
+ if (clusterName === 'temperatureAlarm' && attributeName === 'state' && isValidObject(attributeValue))
1206
+ attributes += `Temp alarm: ${stringify(attributeValue)} `;
1205
1207
  if (clusterName === 'occupancySensing' && attributeName === 'occupancy' && isValidObject(attributeValue, 1))
1206
1208
  attributes += `Occupancy: ${attributeValue.occupied} `;
1207
1209
  if (clusterName === 'illuminanceMeasurement' && attributeName === 'measuredValue') {
@@ -1265,6 +1265,7 @@ export const supportedClusters = [
1265
1265
  SoilMeasurement,
1266
1266
  Switch,
1267
1267
  TargetNavigator,
1268
+ TemperatureAlarm,
1268
1269
  TemperatureControl,
1269
1270
  TemperatureMeasurement,
1270
1271
  Thermostat,
@@ -18,6 +18,7 @@ import { PowerTopology } from '@matter/types/clusters/power-topology';
18
18
  import { PumpConfigurationAndControl } from '@matter/types/clusters/pump-configuration-and-control';
19
19
  import { ResourceMonitoring } from '@matter/types/clusters/resource-monitoring';
20
20
  import { SmokeCoAlarm } from '@matter/types/clusters/smoke-co-alarm';
21
+ import type { TemperatureAlarm } from '@matter/types/clusters/temperature-alarm';
21
22
  import { Thermostat } from '@matter/types/clusters/thermostat';
22
23
  import { ThermostatUserInterfaceConfiguration } from '@matter/types/clusters/thermostat-user-interface-configuration';
23
24
  import { ValveConfigurationAndControl } from '@matter/types/clusters/valve-configuration-and-control';
@@ -119,9 +120,9 @@ export declare class MatterbridgeEndpoint extends Endpoint {
119
120
  addCommandHandler<C extends CommandHandlers>(command: C, handler: CommandHandlerFunction<C>): this;
120
121
  removeCommandHandler<C extends CommandHandlers>(command: C, handler: CommandHandlerFunction<C>): this;
121
122
  executeCommandHandler<C extends CommandHandlers>(command: C, request: CommandHandlerData<C>['request'], cluster: CommandHandlerData<C>['cluster'], attributes: CommandHandlerData<C>['attributes'], endpoint: CommandHandlerData<C>['endpoint']): Promise<CommandHandlerExecutionResult<C>>;
122
- invokeBehaviorCommand<T extends Behavior.Type, C extends BehaviorCommandName<T>>(cluster: T, command: C, params?: BehaviorCommandParams<T, C>): Promise<void>;
123
- invokeBehaviorCommand<T extends ClusterType, C extends ClusterCommandName<T>>(cluster: T, command: C, params?: ClusterCommandParams<T, C>): Promise<void>;
124
- invokeBehaviorCommand(cluster: ClusterId | string, command: CommandHandlers, params?: Record<string, boolean | number | bigint | string | object | null>): Promise<void>;
123
+ invokeBehaviorCommand<T extends Behavior.Type, C extends BehaviorCommandName<T>>(cluster: T, command: C, params?: BehaviorCommandParams<T, C>, waiterCondition?: () => boolean): Promise<void>;
124
+ invokeBehaviorCommand<T extends ClusterType, C extends ClusterCommandName<T>>(cluster: T, command: C, params?: ClusterCommandParams<T, C>, waiterCondition?: () => boolean): Promise<void>;
125
+ invokeBehaviorCommand(cluster: ClusterId | string, command: CommandHandlers, params?: Record<string, boolean | number | bigint | string | object | null>, waiterCondition?: () => boolean): Promise<void>;
125
126
  addRequiredClusters(): MatterbridgeEndpoint;
126
127
  addRequiredClusterServers(): MatterbridgeEndpoint;
127
128
  addOptionalClusterServers(): MatterbridgeEndpoint;
@@ -207,9 +208,10 @@ export declare class MatterbridgeEndpoint extends Endpoint {
207
208
  }, airflowDirection?: FanControl.AirflowDirection): this;
208
209
  createDefaultHepaFilterMonitoringClusterServer(condition?: number, changeIndication?: ResourceMonitoring.ChangeIndication, inPlaceIndicator?: boolean | undefined, lastChangedTime?: number | null | undefined, replacementProductList?: ResourceMonitoring.ReplacementProduct[]): this;
209
210
  createDefaultActivatedCarbonFilterMonitoringClusterServer(condition?: number, changeIndication?: ResourceMonitoring.ChangeIndication, inPlaceIndicator?: boolean | undefined, lastChangedTime?: number | null | undefined, replacementProductList?: ResourceMonitoring.ReplacementProduct[]): this;
211
+ createDefaultTemperatureAlarmClusterServer(criticalOverTemperatureThreshold?: number, criticalUnderTemperatureThreshold?: number, supported?: TemperatureAlarm.Alarm, mask?: TemperatureAlarm.Alarm, latch?: TemperatureAlarm.Alarm, state?: TemperatureAlarm.Alarm): this;
210
212
  createDefaultWaterTankLevelMonitoringClusterServer(condition?: number, changeIndication?: ResourceMonitoring.ChangeIndication, inPlaceIndicator?: boolean | undefined, lastChangedTime?: number | null | undefined, replacementProductList?: ResourceMonitoring.ReplacementProduct[]): this;
211
213
  createDefaultDoorLockClusterServer(lockState?: DoorLock.LockState, lockType?: DoorLock.LockType, autoRelockTime?: number, numberOfWeekDaySchedulesSupportedPerUser?: number, numberOfYearDaySchedulesSupportedPerUser?: number, numberOfHolidaySchedulesSupported?: number): this;
212
- createUserPinDoorLockClusterServer(lockState?: DoorLock.LockState, lockType?: DoorLock.LockType, autoRelockTime?: number, minPinCodeLength?: number, maxPinCodeLength?: number, numberOfWeekDaySchedulesSupportedPerUser?: number, numberOfYearDaySchedulesSupportedPerUser?: number, numberOfHolidaySchedulesSupported?: number): this;
214
+ createUserPinDoorLockClusterServer(lockState?: DoorLock.LockState, lockType?: DoorLock.LockType, autoRelockTime?: number, minPinCodeLength?: number, maxPinCodeLength?: number, numberOfWeekDaySchedulesSupportedPerUser?: number, numberOfYearDaySchedulesSupportedPerUser?: number, numberOfHolidaySchedulesSupported?: number, expiringUserTimeout?: number, numberOfRfidUsersSupported?: number, minRfidCodeLength?: number, maxRfidCodeLength?: number): this;
213
215
  createDefaultModeSelectClusterServer(description: string, supportedModes: ModeSelect.ModeOption[], currentMode?: number, startUpMode?: number): this;
214
216
  createDefaultValveConfigurationAndControlClusterServer(valveState?: ValveConfigurationAndControl.ValveState, valveLevel?: number, movementDuration?: number, autoClose?: boolean): this;
215
217
  createDefaultPumpConfigurationAndControlClusterServer(pumpMode?: PumpConfigurationAndControl.OperationMode, maxPressure?: number | null, maxSpeed?: number | null, maxFlow?: number | null, minConstSpeed?: number | null, maxConstSpeed?: number | null, speed?: number | null): this;
@@ -79,6 +79,7 @@ import { MatterbridgePowerSourceServer } from './behaviors/powerSourceServer.js'
79
79
  import { MatterbridgePumpConfigurationAndControlServer } from './behaviors/pumpConfigurationAndControlServer.js';
80
80
  import { MatterbridgeSmokeCoAlarmServer } from './behaviors/smokeCoAlarmServer.js';
81
81
  import { MatterbridgeSwitchServer } from './behaviors/switchServer.js';
82
+ import { MatterbridgeTemperatureAlarmServer } from './behaviors/temperatureAlarmServer.js';
82
83
  import { MatterbridgeThermostatServer } from './behaviors/thermostatServer.js';
83
84
  import { MatterbridgeValveConfigurationAndControlServer } from './behaviors/valveConfigurationAndControlServer.js';
84
85
  import { MatterbridgeWaterTankLevelMonitoringServer } from './behaviors/waterTankLevelMonitoringServer.js';
@@ -278,8 +279,8 @@ export class MatterbridgeEndpoint extends Endpoint {
278
279
  async executeCommandHandler(command, request, cluster, attributes, endpoint) {
279
280
  return this.commandHandler.executeHandler(command, { command, request, cluster, attributes, endpoint });
280
281
  }
281
- async invokeBehaviorCommand(cluster, command, params) {
282
- await invokeBehaviorCommand(this, cluster, command, params);
282
+ async invokeBehaviorCommand(cluster, command, params, waiterCondition) {
283
+ await invokeBehaviorCommand(this, cluster, command, params, waiterCondition);
283
284
  }
284
285
  addRequiredClusters() {
285
286
  addRequiredClusterServers(this);
@@ -1285,6 +1286,25 @@ export class MatterbridgeEndpoint extends Endpoint {
1285
1286
  });
1286
1287
  return this;
1287
1288
  }
1289
+ createDefaultTemperatureAlarmClusterServer(criticalOverTemperatureThreshold = 60 * 100, criticalUnderTemperatureThreshold = -10 * 100, supported = { criticalOverTemperatureAlarm: true, criticalUnderTemperatureAlarm: true }, mask = supported, latch = {}, state = {}) {
1290
+ const bitmap = (alarm) => ({
1291
+ criticalOverTemperatureAlarm: Boolean(alarm.criticalOverTemperatureAlarm),
1292
+ majorOverTemperatureAlarm: false,
1293
+ minorOverTemperatureAlarm: false,
1294
+ minorUnderTemperatureAlarm: false,
1295
+ majorUnderTemperatureAlarm: false,
1296
+ criticalUnderTemperatureAlarm: Boolean(alarm.criticalUnderTemperatureAlarm),
1297
+ });
1298
+ this.behaviors.require(MatterbridgeTemperatureAlarmServer, {
1299
+ criticalOverTemperatureThreshold,
1300
+ criticalUnderTemperatureThreshold,
1301
+ latch: bitmap(latch),
1302
+ supported: bitmap(supported),
1303
+ mask: bitmap(mask),
1304
+ state: bitmap(state),
1305
+ });
1306
+ return this;
1307
+ }
1288
1308
  createDefaultWaterTankLevelMonitoringClusterServer(condition = 100, changeIndication = ResourceMonitoring.ChangeIndication.Ok, inPlaceIndicator = true, lastChangedTime = null, replacementProductList = []) {
1289
1309
  this.behaviors.require(MatterbridgeWaterTankLevelMonitoringServer.with(ResourceMonitoring.Feature.Condition, ResourceMonitoring.Feature.Warning, ResourceMonitoring.Feature.ReplacementProductList), {
1290
1310
  condition,
@@ -1313,8 +1333,8 @@ export class MatterbridgeEndpoint extends Endpoint {
1313
1333
  });
1314
1334
  return this;
1315
1335
  }
1316
- createUserPinDoorLockClusterServer(lockState = DoorLock.LockState.Locked, lockType = DoorLock.LockType.DeadBolt, autoRelockTime = 0, minPinCodeLength = 4, maxPinCodeLength = 10, numberOfWeekDaySchedulesSupportedPerUser, numberOfYearDaySchedulesSupportedPerUser, numberOfHolidaySchedulesSupported) {
1317
- this.behaviors.require(MatterbridgeDoorLockServer.with(DoorLock.Feature.User, DoorLock.Feature.PinCredential, ...(numberOfWeekDaySchedulesSupportedPerUser !== undefined ? [DoorLock.Feature.WeekDayAccessSchedules] : []), ...(numberOfYearDaySchedulesSupportedPerUser !== undefined ? [DoorLock.Feature.YearDayAccessSchedules] : []), ...(numberOfHolidaySchedulesSupported !== undefined ? [DoorLock.Feature.HolidaySchedules] : [])).enable({
1336
+ createUserPinDoorLockClusterServer(lockState = DoorLock.LockState.Locked, lockType = DoorLock.LockType.DeadBolt, autoRelockTime = 0, minPinCodeLength = 4, maxPinCodeLength = 10, numberOfWeekDaySchedulesSupportedPerUser, numberOfYearDaySchedulesSupportedPerUser, numberOfHolidaySchedulesSupported, expiringUserTimeout, numberOfRfidUsersSupported, minRfidCodeLength = 8, maxRfidCodeLength = 20) {
1337
+ this.behaviors.require(MatterbridgeDoorLockServer.with(DoorLock.Feature.User, DoorLock.Feature.PinCredential, ...(numberOfWeekDaySchedulesSupportedPerUser !== undefined ? [DoorLock.Feature.WeekDayAccessSchedules] : []), ...(numberOfYearDaySchedulesSupportedPerUser !== undefined ? [DoorLock.Feature.YearDayAccessSchedules] : []), ...(numberOfHolidaySchedulesSupported !== undefined ? [DoorLock.Feature.HolidaySchedules] : []), ...(numberOfRfidUsersSupported !== undefined ? [DoorLock.Feature.RfidCredential] : [])).enable({
1318
1338
  events: { doorLockAlarm: true, lockOperation: true, lockOperationError: true },
1319
1339
  commands: { lockDoor: true, unlockDoor: true, unlockWithTimeout: true },
1320
1340
  }), {
@@ -1332,9 +1352,11 @@ export class MatterbridgeEndpoint extends Endpoint {
1332
1352
  numberOfTotalUsersSupported: 10,
1333
1353
  credentialRulesSupport: { single: true },
1334
1354
  numberOfCredentialsSupportedPerUser: 10,
1355
+ ...(expiringUserTimeout !== undefined ? { expiringUserTimeout } : {}),
1335
1356
  ...(numberOfWeekDaySchedulesSupportedPerUser !== undefined ? { numberOfWeekDaySchedulesSupportedPerUser } : {}),
1336
1357
  ...(numberOfYearDaySchedulesSupportedPerUser !== undefined ? { numberOfYearDaySchedulesSupportedPerUser } : {}),
1337
1358
  ...(numberOfHolidaySchedulesSupported !== undefined ? { numberOfHolidaySchedulesSupported } : {}),
1359
+ ...(numberOfRfidUsersSupported !== undefined ? { numberOfRfidUsersSupported, minRfidCodeLength, maxRfidCodeLength } : {}),
1338
1360
  });
1339
1361
  return this;
1340
1362
  }
@@ -8,6 +8,7 @@ import type { CommodityPrice } from '@matter/types/clusters/commodity-price';
8
8
  import type { CommodityTariff } from '@matter/types/clusters/commodity-tariff';
9
9
  import type { DeviceEnergyManagement } from '@matter/types/clusters/device-energy-management';
10
10
  import type { DeviceEnergyManagementMode } from '@matter/types/clusters/device-energy-management-mode';
11
+ import type { DishwasherAlarm } from '@matter/types/clusters/dishwasher-alarm';
11
12
  import type { DishwasherMode } from '@matter/types/clusters/dishwasher-mode';
12
13
  import type { DoorLock } from '@matter/types/clusters/door-lock';
13
14
  import type { EnergyEvse } from '@matter/types/clusters/energy-evse';
@@ -30,6 +31,7 @@ import type { RvcOperationalState } from '@matter/types/clusters/rvc-operational
30
31
  import type { RvcRunMode } from '@matter/types/clusters/rvc-run-mode';
31
32
  import type { ServiceArea } from '@matter/types/clusters/service-area';
32
33
  import type { SmokeCoAlarm } from '@matter/types/clusters/smoke-co-alarm';
34
+ import type { TemperatureAlarm } from '@matter/types/clusters/temperature-alarm';
33
35
  import type { TemperatureControl } from '@matter/types/clusters/temperature-control';
34
36
  import type { Thermostat } from '@matter/types/clusters/thermostat';
35
37
  import type { ThreadNetworkDiagnostics } from '@matter/types/clusters/thread-network-diagnostics';
@@ -674,6 +676,34 @@ export type CommandHandlerDataMap = {
674
676
  attributes: ClusterAttributeValues<(typeof SmokeCoAlarm)['attributes']>;
675
677
  endpoint: MatterbridgeEndpoint;
676
678
  };
679
+ 'DishwasherAlarm.reset': {
680
+ command: 'reset';
681
+ request: DishwasherAlarm.ResetRequest;
682
+ cluster: 'dishwasherAlarm';
683
+ attributes: ClusterAttributeValues<(typeof DishwasherAlarm)['attributes']>;
684
+ endpoint: MatterbridgeEndpoint;
685
+ };
686
+ 'DishwasherAlarm.modifyEnabledAlarms': {
687
+ command: 'modifyEnabledAlarms';
688
+ request: DishwasherAlarm.ModifyEnabledAlarmsRequest;
689
+ cluster: 'dishwasherAlarm';
690
+ attributes: ClusterAttributeValues<(typeof DishwasherAlarm)['attributes']>;
691
+ endpoint: MatterbridgeEndpoint;
692
+ };
693
+ 'TemperatureAlarm.reset': {
694
+ command: 'reset';
695
+ request: TemperatureAlarm.ResetRequest;
696
+ cluster: 'temperatureAlarm';
697
+ attributes: ClusterAttributeValues<(typeof TemperatureAlarm)['attributes']>;
698
+ endpoint: MatterbridgeEndpoint;
699
+ };
700
+ 'TemperatureAlarm.modifyEnabledAlarms': {
701
+ command: 'modifyEnabledAlarms';
702
+ request: TemperatureAlarm.ModifyEnabledAlarmsRequest;
703
+ cluster: 'temperatureAlarm';
704
+ attributes: ClusterAttributeValues<(typeof TemperatureAlarm)['attributes']>;
705
+ endpoint: MatterbridgeEndpoint;
706
+ };
677
707
  'resetCounts': CommandHandlerData<'ThreadNetworkDiagnostics.resetCounts'>;
678
708
  'ThreadNetworkDiagnostics.resetCounts': {
679
709
  command: 'resetCounts';
@@ -41,7 +41,7 @@ export declare function getBehaviourTypesFromClusterClientIds(clusterClientList:
41
41
  export declare function getBehaviourTypeFromClusterServerId(clusterId: ClusterId): Behavior.Type | undefined;
42
42
  export declare function getBehaviourTypeFromClusterClientId(clusterId: ClusterId): ClusterBehavior.Type | undefined;
43
43
  export declare function getBehavior(endpoint: MatterbridgeEndpoint, cluster: Behavior.Type | ClusterType | ClusterId | string): Behavior.Type | undefined;
44
- export declare function invokeBehaviorCommand(endpoint: MatterbridgeEndpoint, cluster: Behavior.Type | ClusterType | ClusterId | string, command: CommandHandlers, params?: Record<string, boolean | number | bigint | string | object | null>): Promise<boolean>;
44
+ export declare function invokeBehaviorCommand(endpoint: MatterbridgeEndpoint, cluster: Behavior.Type | ClusterType | ClusterId | string, command: CommandHandlers, params?: Record<string, boolean | number | bigint | string | object | null>, waiterCondition?: () => boolean): Promise<boolean>;
45
45
  export declare function invokeSubscribeHandler(endpoint: MatterbridgeEndpoint, cluster: Behavior.Type | ClusterType | ClusterId | string, attribute: string, newValue: unknown, oldValue: unknown): Promise<boolean>;
46
46
  export declare function addRequiredClusterServers(endpoint: MatterbridgeEndpoint): void;
47
47
  export declare function addOptionalClusterServers(endpoint: MatterbridgeEndpoint): void;
@@ -99,6 +99,7 @@ import { ScenesManagement } from '@matter/types/clusters/scenes-management';
99
99
  import { SmokeCoAlarm } from '@matter/types/clusters/smoke-co-alarm';
100
100
  import { SoilMeasurement } from '@matter/types/clusters/soil-measurement';
101
101
  import { Switch } from '@matter/types/clusters/switch';
102
+ import { TemperatureAlarm } from '@matter/types/clusters/temperature-alarm';
102
103
  import { TemperatureMeasurement } from '@matter/types/clusters/temperature-measurement';
103
104
  import { Thermostat } from '@matter/types/clusters/thermostat';
104
105
  import { ThermostatUserInterfaceConfiguration } from '@matter/types/clusters/thermostat-user-interface-configuration';
@@ -112,6 +113,7 @@ import { MeasurementType } from '@matter/types/globals';
112
113
  import { deepEqual } from '@matterbridge/utils/deep-equal';
113
114
  import { logModuleLoaded } from '@matterbridge/utils/loader';
114
115
  import { isValidArray } from '@matterbridge/utils/validate';
116
+ import { waiter } from '@matterbridge/utils/wait';
115
117
  import { BLUE, CYAN, db, debugStringify, er, hk, nf, or, wr, YELLOW, zb } from 'node-ansi-logger';
116
118
  import { MatterbridgeBindingServer } from './behaviors/bindingServer.js';
117
119
  import { MatterbridgeBooleanStateConfigurationServer } from './behaviors/booleanStateConfigurationServer.js';
@@ -129,6 +131,7 @@ import { MatterbridgeOperationalStateServer } from './behaviors/operationalState
129
131
  import { MatterbridgePowerSourceServer } from './behaviors/powerSourceServer.js';
130
132
  import { MatterbridgePumpConfigurationAndControlServer } from './behaviors/pumpConfigurationAndControlServer.js';
131
133
  import { MatterbridgeSmokeCoAlarmServer } from './behaviors/smokeCoAlarmServer.js';
134
+ import { MatterbridgeTemperatureAlarmServer } from './behaviors/temperatureAlarmServer.js';
132
135
  import { MatterbridgeThermostatServer } from './behaviors/thermostatServer.js';
133
136
  import { MatterbridgeValveConfigurationAndControlServer } from './behaviors/valveConfigurationAndControlServer.js';
134
137
  import { MatterbridgeWindowCoveringServer } from './behaviors/windowCoveringServer.js';
@@ -307,6 +310,8 @@ export function getBehaviourTypeFromClusterServerId(clusterId) {
307
310
  return BooleanStateServer.enable({ events: { stateChange: true } });
308
311
  if (clusterId === BooleanStateConfiguration.id)
309
312
  return MatterbridgeBooleanStateConfigurationServer;
313
+ if (clusterId === TemperatureAlarm.id)
314
+ return MatterbridgeTemperatureAlarmServer;
310
315
  if (clusterId === PowerTopology.id)
311
316
  return PowerTopologyServer.with('TreeTopology');
312
317
  if (clusterId === ElectricalPowerMeasurement.id)
@@ -426,7 +431,7 @@ export function getBehavior(endpoint, cluster) {
426
431
  }
427
432
  return behavior;
428
433
  }
429
- export async function invokeBehaviorCommand(endpoint, cluster, command, params) {
434
+ export async function invokeBehaviorCommand(endpoint, cluster, command, params, waiterCondition) {
430
435
  const behaviorId = getBehavior(endpoint, cluster)?.id;
431
436
  if (!behaviorId) {
432
437
  endpoint.log?.error(`invokeBehaviorCommand error: command ${hk}${command}${er} not found on endpoint ${or}${endpoint.maybeId}${er}:${or}${endpoint.maybeNumber}${er}`);
@@ -459,6 +464,8 @@ export async function invokeBehaviorCommand(endpoint, cluster, command, params)
459
464
  delete behavior.context;
460
465
  }
461
466
  });
467
+ if (invoked && waiterCondition)
468
+ return await waiter(`invokeBehaviorCommand ${command}`, waiterCondition, false, 1000, 50);
462
469
  return invoked;
463
470
  }
464
471
  export async function invokeSubscribeHandler(endpoint, cluster, attribute, newValue, oldValue) {
@@ -547,6 +554,8 @@ export function addClusterServers(endpoint, serverList) {
547
554
  endpoint.createDefaultBooleanStateClusterServer();
548
555
  if (serverList.includes(BooleanStateConfiguration.id))
549
556
  endpoint.createDefaultBooleanStateConfigurationClusterServer();
557
+ if (serverList.includes(TemperatureAlarm.id))
558
+ endpoint.createDefaultTemperatureAlarmClusterServer();
550
559
  if (serverList.includes(PowerTopology.id))
551
560
  endpoint.createDefaultPowerTopologyClusterServer();
552
561
  if (serverList.includes(ElectricalPowerMeasurement.id))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matterbridge/core",
3
- "version": "3.10.8-dev-20260903-4ab4a0f",
3
+ "version": "3.10.8-dev-20260903-014e30e",
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-20260903-4ab4a0f",
136
- "@matterbridge/thread": "3.10.8-dev-20260903-4ab4a0f",
137
- "@matterbridge/types": "3.10.8-dev-20260903-4ab4a0f",
138
- "@matterbridge/utils": "3.10.8-dev-20260903-4ab4a0f",
135
+ "@matterbridge/dgram": "3.10.8-dev-20260903-014e30e",
136
+ "@matterbridge/thread": "3.10.8-dev-20260903-014e30e",
137
+ "@matterbridge/types": "3.10.8-dev-20260903-014e30e",
138
+ "@matterbridge/utils": "3.10.8-dev-20260903-014e30e",
139
139
  "escape-html": "1.0.3",
140
140
  "express": "5.2.1",
141
141
  "express-rate-limit": "8.7.0",