homebridge 2.0.0-alpha.61 → 2.0.0-alpha.63

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.
@@ -10,7 +10,64 @@
10
10
  */
11
11
  import { ColorControlServer, DoorLockServer, IdentifyServer, LevelControlServer, OnOffServer, RvcCleanModeServer, RvcOperationalStateServer, RvcRunModeServer, ServiceAreaServer, ThermostatServer, WindowCoveringServer, } from '@matter/main/behaviors';
12
12
  import { Logger } from '../logger.js';
13
+ import { clusterNames } from './matterTypes.js';
13
14
  const log = Logger.withPrefix('Matter/Behaviours');
15
+ /**
16
+ * Command names for each cluster
17
+ * Provides type safety and autocomplete for command names
18
+ */
19
+ const commandNames = {
20
+ OnOff: {
21
+ on: 'on',
22
+ off: 'off',
23
+ toggle: 'toggle',
24
+ },
25
+ LevelControl: {
26
+ moveToLevel: 'moveToLevel',
27
+ moveToLevelWithOnOff: 'moveToLevelWithOnOff',
28
+ move: 'move',
29
+ step: 'step',
30
+ stop: 'stop',
31
+ },
32
+ WindowCovering: {
33
+ upOrOpen: 'upOrOpen',
34
+ downOrClose: 'downOrClose',
35
+ stopMotion: 'stopMotion',
36
+ },
37
+ DoorLock: {
38
+ lockDoor: 'lockDoor',
39
+ unlockDoor: 'unlockDoor',
40
+ },
41
+ Thermostat: {
42
+ setpointRaiseLower: 'setpointRaiseLower',
43
+ },
44
+ Identify: {
45
+ identify: 'identify',
46
+ },
47
+ ColorControl: {
48
+ moveToColorTemperatureLogic: 'moveToColorTemperatureLogic',
49
+ moveToHueAndSaturationLogic: 'moveToHueAndSaturationLogic',
50
+ moveToColorLogic: 'moveToColorLogic',
51
+ moveToHueLogic: 'moveToHueLogic',
52
+ moveToSaturationLogic: 'moveToSaturationLogic',
53
+ stopAllColorMovement: 'stopAllColorMovement',
54
+ },
55
+ RvcOperationalState: {
56
+ pause: 'pause',
57
+ resume: 'resume',
58
+ goHome: 'goHome',
59
+ },
60
+ RvcRunMode: {
61
+ changeToMode: 'changeToMode',
62
+ },
63
+ RvcCleanMode: {
64
+ changeToMode: 'changeToMode',
65
+ },
66
+ ServiceArea: {
67
+ selectAreas: 'selectAreas',
68
+ skipArea: 'skipArea',
69
+ },
70
+ };
14
71
  /**
15
72
  * Store for custom handlers
16
73
  * Maps endpoint ID -> cluster name -> command name -> handler
@@ -74,7 +131,7 @@ export function registerHandler(endpointId, clusterName, commandName, handler) {
74
131
  }
75
132
  const clusterHandlers = endpointHandlers.get(clusterName);
76
133
  clusterHandlers.set(commandName, handler);
77
- log.info(`Registered handler for ${endpointId}.${clusterName}.${commandName}`);
134
+ log.debug(`Registered handler for ${endpointId}.${clusterName}.${commandName}`);
78
135
  }
79
136
  /**
80
137
  * Get a handler for a specific endpoint/cluster/command
@@ -82,69 +139,45 @@ export function registerHandler(endpointId, clusterName, commandName, handler) {
82
139
  function getHandler(endpointId, clusterName, commandName) {
83
140
  return handlerStore.get(endpointId)?.get(clusterName)?.get(commandName);
84
141
  }
142
+ /**
143
+ * Execute a handler with consistent error handling and logging
144
+ */
145
+ function executeHandler(endpointId, clusterName, commandName, request) {
146
+ const handler = getHandler(endpointId, clusterName, commandName);
147
+ log.debug(`${clusterName}.${commandName} called for endpoint ${endpointId}`);
148
+ if (handler) {
149
+ handler(request);
150
+ log.debug(` ✓ Plugin handler for ${endpointId}.${clusterName}.${commandName} executed successfully`);
151
+ }
152
+ else {
153
+ log.warn(` ⚠ No handler registered for ${endpointId}.${clusterName}.${commandName}`);
154
+ }
155
+ }
85
156
  /**
86
157
  * Custom OnOff Server that calls plugin handlers
87
158
  */
