matterbridge 2.0.0-edge1 → 2.1.0-dev.1

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 (82) hide show
  1. package/CHANGELOG.md +36 -3
  2. package/README.md +1 -1
  3. package/dist/cli.js +0 -26
  4. package/dist/cluster/export.js +0 -2
  5. package/dist/defaultConfigSchema.js +0 -23
  6. package/dist/deviceManager.js +2 -27
  7. package/dist/frontend.js +99 -245
  8. package/dist/index.js +2 -33
  9. package/dist/logger/export.js +0 -1
  10. package/dist/matter/export.js +0 -7
  11. package/dist/matterbridge.js +99 -710
  12. package/dist/matterbridgeAccessoryPlatform.js +0 -33
  13. package/dist/matterbridgeBehaviors.js +42 -32
  14. package/dist/matterbridgeDeviceTypes.js +90 -84
  15. package/dist/matterbridgeDynamicPlatform.js +0 -33
  16. package/dist/matterbridgeEndpoint.js +992 -2454
  17. package/dist/matterbridgePlatform.js +11 -130
  18. package/dist/matterbridgeTypes.js +0 -25
  19. package/dist/pluginManager.js +7 -251
  20. package/dist/storage/export.js +0 -1
  21. package/dist/utils/colorUtils.js +2 -205
  22. package/dist/utils/export.js +0 -1
  23. package/dist/utils/utils.js +10 -255
  24. package/frontend/build/asset-manifest.json +3 -3
  25. package/frontend/build/index.html +1 -1
  26. package/frontend/build/static/js/{main.ea28015b.js → main.26dbf9b9.js} +3 -3
  27. package/frontend/build/static/js/main.26dbf9b9.js.map +1 -0
  28. package/npm-shrinkwrap.json +97 -79
  29. package/package.json +2 -4
  30. package/dist/cli.d.ts.map +0 -1
  31. package/dist/cli.js.map +0 -1
  32. package/dist/cluster/export.d.ts.map +0 -1
  33. package/dist/cluster/export.js.map +0 -1
  34. package/dist/defaultConfigSchema.d.ts.map +0 -1
  35. package/dist/defaultConfigSchema.js.map +0 -1
  36. package/dist/deviceManager.d.ts +0 -46
  37. package/dist/deviceManager.d.ts.map +0 -1
  38. package/dist/deviceManager.js.map +0 -1
  39. package/dist/frontend.d.ts +0 -98
  40. package/dist/frontend.d.ts.map +0 -1
  41. package/dist/frontend.js.map +0 -1
  42. package/dist/index.d.ts.map +0 -1
  43. package/dist/index.js.map +0 -1
  44. package/dist/logger/export.d.ts.map +0 -1
  45. package/dist/logger/export.js.map +0 -1
  46. package/dist/matter/export.d.ts.map +0 -1
  47. package/dist/matter/export.js.map +0 -1
  48. package/dist/matterbridge.d.ts +0 -357
  49. package/dist/matterbridge.d.ts.map +0 -1
  50. package/dist/matterbridge.js.map +0 -1
  51. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  52. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  53. package/dist/matterbridgeBehaviors.d.ts +0 -123
  54. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  55. package/dist/matterbridgeBehaviors.js.map +0 -1
  56. package/dist/matterbridgeDeviceTypes.d.ts +0 -109
  57. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  58. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  59. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  60. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  61. package/dist/matterbridgeEndpoint.d.ts +0 -1167
  62. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  63. package/dist/matterbridgeEndpoint.js.map +0 -1
  64. package/dist/matterbridgePlatform.d.ts +0 -154
  65. package/dist/matterbridgePlatform.d.ts.map +0 -1
  66. package/dist/matterbridgePlatform.js.map +0 -1
  67. package/dist/matterbridgeTypes.d.ts.map +0 -1
  68. package/dist/matterbridgeTypes.js.map +0 -1
  69. package/dist/pluginManager.d.ts +0 -238
  70. package/dist/pluginManager.d.ts.map +0 -1
  71. package/dist/pluginManager.js.map +0 -1
  72. package/dist/storage/export.d.ts.map +0 -1
  73. package/dist/storage/export.js.map +0 -1
  74. package/dist/utils/colorUtils.d.ts.map +0 -1
  75. package/dist/utils/colorUtils.js.map +0 -1
  76. package/dist/utils/export.d.ts.map +0 -1
  77. package/dist/utils/export.js.map +0 -1
  78. package/dist/utils/utils.d.ts +0 -221
  79. package/dist/utils/utils.d.ts.map +0 -1
  80. package/dist/utils/utils.js.map +0 -1
  81. package/frontend/build/static/js/main.ea28015b.js.map +0 -1
  82. /package/frontend/build/static/js/{main.ea28015b.js.LICENSE.txt → main.26dbf9b9.js.LICENSE.txt} +0 -0
@@ -1,56 +1,323 @@
1
- /**
2
- * This file contains the class MatterbridgeEndpoint that extends the Endpoint class from the Matter.js library.
3
- *
4
- * @file matterbridgeEndpoint.ts
5
- * @author Luca Liguori
6
- * @date 2024-10-01
7
- * @version 1.0.0
8
- *
9
- * Copyright 2024, 2025, 2026 Luca Liguori.
10
- *
11
- * Licensed under the Apache License, Version 2.0 (the "License");
12
- * you may not use this file except in compliance with the License.
13
- * You may obtain a copy of the License at
14
- *
15
- * http://www.apache.org/licenses/LICENSE-2.0
16
- *
17
- * Unless required by applicable law or agreed to in writing, software
18
- * distributed under the License is distributed on an "AS IS" BASIS,
19
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
- * See the License for the specific language governing permissions and
21
- * limitations under the License. *
22
- */
23
- /* eslint-disable @typescript-eslint/no-unused-vars */
24
- // Node.js modules
25
1
  import { createHash } from 'crypto';
26
- // AnsiLogger module
27
- import { AnsiLogger, BLUE, CYAN, LogLevel, TimestampFormat, YELLOW, db, debugStringify, er, hk, or, rs, zb } from 'node-ansi-logger';
28
- // Matterbridge
29
- import { MatterbridgeBehavior, MatterbridgeBehaviorDevice, MatterbridgeBooleanStateConfigurationServer, MatterbridgeColorControlServer, MatterbridgeDoorLockServer, MatterbridgeFanControlServer, MatterbridgeIdentifyServer, MatterbridgeLevelControlServer, MatterbridgeOnOffServer, MatterbridgeThermostatServer, MatterbridgeValveConfigurationAndControlServer, MatterbridgeWindowCoveringServer, } from './matterbridgeBehaviors.js';
2
+ import { AnsiLogger, BLUE, CYAN, YELLOW, db, debugStringify, er, hk, or, zb } from './logger/export.js';
30
3
  import { bridgedNode } from './matterbridgeDeviceTypes.js';
31
4
  import { deepCopy, isValidNumber } from './utils/utils.js';
