matterbridge 1.4.0 → 1.4.2

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.
Files changed (53) hide show
  1. package/CHANGELOG.md +38 -1
  2. package/README.md +6 -4
  3. package/dist/cluster/AirQualityCluster.d.ts.map +1 -1
  4. package/dist/cluster/AirQualityCluster.js +1 -0
  5. package/dist/cluster/AirQualityCluster.js.map +1 -1
  6. package/dist/cluster/BridgedDeviceBasicInformationCluster.d.ts.map +1 -1
  7. package/dist/cluster/BridgedDeviceBasicInformationCluster.js +1 -0
  8. package/dist/cluster/BridgedDeviceBasicInformationCluster.js.map +1 -1
  9. package/dist/cluster/PowerTopologyCluster.d.ts.map +1 -1
  10. package/dist/cluster/PowerTopologyCluster.js +1 -1
  11. package/dist/cluster/PowerTopologyCluster.js.map +1 -1
  12. package/dist/cluster/TvocCluster.d.ts.map +1 -1
  13. package/dist/cluster/TvocCluster.js +1 -0
  14. package/dist/cluster/TvocCluster.js.map +1 -1
  15. package/dist/deviceManager.d.ts +46 -0
  16. package/dist/deviceManager.d.ts.map +1 -0
  17. package/dist/deviceManager.js +92 -0
  18. package/dist/deviceManager.js.map +1 -0
  19. package/dist/matterbridge.d.ts +21 -76
  20. package/dist/matterbridge.d.ts.map +1 -1
  21. package/dist/matterbridge.js +345 -459
  22. package/dist/matterbridge.js.map +1 -1
  23. package/dist/matterbridgeDevice.d.ts +69 -148
  24. package/dist/matterbridgeDevice.d.ts.map +1 -1
  25. package/dist/matterbridgeDevice.js +232 -30
  26. package/dist/matterbridgeDevice.js.map +1 -1
  27. package/dist/matterbridgePlatform.d.ts +6 -1
  28. package/dist/matterbridgePlatform.d.ts.map +1 -1
  29. package/dist/matterbridgePlatform.js +8 -0
  30. package/dist/matterbridgePlatform.js.map +1 -1
  31. package/dist/matterbridgeTypes.d.ts +28 -1
  32. package/dist/matterbridgeTypes.d.ts.map +1 -1
  33. package/dist/matterbridgeTypes.js +26 -1
  34. package/dist/matterbridgeTypes.js.map +1 -1
  35. package/dist/{plugins.d.ts → pluginManager.d.ts} +6 -3
  36. package/dist/pluginManager.d.ts.map +1 -0
  37. package/dist/{plugins.js → pluginManager.js} +26 -16
  38. package/dist/pluginManager.js.map +1 -0
  39. package/dist/utils/utils.d.ts +57 -0
  40. package/dist/utils/utils.d.ts.map +1 -1
  41. package/dist/utils/utils.js +103 -0
  42. package/dist/utils/utils.js.map +1 -1
  43. package/frontend/build/asset-manifest.json +6 -6
  44. package/frontend/build/index.html +1 -1
  45. package/frontend/build/static/css/{main.df840158.css → main.5174e68c.css} +2 -2
  46. package/frontend/build/static/css/{main.df840158.css.map → main.5174e68c.css.map} +1 -1
  47. package/frontend/build/static/js/{main.2a46688a.js → main.dec34964.js} +3 -3
  48. package/frontend/build/static/js/main.dec34964.js.map +1 -0
  49. package/package.json +26 -25
  50. package/dist/plugins.d.ts.map +0 -1
  51. package/dist/plugins.js.map +0 -1
  52. package/frontend/build/static/js/main.2a46688a.js.map +0 -1
  53. /package/frontend/build/static/js/{main.2a46688a.js.LICENSE.txt → main.dec34964.js.LICENSE.txt} +0 -0
@@ -20,13 +20,13 @@
20
20
  * See the License for the specific language governing permissions and
21
21
  * limitations under the License. *
22
22
  */