88
159
  export class HomebridgeOnOffServer extends OnOffServer {
89
160
  on() {
90
161
  const endpointId = this.endpoint.id;
91
- const handler = getHandler(endpointId, 'onOff', 'on');
92
- log.info(`OnOff.on called for endpoint ${endpointId}`);
93
- if (handler) {
94
- try {
95
- handler();
96
- log.info(' ✓ Plugin handler executed successfully');
97
- }
98
- catch (error) {
99
- log.error(' ✗ Error in plugin handler:', error);
100
- }
101
- }
102
- else {
103
- log.warn(` ⚠ No handler registered for ${endpointId}.onOff.on`);
104
- }
162
+ executeHandler(endpointId, clusterNames.OnOff, commandNames.OnOff.on);
105
163
  const result = super.on();
106
- // Sync the new state to cache for persistence
107
- syncEndpointStateToCache(endpointId, 'onOff', { onOff: true });
164
+ syncEndpointStateToCache(endpointId, clusterNames.OnOff, { onOff: true });
108
165
  return result;
109
166
  }
110
167
  off() {
111
168
  const endpointId = this.endpoint.id;
112
- const handler = getHandler(endpointId, 'onOff', 'off');
113
- log.info(`OnOff.off called for endpoint ${endpointId}`);
114
- if (handler) {
115
- try {
116
- handler();
117
- log.info(' ✓ Plugin handler executed successfully');
118
- }
119
- catch (error) {
120
- log.error(' ✗ Error in plugin handler:', error);
121
- }
122
- }
123
- else {
124
- log.warn(` ⚠ No handler registered for ${endpointId}.onOff.off`);
125
- }
169
+ executeHandler(endpointId, clusterNames.OnOff, commandNames.OnOff.off);
126
170
  const result = super.off();
127
- // Sync the new state to cache for persistence
128
- syncEndpointStateToCache(endpointId, 'onOff', { onOff: false });
171
+ syncEndpointStateToCache(endpointId, clusterNames.OnOff, { onOff: false });
129
172
  return result;
130
173
  }
131
174
  toggle() {
132
175
  const endpointId = this.endpoint.id;
133
- const handler = getHandler(endpointId, 'onOff', 'toggle');
134
- log.info(`OnOff.toggle called for endpoint ${endpointId}`);
135
- if (handler) {
136
- try {
137
- handler();
138
- log.info(' ✓ Plugin handler executed successfully');
139
- }
140
- catch (error) {
141
- log.error(' ✗ Error in plugin handler:', error);
142
- }
143
- }
176
+ executeHandler(endpointId, clusterNames.OnOff, commandNames.OnOff.toggle);
144
177
  const result = super.toggle();
145
178
  // Read the new state from the endpoint and sync to cache
146
179
  const newState = this.state.onOff;
147
- syncEndpointStateToCache(endpointId, 'onOff', { onOff: newState });
180
+ syncEndpointStateToCache(endpointId, clusterNames.OnOff, { onOff: newState });
148
181
  return result;
149
182
  }
150
183
  }