32
- // @matter
33
- import { Endpoint, MutableEndpoint, SupportedBehaviors, NamedHandler, Lifecycle } from '@matter/main';
34
- import { EndpointNumber, VendorId } from '@matter/main';
35
- import { AirQuality, AirQualityCluster, BasicInformation, BasicInformationCluster, BooleanState, BooleanStateCluster, BooleanStateConfiguration, BooleanStateConfigurationCluster, BridgedDeviceBasicInformation, BridgedDeviceBasicInformationCluster, CarbonDioxideConcentrationMeasurement, CarbonDioxideConcentrationMeasurementCluster, CarbonMonoxideConcentrationMeasurement, CarbonMonoxideConcentrationMeasurementCluster, ColorControl, ColorControlCluster, ConcentrationMeasurement, Descriptor, DoorLock, DoorLockCluster, ElectricalEnergyMeasurement, ElectricalEnergyMeasurementCluster, ElectricalPowerMeasurement, ElectricalPowerMeasurementCluster, FanControl, FanControlCluster, FixedLabel, FixedLabelCluster, FlowMeasurement, FlowMeasurementCluster, FormaldehydeConcentrationMeasurement, FormaldehydeConcentrationMeasurementCluster, Groups, GroupsCluster, Identify, IdentifyCluster, IlluminanceMeasurement, IlluminanceMeasurementCluster, LevelControl, LevelControlCluster, ModeSelect, ModeSelectCluster, NitrogenDioxideConcentrationMeasurement, NitrogenDioxideConcentrationMeasurementCluster, OccupancySensing, OccupancySensingCluster, OnOff, OnOffCluster, OzoneConcentrationMeasurement, OzoneConcentrationMeasurementCluster, Pm10ConcentrationMeasurement, Pm10ConcentrationMeasurementCluster, Pm1ConcentrationMeasurement, Pm1ConcentrationMeasurementCluster, Pm25ConcentrationMeasurement, Pm25ConcentrationMeasurementCluster, PowerSource, PowerSourceCluster, PowerSourceConfigurationCluster, PowerTopology, PowerTopologyCluster, PressureMeasurement, PressureMeasurementCluster, PumpConfigurationAndControl, PumpConfigurationAndControlCluster, RadonConcentrationMeasurement, RadonConcentrationMeasurementCluster, RelativeHumidityMeasurement, RelativeHumidityMeasurementCluster, SmokeCoAlarm, SmokeCoAlarmCluster, Switch, SwitchCluster, TemperatureMeasurement, TemperatureMeasurementCluster, Thermostat, ThermostatCluster, TotalVolatileOrganicCompoundsConcentrationMeasurement, TotalVolatileOrganicCompoundsConcentrationMeasurementCluster, UserLabel, UserLabelCluster, ValveConfigurationAndControl, ValveConfigurationAndControlCluster, WindowCovering, WindowCoveringCluster, } from '@matter/main/clusters';
36
- import { MeasurementType, getClusterNameById } from '@matter/main/types';
37
- import { Specification } from '@matter/main/model';
38
- import { DescriptorServer } from '@matter/node/behaviors/descriptor';
39
- import { IdentifyBehavior } from '@matter/node/behaviors/identify';
40
- import { GroupsServer } from '@matter/node/behaviors/groups';
41
- import { TemperatureMeasurementServer } from '@matter/node/behaviors/temperature-measurement';
42
- import { RelativeHumidityMeasurementServer } from '@matter/node/behaviors/relative-humidity-measurement';
43
- import { PressureMeasurementServer } from '@matter/node/behaviors/pressure-measurement';
44
- import { BridgedDeviceBasicInformationServer } from '@matter/node/behaviors/bridged-device-basic-information';
45
- import { FlowMeasurementServer } from '@matter/node/behaviors/flow-measurement';
46
- import { IlluminanceMeasurementServer } from '@matter/node/behaviors/illuminance-measurement';
47
- import { BooleanStateServer } from '@matter/node/behaviors/boolean-state';
48
- import { OccupancySensingServer } from '@matter/node/behaviors/occupancy-sensing';
49
- import { AirQualityServer, BasicInformationServer, CarbonDioxideConcentrationMeasurementServer, CarbonMonoxideConcentrationMeasurementServer, ElectricalEnergyMeasurementServer, ElectricalPowerMeasurementServer, FixedLabelServer, FormaldehydeConcentrationMeasurementServer, ModeSelectServer, NitrogenDioxideConcentrationMeasurementServer, OzoneConcentrationMeasurementServer, Pm10ConcentrationMeasurementServer, Pm1ConcentrationMeasurementServer, Pm25ConcentrationMeasurementServer, PowerSourceServer, PowerTopologyServer, RadonConcentrationMeasurementServer, SmokeCoAlarmServer, SwitchServer, TotalVolatileOrganicCompoundsConcentrationMeasurementServer, UserLabelServer, } from '@matter/main/behaviors';
50
- import { ClusterServer, GroupsClusterHandler } from '@project-chip/matter.js/cluster';
5
+ import { MatterbridgeBehavior, MatterbridgeBehaviorDevice, MatterbridgeIdentifyServer, MatterbridgeOnOffServer, MatterbridgeLevelControlServer, MatterbridgeColorControlServer, MatterbridgeWindowCoveringServer, MatterbridgeThermostatServer, MatterbridgeFanControlServer, MatterbridgeDoorLockServer, MatterbridgeModeSelectServer, MatterbridgeValveConfigurationAndControlServer, MatterbridgeSmokeCoAlarmServer, MatterbridgeBooleanStateConfigurationServer, } from './matterbridgeBehaviors.js';
6
+ import { Endpoint, Lifecycle, MutableEndpoint, NamedHandler, SupportedBehaviors, VendorId } from '@matter/main';
7
+ import { getClusterNameById, MeasurementType } from '@matter/main/types';
8
+ import { Descriptor } from '@matter/main/clusters/descriptor';
9
+ import { PowerSource } from '@matter/main/clusters/power-source';
10
+ import { UserLabel } from '@matter/main/clusters/user-label';
11
+ import { FixedLabel } from '@matter/main/clusters/fixed-label';
12
+ import { BasicInformation } from '@matter/main/clusters/basic-information';
13
+ import { BridgedDeviceBasicInformation } from '@matter/main/clusters/bridged-device-basic-information';
14
+ import { Identify } from '@matter/main/clusters/identify';
15
+ import { Groups } from '@matter/main/clusters/groups';
16
+ import { OnOff } from '@matter/main/clusters/on-off';
17
+ import { LevelControl } from '@matter/main/clusters/level-control';
18
+ import { ColorControl } from '@matter/main/clusters/color-control';
19
+ import { WindowCovering } from '@matter/main/clusters/window-covering';
20
+ import { Thermostat } from '@matter/main/clusters/thermostat';
21
+ import { FanControl } from '@matter/main/clusters/fan-control';
22
+ import { DoorLock } from '@matter/main/clusters/door-lock';
23
+ import { ModeSelect } from '@matter/main/clusters/mode-select';
24
+ import { ValveConfigurationAndControl } from '@matter/main/clusters/valve-configuration-and-control';
25
+ import { PumpConfigurationAndControl } from '@matter/main/clusters/pump-configuration-and-control';
26
+ import { SmokeCoAlarm } from '@matter/main/clusters/smoke-co-alarm';
27
+ import { Switch } from '@matter/main/clusters/switch';
28
+ import { BooleanState } from '@matter/main/clusters/boolean-state';
29
+ import { BooleanStateConfiguration } from '@matter/main/clusters/boolean-state-configuration';
30
+ import { PowerTopology } from '@matter/main/clusters/power-topology';
31
+ import { ElectricalPowerMeasurement } from '@matter/main/clusters/electrical-power-measurement';
32
+ import { ElectricalEnergyMeasurement } from '@matter/main/clusters/electrical-energy-measurement';
33
+ import { TemperatureMeasurement } from '@matter/main/clusters/temperature-measurement';
34
+ import { RelativeHumidityMeasurement } from '@matter/main/clusters/relative-humidity-measurement';
35
+ import { PressureMeasurement } from '@matter/main/clusters/pressure-measurement';
36
+ import { FlowMeasurement } from '@matter/main/clusters/flow-measurement';
37
+ import { IlluminanceMeasurement } from '@matter/main/clusters/illuminance-measurement';
38
+ import { OccupancySensing } from '@matter/main/clusters/occupancy-sensing';
39
+ import { AirQuality } from '@matter/main/clusters/air-quality';
40
+ import { CarbonMonoxideConcentrationMeasurement } from '@matter/main/clusters/carbon-monoxide-concentration-measurement';
41
+ import { CarbonDioxideConcentrationMeasurement } from '@matter/main/clusters/carbon-dioxide-concentration-measurement';
42
+ import { NitrogenDioxideConcentrationMeasurement } from '@matter/main/clusters/nitrogen-dioxide-concentration-measurement';
43
+ import { OzoneConcentrationMeasurement } from '@matter/main/clusters/ozone-concentration-measurement';
44
+ import { FormaldehydeConcentrationMeasurement } from '@matter/main/clusters/formaldehyde-concentration-measurement';
45
+ import { Pm1ConcentrationMeasurement } from '@matter/main/clusters/pm1-concentration-measurement';
46
+ import { Pm25ConcentrationMeasurement } from '@matter/main/clusters/pm25-concentration-measurement';
47
+ import { Pm10ConcentrationMeasurement } from '@matter/main/clusters/pm10-concentration-measurement';
48
+ import { RadonConcentrationMeasurement } from '@matter/main/clusters/radon-concentration-measurement';
49
+ import { TotalVolatileOrganicCompoundsConcentrationMeasurement } from '@matter/main/clusters/total-volatile-organic-compounds-concentration-measurement';
50
+ import { ConcentrationMeasurement } from '@matter/main/clusters/concentration-measurement';
51
+ import { DescriptorServer } from '@matter/main/behaviors/descriptor';
52
+ import { PowerSourceServer } from '@matter/main/behaviors/power-source';
53
+ import { UserLabelServer } from '@matter/main/behaviors/user-label';
54
+ import { FixedLabelServer } from '@matter/main/behaviors/fixed-label';
55
+ import { BasicInformationServer } from '@matter/main/behaviors/basic-information';
56
+ import { BridgedDeviceBasicInformationServer } from '@matter/main/behaviors/bridged-device-basic-information';
57
+ import { GroupsServer } from '@matter/main/behaviors/groups';
58
+ import { ScenesManagementServer } from '@matter/main/behaviors/scenes-management';
59
+ import { PumpConfigurationAndControlServer } from '@matter/main/behaviors/pump-configuration-and-control';
60
+ import { SwitchServer } from '@matter/main/behaviors/switch';
61
+ import { BooleanStateServer } from '@matter/main/behaviors/boolean-state';
62
+ import { PowerTopologyServer } from '@matter/main/behaviors/power-topology';
63
+ import { ElectricalPowerMeasurementServer } from '@matter/main/behaviors/electrical-power-measurement';
64
+ import { ElectricalEnergyMeasurementServer } from '@matter/main/behaviors/electrical-energy-measurement';
65
+ import { TemperatureMeasurementServer } from '@matter/main/behaviors/temperature-measurement';
66
+ import { RelativeHumidityMeasurementServer } from '@matter/main/behaviors/relative-humidity-measurement';
67
+ import { PressureMeasurementServer } from '@matter/main/behaviors/pressure-measurement';
68
+ import { FlowMeasurementServer } from '@matter/main/behaviors/flow-measurement';
69
+ import { IlluminanceMeasurementServer } from '@matter/main/behaviors/illuminance-measurement';
70
+ import { OccupancySensingServer } from '@matter/main/behaviors/occupancy-sensing';
71
+ import { AirQualityServer } from '@matter/main/behaviors/air-quality';
72
+ import { CarbonMonoxideConcentrationMeasurementServer } from '@matter/main/behaviors/carbon-monoxide-concentration-measurement';
73
+ import { CarbonDioxideConcentrationMeasurementServer } from '@matter/main/behaviors/carbon-dioxide-concentration-measurement';
74
+ import { NitrogenDioxideConcentrationMeasurementServer } from '@matter/main/behaviors/nitrogen-dioxide-concentration-measurement';
75
+ import { OzoneConcentrationMeasurementServer } from '@matter/main/behaviors/ozone-concentration-measurement';
76
+ import { FormaldehydeConcentrationMeasurementServer } from '@matter/main/behaviors/formaldehyde-concentration-measurement';
77
+ import { Pm1ConcentrationMeasurementServer } from '@matter/main/behaviors/pm1-concentration-measurement';
78
+ import { Pm25ConcentrationMeasurementServer } from '@matter/main/behaviors/pm25-concentration-measurement';
79
+ import { Pm10ConcentrationMeasurementServer } from '@matter/main/behaviors/pm10-concentration-measurement';
80
+ import { RadonConcentrationMeasurementServer } from '@matter/main/behaviors/radon-concentration-measurement';
81
+ import { TotalVolatileOrganicCompoundsConcentrationMeasurementServer } from '@matter/main/behaviors/total-volatile-organic-compounds-concentration-measurement';
82
+ function capitalizeFirstLetter(name) {
83
+ if (!name)
84
+ return name;
85
+ return name.charAt(0).toUpperCase() + name.slice(1);
86
+ }
87
+ function lowercaseFirstLetter(name) {
88
+ if (!name)
89
+ return name;
90
+ return name.charAt(0).toLowerCase() + name.slice(1);
91
+ }
92
+ function createUniqueId(param1, param2, param3, param4) {
93
+ const hash = createHash('md5');
94
+ hash.update(param1 + param2 + param3 + param4);
95
+ return hash.digest('hex');
96
+ }
97
+ function getBehaviourTypesFromClusterServerIds(clusterServerList) {
98
+ const behaviorTypes = [];
99
+ clusterServerList.forEach((clusterId) => {
100
+ behaviorTypes.push(getBehaviourTypeFromClusterServerId(clusterId));
101
+ });
102
+ return behaviorTypes;
103
+ }
104
+ function getBehaviourTypesFromClusterClientIds(clusterClientList) {
105
+ const behaviorTypes = [];
106
+ clusterClientList.forEach((clusterId) => {
107
+ });
108
+ return behaviorTypes;
109
+ }
110
+ function getBehaviourTypeFromClusterServerId(clusterId) {
111
+ if (clusterId === PowerSource.Cluster.id)
112
+ return PowerSourceServer.with(PowerSource.Feature.Wired);
113
+ if (clusterId === UserLabel.Cluster.id)
114
+ return UserLabelServer;
115
+ if (clusterId === FixedLabel.Cluster.id)
116
+ return FixedLabelServer;
117
+ if (clusterId === BasicInformation.Cluster.id)
118
+ return BasicInformationServer;
119
+ if (clusterId === BridgedDeviceBasicInformation.Cluster.id)
120
+ return BridgedDeviceBasicInformationServer;
121
+ if (clusterId === Identify.Cluster.id)
122
+ return MatterbridgeIdentifyServer;
123
+ if (clusterId === Groups.Cluster.id)
124
+ return GroupsServer;
125
+ if (clusterId === OnOff.Cluster.id)
126
+ return MatterbridgeOnOffServer.with('Lighting');
127
+ if (clusterId === LevelControl.Cluster.id)
128
+ return MatterbridgeLevelControlServer.with('OnOff', 'Lighting');
129
+ if (clusterId === ColorControl.Cluster.id)
130
+ return MatterbridgeColorControlServer;
131
+ if (clusterId === WindowCovering.Cluster.id)
132
+ return MatterbridgeWindowCoveringServer.with('Lift', 'PositionAwareLift');
133
+ if (clusterId === Thermostat.Cluster.id)
134
+ return MatterbridgeThermostatServer.with('AutoMode', 'Heating', 'Cooling');
135
+ if (clusterId === FanControl.Cluster.id)
136
+ return MatterbridgeFanControlServer;
137
+ if (clusterId === DoorLock.Cluster.id)
138
+ return MatterbridgeDoorLockServer;
139
+ if (clusterId === ModeSelect.Cluster.id)
140
+ return MatterbridgeModeSelectServer;
141
+ if (clusterId === ValveConfigurationAndControl.Cluster.id)
142
+ return MatterbridgeValveConfigurationAndControlServer.with('Level');
143
+ if (clusterId === PumpConfigurationAndControl.Cluster.id)
144
+ return PumpConfigurationAndControlServer.with('ConstantSpeed');
145
+ if (clusterId === SmokeCoAlarm.Cluster.id)
146
+ return MatterbridgeSmokeCoAlarmServer.with('SmokeAlarm', 'CoAlarm');
147
+ if (clusterId === Switch.Cluster.id)
148
+ return SwitchServer.with('MomentarySwitch', 'MomentarySwitchRelease', 'MomentarySwitchLongPress', 'MomentarySwitchMultiPress');
149
+ if (clusterId === BooleanState.Cluster.id)
150
+ return BooleanStateServer.enable({ events: { stateChange: true } });
151
+ if (clusterId === BooleanStateConfiguration.Cluster.id)
152
+ return MatterbridgeBooleanStateConfigurationServer;
153
+ if (clusterId === PowerTopology.Cluster.id)
154
+ return PowerTopologyServer.with('TreeTopology');
155
+ if (clusterId === ElectricalPowerMeasurement.Cluster.id)
156
+ return ElectricalPowerMeasurementServer.with('AlternatingCurrent');
157
+ if (clusterId === ElectricalEnergyMeasurement.Cluster.id)
158
+ return ElectricalEnergyMeasurementServer.with('ImportedEnergy', 'ExportedEnergy', 'CumulativeEnergy');
159
+ if (clusterId === TemperatureMeasurement.Cluster.id)
160
+ return TemperatureMeasurementServer;
161
+ if (clusterId === RelativeHumidityMeasurement.Cluster.id)
162
+ return RelativeHumidityMeasurementServer;
163
+ if (clusterId === PressureMeasurement.Cluster.id)
164
+ return PressureMeasurementServer;
165
+ if (clusterId === FlowMeasurement.Cluster.id)
166
+ return FlowMeasurementServer;
167
+ if (clusterId === IlluminanceMeasurement.Cluster.id)
168
+ return IlluminanceMeasurementServer;
169
+ if (clusterId === OccupancySensing.Cluster.id)
170
+ return OccupancySensingServer;
171
+ if (clusterId === AirQuality.Cluster.id)
172
+ return AirQualityServer.with('Fair', 'Moderate', 'VeryPoor', 'ExtremelyPoor');
173
+ if (clusterId === CarbonMonoxideConcentrationMeasurement.Cluster.id)
174
+ return CarbonMonoxideConcentrationMeasurementServer.with('NumericMeasurement');
175
+ if (clusterId === CarbonDioxideConcentrationMeasurement.Cluster.id)
176
+ return CarbonDioxideConcentrationMeasurementServer.with('NumericMeasurement');
177
+ if (clusterId === NitrogenDioxideConcentrationMeasurement.Cluster.id)
178
+ return NitrogenDioxideConcentrationMeasurementServer.with('NumericMeasurement');
179
+ if (clusterId === OzoneConcentrationMeasurement.Cluster.id)
180
+ return OzoneConcentrationMeasurementServer.with('NumericMeasurement');
181
+ if (clusterId === FormaldehydeConcentrationMeasurement.Cluster.id)
182
+ return FormaldehydeConcentrationMeasurementServer.with('NumericMeasurement');
183
+ if (clusterId === Pm1ConcentrationMeasurement.Cluster.id)
184
+ return Pm1ConcentrationMeasurementServer.with('NumericMeasurement');
185
+ if (clusterId === Pm25ConcentrationMeasurement.Cluster.id)
186
+ return Pm25ConcentrationMeasurementServer.with('NumericMeasurement');
187
+ if (clusterId === Pm10ConcentrationMeasurement.Cluster.id)
188
+ return Pm10ConcentrationMeasurementServer.with('NumericMeasurement');
189
+ if (clusterId === RadonConcentrationMeasurement.Cluster.id)
190
+ return RadonConcentrationMeasurementServer.with('NumericMeasurement');
191
+ if (clusterId === TotalVolatileOrganicCompoundsConcentrationMeasurement.Cluster.id)
192
+ return TotalVolatileOrganicCompoundsConcentrationMeasurementServer.with('NumericMeasurement');
193
+ return MatterbridgeIdentifyServer;
194
+ }
195
+ function getBehaviourTypeFromClusterClientId(clusterId) {
196
+ }
197
+ function getBehavior(endpoint, cluster) {
198
+ let behavior;
199
+ if (typeof cluster === 'string') {
200
+ behavior = endpoint.behaviors.supported[lowercaseFirstLetter(cluster)];
201
+ }
202
+ else if (typeof cluster === 'number') {
203
+ behavior = endpoint.behaviors.supported[lowercaseFirstLetter(getClusterNameById(cluster))];
204
+ }
205
+ else if (typeof cluster === 'object') {
206
+ behavior = endpoint.behaviors.supported[lowercaseFirstLetter(cluster.name)];
207
+ }
208
+ else if (typeof cluster === 'function') {
209
+ behavior = cluster;
210
+ }
211
+ return behavior;
212
+ }
213
+ function addRequiredClusterServers(endpoint) {
214
+ const requiredServerList = [];
215
+ endpoint.log.debug(`addRequiredClusterServers for ${CYAN}${endpoint.maybeId}${db}`);
216
+ endpoint.deviceTypes.values().forEach((deviceType) => {
217
+ endpoint.log.debug(`- for deviceType: ${zb}${'0x' + deviceType.code.toString(16).padStart(4, '0')}${db}-${zb}${deviceType.name}${db}`);
218
+ deviceType.requiredServerClusters.forEach((clusterId) => {
219
+ if (!requiredServerList.includes(clusterId) && !endpoint.hasClusterServer(clusterId)) {
220
+ requiredServerList.push(clusterId);
221
+ endpoint.log.debug(`- cluster: ${hk}${'0x' + clusterId.toString(16).padStart(4, '0')}${db}-${hk}${getClusterNameById(clusterId)}${db}`);
222
+ }
223
+ });
224
+ });
225
+ addClusterServers(endpoint, requiredServerList);
226
+ }
227
+ function addOptionalClusterServers(endpoint) {
228
+ const optionalServerList = [];
229
+ endpoint.log.debug(`addOptionalClusterServers for ${CYAN}${endpoint.maybeId}${db}`);
230
+ endpoint.deviceTypes.values().forEach((deviceType) => {
231
+ endpoint.log.debug(`- for deviceType: ${zb}${'0x' + deviceType.code.toString(16).padStart(4, '0')}${db}-${zb}${deviceType.name}${db}`);
232
+ deviceType.optionalServerClusters.forEach((clusterId) => {
233
+ if (!optionalServerList.includes(clusterId) && !endpoint.hasClusterServer(clusterId)) {
234
+ optionalServerList.push(clusterId);
235
+ endpoint.log.debug(`- cluster: ${hk}${'0x' + clusterId.toString(16).padStart(4, '0')}${db}-${hk}${getClusterNameById(clusterId)}${db}`);
236
+ }
237
+ });
238
+ });
239
+ addClusterServers(endpoint, optionalServerList);
240
+ }
241
+ function addClusterServers(endpoint, serverList) {
242
+ if (serverList.includes(PowerSource.Cluster.id))
243
+ endpoint.createDefaultPowerSourceWiredClusterServer();
244
+ if (serverList.includes(Identify.Cluster.id))
245
+ endpoint.createDefaultIdentifyClusterServer();
246
+ if (serverList.includes(Groups.Cluster.id))
247
+ endpoint.createDefaultGroupsClusterServer();
248
+ if (serverList.includes(OnOff.Cluster.id))
249
+ endpoint.createDefaultOnOffClusterServer();
250
+ if (serverList.includes(LevelControl.Cluster.id))
251
+ endpoint.createDefaultLevelControlClusterServer();
252
+ if (serverList.includes(ColorControl.Cluster.id))
253
+ endpoint.createDefaultColorControlClusterServer();
254
+ if (serverList.includes(WindowCovering.Cluster.id))
255
+ endpoint.createDefaultWindowCoveringClusterServer();
256
+ if (serverList.includes(Thermostat.Cluster.id))
257
+ endpoint.createDefaultThermostatClusterServer();
258
+ if (serverList.includes(FanControl.Cluster.id))
259
+ endpoint.createDefaultFanControlClusterServer();
260
+ if (serverList.includes(DoorLock.Cluster.id))
261
+ endpoint.createDefaultDoorLockClusterServer();
262
+ if (serverList.includes(ValveConfigurationAndControl.Cluster.id))
263
+ endpoint.createDefaultValveConfigurationAndControlClusterServer();
264
+ if (serverList.includes(PumpConfigurationAndControl.Cluster.id))
265
+ endpoint.createDefaultPumpConfigurationAndControlClusterServer();
266
+ if (serverList.includes(SmokeCoAlarm.Cluster.id))
267
+ endpoint.createDefaultSmokeCOAlarmClusterServer();
268
+ if (serverList.includes(Switch.Cluster.id))
269
+ endpoint.createDefaultSwitchClusterServer();
270
+ if (serverList.includes(BooleanState.Cluster.id))
271
+ endpoint.createDefaultBooleanStateClusterServer();
272
+ if (serverList.includes(BooleanStateConfiguration.Cluster.id))
273
+ endpoint.createDefaultBooleanStateConfigurationClusterServer();
274
+ if (serverList.includes(PowerTopology.Cluster.id))
275
+ endpoint.createDefaultPowerTopologyClusterServer();
276
+ if (serverList.includes(ElectricalPowerMeasurement.Cluster.id))
277
+ endpoint.createDefaultElectricalPowerMeasurementClusterServer();
278
+ if (serverList.includes(ElectricalEnergyMeasurement.Cluster.id))
279
+ endpoint.createDefaultElectricalEnergyMeasurementClusterServer();
280
+ if (serverList.includes(TemperatureMeasurement.Cluster.id))
281
+ endpoint.createDefaultTemperatureMeasurementClusterServer();
282
+ if (serverList.includes(RelativeHumidityMeasurement.Cluster.id))
283
+ endpoint.createDefaultRelativeHumidityMeasurementClusterServer();
284
+ if (serverList.includes(PressureMeasurement.Cluster.id))
285
+ endpoint.createDefaultPressureMeasurementClusterServer();
286
+ if (serverList.includes(FlowMeasurement.Cluster.id))
287
+ endpoint.createDefaultFlowMeasurementClusterServer();
288
+ if (serverList.includes(IlluminanceMeasurement.Cluster.id))
289
+ endpoint.createDefaultIlluminanceMeasurementClusterServer();
290
+ if (serverList.includes(OccupancySensing.Cluster.id))
291
+ endpoint.createDefaultOccupancySensingClusterServer();
292
+ if (serverList.includes(AirQuality.Cluster.id))
293
+ endpoint.createDefaultAirQualityClusterServer();
294
+ if (serverList.includes(CarbonMonoxideConcentrationMeasurement.Cluster.id))
295
+ endpoint.createDefaultCarbonMonoxideConcentrationMeasurementClusterServer();
296
+ if (serverList.includes(CarbonDioxideConcentrationMeasurement.Cluster.id))
297
+ endpoint.createDefaultCarbonDioxideConcentrationMeasurementClusterServer();
298
+ if (serverList.includes(NitrogenDioxideConcentrationMeasurement.Cluster.id))
299
+ endpoint.createDefaultNitrogenDioxideConcentrationMeasurementClusterServer();
300
+ if (serverList.includes(OzoneConcentrationMeasurement.Cluster.id))
301
+ endpoint.createDefaultOzoneConcentrationMeasurementClusterServer();
302
+ if (serverList.includes(FormaldehydeConcentrationMeasurement.Cluster.id))
303
+ endpoint.createDefaultFormaldehydeConcentrationMeasurementClusterServer();
304
+ if (serverList.includes(Pm1ConcentrationMeasurement.Cluster.id))
305
+ endpoint.createDefaultPm1ConcentrationMeasurementClusterServer();
306
+ if (serverList.includes(Pm25ConcentrationMeasurement.Cluster.id))
307
+ endpoint.createDefaultPm25ConcentrationMeasurementClusterServer();
308
+ if (serverList.includes(Pm10ConcentrationMeasurement.Cluster.id))
309
+ endpoint.createDefaultPm10ConcentrationMeasurementClusterServer();
310
+ if (serverList.includes(RadonConcentrationMeasurement.Cluster.id))
311
+ endpoint.createDefaultRadonConcentrationMeasurementClusterServer();
312
+ if (serverList.includes(TotalVolatileOrganicCompoundsConcentrationMeasurement.Cluster.id))
313
+ endpoint.createDefaultTvocMeasurementClusterServer();
314
+ }
315
+ export function optionsFor(type, options) {
316
+ return options;
317
+ }
51
318
  export class MatterbridgeEndpoint extends Endpoint {
52
319
  static bridgeMode = '';
53
- static logLevel = LogLevel.INFO;
320
+ static logLevel = "info";
54
321
  log;
55
322
  plugin = undefined;
56
323
  configUrl = undefined;
@@ -71,21 +338,10 @@ export class MatterbridgeEndpoint extends Endpoint {
71
338
  uniqueStorageKey = undefined;
72
339
  tagList = undefined;
73
340
  subType = '';
74
- // Maps matter deviceTypes and endpoints
75
341
  deviceTypes = new Map();
76
- clusterServers = new Map();
77
- clusterClients = new Map();
78
342
  commandHandler = new NamedHandler();
79
- /**
80
- * Represents a MatterbridgeEndpoint.
81
- * @constructor
82
- * @param {DeviceTypeDefinition | AtLeastOne<DeviceTypeDefinition>} definition - The DeviceTypeDefinition(s) of the endpoint.
83
- * @param {MatterbridgeEndpointOptions} [options={}] - The options for the device.
84
- * @param {boolean} [debug=false] - Debug flag.
85
- */
86
343
  constructor(definition, options = {}, debug = false) {
87
344
  let deviceTypeList = [];
88
- // Get the first DeviceTypeDefinition
89
345
  let firstDefinition;
90
346
  if (Array.isArray(definition)) {
91
347
  firstDefinition = definition[0];
@@ -98,7 +354,6 @@ export class MatterbridgeEndpoint extends Endpoint {
98
354
  firstDefinition = definition;
99
355
  deviceTypeList = [{ deviceType: firstDefinition.code, revision: firstDefinition.revision }];
100
356
  }
101
- // Convert the first DeviceTypeDefinition to an EndpointType.Options
102
357
  const deviceTypeDefinitionV8 = {
103
358
  name: firstDefinition.name.replace('-', '_'),
104
359
  deviceType: firstDefinition.code,
@@ -106,18 +361,17 @@ export class MatterbridgeEndpoint extends Endpoint {
106
361
  deviceClass: firstDefinition.deviceClass.toLowerCase(),
107
362
  requirements: {
108
363
  server: {
109
- mandatory: SupportedBehaviors(...MatterbridgeEndpoint.getBehaviourTypesFromClusterServerIds(firstDefinition.requiredServerClusters)),
110
- optional: SupportedBehaviors(...MatterbridgeEndpoint.getBehaviourTypesFromClusterServerIds(firstDefinition.optionalServerClusters)),
364
+ mandatory: SupportedBehaviors(...getBehaviourTypesFromClusterServerIds(firstDefinition.requiredServerClusters)),
365
+ optional: SupportedBehaviors(...getBehaviourTypesFromClusterServerIds(firstDefinition.optionalServerClusters)),
111
366
  },
112
367
  client: {
113
- mandatory: SupportedBehaviors(...MatterbridgeEndpoint.getBehaviourTypesFromClusterClientIds(firstDefinition.requiredClientClusters)),
114
- optional: SupportedBehaviors(...MatterbridgeEndpoint.getBehaviourTypesFromClusterClientIds(firstDefinition.optionalClientClusters)),
368
+ mandatory: SupportedBehaviors(...getBehaviourTypesFromClusterClientIds(firstDefinition.requiredClientClusters)),
369
+ optional: SupportedBehaviors(...getBehaviourTypesFromClusterClientIds(firstDefinition.optionalClientClusters)),
115
370
  },
116
371
  },
117
372
  behaviors: options.tagList ? SupportedBehaviors(DescriptorServer.with(Descriptor.Feature.TagList)) : {},
118
373
  };
119
374
  const endpointV8 = MutableEndpoint(deviceTypeDefinitionV8);
120
- // Convert the options to an Endpoint.Options
121
375
  const optionsV8 = {
122
376
  id: options.uniqueStorageKey?.replace(/[ .]/g, ''),
123
377
  number: options.endpointId,
@@ -135,294 +389,181 @@ export class MatterbridgeEndpoint extends Endpoint {
135
389
  }
136
390
  else
137
391
  this.deviceTypes.set(firstDefinition.code, firstDefinition);
138
- // console.log('MatterbridgeEndpoint.option', options);
139
- // console.log('MatterbridgeEndpoint.endpointV8', endpointV8);
140
- // console.log('MatterbridgeEndpoint.optionsV8', optionsV8);
141
- // Create the logger
142
- this.log = new AnsiLogger({ logName: 'MatterbridgeEndpoint', logTimestampFormat: TimestampFormat.TIME_MILLIS, logLevel: debug === true ? LogLevel.DEBUG : MatterbridgeEndpoint.logLevel });
392
+ this.log = new AnsiLogger({ logName: 'MatterbridgeEndpoint', logTimestampFormat: 4, logLevel: debug === true ? "debug" : MatterbridgeEndpoint.logLevel });
143
393
  this.log.debug(`${YELLOW}new${db} MatterbridgeEndpoint: ${zb}${'0x' + firstDefinition.code.toString(16).padStart(4, '0')}${db}-${zb}${firstDefinition.name}${db} ` +
144
394
  `id: ${CYAN}${options.uniqueStorageKey}${db} number: ${CYAN}${options.endpointId}${db} taglist: ${CYAN}${options.tagList ? debugStringify(options.tagList) : 'undefined'}${db}`);
145
- // Add MatterbridgeBehavior with MatterbridgeBehaviorDevice
146
395
  this.behaviors.require(MatterbridgeBehavior, { deviceCommand: new MatterbridgeBehaviorDevice(this.log, this.commandHandler, undefined) });
147
396
  }
148
- /**
149
- * Loads an instance of the MatterbridgeEndpoint class.
150
- *
151
- * @param {DeviceTypeDefinition | AtLeastOne<DeviceTypeDefinition>} definition - The DeviceTypeDefinition(s) of the device.
152
- * @param {MatterbridgeEndpointOptions} [options={}] - The options for the device.
153
- * @param {boolean} [debug=false] - Debug flag.
154
- * @returns {Promise<MatterbridgeEndpoint>} MatterbridgeEndpoint instance.
155
- */
156
397
  static async loadInstance(definition, options = {}, debug = false) {
157
398
  return new MatterbridgeEndpoint(definition, options, debug);
158
399
  }
159
- static getBehaviourTypesFromClusterServerIds(clusterServerList) {
160
- // Map Server ClusterId to Behavior.Type
161
- const behaviorTypes = [];
162
- clusterServerList.forEach((clusterId) => {
163
- behaviorTypes.push(MatterbridgeEndpoint.getBehaviourTypeFromClusterServerId(clusterId));
164
- });
165
- return behaviorTypes;
400
+ getDeviceTypes() {
401
+ return Array.from(this.deviceTypes.values());
166
402
  }
167
- static getBehaviourTypesFromClusterClientIds(clusterClientList) {
168
- // Map Client ClusterId to Behavior.Type
169
- const behaviorTypes = [];
170
- clusterClientList.forEach((clusterId) => {
171
- // behaviorTypes.push(MatterbridgeEndpoint.getBehaviourTypeFromClusterClientId(clusterId));
172
- });
173
- return behaviorTypes;
174
- }
175
- static getBehaviourTypeFromClusterServerId(clusterId, subType) {
176
- // Map ClusterId to Behavior.Type
177
- if (clusterId === Identify.Cluster.id)
178
- return MatterbridgeIdentifyServer;
179
- if (clusterId === Groups.Cluster.id)
180
- return GroupsServer;
181
- if (clusterId === OnOff.Cluster.id && subType === undefined)
182
- return MatterbridgeOnOffServer.with('Lighting');
183
- if (clusterId === OnOff.Cluster.id && subType === '')
184
- return MatterbridgeOnOffServer;
185
- if (clusterId === OnOff.Cluster.id && subType === 'LightingOnOff')
186
- return MatterbridgeOnOffServer.with('Lighting');
187
- if (clusterId === OnOff.Cluster.id && subType === 'DeadFrontBehaviorOnOff')
188
- return MatterbridgeOnOffServer.with('DeadFrontBehavior');
189
- if (clusterId === LevelControl.Cluster.id)
190
- return MatterbridgeLevelControlServer.with('OnOff', 'Lighting');
191
- if (clusterId === ColorControl.Cluster.id && subType === undefined)
192
- return MatterbridgeColorControlServer;
193
- if (clusterId === ColorControl.Cluster.id && subType === 'CompleteColorControl')
194
- return MatterbridgeColorControlServer;
195
- if (clusterId === ColorControl.Cluster.id && subType === 'XyColorControl')
196
- return MatterbridgeColorControlServer.with('Xy', 'ColorTemperature');
197
- if (clusterId === ColorControl.Cluster.id && subType === 'HueSaturationColorControl')
198
- return MatterbridgeColorControlServer.with('HueSaturation', 'ColorTemperature');
199
- if (clusterId === ColorControl.Cluster.id && subType === 'ColorTemperatureColorControl')
200
- return MatterbridgeColorControlServer.with('ColorTemperature');
201
- if (clusterId === DoorLock.Cluster.id)
202
- return MatterbridgeDoorLockServer;
203
- if (clusterId === Thermostat.Cluster.id && subType === undefined)
204
- return MatterbridgeThermostatServer.with('AutoMode', 'Heating', 'Cooling');
205
- if (clusterId === Thermostat.Cluster.id && subType === 'AutoModeThermostat')
206
- return MatterbridgeThermostatServer.with('AutoMode', 'Heating', 'Cooling');
207
- if (clusterId === Thermostat.Cluster.id && subType === 'HeatingThermostat')
208
- return MatterbridgeThermostatServer.with('Heating');
209
- if (clusterId === Thermostat.Cluster.id && subType === 'CoolingThermostat')
210
- return MatterbridgeThermostatServer.with('Cooling');
211
- if (clusterId === WindowCovering.Cluster.id)
212
- return MatterbridgeWindowCoveringServer;
213
- if (clusterId === FanControl.Cluster.id)
214
- return MatterbridgeFanControlServer;
215
- if (clusterId === Switch.Cluster.id && subType === undefined)
216
- return SwitchServer.with('MomentarySwitch', 'MomentarySwitchRelease', 'MomentarySwitchLongPress', 'MomentarySwitchMultiPress');
217
- if (clusterId === Switch.Cluster.id && subType === 'MomentarySwitch')
218
- return SwitchServer.with('MomentarySwitch', 'MomentarySwitchRelease', 'MomentarySwitchLongPress', 'MomentarySwitchMultiPress');
219
- if (clusterId === Switch.Cluster.id && subType === 'LatchingSwitch')
220
- return SwitchServer.with('LatchingSwitch');
221
- if (clusterId === TemperatureMeasurement.Cluster.id)
222
- return TemperatureMeasurementServer;
223
- if (clusterId === RelativeHumidityMeasurement.Cluster.id)
224
- return RelativeHumidityMeasurementServer;
225
- if (clusterId === PressureMeasurement.Cluster.id)
226
- return PressureMeasurementServer;
227
- if (clusterId === FlowMeasurement.Cluster.id)
228
- return FlowMeasurementServer;
229
- if (clusterId === BooleanState.Cluster.id)
230
- return BooleanStateServer.enable({ events: { stateChange: true } });
231
- if (clusterId === BooleanStateConfiguration.Cluster.id)
232
- return MatterbridgeBooleanStateConfigurationServer;
233
- if (clusterId === OccupancySensing.Cluster.id)
234
- return OccupancySensingServer;
235
- if (clusterId === IlluminanceMeasurement.Cluster.id)
236
- return IlluminanceMeasurementServer;
237
- if (clusterId === SmokeCoAlarm.Cluster.id)
238
- return SmokeCoAlarmServer.with('SmokeAlarm', 'CoAlarm');
239
- if (clusterId === ValveConfigurationAndControl.Cluster.id)
240
- return MatterbridgeValveConfigurationAndControlServer.with('Level');
241
- if (clusterId === AirQuality.Cluster.id)
242
- return AirQualityServer.with('Fair', 'Moderate', 'VeryPoor', 'ExtremelyPoor');
243
- if (clusterId === CarbonMonoxideConcentrationMeasurement.Cluster.id)
244
- return CarbonMonoxideConcentrationMeasurementServer.with('NumericMeasurement');
245
- if (clusterId === CarbonDioxideConcentrationMeasurement.Cluster.id)
246
- return CarbonDioxideConcentrationMeasurementServer.with('NumericMeasurement');
247
- if (clusterId === NitrogenDioxideConcentrationMeasurement.Cluster.id)
248
- return NitrogenDioxideConcentrationMeasurementServer.with('NumericMeasurement');
249
- if (clusterId === OzoneConcentrationMeasurement.Cluster.id)
250
- return OzoneConcentrationMeasurementServer.with('NumericMeasurement');
251
- if (clusterId === FormaldehydeConcentrationMeasurement.Cluster.id)
252
- return FormaldehydeConcentrationMeasurementServer.with('NumericMeasurement');
253
- if (clusterId === Pm1ConcentrationMeasurement.Cluster.id)
254
- return Pm1ConcentrationMeasurementServer.with('NumericMeasurement');
255
- if (clusterId === Pm25ConcentrationMeasurement.Cluster.id)
256
- return Pm25ConcentrationMeasurementServer.with('NumericMeasurement');
257
- if (clusterId === Pm10ConcentrationMeasurement.Cluster.id)
258
- return Pm10ConcentrationMeasurementServer.with('NumericMeasurement');
259
- if (clusterId === RadonConcentrationMeasurement.Cluster.id)
260
- return RadonConcentrationMeasurementServer.with('NumericMeasurement');
261
- if (clusterId === TotalVolatileOrganicCompoundsConcentrationMeasurement.Cluster.id)
262
- return TotalVolatileOrganicCompoundsConcentrationMeasurementServer.with('NumericMeasurement');
263
- if (clusterId === ModeSelect.Cluster.id)
264
- return ModeSelectServer;
265
- if (clusterId === UserLabel.Cluster.id)
266
- return UserLabelServer;
267
- if (clusterId === FixedLabel.Cluster.id)
268
- return FixedLabelServer;
269
- if (clusterId === PowerTopology.Cluster.id)
270
- return PowerTopologyServer.with('TreeTopology');
271
- if (clusterId === ElectricalPowerMeasurement.Cluster.id)
272
- return ElectricalPowerMeasurementServer.with('AlternatingCurrent');
273
- if (clusterId === ElectricalEnergyMeasurement.Cluster.id)
274
- return ElectricalEnergyMeasurementServer.with('ImportedEnergy', 'ExportedEnergy', 'CumulativeEnergy');
275
- if (clusterId === PowerSource.Cluster.id && subType === undefined)
276
- return PowerSourceServer;
277
- if (clusterId === PowerSource.Cluster.id && subType === 'WiredPowerSource')
278
- return PowerSourceServer.with(PowerSource.Feature.Wired);
279
- if (clusterId === PowerSource.Cluster.id && subType === 'BatteryReplaceablePowerSource')
280
- return PowerSourceServer.with(PowerSource.Feature.Battery, PowerSource.Feature.Replaceable);
281
- if (clusterId === PowerSource.Cluster.id && subType === 'BatteryRechargeablePowerSource')
282
- return PowerSourceServer.with(PowerSource.Feature.Battery, PowerSource.Feature.Rechargeable);
283
- if (clusterId === BasicInformation.Cluster.id)
284
- return BasicInformationServer;
285
- if (clusterId === BridgedDeviceBasicInformation.Cluster.id)
286
- return BridgedDeviceBasicInformationServer;
287
- return MatterbridgeIdentifyServer;
403
+ hasClusterServer(cluster) {
404
+ const behavior = getBehavior(this, cluster);
405
+ if (behavior)
406
+ return this.behaviors.supported[behavior.id] !== undefined;
407
+ else
408
+ return false;
288
409
  }
289
- static getBehaviourTypeFromClusterClientId(clusterId) {
290
- // Map ClusterId to Behavior.Type
291
- return IdentifyBehavior;
292
- }
293
- /**
294
- * Adds a device type to the list of device types.
295
- * If the device type is not already present in the list, it will be added.
296
- *
297
- * @param {DeviceTypeDefinition} deviceType - The device type to add.
298
- *
299
- * @deprecated This method is deprecated and will be removed in future versions. Use the constructor options instead.
300
- */
301
- addDeviceType(deviceType) {
302
- if (!this.deviceTypes.has(deviceType.code)) {
303
- // Keep the Matterbridge internal map
304
- this.log.debug(`addDeviceType: ${zb}${'0x' + deviceType.code.toString(16).padStart(4, '0')}${db}-${zb}${deviceType.name}${db}`);
305
- this.deviceTypes.set(deviceType.code, deviceType);
306
- // Add the device types to the descriptor server
307
- const deviceTypeList = Array.from(this.deviceTypes.values()).map((dt) => ({
308
- deviceType: dt.code,
309
- revision: dt.revision,
310
- }));
311
- if (this.tagList) {
312
- this.behaviors.require(DescriptorServer.with(Descriptor.Feature.TagList), {
313
- tagList: this.tagList,
314
- deviceTypeList,
315
- });
316
- }
317
- else {
318
- this.behaviors.require(DescriptorServer, {
319
- deviceTypeList,
320
- });
321
- }
410
+ hasAttributeServer(cluster, attribute) {
411
+ const behavior = getBehavior(this, cluster);
412
+ if (!behavior || !this.behaviors.supported[behavior.id])
413
+ return false;
414
+ const options = this.behaviors.optionsFor(behavior);
415
+ return lowercaseFirstLetter(attribute) in options;
416
+ }
417
+ getClusterServerOptions(cluster) {
418
+ const behavior = getBehavior(this, cluster);
419
+ if (!behavior)
420
+ return undefined;
421
+ return this.behaviors.optionsFor(behavior);
422
+ }
423
+ getAttribute(clusterId, attribute, log) {
424
+ const clusterName = lowercaseFirstLetter(getClusterNameById(clusterId));
425
+ if (this.construction.status !== Lifecycle.Status.Active) {
426
+ this.log.error(`getAttribute ${hk}${clusterName}.${attribute}${er} error: Endpoint ${or}${this.maybeId}${er}:${or}${this.maybeNumber}${er} is in the ${BLUE}${this.construction.status}${er} state`);
427
+ return undefined;
428
+ }
429
+ const state = this.state;
430
+ if (!(clusterName in state)) {
431
+ this.log.error(`getAttribute error: Cluster ${'0x' + clusterId.toString(16).padStart(4, '0')}:${clusterName} not found on endpoint ${or}${this.id}${er}:${or}${this.number}${er}`);
432
+ return undefined;
433
+ }
434
+ attribute = lowercaseFirstLetter(attribute);
435
+ if (!(attribute in state[clusterName])) {
436
+ this.log.error(`getAttribute error: Attribute ${hk}${attribute}${er} not found on Cluster ${'0x' + clusterId.toString(16).padStart(4, '0')}:${clusterName} on endpoint ${or}${this.id}${er}:${or}${this.number}${er}`);
437
+ return undefined;
322
438
  }
439
+ const value = state[clusterName][attribute];
440
+ log?.info(`${db}Get endpoint ${or}${this.id}${db}:${or}${this.number}${db} attribute ${hk}${capitalizeFirstLetter(clusterName)}${db}.${hk}${attribute}${db} value ${YELLOW}${value !== null && typeof value === 'object' ? debugStringify(value) : value}${db}`);
441
+ return value;
323
442
  }
324
- /**
325
- * Adds one or more device types with the required cluster servers and the specified cluster servers.
326
- *
327
- * @param {AtLeastOne<DeviceTypeDefinition>} deviceTypes - The device types to add.
328
- * @param {ClusterId[]} includeServerList - The list of cluster IDs to include.
329
- *
330
- * @deprecated This method is deprecated and will be removed in future versions. Use the constructor options instead.
331
- */
332
- addDeviceTypeWithClusterServer(deviceTypes, includeServerList) {
333
- this.log.debug('addDeviceTypeWithClusterServer:');
334
- deviceTypes.forEach((deviceType) => {
335
- this.log.debug(`- with deviceType: ${zb}${'0x' + deviceType.code.toString(16).padStart(4, '0')}${db}-${zb}${deviceType.name}${db}`);
336
- deviceType.requiredServerClusters.forEach((clusterId) => {
337
- if (!includeServerList.includes(clusterId))
338
- includeServerList.push(clusterId);
339
- });
340
- });
341
- includeServerList.forEach((clusterId) => {
342
- if (!this.getClusterServerById(clusterId)) {
343
- this.log.debug(`- with cluster: ${hk}${'0x' + clusterId.toString(16).padStart(4, '0')}${db}-${hk}${getClusterNameById(clusterId)}${db}`);
344
- }
345
- else {
346
- includeServerList.splice(includeServerList.indexOf(clusterId), 1);
347
- }
348
- });
349
- deviceTypes.forEach((deviceType) => {
350
- this.addDeviceType(deviceType);
351
- });
352
- this.addClusterServerFromList(this, includeServerList);
353
- }
354
- /**
355
- * Adds the required cluster servers (only if they are not present) for the device types of the specified endpoint.
356
- *
357
- * @param {MatterbridgeEndpoint} endpoint - The endpoint to add the required cluster servers to.
358
- * @returns {MatterbridgeEndpoint} The updated endpoint with the required cluster servers added.
359
- */
360
- addRequiredClusterServers(endpoint) {
361
- const requiredServerList = [];
362
- this.log.debug(`addRequiredClusterServer for ${CYAN}${endpoint.id}${db}`);
363
- endpoint.getDeviceTypes().forEach((deviceType) => {
364
- this.log.debug(`- for deviceType: ${zb}${'0x' + deviceType.code.toString(16).padStart(4, '0')}${db}-${zb}${deviceType.name}${db}`);
365
- deviceType.requiredServerClusters.forEach((clusterId) => {
366
- if (!requiredServerList.includes(clusterId) && !endpoint.getClusterServerById(clusterId))
367
- requiredServerList.push(clusterId);
443
+ async setAttribute(clusterId, attribute, value, log) {
444
+ const clusterName = lowercaseFirstLetter(getClusterNameById(clusterId));
445
+ if (this.construction.status !== Lifecycle.Status.Active) {
446
+ this.log.error(`setAttribute ${hk}${clusterName}.${attribute}${er} error: Endpoint ${or}${this.maybeId}${er}:${or}${this.maybeNumber}${er} is in the ${BLUE}${this.construction.status}${er} state`);
447
+ return false;
448
+ }
449
+ const state = this.state;
450
+ if (!(clusterName in state)) {
451
+ this.log.error(`setAttribute ${hk}${attribute}${er} error: Cluster ${'0x' + clusterId.toString(16).padStart(4, '0')}:${clusterName} not found on endpoint ${or}${this.id}${er}:${or}${this.number}${er}`);
452
+ return false;
453
+ }
454
+ attribute = lowercaseFirstLetter(attribute);
455
+ if (!(attribute in state[clusterName])) {
456
+ this.log.error(`setAttribute error: Attribute ${hk}${attribute}${er} not found on Cluster ${'0x' + clusterId.toString(16).padStart(4, '0')}:${clusterName} on endpoint ${or}${this.id}${er}:${or}${this.number}${er}`);
457
+ return false;
458
+ }
459
+ let oldValue = state[clusterName][attribute];
460
+ if (typeof oldValue === 'object')
461
+ oldValue = deepCopy(oldValue);
462
+ await this.setStateOf(this.behaviors.supported[clusterName], { [attribute]: value });
463
+ log?.info(`${db}Set endpoint ${or}${this.id}${db}:${or}${this.number}${db} attribute ${hk}${capitalizeFirstLetter(clusterName)}${db}.${hk}${attribute}${db} ` +
464
+ `from ${YELLOW}${oldValue !== null && typeof oldValue === 'object' ? debugStringify(oldValue) : oldValue}${db} ` +
465
+ `to ${YELLOW}${value !== null && typeof value === 'object' ? debugStringify(value) : value}${db}`);
466
+ return true;
467
+ }
468
+ async subscribeAttribute(clusterId, attribute, listener, log) {
469
+ const clusterName = lowercaseFirstLetter(getClusterNameById(clusterId));
470
+ if (this.construction.status !== Lifecycle.Status.Active) {
471
+ await this.construction.ready;
472
+ }
473
+ const events = this.events;
474
+ if (!(clusterName in events)) {
475
+ this.log.error(`subscribeAttribute ${hk}${attribute}${er} error: Cluster ${'0x' + clusterId.toString(16).padStart(4, '0')}:${clusterName} not found on endpoint ${or}${this.maybeId}${er}:${or}${this.maybeNumber}${er}`);
476
+ return false;
477
+ }
478
+ attribute = lowercaseFirstLetter(attribute) + '$Changed';
479
+ if (!(attribute in events[clusterName])) {
480
+ this.log.error(`subscribeAttribute error: Attribute ${hk}${attribute}${er} not found on Cluster ${'0x' + clusterId.toString(16).padStart(4, '0')}:${clusterName} on endpoint ${or}${this.maybeId}${er}:${or}${this.maybeNumber}${er}`);
481
+ return false;
482
+ }
483
+ events[clusterName][attribute].on(listener);
484
+ log?.info(`${db}Subscribed endpoint ${or}${this.id}${db}:${or}${this.number}${db} attribute ${hk}${capitalizeFirstLetter(clusterName)}${db}.${hk}${attribute}${db}`);
485
+ return true;
486
+ }
487
+ async triggerEvent(clusterId, event, payload, log, endpoint) {
488
+ if (!endpoint)
489
+ endpoint = this;
490
+ const clusterName = lowercaseFirstLetter(getClusterNameById(clusterId));
491
+ if (endpoint.construction.status !== Lifecycle.Status.Active) {
492
+ this.log.error(`triggerEvent ${hk}${clusterName}.${event}${er} error: Endpoint ${or}${endpoint.maybeId}${er}:${or}${endpoint.maybeNumber}${er} is in the ${BLUE}${endpoint.construction.status}${er} state`);
493
+ return false;
494
+ }
495
+ const events = endpoint.events;
496
+ if (!(clusterName in events) || !(event in events[clusterName])) {
497
+ this.log.error(`triggerEvent ${hk}${event}${er} error: Cluster ${'0x' + clusterId.toString(16).padStart(4, '0')}:${clusterName} not found on endpoint ${or}${endpoint.id}${er}:${or}${endpoint.number}${er}`);
498
+ return false;
499
+ }
500
+ await endpoint.act((agent) => agent[clusterName].events[event].emit(payload, agent.context));
501
+ log?.info(`${db}Trigger event ${hk}${capitalizeFirstLetter(clusterName)}${db}.${hk}${event}${db} with ${debugStringify(payload)}${db} on endpoint ${or}${endpoint.id}${db}:${or}${endpoint.number}${db} `);
502
+ return true;
503
+ }
504
+ addClusterServers(serverList) {
505
+ addClusterServers(this, serverList);
506
+ }
507
+ async addFixedLabel(label, value) {
508
+ if (!this.hasClusterServer(FixedLabel.Cluster.id)) {
509
+ this.log.debug(`addFixedLabel: add cluster ${hk}FixedLabel${db}:${hk}fixedLabel${db} with label ${CYAN}${label}${db} value ${CYAN}${value}${db}`);
510
+ this.behaviors.require(FixedLabelServer, {
511
+ labelList: [{ label, value }],
368
512
  });
369
- });
370
- requiredServerList.forEach((clusterId) => {
371
- this.log.debug(`- with cluster: ${hk}${'0x' + clusterId.toString(16).padStart(4, '0')}${db}-${hk}${getClusterNameById(clusterId)}${db}`);
372
- });
373
- this.addClusterServerFromList(endpoint, requiredServerList);
374
- return endpoint;
375
- }
376
- /**
377
- * Adds the optional cluster servers (only if they are not present) for the device types of the specified endpoint.
378
- *
379
- * @param {MatterbridgeEndpoint} endpoint - The endpoint to add the required cluster servers to.
380
- * @returns {MatterbridgeEndpoint} The updated endpoint with the required cluster servers added.
381
- */
382
- addOptionalClusterServers(endpoint) {
383
- const optionalServerList = [];
384
- this.log.debug(`addRequiredClusterServer for ${CYAN}${endpoint.id}${db}`);
385
- endpoint.getDeviceTypes().forEach((deviceType) => {
386
- this.log.debug(`- for deviceType: ${zb}${'0x' + deviceType.code.toString(16).padStart(4, '0')}${db}-${zb}${deviceType.name}${db}`);
387
- deviceType.optionalServerClusters.forEach((clusterId) => {
388
- if (!optionalServerList.includes(clusterId) && !endpoint.getClusterServerById(clusterId))
389
- optionalServerList.push(clusterId);
513
+ return this;
514
+ }
515
+ this.log.debug(`addFixedLabel: add label ${CYAN}${label}${db} value ${CYAN}${value}${db}`);
516
+ const labelList = (this.getAttribute(FixedLabel.Cluster.id, 'labelList', this.log) ?? []).filter((entryLabel) => entryLabel.label !== label);
517
+ labelList.push({ label, value });
518
+ await this.setAttribute(FixedLabel.Cluster.id, 'labelList', labelList, this.log);
519
+ return this;
520
+ }
521
+ async addUserLabel(label, value) {
522
+ if (!this.hasClusterServer(UserLabel.Cluster.id)) {
523
+ this.log.debug(`addUserLabel: add cluster ${hk}UserLabel${db}:${hk}userLabel${db} with label ${CYAN}${label}${db} value ${CYAN}${value}${db}`);
524
+ this.behaviors.require(UserLabelServer, {
525
+ labelList: [{ label, value }],
390
526
  });
391
- });
392
- optionalServerList.forEach((clusterId) => {
393
- this.log.debug(`- with cluster: ${hk}${'0x' + clusterId.toString(16).padStart(4, '0')}${db}-${hk}${getClusterNameById(clusterId)}${db}`);
394
- });
395
- this.addClusterServerFromList(endpoint, optionalServerList);
396
- return endpoint;
397
- }
398
- /**
399
- * Adds a child endpoint with the specified device types and options.
400
- * If the child endpoint is not already present, it will be created and added.
401
- * If the child endpoint is already present, the device types will be added to the existing child endpoint.
402
- *
403
- * @param {string} endpointName - The name of the new endpoint to add.
404
- * @param {DeviceTypeDefinition | AtLeastOne<DeviceTypeDefinition>} definition - The device types to add.
405
- * @param {MatterbridgeEndpointOptions} [options={}] - The options for the endpoint.
406
- * @param {boolean} [debug=false] - Whether to enable debug logging.
407
- * @returns {MatterbridgeEndpoint} - The child endpoint that was found or added.
408
- *
409
- * @example
410
- * ```typescript
411
- * const endpoint = device.addChildDeviceType('Temperature', [temperatureSensor], { tagList: [{ mfgCode: null, namespaceId: LocationTag.Indoor.namespaceId, tag: LocationTag.Indoor.tag, label: null }] }, true);
412
- * ```
413
- */
527
+ return this;
528
+ }
529
+ this.log.debug(`addUserLabel: add label ${CYAN}${label}${db} value ${CYAN}${value}${db}`);
530
+ const labelList = (this.getAttribute(UserLabel.Cluster.id, 'labelList', this.log) ?? []).filter((entryLabel) => entryLabel.label !== label);
531
+ labelList.push({ label, value });
532
+ await this.setAttribute(UserLabel.Cluster.id, 'labelList', labelList, this.log);
533
+ return this;
534
+ }
535
+ addCommandHandler(command, handler) {
536
+ this.commandHandler.addHandler(command, handler);
537
+ return this;
538
+ }
539
+ async executeCommandHandler(command, request) {
540
+ await this.commandHandler.executeHandler(command, { request });
541
+ }
542
+ addRequiredClusterServers() {
543
+ addRequiredClusterServers(this);
544
+ return this;
545
+ }
546
+ addOptionalClusterServers() {
547
+ addOptionalClusterServers(this);
548
+ return this;
549
+ }
414
550
  addChildDeviceType(endpointName, definition, options = {}, debug = false) {
415
551
  this.log.debug(`addChildDeviceType: ${CYAN}${endpointName}${db}`);
552
+ let alreadyAdded = false;
416
553
  let child = this.getChildEndpointByName(endpointName);
417
- if (!child) {
554
+ if (child) {
555
+ this.log.debug(`****- endpoint ${CYAN}${endpointName}${db} already added!`);
556
+ alreadyAdded = true;
557
+ }
558
+ else {
418
559
  if ('tagList' in options) {
419
560
  for (const tag of options.tagList) {
420
561
  this.log.debug(`- with tagList: mfgCode ${CYAN}${tag.mfgCode}${db} namespaceId ${CYAN}${tag.namespaceId}${db} tag ${CYAN}${tag.tag}${db} label ${CYAN}${tag.label}${db}`);
421
562
  }
422
- child = new MatterbridgeEndpoint(definition, { uniqueStorageKey: endpointName, tagList: options.tagList }, debug);
563
+ child = new MatterbridgeEndpoint(definition, { uniqueStorageKey: endpointName, endpointId: options.endpointId, tagList: options.tagList }, debug);
423
564
  }
424
565
  else {
425
- child = new MatterbridgeEndpoint(definition, { uniqueStorageKey: endpointName }, debug);
566
+ child = new MatterbridgeEndpoint(definition, { uniqueStorageKey: endpointName, endpointId: options.endpointId }, debug);
426
567
  }
427
568
  }
428
569
  if (Array.isArray(definition)) {
@@ -433,6 +574,8 @@ export class MatterbridgeEndpoint extends Endpoint {
433
574
  else {
434
575
  this.log.debug(`- with deviceType: ${zb}${'0x' + definition.code.toString(16).padStart(4, '0')}${db}-${zb}${definition.name}${db}`);
435
576
  }
577
+ if (alreadyAdded)
578
+ return child;
436
579
  if (this.lifecycle.isInstalled) {
437
580
  this.log.debug(`- with lifecycle installed`);
438
581
  this.add(child);
@@ -443,62 +586,58 @@ export class MatterbridgeEndpoint extends Endpoint {
443
586
  }
444
587
  return child;
445
588
  }
446
- /**
447
- * Adds a child endpoint with one or more device types with the required cluster servers and the specified cluster servers.
448
- * If the child endpoint is not already present in the childEndpoints, it will be added.
449
- * If the child endpoint is already present in the childEndpoints, the device types and cluster servers will be added to the existing child endpoint.
450
- *
451
- * @param {string} endpointName - The name of the new enpoint to add.
452
- * @param {DeviceTypeDefinition | AtLeastOne<DeviceTypeDefinition>} definition - The device types to add.
453
- * @param {ClusterId[]} [includeServerList=[]] - The list of cluster IDs to include.
454
- * @param {MatterbridgeEndpointOptions} [options={}] - The options for the device.
455
- * @param {boolean} [debug=false] - Whether to enable debug logging.
456
- * @returns {MatterbridgeEndpoint} - The child endpoint that was found or added.
457
- *
458
- * @example
459
- * ```typescript
460
- * const endpoint = device.addChildDeviceTypeWithClusterServer('Temperature', [temperatureSensor], [], { tagList: [{ mfgCode: null, namespaceId: LocationTag.Indoor.namespaceId, tag: LocationTag.Indoor.tag, label: null }] }, true);
461
- * ```
462
- */
463
- addChildDeviceTypeWithClusterServer(endpointName, definition, includeServerList = [], options = {}, debug = false) {
589
+ addChildDeviceTypeWithClusterServer(endpointName, definition, serverList = [], options = {}, debug = false) {
464
590
  this.log.debug(`addChildDeviceTypeWithClusterServer: ${CYAN}${endpointName}${db}`);
591
+ let alreadyAdded = false;
465
592
  let child = this.getChildEndpointByName(endpointName);
466
- if (!child) {
593
+ if (child) {
594
+ this.log.debug(`****- endpoint ${CYAN}${endpointName}${db} already added!`);
595
+ alreadyAdded = true;
596
+ }
597
+ else {
467
598
  if ('tagList' in options) {
468
599
  for (const tag of options.tagList) {
469
600
  this.log.debug(`- with tagList: mfgCode ${CYAN}${tag.mfgCode}${db} namespaceId ${CYAN}${tag.namespaceId}${db} tag ${CYAN}${tag.tag}${db} label ${CYAN}${tag.label}${db}`);
470
601
  }
471
- child = new MatterbridgeEndpoint(definition, { uniqueStorageKey: endpointName, tagList: options.tagList }, debug);
602
+ child = new MatterbridgeEndpoint(definition, { uniqueStorageKey: endpointName, endpointId: options.endpointId, tagList: options.tagList }, debug);
472
603
  }
473
604
  else {
474
- child = new MatterbridgeEndpoint(definition, { uniqueStorageKey: endpointName }, debug);
605
+ child = new MatterbridgeEndpoint(definition, { uniqueStorageKey: endpointName, endpointId: options.endpointId }, debug);
475
606
  }
476
607
  }
477
608
  if (Array.isArray(definition)) {
478
609
  definition.forEach((deviceType) => {
479
610
  this.log.debug(`- with deviceType: ${zb}${'0x' + deviceType.code.toString(16).padStart(4, '0')}${db}-${zb}${deviceType.name}${db}`);
480
611
  deviceType.requiredServerClusters.forEach((clusterId) => {
481
- if (!includeServerList.includes(clusterId))
482
- includeServerList.push(clusterId);
612
+ if (!serverList.includes(clusterId))
613
+ serverList.push(clusterId);
483
614
  });
484
615
  });
485
616
  }
486
617
  else {
487
618
  this.log.debug(`- with deviceType: ${zb}${'0x' + definition.code.toString(16).padStart(4, '0')}${db}-${zb}${definition.name}${db}`);
488
619
  definition.requiredServerClusters.forEach((clusterId) => {
489
- if (!includeServerList.includes(clusterId))
490
- includeServerList.push(clusterId);
620
+ if (!serverList.includes(clusterId))
621
+ serverList.push(clusterId);
491
622
  });
492
623
  }
493
- includeServerList.forEach((clusterId) => {
494
- if (!child.getClusterServerById(clusterId)) {
624
+ serverList.forEach((clusterId) => {
625
+ if (!child.hasClusterServer(clusterId)) {
495
626
  this.log.debug(`- with cluster: ${hk}${'0x' + clusterId.toString(16).padStart(4, '0')}${db}-${hk}${getClusterNameById(clusterId)}${db}`);
496
627
  }
497
628
  else {
498
- includeServerList.splice(includeServerList.indexOf(clusterId), 1);
629
+ serverList.splice(serverList.indexOf(clusterId), 1);
499
630
  }
500
631
  });
501
- this.addClusterServerFromList(child, includeServerList);
632
+ if (alreadyAdded) {
633
+ serverList.forEach((clusterId) => {
634
+ if (child.hasClusterServer(clusterId))
635
+ serverList.splice(serverList.indexOf(clusterId), 1);
636
+ });
637
+ }
638
+ addClusterServers(child, serverList);
639
+ if (alreadyAdded)
640
+ return child;
502
641
  if (this.lifecycle.isInstalled) {
503
642
  this.log.debug(`- with lifecycle installed`);
504
643
  this.add(child);
@@ -509,12 +648,6 @@ export class MatterbridgeEndpoint extends Endpoint {
509
648
  }
510
649
  return child;
511
650
  }
512
- /**
513
- * Retrieves a child endpoint by its name.
514
- *
515
- * @param {string} endpointName - The name of the endpoint to retrieve.
516
- * @returns {Endpoint | undefined} The child endpoint with the specified name, or undefined if not found.
517
- */
518
651
  getChildEndpointByName(endpointName) {
519
652
  return this.parts.find((part) => part.id === endpointName);
520
653
  }
@@ -524,546 +657,100 @@ export class MatterbridgeEndpoint extends Endpoint {
524
657
  getChildEndpoints() {
525
658
  return Array.from(this.parts);
526
659
  }
527
- getDeviceTypes() {
528
- return Array.from(this.deviceTypes.values());
529
- }
530
- /**
531
- * Sets the device types.
532
- *
533
- * @param {AtLeastOne<DeviceTypeDefinition>} deviceTypes - The device types to set.
534
- *
535
- * @deprecated This method is deprecated and will be removed in future versions.
536
- */
537
- setDeviceTypes(deviceTypes) {
538
- deviceTypes.forEach((deviceType) => {
539
- this.addDeviceType(deviceType);
540
- });
541
- }
542
- async setBridgedDeviceReachability(reachable) {
543
- // await this.setAttribute(BridgedDeviceBasicInformationCluster.id, 'reachable', reachable, this.log);
544
- // await this.triggerEvent(BridgedDeviceBasicInformationCluster.id, 'reachableChanged', { reachableNewValue: reachable }, this.log);
545
- }
546
- hasClusterServer(cluster) {
547
- return this.clusterServers.has(cluster.id);
548
- }
549
- getClusterServer(cluster) {
550
- const clusterServer = this.clusterServers.get(cluster.id);
551
- if (clusterServer !== undefined) {
552
- return clusterServer;
553
- }
554
- }
555
- getAllClusterServers() {
556
- return [...this.clusterServers.values()];
557
- }
558
- getClusterServerById(clusterId) {
559
- return this.clusterServers.get(clusterId);
560
- }
561
- /**
562
- * Add a tagList.
563
- *
564
- * @deprecated This method is deprecated and will be removed in future versions. Use the constructor options instead.
565
- */
566
- addTagList(endpoint, mfgCode, namespaceId, tag, label) {
567
- // Do nothing here only for old api compatibility
568
- }
569
- addClusterServer(cluster) {
570
- // console.log('addClusterServer:', cluster.id, cluster.name, cluster.attributes, cluster.events, cluster.commands);
571
- let features = {};
572
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
573
- const options = {};
574
- for (const attribute of Object.values(cluster.attributes)) {
575
- // console.error('Attribute:', (attribute as any).id, (attribute as any).name, (attribute as any).value);
576
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
577
- if (attribute.name === 'featureMap') {
578
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
579
- features = attribute.value;
580
- // console.log('Cluster', cluster.name, 'FeatureMap:', features);
581
- // options[(attribute as any).name] = (attribute as any).value;
582
- }
583
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
584
- if (attribute.id < 0xfff0) {
585
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
586
- options[attribute.name] = attribute.value;
587
- }
588
- }
589
- this.log.debug(`addClusterServer: ${hk}${'0x' + cluster.id.toString(16).padStart(4, '0')}${db}-${hk}${getClusterNameById(cluster.id)}${db} with options: ${debugStringify(options)}${rs}`);
590
- if (this.clusterServers.has(cluster.id)) {
591
- this.log.debug(`****cluster ${hk}${'0x' + cluster.id.toString(16).padStart(4, '0')}${db}-${hk}${getClusterNameById(cluster.id)}${db} already added`);
592
- }
593
- this.subType = '';
594
- if (cluster.id === OnOffCluster.id && features['lighting'])
595
- this.subType = 'LightingOnOff';
596
- if (cluster.id === OnOffCluster.id && features['deadFrontBehavior'])
597
- this.subType = 'DeadFrontBehaviorOnOff';
598
- if (cluster.id === ColorControl.Cluster.id && cluster.isAttributeSupportedByName('currentX') && !cluster.isAttributeSupportedByName('currentHue'))
599
- this.subType = 'XyColorControl';
600
- else if (cluster.id === ColorControl.Cluster.id && cluster.isAttributeSupportedByName('currentHue') && !cluster.isAttributeSupportedByName('currentX'))
601
- this.subType = 'HueSaturationColorControl';
602
- else if (cluster.id === ColorControl.Cluster.id && cluster.isAttributeSupportedByName('colorTemperatureMireds') && !cluster.isAttributeSupportedByName('currentHue') && !cluster.isAttributeSupportedByName('currentX'))
603
- this.subType = 'ColorTemperatureColorControl';
604
- else if (cluster.id === ColorControl.Cluster.id)
605
- this.subType = 'CompleteColorControl';
606
- if (cluster.id === SwitchCluster.id && cluster.isEventSupportedByName('multiPressComplete'))
607
- this.subType = 'MomentarySwitch';
608
- if (cluster.id === SwitchCluster.id && cluster.isEventSupportedByName('switchLatched'))
609
- this.subType = 'LatchingSwitch';
610
- if (cluster.id === PowerSourceCluster.id && cluster.isAttributeSupportedByName('wiredCurrentType'))
611
- this.subType = 'WiredPowerSource';
612
- if (cluster.id === PowerSourceCluster.id && cluster.isAttributeSupportedByName('batReplacementDescription'))
613
- this.subType = 'BatteryReplaceablePowerSource';
614
- if (cluster.id === PowerSourceCluster.id && cluster.isAttributeSupportedByName('batChargeState'))
615
- this.subType = 'BatteryRechargeablePowerSource';
616
- if (cluster.id === ThermostatCluster.id && cluster.isAttributeSupportedByName('occupiedCoolingSetpoint'))
617
- this.subType = 'CoolingThermostat';
618
- if (cluster.id === ThermostatCluster.id && cluster.isAttributeSupportedByName('occupiedHeatingSetpoint'))
619
- this.subType = 'HeatingThermostat';
620
- if (cluster.id === ThermostatCluster.id && cluster.isAttributeSupportedByName('minSetpointDeadBand'))
621
- this.subType = 'AutoModeThermostat';
622
- const behavior = MatterbridgeEndpoint.getBehaviourTypeFromClusterServerId(cluster.id, this.subType);
623
- this.clusterServers.set(cluster.id, cluster);
624
- if (cluster.id === BasicInformationCluster.id)
625
- return; // Not used in Matterbridge edge for devices. Only on server node.
626
- this.behaviors.require(behavior, options);
627
- }
628
- /**
629
- * Adds cluster servers to the specified endpoint based on the provided server list.
630
- *
631
- * @param {Endpoint} endpoint - The endpoint to add cluster servers to.
632
- * @param {ClusterId[]} includeServerList - The list of cluster IDs to include.
633
- * @returns void
634
- */
635
- addClusterServerFromList(endpoint, includeServerList) {
636
- if (includeServerList.includes(Identify.Cluster.id))
637
- endpoint.addClusterServer(this.getDefaultIdentifyClusterServer());
638
- if (includeServerList.includes(Groups.Cluster.id))
639
- endpoint.addClusterServer(this.getDefaultGroupsClusterServer());
640
- if (includeServerList.includes(OnOff.Cluster.id))
641
- endpoint.addClusterServer(this.getDefaultOnOffClusterServer());
642
- if (includeServerList.includes(LevelControl.Cluster.id))
643
- endpoint.addClusterServer(this.getDefaultLevelControlClusterServer());
644
- if (includeServerList.includes(ColorControl.Cluster.id))
645
- endpoint.addClusterServer(this.getDefaultColorControlClusterServer());
646
- if (includeServerList.includes(Switch.Cluster.id))
647
- endpoint.addClusterServer(this.getDefaultSwitchClusterServer());
648
- if (includeServerList.includes(DoorLock.Cluster.id))
649
- endpoint.addClusterServer(this.getDefaultDoorLockClusterServer());
650
- if (includeServerList.includes(Thermostat.Cluster.id))
651
- endpoint.addClusterServer(this.getDefaultThermostatClusterServer());
652
- if (includeServerList.includes(WindowCovering.Cluster.id))
653
- endpoint.addClusterServer(this.getDefaultWindowCoveringClusterServer());
654
- if (includeServerList.includes(FanControl.Cluster.id))
655
- endpoint.addClusterServer(this.getDefaultFanControlClusterServer());
656
- if (includeServerList.includes(TemperatureMeasurement.Cluster.id))
657
- endpoint.addClusterServer(this.getDefaultTemperatureMeasurementClusterServer());
658
- if (includeServerList.includes(RelativeHumidityMeasurement.Cluster.id))
659
- endpoint.addClusterServer(this.getDefaultRelativeHumidityMeasurementClusterServer());
660
- if (includeServerList.includes(PressureMeasurement.Cluster.id))
661
- endpoint.addClusterServer(this.getDefaultPressureMeasurementClusterServer());
662
- if (includeServerList.includes(FlowMeasurement.Cluster.id))
663
- endpoint.addClusterServer(this.getDefaultFlowMeasurementClusterServer());
664
- if (includeServerList.includes(BooleanState.Cluster.id))
665
- endpoint.addClusterServer(this.getDefaultBooleanStateClusterServer());
666
- if (includeServerList.includes(BooleanStateConfiguration.Cluster.id))
667
- endpoint.addClusterServer(this.getDefaultBooleanStateConfigurationClusterServer());
668
- if (includeServerList.includes(OccupancySensing.Cluster.id))
669
- endpoint.addClusterServer(this.getDefaultOccupancySensingClusterServer());
670
- if (includeServerList.includes(IlluminanceMeasurement.Cluster.id))
671
- endpoint.addClusterServer(this.getDefaultIlluminanceMeasurementClusterServer());
672
- if (includeServerList.includes(PowerSource.Cluster.id))
673
- endpoint.addClusterServer(this.getDefaultPowerSourceWiredClusterServer());
674
- if (includeServerList.includes(PowerTopology.Cluster.id))
675
- endpoint.addClusterServer(this.getDefaultPowerTopologyClusterServer());
676
- if (includeServerList.includes(ElectricalPowerMeasurement.Cluster.id))
677
- endpoint.addClusterServer(this.getDefaultElectricalPowerMeasurementClusterServer());
678
- if (includeServerList.includes(ElectricalEnergyMeasurement.Cluster.id))
679
- endpoint.addClusterServer(this.getDefaultElectricalEnergyMeasurementClusterServer());
680
- if (includeServerList.includes(SmokeCoAlarm.Cluster.id))
681
- endpoint.addClusterServer(this.getDefaultSmokeCOAlarmClusterServer());
682
- if (includeServerList.includes(AirQuality.Cluster.id))
683
- endpoint.addClusterServer(this.getDefaultAirQualityClusterServer());
684
- if (includeServerList.includes(CarbonMonoxideConcentrationMeasurement.Cluster.id))
685
- endpoint.addClusterServer(this.getDefaultCarbonMonoxideConcentrationMeasurementClusterServer());
686
- if (includeServerList.includes(CarbonDioxideConcentrationMeasurement.Cluster.id))
687
- endpoint.addClusterServer(this.getDefaultCarbonDioxideConcentrationMeasurementClusterServer());
688
- if (includeServerList.includes(NitrogenDioxideConcentrationMeasurement.Cluster.id))
689
- endpoint.addClusterServer(this.getDefaultNitrogenDioxideConcentrationMeasurementClusterServer());
690
- if (includeServerList.includes(OzoneConcentrationMeasurement.Cluster.id))
691
- endpoint.addClusterServer(this.getDefaultOzoneConcentrationMeasurementClusterServer());
692
- if (includeServerList.includes(FormaldehydeConcentrationMeasurement.Cluster.id))
693
- endpoint.addClusterServer(this.getDefaultFormaldehydeConcentrationMeasurementClusterServer());
694
- if (includeServerList.includes(Pm1ConcentrationMeasurement.Cluster.id))
695
- endpoint.addClusterServer(this.getDefaultPm1ConcentrationMeasurementClusterServer());
696
- if (includeServerList.includes(Pm25ConcentrationMeasurement.Cluster.id))
697
- endpoint.addClusterServer(this.getDefaultPm25ConcentrationMeasurementClusterServer());
698
- if (includeServerList.includes(Pm10ConcentrationMeasurement.Cluster.id))
699
- endpoint.addClusterServer(this.getDefaultPm10ConcentrationMeasurementClusterServer());
700
- if (includeServerList.includes(RadonConcentrationMeasurement.Cluster.id))
701
- endpoint.addClusterServer(this.getDefaultRadonConcentrationMeasurementClusterServer());
702
- if (includeServerList.includes(TotalVolatileOrganicCompoundsConcentrationMeasurement.Cluster.id))
703
- endpoint.addClusterServer(this.getDefaultTvocMeasurementClusterServer());
704
- // if (includeServerList.includes(DeviceEnergyManagement.Cluster.id)) endpoint.addClusterServer(this.getDefaultDeviceEnergyManagementClusterServer());
705
- // if (includeServerList.includes(DeviceEnergyManagementMode.Cluster.id)) endpoint.addClusterServer(this.getDefaultDeviceEnergyManagementModeClusterServer());
706
- }
707
- async addFixedLabel(label, value) {
708
- if (!this.clusterServers.get(FixedLabelCluster.id)) {
709
- this.log.debug(`addFixedLabel: add cluster ${hk}FixedLabelCluster${db} with label ${CYAN}${label}${db} value ${CYAN}${value}${db}`);
710
- this.addClusterServer(ClusterServer(FixedLabelCluster, {
711
- labelList: [{ label, value }],
712
- }, {}));
713
- return;
714
- }
715
- this.log.debug(`addFixedLabel: add label ${CYAN}${label}${db} value ${CYAN}${value}${db}`);
716
- const labelList = (this.getAttribute(FixedLabelCluster.id, 'labelList', this.log) ?? []).filter((entryLabel) => entryLabel.label !== label);
717
- labelList.push({ label, value });
718
- await this.setAttribute(FixedLabelCluster.id, 'labelList', labelList, this.log);
719
- }
720
- async addUserLabel(label, value) {
721
- if (!this.clusterServers.get(UserLabelCluster.id)) {
722
- this.log.debug(`addUserLabel: add cluster ${hk}UserLabelCluster${db} with label ${CYAN}${label}${db} value ${CYAN}${value}${db}`);
723
- this.addClusterServer(ClusterServer(UserLabelCluster, {
724
- labelList: [{ label, value }],
725
- }, {}));
660
+ static serialize(device) {
661
+ if (!device.serialNumber || !device.deviceName || !device.uniqueId)
726
662
  return;
727
- }
728
- this.log.debug(`addUserLabel: add label ${CYAN}${label}${db} value ${CYAN}${value}${db}`);
729
- const labelList = (this.getAttribute(UserLabelCluster.id, 'labelList', this.log) ?? []).filter((entryLabel) => entryLabel.label !== label);
730
- labelList.push({ label, value });
731
- await this.setAttribute(UserLabelCluster.id, 'labelList', labelList, this.log);
732
- }
733
- capitalizeFirstLetter(name) {
734
- if (!name)
735
- return name;
736
- return name.charAt(0).toUpperCase() + name.slice(1);
737
- }
738
- lowercaseFirstLetter(name) {
739
- if (!name)
740
- return name;
741
- return name.charAt(0).toLowerCase() + name.slice(1);
742
- }
743
- /**
744
- * Retrieves the value of the specified attribute from the given endpoint and cluster.
745
- *
746
- * @param {ClusterId} clusterId - The ID of the cluster to retrieve the attribute from.
747
- * @param {string} attribute - The name of the attribute to retrieve.
748
- * @param {AnsiLogger} [log] - Optional logger for error and info messages.
749
- * @param {MatterbridgeEndpoint} [endpoint] - Optional the child endpoint to retrieve the attribute from.
750
- * @returns {any} The value of the attribute, or undefined if the attribute is not found.
751
- */
752
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
753
- getAttribute(clusterId, attribute, log, endpoint) {
754
- if (!endpoint)
755
- endpoint = this;
756
- const clusterName = this.lowercaseFirstLetter(getClusterNameById(clusterId));
757
- if (endpoint.construction.status !== Lifecycle.Status.Active) {
758
- this.log.error(`getAttribute ${hk}${clusterName}.${attribute}${er} error: Endpoint ${or}${endpoint.id}${er} is in the ${BLUE}${endpoint.construction.status}${er} state`);
759
- return undefined;
760
- }
761
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
762
- const state = endpoint.state;
763
- if (!(clusterName in state)) {
764
- this.log.error(`getAttribute error: Cluster ${'0x' + clusterId.toString(16).padStart(4, '0')}:${clusterName} not found on endpoint ${or}${endpoint.id}${er}:${or}${endpoint.number}${er}`);
765
- return undefined;
766
- }
767
- attribute = this.lowercaseFirstLetter(attribute);
768
- if (!(attribute in state[clusterName])) {
769
- this.log.error(`getAttribute error: Attribute ${hk}${attribute}${er} not found on Cluster ${'0x' + clusterId.toString(16).padStart(4, '0')}:${clusterName} on endpoint ${or}${endpoint.id}${er}:${or}${endpoint.number}${er}`);
770
- return undefined;
771
- }
772
- const value = state[clusterName][attribute];
773
- log?.info(`${db}Get endpoint ${or}${endpoint.id}${db}:${or}${endpoint.number}${db} attribute ${hk}${this.capitalizeFirstLetter(clusterName)}${db}.${hk}${attribute}${db} value ${YELLOW}${typeof value === 'object' ? debugStringify(value) : value}${db}`);
774
- return value;
775
- }
776
- /**
777
- * Sets the value of an attribute on a cluster server endpoint.
778
- *
779
- * @param {ClusterId} clusterId - The ID of the cluster.
780
- * @param {string} attribute - The name of the attribute.
781
- * @param {any} value - The value to set for the attribute.
782
- * @param {AnsiLogger} [log] - (Optional) The logger to use for logging errors and information.
783
- * @param {MatterbridgeEndpoint} [endpoint] - (Optional) The endpoint to set the attribute on. If not provided, the attribute will be set on the current endpoint.
784
- * @returns {Promise<boolean>} - A promise that resolves to a boolean indicating whether the attribute was successfully set.
785
- */
786
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
787
- async setAttribute(clusterId, attribute, value, log, endpoint) {
788
- if (!endpoint)
789
- endpoint = this;
790
- const clusterName = this.lowercaseFirstLetter(getClusterNameById(clusterId));
791
- if (endpoint.construction.status !== Lifecycle.Status.Active) {
792
- this.log.error(`setAttribute ${hk}${clusterName}.${attribute}${er} error: Endpoint ${or}${endpoint.id}${er} is in the ${BLUE}${endpoint.construction.status}${er} state`);
793
- return false;
794
- }
795
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
796
- const state = endpoint.state;
797
- if (!(clusterName in state)) {
798
- this.log.error(`setAttribute ${hk}${attribute}${er} error: Cluster ${'0x' + clusterId.toString(16).padStart(4, '0')}:${clusterName} not found on endpoint ${or}${endpoint.id}${er}:${or}${endpoint.number}${er}`);
799
- return false;
800
- }
801
- attribute = this.lowercaseFirstLetter(attribute);
802
- if (!(attribute in state[clusterName])) {
803
- this.log.error(`setAttribute error: Attribute ${hk}${attribute}${er} not found on Cluster ${'0x' + clusterId.toString(16).padStart(4, '0')}:${clusterName} on endpoint ${or}${endpoint.id}${er}:${or}${endpoint.number}${er}`);
804
- return false;
805
- }
806
- let oldValue = state[clusterName][attribute];
807
- if (typeof oldValue === 'object')
808
- oldValue = deepCopy(oldValue);
809
- await endpoint.setStateOf(endpoint.behaviors.supported[clusterName], { [attribute]: value });
810
- log?.info(`${db}Set endpoint ${or}${endpoint.id}${db}:${or}${endpoint.number}${db} attribute ${hk}${this.capitalizeFirstLetter(clusterName)}${db}.${hk}${attribute}${db} ` +
811
- `from ${YELLOW}${typeof oldValue === 'object' ? debugStringify(oldValue) : oldValue}${db} ` +
812
- `to ${YELLOW}${typeof value === 'object' ? debugStringify(value) : value}${db}`);
813
- return true;
814
- }
815
- /**
816
- * Subscribes to an attribute on a cluster.
817
- *
818
- * @param {ClusterId} clusterId - The ID of the cluster.
819
- * @param {string} attribute - The name of the attribute to subscribe to.
820
- * @param {(newValue: any, oldValue: any) => void} listener - A callback function that will be called when the attribute value changes.
821
- * @param {AnsiLogger} [log] - Optional logger for logging errors and information.
822
- * @param {MatterbridgeEndpoint} [endpoint] - Optional endpoint to subscribe the attribute on. Defaults to the current endpoint.
823
- * @returns {boolean} - A boolean indicating whether the subscription was successful.
824
- */
825
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
826
- async subscribeAttribute(clusterId, attribute, listener, log, endpoint) {
827
- if (!endpoint)
828
- endpoint = this;
829
- const clusterName = this.lowercaseFirstLetter(getClusterNameById(clusterId));
830
- if (endpoint.construction.status !== Lifecycle.Status.Active) {
831
- // this.log.error(`subscribeAttribute ${hk}${clusterName}.${attribute}${er} error: Endpoint ${or}${endpoint.id}${er} is in the ${BLUE}${endpoint.construction.status}${er} state`);
832
- await endpoint.construction.ready;
833
- }
834
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
835
- const events = endpoint.events;
836
- if (!(clusterName in events)) {
837
- this.log.error(`subscribeAttribute ${hk}${attribute}${er} error: Cluster ${'0x' + clusterId.toString(16).padStart(4, '0')}:${clusterName} not found on endpoint ${or}${endpoint.id}${er}:${or}${endpoint.number}${er}`);
838
- return false;
839
- }
840
- attribute = this.lowercaseFirstLetter(attribute) + '$Changed';
841
- if (!(attribute in events[clusterName])) {
842
- this.log.error(`subscribeAttribute error: Attribute ${hk}${attribute}${er} not found on Cluster ${'0x' + clusterId.toString(16).padStart(4, '0')}:${clusterName} on endpoint ${or}${endpoint.id}${er}:${or}${endpoint.number}${er}`);
843
- return false;
844
- }
845
- events[clusterName][attribute].on(listener);
846
- log?.info(`${db}Subscribe endpoint ${or}${endpoint.id}${db}:${or}${endpoint.number}${db} attribute ${hk}${this.capitalizeFirstLetter(clusterName)}${db}.${hk}${attribute}${db}`);
847
- return true;
848
- }
849
- /**
850
- * Triggers an event on the specified cluster.
851
- *
852
- * @param {ClusterId} clusterId - The ID of the cluster.
853
- * @param {string} event - The name of the event to trigger.
854
- * @param {Record<string, boolean | number | bigint | string | object | undefined | null>} payload - The payload to pass to the event.
855
- * @param {AnsiLogger} [log] - Optional logger for logging information.
856
- * @param {MatterbridgeEndpoint} [endpoint] - Optional endpoint to trigger the event on. Defaults to the current endpoint.
857
- * @returns {Promise<boolean>} - A promise that resolves to a boolean indicating whether the event was successfully triggered.
858
- */
859
- async triggerEvent(clusterId, event, payload, log, endpoint) {
860
- if (!endpoint)
861
- endpoint = this;
862
- const clusterName = this.lowercaseFirstLetter(getClusterNameById(clusterId));
863
- if (endpoint.construction.status !== Lifecycle.Status.Active) {
864
- // this.log.error(`triggerEvent ${hk}${clusterName}.${event}${er} error: Endpoint ${or}${endpoint.id}${er} is in the ${BLUE}${endpoint.construction.status}${er} state`);
865
- await endpoint.construction.ready;
866
- // return false;
867
- }
868
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
869
- const events = endpoint.events;
870
- if (!(clusterName in events) || !(event in events[clusterName])) {
871
- this.log.error(`triggerEvent ${hk}${event}${er} error: Cluster ${'0x' + clusterId.toString(16).padStart(4, '0')}:${clusterName} not found on endpoint ${or}${endpoint.id}${er}:${or}${endpoint.number}${er}`);
872
- return false;
873
- }
874
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
875
- // @ts-ignore
876
- await endpoint.act((agent) => agent[clusterName].events[event].emit(payload, agent.context));
877
- log?.info(`${db}Trigger event ${hk}${this.capitalizeFirstLetter(clusterName)}${db}.${hk}${event}${db} with ${debugStringify(payload)}${db} on endpoint ${or}${endpoint.id}${db}:${or}${endpoint.number}${db} `);
878
- return true;
879
- }
880
- /**
881
- * Adds a command handler for the specified command.
882
- *
883
- * @param {keyof MatterbridgeEndpointCommands} command - The command to add the handler for.
884
- * @param {(data: any) => void} handler - The handler function to execute when the command is received.
885
- * @returns {void}
886
- */
887
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
888
- addCommandHandler(command, handler) {
889
- this.commandHandler.addHandler(command, handler);
890
- }
891
- /**
892
- * Serializes the Matterbridge device into a serialized object.
893
- *
894
- * @param pluginName - The name of the plugin.
895
- * @returns The serialized Matterbridge device object.
896
- */
897
- serialize() {
898
- return undefined;
899
- /*
900
- if (!this.serialNumber || !this.deviceName || !this.uniqueId) return;
901
- const cluster = this.getClusterServer(BasicInformationCluster) ?? this.getClusterServer(BridgedDeviceBasicInformationCluster);
902
- if (!cluster) return;
903
- const serialized: SerializedMatterbridgeDevice = {
904
- pluginName: this.plugin ?? 'Unknown',
905
- serialNumber: this.serialNumber,
906
- deviceName: this.deviceName,
907
- uniqueId: this.uniqueId,
908
- productName: cluster.attributes.productName?.getLocal(),
909
- vendorId: cluster.attributes.vendorId?.getLocal(),
910
- vendorName: cluster.attributes.vendorName?.getLocal(),
911
- deviceTypes: Array.from(this.deviceTypes.values()),
912
- endpoint: this.number,
913
- endpointName: this.id,
914
- clusterServersId: [],
663
+ const serialized = {
664
+ pluginName: device.plugin ?? '',
665
+ deviceName: device.deviceName,
666
+ serialNumber: device.serialNumber,
667
+ uniqueId: device.uniqueId,
668
+ productId: device.productId,
669
+ productName: device.productName,
670
+ vendorId: device.vendorId,
671
+ vendorName: device.vendorName,
672
+ deviceTypes: Array.from(device.deviceTypes.values()),
673
+ endpoint: device.maybeNumber,
674
+ endpointName: device.maybeId ?? device.deviceName,
675
+ clusterServersId: [],
915
676
  };
916
- this.getAllClusterServers().forEach((clusterServer) => {
917
- serialized.clusterServersId.push(clusterServer.id);
677
+ Object.keys(device.behaviors.supported).forEach((behaviorName) => {
678
+ if (behaviorName === 'bridgedDeviceBasicInformation')
679
+ serialized.clusterServersId.push(BridgedDeviceBasicInformation.Cluster.id);
680
+ if (behaviorName === 'powerSource')
681
+ serialized.clusterServersId.push(PowerSource.Cluster.id);
918
682
  });
919
683
  return serialized;
920
- */
921
684
  }
922
- /**
923
- * Deserializes the device into a serialized object.
924
- *
925
- * @returns The deserialized MatterbridgeDevice.
926
- */
927
685
  static deserialize(serializedDevice) {
928
- return undefined;
929
- /*
930
- const device = new MatterbridgeDevice(serializedDevice.deviceTypes);
931
- device.serialNumber = serializedDevice.serialNumber;
686
+ const device = new MatterbridgeEndpoint(serializedDevice.deviceTypes, { uniqueStorageKey: serializedDevice.endpointName, endpointId: serializedDevice.endpoint }, false);
687
+ device.plugin = serializedDevice.pluginName;
932
688
  device.deviceName = serializedDevice.deviceName;
689
+ device.serialNumber = serializedDevice.serialNumber;
933
690
  device.uniqueId = serializedDevice.uniqueId;
691
+ device.vendorId = serializedDevice.vendorId;
692
+ device.vendorName = serializedDevice.vendorName;
693
+ device.productId = serializedDevice.productId;
694
+ device.productName = serializedDevice.productName;
934
695
  for (const clusterId of serializedDevice.clusterServersId) {
935
- if (clusterId === BasicInformationCluster.id)
936
- device.createDefaultBasicInformationClusterServer(
937
- serializedDevice.deviceName,
938
- serializedDevice.serialNumber,
939
- serializedDevice.vendorId ?? 0xfff1,
940
- serializedDevice.vendorName ?? 'Matterbridge',
941
- serializedDevice.productId ?? 0x8000,
942
- serializedDevice.productName ?? 'Matterbridge device',
943
- );
944
- else if (clusterId === BridgedDeviceBasicInformationCluster.id)
945
- device.createDefaultBridgedDeviceBasicInformationClusterServer(
946
- serializedDevice.deviceName,
947
- serializedDevice.serialNumber,
948
- serializedDevice.vendorId ?? 0xfff1,
949
- serializedDevice.vendorName ?? 'Matterbridge',
950
- serializedDevice.productName ?? 'Matterbridge device',
951
- );
952
- else device.addClusterServerFromList(device, [clusterId]);
696
+ if (clusterId === BridgedDeviceBasicInformation.Cluster.id)
697
+ device.createDefaultBridgedDeviceBasicInformationClusterServer(serializedDevice.deviceName, serializedDevice.serialNumber, serializedDevice.vendorId ?? 0xfff1, serializedDevice.vendorName ?? 'Matterbridge', serializedDevice.productName ?? 'Matterbridge device');
698
+ else if (clusterId === PowerSource.Cluster.id)
699
+ device.createDefaultPowerSourceWiredClusterServer();
953
700
  }
954
701
  return device;
955
- */
956
- }
957
- /**
958
- * From here copy paste from MatterbridgeDevice
959
- */
960
- /**
961
- * Get a default IdentifyCluster server.
962
- */
963
- getDefaultIdentifyClusterServer(identifyTime = 0, identifyType = Identify.IdentifyType.None) {
964
- return ClusterServer(IdentifyCluster, {
965
- identifyTime,
966
- identifyType,
967
- }, {
968
- identify: async (data) => {
969
- // Never called in edge
970
- },
971
- triggerEffect: async (data) => {
972
- // Never called in edge
973
- },
974
- });
975
- }
976
- /**
977
- * Creates a default IdentifyCluster server.
978
- */
979
- createDefaultIdentifyClusterServer(identifyTime = 0, identifyType = Identify.IdentifyType.None) {
980
- this.addClusterServer(this.getDefaultIdentifyClusterServer(identifyTime, identifyType));
981
- return this;
982
- }
983
- /**
984
- * Get a default IdentifyCluster server.
985
- */
986
- getDefaultGroupsClusterServer() {
987
- return ClusterServer(GroupsCluster, {
988
- nameSupport: {
989
- nameSupport: true,
990
- },
991
- }, GroupsClusterHandler());
992
- // return createDefaultGroupsClusterServer();
993
702
  }
994
- /**
995
- * Creates a default groups cluster server and adds it to the device.
996
- */
997
- createDefaultGroupsClusterServer() {
998
- this.addClusterServer(this.getDefaultGroupsClusterServer());
703
+ createDefaultPowerSourceWiredClusterServer(wiredCurrentType = PowerSource.WiredCurrentType.Ac) {
704
+ this.behaviors.require(PowerSourceServer.with(PowerSource.Feature.Wired), {
705
+ wiredCurrentType,
706
+ description: wiredCurrentType === PowerSource.WiredCurrentType.Ac ? 'AC Power' : 'DC Power',
707
+ status: PowerSource.PowerSourceStatus.Active,
708
+ order: 0,
709
+ endpointList: [],
710
+ });
999
711
  return this;
1000
712
  }
1001
- /**
1002
- * Get a default scenes cluster server and adds it to the current instance.
1003
- * @deprecated This method is deprecated.
1004
- *
1005
- */
1006
- getDefaultScenesClusterServer() {
1007
- /*
1008
- return ClusterServer(
1009
- ScenesCluster,
1010
- {
1011
- sceneCount: 0,
1012
- currentScene: 0,
1013
- currentGroup: GroupId(0),
1014
- sceneValid: false,
1015
- nameSupport: {
1016
- nameSupport: true,
1017
- },
1018
- lastConfiguredBy: null,
1019
- },
1020
- {},
1021
- );
1022
- */
1023
- }
1024
- /**
1025
- * Creates a default scenes cluster server and adds it to the current instance.
1026
- * @deprecated This method is deprecated.
1027
- */
1028
- createDefaultScenesClusterServer() {
1029
- /*
1030
- this.addClusterServer(this.getDefaultScenesClusterServer());
1031
- */
713
+ createDefaultPowerSourceReplaceableBatteryClusterServer(batPercentRemaining = 100, batChargeLevel = PowerSource.BatChargeLevel.Ok, batVoltage = 1500, batReplacementDescription = 'Battery type', batQuantity = 1) {
714
+ this.behaviors.require(PowerSourceServer.with(PowerSource.Feature.Battery, PowerSource.Feature.Replaceable), {
715
+ status: PowerSource.PowerSourceStatus.Active,
716
+ order: 0,
717
+ description: 'Primary battery',
718
+ batVoltage,
719
+ batPercentRemaining: Math.min(Math.max(batPercentRemaining * 2, 0), 200),
720
+ batChargeLevel,
721
+ batReplacementNeeded: false,
722
+ batReplaceability: PowerSource.BatReplaceability.UserReplaceable,
723
+ activeBatFaults: undefined,
724
+ batReplacementDescription,
725
+ batQuantity,
726
+ endpointList: [],
727
+ });
1032
728
  return this;
1033
729
  }
1034
- /**
1035
- * Creates a unique identifier based on the provided parameters.
1036
- * @param param1 - The first parameter.
1037
- * @param param2 - The second parameter.
1038
- * @param param3 - The third parameter.
1039
- * @param param4 - The fourth parameter.
1040
- * @returns A unique identifier generated using the MD5 hash algorithm.
1041
- */
1042
- createUniqueId(param1, param2, param3, param4) {
1043
- const hash = createHash('md5');
1044
- hash.update(param1 + param2 + param3 + param4);
1045
- return hash.digest('hex');
1046
- }
1047
- /**
1048
- * Get a default Basic Information Cluster Server.
1049
- *
1050
- * @param deviceName - The name of the device.
1051
- * @param serialNumber - The serial number of the device.
1052
- * @param vendorId - The vendor ID of the device.
1053
- * @param vendorName - The vendor name of the device.
1054
- * @param productId - The product ID of the device.
1055
- * @param productName - The product name of the device.
1056
- * @param softwareVersion - The software version of the device. Default is 1.
1057
- * @param softwareVersionString - The software version string of the device. Default is 'v.1.0.0'.
1058
- * @param hardwareVersion - The hardware version of the device. Default is 1.
1059
- * @param hardwareVersionString - The hardware version string of the device. Default is 'v.1.0.0'.
1060
- */
1061
- getDefaultBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productId, productName, softwareVersion = 1, softwareVersionString = '1.0.0', hardwareVersion = 1, hardwareVersionString = '1.0.0') {
1062
- this.log.logName = deviceName;
1063
- this.deviceName = deviceName;
1064
- this.serialNumber = serialNumber;
1065
- this.uniqueId = this.createUniqueId(deviceName, serialNumber, vendorName, productName);
1066
- this.productId = productId;
730
+ createDefaultPowerSourceRechargeableBatteryClusterServer(batPercentRemaining = 100, batChargeLevel = PowerSource.BatChargeLevel.Ok, batVoltage = 1500) {
731
+ this.behaviors.require(PowerSourceServer.with(PowerSource.Feature.Battery, PowerSource.Feature.Rechargeable), {
732
+ status: PowerSource.PowerSourceStatus.Active,
733
+ order: 0,
734
+ description: 'Primary battery',
735
+ batVoltage,
736
+ batPercentRemaining: Math.min(Math.max(batPercentRemaining * 2, 0), 200),
737
+ batTimeRemaining: 1,
738
+ batChargeLevel,
739
+ batReplacementNeeded: false,
740
+ batReplaceability: PowerSource.BatReplaceability.Unspecified,
741
+ activeBatFaults: undefined,
742
+ batChargeState: PowerSource.BatChargeState.IsNotCharging,
743
+ batFunctionalWhileCharging: true,
744
+ endpointList: [],
745
+ });
746
+ return this;
747
+ }
748
+ createDefaultBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productId, productName, softwareVersion = 1, softwareVersionString = '1.0.0', hardwareVersion = 1, hardwareVersionString = '1.0.0') {
749
+ this.log.logName = deviceName;
750
+ this.deviceName = deviceName;
751
+ this.serialNumber = serialNumber;
752
+ this.uniqueId = createUniqueId(deviceName, serialNumber, vendorName, productName);
753
+ this.productId = productId;
1067
754
  this.productName = productName;
1068
755
  this.vendorId = vendorId;
1069
756
  this.vendorName = vendorName;
@@ -1071,74 +758,21 @@ export class MatterbridgeEndpoint extends Endpoint {
1071
758
  this.softwareVersionString = softwareVersionString;
1072
759
  this.hardwareVersion = hardwareVersion;
1073
760
  this.hardwareVersionString = hardwareVersionString;
1074
- return ClusterServer(BasicInformationCluster, {
1075
- dataModelRevision: 1,
1076
- location: 'XX',
1077
- vendorId: VendorId(vendorId),
1078
- vendorName: vendorName.slice(0, 32),
1079
- productId: productId,
1080
- productName: productName.slice(0, 32),
1081
- productUrl: this.productUrl,
1082
- productLabel: deviceName.slice(0, 64),
1083
- nodeLabel: deviceName.slice(0, 32),
1084
- serialNumber: serialNumber.slice(0, 32),
1085
- uniqueId: this.createUniqueId(deviceName, serialNumber, vendorName, productName),
1086
- softwareVersion,
1087
- softwareVersionString: softwareVersionString.slice(0, 64),
1088
- hardwareVersion,
1089
- hardwareVersionString: hardwareVersionString.slice(0, 64),
1090
- reachable: true,
1091
- capabilityMinima: { caseSessionsPerFabric: 3, subscriptionsPerFabric: 3 },
1092
- specificationVersion: Specification.SPECIFICATION_VERSION,
1093
- maxPathsPerInvoke: 1,
1094
- }, {}, {
1095
- startUp: true,
1096
- shutDown: true,
1097
- leave: true,
1098
- reachableChanged: true,
1099
- });
1100
- }
1101
- /**
1102
- * Creates a default Basic Information Cluster Server.
1103
- *
1104
- * @param deviceName - The name of the device.
1105
- * @param serialNumber - The serial number of the device.
1106
- * @param vendorId - The vendor ID of the device.
1107
- * @param vendorName - The vendor name of the device.
1108
- * @param productId - The product ID of the device.
1109
- * @param productName - The product name of the device.
1110
- * @param softwareVersion - The software version of the device. Default is 1.
1111
- * @param softwareVersionString - The software version string of the device. Default is 'v.1.0.0'.
1112
- * @param hardwareVersion - The hardware version of the device. Default is 1.
1113
- * @param hardwareVersionString - The hardware version string of the device. Default is 'v.1.0.0'.
1114
- */
1115
- createDefaultBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productId, productName, softwareVersion = 1, softwareVersionString = '1.0.0', hardwareVersion = 1, hardwareVersionString = '1.0.0') {
1116
761
  if (MatterbridgeEndpoint.bridgeMode === 'bridge') {
1117
- this.addDeviceType(bridgedNode);
762
+ const options = this.getClusterServerOptions(Descriptor.Cluster.id);
763
+ if (options) {
764
+ const deviceTypeList = options.deviceTypeList;
765
+ deviceTypeList.push({ deviceType: bridgedNode.code, revision: bridgedNode.revision });
766
+ }
1118
767
  this.createDefaultBridgedDeviceBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productName, softwareVersion, softwareVersionString, hardwareVersion, hardwareVersionString);
1119
- return;
1120
768
  }
1121
- this.addClusterServer(this.getDefaultBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productId, productName, softwareVersion, softwareVersionString, hardwareVersion, hardwareVersionString));
1122
769
  return this;
1123
770
  }
1124
- /**
1125
- * Get a default BridgedDeviceBasicInformationClusterServer.
1126
- *
1127
- * @param deviceName - The name of the device.
1128
- * @param serialNumber - The serial number of the device.
1129
- * @param vendorId - The vendor ID of the device.
1130
- * @param vendorName - The name of the vendor.
1131
- * @param productName - The name of the product.
1132
- * @param softwareVersion - The software version of the device. Default is 1.
1133
- * @param softwareVersionString - The software version string of the device. Default is 'v.1.0.0'.
1134
- * @param hardwareVersion - The hardware version of the device. Default is 1.
1135
- * @param hardwareVersionString - The hardware version string of the device. Default is 'v.1.0.0'.
1136
- */
1137
- getDefaultBridgedDeviceBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productName, softwareVersion = 1, softwareVersionString = '1.0.0', hardwareVersion = 1, hardwareVersionString = '1.0.0') {
771
+ createDefaultBridgedDeviceBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productName, softwareVersion = 1, softwareVersionString = '1.0.0', hardwareVersion = 1, hardwareVersionString = '1.0.0') {
1138
772
  this.log.logName = deviceName;
1139
773
  this.deviceName = deviceName;
1140
774
  this.serialNumber = serialNumber;
1141
- this.uniqueId = this.createUniqueId(deviceName, serialNumber, vendorName, productName);
775
+ this.uniqueId = createUniqueId(deviceName, serialNumber, vendorName, productName);
1142
776
  this.productId = undefined;
1143
777
  this.productName = productName;
1144
778
  this.vendorId = vendorId;
@@ -1147,248 +781,64 @@ export class MatterbridgeEndpoint extends Endpoint {
1147
781
  this.softwareVersionString = softwareVersionString;
1148
782
  this.hardwareVersion = hardwareVersion;
1149
783
  this.hardwareVersionString = hardwareVersionString;
1150
- return ClusterServer(BridgedDeviceBasicInformationCluster, {
1151
- vendorId: vendorId !== undefined ? VendorId(vendorId) : undefined, // 4874
784
+ this.behaviors.require(BridgedDeviceBasicInformationServer.enable({
785
+ events: { leave: true, reachableChanged: true },
786
+ }), {
787
+ vendorId: vendorId !== undefined ? VendorId(vendorId) : undefined,
1152
788
  vendorName: vendorName.slice(0, 32),
1153
789
  productName: productName.slice(0, 32),
1154
790
  productUrl: this.productUrl,
1155
791
  productLabel: deviceName.slice(0, 64),
1156
792
  nodeLabel: deviceName.slice(0, 32),
1157
793
  serialNumber: serialNumber.slice(0, 32),
1158
- uniqueId: this.createUniqueId(deviceName, serialNumber, vendorName, productName),
794
+ uniqueId: this.uniqueId,
1159
795
  softwareVersion,
1160
796
  softwareVersionString: softwareVersionString.slice(0, 64),
1161
797
  hardwareVersion,
1162
798
  hardwareVersionString: hardwareVersionString.slice(0, 64),
1163
799
  reachable: true,
1164
- }, {}, {
1165
- startUp: true,
1166
- shutDown: true,
1167
- leave: true,
1168
- reachableChanged: true,
1169
800
  });
1170
- }
1171
- /**
1172
- * Creates a default BridgedDeviceBasicInformationClusterServer.
1173
- *
1174
- * @param deviceName - The name of the device.
1175
- * @param serialNumber - The serial number of the device.
1176
- * @param vendorId - The vendor ID of the device.
1177
- * @param vendorName - The name of the vendor.
1178
- * @param productName - The name of the product.
1179
- * @param softwareVersion - The software version of the device. Default is 1.
1180
- * @param softwareVersionString - The software version string of the device. Default is 'v.1.0.0'.
1181
- * @param hardwareVersion - The hardware version of the device. Default is 1.
1182
- * @param hardwareVersionString - The hardware version string of the device. Default is 'v.1.0.0'.
1183
- */
1184
- createDefaultBridgedDeviceBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productName, softwareVersion = 1, softwareVersionString = '1.0.0', hardwareVersion = 1, hardwareVersionString = '1.0.0') {
1185
- this.addClusterServer(this.getDefaultBridgedDeviceBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productName, softwareVersion, softwareVersionString, hardwareVersion, hardwareVersionString));
1186
801
  return this;
1187
802
  }
1188
- /**
1189
- * Get a default Power Topology Cluster Server. Only needed for an electricalSensor device type.
1190
- *
1191
- * @returns {ClusterServer} - The configured Power Topology Cluster Server.
1192
- */
1193
- getDefaultPowerTopologyClusterServer() {
1194
- return ClusterServer(PowerTopologyCluster.with(PowerTopology.Feature.TreeTopology), {}, {}, {});
1195
- }
1196
- /**
1197
- * Get a default Electrical Energy Measurement Cluster Server.
1198
- *
1199
- * @param {number} energy - The total consumption value in mW/h.
1200
- * @returns {ClusterServer} - The configured Electrical Energy Measurement Cluster Server.
1201
- */
1202
- getDefaultElectricalEnergyMeasurementClusterServer(energy = null) {
1203
- return ClusterServer(ElectricalEnergyMeasurementCluster.with(ElectricalEnergyMeasurement.Feature.ImportedEnergy, ElectricalEnergyMeasurement.Feature.ExportedEnergy, ElectricalEnergyMeasurement.Feature.CumulativeEnergy), {
1204
- accuracy: {
1205
- measurementType: MeasurementType.ElectricalEnergy,
1206
- measured: true,
1207
- minMeasuredValue: Number.MIN_SAFE_INTEGER,
1208
- maxMeasuredValue: Number.MAX_SAFE_INTEGER,
1209
- accuracyRanges: [{ rangeMin: Number.MIN_SAFE_INTEGER, rangeMax: Number.MAX_SAFE_INTEGER, fixedMax: 1 }],
1210
- },
1211
- cumulativeEnergyReset: null,
1212
- cumulativeEnergyImported: energy ? { energy } : null,
1213
- cumulativeEnergyExported: null,
1214
- }, {}, {
1215
- cumulativeEnergyMeasured: true,
803
+ createDefaultIdentifyClusterServer(identifyTime = 0, identifyType = Identify.IdentifyType.None) {
804
+ this.behaviors.require(MatterbridgeIdentifyServer, {
805
+ identifyTime,
806
+ identifyType,
1216
807
  });
808
+ return this;
1217
809
  }
1218
- /**
1219
- * Get a default Electrical Power Measurement Cluster Server.
1220
- *
1221
- * @param {number} voltage - The voltage value in millivolts.
1222
- * @param {number} current - The current value in milliamperes.
1223
- * @param {number} power - The power value in milliwatts.
1224
- * @param {number} frequency - The frequency value in millihertz.
1225
- * @returns {ClusterServer} - The configured Electrical Power Measurement Cluster Server.
1226
- */
1227
- getDefaultElectricalPowerMeasurementClusterServer(voltage = null, current = null, power = null, frequency = null) {
1228
- return ClusterServer(ElectricalPowerMeasurementCluster.with(ElectricalPowerMeasurement.Feature.AlternatingCurrent), {
1229
- powerMode: ElectricalPowerMeasurement.PowerMode.Ac,
1230
- numberOfMeasurementTypes: 4,
1231
- accuracy: [
1232
- {
1233
- measurementType: MeasurementType.Voltage,
1234
- measured: true,
1235
- minMeasuredValue: Number.MIN_SAFE_INTEGER,
1236
- maxMeasuredValue: Number.MAX_SAFE_INTEGER,
1237
- accuracyRanges: [{ rangeMin: Number.MIN_SAFE_INTEGER, rangeMax: Number.MAX_SAFE_INTEGER, fixedMax: 1 }],
1238
- },
1239
- {
1240
- measurementType: MeasurementType.ActiveCurrent,
1241
- measured: true,
1242
- minMeasuredValue: Number.MIN_SAFE_INTEGER,
1243
- maxMeasuredValue: Number.MAX_SAFE_INTEGER,
1244
- accuracyRanges: [{ rangeMin: Number.MIN_SAFE_INTEGER, rangeMax: Number.MAX_SAFE_INTEGER, fixedMax: 1 }],
1245
- },
1246
- {
1247
- measurementType: MeasurementType.ActivePower,
1248
- measured: true,
1249
- minMeasuredValue: Number.MIN_SAFE_INTEGER,
1250
- maxMeasuredValue: Number.MAX_SAFE_INTEGER,
1251
- accuracyRanges: [{ rangeMin: Number.MIN_SAFE_INTEGER, rangeMax: Number.MAX_SAFE_INTEGER, fixedMax: 1 }],
1252
- },
1253
- {
1254
- measurementType: MeasurementType.Frequency,
1255
- measured: true,
1256
- minMeasuredValue: Number.MIN_SAFE_INTEGER,
1257
- maxMeasuredValue: Number.MAX_SAFE_INTEGER,
1258
- accuracyRanges: [{ rangeMin: Number.MIN_SAFE_INTEGER, rangeMax: Number.MAX_SAFE_INTEGER, fixedMax: 1 }],
1259
- },
1260
- ],
1261
- voltage: voltage,
1262
- activeCurrent: current,
1263
- activePower: power,
1264
- frequency: frequency,
1265
- }, {}, {});
1266
- }
1267
- /**
1268
- * Get a default OnOff cluster server for light devices.
1269
- *
1270
- * @param {boolean} [onOff=false] - The initial state of the OnOff cluster.
1271
- * @param {boolean} [globalSceneControl=false] - The global scene control state.
1272
- * @param {number} [onTime=0] - The on time value.
1273
- * @param {number} [offWaitTime=0] - The off wait time value.
1274
- * @param {OnOff.StartUpOnOff | null} [startUpOnOff=null] - The start-up OnOff state. Null means previous state.
1275
- * @returns {ClusterServer} - The configured OnOff cluster server.
1276
- */
1277
- getDefaultOnOffClusterServer(onOff = false, globalSceneControl = false, onTime = 0, offWaitTime = 0, startUpOnOff = null) {
1278
- return ClusterServer(OnOffCluster.with(OnOff.Feature.Lighting), {
810
+ createDefaultGroupsClusterServer() {
811
+ this.behaviors.require(GroupsServer);
812
+ return this;
813
+ }
814
+ createDefaultScenesClusterServer() {
815
+ this.behaviors.require(ScenesManagementServer);
816
+ return this;
817
+ }
818
+ createDefaultOnOffClusterServer(onOff = false, globalSceneControl = false, onTime = 0, offWaitTime = 0, startUpOnOff = null) {
819
+ this.behaviors.require(MatterbridgeOnOffServer.with(OnOff.Feature.Lighting), {
1279
820
  onOff,
1280
821
  globalSceneControl,
1281
822
  onTime,
1282
823
  offWaitTime,
1283
824
  startUpOnOff,
1284
- }, {
1285
- on: async (data) => {
1286
- // Never called in edge
1287
- },
1288
- off: async (data) => {
1289
- // Never called in edge
1290
- },
1291
- toggle: async (data) => {
1292
- // Never called in edge
1293
- },
1294
- offWithEffect: async () => {
1295
- // Never called in edge
1296
- },
1297
- onWithRecallGlobalScene: async () => {
1298
- // Never called in edge
1299
- },
1300
- onWithTimedOff: async () => {
1301
- // Never called in edge
1302
- },
1303
- }, {});
1304
- }
1305
- /**
1306
- * Creates a default OnOff cluster server for light devices.
1307
- *
1308
- * @param {boolean} [onOff=false] - The initial state of the OnOff cluster.
1309
- * @param {boolean} [globalSceneControl=false] - The global scene control state.
1310
- * @param {number} [onTime=0] - The on time value.
1311
- * @param {number} [offWaitTime=0] - The off wait time value.
1312
- * @param {OnOff.StartUpOnOff | null} [startUpOnOff=null] - The start-up OnOff state. Null means previous state.
1313
- * @returns {void}
1314
- */
1315
- createDefaultOnOffClusterServer(onOff = false, globalSceneControl = false, onTime = 0, offWaitTime = 0, startUpOnOff = null) {
1316
- this.addClusterServer(this.getDefaultOnOffClusterServer(onOff, globalSceneControl, onTime, offWaitTime, startUpOnOff));
825
+ });
1317
826
  return this;
1318
827
  }
1319
- /**
1320
- * Get an OnOff cluster server without features.
1321
- *
1322
- * @param {boolean} [onOff=false] - The initial state of the OnOff cluster.
1323
- *
1324
- * @returns {ClusterServer} - The configured OnOff cluster server.
1325
- */
1326
- getOnOffClusterServer(onOff = false) {
1327
- return ClusterServer(OnOffCluster, {
1328
- onOff,
1329
- }, {
1330
- on: async (data) => {
1331
- // Never called in edge
1332
- },
1333
- off: async (data) => {
1334
- // Never called in edge
1335
- },
1336
- toggle: async (data) => {
1337
- // Never called in edge
1338
- },
1339
- }, {});
1340
- }
1341
- /**
1342
- * Creates an OnOff cluster server without features.
1343
- *
1344
- * @param {boolean} [onOff=false] - The initial state of the OnOff cluster.
1345
- */
1346
828
  createOnOffClusterServer(onOff = false) {
1347
- this.addClusterServer(this.getOnOffClusterServer(onOff));
1348
- return this;
1349
- }
1350
- /**
1351
- * Get a DeadFront OnOff cluster server.
1352
- *
1353
- * @param {boolean} [onOff=false] - The initial state of the OnOff cluster.
1354
- *
1355
- * @returns {ClusterServer} - The configured OnOff cluster server.
1356
- */
1357
- getDeadFrontOnOffClusterServer(onOff = false) {
1358
- return ClusterServer(OnOffCluster.with(OnOff.Feature.DeadFrontBehavior), {
829
+ this.behaviors.require(MatterbridgeOnOffServer, {
1359
830
  onOff,
1360
- }, {
1361
- on: async (data) => {
1362
- // Never called in edge
1363
- },
1364
- off: async (data) => {
1365
- // Never called in edge
1366
- },
1367
- toggle: async (data) => {
1368
- // Never called in edge
1369
- },
1370
- }, {});
831
+ });
832
+ return this;
1371
833
  }
1372
- /**
1373
- * Creates a DeadFront OnOff cluster server.
1374
- *
1375
- * @param {boolean} [onOff=false] - The initial state of the OnOff cluster.
1376
- */
1377
834
  createDeadFrontOnOffClusterServer(onOff = false) {
1378
- this.addClusterServer(this.getDeadFrontOnOffClusterServer(onOff));
835
+ this.behaviors.require(MatterbridgeOnOffServer.with(OnOff.Feature.DeadFrontBehavior), {
836
+ onOff,
837
+ });
1379
838
  return this;
1380
839
  }
1381
- /**
1382
- * Get a default level control cluster server.
1383
- *
1384
- * @param currentLevel - The current level (default: 254).
1385
- * @param minLevel - The minimum level (default: 1).
1386
- * @param maxLevel - The maximum level (default: 254).
1387
- * @param onLevel - The on level (default: null).
1388
- * @param startUpCurrentLevel - The startUp on level (default: null).
1389
- */
1390
- getDefaultLevelControlClusterServer(currentLevel = 254, minLevel = 1, maxLevel = 254, onLevel = null, startUpCurrentLevel = null) {
1391
- return ClusterServer(LevelControlCluster.with(LevelControl.Feature.OnOff, LevelControl.Feature.Lighting), {
840
+ createDefaultLevelControlClusterServer(currentLevel = 254, minLevel = 1, maxLevel = 254, onLevel = null, startUpCurrentLevel = null) {
841
+ this.behaviors.require(MatterbridgeLevelControlServer.with(LevelControl.Feature.OnOff, LevelControl.Feature.Lighting), {
1392
842
  currentLevel,
1393
843
  minLevel,
1394
844
  maxLevel,
@@ -1399,59 +849,11 @@ export class MatterbridgeEndpoint extends Endpoint {
1399
849
  executeIfOff: false,
1400
850
  coupleColorTempToLevel: false,
1401
851
  },
1402
- }, {
1403
- moveToLevel: async (data) => {
1404
- // Never called in edge
1405
- },
1406
- move: async () => {
1407
- // Never called in edge
1408
- },
1409
- step: async () => {
1410
- // Never called in edge
1411
- },
1412
- stop: async () => {
1413
- // Never called in edge
1414
- },
1415
- moveToLevelWithOnOff: async (data) => {
1416
- // Never called in edge
1417
- },
1418
- moveWithOnOff: async () => {
1419
- // Never called in edge
1420
- },
1421
- stepWithOnOff: async () => {
1422
- // Never called in edge
1423
- },
1424
- stopWithOnOff: async () => {
1425
- // Never called in edge
1426
- },
1427
852
  });
1428
- }
1429
- /**
1430
- * Creates a default level control cluster server.
1431
- *
1432
- * @param currentLevel - The current level (default: 254).
1433
- * @param minLevel - The minimum level (default: 1).
1434
- * @param maxLevel - The maximum level (default: 254).
1435
- * @param onLevel - The on level (default: null).
1436
- * @param startUpCurrentLevel - The startUp on level (default: null).
1437
- */
1438
- createDefaultLevelControlClusterServer(currentLevel = 254, minLevel = 1, maxLevel = 254, onLevel = null, startUpCurrentLevel = null) {
1439
- this.addClusterServer(this.getDefaultLevelControlClusterServer(currentLevel, minLevel, maxLevel, onLevel, startUpCurrentLevel));
1440
853
  return this;
1441
854
  }
1442
- /**
1443
- * Get a default color control cluster server with Xy, HueSaturation and ColorTemperature.
1444
- *
1445
- * @param currentX - The current X value.
1446
- * @param currentY - The current Y value.
1447
- * @param currentHue - The current hue value.
1448
- * @param currentSaturation - The current saturation value.
1449
- * @param colorTemperatureMireds - The color temperature in mireds.
1450
- * @param colorTempPhysicalMinMireds - The physical minimum color temperature in mireds.
1451
- * @param colorTempPhysicalMaxMireds - The physical maximum color temperature in mireds.
1452
- */
1453
- getDefaultColorControlClusterServer(currentX = 0, currentY = 0, currentHue = 0, currentSaturation = 0, colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
1454
- return ClusterServer(ColorControlCluster.with(ColorControl.Feature.Xy, ColorControl.Feature.HueSaturation, ColorControl.Feature.ColorTemperature), {
855
+ createDefaultColorControlClusterServer(currentX = 0, currentY = 0, currentHue = 0, currentSaturation = 0, colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
856
+ this.behaviors.require(MatterbridgeColorControlServer.with(ColorControl.Feature.Xy, ColorControl.Feature.HueSaturation, ColorControl.Feature.ColorTemperature), {
1455
857
  colorMode: ColorControl.ColorMode.CurrentHueAndCurrentSaturation,
1456
858
  enhancedColorMode: ColorControl.EnhancedColorMode.CurrentHueAndCurrentSaturation,
1457
859
  colorCapabilities: { xy: true, hueSaturation: true, colorLoop: false, enhancedHue: false, colorTemperature: true },
@@ -1469,77 +871,11 @@ export class MatterbridgeEndpoint extends Endpoint {
1469
871
  coupleColorTempToLevelMinMireds: colorTempPhysicalMinMireds,
1470
872
  remainingTime: 0,
1471
873
  startUpColorTemperatureMireds: null,
1472
- }, {
1473
- moveToColor: async (data) => {
1474
- // Never called in edge
1475
- },
1476
- moveColor: async () => {
1477
- // Never called in edge
1478
- },
1479
- stepColor: async () => {
1480
- // Never called in edge
1481
- },
1482
- moveToHue: async (data) => {
1483
- // Never called in edge
1484
- },
1485
- moveHue: async () => {
1486
- // Never called in edge
1487
- },
1488
- stepHue: async () => {
1489
- // Never called in edge
1490
- },
1491
- moveToSaturation: async (data) => {
1492
- // Never called in edge
1493
- },
1494
- moveSaturation: async () => {
1495
- // Never called in edge
1496
- },
1497
- stepSaturation: async () => {
1498
- // Never called in edge
1499
- },
1500
- moveToHueAndSaturation: async (data) => {
1501
- // Never called in edge
1502
- },
1503
- stopMoveStep: async () => {
1504
- // Never called in edge
1505
- },
1506
- moveToColorTemperature: async (data) => {
1507
- // Never called in edge
1508
- },
1509
- moveColorTemperature: async () => {
1510
- // Never called in edge
1511
- },
1512
- stepColorTemperature: async () => {
1513
- // Never called in edge
1514
- },
1515
- }, {});
1516
- }
1517
- /**
1518
- * Creates a default color control cluster server with Xy, HueSaturation and ColorTemperature.
1519
- *
1520
- * @param currentX - The current X value.
1521
- * @param currentY - The current Y value.
1522
- * @param currentHue - The current hue value.
1523
- * @param currentSaturation - The current saturation value.
1524
- * @param colorTemperatureMireds - The color temperature in mireds.
1525
- * @param colorTempPhysicalMinMireds - The physical minimum color temperature in mireds.
1526
- * @param colorTempPhysicalMaxMireds - The physical maximum color temperature in mireds.
1527
- */
1528
- createDefaultColorControlClusterServer(currentX = 0, currentY = 0, currentHue = 0, currentSaturation = 0, colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
1529
- this.addClusterServer(this.getDefaultColorControlClusterServer(currentX, currentY, currentHue, currentSaturation, colorTemperatureMireds, colorTempPhysicalMinMireds, colorTempPhysicalMaxMireds));
874
+ });
1530
875
  return this;
1531
876
  }
1532
- /**
1533
- * Get a Xy color control cluster server with Xy and ColorTemperature.
1534
- *
1535
- * @param currentX - The current X value.
1536
- * @param currentY - The current Y value.
1537
- * @param colorTemperatureMireds - The color temperature in mireds.
1538
- * @param colorTempPhysicalMinMireds - The physical minimum color temperature in mireds.
1539
- * @param colorTempPhysicalMaxMireds - The physical maximum color temperature in mireds.
1540
- */
1541
- getXyColorControlClusterServer(currentX = 0, currentY = 0, colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
1542
- return ClusterServer(ColorControlCluster.with(ColorControl.Feature.Xy, ColorControl.Feature.ColorTemperature), {
877
+ createXyColorControlClusterServer(currentX = 0, currentY = 0, colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
878
+ this.behaviors.require(MatterbridgeColorControlServer.with(ColorControl.Feature.Xy, ColorControl.Feature.ColorTemperature), {
1543
879
  colorMode: ColorControl.ColorMode.CurrentXAndCurrentY,
1544
880
  enhancedColorMode: ColorControl.EnhancedColorMode.CurrentXAndCurrentY,
1545
881
  colorCapabilities: { xy: true, hueSaturation: false, colorLoop: false, enhancedHue: false, colorTemperature: true },
@@ -1555,54 +891,11 @@ export class MatterbridgeEndpoint extends Endpoint {
1555
891
  coupleColorTempToLevelMinMireds: colorTempPhysicalMinMireds,
1556
892
  startUpColorTemperatureMireds: null,
1557
893
  remainingTime: 0,
1558
- }, {
1559
- moveToColor: async () => {
1560
- // Never called in edge
1561
- },
1562
- moveColor: async () => {
1563
- // Never called in edge
1564
- },
1565
- stepColor: async () => {
1566
- // Never called in edge
1567
- },
1568
- stopMoveStep: async () => {
1569
- // Never called in edge
1570
- },
1571
- moveToColorTemperature: async () => {
1572
- // Never called in edge
1573
- },
1574
- moveColorTemperature: async () => {
1575
- // Never called in edge
1576
- },
1577
- stepColorTemperature: async () => {
1578
- // Never called in edge
1579
- },
1580
- }, {});
1581
- }
1582
- /**
1583
- * Creates a Xy color control cluster server with Xy and ColorTemperature.
1584
- *
1585
- * @param currentX - The current X value.
1586
- * @param currentY - The current Y value.
1587
- * @param colorTemperatureMireds - The color temperature in mireds.
1588
- * @param colorTempPhysicalMinMireds - The physical minimum color temperature in mireds.
1589
- * @param colorTempPhysicalMaxMireds - The physical maximum color temperature in mireds.
1590
- */
1591
- createXyColorControlClusterServer(currentX = 0, currentY = 0, colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
1592
- this.addClusterServer(this.getXyColorControlClusterServer(currentX, currentY, colorTemperatureMireds, colorTempPhysicalMinMireds, colorTempPhysicalMaxMireds));
894
+ });
1593
895
  return this;
1594
896
  }
1595
- /**
1596
- * Get a default hue and saturation control cluster server with HueSaturation and ColorTemperature.
1597
- *
1598
- * @param currentHue - The current hue value.
1599
- * @param currentSaturation - The current saturation value.
1600
- * @param colorTemperatureMireds - The color temperature in mireds.
1601
- * @param colorTempPhysicalMinMireds - The physical minimum color temperature in mireds.
1602
- * @param colorTempPhysicalMaxMireds - The physical maximum color temperature in mireds.
1603
- */
1604
- getHsColorControlClusterServer(currentHue = 0, currentSaturation = 0, colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
1605
- return ClusterServer(ColorControlCluster.with(ColorControl.Feature.HueSaturation, ColorControl.Feature.ColorTemperature), {
897
+ createHsColorControlClusterServer(currentHue = 0, currentSaturation = 0, colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
898
+ this.behaviors.require(MatterbridgeColorControlServer.with(ColorControl.Feature.HueSaturation, ColorControl.Feature.ColorTemperature), {
1606
899
  colorMode: ColorControl.ColorMode.CurrentHueAndCurrentSaturation,
1607
900
  enhancedColorMode: ColorControl.EnhancedColorMode.CurrentHueAndCurrentSaturation,
1608
901
  colorCapabilities: { xy: false, hueSaturation: true, colorLoop: false, enhancedHue: false, colorTemperature: true },
@@ -1618,64 +911,11 @@ export class MatterbridgeEndpoint extends Endpoint {
1618
911
  coupleColorTempToLevelMinMireds: colorTempPhysicalMinMireds,
1619
912
  startUpColorTemperatureMireds: null,
1620
913
  remainingTime: 0,
1621
- }, {
1622
- moveToHue: async () => {
1623
- // Never called in edge
1624
- },
1625
- moveHue: async () => {
1626
- // Never called in edge
1627
- },
1628
- stepHue: async () => {
1629
- // Never called in edge
1630
- },
1631
- moveToSaturation: async () => {
1632
- // Never called in edge
1633
- },
1634
- moveSaturation: async () => {
1635
- // Never called in edge
1636
- },
1637
- stepSaturation: async () => {
1638
- // Never called in edge
1639
- },
1640
- moveToHueAndSaturation: async () => {
1641
- // Never called in edge
1642
- },
1643
- stopMoveStep: async () => {
1644
- // Never called in edge
1645
- },
1646
- moveToColorTemperature: async () => {
1647
- // Never called in edge
1648
- },
1649
- moveColorTemperature: async () => {
1650
- // Never called in edge
1651
- },
1652
- stepColorTemperature: async () => {
1653
- // Never called in edge
1654
- },
1655
- }, {});
1656
- }
1657
- /**
1658
- * Creates a hue and saturation color control cluster server with HueSaturation and ColorTemperature.
1659
- *
1660
- * @param currentHue - The current hue value.
1661
- * @param currentSaturation - The current saturation value.
1662
- * @param colorTemperatureMireds - The color temperature in mireds.
1663
- * @param colorTempPhysicalMinMireds - The physical minimum color temperature in mireds.
1664
- * @param colorTempPhysicalMaxMireds - The physical maximum color temperature in mireds.
1665
- */
1666
- createHsColorControlClusterServer(currentHue = 0, currentSaturation = 0, colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
1667
- this.addClusterServer(this.getHsColorControlClusterServer(currentHue, currentSaturation, colorTemperatureMireds, colorTempPhysicalMinMireds, colorTempPhysicalMaxMireds));
914
+ });
1668
915
  return this;
1669
916
  }
1670
- /**
1671
- * Get a color temperature color control cluster server.
1672
- *
1673
- * @param colorTemperatureMireds - The color temperature in mireds.
1674
- * @param colorTempPhysicalMinMireds - The physical minimum color temperature in mireds.
1675
- * @param colorTempPhysicalMaxMireds - The physical maximum color temperature in mireds.
1676
- */
1677
- getCtColorControlClusterServer(colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
1678
- return ClusterServer(ColorControlCluster.with(ColorControl.Feature.ColorTemperature), {
917
+ createCtColorControlClusterServer(colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
918
+ this.behaviors.require(MatterbridgeColorControlServer.with(ColorControl.Feature.ColorTemperature), {
1679
919
  colorMode: ColorControl.ColorMode.ColorTemperatureMireds,
1680
920
  enhancedColorMode: ColorControl.EnhancedColorMode.ColorTemperatureMireds,
1681
921
  colorCapabilities: { xy: false, hueSaturation: false, colorLoop: false, enhancedHue: false, colorTemperature: true },
@@ -1689,92 +929,18 @@ export class MatterbridgeEndpoint extends Endpoint {
1689
929
  coupleColorTempToLevelMinMireds: colorTempPhysicalMinMireds,
1690
930
  remainingTime: 0,
1691
931
  startUpColorTemperatureMireds: null,
1692
- }, {
1693
- stopMoveStep: async () => {
1694
- // Never called in edge
1695
- },
1696
- moveToColorTemperature: async () => {
1697
- // Never called in edge
1698
- },
1699
- moveColorTemperature: async () => {
1700
- // Never called in edge
1701
- },
1702
- stepColorTemperature: async () => {
1703
- // Never called in edge
1704
- },
1705
- }, {});
1706
- }
1707
- /**
1708
- * Creates a color temperature color control cluster server.
1709
- *
1710
- * @param colorTemperatureMireds - The color temperature in mireds.
1711
- * @param colorTempPhysicalMinMireds - The physical minimum color temperature in mireds.
1712
- * @param colorTempPhysicalMaxMireds - The physical maximum color temperature in mireds.
1713
- */
1714
- createCtColorControlClusterServer(colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
1715
- this.addClusterServer(this.getCtColorControlClusterServer(colorTemperatureMireds, colorTempPhysicalMinMireds, colorTempPhysicalMaxMireds));
1716
- return this;
1717
- }
1718
- isColorControlConfigured = false;
1719
- /**
1720
- * Configures the color control cluster for a device.
1721
- *
1722
- * @remark This method must be called only after creating the cluster with getDefaultColorControlClusterServer or createDefaultColorControlClusterServer
1723
- * and before starting the matter node.
1724
- *
1725
- * @deprecated Use configureColorControlMode instead.
1726
- *
1727
- * @param {boolean} hueSaturation - A boolean indicating whether the device supports hue and saturation control.
1728
- * @param {boolean} xy - A boolean indicating whether the device supports XY control.
1729
- * @param {boolean} colorTemperature - A boolean indicating whether the device supports color temperature control.
1730
- * @param {ColorControl.ColorMode} colorMode - An optional parameter specifying the color mode of the device.
1731
- * @param {Endpoint} endpoint - An optional parameter specifying the endpoint to configure. If not provided, the device endpoint will be used.
1732
- */
1733
- async configureColorControlCluster(hueSaturation, xy, colorTemperature, colorMode, endpoint) {
1734
- if (!endpoint)
1735
- endpoint = this;
1736
- if (this.isColorControlConfigured)
1737
- return;
1738
- if (endpoint.construction.status !== Lifecycle.Status.Active) {
1739
- this.log.debug(`**configureColorControlCluster() delaying for endpoint construction ${endpoint.construction.status}`);
1740
- setTimeout(async () => {
1741
- await endpoint.configureColorControlCluster(hueSaturation, xy, colorTemperature, colorMode, endpoint);
1742
- this.isColorControlConfigured = true;
1743
- }, 500);
1744
- return;
1745
- }
1746
- this.log.debug(`**configureColorControlCluster()`);
1747
- await endpoint.setAttribute(ColorControlCluster.id, 'featureMap', { hueSaturation, enhancedHue: false, colorLoop: false, xy, colorTemperature }, this.log, endpoint);
1748
- await endpoint.setAttribute(ColorControlCluster.id, 'colorCapabilities', { hueSaturation, enhancedHue: false, colorLoop: false, xy, colorTemperature }, this.log, endpoint);
1749
- if (isValidNumber(colorMode, ColorControl.ColorMode.CurrentHueAndCurrentSaturation, ColorControl.ColorMode.ColorTemperatureMireds)) {
1750
- await endpoint.setAttribute(ColorControlCluster.id, 'colorMode', colorMode, this.log, endpoint);
1751
- await endpoint.setAttribute(ColorControlCluster.id, 'enhancedColorMode', colorMode, this.log, endpoint);
1752
- }
1753
- this.isColorControlConfigured = true;
932
+ });
1754
933
  return this;
1755
934
  }
1756
- /**
1757
- * Configures the color control mode for the device.
1758
- *
1759
- * @param {ColorControl.ColorMode} colorMode - The color mode to set.
1760
- * @param {Endpoint} endpoint - The optional endpoint to configure. If not provided, the method will configure the current endpoint.
1761
- */
1762
- async configureColorControlMode(colorMode, endpoint) {
1763
- if (!endpoint)
1764
- endpoint = this;
935
+ async configureColorControlMode(colorMode) {
1765
936
  if (isValidNumber(colorMode, ColorControl.ColorMode.CurrentHueAndCurrentSaturation, ColorControl.ColorMode.ColorTemperatureMireds)) {
1766
- await endpoint.setAttribute(ColorControlCluster.id, 'colorMode', colorMode, this.log, endpoint);
1767
- await endpoint.setAttribute(ColorControlCluster.id, 'enhancedColorMode', colorMode, this.log, endpoint);
937
+ await this.setAttribute(ColorControl.Cluster.id, 'colorMode', colorMode, this.log);
938
+ await this.setAttribute(ColorControl.Cluster.id, 'enhancedColorMode', colorMode, this.log);
1768
939
  }
1769
940
  return this;
1770
941
  }
1771
- /**
1772
- * Get a default window covering cluster server.
1773
- *
1774
- * @param positionPercent100ths - The position percentage in 100ths (0-10000). Defaults to 0. Matter uses 10000 = fully closed 0 = fully opened.
1775
- */
1776
- getDefaultWindowCoveringClusterServer(positionPercent100ths) {
1777
- return ClusterServer(WindowCoveringCluster.with(WindowCovering.Feature.Lift, WindowCovering.Feature.PositionAwareLift), {
942
+ createDefaultWindowCoveringClusterServer(positionPercent100ths) {
943
+ this.behaviors.require(MatterbridgeWindowCoveringServer.with(WindowCovering.Feature.Lift, WindowCovering.Feature.PositionAwareLift), {
1778
944
  type: WindowCovering.WindowCoveringType.Rollershade,
1779
945
  configStatus: {
1780
946
  operational: true,
@@ -1788,1146 +954,518 @@ export class MatterbridgeEndpoint extends Endpoint {
1788
954
  operationalStatus: { global: WindowCovering.MovementStatus.Stopped, lift: WindowCovering.MovementStatus.Stopped, tilt: WindowCovering.MovementStatus.Stopped },
1789
955
  endProductType: WindowCovering.EndProductType.RollerShade,
1790
956
  mode: { motorDirectionReversed: false, calibrationMode: false, maintenanceMode: false, ledFeedback: false },
1791
- targetPositionLiftPercent100ths: positionPercent100ths ?? 0, // 0 Fully open 10000 fully closed
1792
- currentPositionLiftPercent100ths: positionPercent100ths ?? 0, // 0 Fully open 10000 fully closed
1793
- }, {
1794
- upOrOpen: async (data) => {
1795
- // Never called in edge
1796
- },
1797
- downOrClose: async (data) => {
1798
- // Never called in edge
1799
- },
1800
- stopMotion: async (data) => {
1801
- // Never called in edge
1802
- },
1803
- goToLiftPercentage: async (data) => {
1804
- // Never called in edge
1805
- },
1806
- }, {});
1807
- }
1808
- /**
1809
- * Creates a default window covering cluster server.
1810
- *
1811
- * @param positionPercent100ths - The position percentage in 100ths (0-10000). Defaults to 0. Matter uses 10000 = fully closed 0 = fully opened.
1812
- */
1813
- createDefaultWindowCoveringClusterServer(positionPercent100ths) {
1814
- this.addClusterServer(this.getDefaultWindowCoveringClusterServer(positionPercent100ths));
957
+ targetPositionLiftPercent100ths: positionPercent100ths ?? 0,
958
+ currentPositionLiftPercent100ths: positionPercent100ths ?? 0,
959
+ });
960
+ return this;
1815
961
  }
1816
- /**
1817
- * Sets the window covering target position as the current position and stops the movement.
1818
- * @param {Endpoint} endpoint - The endpoint on which to set the window covering (default the device endpoint).
1819
- */
1820
- async setWindowCoveringTargetAsCurrentAndStopped(endpoint) {
1821
- if (!endpoint)
1822
- endpoint = this;
1823
- const position = endpoint.getAttribute(WindowCoveringCluster.id, 'currentPositionLiftPercent100ths', this.log, endpoint); // windowCoveringCluster.getCurrentPositionLiftPercent100thsAttribute();
962
+ async setWindowCoveringTargetAsCurrentAndStopped() {
963
+ const position = this.getAttribute(WindowCovering.Cluster.id, 'currentPositionLiftPercent100ths', this.log);
1824
964
  if (position !== null) {
1825
- await endpoint.setAttribute(WindowCoveringCluster.id, 'targetPositionLiftPercent100ths', position, this.log, endpoint);
1826
- await endpoint.setAttribute(WindowCoveringCluster.id, 'operationalStatus', {
965
+ await this.setAttribute(WindowCovering.Cluster.id, 'targetPositionLiftPercent100ths', position, this.log);
966
+ await this.setAttribute(WindowCovering.Cluster.id, 'operationalStatus', {
1827
967
  global: WindowCovering.MovementStatus.Stopped,
1828
968
  lift: WindowCovering.MovementStatus.Stopped,
1829
969
  tilt: WindowCovering.MovementStatus.Stopped,
1830
- }, this.log, endpoint);
970
+ }, this.log);
1831
971
  }
1832
972
  this.log.debug(`Set WindowCovering currentPositionLiftPercent100ths and targetPositionLiftPercent100ths to ${position} and operationalStatus to Stopped.`);
1833
973
  }
1834
- /**
1835
- * Sets the current and target status of a window covering.
1836
- * @param {number} current - The current position of the window covering.
1837
- * @param {number} target - The target position of the window covering.
1838
- * @param {WindowCovering.MovementStatus} status - The movement status of the window covering.
1839
- * @param {Endpoint} endpoint - The endpoint on which to set the window covering (default the device endpoint).
1840
- */
1841
- async setWindowCoveringCurrentTargetStatus(current, target, status, endpoint) {
1842
- if (!endpoint)
1843
- endpoint = this;
1844
- await endpoint.setAttribute(WindowCoveringCluster.id, 'currentPositionLiftPercent100ths', current, this.log, endpoint);
1845
- await endpoint.setAttribute(WindowCoveringCluster.id, 'targetPositionLiftPercent100ths', target, this.log, endpoint);
1846
- await endpoint.setAttribute(WindowCoveringCluster.id, 'operationalStatus', {
974
+ async setWindowCoveringCurrentTargetStatus(current, target, status) {
975
+ await this.setAttribute(WindowCovering.Cluster.id, 'currentPositionLiftPercent100ths', current, this.log);
976
+ await this.setAttribute(WindowCovering.Cluster.id, 'targetPositionLiftPercent100ths', target, this.log);
977
+ await this.setAttribute(WindowCovering.Cluster.id, 'operationalStatus', {
1847
978
  global: status,
1848
979
  lift: status,
1849
980
  tilt: status,
1850
- }, this.log, endpoint);
981
+ }, this.log);
1851
982
  this.log.debug(`Set WindowCovering currentPositionLiftPercent100ths: ${current}, targetPositionLiftPercent100ths: ${target} and operationalStatus: ${status}.`);
1852
983
  }
1853
- /**
1854
- * Sets the status of the window covering.
1855
- * @param {WindowCovering.MovementStatus} status - The movement status to set.
1856
- * @param {Endpoint} endpoint - The endpoint on which to set the window covering (default the device endpoint).
1857
- */
1858
- async setWindowCoveringStatus(status, endpoint) {
1859
- if (!endpoint)
1860
- endpoint = this;
1861
- await endpoint.setAttribute(WindowCoveringCluster.id, 'operationalStatus', {
984
+ async setWindowCoveringStatus(status) {
985
+ await this.setAttribute(WindowCovering.Cluster.id, 'operationalStatus', {
1862
986
  global: status,
1863
987
  lift: status,
1864
988
  tilt: status,
1865
- }, this.log, endpoint);
989
+ }, this.log);
1866
990
  this.log.debug(`Set WindowCovering operationalStatus: ${status}`);
1867
991
  }
1868
- /**
1869
- * Retrieves the status of the window covering.
1870
- * @param {Endpoint} endpoint - The endpoint on which to get the window covering (default the device endpoint).
1871
- *
1872
- * @returns The global operational status of the window covering.
1873
- */
1874
- getWindowCoveringStatus(endpoint) {
1875
- if (!endpoint)
1876
- endpoint = this;
1877
- const status = endpoint.getAttribute(WindowCoveringCluster.id, 'operationalStatus', this.log, endpoint);
992
+ getWindowCoveringStatus() {
993
+ const status = this.getAttribute(WindowCovering.Cluster.id, 'operationalStatus', this.log);
1878
994
  this.log.debug(`Get WindowCovering operationalStatus: ${status.global}`);
1879
995
  return status.global;
1880
996
  }
1881
- /**
1882
- * Sets the target and current position of the window covering.
1883
- *
1884
- * @param position - The position to set, specified as a number.
1885
- * @param {Endpoint} endpoint - The endpoint on which to set the window covering (default the device endpoint).
1886
- */
1887
- async setWindowCoveringTargetAndCurrentPosition(position, endpoint) {
1888
- if (!endpoint)
1889
- endpoint = this;
1890
- await endpoint.setAttribute(WindowCoveringCluster.id, 'currentPositionLiftPercent100ths', position, this.log, endpoint);
1891
- await endpoint.setAttribute(WindowCoveringCluster.id, 'targetPositionLiftPercent100ths', position, this.log, endpoint);
997
+ async setWindowCoveringTargetAndCurrentPosition(position) {
998
+ await this.setAttribute(WindowCovering.Cluster.id, 'currentPositionLiftPercent100ths', position, this.log);
999
+ await this.setAttribute(WindowCovering.Cluster.id, 'targetPositionLiftPercent100ths', position, this.log);
1892
1000
  this.log.debug(`Set WindowCovering currentPositionLiftPercent100ths: ${position} and targetPositionLiftPercent100ths: ${position}.`);
1893
1001
  }
1894
- /**
1895
- * Get a default door lock cluster server.
1896
- *
1897
- * @remarks
1898
- * This method adds a cluster server for a door lock cluster with default settings.
1899
- *
1900
- */
1901
- getDefaultDoorLockClusterServer(lockState = DoorLock.LockState.Locked, lockType = DoorLock.LockType.DeadBolt) {
1902
- return ClusterServer(DoorLockCluster, {
1903
- operatingMode: DoorLock.OperatingMode.Normal,
1904
- lockState,
1905
- lockType,
1906
- actuatorEnabled: false,
1907
- supportedOperatingModes: { normal: true, vacation: false, privacy: false, noRemoteLockUnlock: false, passage: false },
1908
- }, {
1909
- lockDoor: async (data) => {
1910
- // Never called in edge
1911
- },
1912
- unlockDoor: async (data) => {
1913
- // Never called in edge
1914
- },
1915
- }, {
1916
- doorLockAlarm: true,
1917
- lockOperation: true,
1918
- lockOperationError: true,
1919
- });
1920
- }
1921
- /**
1922
- * Creates a default door lock cluster server.
1923
- *
1924
- * @remarks
1925
- * This method adds a cluster server for a door lock cluster with default settings.
1926
- *
1927
- */
1928
- createDefaultDoorLockClusterServer(lockState = DoorLock.LockState.Locked, lockType = DoorLock.LockType.DeadBolt) {
1929
- this.addClusterServer(this.getDefaultDoorLockClusterServer(lockState, lockType));
1930
- }
1931
- /**
1932
- * Get a default momentary switch cluster server.
1933
- *
1934
- * @remarks
1935
- * This method adds a cluster server with default momentary switch features and configurations suitable for (AppleHome) Single Double Long automations.
1936
- */
1937
- getDefaultSwitchClusterServer() {
1938
- return ClusterServer(SwitchCluster.with(Switch.Feature.MomentarySwitch, Switch.Feature.MomentarySwitchRelease, Switch.Feature.MomentarySwitchLongPress, Switch.Feature.MomentarySwitchMultiPress), {
1939
- numberOfPositions: 2,
1940
- currentPosition: 0,
1941
- multiPressMax: 2,
1942
- }, {}, {
1943
- initialPress: true,
1944
- longPress: true,
1945
- shortRelease: true,
1946
- longRelease: true,
1947
- multiPressOngoing: true,
1948
- multiPressComplete: true,
1002
+ createDefaultThermostatClusterServer(localTemperature = 23, occupiedHeatingSetpoint = 21, occupiedCoolingSetpoint = 25, minSetpointDeadBand = 1, minHeatSetpointLimit = 0, maxHeatSetpointLimit = 50, minCoolSetpointLimit = 0, maxCoolSetpointLimit = 50) {
1003
+ this.behaviors.require(MatterbridgeThermostatServer.with(Thermostat.Feature.Heating, Thermostat.Feature.Cooling, Thermostat.Feature.AutoMode), {
1004
+ localTemperature: localTemperature * 100,
1005
+ systemMode: Thermostat.SystemMode.Auto,
1006
+ controlSequenceOfOperation: Thermostat.ControlSequenceOfOperation.CoolingAndHeating,
1007
+ occupiedHeatingSetpoint: occupiedHeatingSetpoint * 100,
1008
+ minHeatSetpointLimit: minHeatSetpointLimit * 100,
1009
+ maxHeatSetpointLimit: maxHeatSetpointLimit * 100,
1010
+ absMinHeatSetpointLimit: minHeatSetpointLimit * 100,
1011
+ absMaxHeatSetpointLimit: maxHeatSetpointLimit * 100,
1012
+ occupiedCoolingSetpoint: occupiedCoolingSetpoint * 100,
1013
+ minCoolSetpointLimit: minCoolSetpointLimit * 100,
1014
+ maxCoolSetpointLimit: maxCoolSetpointLimit * 100,
1015
+ absMinCoolSetpointLimit: minCoolSetpointLimit * 100,
1016
+ absMaxCoolSetpointLimit: maxCoolSetpointLimit * 100,
1017
+ minSetpointDeadBand: minSetpointDeadBand * 100,
1018
+ thermostatRunningMode: Thermostat.ThermostatRunningMode.Off,
1949
1019
  });
1020
+ return this;
1950
1021
  }
1951
- /**
1952
- * Creates a default momentary switch cluster server.
1953
- *
1954
- * @remarks
1955
- * This method adds a cluster server with default momentary switch features and configurations.
1956
- */
1957
- createDefaultSwitchClusterServer() {
1958
- this.addClusterServer(this.getDefaultSwitchClusterServer());
1959
- }
1960
- /**
1961
- * Get a default latching switch cluster server.
1962
- *
1963
- * @remarks
1964
- * This method adds a cluster server with default latching switch features and configuration.
1965
- */
1966
- getDefaultLatchingSwitchClusterServer() {
1967
- return ClusterServer(SwitchCluster.with(Switch.Feature.LatchingSwitch), {
1968
- numberOfPositions: 2,
1969
- currentPosition: 0,
1970
- }, {}, {
1971
- switchLatched: true,
1022
+ createDefaultHeatingThermostatClusterServer(localTemperature = 23, occupiedHeatingSetpoint = 21, minHeatSetpointLimit = 0, maxHeatSetpointLimit = 50) {
1023
+ this.behaviors.require(MatterbridgeThermostatServer.with(Thermostat.Feature.Heating), {
1024
+ localTemperature: localTemperature * 100,
1025
+ systemMode: Thermostat.SystemMode.Heat,
1026
+ controlSequenceOfOperation: Thermostat.ControlSequenceOfOperation.HeatingOnly,
1027
+ occupiedHeatingSetpoint: occupiedHeatingSetpoint * 100,
1028
+ minHeatSetpointLimit: minHeatSetpointLimit * 100,
1029
+ maxHeatSetpointLimit: maxHeatSetpointLimit * 100,
1030
+ absMinHeatSetpointLimit: minHeatSetpointLimit * 100,
1031
+ absMaxHeatSetpointLimit: maxHeatSetpointLimit * 100,
1972
1032
  });
1033
+ return this;
1973
1034
  }
1974
- /**
1975
- * Creates a default latching switch cluster server.
1976
- *
1977
- * @remarks
1978
- * This method adds a cluster server with default latching switch features and configuration.
1979
- */
1980
- createDefaultLatchingSwitchClusterServer() {
1981
- this.addClusterServer(this.getDefaultLatchingSwitchClusterServer());
1982
- }
1983
- /**
1984
- * Triggers a switch event on the specified endpoint.
1985
- *
1986
- * @param {string} event - The type of event to trigger. Possible values are 'Single', 'Double', 'Long' for momentarySwitch and 'Press', 'Release' for latchingSwitch.
1987
- * @param {Endpoint} endpoint - The endpoint on which to trigger the event (default the device endpoint).
1988
- * @returns {void}
1989
- */
1990
- async triggerSwitchEvent(event, log, endpoint) {
1991
- if (!endpoint)
1992
- endpoint = this;
1993
- if (['Single', 'Double', 'Long'].includes(event)) {
1994
- const cluster = endpoint.getClusterServer(SwitchCluster.with(Switch.Feature.MomentarySwitch, Switch.Feature.MomentarySwitchRelease, Switch.Feature.MomentarySwitchLongPress, Switch.Feature.MomentarySwitchMultiPress));
1995
- if (!cluster || !cluster.getFeatureMapAttribute().momentarySwitch) {
1996
- log?.error(`triggerSwitchEvent ${event} error: Switch cluster with MomentarySwitch not found on endpoint ${endpoint.id}:${endpoint.number}`);
1997
- return false;
1998
- }
1999
- if (endpoint.number === undefined) {
2000
- log?.error(`triggerSwitchEvent ${event} error: Endpoint number not assigned on endpoint ${endpoint.id}:${endpoint.number}`);
1035
+ createDefaultCoolingThermostatClusterServer(localTemperature = 23, occupiedCoolingSetpoint = 25, minCoolSetpointLimit = 0, maxCoolSetpointLimit = 50) {
1036
+ this.behaviors.require(MatterbridgeThermostatServer.with(Thermostat.Feature.Cooling), {
1037
+ localTemperature: localTemperature * 100,
1038
+ systemMode: Thermostat.SystemMode.Cool,
1039
+ controlSequenceOfOperation: Thermostat.ControlSequenceOfOperation.CoolingOnly,
1040
+ occupiedCoolingSetpoint: occupiedCoolingSetpoint * 100,
1041
+ minCoolSetpointLimit: minCoolSetpointLimit * 100,
1042
+ maxCoolSetpointLimit: maxCoolSetpointLimit * 100,
1043
+ absMinCoolSetpointLimit: minCoolSetpointLimit * 100,
1044
+ absMaxCoolSetpointLimit: maxCoolSetpointLimit * 100,
1045
+ });
1046
+ return this;
1047
+ }
1048
+ createDefaultFanControlClusterServer(fanMode = FanControl.FanMode.Off) {
1049
+ this.behaviors.require(MatterbridgeFanControlServer.with(FanControl.Feature.MultiSpeed, FanControl.Feature.Auto, FanControl.Feature.Step), {
1050
+ fanMode,
1051
+ fanModeSequence: FanControl.FanModeSequence.OffLowMedHighAuto,
1052
+ percentSetting: 0,
1053
+ percentCurrent: 0,
1054
+ speedMax: 100,
1055
+ speedSetting: 0,
1056
+ speedCurrent: 0,
1057
+ });
1058
+ return this;
1059
+ }
1060
+ createDefaultDoorLockClusterServer(lockState = DoorLock.LockState.Locked, lockType = DoorLock.LockType.DeadBolt) {
1061
+ this.behaviors.require(MatterbridgeDoorLockServer.enable({ events: { doorLockAlarm: true, lockOperation: true, lockOperationError: true } }), {
1062
+ operatingMode: DoorLock.OperatingMode.Normal,
1063
+ lockState,
1064
+ lockType,
1065
+ actuatorEnabled: false,
1066
+ supportedOperatingModes: { normal: true, vacation: false, privacy: false, noRemoteLockUnlock: false, passage: false },
1067
+ });
1068
+ return this;
1069
+ }
1070
+ createDefaultModeSelectClusterServer(description, supportedModes, currentMode = 0, startUpMode = 0) {
1071
+ this.behaviors.require(MatterbridgeModeSelectServer, {
1072
+ description: description,
1073
+ standardNamespace: null,
1074
+ supportedModes: supportedModes,
1075
+ currentMode: currentMode,
1076
+ startUpMode: startUpMode,
1077
+ });
1078
+ return this;
1079
+ }
1080
+ createDefaultValveConfigurationAndControlClusterServer(valveState = ValveConfigurationAndControl.ValveState.Closed, valveLevel = 0) {
1081
+ this.behaviors.require(MatterbridgeValveConfigurationAndControlServer.with(ValveConfigurationAndControl.Feature.Level), {
1082
+ currentState: valveState,
1083
+ targetState: valveState,
1084
+ currentLevel: valveLevel,
1085
+ targetLevel: valveLevel,
1086
+ openDuration: null,
1087
+ defaultOpenDuration: null,
1088
+ remainingDuration: null,
1089
+ });
1090
+ return this;
1091
+ }
1092
+ createDefaultPumpConfigurationAndControlClusterServer(pumpMode = PumpConfigurationAndControl.OperationMode.Normal) {
1093
+ this.behaviors.require(PumpConfigurationAndControlServer.with(PumpConfigurationAndControl.Feature.ConstantSpeed), {
1094
+ minConstSpeed: null,
1095
+ maxConstSpeed: null,
1096
+ maxPressure: null,
1097
+ maxSpeed: null,
1098
+ maxFlow: null,
1099
+ effectiveOperationMode: pumpMode,
1100
+ effectiveControlMode: PumpConfigurationAndControl.ControlMode.ConstantSpeed,
1101
+ capacity: null,
1102
+ operationMode: pumpMode,
1103
+ });
1104
+ return this;
1105
+ }
1106
+ createDefaultSmokeCOAlarmClusterServer(smokeState = SmokeCoAlarm.AlarmState.Normal, coState = SmokeCoAlarm.AlarmState.Normal) {
1107
+ this.behaviors.require(MatterbridgeSmokeCoAlarmServer.with(SmokeCoAlarm.Feature.SmokeAlarm, SmokeCoAlarm.Feature.CoAlarm).enable({
1108
+ events: { smokeAlarm: true, interconnectSmokeAlarm: true, coAlarm: true, interconnectCoAlarm: true, lowBattery: true, hardwareFault: true, endOfService: true, selfTestComplete: true, alarmMuted: true, muteEnded: true, allClear: true },
1109
+ }), {
1110
+ smokeState,
1111
+ coState,
1112
+ expressedState: SmokeCoAlarm.ExpressedState.Normal,
1113
+ batteryAlert: SmokeCoAlarm.AlarmState.Normal,
1114
+ deviceMuted: SmokeCoAlarm.MuteState.NotMuted,
1115
+ testInProgress: false,
1116
+ hardwareFaultAlert: false,
1117
+ endOfServiceAlert: SmokeCoAlarm.EndOfService.Normal,
1118
+ interconnectSmokeAlarm: SmokeCoAlarm.AlarmState.Normal,
1119
+ interconnectCoAlarm: SmokeCoAlarm.AlarmState.Normal,
1120
+ });
1121
+ return this;
1122
+ }
1123
+ createDefaultSwitchClusterServer() {
1124
+ this.behaviors.require(SwitchServer.with(Switch.Feature.MomentarySwitch, Switch.Feature.MomentarySwitchRelease, Switch.Feature.MomentarySwitchLongPress, Switch.Feature.MomentarySwitchMultiPress).enable({
1125
+ events: { initialPress: true, longPress: true, shortRelease: true, longRelease: true, multiPressOngoing: true, multiPressComplete: true },
1126
+ }), {
1127
+ numberOfPositions: 2,
1128
+ currentPosition: 0,
1129
+ multiPressMax: 2,
1130
+ });
1131
+ return this;
1132
+ }
1133
+ createDefaultLatchingSwitchClusterServer() {
1134
+ this.behaviors.require(SwitchServer.with(Switch.Feature.LatchingSwitch).enable({
1135
+ events: { switchLatched: true },
1136
+ }), {
1137
+ numberOfPositions: 2,
1138
+ currentPosition: 0,
1139
+ });
1140
+ return this;
1141
+ }
1142
+ async triggerSwitchEvent(event, log) {
1143
+ if (this.maybeNumber === undefined) {
1144
+ this.log.error(`triggerSwitchEvent ${event} error: Endpoint number not assigned on endpoint ${this.maybeId}:${this.maybeNumber}`);
1145
+ return false;
1146
+ }
1147
+ if (['Single', 'Double', 'Long'].includes(event)) {
1148
+ if (!this.hasClusterServer(Switch.Cluster.id) || this.getAttribute(Switch.Cluster.id, 'featureMap').momentarySwitch === false) {
1149
+ this.log.error(`triggerSwitchEvent ${event} error: Switch cluster with MomentarySwitch not found on endpoint ${this.maybeId}:${this.maybeNumber}`);
2001
1150
  return false;
2002
1151
  }
2003
1152
  if (event === 'Single') {
2004
- await endpoint.setAttribute(cluster.id, 'currentPosition', 1, log);
2005
- endpoint.triggerEvent(cluster.id, 'initialPress', { newPosition: 1 }, log);
2006
- await endpoint.setAttribute(cluster.id, 'currentPosition', 0, log);
2007
- endpoint.triggerEvent(cluster.id, 'shortRelease', { previousPosition: 1 }, log);
2008
- await endpoint.setAttribute(cluster.id, 'currentPosition', 0, log);
2009
- endpoint.triggerEvent(cluster.id, 'multiPressComplete', { previousPosition: 1, totalNumberOfPressesCounted: 1 }, log);
2010
- log?.info(`${db}Trigger endpoint ${or}${endpoint.id}:${endpoint.number}${db} event ${hk}${cluster.name}.SinglePress${db}`);
1153
+ await this.setAttribute(Switch.Cluster.id, 'currentPosition', 1, log);
1154
+ this.triggerEvent(Switch.Cluster.id, 'initialPress', { newPosition: 1 }, log);
1155
+ await this.setAttribute(Switch.Cluster.id, 'currentPosition', 0, log);
1156
+ this.triggerEvent(Switch.Cluster.id, 'shortRelease', { previousPosition: 1 }, log);
1157
+ await this.setAttribute(Switch.Cluster.id, 'currentPosition', 0, log);
1158
+ this.triggerEvent(Switch.Cluster.id, 'multiPressComplete', { previousPosition: 1, totalNumberOfPressesCounted: 1 }, log);
1159
+ log?.info(`${db}Trigger endpoint ${or}${this.id}:${this.number}${db} event ${hk}Switch.SinglePress${db}`);
2011
1160
  }
2012
1161
  if (event === 'Double') {
2013
- await endpoint.setAttribute(cluster.id, 'currentPosition', 1, log);
2014
- endpoint.triggerEvent(cluster.id, 'initialPress', { newPosition: 1 }, log);
2015
- await endpoint.setAttribute(cluster.id, 'currentPosition', 0, log);
2016
- endpoint.triggerEvent(cluster.id, 'shortRelease', { previousPosition: 1 }, log);
2017
- await endpoint.setAttribute(cluster.id, 'currentPosition', 1, log);
2018
- endpoint.triggerEvent(cluster.id, 'initialPress', { newPosition: 1 }, log);
2019
- endpoint.triggerEvent(cluster.id, 'multiPressOngoing', { newPosition: 1, currentNumberOfPressesCounted: 2 }, log);
2020
- await endpoint.setAttribute(cluster.id, 'currentPosition', 0, log);
2021
- endpoint.triggerEvent(cluster.id, 'shortRelease', { previousPosition: 1 }, log);
2022
- endpoint.triggerEvent(cluster.id, 'multiPressComplete', { previousPosition: 1, totalNumberOfPressesCounted: 2 }, log);
2023
- log?.info(`${db}Trigger endpoint ${or}${endpoint.id}:${endpoint.number}${db} event ${hk}${cluster.name}.DoublePress${db}`);
1162
+ await this.setAttribute(Switch.Cluster.id, 'currentPosition', 1, log);
1163
+ this.triggerEvent(Switch.Cluster.id, 'initialPress', { newPosition: 1 }, log);
1164
+ await this.setAttribute(Switch.Cluster.id, 'currentPosition', 0, log);
1165
+ this.triggerEvent(Switch.Cluster.id, 'shortRelease', { previousPosition: 1 }, log);
1166
+ await this.setAttribute(Switch.Cluster.id, 'currentPosition', 1, log);
1167
+ this.triggerEvent(Switch.Cluster.id, 'initialPress', { newPosition: 1 }, log);
1168
+ this.triggerEvent(Switch.Cluster.id, 'multiPressOngoing', { newPosition: 1, currentNumberOfPressesCounted: 2 }, log);
1169
+ await this.setAttribute(Switch.Cluster.id, 'currentPosition', 0, log);
1170
+ this.triggerEvent(Switch.Cluster.id, 'shortRelease', { previousPosition: 1 }, log);
1171
+ this.triggerEvent(Switch.Cluster.id, 'multiPressComplete', { previousPosition: 1, totalNumberOfPressesCounted: 2 }, log);
1172
+ log?.info(`${db}Trigger endpoint ${or}${this.id}:${this.number}${db} event ${hk}Switch.DoublePress${db}`);
2024
1173
  }
2025
1174
  if (event === 'Long') {
2026
- await endpoint.setAttribute(cluster.id, 'currentPosition', 1, log);
2027
- endpoint.triggerEvent(cluster.id, 'initialPress', { newPosition: 1 }, log);
2028
- endpoint.triggerEvent(cluster.id, 'longPress', { newPosition: 1 }, log);
2029
- await endpoint.setAttribute(cluster.id, 'currentPosition', 0, log);
2030
- endpoint.triggerEvent(cluster.id, 'longRelease', { previousPosition: 1 }, log);
2031
- log?.info(`${db}Trigger endpoint ${or}${endpoint.id}:${endpoint.number}${db} event ${hk}${cluster.name}.LongPress${db}`);
1175
+ await this.setAttribute(Switch.Cluster.id, 'currentPosition', 1, log);
1176
+ this.triggerEvent(Switch.Cluster.id, 'initialPress', { newPosition: 1 }, log);
1177
+ this.triggerEvent(Switch.Cluster.id, 'longPress', { newPosition: 1 }, log);
1178
+ await this.setAttribute(Switch.Cluster.id, 'currentPosition', 0, log);
1179
+ this.triggerEvent(Switch.Cluster.id, 'longRelease', { previousPosition: 1 }, log);
1180
+ log?.info(`${db}Trigger endpoint ${or}${this.id}:${this.number}${db} event ${hk}Switch.LongPress${db}`);
2032
1181
  }
2033
1182
  }
2034
1183
  if (['Press', 'Release'].includes(event)) {
2035
- const cluster = endpoint.getClusterServer(SwitchCluster.with(Switch.Feature.LatchingSwitch));
2036
- if (!cluster || !cluster.getFeatureMapAttribute().latchingSwitch) {
2037
- log?.error(`triggerSwitchEvent ${event} error: Switch cluster with LatchingSwitch not found on endpoint ${endpoint.id}:${endpoint.number}`);
2038
- return false;
2039
- }
2040
- if (endpoint.number === undefined) {
2041
- log?.error(`triggerSwitchEvent ${event} error: Endpoint number not assigned on endpoint ${endpoint.id}:${endpoint.number}`);
1184
+ if (!this.hasClusterServer(Switch.Cluster.id) || this.getAttribute(Switch.Cluster.id, 'featureMap').latchingSwitch === false) {
1185
+ this.log.error(`triggerSwitchEvent ${event} error: Switch cluster with LatchingSwitch not found on endpoint ${this.maybeId}:${this.maybeNumber}`);
2042
1186
  return false;
2043
1187
  }
2044
1188
  if (event === 'Press') {
2045
- await endpoint.setAttribute(cluster.id, 'currentPosition', 1, log);
2046
- endpoint.triggerEvent(cluster.id, 'switchLatched', { newPosition: 1 }, log);
2047
- log?.info(`${db}Trigger endpoint ${or}${endpoint.id}:${endpoint.number}${db} event ${hk}${cluster.name}.Press${db}`);
1189
+ await this.setAttribute(Switch.Cluster.id, 'currentPosition', 1, log);
1190
+ this.triggerEvent(Switch.Cluster.id, 'switchLatched', { newPosition: 1 }, log);
1191
+ log?.info(`${db}Trigger endpoint ${or}${this.id}:${this.number}${db} event ${hk}Switch.Press${db}`);
2048
1192
  }
2049
1193
  if (event === 'Release') {
2050
- await endpoint.setAttribute(cluster.id, 'currentPosition', 0, log);
2051
- endpoint.triggerEvent(cluster.id, 'switchLatched', { newPosition: 0 }, log);
2052
- log?.info(`${db}Trigger endpoint ${or}${endpoint.id}:${endpoint.number}${db} event ${hk}${cluster.name}.Release${db}`);
1194
+ await this.setAttribute(Switch.Cluster.id, 'currentPosition', 0, log);
1195
+ this.triggerEvent(Switch.Cluster.id, 'switchLatched', { newPosition: 0 }, log);
1196
+ log?.info(`${db}Trigger endpoint ${or}${this.id}:${this.number}${db} event ${hk}Switch.Release${db}`);
2053
1197
  }
2054
1198
  }
2055
1199
  return true;
2056
1200
  }
2057
- /**
2058
- * Retrieves the default mode select cluster server.
2059
- *
2060
- * @param description - The description of the cluster server.
2061
- * @param supportedModes - The supported modes for the cluster server.
2062
- * @param currentMode - The current mode of the cluster server. Defaults to 0.
2063
- * @param startUpMode - The startup mode of the cluster server. Defaults to 0.
2064
- * @returns The default mode select cluster server.
2065
- */
2066
- getDefaultModeSelectClusterServer(description, supportedModes, currentMode = 0, startUpMode = 0) {
2067
- return ClusterServer(ModeSelectCluster, {
2068
- description: description,
2069
- standardNamespace: null,
2070
- supportedModes: supportedModes,
2071
- currentMode: currentMode,
2072
- startUpMode: startUpMode,
2073
- }, {
2074
- changeToMode: async (data) => {
2075
- // Never called in edge
2076
- },
1201
+ createDefaultBooleanStateClusterServer(contact) {
1202
+ this.behaviors.require(BooleanStateServer.enable({
1203
+ events: { stateChange: true },
1204
+ }), {
1205
+ stateValue: contact ?? true,
2077
1206
  });
1207
+ return this;
2078
1208
  }
2079
- /**
2080
- * Creates a default mode select cluster server.
2081
- *
2082
- * @param description - The description of the cluster server.
2083
- * @param supportedModes - The supported modes for the cluster server.
2084
- * @param currentMode - The current mode of the cluster server. Defaults to 0.
2085
- * @param startUpMode - The startup mode of the cluster server. Defaults to 0.
2086
- * @param endpoint - The endpoint to add the cluster server to. Defaults to `this` if not provided.
2087
- *
2088
- */
2089
- createDefaultModeSelectClusterServer(description, supportedModes, currentMode = 0, startUpMode = 0, endpoint) {
2090
- if (!endpoint)
2091
- endpoint = this;
2092
- endpoint.addClusterServer(this.getDefaultModeSelectClusterServer(description, supportedModes, currentMode, startUpMode));
1209
+ createDefaultBooleanStateConfigurationClusterServer(sensorFault = false, currentSensitivityLevel = 0, supportedSensitivityLevels = 2, defaultSensitivityLevel = 0) {
1210
+ this.behaviors.require(MatterbridgeBooleanStateConfigurationServer.with(BooleanStateConfiguration.Feature.Visual, BooleanStateConfiguration.Feature.Audible, BooleanStateConfiguration.Feature.SensitivityLevel).enable({
1211
+ events: { alarmsStateChanged: true, sensorFault: true },
1212
+ }), {
1213
+ currentSensitivityLevel,
1214
+ supportedSensitivityLevels,
1215
+ defaultSensitivityLevel,
1216
+ alarmsActive: { visual: false, audible: false },
1217
+ alarmsEnabled: { visual: true, audible: true },
1218
+ alarmsSupported: { visual: true, audible: true },
1219
+ sensorFault: { generalFault: sensorFault },
1220
+ });
1221
+ return this;
2093
1222
  }
2094
- /**
2095
- * Get a default occupancy sensing cluster server.
2096
- *
2097
- * @param occupied - A boolean indicating whether the occupancy is occupied or not. Default is false.
2098
- */
2099
- getDefaultOccupancySensingClusterServer(occupied = false) {
2100
- return ClusterServer(OccupancySensingCluster, {
2101
- occupancy: { occupied },
2102
- occupancySensorType: OccupancySensing.OccupancySensorType.Pir,
2103
- occupancySensorTypeBitmap: { pir: true, ultrasonic: false, physicalContact: false },
2104
- pirOccupiedToUnoccupiedDelay: 30,
2105
- }, {});
1223
+ createDefaultPowerTopologyClusterServer() {
1224
+ this.behaviors.require(PowerTopologyServer.with(PowerTopology.Feature.TreeTopology));
1225
+ return this;
2106
1226
  }
2107
- /**
2108
- * Creates a default occupancy sensing cluster server.
2109
- *
2110
- * @param occupied - A boolean indicating whether the occupancy is occupied or not. Default is false.
2111
- */
2112
- createDefaultOccupancySensingClusterServer(occupied = false) {
2113
- this.addClusterServer(this.getDefaultOccupancySensingClusterServer(occupied));
1227
+ createDefaultElectricalEnergyMeasurementClusterServer(energy = null) {
1228
+ this.behaviors.require(ElectricalEnergyMeasurementServer.with(ElectricalEnergyMeasurement.Feature.ImportedEnergy, ElectricalEnergyMeasurement.Feature.ExportedEnergy, ElectricalEnergyMeasurement.Feature.CumulativeEnergy), {
1229
+ accuracy: {
1230
+ measurementType: MeasurementType.ElectricalEnergy,
1231
+ measured: true,
1232
+ minMeasuredValue: Number.MIN_SAFE_INTEGER,
1233
+ maxMeasuredValue: Number.MAX_SAFE_INTEGER,
1234
+ accuracyRanges: [{ rangeMin: Number.MIN_SAFE_INTEGER, rangeMax: Number.MAX_SAFE_INTEGER, fixedMax: 1 }],
1235
+ },
1236
+ cumulativeEnergyReset: null,
1237
+ cumulativeEnergyImported: energy ? { energy } : null,
1238
+ cumulativeEnergyExported: null,
1239
+ });
1240
+ return this;
2114
1241
  }
2115
- /**
2116
- * Get a default Illuminance Measurement Cluster Server.
2117
- *
2118
- * @param measuredValue - The measured value of illuminance.
2119
- */
2120
- getDefaultIlluminanceMeasurementClusterServer(measuredValue = 0) {
2121
- return ClusterServer(IlluminanceMeasurementCluster, {
1242
+ createDefaultElectricalPowerMeasurementClusterServer(voltage = null, current = null, power = null, frequency = null) {
1243
+ this.behaviors.require(ElectricalPowerMeasurementServer.with(ElectricalPowerMeasurement.Feature.AlternatingCurrent), {
1244
+ powerMode: ElectricalPowerMeasurement.PowerMode.Ac,
1245
+ numberOfMeasurementTypes: 4,
1246
+ accuracy: [
1247
+ {
1248
+ measurementType: MeasurementType.Voltage,
1249
+ measured: true,
1250
+ minMeasuredValue: Number.MIN_SAFE_INTEGER,
1251
+ maxMeasuredValue: Number.MAX_SAFE_INTEGER,
1252
+ accuracyRanges: [{ rangeMin: Number.MIN_SAFE_INTEGER, rangeMax: Number.MAX_SAFE_INTEGER, fixedMax: 1 }],
1253
+ },
1254
+ {
1255
+ measurementType: MeasurementType.ActiveCurrent,
1256
+ measured: true,
1257
+ minMeasuredValue: Number.MIN_SAFE_INTEGER,
1258
+ maxMeasuredValue: Number.MAX_SAFE_INTEGER,
1259
+ accuracyRanges: [{ rangeMin: Number.MIN_SAFE_INTEGER, rangeMax: Number.MAX_SAFE_INTEGER, fixedMax: 1 }],
1260
+ },
1261
+ {
1262
+ measurementType: MeasurementType.ActivePower,
1263
+ measured: true,
1264
+ minMeasuredValue: Number.MIN_SAFE_INTEGER,
1265
+ maxMeasuredValue: Number.MAX_SAFE_INTEGER,
1266
+ accuracyRanges: [{ rangeMin: Number.MIN_SAFE_INTEGER, rangeMax: Number.MAX_SAFE_INTEGER, fixedMax: 1 }],
1267
+ },
1268
+ {
1269
+ measurementType: MeasurementType.Frequency,
1270
+ measured: true,
1271
+ minMeasuredValue: Number.MIN_SAFE_INTEGER,
1272
+ maxMeasuredValue: Number.MAX_SAFE_INTEGER,
1273
+ accuracyRanges: [{ rangeMin: Number.MIN_SAFE_INTEGER, rangeMax: Number.MAX_SAFE_INTEGER, fixedMax: 1 }],
1274
+ },
1275
+ ],
1276
+ voltage: voltage,
1277
+ activeCurrent: current,
1278
+ activePower: power,
1279
+ frequency: frequency,
1280
+ });
1281
+ return this;
1282
+ }
1283
+ getDefaultTemperatureMeasurementClusterServer(measuredValue = 0) {
1284
+ return optionsFor(TemperatureMeasurementServer, {
2122
1285
  measuredValue,
2123
1286
  minMeasuredValue: null,
2124
1287
  maxMeasuredValue: null,
2125
1288
  tolerance: 0,
2126
- }, {}, {});
1289
+ });
2127
1290
  }
2128
- /**
2129
- * Creates a default Illuminance Measurement Cluster Server.
2130
- *
2131
- * @param measuredValue - The measured value of illuminance.
2132
- */
2133
- createDefaultIlluminanceMeasurementClusterServer(measuredValue = 0) {
2134
- this.addClusterServer(this.getDefaultIlluminanceMeasurementClusterServer(measuredValue));
1291
+ createDefaultTemperatureMeasurementClusterServer(measuredValue = 0) {
1292
+ this.behaviors.require(TemperatureMeasurementServer, this.getDefaultTemperatureMeasurementClusterServer(measuredValue));
1293
+ return this;
2135
1294
  }
2136
- /**
2137
- * Get a default flow measurement cluster server.
2138
- *
2139
- * @param measuredValue - The measured value of the flow in 10 x m/h.
2140
- */
2141
- getDefaultFlowMeasurementClusterServer(measuredValue = 0) {
2142
- return ClusterServer(FlowMeasurementCluster, {
1295
+ getDefaultRelativeHumidityMeasurementClusterServer(measuredValue = 0) {
1296
+ return optionsFor(RelativeHumidityMeasurementServer, {
2143
1297
  measuredValue,
2144
1298
  minMeasuredValue: null,
2145
1299
  maxMeasuredValue: null,
2146
1300
  tolerance: 0,
2147
- }, {}, {});
1301
+ });
2148
1302
  }
2149
- /**
2150
- * Creates a default flow measurement cluster server.
2151
- *
2152
- * @param measuredValue - The measured value of the flow in 10 x m/h.
2153
- */
2154
- createDefaultFlowMeasurementClusterServer(measuredValue = 0) {
2155
- this.addClusterServer(this.getDefaultFlowMeasurementClusterServer(measuredValue));
1303
+ createDefaultRelativeHumidityMeasurementClusterServer(measuredValue = 0) {
1304
+ this.behaviors.require(RelativeHumidityMeasurementServer, this.getDefaultRelativeHumidityMeasurementClusterServer(measuredValue));
1305
+ return this;
2156
1306
  }
2157
- /**
2158
- * Get a default temperature measurement cluster server.
2159
- *
2160
- * @param measuredValue - The measured value of the temperature x 100.
2161
- */
2162
- getDefaultTemperatureMeasurementClusterServer(measuredValue = 0) {
2163
- return ClusterServer(TemperatureMeasurementCluster, {
1307
+ getDefaultPressureMeasurementClusterServer(measuredValue = 1000) {
1308
+ return optionsFor(PressureMeasurementServer, {
2164
1309
  measuredValue,
2165
1310
  minMeasuredValue: null,
2166
1311
  maxMeasuredValue: null,
2167
1312
  tolerance: 0,
2168
- }, {}, {});
1313
+ });
2169
1314
  }
2170
- /**
2171
- * Creates a default temperature measurement cluster server.
2172
- *
2173
- * @param measuredValue - The measured value of the temperature x 100.
2174
- */
2175
- createDefaultTemperatureMeasurementClusterServer(measuredValue = 0) {
2176
- this.addClusterServer(this.getDefaultTemperatureMeasurementClusterServer(measuredValue));
1315
+ createDefaultPressureMeasurementClusterServer(measuredValue = 1000) {
1316
+ this.behaviors.require(PressureMeasurementServer, this.getDefaultPressureMeasurementClusterServer(measuredValue));
1317
+ return this;
2177
1318
  }
2178
- /**
2179
- * Get a default RelativeHumidityMeasurementCluster server.
2180
- *
2181
- * @param measuredValue - The measured value of the relative humidity x 100.
2182
- */
2183
- getDefaultRelativeHumidityMeasurementClusterServer(measuredValue = 0) {
2184
- return ClusterServer(RelativeHumidityMeasurementCluster, {
1319
+ getDefaultIlluminanceMeasurementClusterServer(measuredValue = 0) {
1320
+ return optionsFor(IlluminanceMeasurementServer, {
2185
1321
  measuredValue,
2186
1322
  minMeasuredValue: null,
2187
1323
  maxMeasuredValue: null,
2188
1324
  tolerance: 0,
2189
- }, {}, {});
1325
+ });
2190
1326
  }
2191
- /**
2192
- * Creates a default RelativeHumidityMeasurementCluster server.
2193
- *
2194
- * @param measuredValue - The measured value of the relative humidity x 100.
2195
- */
2196
- createDefaultRelativeHumidityMeasurementClusterServer(measuredValue = 0) {
2197
- this.addClusterServer(this.getDefaultRelativeHumidityMeasurementClusterServer(measuredValue));
1327
+ createDefaultIlluminanceMeasurementClusterServer(measuredValue = 0) {
1328
+ this.behaviors.require(IlluminanceMeasurementServer, this.getDefaultIlluminanceMeasurementClusterServer(measuredValue));
1329
+ return this;
2198
1330
  }
2199
- /**
2200
- * Get a default Pressure Measurement Cluster Server.
2201
- *
2202
- * @param measuredValue - The measured value for the pressure.
2203
- */
2204
- getDefaultPressureMeasurementClusterServer(measuredValue = 1000) {
2205
- return ClusterServer(PressureMeasurementCluster, {
1331
+ getDefaultFlowMeasurementClusterServer(measuredValue = 0) {
1332
+ return optionsFor(FlowMeasurementServer, {
2206
1333
  measuredValue,
2207
1334
  minMeasuredValue: null,
2208
1335
  maxMeasuredValue: null,
2209
1336
  tolerance: 0,
2210
- }, {}, {});
2211
- }
2212
- /**
2213
- * Creates a default Pressure Measurement Cluster Server.
2214
- *
2215
- * @param measuredValue - The measured value for the pressure.
2216
- */
2217
- createDefaultPressureMeasurementClusterServer(measuredValue = 1000) {
2218
- this.addClusterServer(this.getDefaultPressureMeasurementClusterServer(measuredValue));
2219
- }
2220
- /**
2221
- * Get a default boolean state cluster server.
2222
- *
2223
- * @param contact - Optional boolean value indicating the contact state. Defaults to `true` if not provided.
2224
- */
2225
- getDefaultBooleanStateClusterServer(contact) {
2226
- return ClusterServer(BooleanStateCluster, {
2227
- stateValue: contact ?? true, // true=contact false=no_contact
2228
- }, {}, {
2229
- stateChange: true,
2230
1337
  });
2231
1338
  }
2232
- /**
2233
- * Creates a default boolean state configuration cluster server.
2234
- *
2235
- * @param contact - Optional boolean value indicating the contact state. Defaults to `true` if not provided.
2236
- */
2237
- createDefaultBooleanStateClusterServer(contact) {
2238
- this.addClusterServer(this.getDefaultBooleanStateClusterServer(contact));
2239
- }
2240
- /**
2241
- * Get a default boolean state configuration cluster server.
2242
- *
2243
- * @param contact - Optional boolean value indicating the sensor fault state. Defaults to `false` if not provided.
2244
- */
2245
- getDefaultBooleanStateConfigurationClusterServer(sensorFault = false) {
2246
- return ClusterServer(BooleanStateConfigurationCluster.with(BooleanStateConfiguration.Feature.Visual, BooleanStateConfiguration.Feature.Audible, BooleanStateConfiguration.Feature.SensitivityLevel), {
2247
- currentSensitivityLevel: 0,
2248
- supportedSensitivityLevels: 2,
2249
- defaultSensitivityLevel: 0,
2250
- alarmsActive: { visual: false, audible: false },
2251
- alarmsEnabled: { visual: false, audible: false },
2252
- alarmsSupported: { visual: true, audible: true },
2253
- // alarmsSuppressed: { visual: false, audible: false },
2254
- sensorFault: { generalFault: sensorFault },
2255
- }, {
2256
- enableDisableAlarm: async (data) => {
2257
- // Never called in edge
2258
- },
2259
- }, {
2260
- alarmsStateChanged: true,
2261
- sensorFault: true,
1339
+ createDefaultFlowMeasurementClusterServer(measuredValue = 0) {
1340
+ this.behaviors.require(FlowMeasurementServer, this.getDefaultFlowMeasurementClusterServer(measuredValue));
1341
+ return this;
1342
+ }
1343
+ getDefaultOccupancySensingClusterServer(occupied = false) {
1344
+ return optionsFor(OccupancySensingServer, {
1345
+ occupancy: { occupied },
1346
+ occupancySensorType: OccupancySensing.OccupancySensorType.Pir,
1347
+ occupancySensorTypeBitmap: { pir: true, ultrasonic: false, physicalContact: false },
1348
+ pirOccupiedToUnoccupiedDelay: 30,
2262
1349
  });
2263
1350
  }
2264
- /**
2265
- * Creates a default boolean state configuration cluster server.
2266
- *
2267
- * @param contact - Optional boolean value indicating the sensor fault state. Defaults to `false` if not provided.
2268
- */
2269
- createDefaultBooleanStateConfigurationClusterServer(sensorFault = false) {
2270
- this.addClusterServer(this.getDefaultBooleanStateConfigurationClusterServer(sensorFault));
2271
- }
2272
- /**
2273
- * Get a default power source replaceable battery cluster server.
2274
- *
2275
- * @param batPercentRemaining - The remaining battery percentage (default: 100).
2276
- * @param batChargeLevel - The battery charge level (default: PowerSource.BatChargeLevel.Ok).
2277
- * @param batVoltage - The battery voltage (default: 1500).
2278
- * @param batReplacementDescription - The battery replacement description (default: 'Battery type').
2279
- * @param batQuantity - The battery quantity (default: 1).
2280
- */
2281
- getDefaultPowerSourceReplaceableBatteryClusterServer(batPercentRemaining = 100, batChargeLevel = PowerSource.BatChargeLevel.Ok, batVoltage = 1500, batReplacementDescription = 'Battery type', batQuantity = 1) {
2282
- return ClusterServer(PowerSourceCluster.with(PowerSource.Feature.Battery, PowerSource.Feature.Replaceable), {
2283
- status: PowerSource.PowerSourceStatus.Active,
2284
- order: 0,
2285
- description: 'Primary battery',
2286
- batVoltage,
2287
- batPercentRemaining: Math.min(Math.max(batPercentRemaining * 2, 0), 200),
2288
- batChargeLevel,
2289
- batReplacementNeeded: false,
2290
- batReplaceability: PowerSource.BatReplaceability.UserReplaceable,
2291
- activeBatFaults: undefined,
2292
- batReplacementDescription,
2293
- batQuantity,
2294
- endpointList: [],
2295
- }, {}, {});
2296
- }
2297
- /**
2298
- * Creates a default power source replaceable battery cluster server.
2299
- *
2300
- * @param batPercentRemaining - The remaining battery percentage (default: 100).
2301
- * @param batChargeLevel - The battery charge level (default: PowerSource.BatChargeLevel.Ok).
2302
- * @param batVoltage - The battery voltage (default: 1500).
2303
- * @param batReplacementDescription - The battery replacement description (default: 'Battery type').
2304
- * @param batQuantity - The battery quantity (default: 1).
2305
- */
2306
- createDefaultPowerSourceReplaceableBatteryClusterServer(batPercentRemaining = 100, batChargeLevel = PowerSource.BatChargeLevel.Ok, batVoltage = 1500, batReplacementDescription = 'Battery type', batQuantity = 1) {
2307
- this.addClusterServer(this.getDefaultPowerSourceReplaceableBatteryClusterServer(batPercentRemaining, batChargeLevel, batVoltage, batReplacementDescription, batQuantity));
2308
- }
2309
- /**
2310
- * Get a default power source rechargeable battery cluster server.
2311
- *
2312
- * @param batPercentRemaining - The remaining battery percentage (default: 100).
2313
- * @param batChargeLevel - The battery charge level (default: PowerSource.BatChargeLevel.Ok).
2314
- * @param batVoltage - The battery voltage (default: 1500).
2315
- */
2316
- getDefaultPowerSourceRechargeableBatteryClusterServer(batPercentRemaining = 100, batChargeLevel = PowerSource.BatChargeLevel.Ok, batVoltage = 1500) {
2317
- return ClusterServer(PowerSourceCluster.with(PowerSource.Feature.Battery, PowerSource.Feature.Rechargeable), {
2318
- status: PowerSource.PowerSourceStatus.Active,
2319
- order: 0,
2320
- description: 'Primary battery',
2321
- batVoltage,
2322
- batPercentRemaining: Math.min(Math.max(batPercentRemaining * 2, 0), 200),
2323
- batTimeRemaining: 1,
2324
- batChargeLevel,
2325
- batReplacementNeeded: false,
2326
- batReplaceability: PowerSource.BatReplaceability.Unspecified,
2327
- activeBatFaults: undefined,
2328
- batChargeState: PowerSource.BatChargeState.IsNotCharging,
2329
- batFunctionalWhileCharging: true,
2330
- endpointList: [],
2331
- }, {}, {});
2332
- }
2333
- /**
2334
- * Creates a default power source rechargeable battery cluster server.
2335
- *
2336
- * @param batPercentRemaining - The remaining battery percentage (default: 100).
2337
- * @param batChargeLevel - The battery charge level (default: PowerSource.BatChargeLevel.Ok).
2338
- * @param batVoltage - The battery voltage (default: 1500).
2339
- */
2340
- createDefaultPowerSourceRechargeableBatteryClusterServer(batPercentRemaining = 100, batChargeLevel = PowerSource.BatChargeLevel.Ok, batVoltage = 1500) {
2341
- this.addClusterServer(this.getDefaultPowerSourceRechargeableBatteryClusterServer(batPercentRemaining, batChargeLevel, batVoltage));
2342
- }
2343
- /**
2344
- * Get a default power source wired cluster server.
2345
- *
2346
- * @param wiredCurrentType - The type of wired current (default: PowerSource.WiredCurrentType.Ac)
2347
- */
2348
- getDefaultPowerSourceWiredClusterServer(wiredCurrentType = PowerSource.WiredCurrentType.Ac) {
2349
- return ClusterServer(PowerSourceCluster.with(PowerSource.Feature.Wired), {
2350
- wiredCurrentType,
2351
- description: wiredCurrentType === PowerSource.WiredCurrentType.Ac ? 'AC Power' : 'DC Power',
2352
- status: PowerSource.PowerSourceStatus.Active,
2353
- order: 0,
2354
- endpointList: [],
2355
- }, {}, {});
1351
+ createDefaultOccupancySensingClusterServer(occupied = false) {
1352
+ this.behaviors.require(OccupancySensingServer, this.getDefaultOccupancySensingClusterServer(occupied));
1353
+ return this;
2356
1354
  }
2357
- /**
2358
- * Creates a default power source wired cluster server.
2359
- *
2360
- * @param wiredCurrentType - The type of wired current (default: PowerSource.WiredCurrentType.Ac)
2361
- */
2362
- createDefaultPowerSourceWiredClusterServer(wiredCurrentType = PowerSource.WiredCurrentType.Ac) {
2363
- this.addClusterServer(this.getDefaultPowerSourceWiredClusterServer(wiredCurrentType));
2364
- }
2365
- /**
2366
- * @deprecated This function is deprecated by Matter 1.3 spec and will be removed in a future version.
2367
- */
2368
- createDefaultPowerSourceConfigurationClusterServer(endpointNumber) {
2369
- this.addClusterServer(ClusterServer(PowerSourceConfigurationCluster, {
2370
- sources: endpointNumber ? [EndpointNumber(endpointNumber)] : [],
2371
- }, {}, {}));
2372
- }
2373
- /**
2374
- * Get a default air quality cluster server.
2375
- *
2376
- * @param airQuality The air quality type. Defaults to `AirQuality.AirQualityType.Unknown`.
2377
- */
2378
- getDefaultAirQualityClusterServer(airQuality = AirQuality.AirQualityEnum.Unknown) {
2379
- return ClusterServer(AirQualityCluster.with(AirQuality.Feature.Fair, AirQuality.Feature.Moderate, AirQuality.Feature.VeryPoor, AirQuality.Feature.ExtremelyPoor), {
1355
+ createDefaultAirQualityClusterServer(airQuality = AirQuality.AirQualityEnum.Unknown) {
1356
+ this.behaviors.require(AirQualityServer.with(AirQuality.Feature.Fair, AirQuality.Feature.Moderate, AirQuality.Feature.VeryPoor, AirQuality.Feature.ExtremelyPoor), {
2380
1357
  airQuality,
2381
- }, {}, {});
1358
+ });
1359
+ return this;
2382
1360
  }
2383
- /**
2384
- * Creates a default air quality cluster server.
2385
- *
2386
- * @param airQuality The air quality type. Defaults to `AirQuality.AirQualityType.Unknown`.
2387
- */
2388
- createDefaultAirQualityClusterServer(airQuality = AirQuality.AirQualityEnum.Unknown) {
2389
- this.addClusterServer(this.getDefaultAirQualityClusterServer(airQuality));
2390
- }
2391
- /**
2392
- * Get a default TVOC measurement cluster server.
2393
- *
2394
- * @param measuredValue - The measured value for TVOC.
2395
- */
2396
- getDefaultTvocMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2397
- return ClusterServer(TotalVolatileOrganicCompoundsConcentrationMeasurementCluster.with('NumericMeasurement'), {
1361
+ createDefaultTvocMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
1362
+ this.behaviors.require(TotalVolatileOrganicCompoundsConcentrationMeasurementServer.with(ConcentrationMeasurement.Feature.NumericMeasurement), {
2398
1363
  measuredValue,
2399
1364
  minMeasuredValue: null,
2400
1365
  maxMeasuredValue: null,
2401
1366
  uncertainty: 0,
2402
1367
  measurementUnit,
2403
1368
  measurementMedium,
2404
- }, {}, {});
2405
- }
2406
- /**
2407
- * Creates a default TVOC measurement cluster server.
2408
- *
2409
- * @param measuredValue - The measured value for TVOC.
2410
- */
2411
- createDefaultTvocMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2412
- this.addClusterServer(this.getDefaultTvocMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
2413
- }
2414
- /**
2415
- * Get a default heating thermostat cluster server with the specified parameters.
2416
- * @param {number} [localTemperature] - The local temperature value in degrees Celsius. Defaults to 23°.
2417
- * @param {number} [occupiedHeatingSetpoint] - The occupied heating setpoint value in degrees Celsius. Defaults to 21°.
2418
- * @param {number} [minHeatSetpointLimit] - The minimum heat setpoint limit value. Defaults to 0°.
2419
- * @param {number} [maxHeatSetpointLimit] - The maximum heat setpoint limit value. Defaults to 50°.
2420
- * @returns {ThermostatClusterServer} A default thermostat cluster server configured with the specified parameters.
2421
- */
2422
- getDefaultHeatingThermostatClusterServer(localTemperature = 23, occupiedHeatingSetpoint = 21, minHeatSetpointLimit = 0, maxHeatSetpointLimit = 50) {
2423
- return ClusterServer(ThermostatCluster.with(Thermostat.Feature.Heating), {
2424
- localTemperature: localTemperature * 100,
2425
- systemMode: Thermostat.SystemMode.Heat,
2426
- controlSequenceOfOperation: Thermostat.ControlSequenceOfOperation.HeatingOnly,
2427
- // Thermostat.Feature.Heating
2428
- occupiedHeatingSetpoint: occupiedHeatingSetpoint * 100,
2429
- minHeatSetpointLimit: minHeatSetpointLimit * 100,
2430
- maxHeatSetpointLimit: maxHeatSetpointLimit * 100,
2431
- absMinHeatSetpointLimit: minHeatSetpointLimit * 100,
2432
- absMaxHeatSetpointLimit: maxHeatSetpointLimit * 100,
2433
- }, {
2434
- setpointRaiseLower: async (data) => {
2435
- // Never called in edge
2436
- },
2437
- }, {});
2438
- }
2439
- /**
2440
- * Creates and adds a default heating thermostat cluster server to the device.
2441
- *
2442
- * @param {number} [localTemperature] - The local temperature value in degrees Celsius. Defaults to 23°.
2443
- * @param {number} [occupiedHeatingSetpoint] - The occupied heating setpoint value in degrees Celsius. Defaults to 21°.
2444
- * @param {number} [minHeatSetpointLimit] - The minimum heat setpoint limit value. Defaults to 0°.
2445
- * @param {number} [maxHeatSetpointLimit] - The maximum heat setpoint limit value. Defaults to 50°.
2446
- */
2447
- createDefaultHeatingThermostatClusterServer(localTemperature = 23, occupiedHeatingSetpoint = 25, minHeatSetpointLimit = 0, maxHeatSetpointLimit = 50) {
2448
- this.addClusterServer(this.getDefaultHeatingThermostatClusterServer(localTemperature, occupiedHeatingSetpoint, minHeatSetpointLimit, maxHeatSetpointLimit));
2449
- }
2450
- /**
2451
- * Get a default cooling thermostat cluster server with the specified parameters.
2452
- * @param {number} [localTemperature] - The local temperature value in degrees Celsius. Defaults to 23°.
2453
- * @param {number} [occupiedCoolingSetpoint] - The occupied cooling setpoint value in degrees Celsius. Defaults to 25°.
2454
- * @param {number} [minCoolSetpointLimit] - The minimum cool setpoint limit value. Defaults to 0°.
2455
- * @param {number} [maxCoolSetpointLimit] - The maximum cool setpoint limit value. Defaults to 50°.
2456
- * @returns {ThermostatClusterServer} A default thermostat cluster server configured with the specified parameters.
2457
- */
2458
- getDefaultCoolingThermostatClusterServer(localTemperature = 23, occupiedCoolingSetpoint = 25, minCoolSetpointLimit = 0, maxCoolSetpointLimit = 50) {
2459
- return ClusterServer(ThermostatCluster.with(Thermostat.Feature.Cooling), {
2460
- localTemperature: localTemperature * 100,
2461
- systemMode: Thermostat.SystemMode.Cool,
2462
- controlSequenceOfOperation: Thermostat.ControlSequenceOfOperation.CoolingOnly,
2463
- // Thermostat.Feature.Cooling
2464
- occupiedCoolingSetpoint: occupiedCoolingSetpoint * 100,
2465
- minCoolSetpointLimit: minCoolSetpointLimit * 100,
2466
- maxCoolSetpointLimit: maxCoolSetpointLimit * 100,
2467
- absMinCoolSetpointLimit: minCoolSetpointLimit * 100,
2468
- absMaxCoolSetpointLimit: maxCoolSetpointLimit * 100,
2469
- }, {
2470
- setpointRaiseLower: async (data) => {
2471
- // Never called in edge
2472
- },
2473
- }, {});
2474
- }
2475
- /**
2476
- * Creates and adds a default cooling thermostat cluster server to the device.
2477
- *
2478
- * @param {number} [localTemperature] - The local temperature value in degrees Celsius. Defaults to 23°.
2479
- * @param {number} [occupiedCoolingSetpoint] - The occupied cooling setpoint value in degrees Celsius. Defaults to 25°.
2480
- * @param {number} [minCoolSetpointLimit] - The minimum cool setpoint limit value. Defaults to 0°.
2481
- * @param {number} [maxCoolSetpointLimit] - The maximum cool setpoint limit value. Defaults to 50°.
2482
- */
2483
- createDefaultCoolingThermostatClusterServer(localTemperature = 23, occupiedCoolingSetpoint = 25, minCoolSetpointLimit = 0, maxCoolSetpointLimit = 50) {
2484
- this.addClusterServer(this.getDefaultCoolingThermostatClusterServer(localTemperature, occupiedCoolingSetpoint, minCoolSetpointLimit, maxCoolSetpointLimit));
2485
- }
2486
- /**
2487
- * Get a default thermostat cluster server with the specified parameters.
2488
- *
2489
- * @param {number} [localTemperature=23] - The local temperature value in degrees Celsius. Defaults to 23°.
2490
- * @param {number} [occupiedHeatingSetpoint=21] - The occupied heating setpoint value in degrees Celsius. Defaults to 21°.
2491
- * @param {number} [occupiedCoolingSetpoint=25] - The occupied cooling setpoint value in degrees Celsius. Defaults to 25°.
2492
- * @param {number} [minSetpointDeadBand=1] - The minimum setpoint dead band value. Defaults to 1°.
2493
- * @param {number} [minHeatSetpointLimit=0] - The minimum heat setpoint limit value. Defaults to 0°.
2494
- * @param {number} [maxHeatSetpointLimit=50] - The maximum heat setpoint limit value. Defaults to 50°.
2495
- * @param {number} [minCoolSetpointLimit=0] - The minimum cool setpoint limit value. Defaults to 0°.
2496
- * @param {number} [maxCoolSetpointLimit=50] - The maximum cool setpoint limit value. Defaults to 50°.
2497
- * @returns {ThermostatClusterServer} A default thermostat cluster server configured with the specified parameters.
2498
- */
2499
- getDefaultThermostatClusterServer(localTemperature = 23, occupiedHeatingSetpoint = 21, occupiedCoolingSetpoint = 25, minSetpointDeadBand = 1, minHeatSetpointLimit = 0, maxHeatSetpointLimit = 50, minCoolSetpointLimit = 0, maxCoolSetpointLimit = 50) {
2500
- return ClusterServer(ThermostatCluster.with(Thermostat.Feature.Heating, Thermostat.Feature.Cooling, Thermostat.Feature.AutoMode), {
2501
- localTemperature: localTemperature * 100,
2502
- systemMode: Thermostat.SystemMode.Auto,
2503
- controlSequenceOfOperation: Thermostat.ControlSequenceOfOperation.CoolingAndHeating,
2504
- // Thermostat.Feature.Heating
2505
- occupiedHeatingSetpoint: occupiedHeatingSetpoint * 100,
2506
- minHeatSetpointLimit: minHeatSetpointLimit * 100,
2507
- maxHeatSetpointLimit: maxHeatSetpointLimit * 100,
2508
- absMinHeatSetpointLimit: minHeatSetpointLimit * 100,
2509
- absMaxHeatSetpointLimit: maxHeatSetpointLimit * 100,
2510
- // Thermostat.Feature.Cooling
2511
- occupiedCoolingSetpoint: occupiedCoolingSetpoint * 100,
2512
- minCoolSetpointLimit: minCoolSetpointLimit * 100,
2513
- maxCoolSetpointLimit: maxCoolSetpointLimit * 100,
2514
- absMinCoolSetpointLimit: minCoolSetpointLimit * 100,
2515
- absMaxCoolSetpointLimit: maxCoolSetpointLimit * 100,
2516
- // Thermostat.Feature.AutoMode
2517
- minSetpointDeadBand: minSetpointDeadBand * 100,
2518
- thermostatRunningMode: Thermostat.ThermostatRunningMode.Off,
2519
- }, {
2520
- setpointRaiseLower: async (data) => {
2521
- // Never called in edge
2522
- },
2523
- }, {});
2524
- }
2525
- /**
2526
- * Creates and adds a default thermostat cluster server to the device.
2527
- *
2528
- * @param {number} [localTemperature=23] - The local temperature value in degrees Celsius. Defaults to 23°.
2529
- * @param {number} [occupiedHeatingSetpoint=21] - The occupied heating setpoint value in degrees Celsius. Defaults to 21°.
2530
- * @param {number} [occupiedCoolingSetpoint=25] - The occupied cooling setpoint value in degrees Celsius. Defaults to 25°.
2531
- * @param {number} [minSetpointDeadBand=1] - The minimum setpoint dead band value. Defaults to 1°.
2532
- * @param {number} [minHeatSetpointLimit=0] - The minimum heat setpoint limit value. Defaults to 0°.
2533
- * @param {number} [maxHeatSetpointLimit=50] - The maximum heat setpoint limit value. Defaults to 50°.
2534
- * @param {number} [minCoolSetpointLimit=0] - The minimum cool setpoint limit value. Defaults to 0°.
2535
- * @param {number} [maxCoolSetpointLimit=50] - The maximum cool setpoint limit value. Defaults to 50°.
2536
- */
2537
- createDefaultThermostatClusterServer(localTemperature = 23, occupiedHeatingSetpoint = 21, occupiedCoolingSetpoint = 25, minSetpointDeadBand = 1, minHeatSetpointLimit = 0, maxHeatSetpointLimit = 50, minCoolSetpointLimit = 0, maxCoolSetpointLimit = 50) {
2538
- this.addClusterServer(this.getDefaultThermostatClusterServer(localTemperature, occupiedHeatingSetpoint, occupiedCoolingSetpoint, minSetpointDeadBand, minHeatSetpointLimit, maxHeatSetpointLimit, minCoolSetpointLimit, maxCoolSetpointLimit));
2539
- }
2540
- /**
2541
- * Returns the default SmokeCOAlarm Cluster Server.
2542
- *
2543
- * @param smokeState - The state of the smoke alarm. Defaults to SmokeCoAlarm.AlarmState.Normal.
2544
- * @param coState - The state of the CO alarm. Defaults to SmokeCoAlarm.AlarmState.Normal.
2545
- * @returns The default SmokeCOAlarmClusterServer.
2546
- */
2547
- getDefaultSmokeCOAlarmClusterServer(smokeState = SmokeCoAlarm.AlarmState.Normal, coState = SmokeCoAlarm.AlarmState.Normal) {
2548
- return ClusterServer(SmokeCoAlarmCluster.with(SmokeCoAlarm.Feature.SmokeAlarm, SmokeCoAlarm.Feature.CoAlarm), {
2549
- smokeState,
2550
- coState,
2551
- expressedState: SmokeCoAlarm.ExpressedState.Normal,
2552
- batteryAlert: SmokeCoAlarm.AlarmState.Normal,
2553
- deviceMuted: SmokeCoAlarm.MuteState.NotMuted,
2554
- testInProgress: false,
2555
- hardwareFaultAlert: false,
2556
- endOfServiceAlert: SmokeCoAlarm.EndOfService.Normal,
2557
- interconnectSmokeAlarm: SmokeCoAlarm.AlarmState.Normal,
2558
- interconnectCoAlarm: SmokeCoAlarm.AlarmState.Normal,
2559
- }, {
2560
- selfTestRequest: async (data) => {
2561
- // Never called in edge
2562
- },
2563
- }, {
2564
- smokeAlarm: true,
2565
- interconnectSmokeAlarm: true,
2566
- coAlarm: true,
2567
- interconnectCoAlarm: true,
2568
- lowBattery: true,
2569
- hardwareFault: true,
2570
- endOfService: true,
2571
- selfTestComplete: true,
2572
- alarmMuted: true,
2573
- muteEnded: true,
2574
- allClear: true,
2575
1369
  });
1370
+ return this;
2576
1371
  }
2577
- /**
2578
- * Create the default SmokeCOAlarm Cluster Server.
2579
- *
2580
- * @param smokeState - The state of the smoke alarm. Defaults to SmokeCoAlarm.AlarmState.Normal.
2581
- * @param coState - The state of the CO alarm. Defaults to SmokeCoAlarm.AlarmState.Normal.
2582
- * @returns The default SmokeCOAlarmClusterServer.
2583
- */
2584
- createDefaultSmokeCOAlarmClusterServer(smokeState = SmokeCoAlarm.AlarmState.Normal, coState = SmokeCoAlarm.AlarmState.Normal) {
2585
- this.addClusterServer(this.getDefaultSmokeCOAlarmClusterServer(smokeState, coState));
2586
- }
2587
- /**
2588
- * Returns the default Carbon Monoxide Concentration Measurement Cluster Server.
2589
- *
2590
- * @param {number} measuredValue - The measured value of the concentration.
2591
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2592
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2593
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
2594
- */
2595
- getDefaultCarbonMonoxideConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2596
- return ClusterServer(CarbonMonoxideConcentrationMeasurementCluster.with('NumericMeasurement'), {
2597
- measuredValue,
2598
- minMeasuredValue: null,
2599
- maxMeasuredValue: null,
2600
- uncertainty: 0,
2601
- measurementUnit,
2602
- measurementMedium,
2603
- }, {}, {});
2604
- }
2605
- /**
2606
- * Create the default Carbon Monoxide Concentration Measurement Cluster Server.
2607
- *
2608
- * @param {number} measuredValue - The measured value of the concentration.
2609
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2610
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2611
- */
2612
1372
  createDefaultCarbonMonoxideConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2613
- this.addClusterServer(this.getDefaultCarbonMonoxideConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
2614
- }
2615
- /**
2616
- * Returns the default Carbon Dioxide Concentration Measurement Cluster Server.
2617
- *
2618
- * @param {number} measuredValue - The measured value of the concentration.
2619
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2620
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2621
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
2622
- */
2623
- getDefaultCarbonDioxideConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2624
- return ClusterServer(CarbonDioxideConcentrationMeasurementCluster.with('NumericMeasurement'), {
1373
+ this.behaviors.require(CarbonMonoxideConcentrationMeasurementServer.with(ConcentrationMeasurement.Feature.NumericMeasurement), {
2625
1374
  measuredValue,
2626
1375
  minMeasuredValue: null,
2627
1376
  maxMeasuredValue: null,
2628
1377
  uncertainty: 0,
2629
1378
  measurementUnit,
2630
1379
  measurementMedium,
2631
- }, {}, {});
2632
- }
2633
- /**
2634
- * Create the default Carbon Dioxide Concentration Measurement Cluster Server.
2635
- *
2636
- * @param {number} measuredValue - The measured value of the concentration.
2637
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2638
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2639
- */
1380
+ });
1381
+ return this;
1382
+ }
2640
1383
  createDefaultCarbonDioxideConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2641
- this.addClusterServer(this.getDefaultCarbonDioxideConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
2642
- }
2643
- /**
2644
- * Returns the default Formaldehyde Concentration Measurement Cluster Server.
2645
- *
2646
- * @param {number} measuredValue - The measured value of the concentration.
2647
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2648
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2649
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
2650
- */
2651
- getDefaultFormaldehydeConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2652
- return ClusterServer(FormaldehydeConcentrationMeasurementCluster.with('NumericMeasurement'), {
1384
+ this.behaviors.require(CarbonDioxideConcentrationMeasurementServer.with(ConcentrationMeasurement.Feature.NumericMeasurement), {
2653
1385
  measuredValue,
2654
1386
  minMeasuredValue: null,
2655
1387
  maxMeasuredValue: null,
2656
1388
  uncertainty: 0,
2657
1389
  measurementUnit,
2658
1390
  measurementMedium,
2659
- }, {}, {});
2660
- }
2661
- /**
2662
- * Create the default Formaldehyde Concentration Measurement Cluster Server.
2663
- *
2664
- * @param {number} measuredValue - The measured value of the concentration.
2665
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2666
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2667
- */
1391
+ });
1392
+ return this;
1393
+ }
2668
1394
  createDefaultFormaldehydeConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2669
- this.addClusterServer(this.getDefaultFormaldehydeConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
2670
- }
2671
- /**
2672
- * Returns the default Pm1 Concentration Measurement Cluster Server.
2673
- *
2674
- * @param {number} measuredValue - The measured value of the concentration.
2675
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2676
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2677
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
2678
- */
2679
- getDefaultPm1ConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2680
- return ClusterServer(Pm1ConcentrationMeasurementCluster.with('NumericMeasurement'), {
1395
+ this.behaviors.require(FormaldehydeConcentrationMeasurementServer.with(ConcentrationMeasurement.Feature.NumericMeasurement), {
2681
1396
  measuredValue,
2682
1397
  minMeasuredValue: null,
2683
1398
  maxMeasuredValue: null,
2684
1399
  uncertainty: 0,
2685
1400
  measurementUnit,
2686
1401
  measurementMedium,
2687
- }, {}, {});
2688
- }
2689
- /**
2690
- * Create the default Pm1 Concentration Measurement Cluster Server.
2691
- *
2692
- * @param {number} measuredValue - The measured value of the concentration.
2693
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2694
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2695
- */
1402
+ });
1403
+ return this;
1404
+ }
2696
1405
  createDefaultPm1ConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2697
- this.addClusterServer(this.getDefaultPm1ConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
2698
- }
2699
- /**
2700
- * Returns the default Pm25 Concentration Measurement Cluster Server.
2701
- *
2702
- * @param {number} measuredValue - The measured value of the concentration.
2703
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2704
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2705
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
2706
- */
2707
- getDefaultPm25ConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2708
- return ClusterServer(Pm25ConcentrationMeasurementCluster.with('NumericMeasurement'), {
1406
+ this.behaviors.require(Pm1ConcentrationMeasurementServer.with(ConcentrationMeasurement.Feature.NumericMeasurement), {
2709
1407
  measuredValue,
2710
1408
  minMeasuredValue: null,
2711
1409
  maxMeasuredValue: null,
2712
1410
  uncertainty: 0,
2713
1411
  measurementUnit,
2714
1412
  measurementMedium,
2715
- }, {}, {});
2716
- }
2717
- /**
2718
- * Create the default Pm25 Concentration Measurement Cluster Server.
2719
- *
2720
- * @param {number} measuredValue - The measured value of the concentration.
2721
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2722
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2723
- */
1413
+ });
1414
+ return this;
1415
+ }
2724
1416
  createDefaultPm25ConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2725
- this.addClusterServer(this.getDefaultPm25ConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
2726
- }
2727
- /**
2728
- * Returns the default Pm10 Concentration Measurement Cluster Server.
2729
- *
2730
- * @param {number} measuredValue - The measured value of the concentration.
2731
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2732
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2733
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
2734
- */
2735
- getDefaultPm10ConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2736
- return ClusterServer(Pm10ConcentrationMeasurementCluster.with('NumericMeasurement'), {
1417
+ this.behaviors.require(Pm25ConcentrationMeasurementServer.with(ConcentrationMeasurement.Feature.NumericMeasurement), {
2737
1418
  measuredValue,
2738
1419
  minMeasuredValue: null,
2739
1420
  maxMeasuredValue: null,
2740
1421
  uncertainty: 0,
2741
1422
  measurementUnit,
2742
1423
  measurementMedium,
2743
- }, {}, {});
2744
- }
2745
- /**
2746
- * Create the default Pm10 Concentration Measurement Cluster Server.
2747
- *
2748
- * @param {number} measuredValue - The measured value of the concentration.
2749
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2750
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2751
- */
1424
+ });
1425
+ return this;
1426
+ }
2752
1427
  createDefaultPm10ConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2753
- this.addClusterServer(this.getDefaultPm10ConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
2754
- }
2755
- /**
2756
- * Returns the default Ozone Concentration Measurement Cluster Server.
2757
- *
2758
- * @param {number} measuredValue - The measured value of the concentration.
2759
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2760
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2761
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
2762
- */
2763
- getDefaultOzoneConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ugm3, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2764
- return ClusterServer(OzoneConcentrationMeasurementCluster.with('NumericMeasurement'), {
1428
+ this.behaviors.require(Pm10ConcentrationMeasurementServer.with(ConcentrationMeasurement.Feature.NumericMeasurement), {
2765
1429
  measuredValue,
2766
1430
  minMeasuredValue: null,
2767
1431
  maxMeasuredValue: null,
2768
1432
  uncertainty: 0,
2769
1433
  measurementUnit,
2770
1434
  measurementMedium,
2771
- }, {}, {});
2772
- }
2773
- /**
2774
- * Create the default Ozone Concentration Measurement Cluster Server.
2775
- *
2776
- * @param {number} measuredValue - The measured value of the concentration.
2777
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2778
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2779
- */
1435
+ });
1436
+ return this;
1437
+ }
2780
1438
  createDefaultOzoneConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ugm3, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2781
- this.addClusterServer(this.getDefaultOzoneConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
2782
- }
2783
- /**
2784
- * Returns the default Radon Concentration Measurement Cluster Server.
2785
- *
2786
- * @param {number} measuredValue - The measured value of the concentration.
2787
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2788
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2789
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
2790
- */
2791
- getDefaultRadonConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2792
- return ClusterServer(RadonConcentrationMeasurementCluster.with('NumericMeasurement'), {
1439
+ this.behaviors.require(OzoneConcentrationMeasurementServer.with(ConcentrationMeasurement.Feature.NumericMeasurement), {
2793
1440
  measuredValue,
2794
1441
  minMeasuredValue: null,
2795
1442
  maxMeasuredValue: null,
2796
1443
  uncertainty: 0,
2797
1444
  measurementUnit,
2798
1445
  measurementMedium,
2799
- }, {}, {});
2800
- }
2801
- /**
2802
- * Create the default Radon Concentration Measurement Cluster Server.
2803
- *
2804
- * @param {number} measuredValue - The measured value of the concentration.
2805
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2806
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2807
- */
1446
+ });
1447
+ return this;
1448
+ }
2808
1449
  createDefaultRadonConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2809
- this.addClusterServer(this.getDefaultRadonConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
2810
- }
2811
- /**
2812
- * Returns the default Nitrogen Dioxide Concentration Measurement Cluster Server.
2813
- *
2814
- * @param {number} measuredValue - The measured value of the concentration.
2815
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2816
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2817
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
2818
- */
2819
- getDefaultNitrogenDioxideConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ugm3, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2820
- return ClusterServer(NitrogenDioxideConcentrationMeasurementCluster.with('NumericMeasurement'), {
1450
+ this.behaviors.require(RadonConcentrationMeasurementServer.with(ConcentrationMeasurement.Feature.NumericMeasurement), {
2821
1451
  measuredValue,
2822
1452
  minMeasuredValue: null,
2823
1453
  maxMeasuredValue: null,
2824
1454
  uncertainty: 0,
2825
1455
  measurementUnit,
2826
1456
  measurementMedium,
2827
- }, {}, {});
2828
- }
2829
- /**
2830
- * Create the default Nitrogen Dioxide Concentration Measurement Cluster Server.
2831
- *
2832
- * @param {number} measuredValue - The measured value of the concentration.
2833
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
2834
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
2835
- */
1457
+ });
1458
+ return this;
1459
+ }
2836
1460
  createDefaultNitrogenDioxideConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ugm3, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
2837
- this.addClusterServer(this.getDefaultNitrogenDioxideConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
2838
- }
2839
- /**
2840
- * Returns the default fan control cluster server rev 2.
2841
- *
2842
- * @param fanMode The fan mode to set. Defaults to `FanControl.FanMode.Off`.
2843
- * @returns The default fan control cluster server.
2844
- */
2845
- getDefaultFanControlClusterServer(fanMode = FanControl.FanMode.Off) {
2846
- return ClusterServer(FanControlCluster.with(FanControl.Feature.MultiSpeed, FanControl.Feature.Auto, FanControl.Feature.Step), {
2847
- fanMode,
2848
- fanModeSequence: FanControl.FanModeSequence.OffLowMedHighAuto,
2849
- percentSetting: 0,
2850
- percentCurrent: 0,
2851
- speedMax: 100,
2852
- speedSetting: 0,
2853
- speedCurrent: 0,
2854
- }, {
2855
- step: async (data) => {
2856
- // Never called in edge
2857
- },
2858
- }, {});
2859
- }
2860
- /**
2861
- * Create the default fan control cluster server rev 2.
2862
- *
2863
- * @param fanMode The fan mode to set. Defaults to `FanControl.FanMode.Off`.
2864
- * @returns The default fan control cluster server.
2865
- */
2866
- createDefaultFanControlClusterServer(fanMode = FanControl.FanMode.Off) {
2867
- this.addClusterServer(this.getDefaultFanControlClusterServer(fanMode));
2868
- }
2869
- /**
2870
- * Returns the default Pump Configuration And Control cluster server.
2871
- *
2872
- * @param {PumpConfigurationAndControl.OperationMode} [pumpMode=PumpConfigurationAndControl.OperationMode.Normal] - The pump mode to set. Defaults to `PumpConfigurationAndControl.OperationMode.Normal`.
2873
- * @returns {ClusterServer} - The default Pump Configuration And Control cluster server.
2874
- */
2875
- getDefaultPumpConfigurationAndControlClusterServer(pumpMode = PumpConfigurationAndControl.OperationMode.Normal) {
2876
- return ClusterServer(PumpConfigurationAndControlCluster.with(PumpConfigurationAndControl.Feature.ConstantSpeed), {
2877
- minConstSpeed: null,
2878
- maxConstSpeed: null,
2879
- maxPressure: null,
2880
- maxSpeed: null,
2881
- maxFlow: null,
2882
- effectiveOperationMode: pumpMode,
2883
- effectiveControlMode: PumpConfigurationAndControl.ControlMode.ConstantSpeed,
2884
- capacity: null,
2885
- operationMode: pumpMode,
2886
- }, {}, {});
2887
- }
2888
- /**
2889
- * Creates the default Pump Configuration And Control cluster server.
2890
- *
2891
- * @param {PumpConfigurationAndControl.OperationMode} [pumpMode=PumpConfigurationAndControl.OperationMode.Normal] - The pump mode to set. Defaults to `PumpConfigurationAndControl.OperationMode.Normal`.
2892
- * @returns {void}
2893
- */
2894
- createDefaultPumpConfigurationAndControlClusterServer(pumpMode = PumpConfigurationAndControl.OperationMode.Normal) {
2895
- this.addClusterServer(this.getDefaultPumpConfigurationAndControlClusterServer(pumpMode));
2896
- }
2897
- /**
2898
- * Returns the default Valve Configuration And Control cluster server rev 2.
2899
- *
2900
- * @param {ValveConfigurationAndControl.ValveState} [valveState=ValveConfigurationAndControl.ValveState.Closed] - The valve state to set. Defaults to `ValveConfigurationAndControl.ValveState.Closed`.
2901
- * @param {number} [valveLevel=0] - The valve level to set. Defaults to 0.
2902
- * @returns {ClusterServer} - The default Valve Configuration And Control cluster server.
2903
- */
2904
- getDefaultValveConfigurationAndControlClusterServer(valveState = ValveConfigurationAndControl.ValveState.Closed, valveLevel = 0) {
2905
- return ClusterServer(ValveConfigurationAndControlCluster.with(ValveConfigurationAndControl.Feature.Level), {
2906
- currentState: valveState,
2907
- targetState: valveState,
2908
- currentLevel: valveLevel,
2909
- targetLevel: valveLevel,
2910
- openDuration: null,
2911
- defaultOpenDuration: null,
2912
- remainingDuration: null,
2913
- }, {
2914
- open: async (data) => {
2915
- // Never called in edge
2916
- },
2917
- close: async (data) => {
2918
- // Never called in edge
2919
- },
2920
- }, {});
2921
- }
2922
- /**
2923
- * Create the default Valve Configuration And Control cluster server rev 2.
2924
- *
2925
- * @param {ValveConfigurationAndControl.ValveState} [valveState=ValveConfigurationAndControl.ValveState.Closed] - The valve state to set. Defaults to `ValveConfigurationAndControl.ValveState.Closed`.
2926
- * @param {number} [valveLevel=0] - The valve level to set. Defaults to 0.
2927
- * @returns {void}
2928
- */
2929
- createDefaultValveConfigurationAndControlClusterServer(valveState = ValveConfigurationAndControl.ValveState.Closed, valveLevel = 0) {
2930
- this.addClusterServer(this.getDefaultValveConfigurationAndControlClusterServer(valveState, valveLevel));
1461
+ this.behaviors.require(NitrogenDioxideConcentrationMeasurementServer.with(ConcentrationMeasurement.Feature.NumericMeasurement), {
1462
+ measuredValue,
1463
+ minMeasuredValue: null,
1464
+ maxMeasuredValue: null,
1465
+ uncertainty: 0,
1466
+ measurementUnit,
1467
+ measurementMedium,
1468
+ });
1469
+ return this;
2931
1470
  }
2932
1471
  }
2933
- //# sourceMappingURL=matterbridgeEndpoint.js.map