matterbridge 3.0.6-dev-20250611-6f49811 → 3.0.6-dev-20250612-a8a696e

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/README.md CHANGED
@@ -324,6 +324,8 @@ It exposes 38 devices:
324
324
  - a microwave Oven device (supported by SmartThings, Alexa and Home Assistant)
325
325
  - an extractor Hood device (supported by SmartThings, Alexa and Home Assistant)
326
326
  - a cooktop device (supported by SmartThings, Alexa and Home Assistant)
327
+ - a water heater device (supported by SmartThings and Home Assistant)
328
+ - a car charger device (supported by Home Assistant)
327
329
 
328
330
  All these virtual devices continuously change state and position. The plugin also shows how to use all the command handlers (you can control all the devices).
329
331
 
package/dist/evse.js CHANGED
@@ -15,7 +15,7 @@ export class Evse extends MatterbridgeEndpoint {
15
15
  .createDefaultPowerTopologyClusterServer()
16
16
  .createDefaultElectricalPowerMeasurementClusterServer()
17
17
  .createDefaultElectricalEnergyMeasurementClusterServer()
18
- .createDefaultDeviceEnergyManagementCluster(DeviceEnergyManagement.EsaType.Evse, false, DeviceEnergyManagement.EsaState.Online, absMinPower, absMaxPower)
18
+ .createDefaultDeviceEnergyManagementClusterServer(DeviceEnergyManagement.EsaType.Evse, false, DeviceEnergyManagement.EsaState.Online, absMinPower, absMaxPower)
19
19
  .createDefaultEnergyEvseClusterServer(state, supplyState, faultState)
20
20
  .createDefaultEnergyEvseModeClusterServer(currentMode, supportedModes)
21
21
  .addRequiredClusterServers();
@@ -49,39 +49,42 @@ export class Evse extends MatterbridgeEndpoint {
49
49
  }
50
50
  export class MatterbridgeEnergyEvseServer extends EnergyEvseServer {
51
51
  disable() {
52
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
53
- device.disable();
54
- device.log.info(`MatterbridgeEnergyEvseServer disable called`);
52
+ const device = this.endpoint.stateOf(MatterbridgeServer);
53
+ device.log.info(`Disable charging (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
54
+ device.commandHandler.executeHandler('disable', { request: {}, cluster: EnergyEvseServer.id, attributes: this.state, endpoint: this.endpoint });
55
+ device.log.debug(`MatterbridgeEnergyEvseServer disable called`);
55
56
  this.state.supplyState = EnergyEvse.SupplyState.Disabled;
56
57
  if (this.state.state === EnergyEvse.State.PluggedInCharging) {
57
58
  this.state.state = EnergyEvse.State.PluggedInDemand;
58
59
  }
59
60
  this.state.chargingEnabledUntil = 0;
60
61
  }
61
- enableCharging({ chargingEnabledUntil, minimumChargeCurrent, maximumChargeCurrent }) {
62
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
63
- device.enableCharging();
64
- device.log.info(`MatterbridgeEnergyEvseServer enableCharging called`);
62
+ enableCharging(request) {
63
+ const device = this.endpoint.stateOf(MatterbridgeServer);
64
+ device.log.info(`EnableCharging (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
65
+ device.commandHandler.executeHandler('enableCharging', { request, cluster: EnergyEvseServer.id, attributes: this.state, endpoint: this.endpoint });
66
+ device.log.debug(`MatterbridgeEnergyEvseServer enableCharging called`);
65
67
  this.state.supplyState = EnergyEvse.SupplyState.ChargingEnabled;
66
68
  if (this.state.state === EnergyEvse.State.PluggedInDemand) {
67
69
  this.state.state = EnergyEvse.State.PluggedInCharging;
68
70
  }
69
- this.state.chargingEnabledUntil = chargingEnabledUntil;
70
- this.state.minimumChargeCurrent = minimumChargeCurrent;
71
- this.state.maximumChargeCurrent = maximumChargeCurrent;
71
+ this.state.chargingEnabledUntil = request.chargingEnabledUntil;
72
+ this.state.minimumChargeCurrent = request.minimumChargeCurrent;
73
+ this.state.maximumChargeCurrent = request.maximumChargeCurrent;
72
74
  }
73
75
  }
74
76
  export class MatterbridgeEnergyEvseModeServer extends EnergyEvseModeServer {
75
- changeToMode({ newMode }) {
76
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
77
- const supported = this.state.supportedModes.find((mode) => mode.mode === newMode);
77
+ changeToMode(request) {
78
+ const device = this.endpoint.stateOf(MatterbridgeServer);
79
+ device.log.info(`Changing mode to ${request.newMode} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
80
+ device.commandHandler.executeHandler('changeToMode', { request, cluster: EnergyEvseModeServer.id, attributes: this.state, endpoint: this.endpoint });
81
+ const supported = this.state.supportedModes.find((mode) => mode.mode === request.newMode);
78
82
  if (!supported) {
79
- device.log.error(`MatterbridgeEnergyEvseModeServer changeToMode called with unsupported newMode: ${newMode}`);
83
+ device.log.error(`MatterbridgeEnergyEvseModeServer changeToMode called with unsupported newMode: ${request.newMode}`);
80
84
  return { status: ModeBase.ModeChangeStatus.UnsupportedMode, statusText: 'Unsupported mode' };
81
85
  }
82
- device.changeToMode({ newMode });
83
- this.state.currentMode = newMode;
84
- device.log.info(`MatterbridgeEnergyEvseModeServer changeToMode called with newMode ${newMode} => ${supported.label}`);
86
+ this.state.currentMode = request.newMode;
87
+ device.log.debug(`MatterbridgeEnergyEvseModeServer changeToMode called with newMode ${request.newMode} => ${supported.label}`);
85
88
  return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Success' };
86
89
  }
87
90
  }
@@ -64,14 +64,16 @@ export class LaundryWasher extends MatterbridgeEndpoint {
64
64
  export class MatterbridgeLevelTemperatureControlServer extends TemperatureControlServer.with(TemperatureControl.Feature.TemperatureLevel) {
65
65
  initialize() {
66
66
  if (this.state.supportedTemperatureLevels.length >= 2) {
67
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
67
+ const device = this.endpoint.stateOf(MatterbridgeServer);
68
68
  device.log.info(`MatterbridgeLevelTemperatureControlServer initialized with selectedTemperatureLevel ${this.state.selectedTemperatureLevel} and supportedTemperatureLevels: ${this.state.supportedTemperatureLevels.join(', ')}`);
69
69
  }
70
70
  }
71
71
  setTemperature(request) {
72
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
72
+ const device = this.endpoint.stateOf(MatterbridgeServer);
73
+ device.log.info(`SetTemperature (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
74
+ device.commandHandler.executeHandler('setTemperature', { request, cluster: TemperatureControlServer.id, attributes: this.state, endpoint: this.endpoint });
73
75
  if (request.targetTemperatureLevel !== undefined && request.targetTemperatureLevel >= 0 && request.targetTemperatureLevel < this.state.supportedTemperatureLevels.length) {
74
- device.log.info(`MatterbridgeLevelTemperatureControlServer: setTemperature called setting selectedTemperatureLevel to ${request.targetTemperatureLevel}: ${this.state.supportedTemperatureLevels[request.targetTemperatureLevel]}`);
76
+ device.log.debug(`MatterbridgeLevelTemperatureControlServer: setTemperature called setting selectedTemperatureLevel to ${request.targetTemperatureLevel}: ${this.state.supportedTemperatureLevels[request.targetTemperatureLevel]}`);
75
77
  this.state.selectedTemperatureLevel = request.targetTemperatureLevel;
76
78
  }
77
79
  else {
@@ -81,13 +83,15 @@ export class MatterbridgeLevelTemperatureControlServer extends TemperatureContro
81
83
  }
82
84
  export class MatterbridgeNumberTemperatureControlServer extends TemperatureControlServer.with(TemperatureControl.Feature.TemperatureNumber, TemperatureControl.Feature.TemperatureStep) {
83
85
  initialize() {
84
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
86
+ const device = this.endpoint.stateOf(MatterbridgeServer);
85
87
  device.log.info(`MatterbridgeNumberTemperatureControlServer initialized with temperatureSetpoint ${this.state.temperatureSetpoint} minTemperature ${this.state.minTemperature} maxTemperature ${this.state.maxTemperature} step ${this.state.step}`);
86
88
  }
87
89
  setTemperature(request) {
88
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
90
+ const device = this.endpoint.stateOf(MatterbridgeServer);
91
+ device.log.info(`SetTemperature (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
92
+ device.commandHandler.executeHandler('setTemperature', { request, cluster: TemperatureControlServer.id, attributes: this.state, endpoint: this.endpoint });
89
93
  if (request.targetTemperature !== undefined && request.targetTemperature >= this.state.minTemperature && request.targetTemperature <= this.state.maxTemperature) {
90
- device.log.info(`MatterbridgeNumberTemperatureControlServer: setTemperature called setting temperatureSetpoint to ${request.targetTemperature}`);
94
+ device.log.debug(`MatterbridgeNumberTemperatureControlServer: setTemperature called setting temperatureSetpoint to ${request.targetTemperature}`);
91
95
  this.state.temperatureSetpoint = request.targetTemperature;
92
96
  }
93
97
  else {
@@ -97,23 +101,25 @@ export class MatterbridgeNumberTemperatureControlServer extends TemperatureContr
97
101
  }
98
102
  export class MatterbridgeLaundryWasherModeServer extends LaundryWasherModeServer {
99
103
  initialize() {
100
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
104
+ const device = this.endpoint.stateOf(MatterbridgeServer);
101
105
  device.log.info(`MatterbridgeLaundryWasherModeServer initialized: currentMode is ${this.state.currentMode}`);
102
106
  this.reactTo(this.agent.get(MatterbridgeOnOffServer).events.onOff$Changed, this.handleOnOffChange);
103
107
  }
104
108
  handleOnOffChange(onOff) {
105
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
109
+ const device = this.endpoint.stateOf(MatterbridgeServer);
110
+ device.log.info(`HandleOnOffChange (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
106
111
  if (onOff === false) {
107
112
  device.log.notice('OnOffServer changed to OFF: setting Dead Front state to Manufacturer Specific');
108
113
  this.state.currentMode = 2;
109
114
  }
110
115
  }
111
116
  changeToMode(request) {
112
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
117
+ const device = this.endpoint.stateOf(MatterbridgeServer);
118
+ device.log.info(`ChangeToMode (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
119
+ device.commandHandler.executeHandler('changeToMode', { request, cluster: LaundryWasherModeServer.id, attributes: this.state, endpoint: this.endpoint });
113
120
  const supportedMode = this.state.supportedModes.find((supportedMode) => supportedMode.mode === request.newMode);
114
121
  if (supportedMode) {
115
- device.log.info(`MatterbridgeLaundryWasherModeServer: changeToMode called with mode ${supportedMode.mode} => ${supportedMode.label}`);
116
- device.changeToMode({ newMode: request.newMode });
122
+ device.log.debug(`MatterbridgeLaundryWasherModeServer: changeToMode called with mode ${supportedMode.mode} => ${supportedMode.label}`);
117
123
  this.state.currentMode = request.newMode;
118
124
  return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Success' };
119
125
  }
@@ -25,423 +25,288 @@ import { SwitchServer } from '@matter/main/behaviors/switch';
25
25
  import { OperationalStateServer } from '@matter/main/behaviors/operational-state';
26
26
  import { ServiceAreaServer } from '@matter/main/behaviors/service-area';
27
27
  import { DeviceEnergyManagementModeServer } from '@matter/main/behaviors/device-energy-management-mode';
28
- export class MatterbridgeServerDevice {
29
- log;
30
- commandHandler;
31
- device;
32
- endpointId = undefined;
33
- endpointNumber = undefined;
34
- constructor(log, commandHandler, device) {
35
- this.log = log;
36
- this.commandHandler = commandHandler;
37
- this.device = device;
38
- }
39
- setEndpointId(endpointId) {
40
- this.endpointId = endpointId;
41
- }
42
- setEndpointNumber(endpointNumber) {
43
- this.endpointNumber = endpointNumber;
44
- }
45
- identify({ identifyTime }) {
46
- this.log.info(`Identifying device for ${identifyTime} seconds`);
47
- this.commandHandler.executeHandler('identify', { request: { identifyTime }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
48
- }
49
- triggerEffect({ effectIdentifier, effectVariant }) {
50
- this.log.info(`Triggering effect ${effectIdentifier} variant ${effectVariant}`);
51
- this.commandHandler.executeHandler('triggerEffect', { request: { effectIdentifier, effectVariant }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
52
- }
53
- on() {
54
- this.log.info(`Switching device on (endpoint ${this.endpointId}.${this.endpointNumber})`);
55
- this.commandHandler.executeHandler('on', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
56
- }
57
- off() {
58
- this.log.info(`Switching device off (endpoint ${this.endpointId}.${this.endpointNumber})`);
59
- this.commandHandler.executeHandler('off', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
60
- }
61
- toggle() {
62
- this.log.info(`Toggle device on/off (endpoint ${this.endpointId}.${this.endpointNumber})`);
63
- this.commandHandler.executeHandler('toggle', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
64
- }
65
- moveToLevel({ level, transitionTime, optionsMask, optionsOverride }) {
66
- this.log.info(`Setting level to ${level} with transitionTime ${transitionTime} (endpoint ${this.endpointId}.${this.endpointNumber})`);
67
- this.commandHandler.executeHandler('moveToLevel', { request: { level, transitionTime, optionsMask, optionsOverride }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
68
- }
69
- moveToLevelWithOnOff({ level, transitionTime, optionsMask, optionsOverride }) {
70
- this.log.info(`Setting level to ${level} with transitionTime ${transitionTime} (endpoint ${this.endpointId}.${this.endpointNumber})`);
71
- this.commandHandler.executeHandler('moveToLevelWithOnOff', { request: { level, transitionTime, optionsMask, optionsOverride }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
72
- }
73
- moveToHue({ optionsMask, optionsOverride, hue, direction, transitionTime }) {
74
- this.log.info(`Setting hue to ${hue} with transitionTime ${transitionTime} (endpoint ${this.endpointId}.${this.endpointNumber})`);
75
- this.commandHandler.executeHandler('moveToHue', { request: { optionsMask, optionsOverride, hue, direction, transitionTime }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
76
- }
77
- moveToSaturation({ optionsMask, optionsOverride, saturation, transitionTime }) {
78
- this.log.info(`Setting saturation to ${saturation} with transitionTime ${transitionTime} (endpoint ${this.endpointId}.${this.endpointNumber})`);
79
- this.commandHandler.executeHandler('moveToSaturation', { request: { optionsMask, optionsOverride, saturation, transitionTime }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
80
- }
81
- moveToHueAndSaturation({ optionsOverride, optionsMask, saturation, hue, transitionTime }) {
82
- this.log.info(`Setting hue to ${hue} and saturation to ${saturation} with transitionTime ${transitionTime} (endpoint ${this.endpointId}.${this.endpointNumber})`);
83
- this.commandHandler.executeHandler('moveToHueAndSaturation', { request: { optionsOverride, optionsMask, saturation, hue, transitionTime }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
84
- }
85
- moveToColor({ optionsMask, optionsOverride, colorX, colorY, transitionTime }) {
86
- this.log.info(`Setting color to ${colorX}, ${colorY} with transitionTime ${transitionTime} (endpoint ${this.endpointId}.${this.endpointNumber})`);
87
- this.commandHandler.executeHandler('moveToColor', { request: { optionsMask, optionsOverride, colorX, colorY, transitionTime }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
88
- }
89
- moveToColorTemperature({ optionsOverride, optionsMask, colorTemperatureMireds, transitionTime }) {
90
- this.log.info(`Setting color temperature to ${colorTemperatureMireds} with transitionTime ${transitionTime} (endpoint ${this.endpointId}.${this.endpointNumber})`);
91
- this.commandHandler.executeHandler('moveToColorTemperature', {
92
- request: { optionsOverride, optionsMask, colorTemperatureMireds, transitionTime },
93
- attributes: {},
94
- endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId },
95
- });
96
- }
97
- upOrOpen() {
98
- this.log.info(`Opening cover (endpoint ${this.endpointId}.${this.endpointNumber})`);
99
- this.commandHandler.executeHandler(`upOrOpen`, { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
100
- }
101
- downOrClose() {
102
- this.log.info(`Closing cover (endpoint ${this.endpointId}.${this.endpointNumber})`);
103
- this.commandHandler.executeHandler(`downOrClose`, { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
104
- }
105
- stopMotion() {
106
- this.log.info(`Stopping cover (endpoint ${this.endpointId}.${this.endpointNumber})`);
107
- this.commandHandler.executeHandler('stopMotion', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
108
- }
109
- goToLiftPercentage({ liftPercent100thsValue }) {
110
- this.log.info(`Setting cover lift percentage to ${liftPercent100thsValue} (endpoint ${this.endpointId}.${this.endpointNumber})`);
111
- this.commandHandler.executeHandler('goToLiftPercentage', { request: { liftPercent100thsValue }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
112
- }
113
- goToTiltPercentage({ tiltPercent100thsValue }) {
114
- this.log.info(`Setting cover tilt percentage to ${tiltPercent100thsValue} (endpoint ${this.endpointId}.${this.endpointNumber})`);
115
- this.commandHandler.executeHandler('goToTiltPercentage', { request: { tiltPercent100thsValue }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
116
- }
117
- lockDoor() {
118
- this.log.info(`Locking door (endpoint ${this.endpointId}.${this.endpointNumber})`);
119
- this.commandHandler.executeHandler('lockDoor', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
120
- }
121
- unlockDoor() {
122
- this.log.info(`Unlocking door (endpoint ${this.endpointId}.${this.endpointNumber})`);
123
- this.commandHandler.executeHandler('unlockDoor', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
124
- }
125
- step({ direction, wrap, lowestOff }) {
126
- this.log.info(`Stepping fan with direction ${direction} (endpoint ${this.endpointId}.${this.endpointNumber})`);
127
- this.commandHandler.executeHandler('step', { request: { direction, wrap, lowestOff }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
128
- }
129
- setpointRaiseLower({ mode, amount }) {
130
- this.log.info(`Setting setpoint by ${amount} in mode ${mode} (endpoint ${this.endpointId}.${this.endpointNumber})`);
131
- this.commandHandler.executeHandler('setpointRaiseLower', { request: { mode, amount }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
132
- }
133
- open({ openDuration, targetLevel }) {
134
- this.log.info(`Opening valve to ${targetLevel}% (endpoint ${this.endpointId}.${this.endpointNumber})`);
135
- this.commandHandler.executeHandler('open', { request: { openDuration, targetLevel }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
136
- }
137
- close() {
138
- this.log.info(`Closing valve (endpoint ${this.endpointId}.${this.endpointNumber})`);
139
- this.commandHandler.executeHandler('close', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
140
- }
141
- changeToMode({ newMode }) {
142
- this.log.info(`Changing mode to ${newMode} (endpoint ${this.endpointId}.${this.endpointNumber})`);
143
- this.commandHandler.executeHandler('changeToMode', { request: { newMode }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
144
- }
145
- selfTestRequest() {
146
- this.log.info(`Testing SmokeCOAlarm (endpoint ${this.endpointId}.${this.endpointNumber})`);
147
- this.commandHandler.executeHandler('selfTestRequest', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
148
- }
149
- enableDisableAlarm({ alarmsToEnableDisable }) {
150
- this.log.info(`Enabling/disabling alarm ${alarmsToEnableDisable} (endpoint ${this.endpointId}.${this.endpointNumber})`);
151
- this.commandHandler.executeHandler('enableDisableAlarm', { request: { alarmsToEnableDisable }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
152
- }
153
- pause() {
154
- this.log.info(`Pause (endpoint ${this.endpointId}.${this.endpointNumber})`);
155
- this.commandHandler.executeHandler('pause', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
156
- }
157
- stop() {
158
- this.log.info(`Stop (endpoint ${this.endpointId}.${this.endpointNumber})`);
159
- this.commandHandler.executeHandler('stop', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
160
- }
161
- start() {
162
- this.log.info(`Start (endpoint ${this.endpointId}.${this.endpointNumber})`);
163
- this.commandHandler.executeHandler('start', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
164
- }
165
- resume() {
166
- this.log.info(`Resume (endpoint ${this.endpointId}.${this.endpointNumber})`);
167
- this.commandHandler.executeHandler('resume', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
168
- }
169
- goHome() {
170
- this.log.info(`GoHome (endpoint ${this.endpointId}.${this.endpointNumber})`);
171
- this.commandHandler.executeHandler('goHome', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
172
- }
173
- selectAreas({ newAreas }) {
174
- this.log.info(`Selecting areas ${newAreas} (endpoint ${this.endpointId}.${this.endpointNumber})`);
175
- this.commandHandler.executeHandler('selectAreas', { request: { newAreas }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
176
- }
177
- boost({ boostInfo }) {
178
- this.log.info(`Boost (endpoint ${this.endpointId}.${this.endpointNumber})`);
179
- this.commandHandler.executeHandler('boost', { request: { boostInfo }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
180
- }
181
- cancelBoost() {
182
- this.log.info(`Cancel boost (endpoint ${this.endpointId}.${this.endpointNumber})`);
183
- this.commandHandler.executeHandler('cancelBoost', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
184
- }
185
- enableCharging() {
186
- this.log.info(`EnableCharging (endpoint ${this.endpointId}.${this.endpointNumber})`);
187
- this.commandHandler.executeHandler('enableCharging', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
188
- }
189
- disable() {
190
- this.log.info(`Disable charging (endpoint ${this.endpointId}.${this.endpointNumber})`);
191
- this.commandHandler.executeHandler('disable', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
192
- }
193
- }
194
28
  export class MatterbridgeServer extends Behavior {
195
29
  static id = 'matterbridge';
196
30
  initialize() {
197
- const device = this.state.deviceCommand;
198
- device?.setEndpointId(this.endpoint.maybeId);
199
- device?.setEndpointNumber(this.endpoint.maybeNumber);
31
+ this.state.log.debug(`MatterbridgeServer initialized (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
200
32
  super.initialize();
201
33
  }
202
34
  }
203
35
  (function (MatterbridgeServer) {
204
36
  class State {
205
- deviceCommand;
37
+ log;
38
+ commandHandler;
206
39
  }
207
40
  MatterbridgeServer.State = State;
208
41
  })(MatterbridgeServer || (MatterbridgeServer = {}));
209
42
  export class MatterbridgeIdentifyServer extends IdentifyServer {
210
- identify({ identifyTime }) {
211
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
212
- device.identify({ identifyTime });
43
+ identify(request) {
44
+ const device = this.endpoint.stateOf(MatterbridgeServer);
45
+ device.log.info(`Identifying device for ${request.identifyTime} seconds (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
46
+ device.commandHandler.executeHandler('identify', { request, cluster: IdentifyServer.id, attributes: this.state, endpoint: this.endpoint });
213
47
  device.log.debug(`MatterbridgeIdentifyServer: identify called`);
214
- super.identify({ identifyTime });
48
+ super.identify(request);
215
49
  }
216
- triggerEffect({ effectIdentifier, effectVariant }) {
217
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
218
- device.triggerEffect({ effectIdentifier, effectVariant });
50
+ triggerEffect(request) {
51
+ const device = this.endpoint.stateOf(MatterbridgeServer);
52
+ device.log.info(`Triggering effect ${request.effectIdentifier} variant ${request.effectVariant} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
53
+ device.commandHandler.executeHandler('triggerEffect', { request, cluster: IdentifyServer.id, attributes: this.state, endpoint: this.endpoint });
219
54
  device.log.debug(`MatterbridgeIdentifyServer: triggerEffect called`);
220
- super.triggerEffect({ effectIdentifier, effectVariant });
55
+ super.triggerEffect(request);
221
56
  }
222
57
  }
223
58
  export class MatterbridgeOnOffServer extends OnOffServer {
224
59
  on() {
225
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
226
- device.on();
60
+ const device = this.endpoint.stateOf(MatterbridgeServer);
61
+ device.log.info(`Switching device on (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
62
+ device.commandHandler.executeHandler('on', { request: {}, cluster: OnOffServer.id, attributes: this.state, endpoint: this.endpoint });
227
63
  device.log.debug(`MatterbridgeOnOffServer: on called`);
228
64
  super.on();
229
65
  }
230
66
  off() {
231
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
232
- device.off();
67
+ const device = this.endpoint.stateOf(MatterbridgeServer);
68
+ device.log.info(`Switching device off (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
69
+ device.commandHandler.executeHandler('off', { request: {}, cluster: OnOffServer.id, attributes: this.state, endpoint: this.endpoint });
233
70
  device.log.debug(`MatterbridgeOnOffServer: off called`);
234
71
  super.off();
235
72
  }
236
73
  toggle() {
237
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
238
- device.toggle();
74
+ const device = this.endpoint.stateOf(MatterbridgeServer);
75
+ device.log.info(`Toggle device on/off (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
76
+ device.commandHandler.executeHandler('toggle', { request: {}, cluster: OnOffServer.id, attributes: this.state, endpoint: this.endpoint });
239
77
  device.log.debug(`MatterbridgeOnOffServer: toggle called`);
240
78
  super.toggle();
241
79
  }
242
80
  }
243
81
  export class MatterbridgeLevelControlServer extends LevelControlServer {
244
- moveToLevel({ level, transitionTime, optionsMask, optionsOverride }) {
245
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
246
- device.moveToLevel({ level, transitionTime, optionsMask, optionsOverride });
82
+ moveToLevel(request) {
83
+ const device = this.endpoint.stateOf(MatterbridgeServer);
84
+ device.log.info(`Setting level to ${request.level} with transitionTime ${request.transitionTime} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
85
+ device.commandHandler.executeHandler('moveToLevel', { request, cluster: LevelControlServer.id, attributes: this.state, endpoint: this.endpoint });
247
86
  device.log.debug(`MatterbridgeLevelControlServer: moveToLevel called`);
248
- super.moveToLevel({ level, transitionTime, optionsMask, optionsOverride });
87
+ super.moveToLevel(request);
249
88
  }
250
- moveToLevelWithOnOff({ level, transitionTime, optionsMask, optionsOverride }) {
251
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
252
- device.moveToLevelWithOnOff({ level, transitionTime, optionsMask, optionsOverride });
89
+ moveToLevelWithOnOff(request) {
90
+ const device = this.endpoint.stateOf(MatterbridgeServer);
91
+ device.log.info(`Setting level to ${request.level} with transitionTime ${request.transitionTime} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
92
+ device.commandHandler.executeHandler('moveToLevelWithOnOff', { request, cluster: LevelControlServer.id, attributes: this.state, endpoint: this.endpoint });
253
93
  device.log.debug(`MatterbridgeLevelControlServer: moveToLevelWithOnOff called`);
254
- super.moveToLevelWithOnOff({ level, transitionTime, optionsMask, optionsOverride });
94
+ super.moveToLevelWithOnOff(request);
255
95
  }
256
96
  }
257
97
  export class MatterbridgeColorControlServer extends ColorControlServer.with(ColorControl.Feature.HueSaturation, ColorControl.Feature.Xy, ColorControl.Feature.ColorTemperature) {
258
- moveToHue({ optionsMask, optionsOverride, hue, direction, transitionTime }) {
259
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
260
- device.moveToHue({ optionsMask, optionsOverride, hue, direction, transitionTime });
98
+ moveToHue(request) {
99
+ const device = this.endpoint.stateOf(MatterbridgeServer);
100
+ device.log.info(`Setting hue to ${request.hue} with transitionTime ${request.transitionTime} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
101
+ device.commandHandler.executeHandler('moveToHue', { request, cluster: ColorControlServer.id, attributes: this.state, endpoint: this.endpoint });
261
102
  device.log.debug(`MatterbridgeColorControlServer: moveToHue called`);
262
- super.moveToHue({ optionsMask, optionsOverride, hue, direction, transitionTime });
103
+ super.moveToHue(request);
263
104
  }
264
- moveToSaturation({ optionsMask, optionsOverride, saturation, transitionTime }) {
265
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
266
- device.moveToSaturation({ optionsMask, optionsOverride, saturation, transitionTime });
105
+ moveToSaturation(request) {
106
+ const device = this.endpoint.stateOf(MatterbridgeServer);
107
+ device.log.info(`Setting saturation to ${request.saturation} with transitionTime ${request.transitionTime} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
108
+ device.commandHandler.executeHandler('moveToSaturation', { request, cluster: ColorControlServer.id, attributes: this.state, endpoint: this.endpoint });
267
109
  device.log.debug(`MatterbridgeColorControlServer: moveToSaturation called`);
268
- super.moveToSaturation({ optionsMask, optionsOverride, saturation, transitionTime });
110
+ super.moveToSaturation(request);
269
111
  }
270
- moveToHueAndSaturation({ optionsOverride, optionsMask, saturation, hue, transitionTime }) {
271
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
272
- device.moveToHueAndSaturation({ optionsOverride, optionsMask, saturation, hue, transitionTime });
112
+ moveToHueAndSaturation(request) {
113
+ const device = this.endpoint.stateOf(MatterbridgeServer);
114
+ device.log.info(`Setting hue to ${request.hue} and saturation to ${request.saturation} with transitionTime ${request.transitionTime} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
115
+ device.commandHandler.executeHandler('moveToHueAndSaturation', { request, cluster: ColorControlServer.id, attributes: this.state, endpoint: this.endpoint });
273
116
  device.log.debug(`MatterbridgeColorControlServer: moveToHueAndSaturation called`);
274
- super.moveToHueAndSaturation({ optionsOverride, optionsMask, saturation, hue, transitionTime });
117
+ super.moveToHueAndSaturation(request);
275
118
  }
276
- moveToColor({ optionsMask, optionsOverride, colorX, colorY, transitionTime }) {
277
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
278
- device.moveToColor({ optionsMask, optionsOverride, colorX, colorY, transitionTime });
119
+ moveToColor(request) {
120
+ const device = this.endpoint.stateOf(MatterbridgeServer);
121
+ device.log.info(`Setting color to ${request.colorX}, ${request.colorY} with transitionTime ${request.transitionTime} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
122
+ device.commandHandler.executeHandler('moveToColor', { request, cluster: ColorControlServer.id, attributes: this.state, endpoint: this.endpoint });
279
123
  device.log.debug(`MatterbridgeColorControlServer: moveToColor called`);
280
- super.moveToColor({ optionsMask, optionsOverride, colorX, colorY, transitionTime });
124
+ super.moveToColor(request);
281
125
  }
282
- moveToColorTemperature({ optionsOverride, optionsMask, colorTemperatureMireds, transitionTime }) {
283
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
284
- device.moveToColorTemperature({ optionsOverride, optionsMask, colorTemperatureMireds, transitionTime });
126
+ moveToColorTemperature(request) {
127
+ const device = this.endpoint.stateOf(MatterbridgeServer);
128
+ device.log.info(`Setting color temperature to ${request.colorTemperatureMireds} with transitionTime ${request.transitionTime} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
129
+ device.commandHandler.executeHandler('moveToColorTemperature', { request, cluster: ColorControlServer.id, attributes: this.state, endpoint: this.endpoint });
285
130
  device.log.debug(`MatterbridgeColorControlServer: moveToColorTemperature called`);
286
- super.moveToColorTemperature({ optionsOverride, optionsMask, colorTemperatureMireds, transitionTime });
131
+ super.moveToColorTemperature(request);
287
132
  }
288
133
  }
289
134
  export class MatterbridgeLiftWindowCoveringServer extends WindowCoveringServer.with(WindowCovering.Feature.Lift, WindowCovering.Feature.PositionAwareLift) {
290
135
  upOrOpen() {
291
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
292
- device.upOrOpen();
136
+ const device = this.endpoint.stateOf(MatterbridgeServer);
137
+ device.log.info(`Opening cover (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
138
+ device.commandHandler.executeHandler(`upOrOpen`, { request: {}, cluster: WindowCoveringServer.id, attributes: this.state, endpoint: this.endpoint });
293
139
  device.log.debug(`MatterbridgeWindowCoveringServer: upOrOpen called`);
294
140
  super.upOrOpen();
295
141
  }
296
142
  downOrClose() {
297
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
298
- device.downOrClose();
143
+ const device = this.endpoint.stateOf(MatterbridgeServer);
144
+ device.log.info(`Closing cover (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
145
+ device.commandHandler.executeHandler(`downOrClose`, { request: {}, cluster: WindowCoveringServer.id, attributes: this.state, endpoint: this.endpoint });
299
146
  device.log.debug(`MatterbridgeWindowCoveringServer: downOrClose called`);
300
147
  super.downOrClose();
301
148
  }
302
149
  stopMotion() {
303
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
304
- device.stopMotion();
150
+ const device = this.endpoint.stateOf(MatterbridgeServer);
151
+ device.log.info(`Stopping cover (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
152
+ device.commandHandler.executeHandler('stopMotion', { request: {}, cluster: WindowCoveringServer.id, attributes: this.state, endpoint: this.endpoint });
305
153
  device.log.debug(`MatterbridgeWindowCoveringServer: stopMotion called`);
306
154
  super.stopMotion();
307
155
  }
308
- goToLiftPercentage({ liftPercent100thsValue }) {
309
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
310
- device.goToLiftPercentage({ liftPercent100thsValue });
311
- device.log.debug(`MatterbridgeWindowCoveringServer: goToLiftPercentage with ${liftPercent100thsValue}`);
312
- super.goToLiftPercentage({ liftPercent100thsValue });
156
+ goToLiftPercentage(request) {
157
+ const device = this.endpoint.stateOf(MatterbridgeServer);
158
+ device.log.info(`Setting cover lift percentage to ${request.liftPercent100thsValue} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
159
+ device.commandHandler.executeHandler('goToLiftPercentage', { request, cluster: WindowCoveringServer.id, attributes: this.state, endpoint: this.endpoint });
160
+ device.log.debug(`MatterbridgeWindowCoveringServer: goToLiftPercentage with ${request.liftPercent100thsValue}`);
161
+ super.goToLiftPercentage(request);
313
162
  }
314
163
  async handleMovement(type, reversed, direction, targetPercent100ths) {
315
164
  }
316
165
  }
317
166
  export class MatterbridgeLiftTiltWindowCoveringServer extends WindowCoveringServer.with(WindowCovering.Feature.Lift, WindowCovering.Feature.PositionAwareLift, WindowCovering.Feature.Tilt, WindowCovering.Feature.PositionAwareTilt) {
318
167
  upOrOpen() {
319
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
320
- device.upOrOpen();
168
+ const device = this.endpoint.stateOf(MatterbridgeServer);
169
+ device.log.info(`Opening cover (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
170
+ device.commandHandler.executeHandler(`upOrOpen`, { request: {}, cluster: WindowCoveringServer.id, attributes: this.state, endpoint: this.endpoint });
321
171
  device.log.debug(`MatterbridgeLiftTiltWindowCoveringServer: upOrOpen called`);
322
172
  super.upOrOpen();
323
173
  }
324
174
  downOrClose() {
325
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
326
- device.downOrClose();
175
+ const device = this.endpoint.stateOf(MatterbridgeServer);
176
+ device.log.info(`Closing cover (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
177
+ device.commandHandler.executeHandler(`downOrClose`, { request: {}, cluster: WindowCoveringServer.id, attributes: this.state, endpoint: this.endpoint });
327
178
  device.log.debug(`MatterbridgeLiftTiltWindowCoveringServer: downOrClose called`);
328
179
  super.downOrClose();
329
180
  }
330
181
  stopMotion() {
331
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
332
- device.stopMotion();
182
+ const device = this.endpoint.stateOf(MatterbridgeServer);
183
+ device.log.info(`Stopping cover (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
184
+ device.commandHandler.executeHandler('stopMotion', { request: {}, cluster: WindowCoveringServer.id, attributes: this.state, endpoint: this.endpoint });
333
185
  device.log.debug(`MatterbridgeLiftTiltWindowCoveringServer: stopMotion called`);
334
186
  super.stopMotion();
335
187
  }
336
- goToLiftPercentage({ liftPercent100thsValue }) {
337
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
338
- device.goToLiftPercentage({ liftPercent100thsValue });
339
- device.log.debug(`MatterbridgeLiftTiltWindowCoveringServer: goToLiftPercentage with ${liftPercent100thsValue}`);
340
- super.goToLiftPercentage({ liftPercent100thsValue });
188
+ goToLiftPercentage(request) {
189
+ const device = this.endpoint.stateOf(MatterbridgeServer);
190
+ device.log.info(`Setting cover lift percentage to ${request.liftPercent100thsValue} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
191
+ device.commandHandler.executeHandler('goToLiftPercentage', { request, cluster: WindowCoveringServer.id, attributes: this.state, endpoint: this.endpoint });
192
+ device.log.debug(`MatterbridgeLiftTiltWindowCoveringServer: goToLiftPercentage with ${request.liftPercent100thsValue}`);
193
+ super.goToLiftPercentage(request);
341
194
  }
342
- goToTiltPercentage({ tiltPercent100thsValue }) {
343
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
344
- device.goToTiltPercentage({ tiltPercent100thsValue });
345
- device.log.debug(`MatterbridgeLiftTiltWindowCoveringServer: goToTiltPercentage with ${tiltPercent100thsValue}`);
346
- super.goToTiltPercentage({ tiltPercent100thsValue });
195
+ goToTiltPercentage(request) {
196
+ const device = this.endpoint.stateOf(MatterbridgeServer);
197
+ device.log.info(`Setting cover tilt percentage to ${request.tiltPercent100thsValue} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
198
+ device.commandHandler.executeHandler('goToTiltPercentage', { request, cluster: WindowCoveringServer.id, attributes: this.state, endpoint: this.endpoint });
199
+ device.log.debug(`MatterbridgeLiftTiltWindowCoveringServer: goToTiltPercentage with ${request.tiltPercent100thsValue}`);
200
+ super.goToTiltPercentage(request);
347
201
  }
348
202
  async handleMovement(type, reversed, direction, targetPercent100ths) {
349
203
  }
350
204
  }
351
205
  export class MatterbridgeDoorLockServer extends DoorLockServer {
352
206
  lockDoor() {
353
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
354
- device.lockDoor();
207
+ const device = this.endpoint.stateOf(MatterbridgeServer);
208
+ device.log.info(`Locking door (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
209
+ device.commandHandler.executeHandler('lockDoor', { request: {}, cluster: DoorLockServer.id, attributes: this.state, endpoint: this.endpoint });
355
210
  device.log.debug(`MatterbridgeDoorLockServer: lockDoor called`);
356
211
  super.lockDoor();
357
212
  }
358
213
  unlockDoor() {
359
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
360
- device.unlockDoor();
214
+ const device = this.endpoint.stateOf(MatterbridgeServer);
215
+ device.log.info(`Unlocking door (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
216
+ device.commandHandler.executeHandler('unlockDoor', { request: {}, cluster: DoorLockServer.id, attributes: this.state, endpoint: this.endpoint });
361
217
  device.log.debug(`MatterbridgeDoorLockServer: unlockDoor called`);
362
218
  super.unlockDoor();
363
219
  }
364
220
  }
365
- export class MatterbridgeModeSelectServer extends ModeSelectServer {
366
- changeToMode({ newMode }) {
367
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
368
- device.changeToMode({ newMode });
369
- device.log.debug(`MatterbridgeModeSelectServer: changeToMode called with mode: ${newMode}`);
370
- super.changeToMode({ newMode });
371
- }
372
- }
373
221
  export class MatterbridgeFanControlServer extends FanControlServer.with(FanControl.Feature.MultiSpeed, FanControl.Feature.Auto, FanControl.Feature.Step) {
374
- step({ direction, wrap, lowestOff }) {
375
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
376
- device.step({ direction, wrap, lowestOff });
222
+ step(request) {
223
+ const device = this.endpoint.stateOf(MatterbridgeServer);
224
+ device.log.info(`Stepping fan with direction ${request.direction} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
225
+ device.commandHandler.executeHandler('step', { request, cluster: FanControlServer.id, attributes: this.state, endpoint: this.endpoint });
377
226
  const lookupStepDirection = ['Increase', 'Decrease'];
378
- device.log.debug(`MatterbridgeFanControlServer: step called with direction: ${lookupStepDirection[direction]} wrap: ${wrap} lowestOff: ${lowestOff}`);
227
+ device.log.debug(`MatterbridgeFanControlServer: step called with direction: ${lookupStepDirection[request.direction]} wrap: ${request.wrap} lowestOff: ${request.lowestOff}`);
379
228
  device.log.debug(`- current percentCurrent: ${this.state.percentCurrent}`);
380
- if (direction === FanControl.StepDirection.Increase) {
381
- if (wrap && this.state.percentCurrent === 100) {
382
- this.state.percentCurrent = lowestOff ? 0 : 10;
229
+ if (request.direction === FanControl.StepDirection.Increase) {
230
+ if (request.wrap && this.state.percentCurrent === 100) {
231
+ this.state.percentCurrent = request.lowestOff ? 0 : 10;
383
232
  }
384
233
  else
385
234
  this.state.percentCurrent = Math.min(this.state.percentCurrent + 10, 100);
386
235
  }
387
- else if (direction === FanControl.StepDirection.Decrease) {
388
- if (wrap && this.state.percentCurrent === (lowestOff ? 0 : 10)) {
236
+ else if (request.direction === FanControl.StepDirection.Decrease) {
237
+ if (request.wrap && this.state.percentCurrent === (request.lowestOff ? 0 : 10)) {
389
238
  this.state.percentCurrent = 100;
390
239
  }
391
240
  else
392
- this.state.percentCurrent = Math.max(this.state.percentCurrent - 10, lowestOff ? 0 : 10);
241
+ this.state.percentCurrent = Math.max(this.state.percentCurrent - 10, request.lowestOff ? 0 : 10);
393
242
  }
394
243
  device.log.debug('Set percentCurrent to:', this.state.percentCurrent);
395
244
  }
396
245
  }
397
246
  export class MatterbridgeThermostatServer extends ThermostatServer.with(Thermostat.Feature.Cooling, Thermostat.Feature.Heating, Thermostat.Feature.AutoMode) {
398
- setpointRaiseLower({ mode, amount }) {
399
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
400
- device.setpointRaiseLower({ mode, amount });
247
+ setpointRaiseLower(request) {
248
+ const device = this.endpoint.stateOf(MatterbridgeServer);
249
+ device.log.info(`Setting setpoint by ${request.amount} in mode ${request.mode} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
250
+ device.commandHandler.executeHandler('setpointRaiseLower', { request, cluster: ThermostatServer.id, attributes: this.state, endpoint: this.endpoint });
401
251
  const lookupSetpointAdjustMode = ['Heat', 'Cool', 'Both'];
402
- device.log.debug(`MatterbridgeThermostatServer: setpointRaiseLower called with mode: ${lookupSetpointAdjustMode[mode]} amount: ${amount / 10}`);
403
- device.log.debug(`- current occupiedHeatingSetpoint: ${this.state.occupiedHeatingSetpoint / 100}`);
404
- device.log.debug(`- current occupiedCoolingSetpoint: ${this.state.occupiedCoolingSetpoint / 100}`);
405
- if ((mode === Thermostat.SetpointRaiseLowerMode.Heat || mode === Thermostat.SetpointRaiseLowerMode.Both) && this.state.occupiedHeatingSetpoint !== undefined) {
406
- const setpoint = this.state.occupiedHeatingSetpoint / 100 + amount / 10;
252
+ device.log.debug(`MatterbridgeThermostatServer: setpointRaiseLower called with mode: ${lookupSetpointAdjustMode[request.mode]} amount: ${request.amount / 10}`);
253
+ if (this.state.occupiedHeatingSetpoint !== undefined)
254
+ device.log.debug(`- current occupiedHeatingSetpoint: ${this.state.occupiedHeatingSetpoint / 100}`);
255
+ if (this.state.occupiedCoolingSetpoint !== undefined)
256
+ device.log.debug(`- current occupiedCoolingSetpoint: ${this.state.occupiedCoolingSetpoint / 100}`);
257
+ if ((request.mode === Thermostat.SetpointRaiseLowerMode.Heat || request.mode === Thermostat.SetpointRaiseLowerMode.Both) && this.state.occupiedHeatingSetpoint !== undefined) {
258
+ const setpoint = this.state.occupiedHeatingSetpoint / 100 + request.amount / 10;
407
259
  this.state.occupiedHeatingSetpoint = setpoint * 100;
408
260
  device.log.debug(`Set occupiedHeatingSetpoint to ${setpoint}`);
409
261
  }
410
- if ((mode === Thermostat.SetpointRaiseLowerMode.Cool || mode === Thermostat.SetpointRaiseLowerMode.Both) && this.state.occupiedCoolingSetpoint !== undefined) {
411
- const setpoint = this.state.occupiedCoolingSetpoint / 100 + amount / 10;
262
+ if ((request.mode === Thermostat.SetpointRaiseLowerMode.Cool || request.mode === Thermostat.SetpointRaiseLowerMode.Both) && this.state.occupiedCoolingSetpoint !== undefined) {
263
+ const setpoint = this.state.occupiedCoolingSetpoint / 100 + request.amount / 10;
412
264
  this.state.occupiedCoolingSetpoint = setpoint * 100;
413
265
  device.log.debug(`Set occupiedCoolingSetpoint to ${setpoint}`);
414
266
  }
415
267
  }
416
268
  }
417
269
  export class MatterbridgeValveConfigurationAndControlServer extends ValveConfigurationAndControlServer.with(ValveConfigurationAndControl.Feature.Level) {
418
- open({ openDuration, targetLevel }) {
419
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
420
- device.log.debug(`MatterbridgeValveConfigurationAndControlServer: open called with openDuration: ${openDuration} targetLevel: ${targetLevel}`);
421
- device.open({ openDuration, targetLevel });
422
- this.state.targetLevel = targetLevel ?? 100;
423
- this.state.currentLevel = targetLevel ?? 100;
270
+ open(request) {
271
+ const device = this.endpoint.stateOf(MatterbridgeServer);
272
+ device.log.info(`Opening valve to ${request.targetLevel ? request.targetLevel + '%' : 'fully opened'} ${request.openDuration ? 'for ' + request.openDuration + 's' : 'until closed'} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
273
+ device.commandHandler.executeHandler('open', { request, cluster: ValveConfigurationAndControlServer.id, attributes: this.state, endpoint: this.endpoint });
274
+ device.log.debug(`MatterbridgeValveConfigurationAndControlServer: open called with openDuration: ${request.openDuration} targetLevel: ${request.targetLevel}`);
275
+ this.state.targetState = ValveConfigurationAndControl.ValveState.Open;
276
+ this.state.currentState = ValveConfigurationAndControl.ValveState.Open;
277
+ this.state.targetLevel = request.targetLevel ?? 100;
278
+ this.state.currentLevel = request.targetLevel ?? 100;
279
+ this.state.openDuration = request.openDuration ?? this.state.defaultOpenDuration;
280
+ if (this.state.openDuration === null)
281
+ this.state.remainingDuration = null;
424
282
  }
425
283
  close() {
426
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
284
+ const device = this.endpoint.stateOf(MatterbridgeServer);
285
+ device.log.info(`Closing valve (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
286
+ device.commandHandler.executeHandler('close', { request: {}, cluster: ValveConfigurationAndControlServer.id, attributes: this.state, endpoint: this.endpoint });
427
287
  device.log.debug(`MatterbridgeValveConfigurationAndControlServer: close called`);
428
- device.close();
288
+ this.state.targetState = ValveConfigurationAndControl.ValveState.Closed;
289
+ this.state.currentState = ValveConfigurationAndControl.ValveState.Closed;
429
290
  this.state.targetLevel = 0;
430
291
  this.state.currentLevel = 0;
292
+ this.state.openDuration = null;
293
+ this.state.remainingDuration = null;
431
294
  }
432
295
  }
433
296
  export class MatterbridgeSmokeCoAlarmServer extends SmokeCoAlarmServer.with(SmokeCoAlarm.Feature.SmokeAlarm, SmokeCoAlarm.Feature.CoAlarm) {
434
297
  selfTestRequest() {
435
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
298
+ const device = this.endpoint.stateOf(MatterbridgeServer);
299
+ device.log.info(`Testing SmokeCOAlarm (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
300
+ device.commandHandler.executeHandler('selfTestRequest', { request: {}, cluster: SmokeCoAlarmServer.id, attributes: this.state, endpoint: this.endpoint });
436
301
  device.log.debug(`MatterbridgeSmokeCoAlarmServer: selfTestRequest called`);
437
- device.selfTestRequest();
438
302
  }
439
303
  }
440
304
  export class MatterbridgeBooleanStateConfigurationServer extends BooleanStateConfigurationServer.with(BooleanStateConfiguration.Feature.Visual, BooleanStateConfiguration.Feature.Audible, BooleanStateConfiguration.Feature.SensitivityLevel) {
441
- enableDisableAlarm({ alarmsToEnableDisable }) {
442
- const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
305
+ enableDisableAlarm(request) {
306
+ const device = this.endpoint.stateOf(MatterbridgeServer);
307
+ device.log.info(`Enabling/disabling alarm ${request.alarmsToEnableDisable} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
308
+ device.commandHandler.executeHandler('enableDisableAlarm', { request, cluster: BooleanStateConfigurationServer.id, attributes: this.state, endpoint: this.endpoint });
443
309
  device.log.debug(`MatterbridgeBooleanStateConfigurationServer: enableDisableAlarm called`);
444
- device.enableDisableAlarm({ alarmsToEnableDisable });
445
310
  }
446
311
  }
447
312
  export class MatterbridgeSwitchServer extends SwitchServer {
@@ -450,15 +315,17 @@ export class MatterbridgeSwitchServer extends SwitchServer {
450
315
  }
451
316
  export class MatterbridgeOperationalStateServer extends OperationalStateServer {
452
317
  initialize() {
453
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
318
+ const device = this.endpoint.stateOf(MatterbridgeServer);
454
319
  device.log.debug('MatterbridgeOperationalStateServer initialized: setting operational state to Stopped');
455
320
  this.state.operationalState = OperationalState.OperationalStateEnum.Stopped;
456
321
  this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' };
322
+ super.initialize();
457
323
  }
458
324
  pause() {
459
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
325
+ const device = this.endpoint.stateOf(MatterbridgeServer);
326
+ device.log.info(`Pause (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
327
+ device.commandHandler.executeHandler('pause', { request: {}, cluster: OperationalStateServer.id, attributes: this.state, endpoint: this.endpoint });
460
328
  device.log.debug('MatterbridgeOperationalStateServer: pause called setting operational state to Paused');
461
- device.pause();
462
329
  this.state.operationalState = OperationalState.OperationalStateEnum.Paused;
463
330
  this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' };
464
331
  return {
@@ -466,9 +333,10 @@ export class MatterbridgeOperationalStateServer extends OperationalStateServer {
466
333
  };
467
334
  }
468
335
  stop() {
469
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
336
+ const device = this.endpoint.stateOf(MatterbridgeServer);
337
+ device.log.info(`Stop (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
338
+ device.commandHandler.executeHandler('stop', { request: {}, cluster: OperationalStateServer.id, attributes: this.state, endpoint: this.endpoint });
470
339
  device.log.debug('MatterbridgeOperationalStateServer: stop called setting operational state to Stopped');
471
- device.stop();
472
340
  this.state.operationalState = OperationalState.OperationalStateEnum.Stopped;
473
341
  this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' };
474
342
  return {
@@ -476,9 +344,10 @@ export class MatterbridgeOperationalStateServer extends OperationalStateServer {
476
344
  };
477
345
  }
478
346
  start() {
479
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
347
+ const device = this.endpoint.stateOf(MatterbridgeServer);
348
+ device.log.info(`Start (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
349
+ device.commandHandler.executeHandler('start', { request: {}, cluster: OperationalStateServer.id, attributes: this.state, endpoint: this.endpoint });
480
350
  device.log.debug('MatterbridgeOperationalStateServer: start called setting operational state to Running');
481
- device.start();
482
351
  this.state.operationalState = OperationalState.OperationalStateEnum.Running;
483
352
  this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' };
484
353
  return {
@@ -486,9 +355,10 @@ export class MatterbridgeOperationalStateServer extends OperationalStateServer {
486
355
  };
487
356
  }
488
357
  resume() {
489
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
358
+ const device = this.endpoint.stateOf(MatterbridgeServer);
359
+ device.log.info(`Resume (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
360
+ device.commandHandler.executeHandler('resume', { request: {}, cluster: OperationalStateServer.id, attributes: this.state, endpoint: this.endpoint });
490
361
  device.log.debug('MatterbridgeOperationalStateServer: resume called setting operational state to Running');
491
- device.resume();
492
362
  this.state.operationalState = OperationalState.OperationalStateEnum.Running;
493
363
  this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' };
494
364
  return {
@@ -497,32 +367,43 @@ export class MatterbridgeOperationalStateServer extends OperationalStateServer {
497
367
  }
498
368
  }
499
369
  export class MatterbridgeServiceAreaServer extends ServiceAreaServer {
500
- selectAreas({ newAreas }) {
501
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
502
- for (const area of newAreas) {
370
+ selectAreas(request) {
371
+ const device = this.endpoint.stateOf(MatterbridgeServer);
372
+ device.log.info(`Selecting areas ${request.newAreas} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
373
+ device.commandHandler.executeHandler('selectAreas', { request, cluster: ServiceAreaServer.id, attributes: this.state, endpoint: this.endpoint });
374
+ for (const area of request.newAreas) {
503
375
  const supportedArea = this.state.supportedAreas.find((supportedArea) => supportedArea.areaId === area);
504
376
  if (!supportedArea) {
505
377
  device.log.error(`MatterbridgeServiceAreaServer selectAreas called with unsupported area: ${area}`);
506
378
  return { status: ServiceArea.SelectAreasStatus.UnsupportedArea, statusText: 'Unsupported areas' };
507
379
  }
508
380
  }
509
- device.selectAreas({ newAreas });
510
- this.state.selectedAreas = newAreas;
511
- device.log.info(`MatterbridgeServiceAreaServer selectAreas called with: ${newAreas.map((area) => area.toString()).join(', ')}`);
512
- return { status: ServiceArea.SelectAreasStatus.Success, statusText: 'Succesfully selected new areas' };
381
+ this.state.selectedAreas = request.newAreas;
382
+ device.log.debug(`MatterbridgeServiceAreaServer selectAreas called with: ${request.newAreas.map((area) => area.toString()).join(', ')}`);
383
+ return super.selectAreas(request);
384
+ }
385
+ }
386
+ export class MatterbridgeModeSelectServer extends ModeSelectServer {
387
+ changeToMode(request) {
388
+ const device = this.endpoint.stateOf(MatterbridgeServer);
389
+ device.log.info(`Changing mode to ${request.newMode} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
390
+ device.commandHandler.executeHandler('changeToMode', { request, cluster: ModeSelectServer.id, attributes: this.state, endpoint: this.endpoint });
391
+ device.log.debug(`MatterbridgeModeSelectServer: changeToMode called with mode: ${request.newMode}`);
392
+ super.changeToMode(request);
513
393
  }
514
394
  }
515
395
  export class MatterbridgeDeviceEnergyManagementModeServer extends DeviceEnergyManagementModeServer {
516
- changeToMode({ newMode }) {
517
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
518
- const supported = this.state.supportedModes.find((mode) => mode.mode === newMode);
396
+ changeToMode(request) {
397
+ const device = this.endpoint.stateOf(MatterbridgeServer);
398
+ device.log.info(`Changing mode to ${request.newMode} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
399
+ device.commandHandler.executeHandler('changeToMode', { request, cluster: DeviceEnergyManagementModeServer.id, attributes: this.state, endpoint: this.endpoint });
400
+ const supported = this.state.supportedModes.find((mode) => mode.mode === request.newMode);
519
401
  if (!supported) {
520
- device.log.error(`MatterbridgeDeviceEnergyManagementModeServer changeToMode called with unsupported newMode: ${newMode}`);
402
+ device.log.error(`MatterbridgeDeviceEnergyManagementModeServer changeToMode called with unsupported newMode: ${request.newMode}`);
521
403
  return { status: ModeBase.ModeChangeStatus.UnsupportedMode, statusText: 'Unsupported mode' };
522
404
  }
523
- device.changeToMode({ newMode });
524
- this.state.currentMode = newMode;
525
- device.log.info(`MatterbridgeDeviceEnergyManagementModeServer changeToMode called with newMode ${newMode} => ${supported.label}`);
526
- return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Success' };
405
+ this.state.currentMode = request.newMode;
406
+ device.log.debug(`MatterbridgeDeviceEnergyManagementModeServer changeToMode called with newMode ${request.newMode} => ${supported.label}`);
407
+ return super.changeToMode(request);
527
408
  }
528
409
  }
@@ -1,7 +1,7 @@
1
1
  import { AnsiLogger, CYAN, YELLOW, db, debugStringify, hk, or, zb } from './logger/export.js';
2
2
  import { bridgedNode } from './matterbridgeDeviceTypes.js';
3
3
  import { isValidNumber, isValidObject, isValidString } from './utils/export.js';
4
- import { MatterbridgeServer, MatterbridgeServerDevice, MatterbridgeIdentifyServer, MatterbridgeOnOffServer, MatterbridgeLevelControlServer, MatterbridgeColorControlServer, MatterbridgeLiftWindowCoveringServer, MatterbridgeLiftTiltWindowCoveringServer, MatterbridgeThermostatServer, MatterbridgeFanControlServer, MatterbridgeDoorLockServer, MatterbridgeModeSelectServer, MatterbridgeValveConfigurationAndControlServer, MatterbridgeSmokeCoAlarmServer, MatterbridgeBooleanStateConfigurationServer, MatterbridgeSwitchServer, MatterbridgeOperationalStateServer, MatterbridgeDeviceEnergyManagementModeServer, } from './matterbridgeBehaviors.js';
4
+ import { MatterbridgeServer, MatterbridgeIdentifyServer, MatterbridgeOnOffServer, MatterbridgeLevelControlServer, MatterbridgeColorControlServer, MatterbridgeLiftWindowCoveringServer, MatterbridgeLiftTiltWindowCoveringServer, MatterbridgeThermostatServer, MatterbridgeFanControlServer, MatterbridgeDoorLockServer, MatterbridgeModeSelectServer, MatterbridgeValveConfigurationAndControlServer, MatterbridgeSmokeCoAlarmServer, MatterbridgeBooleanStateConfigurationServer, MatterbridgeSwitchServer, MatterbridgeOperationalStateServer, MatterbridgeDeviceEnergyManagementModeServer, } from './matterbridgeBehaviors.js';
5
5
  import { addClusterServers, addFixedLabel, addOptionalClusterServers, addRequiredClusterServers, addUserLabel, createUniqueId, getBehavior, getBehaviourTypesFromClusterClientIds, getBehaviourTypesFromClusterServerIds, getDefaultOperationalStateClusterServer, getDefaultFlowMeasurementClusterServer, getDefaultIlluminanceMeasurementClusterServer, getDefaultPressureMeasurementClusterServer, getDefaultRelativeHumidityMeasurementClusterServer, getDefaultTemperatureMeasurementClusterServer, getDefaultOccupancySensingClusterServer, lowercaseFirstLetter, updateAttribute, getClusterId, getAttributeId, setAttribute, getAttribute, checkNotLatinCharacters, generateUniqueId, subscribeAttribute, invokeBehaviorCommand, triggerEvent, } from './matterbridgeEndpointHelpers.js';
6
6
  import { Endpoint, Lifecycle, MutableEndpoint, NamedHandler, SupportedBehaviors, UINT16_MAX, UINT32_MAX, VendorId } from '@matter/main';
7
7
  import { getClusterNameById, MeasurementType } from '@matter/main/types';
@@ -143,7 +143,7 @@ export class MatterbridgeEndpoint extends Endpoint {
143
143
  this.deviceTypes.set(firstDefinition.code, firstDefinition);
144
144
  this.log = new AnsiLogger({ logName: options.uniqueStorageKey ?? 'MatterbridgeEndpoint', logTimestampFormat: 4, logLevel: debug === true ? "debug" : MatterbridgeEndpoint.logLevel });
145
145
  this.log.debug(`${YELLOW}new${db} MatterbridgeEndpoint: ${zb}${'0x' + firstDefinition.code.toString(16).padStart(4, '0')}${db}-${zb}${firstDefinition.name}${db} id: ${CYAN}${options.uniqueStorageKey}${db} number: ${CYAN}${options.endpointId}${db} taglist: ${CYAN}${options.tagList ? debugStringify(options.tagList) : 'undefined'}${db}`);
146
- this.behaviors.require(MatterbridgeServer, { deviceCommand: new MatterbridgeServerDevice(this.log, this.commandHandler, undefined) });
146
+ this.behaviors.require(MatterbridgeServer, { log: this.log, commandHandler: this.commandHandler });
147
147
  }
148
148
  static async loadInstance(definition, options = {}, debug = false) {
149
149
  return new MatterbridgeEndpoint(definition, options, debug);
@@ -871,13 +871,13 @@ export class MatterbridgeEndpoint extends Endpoint {
871
871
  this.behaviors.require(MatterbridgeValveConfigurationAndControlServer.with(ValveConfigurationAndControl.Feature.Level), {
872
872
  currentState: valveState,
873
873
  targetState: valveState,
874
- currentLevel: valveLevel,
875
- targetLevel: valveLevel,
876
874
  openDuration: null,
877
875
  defaultOpenDuration: null,
878
876
  remainingDuration: null,
879
- defaultOpenLevel: 100,
880
877
  valveFault: { generalFault: false, blocked: false, leaking: false, notConnected: false, shortCircuit: false, currentExceeded: false },
878
+ currentLevel: valveLevel,
879
+ targetLevel: valveLevel,
880
+ defaultOpenLevel: 100,
881
881
  levelStep: 1,
882
882
  });
883
883
  return this;
@@ -1043,7 +1043,7 @@ export class MatterbridgeEndpoint extends Endpoint {
1043
1043
  });
1044
1044
  return this;
1045
1045
  }
1046
- createDefaultDeviceEnergyManagementCluster(esaType = DeviceEnergyManagement.EsaType.Other, esaCanGenerate = false, esaState = DeviceEnergyManagement.EsaState.Online, absMinPower = 0, absMaxPower = 0) {
1046
+ createDefaultDeviceEnergyManagementClusterServer(esaType = DeviceEnergyManagement.EsaType.Other, esaCanGenerate = false, esaState = DeviceEnergyManagement.EsaState.Online, absMinPower = 0, absMaxPower = 0) {
1047
1047
  this.behaviors.require(DeviceEnergyManagementServer.with(DeviceEnergyManagement.Feature.PowerForecastReporting), {
1048
1048
  forecast: null,
1049
1049
  esaType,
@@ -1054,7 +1054,7 @@ export class MatterbridgeEndpoint extends Endpoint {
1054
1054
  });
1055
1055
  return this;
1056
1056
  }
1057
- createDefaultDeviceEnergyManagementModeCluster(currentMode, supportedModes) {
1057
+ createDefaultDeviceEnergyManagementModeClusterServer(currentMode, supportedModes) {
1058
1058
  this.behaviors.require(MatterbridgeDeviceEnergyManagementModeServer, {
1059
1059
  supportedModes: supportedModes ?? [
1060
1060
  { label: 'No Energy Management (Forecast reporting only)', mode: 1, modeTags: [{ value: DeviceEnergyManagementMode.ModeTag.NoOptimization }] },
@@ -42,6 +42,8 @@ import { Pm10ConcentrationMeasurement } from '@matter/main/clusters/pm10-concent
42
42
  import { RadonConcentrationMeasurement } from '@matter/main/clusters/radon-concentration-measurement';
43
43
  import { TotalVolatileOrganicCompoundsConcentrationMeasurement } from '@matter/main/clusters/total-volatile-organic-compounds-concentration-measurement';
44
44
  import { OperationalState } from '@matter/main/clusters/operational-state';
45
+ import { DeviceEnergyManagement } from '@matter/main/clusters/device-energy-management';
46
+ import { DeviceEnergyManagementMode } from '@matter/main/clusters/device-energy-management-mode';
45
47
  import { PowerSourceServer } from '@matter/main/behaviors/power-source';
46
48
  import { UserLabelServer } from '@matter/main/behaviors/user-label';
47
49
  import { FixedLabelServer } from '@matter/main/behaviors/fixed-label';
@@ -71,10 +73,11 @@ import { Pm25ConcentrationMeasurementServer } from '@matter/main/behaviors/pm25-
71
73
  import { Pm10ConcentrationMeasurementServer } from '@matter/main/behaviors/pm10-concentration-measurement';
72
74
  import { RadonConcentrationMeasurementServer } from '@matter/main/behaviors/radon-concentration-measurement';
73
75
  import { TotalVolatileOrganicCompoundsConcentrationMeasurementServer } from '@matter/main/behaviors/total-volatile-organic-compounds-concentration-measurement';
76
+ import { DeviceEnergyManagementServer } from '@matter/node/behaviors/device-energy-management';
74
77
  import { createHash } from 'node:crypto';
75
78
  import { BLUE, CYAN, db, debugStringify, er, hk, or, YELLOW, zb } from 'node-ansi-logger';
76
79
  import { deepCopy, deepEqual, isValidArray } from './utils/export.js';
77
- import { MatterbridgeIdentifyServer, MatterbridgeOnOffServer, MatterbridgeLevelControlServer, MatterbridgeColorControlServer, MatterbridgeLiftWindowCoveringServer, MatterbridgeThermostatServer, MatterbridgeFanControlServer, MatterbridgeDoorLockServer, MatterbridgeModeSelectServer, MatterbridgeValveConfigurationAndControlServer, MatterbridgeSmokeCoAlarmServer, MatterbridgeBooleanStateConfigurationServer, MatterbridgeOperationalStateServer, } from './matterbridgeBehaviors.js';
80
+ import { MatterbridgeIdentifyServer, MatterbridgeOnOffServer, MatterbridgeLevelControlServer, MatterbridgeColorControlServer, MatterbridgeLiftWindowCoveringServer, MatterbridgeThermostatServer, MatterbridgeFanControlServer, MatterbridgeDoorLockServer, MatterbridgeModeSelectServer, MatterbridgeValveConfigurationAndControlServer, MatterbridgeSmokeCoAlarmServer, MatterbridgeBooleanStateConfigurationServer, MatterbridgeOperationalStateServer, MatterbridgeDeviceEnergyManagementModeServer, } from './matterbridgeBehaviors.js';
78
81
  export function capitalizeFirstLetter(name) {
79
82
  if (!name)
80
83
  return name;
@@ -204,6 +207,10 @@ export function getBehaviourTypeFromClusterServerId(clusterId) {
204
207
  return RadonConcentrationMeasurementServer.with('NumericMeasurement');
205
208
  if (clusterId === TotalVolatileOrganicCompoundsConcentrationMeasurement.Cluster.id)
206
209
  return TotalVolatileOrganicCompoundsConcentrationMeasurementServer.with('NumericMeasurement');
210
+ if (clusterId === DeviceEnergyManagement.Cluster.id)
211
+ return DeviceEnergyManagementServer.with('PowerForecastReporting');
212
+ if (clusterId === DeviceEnergyManagementMode.Cluster.id)
213
+ return MatterbridgeDeviceEnergyManagementModeServer;
207
214
  return MatterbridgeIdentifyServer;
208
215
  }
209
216
  export function getBehaviourTypeFromClusterClientId(_clusterId) {
@@ -240,6 +247,25 @@ export async function invokeBehaviorCommand(endpoint, cluster, command, params)
240
247
  });
241
248
  return true;
242
249
  }
250
+ export async function invokeSubscribeHandler(endpoint, cluster, attribute, newValue, oldValue) {
251
+ const event = attribute + '$Changed';
252
+ const clusterName = getBehavior(endpoint, cluster)?.id;
253
+ if (!clusterName) {
254
+ endpoint.log.error(`invokeSubscribeHandler ${hk}${event}${er} error: cluster not found on endpoint ${or}${endpoint.maybeId}${er}:${or}${endpoint.maybeNumber}${er}`);
255
+ return false;
256
+ }
257
+ if (endpoint.construction.status !== Lifecycle.Status.Active) {
258
+ endpoint.log.error(`invokeSubscribeHandler ${hk}${clusterName}.${event}${er} error: Endpoint ${or}${endpoint.maybeId}${er}:${or}${endpoint.maybeNumber}${er} is in the ${BLUE}${endpoint.construction.status}${er} state`);
259
+ return false;
260
+ }
261
+ const events = endpoint.events;
262
+ if (!(clusterName in events) || !(event in events[clusterName])) {
263
+ endpoint.log.error(`invokeSubscribeHandler ${hk}${event}${er} error: cluster ${clusterName} not found on endpoint ${or}${endpoint.id}${er}:${or}${endpoint.number}${er}`);
264
+ return false;
265
+ }
266
+ await endpoint.act((agent) => agent[clusterName].events[event].emit(newValue, oldValue, { ...agent.context, offline: false }));
267
+ return true;
268
+ }
243
269
  export function addRequiredClusterServers(endpoint) {
244
270
  const requiredServerList = [];
245
271
  endpoint.log.debug(`addRequiredClusterServers for ${CYAN}${endpoint.maybeId}${db}`);
@@ -343,6 +369,10 @@ export function addClusterServers(endpoint, serverList) {
343
369
  endpoint.createDefaultRadonConcentrationMeasurementClusterServer();
344
370
  if (serverList.includes(TotalVolatileOrganicCompoundsConcentrationMeasurement.Cluster.id))
345
371
  endpoint.createDefaultTvocMeasurementClusterServer();
372
+ if (serverList.includes(DeviceEnergyManagement.Cluster.id))
373
+ endpoint.createDefaultDeviceEnergyManagementClusterServer();
374
+ if (serverList.includes(DeviceEnergyManagementMode.Cluster.id))
375
+ endpoint.createDefaultDeviceEnergyManagementModeClusterServer();
346
376
  }
347
377
  export async function addFixedLabel(endpoint, label, value) {
348
378
  if (!endpoint.hasClusterServer(FixedLabel.Cluster.id)) {
@@ -137,8 +137,8 @@ export class MatterbridgePlatform {
137
137
  this.selectEntity.clear();
138
138
  await this.saveSelects();
139
139
  }
140
- async clearDeviceSelect(device) {
141
- this.selectDevice.delete(device);
140
+ async clearDeviceSelect(serial) {
141
+ this.selectDevice.delete(serial);
142
142
  await this.saveSelects();
143
143
  }
144
144
  setSelectDevice(serial, name, configUrl, icon, entities) {
@@ -94,49 +94,52 @@ export class RoboticVacuumCleaner extends MatterbridgeEndpoint {
94
94
  }
95
95
  }
96
96
  export class MatterbridgeRvcRunModeServer extends RvcRunModeServer {
97
- changeToMode({ newMode }) {
98
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
99
- const supported = this.state.supportedModes.find((mode) => mode.mode === newMode);
97
+ changeToMode(request) {
98
+ const device = this.endpoint.stateOf(MatterbridgeServer);
99
+ device.log.info(`Changing mode to ${request.newMode} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
100
+ device.commandHandler.executeHandler('changeToMode', { request, cluster: RvcRunModeServer.id, attributes: this.state, endpoint: this.endpoint });
101
+ const supported = this.state.supportedModes.find((mode) => mode.mode === request.newMode);
100
102
  if (!supported) {
101
- device.log.error(`MatterbridgeRvcRunModeServer changeToMode called with unsupported newMode: ${newMode}`);
103
+ device.log.error(`MatterbridgeRvcRunModeServer changeToMode called with unsupported newMode: ${request.newMode}`);
102
104
  return { status: ModeBase.ModeChangeStatus.UnsupportedMode, statusText: 'Unsupported mode' };
103
105
  }
104
- device.changeToMode({ newMode });
105
- this.state.currentMode = newMode;
106
+ this.state.currentMode = request.newMode;
106
107
  if (supported.modeTags.find((tag) => tag.value === RvcRunMode.ModeTag.Cleaning)) {
107
- device.log.info('MatterbridgeRvcRunModeServer changeToMode called with newMode Cleaning => Running');
108
+ device.log.debug('MatterbridgeRvcRunModeServer changeToMode called with newMode Cleaning => Running');
108
109
  this.agent.get(MatterbridgeRvcOperationalStateServer).state.operationalState = RvcOperationalState.OperationalState.Running;
109
110
  return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Running' };
110
111
  }
111
112
  else if (supported.modeTags.find((tag) => tag.value === RvcRunMode.ModeTag.Idle)) {
112
- device.log.info('MatterbridgeRvcRunModeServer changeToMode called with newMode Idle => Docked');
113
+ device.log.debug('MatterbridgeRvcRunModeServer changeToMode called with newMode Idle => Docked');
113
114
  this.agent.get(MatterbridgeRvcOperationalStateServer).state.operationalState = RvcOperationalState.OperationalState.Docked;
114
115
  return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Docked' };
115
116
  }
116
- device.log.info(`MatterbridgeRvcRunModeServer changeToMode called with newMode ${newMode} => ${supported.label}`);
117
+ device.log.debug(`MatterbridgeRvcRunModeServer changeToMode called with newMode ${request.newMode} => ${supported.label}`);
117
118
  this.agent.get(MatterbridgeRvcOperationalStateServer).state.operationalState = RvcOperationalState.OperationalState.Running;
118
119
  return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Success' };
119
120
  }
120
121
  }
121
122
  export class MatterbridgeRvcCleanModeServer extends RvcCleanModeServer {
122
- changeToMode({ newMode }) {
123
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
124
- const supported = this.state.supportedModes.find((mode) => mode.mode === newMode);
123
+ changeToMode(request) {
124
+ const device = this.endpoint.stateOf(MatterbridgeServer);
125
+ device.log.info(`Changing mode to ${request.newMode} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
126
+ device.commandHandler.executeHandler('changeToMode', { request, cluster: RvcCleanModeServer.id, attributes: this.state, endpoint: this.endpoint });
127
+ const supported = this.state.supportedModes.find((mode) => mode.mode === request.newMode);
125
128
  if (!supported) {
126
- device.log.error(`MatterbridgeRvcCleanModeServer changeToMode called with unsupported newMode: ${newMode}`);
129
+ device.log.error(`MatterbridgeRvcCleanModeServer changeToMode called with unsupported newMode: ${request.newMode}`);
127
130
  return { status: ModeBase.ModeChangeStatus.UnsupportedMode, statusText: 'Unsupported mode' };
128
131
  }
129
- device.changeToMode({ newMode });
130
- this.state.currentMode = newMode;
131
- device.log.info(`MatterbridgeRvcCleanModeServer changeToMode called with newMode ${newMode} => ${supported.label}`);
132
+ this.state.currentMode = request.newMode;
133
+ device.log.debug(`MatterbridgeRvcCleanModeServer changeToMode called with newMode ${request.newMode} => ${supported.label}`);
132
134
  return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Success' };
133
135
  }
134
136
  }
135
137
  export class MatterbridgeRvcOperationalStateServer extends RvcOperationalStateServer {
136
138
  pause() {
137
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
138
- device.log.info('MatterbridgeRvcOperationalStateServer: pause called setting operational state to Paused and currentMode to Idle');
139
- device.pause();
139
+ const device = this.endpoint.stateOf(MatterbridgeServer);
140
+ device.log.info(`Pause (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
141
+ device.commandHandler.executeHandler('pause', { request: {}, cluster: RvcOperationalStateServer.id, attributes: this.state, endpoint: this.endpoint });
142
+ device.log.debug('MatterbridgeRvcOperationalStateServer: pause called setting operational state to Paused and currentMode to Idle');
140
143
  this.agent.get(MatterbridgeRvcRunModeServer).state.currentMode = 1;
141
144
  this.state.operationalState = RvcOperationalState.OperationalState.Paused;
142
145
  this.state.operationalError = { errorStateId: RvcOperationalState.ErrorState.NoError, errorStateLabel: 'No Error', errorStateDetails: 'Fully operational' };
@@ -145,9 +148,10 @@ export class MatterbridgeRvcOperationalStateServer extends RvcOperationalStateSe
145
148
  };
146
149
  }
147
150
  resume() {
148
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
149
- device.log.info('MatterbridgeRvcOperationalStateServer: resume called setting operational state to Running and currentMode to Cleaning');
150
- device.resume();
151
+ const device = this.endpoint.stateOf(MatterbridgeServer);
152
+ device.log.info(`Resume (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
153
+ device.commandHandler.executeHandler('resume', { request: {}, cluster: RvcOperationalStateServer.id, attributes: this.state, endpoint: this.endpoint });
154
+ device.log.debug('MatterbridgeRvcOperationalStateServer: resume called setting operational state to Running and currentMode to Cleaning');
151
155
  this.agent.get(MatterbridgeRvcRunModeServer).state.currentMode = 2;
152
156
  this.state.operationalState = RvcOperationalState.OperationalState.Running;
153
157
  this.state.operationalError = { errorStateId: RvcOperationalState.ErrorState.NoError, errorStateLabel: 'No Error', errorStateDetails: 'Fully operational' };
@@ -156,9 +160,10 @@ export class MatterbridgeRvcOperationalStateServer extends RvcOperationalStateSe
156
160
  };
157
161
  }
158
162
  goHome() {
159
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
160
- device.log.info('MatterbridgeRvcOperationalStateServer: goHome called setting operational state to Docked and currentMode to Idle');
161
- device.goHome();
163
+ const device = this.endpoint.stateOf(MatterbridgeServer);
164
+ device.log.info(`GoHome (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
165
+ device.commandHandler.executeHandler('goHome', { request: {}, cluster: RvcOperationalStateServer.id, attributes: this.state, endpoint: this.endpoint });
166
+ device.log.debug('MatterbridgeRvcOperationalStateServer: goHome called setting operational state to Docked and currentMode to Idle');
162
167
  this.agent.get(MatterbridgeRvcRunModeServer).state.currentMode = 1;
163
168
  this.state.operationalState = RvcOperationalState.OperationalState.Docked;
164
169
  this.state.operationalError = { errorStateId: RvcOperationalState.ErrorState.NoError, errorStateLabel: 'No Error', errorStateDetails: 'Fully operational' };
@@ -48,30 +48,33 @@ export class WaterHeater extends MatterbridgeEndpoint {
48
48
  }
49
49
  }
50
50
  export class MatterbridgeWaterHeaterManagementServer extends WaterHeaterManagementServer {
51
- boost({ boostInfo }) {
52
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
53
- device.boost({ boostInfo });
54
- device.log.info(`MatterbridgeWaterHeaterManagementServer boost called with: ${JSON.stringify(boostInfo)}`);
51
+ boost(request) {
52
+ const device = this.endpoint.stateOf(MatterbridgeServer);
53
+ device.log.info(`Boost (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
54
+ device.commandHandler.executeHandler('boost', { request, cluster: WaterHeaterManagementServer.id, attributes: this.state, endpoint: this.endpoint });
55
+ device.log.debug(`MatterbridgeWaterHeaterManagementServer boost called with: ${JSON.stringify(request)}`);
55
56
  this.state.boostState = WaterHeaterManagement.BoostState.Active;
56
57
  }
57
58
  cancelBoost() {
58
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
59
- device.cancelBoost();
60
- device.log.info(`MatterbridgeWaterHeaterManagementServer cancelBoost called`);
59
+ const device = this.endpoint.stateOf(MatterbridgeServer);
60
+ device.log.info(`Cancel boost (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
61
+ device.commandHandler.executeHandler('cancelBoost', { request: {}, cluster: WaterHeaterManagementServer.id, attributes: this.state, endpoint: this.endpoint });
62
+ device.log.debug(`MatterbridgeWaterHeaterManagementServer cancelBoost called`);
61
63
  this.state.boostState = WaterHeaterManagement.BoostState.Inactive;
62
64
  }
63
65
  }
64
66
  export class MatterbridgeWaterHeaterModeServer extends WaterHeaterModeServer {
65
- changeToMode({ newMode }) {
66
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
67
- const supported = this.state.supportedModes.find((mode) => mode.mode === newMode);
67
+ changeToMode(request) {
68
+ const device = this.endpoint.stateOf(MatterbridgeServer);
69
+ device.log.info(`Changing mode to ${request.newMode} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
70
+ device.commandHandler.executeHandler('changeToMode', { request, cluster: WaterHeaterModeServer.id, attributes: this.state, endpoint: this.endpoint });
71
+ const supported = this.state.supportedModes.find((mode) => mode.mode === request.newMode);
68
72
  if (!supported) {
69
- device.log.error(`MatterbridgeWaterHeaterModeServer changeToMode called with unsupported newMode: ${newMode}`);
73
+ device.log.error(`MatterbridgeWaterHeaterModeServer changeToMode called with unsupported newMode: ${request.newMode}`);
70
74
  return { status: ModeBase.ModeChangeStatus.UnsupportedMode, statusText: 'Unsupported mode' };
71
75
  }
72
- device.changeToMode({ newMode });
73
- this.state.currentMode = newMode;
74
- device.log.info(`MatterbridgeWaterHeaterModeServer changeToMode called with newMode ${newMode} => ${supported.label}`);
76
+ this.state.currentMode = request.newMode;
77
+ device.log.debug(`MatterbridgeWaterHeaterModeServer changeToMode called with newMode ${request.newMode} => ${supported.label}`);
75
78
  return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Success' };
76
79
  }
77
80
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.0.6-dev-20250611-6f49811",
3
+ "version": "3.0.6-dev-20250612-a8a696e",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "matterbridge",
9
- "version": "3.0.6-dev-20250611-6f49811",
9
+ "version": "3.0.6-dev-20250612-a8a696e",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@matter/main": "0.14.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.0.6-dev-20250611-6f49811",
3
+ "version": "3.0.6-dev-20250612-a8a696e",
4
4
  "description": "Matterbridge plugin manager for Matter",
5
5
  "author": "https://github.com/Luligu",
6
6
  "license": "Apache-2.0",