matterbridge 2.1.0-dev.3 → 2.1.0-dev.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -7
- package/dist/frontend.js +82 -73
- package/dist/matter/export.js +6 -5
- package/dist/matterbridgeEndpoint.js +45 -396
- package/dist/matterbridgeEndpointHelpers.js +513 -0
- package/npm-shrinkwrap.json +5 -12
- package/package.json +1 -1
|
@@ -1,18 +1,14 @@
|
|
|
1
|
-
import { createHash } from 'crypto';
|
|
2
1
|
import { AnsiLogger, BLUE, CYAN, YELLOW, db, debugStringify, er, hk, or, zb } from './logger/export.js';
|
|
3
2
|
import { bridgedNode } from './matterbridgeDeviceTypes.js';
|
|
4
|
-
import {
|
|
3
|
+
import { isValidNumber, isValidObject } from './utils/utils.js';
|
|
5
4
|
import { MatterbridgeBehavior, MatterbridgeBehaviorDevice, MatterbridgeIdentifyServer, MatterbridgeOnOffServer, MatterbridgeLevelControlServer, MatterbridgeColorControlServer, MatterbridgeWindowCoveringServer, MatterbridgeThermostatServer, MatterbridgeFanControlServer, MatterbridgeDoorLockServer, MatterbridgeModeSelectServer, MatterbridgeValveConfigurationAndControlServer, MatterbridgeSmokeCoAlarmServer, MatterbridgeBooleanStateConfigurationServer, } from './matterbridgeBehaviors.js';
|
|
5
|
+
import { addClusterServers, addFixedLabel, addOptionalClusterServers, addRequiredClusterServers, addUserLabel, capitalizeFirstLetter, createUniqueId, getBehavior, getBehaviourTypesFromClusterClientIds, getBehaviourTypesFromClusterServerIds, getDefaultFlowMeasurementClusterServer, getDefaultIlluminanceMeasurementClusterServer, getDefaultPressureMeasurementClusterServer, getDefaultRelativeHumidityMeasurementClusterServer, getDefaultTemperatureMeasurementClusterServer, getDefaultOccupancySensingClusterServer, lowercaseFirstLetter, updateAttribute, getClusterId, getAttributeId, setAttribute, getAttribute, } from './matterbridgeEndpointHelpers.js';
|
|
6
6
|
import { Endpoint, Lifecycle, MutableEndpoint, NamedHandler, SupportedBehaviors, VendorId } from '@matter/main';
|
|
7
7
|
import { getClusterNameById, MeasurementType } from '@matter/main/types';
|
|
8
8
|
import { Descriptor } from '@matter/main/clusters/descriptor';
|
|
9
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
10
|
import { BridgedDeviceBasicInformation } from '@matter/main/clusters/bridged-device-basic-information';
|
|
14
11
|
import { Identify } from '@matter/main/clusters/identify';
|
|
15
|
-
import { Groups } from '@matter/main/clusters/groups';
|
|
16
12
|
import { OnOff } from '@matter/main/clusters/on-off';
|
|
17
13
|
import { LevelControl } from '@matter/main/clusters/level-control';
|
|
18
14
|
import { ColorControl } from '@matter/main/clusters/color-control';
|
|
@@ -20,39 +16,18 @@ import { WindowCovering } from '@matter/main/clusters/window-covering';
|
|
|
20
16
|
import { Thermostat } from '@matter/main/clusters/thermostat';
|
|
21
17
|
import { FanControl } from '@matter/main/clusters/fan-control';
|
|
22
18
|
import { DoorLock } from '@matter/main/clusters/door-lock';
|
|
23
|
-
import { ModeSelect } from '@matter/main/clusters/mode-select';
|
|
24
19
|
import { ValveConfigurationAndControl } from '@matter/main/clusters/valve-configuration-and-control';
|
|
25
20
|
import { PumpConfigurationAndControl } from '@matter/main/clusters/pump-configuration-and-control';
|
|
26
21
|
import { SmokeCoAlarm } from '@matter/main/clusters/smoke-co-alarm';
|
|
27
22
|
import { Switch } from '@matter/main/clusters/switch';
|
|
28
|
-
import { BooleanState } from '@matter/main/clusters/boolean-state';
|
|
29
23
|
import { BooleanStateConfiguration } from '@matter/main/clusters/boolean-state-configuration';
|
|
30
24
|
import { PowerTopology } from '@matter/main/clusters/power-topology';
|
|
31
25
|
import { ElectricalPowerMeasurement } from '@matter/main/clusters/electrical-power-measurement';
|
|
32
26
|
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
27
|
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
28
|
import { ConcentrationMeasurement } from '@matter/main/clusters/concentration-measurement';
|
|
51
29
|
import { DescriptorServer } from '@matter/main/behaviors/descriptor';
|
|
52
30
|
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
31
|
import { BridgedDeviceBasicInformationServer } from '@matter/main/behaviors/bridged-device-basic-information';
|
|
57
32
|
import { GroupsServer } from '@matter/main/behaviors/groups';
|
|
58
33
|
import { ScenesManagementServer } from '@matter/main/behaviors/scenes-management';
|
|
@@ -79,242 +54,6 @@ import { Pm25ConcentrationMeasurementServer } from '@matter/main/behaviors/pm25-
|
|
|
79
54
|
import { Pm10ConcentrationMeasurementServer } from '@matter/main/behaviors/pm10-concentration-measurement';
|
|
80
55
|
import { RadonConcentrationMeasurementServer } from '@matter/main/behaviors/radon-concentration-measurement';
|
|
81
56
|
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
|
-
Array.from(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
|
-
Array.from(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
|
-
}
|
|
318
57
|
export class MatterbridgeEndpoint extends Endpoint {
|
|
319
58
|
static bridgeMode = '';
|
|
320
59
|
static logLevel = "info";
|
|
@@ -337,7 +76,6 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
337
76
|
deviceType;
|
|
338
77
|
uniqueStorageKey = undefined;
|
|
339
78
|
tagList = undefined;
|
|
340
|
-
subType = '';
|
|
341
79
|
deviceTypes = new Map();
|
|
342
80
|
commandHandler = new NamedHandler();
|
|
343
81
|
constructor(definition, options = {}, debug = false) {
|
|
@@ -412,7 +150,8 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
412
150
|
if (!behavior || !this.behaviors.supported[behavior.id])
|
|
413
151
|
return false;
|
|
414
152
|
const options = this.behaviors.optionsFor(behavior);
|
|
415
|
-
|
|
153
|
+
const defaults = this.behaviors.defaultsFor(behavior);
|
|
154
|
+
return lowercaseFirstLetter(attribute) in options || lowercaseFirstLetter(attribute) in defaults;
|
|
416
155
|
}
|
|
417
156
|
getClusterServerOptions(cluster) {
|
|
418
157
|
const behavior = getBehavior(this, cluster);
|
|
@@ -420,50 +159,14 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
420
159
|
return undefined;
|
|
421
160
|
return this.behaviors.optionsFor(behavior);
|
|
422
161
|
}
|
|
423
|
-
getAttribute(
|
|
424
|
-
|
|
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;
|
|
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;
|
|
162
|
+
getAttribute(cluster, attribute, log) {
|
|
163
|
+
return getAttribute(this, cluster, attribute, log);
|
|
442
164
|
}
|
|
443
165
|
async setAttribute(clusterId, attribute, value, log) {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
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;
|
|
166
|
+
return await setAttribute(this, clusterId, attribute, value, log);
|
|
167
|
+
}
|
|
168
|
+
async updateAttribute(cluster, attribute, value, log) {
|
|
169
|
+
return await updateAttribute(this, cluster, attribute, value, log);
|
|
467
170
|
}
|
|
468
171
|
async subscribeAttribute(clusterId, attribute, listener, log) {
|
|
469
172
|
const clusterName = lowercaseFirstLetter(getClusterNameById(clusterId));
|
|
@@ -484,52 +187,30 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
484
187
|
log?.info(`${db}Subscribed endpoint ${or}${this.id}${db}:${or}${this.number}${db} attribute ${hk}${capitalizeFirstLetter(clusterName)}${db}.${hk}${attribute}${db}`);
|
|
485
188
|
return true;
|
|
486
189
|
}
|
|
487
|
-
async triggerEvent(clusterId, event, payload, log
|
|
488
|
-
if (!endpoint)
|
|
489
|
-
endpoint = this;
|
|
190
|
+
async triggerEvent(clusterId, event, payload, log) {
|
|
490
191
|
const clusterName = lowercaseFirstLetter(getClusterNameById(clusterId));
|
|
491
|
-
if (
|
|
492
|
-
this.log.error(`triggerEvent ${hk}${clusterName}.${event}${er} error: Endpoint ${or}${
|
|
192
|
+
if (this.construction.status !== Lifecycle.Status.Active) {
|
|
193
|
+
this.log.error(`triggerEvent ${hk}${clusterName}.${event}${er} error: Endpoint ${or}${this.maybeId}${er}:${or}${this.maybeNumber}${er} is in the ${BLUE}${this.construction.status}${er} state`);
|
|
493
194
|
return false;
|
|
494
195
|
}
|
|
495
|
-
const events =
|
|
196
|
+
const events = this.events;
|
|
496
197
|
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}${
|
|
198
|
+
this.log.error(`triggerEvent ${hk}${event}${er} error: Cluster ${'0x' + clusterId.toString(16).padStart(4, '0')}:${clusterName} not found on endpoint ${or}${this.id}${er}:${or}${this.number}${er}`);
|
|
498
199
|
return false;
|
|
499
200
|
}
|
|
500
|
-
await
|
|
501
|
-
log?.info(`${db}Trigger event ${hk}${capitalizeFirstLetter(clusterName)}${db}.${hk}${event}${db} with ${debugStringify(payload)}${db} on endpoint ${or}${
|
|
201
|
+
await this.act((agent) => agent[clusterName].events[event].emit(payload, agent.context));
|
|
202
|
+
log?.info(`${db}Trigger event ${hk}${capitalizeFirstLetter(clusterName)}${db}.${hk}${event}${db} with ${debugStringify(payload)}${db} on endpoint ${or}${this.id}${db}:${or}${this.number}${db} `);
|
|
502
203
|
return true;
|
|
503
204
|
}
|
|
504
205
|
addClusterServers(serverList) {
|
|
505
206
|
addClusterServers(this, serverList);
|
|
506
207
|
}
|
|
507
208
|
async addFixedLabel(label, value) {
|
|
508
|
-
|
|
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 }],
|
|
512
|
-
});
|
|
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);
|
|
209
|
+
await addFixedLabel(this, label, value);
|
|
519
210
|
return this;
|
|
520
211
|
}
|
|
521
212
|
async addUserLabel(label, value) {
|
|
522
|
-
|
|
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 }],
|
|
526
|
-
});
|
|
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);
|
|
213
|
+
await addUserLabel(this, label, value);
|
|
533
214
|
return this;
|
|
534
215
|
}
|
|
535
216
|
addCommandHandler(command, handler) {
|
|
@@ -553,6 +234,21 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
553
234
|
getAllClusterServerNames() {
|
|
554
235
|
return Object.keys(this.behaviors.supported);
|
|
555
236
|
}
|
|
237
|
+
forEachAttribute(callback) {
|
|
238
|
+
for (const [clusterName, clusterAttributes] of Object.entries(this.state)) {
|
|
239
|
+
for (const [attributeName, attributeValue] of Object.entries(clusterAttributes)) {
|
|
240
|
+
const clusterId = getClusterId(this, clusterName);
|
|
241
|
+
if (clusterId === undefined) {
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
const attributeId = getAttributeId(this, clusterName, attributeName);
|
|
245
|
+
if (attributeId === undefined) {
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
callback(clusterName, clusterId, attributeName, attributeId, attributeValue);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
556
252
|
addChildDeviceType(endpointName, definition, options = {}, debug = false) {
|
|
557
253
|
this.log.debug(`addChildDeviceType: ${CYAN}${endpointName}${db}`);
|
|
558
254
|
let alreadyAdded = false;
|
|
@@ -943,7 +639,6 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
943
639
|
await this.setAttribute(ColorControl.Cluster.id, 'colorMode', colorMode, this.log);
|
|
944
640
|
await this.setAttribute(ColorControl.Cluster.id, 'enhancedColorMode', colorMode, this.log);
|
|
945
641
|
}
|
|
946
|
-
return this;
|
|
947
642
|
}
|
|
948
643
|
createDefaultWindowCoveringClusterServer(positionPercent100ths) {
|
|
949
644
|
this.behaviors.require(MatterbridgeWindowCoveringServer.with(WindowCovering.Feature.Lift, WindowCovering.Feature.PositionAwareLift), {
|
|
@@ -967,7 +662,7 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
967
662
|
}
|
|
968
663
|
async setWindowCoveringTargetAsCurrentAndStopped() {
|
|
969
664
|
const position = this.getAttribute(WindowCovering.Cluster.id, 'currentPositionLiftPercent100ths', this.log);
|
|
970
|
-
if (position
|
|
665
|
+
if (isValidNumber(position, 0, 10000)) {
|
|
971
666
|
await this.setAttribute(WindowCovering.Cluster.id, 'targetPositionLiftPercent100ths', position, this.log);
|
|
972
667
|
await this.setAttribute(WindowCovering.Cluster.id, 'operationalStatus', {
|
|
973
668
|
global: WindowCovering.MovementStatus.Stopped,
|
|
@@ -997,8 +692,10 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
997
692
|
}
|
|
998
693
|
getWindowCoveringStatus() {
|
|
999
694
|
const status = this.getAttribute(WindowCovering.Cluster.id, 'operationalStatus', this.log);
|
|
1000
|
-
|
|
1001
|
-
|
|
695
|
+
if (isValidObject(status, 3) && 'global' in status && typeof status.global === 'number') {
|
|
696
|
+
this.log.debug(`Get WindowCovering operationalStatus: ${status.global}`);
|
|
697
|
+
return status.global;
|
|
698
|
+
}
|
|
1002
699
|
}
|
|
1003
700
|
async setWindowCoveringTargetAndCurrentPosition(position) {
|
|
1004
701
|
await this.setAttribute(WindowCovering.Cluster.id, 'currentPositionLiftPercent100ths', position, this.log);
|
|
@@ -1286,76 +983,28 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1286
983
|
});
|
|
1287
984
|
return this;
|
|
1288
985
|
}
|
|
1289
|
-
getDefaultTemperatureMeasurementClusterServer(measuredValue = 0) {
|
|
1290
|
-
return optionsFor(TemperatureMeasurementServer, {
|
|
1291
|
-
measuredValue,
|
|
1292
|
-
minMeasuredValue: null,
|
|
1293
|
-
maxMeasuredValue: null,
|
|
1294
|
-
tolerance: 0,
|
|
1295
|
-
});
|
|
1296
|
-
}
|
|
1297
986
|
createDefaultTemperatureMeasurementClusterServer(measuredValue = 0) {
|
|
1298
|
-
this.behaviors.require(TemperatureMeasurementServer,
|
|
987
|
+
this.behaviors.require(TemperatureMeasurementServer, getDefaultTemperatureMeasurementClusterServer(measuredValue));
|
|
1299
988
|
return this;
|
|
1300
989
|
}
|
|
1301
|
-
getDefaultRelativeHumidityMeasurementClusterServer(measuredValue = 0) {
|
|
1302
|
-
return optionsFor(RelativeHumidityMeasurementServer, {
|
|
1303
|
-
measuredValue,
|
|
1304
|
-
minMeasuredValue: null,
|
|
1305
|
-
maxMeasuredValue: null,
|
|
1306
|
-
tolerance: 0,
|
|
1307
|
-
});
|
|
1308
|
-
}
|
|
1309
990
|
createDefaultRelativeHumidityMeasurementClusterServer(measuredValue = 0) {
|
|
1310
|
-
this.behaviors.require(RelativeHumidityMeasurementServer,
|
|
991
|
+
this.behaviors.require(RelativeHumidityMeasurementServer, getDefaultRelativeHumidityMeasurementClusterServer(measuredValue));
|
|
1311
992
|
return this;
|
|
1312
993
|
}
|
|
1313
|
-
getDefaultPressureMeasurementClusterServer(measuredValue = 1000) {
|
|
1314
|
-
return optionsFor(PressureMeasurementServer, {
|
|
1315
|
-
measuredValue,
|
|
1316
|
-
minMeasuredValue: null,
|
|
1317
|
-
maxMeasuredValue: null,
|
|
1318
|
-
tolerance: 0,
|
|
1319
|
-
});
|
|
1320
|
-
}
|
|
1321
994
|
createDefaultPressureMeasurementClusterServer(measuredValue = 1000) {
|
|
1322
|
-
this.behaviors.require(PressureMeasurementServer,
|
|
995
|
+
this.behaviors.require(PressureMeasurementServer, getDefaultPressureMeasurementClusterServer(measuredValue));
|
|
1323
996
|
return this;
|
|
1324
997
|
}
|
|
1325
|
-
getDefaultIlluminanceMeasurementClusterServer(measuredValue = 0) {
|
|
1326
|
-
return optionsFor(IlluminanceMeasurementServer, {
|
|
1327
|
-
measuredValue,
|
|
1328
|
-
minMeasuredValue: null,
|
|
1329
|
-
maxMeasuredValue: null,
|
|
1330
|
-
tolerance: 0,
|
|
1331
|
-
});
|
|
1332
|
-
}
|
|
1333
998
|
createDefaultIlluminanceMeasurementClusterServer(measuredValue = 0) {
|
|
1334
|
-
this.behaviors.require(IlluminanceMeasurementServer,
|
|
999
|
+
this.behaviors.require(IlluminanceMeasurementServer, getDefaultIlluminanceMeasurementClusterServer(measuredValue));
|
|
1335
1000
|
return this;
|
|
1336
1001
|
}
|
|
1337
|
-
getDefaultFlowMeasurementClusterServer(measuredValue = 0) {
|
|
1338
|
-
return optionsFor(FlowMeasurementServer, {
|
|
1339
|
-
measuredValue,
|
|
1340
|
-
minMeasuredValue: null,
|
|
1341
|
-
maxMeasuredValue: null,
|
|
1342
|
-
tolerance: 0,
|
|
1343
|
-
});
|
|
1344
|
-
}
|
|
1345
1002
|
createDefaultFlowMeasurementClusterServer(measuredValue = 0) {
|
|
1346
|
-
this.behaviors.require(FlowMeasurementServer,
|
|
1003
|
+
this.behaviors.require(FlowMeasurementServer, getDefaultFlowMeasurementClusterServer(measuredValue));
|
|
1347
1004
|
return this;
|
|
1348
1005
|
}
|
|
1349
|
-
getDefaultOccupancySensingClusterServer(occupied = false) {
|
|
1350
|
-
return optionsFor(OccupancySensingServer, {
|
|
1351
|
-
occupancy: { occupied },
|
|
1352
|
-
occupancySensorType: OccupancySensing.OccupancySensorType.Pir,
|
|
1353
|
-
occupancySensorTypeBitmap: { pir: true, ultrasonic: false, physicalContact: false },
|
|
1354
|
-
pirOccupiedToUnoccupiedDelay: 30,
|
|
1355
|
-
});
|
|
1356
|
-
}
|
|
1357
1006
|
createDefaultOccupancySensingClusterServer(occupied = false) {
|
|
1358
|
-
this.behaviors.require(OccupancySensingServer,
|
|
1007
|
+
this.behaviors.require(OccupancySensingServer, getDefaultOccupancySensingClusterServer(occupied));
|
|
1359
1008
|
return this;
|
|
1360
1009
|
}
|
|
1361
1010
|
createDefaultAirQualityClusterServer(airQuality = AirQuality.AirQualityEnum.Unknown) {
|