matterbridge 2.0.0 → 2.1.0-dev.10

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 (103) hide show
  1. package/CHANGELOG.md +26 -4
  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 +1 -26
  7. package/dist/frontend.js +143 -313
  8. package/dist/index.js +2 -30
  9. package/dist/logger/export.js +0 -1
  10. package/dist/matter/behaviors.js +1 -0
  11. package/dist/matter/clusters.js +1 -0
  12. package/dist/matter/devices.js +1 -0
  13. package/dist/matter/endpoints.js +1 -0
  14. package/dist/matter/export.js +1 -11
  15. package/dist/matter/types.js +2 -0
  16. package/dist/matterbridge.js +77 -715
  17. package/dist/matterbridgeAccessoryPlatform.js +0 -33
  18. package/dist/matterbridgeBehaviors.js +38 -38
  19. package/dist/matterbridgeDeviceTypes.js +11 -112
  20. package/dist/matterbridgeDynamicPlatform.js +0 -33
  21. package/dist/matterbridgeEndpoint.js +664 -2563
  22. package/dist/matterbridgeEndpointHelpers.js +513 -0
  23. package/dist/matterbridgePlatform.js +5 -125
  24. package/dist/matterbridgeTypes.js +0 -28
  25. package/dist/pluginManager.js +3 -240
  26. package/dist/storage/export.js +0 -1
  27. package/dist/utils/colorUtils.js +2 -205
  28. package/dist/utils/export.js +0 -1
  29. package/dist/utils/utils.js +7 -251
  30. package/frontend/build/asset-manifest.json +3 -3
  31. package/frontend/build/index.html +1 -1
  32. package/frontend/build/static/js/{main.6df4ebe4.js → main.26dbf9b9.js} +3 -3
  33. package/frontend/build/static/js/{main.6df4ebe4.js.map → main.26dbf9b9.js.map} +1 -1
  34. package/npm-shrinkwrap.json +86 -78
  35. package/package.json +22 -4
  36. package/dist/cli.d.ts +0 -25
  37. package/dist/cli.d.ts.map +0 -1
  38. package/dist/cli.js.map +0 -1
  39. package/dist/cluster/export.d.ts +0 -2
  40. package/dist/cluster/export.d.ts.map +0 -1
  41. package/dist/cluster/export.js.map +0 -1
  42. package/dist/defaultConfigSchema.d.ts +0 -27
  43. package/dist/defaultConfigSchema.d.ts.map +0 -1
  44. package/dist/defaultConfigSchema.js.map +0 -1
  45. package/dist/deviceManager.d.ts +0 -46
  46. package/dist/deviceManager.d.ts.map +0 -1
  47. package/dist/deviceManager.js.map +0 -1
  48. package/dist/frontend.d.ts +0 -98
  49. package/dist/frontend.d.ts.map +0 -1
  50. package/dist/frontend.js.map +0 -1
  51. package/dist/index.d.ts +0 -34
  52. package/dist/index.d.ts.map +0 -1
  53. package/dist/index.js.map +0 -1
  54. package/dist/logger/export.d.ts +0 -2
  55. package/dist/logger/export.d.ts.map +0 -1
  56. package/dist/logger/export.js.map +0 -1
  57. package/dist/matter/export.d.ts +0 -10
  58. package/dist/matter/export.d.ts.map +0 -1
  59. package/dist/matter/export.js.map +0 -1
  60. package/dist/matterbridge.d.ts +0 -356
  61. package/dist/matterbridge.d.ts.map +0 -1
  62. package/dist/matterbridge.js.map +0 -1
  63. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -39
  64. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  65. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  66. package/dist/matterbridgeBehaviors.d.ts +0 -963
  67. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  68. package/dist/matterbridgeBehaviors.js.map +0 -1
  69. package/dist/matterbridgeDeviceTypes.d.ts +0 -177
  70. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  71. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  72. package/dist/matterbridgeDynamicPlatform.d.ts +0 -39
  73. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  74. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  75. package/dist/matterbridgeEndpoint.d.ts +0 -10254
  76. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  77. package/dist/matterbridgeEndpoint.js.map +0 -1
  78. package/dist/matterbridgeEndpointDefault.d.ts +0 -2
  79. package/dist/matterbridgeEndpointDefault.d.ts.map +0 -1
  80. package/dist/matterbridgeEndpointDefault.js +0 -159
  81. package/dist/matterbridgeEndpointDefault.js.map +0 -1
  82. package/dist/matterbridgePlatform.d.ts +0 -164
  83. package/dist/matterbridgePlatform.d.ts.map +0 -1
  84. package/dist/matterbridgePlatform.js.map +0 -1
  85. package/dist/matterbridgeTypes.d.ts +0 -167
  86. package/dist/matterbridgeTypes.d.ts.map +0 -1
  87. package/dist/matterbridgeTypes.js.map +0 -1
  88. package/dist/pluginManager.d.ts +0 -238
  89. package/dist/pluginManager.d.ts.map +0 -1
  90. package/dist/pluginManager.js.map +0 -1
  91. package/dist/storage/export.d.ts +0 -2
  92. package/dist/storage/export.d.ts.map +0 -1
  93. package/dist/storage/export.js.map +0 -1
  94. package/dist/utils/colorUtils.d.ts +0 -61
  95. package/dist/utils/colorUtils.d.ts.map +0 -1
  96. package/dist/utils/colorUtils.js.map +0 -1
  97. package/dist/utils/export.d.ts +0 -3
  98. package/dist/utils/export.d.ts.map +0 -1
  99. package/dist/utils/export.js.map +0 -1
  100. package/dist/utils/utils.d.ts +0 -221
  101. package/dist/utils/utils.d.ts.map +0 -1
  102. package/dist/utils/utils.js.map +0 -1
  103. /package/frontend/build/static/js/{main.6df4ebe4.js.LICENSE.txt → main.26dbf9b9.js.LICENSE.txt} +0 -0