23
- import { BasicInformationCluster, BooleanState, BooleanStateCluster, ClusterServer, ColorControl, ColorControlCluster, DoorLock, DoorLockCluster, ElectricalMeasurement, ElectricalMeasurementCluster, FanControl, FanControlCluster, FixedLabelCluster, FlowMeasurement, FlowMeasurementCluster, Groups, GroupsCluster, GroupsClusterHandler, Identify, IdentifyCluster, IlluminanceMeasurement, IlluminanceMeasurementCluster, LevelControl, LevelControlCluster, ModeSelectCluster, OccupancySensing, OccupancySensingCluster, OnOff, OnOffCluster, PowerSource, PowerSourceCluster, PowerSourceConfigurationCluster, PressureMeasurement, PressureMeasurementCluster, RelativeHumidityMeasurement, RelativeHumidityMeasurementCluster, Scenes, ScenesCluster, ScenesClusterHandler, Switch, SwitchCluster, TemperatureMeasurement, TemperatureMeasurementCluster, Thermostat, ThermostatCluster, ThreadNetworkDiagnostics, ThreadNetworkDiagnosticsCluster, TimeSync, TimeSyncCluster, WindowCovering, WindowCoveringCluster, getClusterNameById, } from '@project-chip/matter-node.js/cluster';
23
+ import { BasicInformationCluster, BooleanState, BooleanStateCluster, ClusterServer, ColorControl, ColorControlCluster, DoorLock, DoorLockCluster, FanControl, FanControlCluster, FixedLabelCluster, FlowMeasurement, FlowMeasurementCluster, Groups, GroupsCluster, GroupsClusterHandler, Identify, IdentifyCluster, IlluminanceMeasurement, IlluminanceMeasurementCluster, LevelControl, LevelControlCluster, ModeSelectCluster, OccupancySensing, OccupancySensingCluster, OnOff, OnOffCluster, PowerSource, PowerSourceCluster, PowerSourceConfigurationCluster, PressureMeasurement, PressureMeasurementCluster, RelativeHumidityMeasurement, RelativeHumidityMeasurementCluster, Scenes, ScenesCluster, ScenesClusterHandler, Switch, SwitchCluster, TemperatureMeasurement, TemperatureMeasurementCluster, Thermostat, ThermostatCluster, ThreadNetworkDiagnostics, ThreadNetworkDiagnosticsCluster, TimeSync, TimeSyncCluster, WindowCovering, WindowCoveringCluster, getClusterNameById, } from '@project-chip/matter-node.js/cluster';
24
24
  import { EndpointNumber, GroupId, VendorId } from '@project-chip/matter-node.js/datatype';
25
25
  import { Device, DeviceClasses, DeviceTypeDefinition, Endpoint } from '@project-chip/matter-node.js/device';
26
26
  import { extendPublicHandlerMethods } from '@project-chip/matter-node.js/util';
27
- import { EveHistory, EveHistoryCluster } from 'matter-history';
27
+ import { EveHistory, EveHistoryCluster, MatterHistory } from 'matter-history';
28
+ import { AnsiLogger, CYAN, YELLOW, db, debugStringify, hk, or, zb } from 'node-ansi-logger';
28
29
  import { AirQuality, AirQualityCluster } from './cluster/AirQualityCluster.js';
29
- import { AnsiLogger, CYAN, db, hk, zb } from 'node-ansi-logger';
30
30
  import { createHash } from 'crypto';
31
31
  import { TvocMeasurement, TvocMeasurementCluster } from './cluster/TvocCluster.js';
32
32
  import { BridgedDeviceBasicInformation, BridgedDeviceBasicInformationCluster } from './cluster/BridgedDeviceBasicInformationCluster.js';
@@ -162,7 +162,9 @@ export const colorTemperatureSwitch = DeviceTypeDefinition({
162
162
  });
163
163
  export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
164
164
  static bridgeMode = '';
165
+ static logLevel = "info" /* LogLevel.INFO */;
165
166
  log;
167
+ plugin = undefined;
166
168
  serialNumber = undefined;
167
169
  deviceName = undefined;
168
170
  uniqueId = undefined;
@@ -180,7 +182,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
180
182
  else
181
183
  firstDefinition = definition;
182
184
  super(firstDefinition, options);
183
- this.log = new AnsiLogger({ logName: 'MatterbridgeDevice', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logDebug: debug });
185
+ this.log = new AnsiLogger({ logName: 'MatterbridgeDevice', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: debug === true ? "debug" /* LogLevel.DEBUG */ : MatterbridgeDevice.logLevel });
184
186
  this.log.debug(`new MatterbridgeDevice with deviceType: ${zb}${firstDefinition.code}${db}-${zb}${firstDefinition.name}${db}`);