@@ -154,94 +187,41 @@ export class HomebridgeOnOffServer extends OnOffServer {
154
187
  export class HomebridgeLevelControlServer extends LevelControlServer {
155
188
  moveToLevel(request) {
156
189
  const endpointId = this.endpoint.id;
157
- const handler = getHandler(endpointId, 'levelControl', 'moveToLevel');
158
- log.info(`LevelControl.moveToLevel called for endpoint ${endpointId} with level ${request.level}`);
159
- if (handler) {
160
- try {
161
- handler(request);
162
- log.info(' ✓ Plugin handler executed successfully');
163
- }
164
- catch (error) {
165
- log.error(' ✗ Error in plugin handler:', error);
166
- }
167
- }
168
- else {
169
- log.warn(` ⚠ No handler registered for ${endpointId}.levelControl.moveToLevel`);
170
- }
190
+ executeHandler(endpointId, clusterNames.LevelControl, commandNames.LevelControl.moveToLevel, request);
171
191
  const result = super.moveToLevel(request);
172
- // Sync the new level to cache for persistence
173
- syncEndpointStateToCache(endpointId, 'levelControl', { currentLevel: request.level });
192
+ syncEndpointStateToCache(endpointId, clusterNames.LevelControl, { currentLevel: request.level });
174
193
  return result;
175
194
  }
176
195
  moveToLevelWithOnOff(request) {
177
196
  const endpointId = this.endpoint.id;
178
- // Try to get a specific handler for moveToLevelWithOnOff first
179
- let handler = getHandler(endpointId, 'levelControl', 'moveToLevelWithOnOff');
180
- // Fall back to moveToLevel handler if no specific handler is registered
181
- if (!handler) {
182
- handler = getHandler(endpointId, 'levelControl', 'moveToLevel');
183
- }
184
- log.info(`LevelControl.moveToLevelWithOnOff called for endpoint ${endpointId} with level ${request.level}`);
197
+ // Try specific handler first, fall back to moveToLevel handler
198
+ const handler = getHandler(endpointId, clusterNames.LevelControl, commandNames.LevelControl.moveToLevelWithOnOff)
199
+ || getHandler(endpointId, clusterNames.LevelControl, commandNames.LevelControl.moveToLevel);
200
+ log.debug(`LevelControl.moveToLevelWithOnOff called for endpoint ${endpointId} with level ${request.level}`);
185
201
  if (handler) {
186
- try {
187
- handler(request);
188
- log.info(' ✓ Plugin handler executed successfully');
189
- }
190
- catch (error) {
191
- log.error(' ✗ Error in plugin handler:', error);
192
- }
202
+ handler(request);
203
+ log.debug(` ✓ Plugin handler for ${endpointId}.LevelControl.moveToLevelWithOnOff executed successfully`);
193
204
  }
194
205
  else {
195
206
  log.warn(` ⚠ No handler registered for ${endpointId}.levelControl.moveToLevelWithOnOff or moveToLevel`);
196
207
  }
197
208
  const result = super.moveToLevelWithOnOff(request);
198
- // Sync the new level to cache for persistence
199
- syncEndpointStateToCache(endpointId, 'levelControl', { currentLevel: request.level });
209
+ syncEndpointStateToCache(endpointId, clusterNames.LevelControl, { currentLevel: request.level });
200
210
  return result;
201
211
  }
202
212
  move(request) {
203
213
  const endpointId = this.endpoint.id;
204
- const handler = getHandler(endpointId, 'levelControl', 'move');
205
- log.info(`LevelControl.move called for endpoint ${endpointId}`);
206
- if (handler) {
207
- try {
208
- handler(request);
209
- log.info(' ✓ Plugin handler executed successfully');
210
- }
211
- catch (error) {
212
- log.error(' ✗ Error in plugin handler:', error);
213
- }
214
- }
214
+ executeHandler(endpointId, clusterNames.LevelControl, commandNames.LevelControl.move, request);
215
215
  return super.move(request);
216
216
  }
217
217
  step(request) {
218
218
  const endpointId = this.endpoint.id;
219
- const handler = getHandler(endpointId, 'levelControl', 'step');
220
- log.info(`LevelControl.step called for endpoint ${endpointId}`);
221
- if (handler) {
222
- try {
223
- handler(request);
224
- log.info(' ✓ Plugin handler executed successfully');
225
- }
226
- catch (error) {
227
- log.error(' ✗ Error in plugin handler:', error);
228
- }
229
- }
219
+ executeHandler(endpointId, clusterNames.LevelControl, commandNames.LevelControl.step, request);
230
220
  return super.step(request);
231
221
  }
232
222
  stop(request) {
233
223
  const endpointId = this.endpoint.id;
234
- const handler = getHandler(endpointId, 'levelControl', 'stop');
235
- log.info(`LevelControl.stop called for endpoint ${endpointId}`);
236
- if (handler) {
237
- try {
238
- handler(request);
239
- log.info(' ✓ Plugin handler executed successfully');
240
- }
241
- catch (error) {
242
- log.error(' ✗ Error in plugin handler:', error);
243
- }
244
- }
224
+ executeHandler(endpointId, clusterNames.LevelControl, commandNames.LevelControl.stop, request);
245
225
  return super.stop(request);
246
226
  }
247
227
  }
@@ -251,17 +231,7 @@ export class HomebridgeLevelControlServer extends LevelControlServer {
251
231
  export class HomebridgeWindowCoveringServer extends WindowCoveringServer {
252
232
  upOrOpen() {
253
233
  const endpointId = this.endpoint.id;
254
- const handler = getHandler(endpointId, 'windowCovering', 'upOrOpen');
255
- log.info(`WindowCovering.upOrOpen called for endpoint ${endpointId}`);
256
- if (handler) {
257
- try {
258
- handler();
259
- log.info(' ✓ Plugin handler executed successfully');
260
- }
261
- catch (error) {
262
- log.error(' ✗ Error in plugin handler:', error);
263
- }
264
- }
234
+ executeHandler(endpointId, clusterNames.WindowCovering, commandNames.WindowCovering.upOrOpen);
265
235
  const result = super.upOrOpen();
266
236
  // Sync state to cache - window covering opening
267
237
  const currentState = this.state;
@@ -272,22 +242,12 @@ export class HomebridgeWindowCoveringServer extends WindowCoveringServer {
272
242
  if (currentState.currentPositionLiftPercent100ths !== undefined) {
273
243
  stateUpdate.currentPositionLiftPercent100ths = currentState.currentPositionLiftPercent100ths;
274
244
  }
275
- syncEndpointStateToCache(endpointId, 'windowCovering', stateUpdate);
245
+ syncEndpointStateToCache(endpointId, clusterNames.WindowCovering, stateUpdate);
276
246
  return result;
277
247
  }
278
248
  downOrClose() {
279
249
  const endpointId = this.endpoint.id;
280
- const handler = getHandler(endpointId, 'windowCovering', 'downOrClose');
281
- log.info(`WindowCovering.downOrClose called for endpoint ${endpointId}`);
282
- if (handler) {
283
- try {
284
- handler();
285
- log.info(' ✓ Plugin handler executed successfully');
286
- }
287
- catch (error) {
288
- log.error(' ✗ Error in plugin handler:', error);
289
- }
290
- }
250
+ executeHandler(endpointId, clusterNames.WindowCovering, commandNames.WindowCovering.downOrClose);
291
251
  const result = super.downOrClose();
292
252
  // Sync state to cache - window covering closing
293
253
  const currentState = this.state;
@@ -298,22 +258,12 @@ export class HomebridgeWindowCoveringServer extends WindowCoveringServer {
298
258
  if (currentState.currentPositionLiftPercent100ths !== undefined) {
299
259
  stateUpdate.currentPositionLiftPercent100ths = currentState.currentPositionLiftPercent100ths;
300
260
  }
301
- syncEndpointStateToCache(endpointId, 'windowCovering', stateUpdate);
261
+ syncEndpointStateToCache(endpointId, clusterNames.WindowCovering, stateUpdate);
302
262
  return result;
303
263
  }
304
264
  stopMotion() {
305
265
  const endpointId = this.endpoint.id;
306
- const handler = getHandler(endpointId, 'windowCovering', 'stopMotion');
307
- log.info(`WindowCovering.stopMotion called for endpoint ${endpointId}`);
308
- if (handler) {
309
- try {
310
- handler();
311
- log.info(' ✓ Plugin handler executed successfully');
312
- }
313
- catch (error) {
314
- log.error(' ✗ Error in plugin handler:', error);
315
- }
316
- }
266
+ executeHandler(endpointId, clusterNames.WindowCovering, commandNames.WindowCovering.stopMotion);
317
267
  const result = super.stopMotion();
318
268
  // Sync state to cache - window covering stopped
319
269
  const currentState = this.state;
@@ -324,7 +274,7 @@ export class HomebridgeWindowCoveringServer extends WindowCoveringServer {
324
274
  if (currentState.currentPositionLiftPercent100ths !== undefined) {
325
275
  stateUpdate.currentPositionLiftPercent100ths = currentState.currentPositionLiftPercent100ths;
326
276
  }
327
- syncEndpointStateToCache(endpointId, 'windowCovering', stateUpdate);
277
+ syncEndpointStateToCache(endpointId, clusterNames.WindowCovering, stateUpdate);
328
278
  return result;
329
279
  }
330
280
  }
@@ -334,43 +284,23 @@ export class HomebridgeWindowCoveringServer extends WindowCoveringServer {
334
284
  export class HomebridgeDoorLockServer extends DoorLockServer {
335
285
  lockDoor() {
336
286
  const endpointId = this.endpoint.id;
337
- const handler = getHandler(endpointId, 'doorLock', 'lockDoor');
338
- log.info(`DoorLock.lockDoor called for endpoint ${endpointId}`);
339
- if (handler) {
340
- try {
341
- handler();
342
- log.info(' ✓ Plugin handler executed successfully');
343
- }
344
- catch (error) {
345
- log.error(' ✗ Error in plugin handler:', error);
346
- }
347
- }
287
+ executeHandler(endpointId, clusterNames.DoorLock, commandNames.DoorLock.lockDoor);
348
288
  const result = super.lockDoor();
349
289
  // Sync lock state to cache
350
290
  const currentState = this.state;
351
291
  if (currentState.lockState !== undefined) {
352
- syncEndpointStateToCache(endpointId, 'doorLock', { lockState: currentState.lockState });
292
+ syncEndpointStateToCache(endpointId, clusterNames.DoorLock, { lockState: currentState.lockState });
353
293
  }
354
294
  return result;
355
295
  }
356
296
  unlockDoor() {
357
297
  const endpointId = this.endpoint.id;
358
- const handler = getHandler(endpointId, 'doorLock', 'unlockDoor');
359
- log.info(`DoorLock.unlockDoor called for endpoint ${endpointId}`);
360
- if (handler) {
361
- try {
362
- handler();
363
- log.info(' ✓ Plugin handler executed successfully');
364
- }
365
- catch (error) {
366
- log.error(' ✗ Error in plugin handler:', error);
367
- }
368
- }
298
+ executeHandler(endpointId, clusterNames.DoorLock, commandNames.DoorLock.unlockDoor);
369
299
  const result = super.unlockDoor();
370
300
  // Sync lock state to cache
371
301
  const currentState = this.state;
372
302
  if (currentState.lockState !== undefined) {
373
- syncEndpointStateToCache(endpointId, 'doorLock', { lockState: currentState.lockState });
303
+ syncEndpointStateToCache(endpointId, clusterNames.DoorLock, { lockState: currentState.lockState });
374
304
  }
375
305
  return result;
376
306
  }
@@ -381,17 +311,7 @@ export class HomebridgeDoorLockServer extends DoorLockServer {
381
311
  export class HomebridgeThermostatServer extends ThermostatServer {
382
312
  setpointRaiseLower(request) {
383
313
  const endpointId = this.endpoint.id;
384
- const handler = getHandler(endpointId, 'thermostat', 'setpointRaiseLower');
385
- log.info(`Thermostat.setpointRaiseLower called for endpoint ${endpointId}`);
386
- if (handler) {
387
- try {
388
- handler(request);
389
- log.info(' ✓ Plugin handler executed successfully');
390
- }
391
- catch (error) {
392
- log.error(' ✗ Error in plugin handler:', error);
393
- }
394
- }
314
+ executeHandler(endpointId, clusterNames.Thermostat, commandNames.Thermostat.setpointRaiseLower, request);
395
315
  const result = super.setpointRaiseLower(request);
396
316
  // Sync thermostat setpoints to cache
397
317
  const currentState = this.state;
@@ -402,7 +322,7 @@ export class HomebridgeThermostatServer extends ThermostatServer {
402
322
  if (currentState.occupiedHeatingSetpoint !== undefined) {
403
323
  stateUpdate.occupiedHeatingSetpoint = currentState.occupiedHeatingSetpoint;
404
324
  }
405
- syncEndpointStateToCache(endpointId, 'thermostat', stateUpdate);
325
+ syncEndpointStateToCache(endpointId, clusterNames.Thermostat, stateUpdate);
406
326
  return result;
407
327
  }
408
328
  }
@@ -412,17 +332,7 @@ export class HomebridgeThermostatServer extends ThermostatServer {
412
332
  export class HomebridgeIdentifyServer extends IdentifyServer {
413
333
  identify(request) {
414
334
  const endpointId = this.endpoint.id;
415
- const handler = getHandler(endpointId, 'identify', 'identify');
416
- log.info(`Identify.identify called for endpoint ${endpointId}`);
417
- if (handler) {
418
- try {
419
- handler(request);
420
- log.info(' ✓ Plugin handler executed successfully');
421
- }
422
- catch (error) {
423
- log.error(' ✗ Error in plugin handler:', error);
424
- }
425
- }
335
+ executeHandler(endpointId, clusterNames.Identify, commandNames.Identify.identify, request);
426
336
  return super.identify(request);
427
337
  }
428
338
  }
@@ -443,22 +353,12 @@ export class HomebridgeColorControlServer extends ColorControlServer {
443
353
  */
444
354
  moveToColorTemperatureLogic(targetMireds, transitionTime) {
445
355
  const endpointId = this.endpoint.id;
446
- const handler = getHandler(endpointId, 'colorControl', 'moveToColorTemperatureLogic');
447
- log.info(`ColorControl.moveToColorTemperatureLogic called for endpoint ${endpointId} with mireds=${targetMireds}, transitionTime=${transitionTime}`);
448
- if (handler) {
449
- try {
450
- handler({ targetMireds, transitionTime });
451
- log.info(' ✓ Plugin handler executed successfully');
452
- }
453
- catch (error) {
454
- log.error(' ✗ Error in plugin handler:', error);
455
- }
456
- }
356
+ executeHandler(endpointId, clusterNames.ColorControl, commandNames.ColorControl.moveToColorTemperatureLogic, { targetMireds, transitionTime });
457
357
  const result = super.moveToColorTemperatureLogic(targetMireds, transitionTime);
458
358
  // Sync color temperature to cache
459
359
  const currentState = this.state;
460
360
  if (currentState.colorTemperatureMireds !== undefined) {
461
- syncEndpointStateToCache(endpointId, 'colorControl', {
361
+ syncEndpointStateToCache(endpointId, clusterNames.ColorControl, {
462
362
  colorTemperatureMireds: currentState.colorTemperatureMireds,
463
363
  });
464
364
  }
@@ -472,17 +372,7 @@ export class HomebridgeColorControlServer extends ColorControlServer {
472
372
  */
473
373
  moveToHueAndSaturationLogic(targetHue, targetSaturation, transitionTime) {
474
374
  const endpointId = this.endpoint.id;
475
- const handler = getHandler(endpointId, 'colorControl', 'moveToHueAndSaturationLogic');
476
- log.info(`ColorControl.moveToHueAndSaturationLogic called for endpoint ${endpointId} with hue=${targetHue}, saturation=${targetSaturation}, transitionTime=${transitionTime}`);
477
- if (handler) {
478
- try {
479
- handler({ targetHue, targetSaturation, transitionTime });
480
- log.info(' ✓ Plugin handler executed successfully');
481
- }
482
- catch (error) {
483
- log.error(' ✗ Error in plugin handler:', error);
484
- }
485
- }
375
+ executeHandler(endpointId, clusterNames.ColorControl, commandNames.ColorControl.moveToHueAndSaturationLogic, { targetHue, targetSaturation, transitionTime });
486
376
  const result = super.moveToHueAndSaturationLogic(targetHue, targetSaturation, transitionTime);
487
377
  // Sync hue and saturation to cache
488
378
  const currentState = this.state;
@@ -493,7 +383,7 @@ export class HomebridgeColorControlServer extends ColorControlServer {
493
383
  if (currentState.currentSaturation !== undefined) {
494
384
  stateUpdate.currentSaturation = currentState.currentSaturation;
495
385
  }
496
- syncEndpointStateToCache(endpointId, 'colorControl', stateUpdate);
386
+ syncEndpointStateToCache(endpointId, clusterNames.ColorControl, stateUpdate);
497
387
  return result;
498
388
  }
499
389
  /**
@@ -504,17 +394,7 @@ export class HomebridgeColorControlServer extends ColorControlServer {
504
394
  */
505
395
  moveToColorLogic(targetX, targetY, transitionTime) {
506
396
  const endpointId = this.endpoint.id;
507
- const handler = getHandler(endpointId, 'colorControl', 'moveToColorLogic');
508
- log.info(`ColorControl.moveToColorLogic called for endpoint ${endpointId} with x=${targetX}, y=${targetY}, transitionTime=${transitionTime}`);
509
- if (handler) {
510
- try {
511
- handler({ targetX, targetY, transitionTime });
512
- log.info(' ✓ Plugin handler executed successfully');
513
- }
514
- catch (error) {
515
- log.error(' ✗ Error in plugin handler:', error);
516
- }
517
- }
397
+ executeHandler(endpointId, clusterNames.ColorControl, commandNames.ColorControl.moveToColorLogic, { targetX, targetY, transitionTime });
518
398
  const result = super.moveToColorLogic(targetX, targetY, transitionTime);
519
399
  // Sync XY color to cache
520
400
  const currentState = this.state;
@@ -525,7 +405,7 @@ export class HomebridgeColorControlServer extends ColorControlServer {
525
405
  if (currentState.currentY !== undefined) {
526
406
  stateUpdate.currentY = currentState.currentY;
527
407
  }
528
- syncEndpointStateToCache(endpointId, 'colorControl', stateUpdate);
408
+ syncEndpointStateToCache(endpointId, clusterNames.ColorControl, stateUpdate);
529
409
  return result;
530
410
  }
531
411
  /**
@@ -537,17 +417,7 @@ export class HomebridgeColorControlServer extends ColorControlServer {
537
417
  */
538
418
  moveToHueLogic(targetHue, direction, transitionTime, isEnhancedHue = false) {
539
419
  const endpointId = this.endpoint.id;
540
- const handler = getHandler(endpointId, 'colorControl', 'moveToHueLogic');
541
- log.info(`ColorControl.moveToHueLogic called for endpoint ${endpointId} with hue=${targetHue}, direction=${direction}, transitionTime=${transitionTime}, enhanced=${isEnhancedHue}`);
542
- if (handler) {
543
- try {
544
- handler({ targetHue, direction, transitionTime, isEnhancedHue });
545
- log.info(' ✓ Plugin handler executed successfully');
546
- }
547
- catch (error) {
548
- log.error(' ✗ Error in plugin handler:', error);
549
- }
550
- }
420
+ executeHandler(endpointId, clusterNames.ColorControl, commandNames.ColorControl.moveToHueLogic, { targetHue, direction, transitionTime, isEnhancedHue });
551
421
  const result = super.moveToHueLogic(targetHue, direction, transitionTime, isEnhancedHue);
552
422
  // Sync hue to cache
553
423
  const currentState = this.state;
@@ -558,7 +428,7 @@ export class HomebridgeColorControlServer extends ColorControlServer {
558
428
  else if (currentState.currentHue !== undefined) {
559
429
  stateUpdate.currentHue = currentState.currentHue;
560
430
  }
561
- syncEndpointStateToCache(endpointId, 'colorControl', stateUpdate);
431
+ syncEndpointStateToCache(endpointId, clusterNames.ColorControl, stateUpdate);
562
432
  return result;
563
433
  }
564
434
  /**
@@ -568,22 +438,12 @@ export class HomebridgeColorControlServer extends ColorControlServer {
568
438
  */
569
439
  moveToSaturationLogic(targetSaturation, transitionTime) {
570
440
  const endpointId = this.endpoint.id;
571
- const handler = getHandler(endpointId, 'colorControl', 'moveToSaturationLogic');
572
- log.info(`ColorControl.moveToSaturationLogic called for endpoint ${endpointId} with saturation=${targetSaturation}, transitionTime=${transitionTime}`);
573
- if (handler) {
574
- try {
575
- handler({ targetSaturation, transitionTime });
576
- log.info(' ✓ Plugin handler executed successfully');
577
- }
578
- catch (error) {
579
- log.error(' ✗ Error in plugin handler:', error);
580
- }
581
- }
441
+ executeHandler(endpointId, clusterNames.ColorControl, commandNames.ColorControl.moveToSaturationLogic, { targetSaturation, transitionTime });
582
442
  const result = super.moveToSaturationLogic(targetSaturation, transitionTime);
583
443
  // Sync saturation to cache
584
444
  const currentState = this.state;
585
445
  if (currentState.currentSaturation !== undefined) {
586
- syncEndpointStateToCache(endpointId, 'colorControl', {
446
+ syncEndpointStateToCache(endpointId, clusterNames.ColorControl, {
587
447
  currentSaturation: currentState.currentSaturation,
588
448
  });
589
449
  }
@@ -594,17 +454,7 @@ export class HomebridgeColorControlServer extends ColorControlServer {
594
454
  */
595
455
  stopAllColorMovement() {
596
456
  const endpointId = this.endpoint.id;
597
- const handler = getHandler(endpointId, 'colorControl', 'stopAllColorMovement');
598
- log.info(`ColorControl.stopAllColorMovement called for endpoint ${endpointId}`);
599
- if (handler) {
600
- try {
601
- handler();
602
- log.info(' ✓ Plugin handler executed successfully');
603
- }
604
- catch (error) {
605
- log.error(' ✗ Error in plugin handler:', error);
606
- }
607
- }
457
+ executeHandler(endpointId, clusterNames.ColorControl, commandNames.ColorControl.stopAllColorMovement);
608
458
  return super.stopAllColorMovement();
609
459
  }
610
460
  }
@@ -615,47 +465,17 @@ export class HomebridgeColorControlServer extends ColorControlServer {
615
465
  export class HomebridgeRvcOperationalStateServer extends RvcOperationalStateServer {
616
466
  pause() {
617
467
  const endpointId = this.endpoint.id;
618
- const handler = getHandler(endpointId, 'rvcOperationalState', 'pause');
619
- log.info(`RvcOperationalState.pause called for endpoint ${endpointId}`);
620
- if (handler) {
621
- try {
622
- handler();
623
- log.info(' ✓ Plugin handler executed successfully');
624
- }
625
- catch (error) {
626
- log.error(' ✗ Error in plugin handler:', error);
627
- }
628
- }
468
+ executeHandler(endpointId, clusterNames.RvcOperationalState, commandNames.RvcOperationalState.pause);
629
469
  return super.pause();
630
470
  }
631
471
  resume() {
632
472
  const endpointId = this.endpoint.id;
633
- const handler = getHandler(endpointId, 'rvcOperationalState', 'resume');
634
- log.info(`RvcOperationalState.resume called for endpoint ${endpointId}`);
635
- if (handler) {
636
- try {
637
- handler();
638
- log.info(' ✓ Plugin handler executed successfully');
639
- }
640
- catch (error) {
641
- log.error(' ✗ Error in plugin handler:', error);
642
- }
643
- }
473
+ executeHandler(endpointId, clusterNames.RvcOperationalState, commandNames.RvcOperationalState.resume);
644
474
  return super.resume();
645
475
  }
646
476
  goHome() {
647
477
  const endpointId = this.endpoint.id;
648
- const handler = getHandler(endpointId, 'rvcOperationalState', 'goHome');
649
- log.info(`RvcOperationalState.goHome called for endpoint ${endpointId}`);
650
- if (handler) {
651
- try {
652
- handler();
653
- log.info(' ✓ Plugin handler executed successfully');
654
- }
655
- catch (error) {
656
- log.error(' ✗ Error in plugin handler:', error);
657
- }
658
- }
478
+ executeHandler(endpointId, clusterNames.RvcOperationalState, commandNames.RvcOperationalState.goHome);
659
479
  return super.goHome();
660
480
  }
661
481
  }
@@ -666,17 +486,7 @@ export class HomebridgeRvcOperationalStateServer extends RvcOperationalStateServ
666
486
  export class HomebridgeRvcRunModeServer extends RvcRunModeServer {
667
487
  changeToMode(request) {
668
488
  const endpointId = this.endpoint.id;
669
- const handler = getHandler(endpointId, 'rvcRunMode', 'changeToMode');
670
- log.info(`RvcRunMode.changeToMode called for endpoint ${endpointId} with mode ${request.newMode}`);
671
- if (handler) {
672
- try {
673
- handler(request);
674
- log.info(' ✓ Plugin handler executed successfully');
675
- }
676
- catch (error) {
677
- log.error(' ✗ Error in plugin handler:', error);
678
- }
679
- }
489
+ executeHandler(endpointId, clusterNames.RvcRunMode, commandNames.RvcRunMode.changeToMode, request);
680
490
  return super.changeToMode(request);
681
491
  }
682
492
  }
@@ -687,17 +497,7 @@ export class HomebridgeRvcRunModeServer extends RvcRunModeServer {
687
497
  export class HomebridgeRvcCleanModeServer extends RvcCleanModeServer {
688
498
  changeToMode(request) {
689
499
  const endpointId = this.endpoint.id;
690
- const handler = getHandler(endpointId, 'rvcCleanMode', 'changeToMode');
691
- log.info(`RvcCleanMode.changeToMode called for endpoint ${endpointId} with mode ${request.newMode}`);
692
- if (handler) {
693
- try {
694
- handler(request);
695
- log.info(' ✓ Plugin handler executed successfully');
696
- }
697
- catch (error) {
698
- log.error(' ✗ Error in plugin handler:', error);
699
- }
700
- }
500
+ executeHandler(endpointId, clusterNames.RvcCleanMode, commandNames.RvcCleanMode.changeToMode, request);
701
501
  return super.changeToMode(request);
702
502
  }
703
503
  }
@@ -708,32 +508,12 @@ export class HomebridgeRvcCleanModeServer extends RvcCleanModeServer {
708
508
  export class HomebridgeServiceAreaServer extends ServiceAreaServer {
709
509
  selectAreas(request) {
710
510
  const endpointId = this.endpoint.id;
711
- const handler = getHandler(endpointId, 'serviceArea', 'selectAreas');
712
- log.info(`ServiceArea.selectAreas called for endpoint ${endpointId}`);
713
- if (handler) {
714
- try {
715
- handler(request);
716
- log.info(' ✓ Plugin handler executed successfully');
717
- }
718
- catch (error) {
719
- log.error(' ✗ Error in plugin handler:', error);
720
- }
721
- }
511
+ executeHandler(endpointId, clusterNames.ServiceArea, commandNames.ServiceArea.selectAreas, request);
722
512
  return super.selectAreas(request);
723
513
  }
724
514
  skipArea(request) {
725
515
  const endpointId = this.endpoint.id;
726
- const handler = getHandler(endpointId, 'serviceArea', 'skipArea');
727
- log.info(`ServiceArea.skipArea called for endpoint ${endpointId}`);
728
- if (handler) {
729
- try {
730
- handler(request);
731
- log.info(' ✓ Plugin handler executed successfully');
732
- }
733
- catch (error) {
734
- log.error(' ✗ Error in plugin handler:', error);
735
- }
736
- }
516
+ executeHandler(endpointId, clusterNames.ServiceArea, commandNames.ServiceArea.skipArea, request);
737
517
  return super.skipArea(request);
738
518
  }
739
519
  }