@@ -0,0 +1,513 @@
1
+ import { createHash } from 'crypto';
2
+ import { BLUE, CYAN, db, debugStringify, er, hk, or, YELLOW, zb } from './logger/export.js';
3
+ import { MatterbridgeIdentifyServer, MatterbridgeOnOffServer, MatterbridgeLevelControlServer, MatterbridgeColorControlServer, MatterbridgeWindowCoveringServer, MatterbridgeThermostatServer, MatterbridgeFanControlServer, MatterbridgeDoorLockServer, MatterbridgeModeSelectServer, MatterbridgeValveConfigurationAndControlServer, MatterbridgeSmokeCoAlarmServer, MatterbridgeBooleanStateConfigurationServer, } from './matterbridgeBehaviors.js';
4
+ import { Lifecycle } from '@matter/main';
5
+ import { getClusterNameById } from '@matter/main/types';
6
+ import { PowerSource } from '@matter/main/clusters/power-source';
7
+ import { UserLabel } from '@matter/main/clusters/user-label';
8
+ import { FixedLabel } from '@matter/main/clusters/fixed-label';
9
+ import { BasicInformation } from '@matter/main/clusters/basic-information';
10
+ import { BridgedDeviceBasicInformation } from '@matter/main/clusters/bridged-device-basic-information';
11
+ import { Identify } from '@matter/main/clusters/identify';
12
+ import { Groups } from '@matter/main/clusters/groups';
13
+ import { OnOff } from '@matter/main/clusters/on-off';
14
+ import { LevelControl } from '@matter/main/clusters/level-control';
15
+ import { ColorControl } from '@matter/main/clusters/color-control';
16
+ import { WindowCovering } from '@matter/main/clusters/window-covering';
17
+ import { Thermostat } from '@matter/main/clusters/thermostat';
18
+ import { FanControl } from '@matter/main/clusters/fan-control';
19
+ import { DoorLock } from '@matter/main/clusters/door-lock';
20
+ import { ModeSelect } from '@matter/main/clusters/mode-select';
21
+ import { ValveConfigurationAndControl } from '@matter/main/clusters/valve-configuration-and-control';
22
+ import { PumpConfigurationAndControl } from '@matter/main/clusters/pump-configuration-and-control';
23
+ import { SmokeCoAlarm } from '@matter/main/clusters/smoke-co-alarm';
24
+ import { Switch } from '@matter/main/clusters/switch';
25
+ import { BooleanState } from '@matter/main/clusters/boolean-state';
26
+ import { BooleanStateConfiguration } from '@matter/main/clusters/boolean-state-configuration';
27
+ import { PowerTopology } from '@matter/main/clusters/power-topology';
28
+ import { ElectricalPowerMeasurement } from '@matter/main/clusters/electrical-power-measurement';
29
+ import { ElectricalEnergyMeasurement } from '@matter/main/clusters/electrical-energy-measurement';
30
+ import { TemperatureMeasurement } from '@matter/main/clusters/temperature-measurement';
31
+ import { RelativeHumidityMeasurement } from '@matter/main/clusters/relative-humidity-measurement';
32
+ import { PressureMeasurement } from '@matter/main/clusters/pressure-measurement';
33
+ import { FlowMeasurement } from '@matter/main/clusters/flow-measurement';
34
+ import { IlluminanceMeasurement } from '@matter/main/clusters/illuminance-measurement';
35
+ import { OccupancySensing } from '@matter/main/clusters/occupancy-sensing';
36
+ import { AirQuality } from '@matter/main/clusters/air-quality';
37
+ import { CarbonMonoxideConcentrationMeasurement } from '@matter/main/clusters/carbon-monoxide-concentration-measurement';
38
+ import { CarbonDioxideConcentrationMeasurement } from '@matter/main/clusters/carbon-dioxide-concentration-measurement';
39
+ import { NitrogenDioxideConcentrationMeasurement } from '@matter/main/clusters/nitrogen-dioxide-concentration-measurement';
40
+ import { OzoneConcentrationMeasurement } from '@matter/main/clusters/ozone-concentration-measurement';
41
+ import { FormaldehydeConcentrationMeasurement } from '@matter/main/clusters/formaldehyde-concentration-measurement';
42
+ import { Pm1ConcentrationMeasurement } from '@matter/main/clusters/pm1-concentration-measurement';
43
+ import { Pm25ConcentrationMeasurement } from '@matter/main/clusters/pm25-concentration-measurement';
44
+ import { Pm10ConcentrationMeasurement } from '@matter/main/clusters/pm10-concentration-measurement';
45
+ import { RadonConcentrationMeasurement } from '@matter/main/clusters/radon-concentration-measurement';
46
+ import { TotalVolatileOrganicCompoundsConcentrationMeasurement } from '@matter/main/clusters/total-volatile-organic-compounds-concentration-measurement';
47
+ import { PowerSourceServer } from '@matter/main/behaviors/power-source';
48
+ import { UserLabelServer } from '@matter/main/behaviors/user-label';
49
+ import { FixedLabelServer } from '@matter/main/behaviors/fixed-label';
50
+ import { BasicInformationServer } from '@matter/main/behaviors/basic-information';
51
+ import { BridgedDeviceBasicInformationServer } from '@matter/main/behaviors/bridged-device-basic-information';
52
+ import { GroupsServer } from '@matter/main/behaviors/groups';
53
+ import { PumpConfigurationAndControlServer } from '@matter/main/behaviors/pump-configuration-and-control';
54
+ import { SwitchServer } from '@matter/main/behaviors/switch';
55
+ import { BooleanStateServer } from '@matter/main/behaviors/boolean-state';
56
+ import { PowerTopologyServer } from '@matter/main/behaviors/power-topology';
57
+ import { ElectricalPowerMeasurementServer } from '@matter/main/behaviors/electrical-power-measurement';
58
+ import { ElectricalEnergyMeasurementServer } from '@matter/main/behaviors/electrical-energy-measurement';
59
+ import { TemperatureMeasurementServer } from '@matter/main/behaviors/temperature-measurement';
60
+ import { RelativeHumidityMeasurementServer } from '@matter/main/behaviors/relative-humidity-measurement';
61
+ import { PressureMeasurementServer } from '@matter/main/behaviors/pressure-measurement';
62
+ import { FlowMeasurementServer } from '@matter/main/behaviors/flow-measurement';
63
+ import { IlluminanceMeasurementServer } from '@matter/main/behaviors/illuminance-measurement';
64
+ import { OccupancySensingServer } from '@matter/main/behaviors/occupancy-sensing';
65
+ import { AirQualityServer } from '@matter/main/behaviors/air-quality';
66
+ import { CarbonMonoxideConcentrationMeasurementServer } from '@matter/main/behaviors/carbon-monoxide-concentration-measurement';
67
+ import { CarbonDioxideConcentrationMeasurementServer } from '@matter/main/behaviors/carbon-dioxide-concentration-measurement';
68
+ import { NitrogenDioxideConcentrationMeasurementServer } from '@matter/main/behaviors/nitrogen-dioxide-concentration-measurement';
69
+ import { OzoneConcentrationMeasurementServer } from '@matter/main/behaviors/ozone-concentration-measurement';
70
+ import { FormaldehydeConcentrationMeasurementServer } from '@matter/main/behaviors/formaldehyde-concentration-measurement';
71
+ import { Pm1ConcentrationMeasurementServer } from '@matter/main/behaviors/pm1-concentration-measurement';
72
+ import { Pm25ConcentrationMeasurementServer } from '@matter/main/behaviors/pm25-concentration-measurement';
73
+ import { Pm10ConcentrationMeasurementServer } from '@matter/main/behaviors/pm10-concentration-measurement';
74
+ import { RadonConcentrationMeasurementServer } from '@matter/main/behaviors/radon-concentration-measurement';
75
+ import { TotalVolatileOrganicCompoundsConcentrationMeasurementServer } from '@matter/main/behaviors/total-volatile-organic-compounds-concentration-measurement';
76
+ import { deepCopy, deepEqual, isValidArray } from './utils/utils.js';
77
+ export function capitalizeFirstLetter(name) {
78
+ if (!name)
79
+ return name;
80
+ return name.charAt(0).toUpperCase() + name.slice(1);
81
+ }
82
+ export function lowercaseFirstLetter(name) {
83
+ if (!name)
84
+ return name;
85
+ return name.charAt(0).toLowerCase() + name.slice(1);
86
+ }
87
+ export function createUniqueId(param1, param2, param3, param4) {
88
+ const hash = createHash('md5');
89
+ hash.update(param1 + param2 + param3 + param4);
90
+ return hash.digest('hex');
91
+ }
92
+ export function getBehaviourTypesFromClusterServerIds(clusterServerList) {
93
+ const behaviorTypes = [];
94
+ clusterServerList.forEach((clusterId) => {
95
+ behaviorTypes.push(getBehaviourTypeFromClusterServerId(clusterId));
96
+ });
97
+ return behaviorTypes;
98
+ }
99
+ export function getBehaviourTypesFromClusterClientIds(clusterClientList) {
100
+ const behaviorTypes = [];
101
+ clusterClientList.forEach((clusterId) => {
102
+ });
103
+ return behaviorTypes;
104
+ }
105
+ export function getBehaviourTypeFromClusterServerId(clusterId) {
106
+ if (clusterId === PowerSource.Cluster.id)
107
+ return PowerSourceServer.with(PowerSource.Feature.Wired);
108
+ if (clusterId === UserLabel.Cluster.id)
109
+ return UserLabelServer;
110
+ if (clusterId === FixedLabel.Cluster.id)
111
+ return FixedLabelServer;
112
+ if (clusterId === BasicInformation.Cluster.id)
113
+ return BasicInformationServer;
114
+ if (clusterId === BridgedDeviceBasicInformation.Cluster.id)
115
+ return BridgedDeviceBasicInformationServer;
116
+ if (clusterId === Identify.Cluster.id)
117
+ return MatterbridgeIdentifyServer;
118
+ if (clusterId === Groups.Cluster.id)
119
+ return GroupsServer;
120
+ if (clusterId === OnOff.Cluster.id)
121
+ return MatterbridgeOnOffServer.with('Lighting');
122
+ if (clusterId === LevelControl.Cluster.id)
123
+ return MatterbridgeLevelControlServer.with('OnOff', 'Lighting');
124
+ if (clusterId === ColorControl.Cluster.id)
125
+ return MatterbridgeColorControlServer;
126
+ if (clusterId === WindowCovering.Cluster.id)
127
+ return MatterbridgeWindowCoveringServer.with('Lift', 'PositionAwareLift');
128
+ if (clusterId === Thermostat.Cluster.id)
129
+ return MatterbridgeThermostatServer.with('AutoMode', 'Heating', 'Cooling');
130
+ if (clusterId === FanControl.Cluster.id)
131
+ return MatterbridgeFanControlServer;
132
+ if (clusterId === DoorLock.Cluster.id)
133
+ return MatterbridgeDoorLockServer;
134
+ if (clusterId === ModeSelect.Cluster.id)
135
+ return MatterbridgeModeSelectServer;
136
+ if (clusterId === ValveConfigurationAndControl.Cluster.id)
137
+ return MatterbridgeValveConfigurationAndControlServer.with('Level');
138
+ if (clusterId === PumpConfigurationAndControl.Cluster.id)
139
+ return PumpConfigurationAndControlServer.with('ConstantSpeed');
140
+ if (clusterId === SmokeCoAlarm.Cluster.id)
141
+ return MatterbridgeSmokeCoAlarmServer.with('SmokeAlarm', 'CoAlarm');
142
+ if (clusterId === Switch.Cluster.id)
143
+ return SwitchServer.with('MomentarySwitch', 'MomentarySwitchRelease', 'MomentarySwitchLongPress', 'MomentarySwitchMultiPress');
144
+ if (clusterId === BooleanState.Cluster.id)
145
+ return BooleanStateServer.enable({ events: { stateChange: true } });
146
+ if (clusterId === BooleanStateConfiguration.Cluster.id)
147
+ return MatterbridgeBooleanStateConfigurationServer;
148
+ if (clusterId === PowerTopology.Cluster.id)
149
+ return PowerTopologyServer.with('TreeTopology');
150
+ if (clusterId === ElectricalPowerMeasurement.Cluster.id)
151
+ return ElectricalPowerMeasurementServer.with('AlternatingCurrent');
152
+ if (clusterId === ElectricalEnergyMeasurement.Cluster.id)
153
+ return ElectricalEnergyMeasurementServer.with('ImportedEnergy', 'ExportedEnergy', 'CumulativeEnergy');
154
+ if (clusterId === TemperatureMeasurement.Cluster.id)
155
+ return TemperatureMeasurementServer;
156
+ if (clusterId === RelativeHumidityMeasurement.Cluster.id)
157
+ return RelativeHumidityMeasurementServer;
158
+ if (clusterId === PressureMeasurement.Cluster.id)
159
+ return PressureMeasurementServer;
160
+ if (clusterId === FlowMeasurement.Cluster.id)
161
+ return FlowMeasurementServer;
162
+ if (clusterId === IlluminanceMeasurement.Cluster.id)
163
+ return IlluminanceMeasurementServer;
164
+ if (clusterId === OccupancySensing.Cluster.id)
165
+ return OccupancySensingServer;
166
+ if (clusterId === AirQuality.Cluster.id)
167
+ return AirQualityServer.with('Fair', 'Moderate', 'VeryPoor', 'ExtremelyPoor');
168
+ if (clusterId === CarbonMonoxideConcentrationMeasurement.Cluster.id)
169
+ return CarbonMonoxideConcentrationMeasurementServer.with('NumericMeasurement');
170
+ if (clusterId === CarbonDioxideConcentrationMeasurement.Cluster.id)
171
+ return CarbonDioxideConcentrationMeasurementServer.with('NumericMeasurement');
172
+ if (clusterId === NitrogenDioxideConcentrationMeasurement.Cluster.id)
173
+ return NitrogenDioxideConcentrationMeasurementServer.with('NumericMeasurement');
174
+ if (clusterId === OzoneConcentrationMeasurement.Cluster.id)
175
+ return OzoneConcentrationMeasurementServer.with('NumericMeasurement');
176
+ if (clusterId === FormaldehydeConcentrationMeasurement.Cluster.id)
177
+ return FormaldehydeConcentrationMeasurementServer.with('NumericMeasurement');
178
+ if (clusterId === Pm1ConcentrationMeasurement.Cluster.id)
179
+ return Pm1ConcentrationMeasurementServer.with('NumericMeasurement');
180
+ if (clusterId === Pm25ConcentrationMeasurement.Cluster.id)
181
+ return Pm25ConcentrationMeasurementServer.with('NumericMeasurement');
182
+ if (clusterId === Pm10ConcentrationMeasurement.Cluster.id)
183
+ return Pm10ConcentrationMeasurementServer.with('NumericMeasurement');
184
+ if (clusterId === RadonConcentrationMeasurement.Cluster.id)
185
+ return RadonConcentrationMeasurementServer.with('NumericMeasurement');
186
+ if (clusterId === TotalVolatileOrganicCompoundsConcentrationMeasurement.Cluster.id)
187
+ return TotalVolatileOrganicCompoundsConcentrationMeasurementServer.with('NumericMeasurement');
188
+ return MatterbridgeIdentifyServer;
189
+ }
190
+ export function getBehaviourTypeFromClusterClientId(clusterId) {
191
+ }
192
+ export function getBehavior(endpoint, cluster) {
193
+ let behavior;
194
+ if (typeof cluster === 'string') {
195
+ behavior = endpoint.behaviors.supported[lowercaseFirstLetter(cluster)];
196
+ }
197
+ else if (typeof cluster === 'number') {
198
+ behavior = endpoint.behaviors.supported[lowercaseFirstLetter(getClusterNameById(cluster))];
199
+ }
200
+ else if (typeof cluster === 'object') {
201
+ behavior = endpoint.behaviors.supported[lowercaseFirstLetter(cluster.name)];
202
+ }
203
+ else if (typeof cluster === 'function') {
204
+ behavior = cluster;
205
+ }
206
+ return behavior;
207
+ }
208
+ export function addRequiredClusterServers(endpoint) {
209
+ const requiredServerList = [];
210
+ endpoint.log.debug(`addRequiredClusterServers for ${CYAN}${endpoint.maybeId}${db}`);
211
+ Array.from(endpoint.deviceTypes.values()).forEach((deviceType) => {
212
+ endpoint.log.debug(`- for deviceType: ${zb}${'0x' + deviceType.code.toString(16).padStart(4, '0')}${db}-${zb}${deviceType.name}${db}`);
213
+ deviceType.requiredServerClusters.forEach((clusterId) => {
214
+ if (!requiredServerList.includes(clusterId) && !endpoint.hasClusterServer(clusterId)) {
215
+ requiredServerList.push(clusterId);
216
+ endpoint.log.debug(`- cluster: ${hk}${'0x' + clusterId.toString(16).padStart(4, '0')}${db}-${hk}${getClusterNameById(clusterId)}${db}`);
217
+ }
218
+ });
219
+ });
220
+ addClusterServers(endpoint, requiredServerList);
221
+ }
222
+ export function addOptionalClusterServers(endpoint) {
223
+ const optionalServerList = [];
224
+ endpoint.log.debug(`addOptionalClusterServers for ${CYAN}${endpoint.maybeId}${db}`);
225
+ Array.from(endpoint.deviceTypes.values()).forEach((deviceType) => {
226
+ endpoint.log.debug(`- for deviceType: ${zb}${'0x' + deviceType.code.toString(16).padStart(4, '0')}${db}-${zb}${deviceType.name}${db}`);
227
+ deviceType.optionalServerClusters.forEach((clusterId) => {
228
+ if (!optionalServerList.includes(clusterId) && !endpoint.hasClusterServer(clusterId)) {
229
+ optionalServerList.push(clusterId);
230
+ endpoint.log.debug(`- cluster: ${hk}${'0x' + clusterId.toString(16).padStart(4, '0')}${db}-${hk}${getClusterNameById(clusterId)}${db}`);
231
+ }
232
+ });
233
+ });
234
+ addClusterServers(endpoint, optionalServerList);
235
+ }
236
+ export function addClusterServers(endpoint, serverList) {
237
+ if (serverList.includes(PowerSource.Cluster.id))
238
+ endpoint.createDefaultPowerSourceWiredClusterServer();
239
+ if (serverList.includes(Identify.Cluster.id))
240
+ endpoint.createDefaultIdentifyClusterServer();
241
+ if (serverList.includes(Groups.Cluster.id))
242
+ endpoint.createDefaultGroupsClusterServer();
243
+ if (serverList.includes(OnOff.Cluster.id))
244
+ endpoint.createDefaultOnOffClusterServer();
245
+ if (serverList.includes(LevelControl.Cluster.id))
246
+ endpoint.createDefaultLevelControlClusterServer();
247
+ if (serverList.includes(ColorControl.Cluster.id))
248
+ endpoint.createDefaultColorControlClusterServer();
249
+ if (serverList.includes(WindowCovering.Cluster.id))
250
+ endpoint.createDefaultWindowCoveringClusterServer();
251
+ if (serverList.includes(Thermostat.Cluster.id))
252
+ endpoint.createDefaultThermostatClusterServer();
253
+ if (serverList.includes(FanControl.Cluster.id))
254
+ endpoint.createDefaultFanControlClusterServer();
255
+ if (serverList.includes(DoorLock.Cluster.id))
256
+ endpoint.createDefaultDoorLockClusterServer();
257
+ if (serverList.includes(ValveConfigurationAndControl.Cluster.id))
258
+ endpoint.createDefaultValveConfigurationAndControlClusterServer();
259
+ if (serverList.includes(PumpConfigurationAndControl.Cluster.id))
260
+ endpoint.createDefaultPumpConfigurationAndControlClusterServer();
261
+ if (serverList.includes(SmokeCoAlarm.Cluster.id))
262
+ endpoint.createDefaultSmokeCOAlarmClusterServer();
263
+ if (serverList.includes(Switch.Cluster.id))
264
+ endpoint.createDefaultSwitchClusterServer();
265
+ if (serverList.includes(BooleanState.Cluster.id))
266
+ endpoint.createDefaultBooleanStateClusterServer();
267
+ if (serverList.includes(BooleanStateConfiguration.Cluster.id))
268
+ endpoint.createDefaultBooleanStateConfigurationClusterServer();
269
+ if (serverList.includes(PowerTopology.Cluster.id))
270
+ endpoint.createDefaultPowerTopologyClusterServer();
271
+ if (serverList.includes(ElectricalPowerMeasurement.Cluster.id))
272
+ endpoint.createDefaultElectricalPowerMeasurementClusterServer();
273
+ if (serverList.includes(ElectricalEnergyMeasurement.Cluster.id))
274
+ endpoint.createDefaultElectricalEnergyMeasurementClusterServer();
275
+ if (serverList.includes(TemperatureMeasurement.Cluster.id))
276
+ endpoint.createDefaultTemperatureMeasurementClusterServer();
277
+ if (serverList.includes(RelativeHumidityMeasurement.Cluster.id))
278
+ endpoint.createDefaultRelativeHumidityMeasurementClusterServer();
279
+ if (serverList.includes(PressureMeasurement.Cluster.id))
280
+ endpoint.createDefaultPressureMeasurementClusterServer();
281
+ if (serverList.includes(FlowMeasurement.Cluster.id))
282
+ endpoint.createDefaultFlowMeasurementClusterServer();
283
+ if (serverList.includes(IlluminanceMeasurement.Cluster.id))
284
+ endpoint.createDefaultIlluminanceMeasurementClusterServer();
285
+ if (serverList.includes(OccupancySensing.Cluster.id))
286
+ endpoint.createDefaultOccupancySensingClusterServer();
287
+ if (serverList.includes(AirQuality.Cluster.id))
288
+ endpoint.createDefaultAirQualityClusterServer();
289
+ if (serverList.includes(CarbonMonoxideConcentrationMeasurement.Cluster.id))
290
+ endpoint.createDefaultCarbonMonoxideConcentrationMeasurementClusterServer();
291
+ if (serverList.includes(CarbonDioxideConcentrationMeasurement.Cluster.id))
292
+ endpoint.createDefaultCarbonDioxideConcentrationMeasurementClusterServer();
293
+ if (serverList.includes(NitrogenDioxideConcentrationMeasurement.Cluster.id))
294
+ endpoint.createDefaultNitrogenDioxideConcentrationMeasurementClusterServer();
295
+ if (serverList.includes(OzoneConcentrationMeasurement.Cluster.id))
296
+ endpoint.createDefaultOzoneConcentrationMeasurementClusterServer();
297
+ if (serverList.includes(FormaldehydeConcentrationMeasurement.Cluster.id))
298
+ endpoint.createDefaultFormaldehydeConcentrationMeasurementClusterServer();
299
+ if (serverList.includes(Pm1ConcentrationMeasurement.Cluster.id))
300
+ endpoint.createDefaultPm1ConcentrationMeasurementClusterServer();
301
+ if (serverList.includes(Pm25ConcentrationMeasurement.Cluster.id))
302
+ endpoint.createDefaultPm25ConcentrationMeasurementClusterServer();
303
+ if (serverList.includes(Pm10ConcentrationMeasurement.Cluster.id))
304
+ endpoint.createDefaultPm10ConcentrationMeasurementClusterServer();
305
+ if (serverList.includes(RadonConcentrationMeasurement.Cluster.id))
306
+ endpoint.createDefaultRadonConcentrationMeasurementClusterServer();
307
+ if (serverList.includes(TotalVolatileOrganicCompoundsConcentrationMeasurement.Cluster.id))
308
+ endpoint.createDefaultTvocMeasurementClusterServer();
309
+ }
310
+ export async function addFixedLabel(endpoint, label, value) {
311
+ if (!endpoint.hasClusterServer(FixedLabel.Cluster.id)) {
312
+ endpoint.log.debug(`addFixedLabel: add cluster ${hk}FixedLabel${db}:${hk}fixedLabel${db} with label ${CYAN}${label}${db} value ${CYAN}${value}${db}`);
313
+ endpoint.behaviors.require(FixedLabelServer, {
314
+ labelList: [{ label, value }],
315
+ });
316
+ return;
317
+ }
318
+ endpoint.log.debug(`addFixedLabel: add label ${CYAN}${label}${db} value ${CYAN}${value}${db}`);
319
+ let labelList = endpoint.getAttribute(FixedLabel.Cluster.id, 'labelList', endpoint.log);
320
+ if (isValidArray(labelList)) {
321
+ labelList = labelList.filter((entry) => entry.label !== label);
322
+ labelList.push({ label, value });
323
+ await endpoint.setAttribute(FixedLabel.Cluster.id, 'labelList', labelList, endpoint.log);
324
+ }
325
+ }
326
+ export async function addUserLabel(endpoint, label, value) {
327
+ if (!endpoint.hasClusterServer(UserLabel.Cluster.id)) {
328
+ endpoint.log.debug(`addUserLabel: add cluster ${hk}UserLabel${db}:${hk}userLabel${db} with label ${CYAN}${label}${db} value ${CYAN}${value}${db}`);
329
+ endpoint.behaviors.require(UserLabelServer, {
330
+ labelList: [{ label, value }],
331
+ });
332
+ return;
333
+ }
334
+ endpoint.log.debug(`addUserLabel: add label ${CYAN}${label}${db} value ${CYAN}${value}${db}`);
335
+ let labelList = endpoint.getAttribute(UserLabel.Cluster.id, 'labelList', endpoint.log);
336
+ if (isValidArray(labelList)) {
337
+ labelList = labelList.filter((entry) => entry.label !== label);
338
+ labelList.push({ label, value });
339
+ await endpoint.setAttribute(UserLabel.Cluster.id, 'labelList', labelList, endpoint.log);
340
+ }
341
+ }
342
+ export function optionsFor(type, options) {
343
+ return options;
344
+ }
345
+ export function getClusterId(endpoint, cluster) {
346
+ return endpoint.behaviors.supported[lowercaseFirstLetter(cluster)]?.schema?.id;
347
+ }
348
+ export function getAttributeId(endpoint, cluster, attribute) {
349
+ if (attribute === 'attributeList')
350
+ return 0xfffb;
351
+ else if (attribute === 'featureMap')
352
+ return 0xfffc;
353
+ else if (attribute === 'eventList')
354
+ return 0xfffa;
355
+ else if (attribute === 'generatedCommandList')
356
+ return 0xfff8;
357
+ else if (attribute === 'acceptedCommandList')
358
+ return 0xfff9;
359
+ else if (attribute === 'clusterRevision')
360
+ return 0xfffd;
361
+ else {
362
+ if (endpoint.behaviors.supported[lowercaseFirstLetter(cluster)]?.schema?.type === 'ConcentrationMeasurement') {
363
+ if (attribute === 'measuredValue')
364
+ return 0x0;
365
+ else if (attribute === 'minMeasuredValue')
366
+ return 0x1;
367
+ else if (attribute === 'maxMeasuredValue')
368
+ return 0x2;
369
+ else if (attribute === 'peakMeasuredValue')
370
+ return 0x3;
371
+ else if (attribute === 'peakMeasuredValueWindow')
372
+ return 0x4;
373
+ else if (attribute === 'averageMeasuredValue')
374
+ return 0x5;
375
+ else if (attribute === 'averageMeasuredValueWindow')
376
+ return 0x6;
377
+ else if (attribute === 'uncertainty')
378
+ return 0x7;
379
+ else if (attribute === 'measurementUnit')
380
+ return 0x8;
381
+ else if (attribute === 'measurementMedium')
382
+ return 0x9;
383
+ else if (attribute === 'levelValue')
384
+ return 0xa;
385
+ }
386
+ return endpoint.behaviors.supported[lowercaseFirstLetter(cluster)]?.schema?.children?.find((child) => child.name === capitalizeFirstLetter(attribute))?.id;
387
+ }
388
+ }
389
+ export function getAttribute(endpoint, cluster, attribute, log) {
390
+ const clusterName = getBehavior(endpoint, cluster)?.id;
391
+ if (!clusterName) {
392
+ endpoint.log.error(`getAttribute ${hk}${attribute}${er} error: cluster not found on endpoint ${or}${endpoint.maybeId}${er}:${or}${endpoint.maybeNumber}${er}`);
393
+ return undefined;
394
+ }
395
+ if (endpoint.construction.status !== Lifecycle.Status.Active) {
396
+ endpoint.log.error(`getAttribute ${hk}${clusterName}.${attribute}${er} error: Endpoint ${or}${endpoint.maybeId}${er}:${or}${endpoint.maybeNumber}${er} is in the ${BLUE}${endpoint.construction.status}${er} state`);
397
+ return undefined;
398
+ }
399
+ const state = endpoint.state;
400
+ attribute = lowercaseFirstLetter(attribute);
401
+ if (!(attribute in state[clusterName])) {
402
+ endpoint.log.error(`getAttribute error: Attribute ${hk}${attribute}${er} not found on Cluster ${'0x' + getClusterId(endpoint, clusterName)?.toString(16).padStart(4, '0')}:${clusterName} on endpoint ${or}${endpoint.id}${er}:${or}${endpoint.number}${er}`);
403
+ return undefined;
404
+ }
405
+ let value = state[clusterName][attribute];
406
+ if (typeof value === 'object')
407
+ value = deepCopy(value);
408
+ log?.info(`${db}Get endpoint ${or}${endpoint.id}${db}:${or}${endpoint.number}${db} attribute ${hk}${capitalizeFirstLetter(clusterName)}${db}.${hk}${attribute}${db} value ${YELLOW}${value !== null && typeof value === 'object' ? debugStringify(value) : value}${db}`);
409
+ return value;
410
+ }
411
+ export async function setAttribute(endpoint, cluster, attribute, value, log) {
412
+ const clusterName = getBehavior(endpoint, cluster)?.id;
413
+ if (!clusterName) {
414
+ endpoint.log.error(`setAttribute ${hk}${attribute}${er} error: cluster not found on endpoint ${or}${endpoint.maybeId}${er}:${or}${endpoint.maybeNumber}${er}`);
415
+ return false;
416
+ }
417
+ if (endpoint.construction.status !== Lifecycle.Status.Active) {
418
+ endpoint.log.error(`setAttribute ${hk}${clusterName}.${attribute}${er} error: Endpoint ${or}${endpoint.maybeId}${er}:${or}${endpoint.maybeNumber}${er} is in the ${BLUE}${endpoint.construction.status}${er} state`);
419
+ return false;
420
+ }
421
+ const state = endpoint.state;
422
+ attribute = lowercaseFirstLetter(attribute);
423
+ if (!(attribute in state[clusterName])) {
424
+ endpoint.log.error(`setAttribute error: Attribute ${hk}${attribute}${er} not found on cluster ${'0x' + getClusterId(endpoint, clusterName)?.toString(16).padStart(4, '0')}:${clusterName} on endpoint ${or}${endpoint.id}${er}:${or}${endpoint.number}${er}`);
425
+ return false;
426
+ }
427
+ let oldValue = state[clusterName][attribute];
428
+ if (typeof oldValue === 'object')
429
+ oldValue = deepCopy(oldValue);
430
+ await endpoint.setStateOf(endpoint.behaviors.supported[clusterName], { [attribute]: value });
431
+ log?.info(`${db}Set endpoint ${or}${endpoint.id}${db}:${or}${endpoint.number}${db} attribute ${hk}${capitalizeFirstLetter(clusterName)}${db}.${hk}${attribute}${db} ` +
432
+ `from ${YELLOW}${oldValue !== null && typeof oldValue === 'object' ? debugStringify(oldValue) : oldValue}${db} ` +
433
+ `to ${YELLOW}${value !== null && typeof value === 'object' ? debugStringify(value) : value}${db}`);
434
+ return true;
435
+ }
436
+ export async function updateAttribute(endpoint, cluster, attribute, value, log) {
437
+ const clusterName = getBehavior(endpoint, cluster)?.id;
438
+ if (!clusterName) {
439
+ endpoint.log.error(`updateAttribute ${hk}${attribute}${er} error: cluster not found on endpoint ${or}${endpoint.maybeId}${er}:${or}${endpoint.maybeNumber}${er}`);
440
+ return false;
441
+ }
442
+ if (endpoint.construction.status !== Lifecycle.Status.Active) {
443
+ endpoint.log.error(`updateAttribute ${hk}${clusterName}.${attribute}${er} error: Endpoint ${or}${endpoint.maybeId}${er}:${or}${endpoint.maybeNumber}${er} is in the ${BLUE}${endpoint.construction.status}${er} state`);
444
+ return false;
445
+ }
446
+ const state = endpoint.state;
447
+ attribute = lowercaseFirstLetter(attribute);
448
+ if (!(attribute in state[clusterName])) {
449
+ endpoint.log.error(`updateAttribute error: Attribute ${hk}${attribute}${er} not found on cluster ${'0x' + getClusterId(endpoint, clusterName)?.toString(16).padStart(4, '0')}:${clusterName} on endpoint ${or}${endpoint.id}${er}:${or}${endpoint.number}${er}`);
450
+ return false;
451
+ }
452
+ let oldValue = state[clusterName][attribute];
453
+ if (typeof oldValue === 'object') {
454
+ if (deepEqual(oldValue, value))
455
+ return false;
456
+ oldValue = deepCopy(oldValue);
457
+ }
458
+ else if (oldValue === value)
459
+ return false;
460
+ await endpoint.setStateOf(endpoint.behaviors.supported[clusterName], { [attribute]: value });
461
+ log?.info(`${db}Update endpoint ${or}${endpoint.id}${db}:${or}${endpoint.number}${db} attribute ${hk}${capitalizeFirstLetter(clusterName)}${db}.${hk}${attribute}${db} ` +
462
+ `from ${YELLOW}${oldValue !== null && typeof oldValue === 'object' ? debugStringify(oldValue) : oldValue}${db} ` +
463
+ `to ${YELLOW}${value !== null && typeof value === 'object' ? debugStringify(value) : value}${db}`);
464
+ return true;
465
+ }
466
+ export function getDefaultTemperatureMeasurementClusterServer(measuredValue = 0) {
467
+ return optionsFor(TemperatureMeasurementServer, {
468
+ measuredValue,
469
+ minMeasuredValue: null,
470
+ maxMeasuredValue: null,
471
+ tolerance: 0,
472
+ });
473
+ }
474
+ export function getDefaultRelativeHumidityMeasurementClusterServer(measuredValue = 0) {
475
+ return optionsFor(RelativeHumidityMeasurementServer, {
476
+ measuredValue,
477
+ minMeasuredValue: null,
478
+ maxMeasuredValue: null,
479
+ tolerance: 0,
480
+ });
481
+ }
482
+ export function getDefaultPressureMeasurementClusterServer(measuredValue = 1000) {
483
+ return optionsFor(PressureMeasurementServer, {
484
+ measuredValue,
485
+ minMeasuredValue: null,
486
+ maxMeasuredValue: null,
487
+ tolerance: 0,
488
+ });
489
+ }
490
+ export function getDefaultIlluminanceMeasurementClusterServer(measuredValue = 0) {
491
+ return optionsFor(IlluminanceMeasurementServer, {
492
+ measuredValue,
493
+ minMeasuredValue: null,
494
+ maxMeasuredValue: null,
495
+ tolerance: 0,
496
+ });
497
+ }
498
+ export function getDefaultFlowMeasurementClusterServer(measuredValue = 0) {
499
+ return optionsFor(FlowMeasurementServer, {
500
+ measuredValue,
501
+ minMeasuredValue: null,
502
+ maxMeasuredValue: null,
503
+ tolerance: 0,
504
+ });
505
+ }
506
+ export function getDefaultOccupancySensingClusterServer(occupied = false) {
507
+ return optionsFor(OccupancySensingServer, {
508
+ occupancy: { occupied },
509
+ occupancySensorType: OccupancySensing.OccupancySensorType.Pir,
510
+ occupancySensorTypeBitmap: { pir: true, ultrasonic: false, physicalContact: false },
511
+ pirOccupiedToUnoccupiedDelay: 30,
512
+ });
513
+ }