185
187
  if (Array.isArray(definition)) {
186
188
  definition.forEach((deviceType) => {
@@ -437,9 +439,8 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
437
439
  if (includeServerList.includes(PowerSource.Cluster.id))
438
440
  endpoint.addClusterServer(this.getDefaultPowerSourceWiredClusterServer());
439
441
  if (includeServerList.includes(EveHistory.Cluster.id))
440
- endpoint.addClusterServer(this.getDefaultStaticEveHistoryClusterServer());
441
- if (includeServerList.includes(ElectricalMeasurement.Cluster.id))
442
- endpoint.addClusterServer(this.getDefaultElectricalMeasurementClusterServer());
442
+ endpoint.addClusterServer(MatterHistory.getEveHistoryClusterServer());
443
+ // if (includeServerList.includes(ElectricalMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultElectricalMeasurementClusterServer());
443
444
  if (includeServerList.includes(PowerTopology.Cluster.id))
444
445
  endpoint.addClusterServer(this.getDefaultPowerTopologyClusterServer());
445
446
  if (includeServerList.includes(ElectricalPowerMeasurement.Cluster.id))
@@ -547,6 +548,88 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
547
548
  return endpoint;
548
549
  }
549
550
  }
551
+ /**
552
+ * Retrieves the value of the specified attribute from the given endpoint and cluster.
553
+ *
554
+ * @param {ClusterId} clusterId - The ID of the cluster to retrieve the attribute from.
555
+ * @param {string} attribute - The name of the attribute to retrieve.
556
+ * @param {AnsiLogger} [log] - Optional logger for error and info messages.
557
+ * @param {Endpoint} [endpoint] - Optional the child endpoint to retrieve the attribute from.
558
+ * @returns {any} The value of the attribute, or undefined if the attribute is not found.
559
+ */
560
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
561
+ getAttribute(clusterId, attribute, log, endpoint) {
562
+ if (!endpoint)
563
+ endpoint = this;
564
+ const clusterServer = endpoint.getClusterServerById(clusterId);
565
+ if (!clusterServer) {
566
+ log?.error(`getAttribute error: Cluster ${clusterId} not found on endpoint ${endpoint.name}:${endpoint.number}`);
567
+ return undefined;
568
+ }
569
+ const capitalizedAttributeName = attribute.charAt(0).toUpperCase() + attribute.slice(1);
570
+ if (!clusterServer.isAttributeSupportedByName(attribute) && !clusterServer.isAttributeSupportedByName(capitalizedAttributeName)) {
571
+ if (log)
572
+ log.error(`getAttribute error: Attribute ${attribute} not found on Cluster ${clusterServer.name} on endpoint ${endpoint.name}:${endpoint.number}`);
573
+ return undefined;
574
+ }
575
+ // Find the getter method
576
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
577
+ if (!clusterServer[`get${capitalizedAttributeName}Attribute`]) {
578
+ log?.error(`getAttribute error: Getter get${capitalizedAttributeName}Attribute not found on Cluster ${clusterServer.name} on endpoint ${endpoint.name}:${endpoint.number}`);
579
+ return undefined;
580
+ }
581
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-empty-object-type
582
+ const getter = clusterServer[`get${capitalizedAttributeName}Attribute`];
583
+ const value = getter();
584
+ log?.info(`${db}Get endpoint ${or}${endpoint.name}:${endpoint.number}${db} attribute ${hk}${clusterServer.name}.${capitalizedAttributeName}${db} value ${YELLOW}${typeof value === 'object' ? debugStringify(value) : value}${db}`);
585
+ return value;
586
+ }
587
+ /**
588
+ * Sets the value of an attribute on a cluster server endpoint.
589
+ *
590
+ * @param {ClusterId} clusterId - The ID of the cluster.
591
+ * @param {string} attribute - The name of the attribute.
592
+ * @param {any} value - The value to set for the attribute.
593
+ * @param {AnsiLogger} [log] - (Optional) The logger to use for logging errors and information.
594
+ * @param {Endpoint} [endpoint] - (Optional) The endpoint to set the attribute on. If not provided, the attribute will be set on the current endpoint.
595
+ */
596
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
597
+ setAttribute(clusterId, attribute, value, log, endpoint) {
598
+ if (!endpoint)
599
+ endpoint = this;
600
+ const clusterServer = endpoint.getClusterServerById(clusterId);
601
+ if (!clusterServer) {
602
+ log?.error(`setAttribute error: Cluster ${clusterId} not found on endpoint ${endpoint.name}:${endpoint.number}`);
603
+ return;
604
+ }
605
+ const capitalizedAttributeName = attribute.charAt(0).toUpperCase() + attribute.slice(1);
606
+ if (!clusterServer.isAttributeSupportedByName(attribute) && !clusterServer.isAttributeSupportedByName(capitalizedAttributeName)) {
607
+ if (log)
608
+ log.error(`setAttribute error: Attribute ${attribute} not found on Cluster ${clusterId} on endpoint ${endpoint.name}:${endpoint.number}`);
609
+ return;
610
+ }
611
+ // Find the getter method
612
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
613
+ if (!clusterServer[`get${capitalizedAttributeName}Attribute`]) {
614
+ log?.error(`setAttribute error: Getter get${capitalizedAttributeName}Attribute not found on Cluster ${clusterServer.name} on endpoint ${endpoint.name}:${endpoint.number}`);
615
+ return;
616
+ }
617
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-empty-object-type
618
+ const getter = clusterServer[`get${capitalizedAttributeName}Attribute`];
619
+ // Find the setter method
620
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
621
+ if (!clusterServer[`set${capitalizedAttributeName}Attribute`]) {
622
+ log?.error(`setAttribute error: Setter set${capitalizedAttributeName}Attribute not found on Cluster ${clusterServer.name} on endpoint ${endpoint.name}:${endpoint.number}`);
623
+ return;
624
+ }
625
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-empty-object-type
626
+ const setter = clusterServer[`set${capitalizedAttributeName}Attribute`];
627
+ const oldValue = getter();
628
+ setter(value);
629
+ log?.info(`${db}Set endpoint ${or}${endpoint.name}:${endpoint.number}${db} attribute ${hk}${clusterServer.name}.${capitalizedAttributeName}${db} ` +
630
+ `from ${YELLOW}${typeof oldValue === 'object' ? debugStringify(oldValue) : oldValue}${db} ` +
631
+ `to ${YELLOW}${typeof value === 'object' ? debugStringify(value) : value}${db}`);
632
+ }
550
633
  /**
551
634
  * Serializes the Matterbridge device into a serialized object.
552
635
  *
@@ -601,7 +684,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
601
684
  /**
602
685
  * Returns a default static EveHistoryClusterServer object with the specified voltage, current, power, and consumption values.
603
686
  * This shows up in HA as a static sensor!
604
- * @deprecated This method is deprecated and will be removed in a future version.
687
+ * @deprecated This method is deprecated and will be removed in a future version. Use MatterHistory.
605
688
  * @param voltage - The voltage value (default: 0).
606
689
  * @param current - The current value (default: 0).
607
690
  * @param power - The power value (default: 0).
@@ -632,7 +715,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
632
715
  /**
633
716
  * Create a default static EveHistoryClusterServer object with the specified voltage, current, power, and consumption values.
634
717
  * This shows up in HA as a static sensor!
635
- * @deprecated This method is deprecated and will be removed in a future version.
718
+ * @deprecated This method is deprecated and will be removed in a future version. Use MatterHistory.
636
719
  * @param voltage - The voltage value (default: 0).
637
720
  * @param current - The current value (default: 0).
638
721
  * @param power - The power value (default: 0).
@@ -644,7 +727,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
644
727
  }
645
728
  /**
646
729
  * Creates a room Eve History Cluster Server.
647
- * @deprecated This method is deprecated and will be removed in a future version.
730
+ * @deprecated This method is deprecated and will be removed in a future version. Use MatterHistory.
648
731
  *
649
732
  * @param history - The MatterHistory object.
650
733
  * @param log - The AnsiLogger object.
@@ -703,7 +786,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
703
786
  }
704
787
  /**
705
788
  * Creates a Weather Eve History Cluster Server.
706
- * @deprecated This method is deprecated and will be removed in a future version.
789
+ * @deprecated This method is deprecated and will be removed in a future version. Use MatterHistory.
707
790
  *
708
791
  * @param history - The MatterHistory instance.
709
792
  * @param log - The AnsiLogger instance.
@@ -765,7 +848,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
765
848
  }
766
849
  /**
767
850
  * Creates an Energy Eve History Cluster Server.
768
- * @deprecated This method is deprecated and will be removed in a future version.
851
+ * @deprecated This method is deprecated and will be removed in a future version. Use MatterHistory.
769
852
  *
770
853
  * @param history - The MatterHistory object.
771
854
  * @param log - The AnsiLogger object.
@@ -843,7 +926,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
843
926
  }
844
927
  /**
845
928
  * Creates a Motion Eve History Cluster Server.
846
- * @deprecated This method is deprecated and will be removed in a future version.
929
+ * @deprecated This method is deprecated and will be removed in a future version. Use MatterHistory.
847
930
  *
848
931
  * @param history - The MatterHistory object.
849
932
  * @param log - The AnsiLogger object.
@@ -907,7 +990,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
907
990
  }
908
991
  /**
909
992
  * Creates a door EveHistoryCluster server.
910
- * @deprecated This method is deprecated and will be removed in a future version.
993
+ * @deprecated This method is deprecated and will be removed in a future version. Use MatterHistory.
911
994
  *
912
995
  * @param history - The MatterHistory instance.
913
996
  * @param log - The AnsiLogger instance.
@@ -1150,6 +1233,9 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
1150
1233
  hardwareVersionString: hardwareVersionString.slice(0, 64),
1151
1234
  reachable: true,
1152
1235
  }, {}, {
1236
+ startUp: true,
1237
+ shutDown: true,
1238
+ leave: true,
1153
1239
  reachableChanged: true,
1154
1240
  });
1155
1241
  }
@@ -1173,9 +1259,8 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
1173
1259
  this.addClusterServer(this.getDefaultBridgedDeviceBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productName, softwareVersion, softwareVersionString, hardwareVersion, hardwareVersionString));
1174
1260
  }
1175
1261
  /**
1176
- * Get a default Electrical Energy Measurement Cluster Server.
1262
+ * Get a default Power Topology Cluster Server.
1177
1263
  *
1178
- * @param energy - The total consumption value.
1179
1264
  */
1180
1265
  getDefaultPowerTopologyClusterServer() {
1181
1266
  return ClusterServer(PowerTopologyCluster.with(PowerTopology.Feature.TreeTopology), {}, {}, {});
@@ -1246,14 +1331,21 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
1246
1331
  * @param power - The active power value.
1247
1332
  * @param consumption - The total active power consumption value.
1248
1333
  */
1334
+ /*
1249
1335
  getDefaultElectricalMeasurementClusterServer(voltage = 0, current = 0, power = 0, consumption = 0) {
1250
- return ClusterServer(ElectricalMeasurementCluster, {
1251
- rmsVoltage: voltage,
1252
- rmsCurrent: current,
1253
- activePower: power,
1254
- totalActivePower: consumption,
1255
- }, {}, {});
1336
+ return ClusterServer(
1337
+ ElectricalMeasurementCluster,
1338
+ {
1339
+ rmsVoltage: voltage,
1340
+ rmsCurrent: current,
1341
+ activePower: power,
1342
+ totalActivePower: consumption,
1343
+ },
1344
+ {},
1345
+ {},
1346
+ );
1256
1347
  }
1348
+ */
1257
1349
  /**
1258
1350
  * @deprecated This method is deprecated and will be removed in a future version.
1259
1351
  * Creates a default Electrical Measurement Cluster Server.
@@ -1263,12 +1355,14 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
1263
1355
  * @param power - The active power value.
1264
1356
  * @param consumption - The total active power consumption value.
1265
1357
  */
1358
+ /*
1266
1359
  createDefaultElectricalMeasurementClusterServer(voltage = 0, current = 0, power = 0, consumption = 0) {
1267
- this.addClusterServer(this.getDefaultElectricalMeasurementClusterServer(voltage, current, power, consumption));
1360
+ this.addClusterServer(this.getDefaultElectricalMeasurementClusterServer(voltage, current, power, consumption));
1268
1361
  }
1362
+ */
1269
1363
  /**
1270
1364
  * Creates a default Dummy Thread Network Diagnostics Cluster server.
1271
- * @deprecated This method is deprecated and is only for testing.
1365
+ * @deprecated This method is deprecated and is only used for testing.
1272
1366
  *
1273
1367
  * @remarks
1274
1368
  * This method adds a cluster server used only to give the networkName to Eve app.
@@ -1554,6 +1648,39 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
1554
1648
  createDefaultXYColorControlClusterServer(currentX = 0, currentY = 0, colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
1555
1649
  this.addClusterServer(this.getDefaultXYColorControlClusterServer(currentX, currentY, colorTemperatureMireds, colorTempPhysicalMinMireds, colorTempPhysicalMaxMireds));
1556
1650
  }
1651
+ /**
1652
+ * Configures the color control cluster for a device.
1653
+ *
1654
+ * @param {boolean} hueSaturation - A boolean indicating whether the device supports hue and saturation control.
1655
+ * @param {boolean} xy - A boolean indicating whether the device supports XY control.
1656
+ * @param {boolean} colorTemperature - A boolean indicating whether the device supports color temperature control.
1657
+ * @param {ColorControl.ColorMode} colorMode - An optional parameter specifying the color mode of the device.
1658
+ * @param {Endpoint} endpoint - An optional parameter specifying the endpoint to configure. If not provided, the device endpoint will be used.
1659
+ */
1660
+ configureColorControlCluster(hueSaturation, xy, colorTemperature, colorMode, endpoint) {
1661
+ if (!endpoint)
1662
+ endpoint = this;
1663
+ endpoint.getClusterServer(ColorControlCluster)?.setFeatureMapAttribute({ hueSaturation, enhancedHue: false, colorLoop: false, xy, colorTemperature });
1664
+ endpoint.getClusterServer(ColorControlCluster)?.setColorCapabilitiesAttribute({ hueSaturation, enhancedHue: false, colorLoop: false, xy, colorTemperature });
1665
+ if (colorMode !== undefined && colorMode >= 0 && colorMode <= 2) {
1666
+ endpoint.getClusterServer(ColorControlCluster)?.setColorModeAttribute(colorMode);
1667
+ endpoint.getClusterServer(ColorControlCluster)?.setEnhancedColorModeAttribute(colorMode);
1668
+ }
1669
+ }
1670
+ /**
1671
+ * Configures the color control mode for the device.
1672
+ *
1673
+ * @param {ColorControl.ColorMode} colorMode - The color mode to set.
1674
+ * @param {Endpoint} endpoint - The optional endpoint to configure. If not provided, the method will configure the current endpoint.
1675
+ */
1676
+ configureColorControlMode(colorMode, endpoint) {
1677
+ if (!endpoint)
1678
+ endpoint = this;
1679
+ if (colorMode !== undefined && colorMode >= 0 && colorMode <= 2) {
1680
+ endpoint.getClusterServer(ColorControlCluster)?.setColorModeAttribute(colorMode);
1681
+ endpoint.getClusterServer(ColorControlCluster)?.setEnhancedColorModeAttribute(colorMode);
1682
+ }
1683
+ }
1557
1684
  /**
1558
1685
  * Get a default window covering cluster server.
1559
1686
  *
@@ -1608,6 +1735,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
1608
1735
  }
1609
1736
  /**
1610
1737
  * Sets the window covering target position as the current position and stops the movement.
1738
+ * @param {Endpoint} endpoint - The endpoint on which to set the window covering (default the device endpoint).
1611
1739
  */
1612
1740
  setWindowCoveringTargetAsCurrentAndStopped(endpoint) {
1613
1741
  if (!endpoint)
@@ -1620,7 +1748,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
1620
1748
  windowCoveringCluster.setOperationalStatusAttribute({
1621
1749
  global: WindowCovering.MovementStatus.Stopped,
1622
1750
  lift: WindowCovering.MovementStatus.Stopped,
1623
- tilt: 0,
1751
+ tilt: WindowCovering.MovementStatus.Stopped,
1624
1752
  });
1625
1753
  }
1626
1754
  this.log.debug(`Set WindowCovering currentPositionLiftPercent100ths and targetPositionLiftPercent100ths to ${position} and operationalStatus to Stopped.`);
@@ -1628,9 +1756,10 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
1628
1756
  }
1629
1757
  /**
1630
1758
  * Sets the current and target status of a window covering.
1631
- * @param current - The current position of the window covering.
1632
- * @param target - The target position of the window covering.
1633
- * @param status - The movement status of the window covering.
1759
+ * @param {number} current - The current position of the window covering.
1760
+ * @param {number} target - The target position of the window covering.
1761
+ * @param {WindowCovering.MovementStatus} status - The movement status of the window covering.
1762
+ * @param {Endpoint} endpoint - The endpoint on which to set the window covering (default the device endpoint).
1634
1763
  */
1635
1764
  setWindowCoveringCurrentTargetStatus(current, target, status, endpoint) {
1636
1765
  if (!endpoint)
@@ -1642,7 +1771,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
1642
1771
  windowCoveringCluster.setOperationalStatusAttribute({
1643
1772
  global: status,
1644
1773
  lift: status,
1645
- tilt: 0,
1774
+ tilt: status,
1646
1775
  });
1647
1776
  }
1648
1777
  this.log.debug(`Set WindowCovering currentPositionLiftPercent100ths: ${current}, targetPositionLiftPercent100ths: ${target} and operationalStatus: ${status}.`);
@@ -1650,6 +1779,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
1650
1779
  /**
1651
1780
  * Sets the status of the window covering.
1652
1781
  * @param {WindowCovering.MovementStatus} status - The movement status to set.
1782
+ * @param {Endpoint} endpoint - The endpoint on which to set the window covering (default the device endpoint).
1653
1783
  */
1654
1784
  setWindowCoveringStatus(status, endpoint) {
1655
1785
  if (!endpoint)
@@ -1657,11 +1787,13 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
1657
1787
  const windowCovering = endpoint.getClusterServer(WindowCoveringCluster.with(WindowCovering.Feature.Lift, WindowCovering.Feature.PositionAwareLift, WindowCovering.Feature.AbsolutePosition));
1658
1788
  if (!windowCovering)
1659
1789
  return;
1660
- windowCovering.setOperationalStatusAttribute({ global: status, lift: status, tilt: 0 });
1790
+ windowCovering.setOperationalStatusAttribute({ global: status, lift: status, tilt: status });
1661
1791
  this.log.debug(`Set WindowCovering operationalStatus: ${status}`);
1662
1792
  }
1663
1793
  /**
1664
1794
  * Retrieves the status of the window covering.
1795
+ * @param {Endpoint} endpoint - The endpoint on which to get the window covering (default the device endpoint).
1796
+ *
1665
1797
  * @returns The global operational status of the window covering.
1666
1798
  */
1667
1799
  getWindowCoveringStatus(endpoint) {
@@ -1678,6 +1810,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
1678
1810
  * Sets the target and current position of the window covering.
1679
1811
  *
1680
1812
  * @param position - The position to set, specified as a number.
1813
+ * @param {Endpoint} endpoint - The endpoint on which to set the window covering (default the device endpoint).
1681
1814
  */
1682
1815
  setWindowCoveringTargetAndCurrentPosition(position, endpoint) {
1683
1816
  if (!endpoint)
@@ -1784,6 +1917,75 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
1784
1917
  this.addFixedLabel('orientation', 'Switch');
1785
1918
  this.addFixedLabel('label', 'Switch');
1786
1919
  }
1920
+ /**
1921
+ * Triggers a switch event on the specified endpoint.
1922
+ *
1923
+ * @param {string} event - The type of event to trigger. Possible values are 'Single', 'Double', 'Long', 'Press', and 'Release'.
1924
+ * @param {Endpoint} endpoint - The endpoint on which to trigger the event (default the device endpoint).
1925
+ * @returns {void}
1926
+ */
1927
+ triggerSwitchEvent(event, endpoint, log) {
1928
+ if (!endpoint)
1929
+ endpoint = this;
1930
+ if (['Single', 'Double', 'Long'].includes(event)) {
1931
+ const cluster = endpoint.getClusterServer(SwitchCluster.with(Switch.Feature.MomentarySwitch, Switch.Feature.MomentarySwitchRelease, Switch.Feature.MomentarySwitchLongPress, Switch.Feature.MomentarySwitchMultiPress));
1932
+ if (!cluster || !cluster.getFeatureMapAttribute().momentarySwitch) {
1933
+ log?.error(`triggerSwitchEvent ${event} error: Switch cluster with MomentarySwitch not found on endpoint ${endpoint.name}:${endpoint.number}`);
1934
+ return;
1935
+ }
1936
+ if (event === 'Single') {
1937
+ cluster.setCurrentPositionAttribute(1);
1938
+ cluster.triggerInitialPressEvent({ newPosition: 1 });
1939
+ cluster.setCurrentPositionAttribute(0);
1940
+ cluster.triggerShortReleaseEvent({ previousPosition: 1 });
1941
+ cluster.setCurrentPositionAttribute(0);
1942
+ cluster.triggerMultiPressCompleteEvent({ previousPosition: 1, totalNumberOfPressesCounted: 1 });
1943
+ log?.info(`${db}Trigger endpoint ${or}${endpoint.name}:${endpoint.number}${db} event ${hk}${cluster.name}.SinglePress${db}`);
1944
+ }
1945
+ if (event === 'Double') {
1946
+ cluster.setCurrentPositionAttribute(1);
1947
+ cluster.triggerInitialPressEvent({ newPosition: 1 });
1948
+ cluster.setCurrentPositionAttribute(0);
1949
+ cluster.triggerShortReleaseEvent({ previousPosition: 1 });
1950
+ cluster.setCurrentPositionAttribute(1);
1951
+ cluster.triggerInitialPressEvent({ newPosition: 1 });
1952
+ cluster.triggerMultiPressOngoingEvent({ newPosition: 1, currentNumberOfPressesCounted: 2 });
1953
+ cluster.setCurrentPositionAttribute(0);
1954
+ cluster.triggerShortReleaseEvent({ previousPosition: 1 });
1955
+ cluster.triggerMultiPressCompleteEvent({ previousPosition: 1, totalNumberOfPressesCounted: 2 });
1956
+ log?.info(`${db}Trigger endpoint ${or}${endpoint.name}:${endpoint.number}${db} event ${hk}${cluster.name}.DoublePress${db}`);
1957
+ }
1958
+ if (event === 'Long') {
1959
+ cluster.setCurrentPositionAttribute(1);
1960
+ cluster.triggerInitialPressEvent({ newPosition: 1 });
1961
+ cluster.triggerLongPressEvent({ newPosition: 1 });
1962
+ cluster.setCurrentPositionAttribute(0);
1963
+ cluster.triggerLongReleaseEvent({ previousPosition: 1 });
1964
+ log?.info(`${db}Trigger endpoint ${or}${endpoint.name}:${endpoint.number}${db} event ${hk}${cluster.name}.LongPress${db}`);
1965
+ }
1966
+ }
1967
+ if (['Press', 'Release'].includes(event)) {
1968
+ const cluster = endpoint.getClusterServer(Switch.Complete);
1969
+ if (!cluster || !cluster.getFeatureMapAttribute().latchingSwitch) {
1970
+ log?.error(`triggerSwitchEvent ${event} error: Switch cluster with LatchingSwitch not found on endpoint ${endpoint.name}:${endpoint.number}`);
1971
+ return;
1972
+ }
1973
+ if (event === 'Press') {
1974
+ cluster.setCurrentPositionAttribute(1);
1975
+ log?.info(`${db}Update endpoint ${or}${endpoint.name}:${endpoint.number}${db} attribute ${hk}${cluster.name}.CurrentPosition${db} to ${YELLOW}1${db}`);
1976
+ if (cluster.triggerSwitchLatchedEvent)
1977
+ cluster.triggerSwitchLatchedEvent({ newPosition: 1 });
1978
+ log?.info(`${db}Trigger endpoint ${or}${endpoint.name}:${endpoint.number}${db} event ${hk}${cluster.name}.Press${db}`);
1979
+ }
1980
+ if (event === 'Release') {
1981
+ cluster.setCurrentPositionAttribute(0);
1982
+ log?.info(`${db}Update endpoint ${or}${endpoint.name}:${endpoint.number}${db} attribute ${hk}${cluster.name}.CurrentPosition${db} to ${YELLOW}0${db}`);
1983
+ if (cluster.triggerSwitchLatchedEvent)
1984
+ cluster.triggerSwitchLatchedEvent({ newPosition: 0 });
1985
+ log?.info(`${db}Trigger endpoint ${or}${endpoint.name}:${endpoint.number}${db} event ${hk}${cluster.name}.Release${db}`);
1986
+ }
1987
+ }
1988
+ }
1787
1989
  /**
1788
1990
  * Retrieves the default mode select cluster server.
1789
1991
  *