matterbridge 1.6.1 → 1.6.3-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.
- package/CHANGELOG.md +45 -1
- package/README-DEV.md +0 -4
- package/README-NGINX.md +63 -0
- package/README.md +7 -3
- package/dist/cli.js +15 -7
- package/dist/cli.js.map +1 -1
- package/dist/deviceManager.d.ts +1 -1
- package/dist/deviceManager.d.ts.map +1 -1
- package/dist/deviceManager.js +1 -1
- package/dist/deviceManager.js.map +1 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -10
- package/dist/index.js.map +1 -1
- package/dist/matter/export.d.ts +5 -0
- package/dist/matter/export.d.ts.map +1 -0
- package/dist/matter/export.js +5 -0
- package/dist/matter/export.js.map +1 -0
- package/dist/matterbridge.d.ts +12 -7
- package/dist/matterbridge.d.ts.map +1 -1
- package/dist/matterbridge.js +133 -83
- package/dist/matterbridge.js.map +1 -1
- package/dist/matterbridgeAccessoryPlatform.d.ts.map +1 -1
- package/dist/matterbridgeAccessoryPlatform.js.map +1 -1
- package/dist/matterbridgeBehaviors.d.ts +1123 -0
- package/dist/matterbridgeBehaviors.d.ts.map +1 -0
- package/dist/matterbridgeBehaviors.js +281 -0
- package/dist/matterbridgeBehaviors.js.map +1 -0
- package/dist/matterbridgeDevice.d.ts +2089 -1511
- package/dist/matterbridgeDevice.d.ts.map +1 -1
- package/dist/matterbridgeDevice.js +243 -209
- package/dist/matterbridgeDevice.js.map +1 -1
- package/dist/matterbridgeDeviceTypes.d.ts +65 -0
- package/dist/matterbridgeDeviceTypes.d.ts.map +1 -0
- package/dist/matterbridgeDeviceTypes.js +307 -0
- package/dist/matterbridgeDeviceTypes.js.map +1 -0
- package/dist/matterbridgeDynamicPlatform.d.ts.map +1 -1
- package/dist/matterbridgeDynamicPlatform.js.map +1 -1
- package/dist/matterbridgeEdge.d.ts +19 -20
- package/dist/matterbridgeEdge.d.ts.map +1 -1
- package/dist/matterbridgeEdge.js +505 -102
- package/dist/matterbridgeEdge.js.map +1 -1
- package/dist/matterbridgeEndpoint.d.ts +3554 -2297
- package/dist/matterbridgeEndpoint.d.ts.map +1 -1
- package/dist/matterbridgeEndpoint.js +709 -476
- package/dist/matterbridgeEndpoint.js.map +1 -1
- package/dist/matterbridgePlatform.d.ts +4 -3
- package/dist/matterbridgePlatform.d.ts.map +1 -1
- package/dist/matterbridgePlatform.js +10 -2
- package/dist/matterbridgePlatform.js.map +1 -1
- package/dist/matterbridgeTypes.d.ts +7 -8
- package/dist/matterbridgeTypes.d.ts.map +1 -1
- package/dist/matterbridgeTypes.js.map +1 -1
- package/dist/matterbridgeWebsocket.d.ts +1 -1
- package/dist/matterbridgeWebsocket.d.ts.map +1 -1
- package/dist/matterbridgeWebsocket.js +5 -3
- package/dist/matterbridgeWebsocket.js.map +1 -1
- package/dist/pluginManager.d.ts.map +1 -1
- package/dist/pluginManager.js +16 -7
- package/dist/pluginManager.js.map +1 -1
- package/dist/utils/colorUtils.js +1 -1
- package/dist/utils/colorUtils.js.map +1 -1
- package/dist/utils/utils.d.ts +21 -0
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +49 -3
- package/dist/utils/utils.js.map +1 -1
- package/frontend/build/asset-manifest.json +62 -6
- package/frontend/build/index.html +1 -1
- package/frontend/build/static/css/main.823e08b6.css +2 -0
- package/frontend/build/static/css/main.823e08b6.css.map +1 -0
- package/frontend/build/static/js/main.a14c87e7.js +115 -0
- package/frontend/build/static/js/{main.045d08f7.js.LICENSE.txt → main.a14c87e7.js.LICENSE.txt} +3 -3
- package/frontend/build/static/js/main.a14c87e7.js.map +1 -0
- package/frontend/build/static/media/roboto-cyrillic-300-normal.1b79538ccd585c259996.woff2 +0 -0
- package/frontend/build/static/media/roboto-cyrillic-300-normal.5f077fd7b977d1715acf.woff +0 -0
- package/frontend/build/static/media/roboto-cyrillic-400-normal.5d2930082227d172f62c.woff +0 -0
- package/frontend/build/static/media/roboto-cyrillic-400-normal.a9e19870cf6c4b973427.woff2 +0 -0
- package/frontend/build/static/media/roboto-cyrillic-500-normal.0ae2428323939af5e1ad.woff2 +0 -0
- package/frontend/build/static/media/roboto-cyrillic-500-normal.dd7bc8a52c6c70c5a3f5.woff +0 -0
- package/frontend/build/static/media/roboto-cyrillic-700-normal.3f6e1548bd5175a8c342.woff +0 -0
- package/frontend/build/static/media/roboto-cyrillic-700-normal.4fdfc29a10e7d4b7c527.woff2 +0 -0
- package/frontend/build/static/media/roboto-cyrillic-ext-300-normal.795dbc8140e3fef82983.woff +0 -0
- package/frontend/build/static/media/roboto-cyrillic-ext-300-normal.80947a31d23c70204b47.woff2 +0 -0
- package/frontend/build/static/media/roboto-cyrillic-ext-400-normal.135d076fa32aa0b4d105.woff +0 -0
- package/frontend/build/static/media/roboto-cyrillic-ext-400-normal.5cec61a21cc20180fbe1.woff2 +0 -0
- package/frontend/build/static/media/roboto-cyrillic-ext-500-normal.6de16332fda843a3dc3d.woff2 +0 -0
- package/frontend/build/static/media/roboto-cyrillic-ext-500-normal.c0a0638f90b31d6454ba.woff +0 -0
- package/frontend/build/static/media/roboto-cyrillic-ext-700-normal.4750292c47fa2bc6ac1a.woff2 +0 -0
- package/frontend/build/static/media/roboto-cyrillic-ext-700-normal.ca247189fc12d00de361.woff +0 -0
- package/frontend/build/static/media/roboto-greek-300-normal.285f3e6261d8eb20417d.woff2 +0 -0
- package/frontend/build/static/media/roboto-greek-300-normal.889beddda1c9bd9f97df.woff +0 -0
- package/frontend/build/static/media/roboto-greek-400-normal.160a791a8e4f46bca3cc.woff +0 -0
- package/frontend/build/static/media/roboto-greek-400-normal.2c32b1315be61477013a.woff2 +0 -0
- package/frontend/build/static/media/roboto-greek-500-normal.60810e07c7b0273013aa.woff +0 -0
- package/frontend/build/static/media/roboto-greek-500-normal.f95e757c5483310f9c11.woff2 +0 -0
- package/frontend/build/static/media/roboto-greek-700-normal.77dd370f2001e184ba0d.woff2 +0 -0
- package/frontend/build/static/media/roboto-greek-700-normal.df87b053fae3d7ad5f7a.woff +0 -0
- package/frontend/build/static/media/roboto-greek-ext-300-normal.b590dbe5c639944366d1.woff +0 -0
- package/frontend/build/static/media/roboto-greek-ext-300-normal.d6049cb54aa6fbe14c42.woff2 +0 -0
- package/frontend/build/static/media/roboto-greek-ext-400-normal.16eb83b4a3b1ea994243.woff +0 -0
- package/frontend/build/static/media/roboto-greek-ext-400-normal.1df4abad55796d11a0c8.woff2 +0 -0
- package/frontend/build/static/media/roboto-greek-ext-500-normal.4a96ba31abcce0f5d52b.woff2 +0 -0
- package/frontend/build/static/media/roboto-greek-ext-500-normal.fd28d9c008bf3af1bed7.woff +0 -0
- package/frontend/build/static/media/roboto-greek-ext-700-normal.2dd6febad11502dec6a6.woff2 +0 -0
- package/frontend/build/static/media/roboto-greek-ext-700-normal.4abdc9fff4507f17d726.woff +0 -0
- package/frontend/build/static/media/roboto-latin-300-normal.b850f1ff581ea232fac9.woff2 +0 -0
- package/frontend/build/static/media/roboto-latin-300-normal.c4bc0593c9954d79cb3a.woff +0 -0
- package/frontend/build/static/media/roboto-latin-400-normal.047a7839f69b209db815.woff +0 -0
- package/frontend/build/static/media/roboto-latin-400-normal.297d48e1b5a10c0831a9.woff2 +0 -0
- package/frontend/build/static/media/roboto-latin-500-normal.68d40d6d01c6f85d24ba.woff +0 -0
- package/frontend/build/static/media/roboto-latin-500-normal.7077203b1982951ecf76.woff2 +0 -0
- package/frontend/build/static/media/roboto-latin-700-normal.4535474e1cf8598695ad.woff2 +0 -0
- package/frontend/build/static/media/roboto-latin-700-normal.9f6a16a7770c87b2042b.woff +0 -0
- package/frontend/build/static/media/roboto-latin-ext-300-normal.14982a9e4857a93b6dce.woff +0 -0
- package/frontend/build/static/media/roboto-latin-ext-300-normal.97cbc447d4a8d41a9543.woff2 +0 -0
- package/frontend/build/static/media/roboto-latin-ext-400-normal.27da5b36b6d3a16f53f4.woff +0 -0
- package/frontend/build/static/media/roboto-latin-ext-400-normal.2eeae187764baf05867d.woff2 +0 -0
- package/frontend/build/static/media/roboto-latin-ext-500-normal.06c30711d588145a4541.woff +0 -0
- package/frontend/build/static/media/roboto-latin-ext-500-normal.9a18d7bb9ff7a6af7b32.woff2 +0 -0
- package/frontend/build/static/media/roboto-latin-ext-700-normal.18841836e391d39e83a8.woff2 +0 -0
- package/frontend/build/static/media/roboto-latin-ext-700-normal.3c5bcdd0e69c4c3ffafe.woff +0 -0
- package/frontend/build/static/media/roboto-vietnamese-300-normal.c96b16e5c05c7b7c3e89.woff2 +0 -0
- package/frontend/build/static/media/roboto-vietnamese-300-normal.f5e7cea32756dfe7af40.woff +0 -0
- package/frontend/build/static/media/roboto-vietnamese-400-normal.0dc97c66f9b542d6fa17.woff +0 -0
- package/frontend/build/static/media/roboto-vietnamese-400-normal.d3f8e26d6c27de8102b6.woff2 +0 -0
- package/frontend/build/static/media/roboto-vietnamese-500-normal.090fabef926bdc0e9b9f.woff2 +0 -0
- package/frontend/build/static/media/roboto-vietnamese-500-normal.23b7b8a2524d2d4b637b.woff +0 -0
- package/frontend/build/static/media/roboto-vietnamese-700-normal.0a79a9fabfc32e33f360.woff2 +0 -0
- package/frontend/build/static/media/roboto-vietnamese-700-normal.35ed0597568ff6f19c16.woff +0 -0
- package/npm-shrinkwrap.json +117 -36
- package/package.json +8 -3
- package/dist/matterbridgeController.d.ts +0 -24
- package/dist/matterbridgeController.d.ts.map +0 -1
- package/dist/matterbridgeController.js +0 -386
- package/dist/matterbridgeController.js.map +0 -1
- package/frontend/build/static/css/main.1cf003ae.css +0 -2
- package/frontend/build/static/css/main.1cf003ae.css.map +0 -1
- package/frontend/build/static/js/main.045d08f7.js +0 -3
- package/frontend/build/static/js/main.045d08f7.js.map +0 -1
|
@@ -21,81 +21,122 @@
|
|
|
21
21
|
* limitations under the License. *
|
|
22
22
|
*/
|
|
23
23
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
24
|
-
//
|
|
25
|
-
import { Endpoint } from '@project-chip/matter.js/endpoint';
|
|
26
|
-
import { MutableEndpoint } from '@project-chip/matter.js/endpoint/type';
|
|
27
|
-
import { SupportedBehaviors } from '@project-chip/matter.js/endpoint/properties';
|
|
28
|
-
import { DescriptorServer } from '@project-chip/matter.js/behavior/definitions/descriptor';
|
|
29
|
-
import { IdentifyServer } from '@project-chip/matter.js/behavior/definitions/identify';
|
|
30
|
-
import { GroupsServer } from '@project-chip/matter.js/behavior/definitions/groups';
|
|
31
|
-
// import { ScenesServer, ScenesBehavior } from '@project-chip/matter.js/behavior/definitions/scenes';
|
|
32
|
-
import { OnOffServer } from '@project-chip/matter.js/behavior/definitions/on-off';
|
|
33
|
-
import { TemperatureMeasurementServer } from '@project-chip/matter.js/behavior/definitions/temperature-measurement';
|
|
34
|
-
import { RelativeHumidityMeasurementServer } from '@project-chip/matter.js/behavior/definitions/relative-humidity-measurement';
|
|
35
|
-
import { PressureMeasurementServer } from '@project-chip/matter.js/behavior/definitions/pressure-measurement';
|
|
36
|
-
import { BridgedDeviceBasicInformationServer } from '@project-chip/matter.js/behavior/definitions/bridged-device-basic-information';
|
|
37
|
-
import { AirQuality, AirQualityCluster, BasicInformationCluster, BooleanState, BooleanStateCluster, BooleanStateConfiguration, BooleanStateConfigurationCluster, BridgedDeviceBasicInformation, BridgedDeviceBasicInformationCluster, CarbonDioxideConcentrationMeasurement, CarbonDioxideConcentrationMeasurementCluster, CarbonMonoxideConcentrationMeasurement, CarbonMonoxideConcentrationMeasurementCluster, ClusterServer, ColorControl, ColorControlCluster, ConcentrationMeasurement, DoorLock, DoorLockCluster, ElectricalEnergyMeasurement, ElectricalEnergyMeasurementCluster, ElectricalPowerMeasurement, ElectricalPowerMeasurementCluster, FanControl, FanControlCluster, FlowMeasurement, FlowMeasurementCluster, FormaldehydeConcentrationMeasurement, FormaldehydeConcentrationMeasurementCluster, Groups, GroupsCluster, GroupsClusterHandler, Identify, IdentifyCluster, IlluminanceMeasurement, IlluminanceMeasurementCluster, LevelControl, LevelControlCluster, MeasurementType, ModeSelectCluster, NitrogenDioxideConcentrationMeasurement, NitrogenDioxideConcentrationMeasurementCluster, OccupancySensing, OccupancySensingCluster, OnOff, OnOffCluster, OzoneConcentrationMeasurement, OzoneConcentrationMeasurementCluster, Pm10ConcentrationMeasurement, Pm10ConcentrationMeasurementCluster, Pm1ConcentrationMeasurement, Pm1ConcentrationMeasurementCluster, Pm25ConcentrationMeasurement, Pm25ConcentrationMeasurementCluster, PowerSource, PowerSourceCluster, PowerSourceConfigurationCluster, PowerTopology, PowerTopologyCluster, PressureMeasurement, PressureMeasurementCluster, RadonConcentrationMeasurement, RadonConcentrationMeasurementCluster, RelativeHumidityMeasurement, RelativeHumidityMeasurementCluster, SmokeCoAlarm, SmokeCoAlarmCluster, Switch, SwitchCluster, TemperatureMeasurement, TemperatureMeasurementCluster, Thermostat, ThermostatCluster, ThreadNetworkDiagnostics, ThreadNetworkDiagnosticsCluster, TimeSynchronization, TimeSynchronizationCluster, TotalVolatileOrganicCompoundsConcentrationMeasurement, TotalVolatileOrganicCompoundsConcentrationMeasurementCluster, WindowCovering, WindowCoveringCluster, getClusterNameById, } from '@project-chip/matter-node.js/cluster';
|
|
38
|
-
import { NamedHandler } from '@project-chip/matter-node.js/util';
|
|
39
|
-
import { EndpointNumber, VendorId } from '@project-chip/matter-node.js/datatype';
|
|
40
|
-
// Matterbridge imports
|
|
41
|
-
import { AnsiLogger, YELLOW, db, debugStringify, er, hk, or, rs, zb } from 'node-ansi-logger';
|
|
24
|
+
// Node.js modules
|
|
42
25
|
import { createHash } from 'crypto';
|
|
43
|
-
|
|
44
|
-
import {
|
|
45
|
-
|
|
46
|
-
import {
|
|
47
|
-
import {
|
|
48
|
-
import {
|
|
49
|
-
|
|
50
|
-
import {
|
|
51
|
-
import {
|
|
52
|
-
import {
|
|
53
|
-
import {
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
26
|
+
// AnsiLogger module
|
|
27
|
+
import { AnsiLogger, BLUE, CYAN, 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, MatterbridgeWindowCoveringServer, } from './matterbridgeBehaviors.js';
|
|
30
|
+
import { bridgedNode } from './matterbridgeDeviceTypes.js';
|
|
31
|
+
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, RadonConcentrationMeasurement, RadonConcentrationMeasurementCluster, RelativeHumidityMeasurement, RelativeHumidityMeasurementCluster, SmokeCoAlarm, SmokeCoAlarmCluster, Switch, SwitchCluster, TemperatureMeasurement, TemperatureMeasurementCluster, Thermostat, ThermostatCluster, TotalVolatileOrganicCompoundsConcentrationMeasurement, TotalVolatileOrganicCompoundsConcentrationMeasurementCluster, UserLabel, UserLabelCluster, 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';
|
|
56
51
|
export class MatterbridgeEndpoint extends Endpoint {
|
|
57
52
|
static bridgeMode = '';
|
|
53
|
+
static logLevel = "info" /* LogLevel.INFO */;
|
|
58
54
|
log;
|
|
59
|
-
|
|
55
|
+
plugin = undefined;
|
|
60
56
|
deviceName = undefined;
|
|
57
|
+
serialNumber = undefined;
|
|
61
58
|
uniqueId = undefined;
|
|
59
|
+
vendorId = undefined;
|
|
60
|
+
vendorName = undefined;
|
|
61
|
+
productId = undefined;
|
|
62
|
+
productName = undefined;
|
|
63
|
+
softwareVersion = undefined;
|
|
64
|
+
softwareVersionString = undefined;
|
|
65
|
+
hardwareVersion = undefined;
|
|
66
|
+
hardwareVersionString = undefined;
|
|
67
|
+
uniqueStorageKey = undefined;
|
|
68
|
+
tagList = undefined;
|
|
62
69
|
// Maps matter deviceTypes and endpoints
|
|
63
70
|
deviceTypes = new Map();
|
|
64
71
|
clusterServers = new Map();
|
|
65
72
|
clusterClients = new Map();
|
|
66
73
|
commandHandler = new NamedHandler();
|
|
67
74
|
/**
|
|
68
|
-
* Represents a MatterbridgeEndpoint
|
|
75
|
+
* Represents a MatterbridgeEndpoint.
|
|
69
76
|
* @constructor
|
|
70
|
-
* @param {DeviceTypeDefinition} definition - The
|
|
71
|
-
* @param {
|
|
72
|
-
*/
|
|
73
|
-
constructor(definition, options = {}) {
|
|
74
|
-
//
|
|
77
|
+
* @param {DeviceTypeDefinition | AtLeastOne<DeviceTypeDefinition>} definition - The DeviceTypeDefinition(s) of the endpoint.
|
|
78
|
+
* @param {MatterbridgeEndpointOptions} [options={}] - The options for the device.
|
|
79
|
+
*/
|
|
80
|
+
constructor(definition, options = {}, debug = false) {
|
|
81
|
+
// Get the first DeviceTypeDefinition
|
|
82
|
+
let firstDefinition;
|
|
83
|
+
if (Array.isArray(definition))
|
|
84
|
+
firstDefinition = definition[0];
|
|
85
|
+
else
|
|
86
|
+
firstDefinition = definition;
|
|
87
|
+
// Convert the first DeviceTypeDefinition to an EndpointType.Options
|
|
75
88
|
const deviceTypeDefinitionV8 = {
|
|
76
|
-
name:
|
|
77
|
-
deviceType:
|
|
78
|
-
deviceRevision:
|
|
79
|
-
deviceClass:
|
|
89
|
+
name: firstDefinition.name.replace('-', '_'),
|
|
90
|
+
deviceType: firstDefinition.code,
|
|
91
|
+
deviceRevision: firstDefinition.revision,
|
|
92
|
+
deviceClass: firstDefinition.deviceClass.toLowerCase(),
|
|
80
93
|
requirements: {
|
|
81
94
|
server: {
|
|
82
|
-
mandatory: SupportedBehaviors(...MatterbridgeEndpoint.getBehaviourTypesFromClusterServerIds(
|
|
83
|
-
optional: SupportedBehaviors(...MatterbridgeEndpoint.getBehaviourTypesFromClusterServerIds(
|
|
95
|
+
mandatory: SupportedBehaviors(...MatterbridgeEndpoint.getBehaviourTypesFromClusterServerIds(firstDefinition.requiredServerClusters)),
|
|
96
|
+
optional: SupportedBehaviors(...MatterbridgeEndpoint.getBehaviourTypesFromClusterServerIds(firstDefinition.optionalServerClusters)),
|
|
84
97
|
},
|
|
85
98
|
client: {
|
|
86
|
-
mandatory: SupportedBehaviors(...MatterbridgeEndpoint.getBehaviourTypesFromClusterClientIds(
|
|
87
|
-
optional: SupportedBehaviors(...MatterbridgeEndpoint.getBehaviourTypesFromClusterClientIds(
|
|
99
|
+
mandatory: SupportedBehaviors(...MatterbridgeEndpoint.getBehaviourTypesFromClusterClientIds(firstDefinition.requiredClientClusters)),
|
|
100
|
+
optional: SupportedBehaviors(...MatterbridgeEndpoint.getBehaviourTypesFromClusterClientIds(firstDefinition.optionalClientClusters)),
|
|
88
101
|
},
|
|
89
102
|
},
|
|
90
|
-
behaviors: SupportedBehaviors(
|
|
103
|
+
behaviors: options.tagList ? SupportedBehaviors(DescriptorServer.with(Descriptor.Feature.TagList)) : {},
|
|
91
104
|
};
|
|
92
105
|
const endpointV8 = MutableEndpoint(deviceTypeDefinitionV8);
|
|
106
|
+
// Convert the options to an Endpoint.Options
|
|
107
|
+
// [{ mfgCode: null, namespaceId: 0x07, tag: 1, label: 'Switch1' }]
|
|
108
|
+
// endpoint = endpoint.enable({features: { tagList: true }});
|
|
93
109
|
const optionsV8 = {
|
|
94
|
-
id: options.uniqueStorageKey,
|
|
110
|
+
id: options.uniqueStorageKey?.replace(/[ .]/g, ''),
|
|
111
|
+
number: options.endpointId,
|
|
112
|
+
descriptor: options.tagList ? { tagList: options.tagList } : undefined,
|
|
113
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
95
114
|
};
|
|
96
115
|
super(endpointV8, optionsV8);
|
|
97
|
-
this.
|
|
98
|
-
this.
|
|
116
|
+
this.uniqueStorageKey = options.uniqueStorageKey;
|
|
117
|
+
this.tagList = options.tagList;
|
|
118
|
+
// Update the endpoint
|
|
119
|
+
this.log = new AnsiLogger({ logName: 'MatterbridgeEndpoint', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: debug === true ? "debug" /* LogLevel.DEBUG */ : MatterbridgeEndpoint.logLevel });
|
|
120
|
+
this.log.debug(`${YELLOW}new${db} MatterbridgeEndpoint: ${zb}${'0x' + firstDefinition.code.toString(16).padStart(4, '0')}${db}-${zb}${firstDefinition.name}${db} ` +
|
|
121
|
+
`id: ${CYAN}${options.uniqueStorageKey}${db} number: ${CYAN}${options.endpointId}${db} taglist: ${CYAN}${options.tagList ? debugStringify(options.tagList) : 'undefined'}${db}`);
|
|
122
|
+
this.deviceTypes.set(firstDefinition.code, firstDefinition);
|
|
123
|
+
// Add the other device types to the descriptor server
|
|
124
|
+
if (Array.isArray(definition)) {
|
|
125
|
+
definition.forEach((deviceType) => {
|
|
126
|
+
this.addDeviceType(deviceType);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
// Add MatterbridgeBehavior with MatterbridgeBehaviorDevice
|
|
130
|
+
this.behaviors.require(MatterbridgeBehavior, { deviceCommand: new MatterbridgeBehaviorDevice(this.log, this.commandHandler, undefined) });
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Loads an instance of the MatterbridgeDevice class.
|
|
134
|
+
*
|
|
135
|
+
* @param {DeviceTypeDefinition | AtLeastOne<DeviceTypeDefinition>} definition - The DeviceTypeDefinition(s) of the device.
|
|
136
|
+
* @returns MatterbridgeDevice instance.
|
|
137
|
+
*/
|
|
138
|
+
static async loadInstance(definition, options = {}, debug = false) {
|
|
139
|
+
return new MatterbridgeEndpoint(definition, options, debug);
|
|
99
140
|
}
|
|
100
141
|
static getBehaviourTypesFromClusterServerIds(clusterServerList) {
|
|
101
142
|
// Map Server ClusterId to Behavior.Type
|
|
@@ -113,57 +154,97 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
113
154
|
});
|
|
114
155
|
return behaviorTypes;
|
|
115
156
|
}
|
|
116
|
-
static getBehaviourTypeFromClusterServerId(clusterId) {
|
|
157
|
+
static getBehaviourTypeFromClusterServerId(clusterId, type) {
|
|
117
158
|
// Map ClusterId to Behavior.Type
|
|
118
159
|
if (clusterId === Identify.Cluster.id)
|
|
119
|
-
return
|
|
160
|
+
return MatterbridgeIdentifyServer;
|
|
120
161
|
if (clusterId === Groups.Cluster.id)
|
|
121
162
|
return GroupsServer;
|
|
122
|
-
// if (clusterId === Scenes.Cluster.id) return ScenesServer;
|
|
123
163
|
if (clusterId === OnOff.Cluster.id)
|
|
124
|
-
return
|
|
164
|
+
return MatterbridgeOnOffServer;
|
|
125
165
|
if (clusterId === LevelControl.Cluster.id)
|
|
126
|
-
return
|
|
166
|
+
return MatterbridgeLevelControlServer;
|
|
127
167
|
if (clusterId === ColorControl.Cluster.id)
|
|
128
|
-
return
|
|
168
|
+
return MatterbridgeColorControlServer;
|
|
129
169
|
if (clusterId === DoorLock.Cluster.id)
|
|
130
|
-
return
|
|
170
|
+
return MatterbridgeDoorLockServer;
|
|
131
171
|
if (clusterId === Thermostat.Cluster.id)
|
|
132
|
-
return
|
|
133
|
-
if (clusterId === TimeSynchronization.Cluster.id)
|
|
134
|
-
return TimeSynchronizationServer.with(TimeSynchronization.Feature.TimeZone);
|
|
172
|
+
return MatterbridgeThermostatServer;
|
|
135
173
|
if (clusterId === WindowCovering.Cluster.id)
|
|
136
|
-
return
|
|
174
|
+
return MatterbridgeWindowCoveringServer;
|
|
137
175
|
if (clusterId === FanControl.Cluster.id)
|
|
138
|
-
return
|
|
176
|
+
return MatterbridgeFanControlServer;
|
|
177
|
+
if (clusterId === Switch.Cluster.id && type === 'MomentarySwitch')
|
|
178
|
+
return SwitchServer.with('MomentarySwitch', 'MomentarySwitchRelease', 'MomentarySwitchLongPress', 'MomentarySwitchMultiPress');
|
|
179
|
+
if (clusterId === Switch.Cluster.id && type === 'LatchingSwitch')
|
|
180
|
+
return SwitchServer.with('LatchingSwitch');
|
|
139
181
|
if (clusterId === TemperatureMeasurement.Cluster.id)
|
|
140
182
|
return TemperatureMeasurementServer;
|
|
141
183
|
if (clusterId === RelativeHumidityMeasurement.Cluster.id)
|
|
142
184
|
return RelativeHumidityMeasurementServer;
|
|
143
185
|
if (clusterId === PressureMeasurement.Cluster.id)
|
|
144
|
-
return PressureMeasurementServer
|
|
186
|
+
return PressureMeasurementServer;
|
|
145
187
|
if (clusterId === FlowMeasurement.Cluster.id)
|
|
146
188
|
return FlowMeasurementServer;
|
|
147
189
|
if (clusterId === BooleanState.Cluster.id)
|
|
148
190
|
return BooleanStateServer;
|
|
149
191
|
if (clusterId === BooleanStateConfiguration.Cluster.id)
|
|
150
|
-
return
|
|
192
|
+
return MatterbridgeBooleanStateConfigurationServer;
|
|
151
193
|
if (clusterId === OccupancySensing.Cluster.id)
|
|
152
194
|
return OccupancySensingServer;
|
|
153
195
|
if (clusterId === IlluminanceMeasurement.Cluster.id)
|
|
154
196
|
return IlluminanceMeasurementServer;
|
|
197
|
+
if (clusterId === SmokeCoAlarm.Cluster.id)
|
|
198
|
+
return SmokeCoAlarmServer.with(SmokeCoAlarm.Feature.SmokeAlarm, SmokeCoAlarm.Feature.CoAlarm);
|
|
199
|
+
if (clusterId === AirQuality.Cluster.id)
|
|
200
|
+
return AirQualityServer.with(AirQuality.Feature.Fair, AirQuality.Feature.Moderate, AirQuality.Feature.VeryPoor, AirQuality.Feature.ExtremelyPoor);
|
|
201
|
+
if (clusterId === CarbonMonoxideConcentrationMeasurement.Cluster.id)
|
|
202
|
+
return CarbonMonoxideConcentrationMeasurementServer.with('NumericMeasurement');
|
|
203
|
+
if (clusterId === CarbonDioxideConcentrationMeasurement.Cluster.id)
|
|
204
|
+
return CarbonDioxideConcentrationMeasurementServer.with('NumericMeasurement');
|
|
205
|
+
if (clusterId === NitrogenDioxideConcentrationMeasurement.Cluster.id)
|
|
206
|
+
return NitrogenDioxideConcentrationMeasurementServer.with('NumericMeasurement');
|
|
207
|
+
if (clusterId === OzoneConcentrationMeasurement.Cluster.id)
|
|
208
|
+
return OzoneConcentrationMeasurementServer.with('NumericMeasurement');
|
|
209
|
+
if (clusterId === FormaldehydeConcentrationMeasurement.Cluster.id)
|
|
210
|
+
return FormaldehydeConcentrationMeasurementServer.with('NumericMeasurement');
|
|
211
|
+
if (clusterId === Pm1ConcentrationMeasurement.Cluster.id)
|
|
212
|
+
return Pm1ConcentrationMeasurementServer.with('NumericMeasurement');
|
|
213
|
+
if (clusterId === Pm25ConcentrationMeasurement.Cluster.id)
|
|
214
|
+
return Pm25ConcentrationMeasurementServer.with('NumericMeasurement');
|
|
215
|
+
if (clusterId === Pm10ConcentrationMeasurement.Cluster.id)
|
|
216
|
+
return Pm10ConcentrationMeasurementServer.with('NumericMeasurement');
|
|
217
|
+
if (clusterId === RadonConcentrationMeasurement.Cluster.id)
|
|
218
|
+
return RadonConcentrationMeasurementServer.with('NumericMeasurement');
|
|
219
|
+
if (clusterId === TotalVolatileOrganicCompoundsConcentrationMeasurement.Cluster.id)
|
|
220
|
+
return TotalVolatileOrganicCompoundsConcentrationMeasurementServer.with('NumericMeasurement');
|
|
221
|
+
if (clusterId === ModeSelect.Cluster.id)
|
|
222
|
+
return ModeSelectServer;
|
|
223
|
+
if (clusterId === UserLabel.Cluster.id)
|
|
224
|
+
return UserLabelServer;
|
|
225
|
+
if (clusterId === FixedLabel.Cluster.id)
|
|
226
|
+
return FixedLabelServer;
|
|
227
|
+
if (clusterId === PowerTopology.Cluster.id)
|
|
228
|
+
return PowerTopologyServer.with('TreeTopology');
|
|
229
|
+
if (clusterId === ElectricalPowerMeasurement.Cluster.id)
|
|
230
|
+
return ElectricalPowerMeasurementServer.with('AlternatingCurrent');
|
|
231
|
+
if (clusterId === ElectricalEnergyMeasurement.Cluster.id)
|
|
232
|
+
return ElectricalEnergyMeasurementServer.with('ImportedEnergy', 'ExportedEnergy', 'CumulativeEnergy');
|
|
233
|
+
if (clusterId === PowerSource.Cluster.id && type === 'WiredPowerSource')
|
|
234
|
+
return PowerSourceServer.with(PowerSource.Feature.Wired);
|
|
235
|
+
if (clusterId === PowerSource.Cluster.id && type === 'BatteryReplaceablePowerSource')
|
|
236
|
+
return PowerSourceServer.with(PowerSource.Feature.Battery, PowerSource.Feature.Replaceable);
|
|
237
|
+
if (clusterId === PowerSource.Cluster.id && type === 'BatteryRechargeablePowerSource')
|
|
238
|
+
return PowerSourceServer.with(PowerSource.Feature.Battery, PowerSource.Feature.Rechargeable);
|
|
239
|
+
if (clusterId === BasicInformation.Cluster.id)
|
|
240
|
+
return BasicInformationServer;
|
|
155
241
|
if (clusterId === BridgedDeviceBasicInformation.Cluster.id)
|
|
156
242
|
return BridgedDeviceBasicInformationServer;
|
|
157
|
-
return
|
|
243
|
+
return MatterbridgeIdentifyServer;
|
|
158
244
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
* @param {DeviceTypeDefinition} definition - The DeviceTypeDefinition of the device.
|
|
163
|
-
* @returns MatterbridgeDevice instance.
|
|
164
|
-
*/
|
|
165
|
-
static async loadInstance(definition, options = {}) {
|
|
166
|
-
return new MatterbridgeEndpoint(definition, options);
|
|
245
|
+
static getBehaviourTypeFromClusterClientId(clusterId) {
|
|
246
|
+
// Map ClusterId to Behavior.Type
|
|
247
|
+
return IdentifyBehavior;
|
|
167
248
|
}
|
|
168
249
|
/**
|
|
169
250
|
* Adds a device type to the list of device types.
|
|
@@ -174,16 +255,24 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
174
255
|
addDeviceType(deviceType) {
|
|
175
256
|
if (!this.deviceTypes.has(deviceType.code)) {
|
|
176
257
|
// Keep the Matterbridge internal map
|
|
177
|
-
this.log.debug(`addDeviceType: ${zb}${deviceType.code}${db}-${zb}${deviceType.name}${db}`);
|
|
258
|
+
this.log.debug(`addDeviceType: ${zb}${'0x' + deviceType.code.toString(16).padStart(4, '0')}${db}-${zb}${deviceType.name}${db}`);
|
|
178
259
|
this.deviceTypes.set(deviceType.code, deviceType);
|
|
179
260
|
// Add the device types to the descriptor server
|
|
180
261
|
const deviceTypeList = Array.from(this.deviceTypes.values()).map((dt) => ({
|
|
181
262
|
deviceType: dt.code,
|
|
182
263
|
revision: dt.revision,
|
|
183
264
|
}));
|
|
184
|
-
this.
|
|
185
|
-
|
|
186
|
-
|
|
265
|
+
if (this.tagList) {
|
|
266
|
+
this.behaviors.require(DescriptorServer.with(Descriptor.Feature.TagList), {
|
|
267
|
+
tagList: this.tagList,
|
|
268
|
+
deviceTypeList,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
this.behaviors.require(DescriptorServer, {
|
|
273
|
+
deviceTypeList,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
187
276
|
}
|
|
188
277
|
}
|
|
189
278
|
/**
|
|
@@ -195,20 +284,64 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
195
284
|
addDeviceTypeWithClusterServer(deviceTypes, includeServerList) {
|
|
196
285
|
this.log.debug('addDeviceTypeWithClusterServer:');
|
|
197
286
|
deviceTypes.forEach((deviceType) => {
|
|
198
|
-
this.log.debug(`- with deviceType: ${zb}${deviceType.code}${db}-${zb}${deviceType.name}${db}`);
|
|
287
|
+
this.log.debug(`- with deviceType: ${zb}${'0x' + deviceType.code.toString(16).padStart(4, '0')}${db}-${zb}${deviceType.name}${db}`);
|
|
199
288
|
deviceType.requiredServerClusters.forEach((clusterId) => {
|
|
200
289
|
if (!includeServerList.includes(clusterId))
|
|
201
290
|
includeServerList.push(clusterId);
|
|
202
291
|
});
|
|
203
292
|
});
|
|
204
293
|
includeServerList.forEach((clusterId) => {
|
|
205
|
-
this.log.debug(`- with cluster: ${hk}${clusterId}${db}-${hk}${getClusterNameById(clusterId)}${db}`);
|
|
294
|
+
this.log.debug(`- with cluster: ${hk}${'0x' + clusterId.toString(16).padStart(4, '0')}${db}-${hk}${getClusterNameById(clusterId)}${db}`);
|
|
206
295
|
});
|
|
207
296
|
deviceTypes.forEach((deviceType) => {
|
|
208
297
|
this.addDeviceType(deviceType);
|
|
209
298
|
});
|
|
210
299
|
this.addClusterServerFromList(this, includeServerList);
|
|
211
300
|
}
|
|
301
|
+
/**
|
|
302
|
+
* Adds the required cluster servers (only if they are not present) for the device types of the specified endpoint.
|
|
303
|
+
*
|
|
304
|
+
* @param {MatterbridgeEndpoint} endpoint - The endpoint to add the required cluster servers to.
|
|
305
|
+
* @returns {MatterbridgeEndpoint} The updated endpoint with the required cluster servers added.
|
|
306
|
+
*/
|
|
307
|
+
addRequiredClusterServers(endpoint) {
|
|
308
|
+
const requiredServerList = [];
|
|
309
|
+
this.log.debug(`addRequiredClusterServer for ${CYAN}${endpoint.id}${db}`);
|
|
310
|
+
endpoint.getDeviceTypes().forEach((deviceType) => {
|
|
311
|
+
this.log.debug(`- for deviceType: ${zb}${'0x' + deviceType.code.toString(16).padStart(4, '0')}${db}-${zb}${deviceType.name}${db}`);
|
|
312
|
+
deviceType.requiredServerClusters.forEach((clusterId) => {
|
|
313
|
+
if (!requiredServerList.includes(clusterId) && !endpoint.getClusterServerById(clusterId))
|
|
314
|
+
requiredServerList.push(clusterId);
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
requiredServerList.forEach((clusterId) => {
|
|
318
|
+
this.log.debug(`- with cluster: ${hk}${'0x' + clusterId.toString(16).padStart(4, '0')}${db}-${hk}${getClusterNameById(clusterId)}${db}`);
|
|
319
|
+
});
|
|
320
|
+
this.addClusterServerFromList(endpoint, requiredServerList);
|
|
321
|
+
return endpoint;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Adds the optional cluster servers (only if they are not present) for the device types of the specified endpoint.
|
|
325
|
+
*
|
|
326
|
+
* @param {MatterbridgeEndpoint} endpoint - The endpoint to add the required cluster servers to.
|
|
327
|
+
* @returns {MatterbridgeEndpoint} The updated endpoint with the required cluster servers added.
|
|
328
|
+
*/
|
|
329
|
+
addOptionalClusterServers(endpoint) {
|
|
330
|
+
const optionalServerList = [];
|
|
331
|
+
this.log.debug(`addRequiredClusterServer for ${CYAN}${endpoint.id}${db}`);
|
|
332
|
+
endpoint.getDeviceTypes().forEach((deviceType) => {
|
|
333
|
+
this.log.debug(`- for deviceType: ${zb}${'0x' + deviceType.code.toString(16).padStart(4, '0')}${db}-${zb}${deviceType.name}${db}`);
|
|
334
|
+
deviceType.optionalServerClusters.forEach((clusterId) => {
|
|
335
|
+
if (!optionalServerList.includes(clusterId) && !endpoint.getClusterServerById(clusterId))
|
|
336
|
+
optionalServerList.push(clusterId);
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
optionalServerList.forEach((clusterId) => {
|
|
340
|
+
this.log.debug(`- with cluster: ${hk}${'0x' + clusterId.toString(16).padStart(4, '0')}${db}-${hk}${getClusterNameById(clusterId)}${db}`);
|
|
341
|
+
});
|
|
342
|
+
this.addClusterServerFromList(endpoint, optionalServerList);
|
|
343
|
+
return endpoint;
|
|
344
|
+
}
|
|
212
345
|
/**
|
|
213
346
|
* Adds a child endpoint with one or more device types with the required cluster servers and the specified cluster servers.
|
|
214
347
|
* If the child endpoint is not already present in the childEndpoints, it will be added.
|
|
@@ -216,30 +349,71 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
216
349
|
*
|
|
217
350
|
* @param {string} endpointName - The name of the new enpoint to add.
|
|
218
351
|
* @param {AtLeastOne<DeviceTypeDefinition>} deviceTypes - The device types to add.
|
|
219
|
-
* @param {ClusterId[]} includeServerList - The list of cluster IDs to include.
|
|
220
|
-
* @
|
|
352
|
+
* @param {ClusterId[]} [includeServerList=[]] - The list of cluster IDs to include.
|
|
353
|
+
* @param {EndpointOptions} [options={}] - The options for the device.
|
|
354
|
+
* @param {boolean} [debug=false] - Whether to enable debug logging.
|
|
355
|
+
* @returns {MatterbridgeEndpoint} - The child endpoint that was found or added.
|
|
221
356
|
*/
|
|
222
|
-
addChildDeviceTypeWithClusterServer(endpointName, deviceTypes, includeServerList) {
|
|
223
|
-
/*
|
|
357
|
+
addChildDeviceTypeWithClusterServer(endpointName, deviceTypes, includeServerList = [], options = {}, debug = false) {
|
|
224
358
|
this.log.debug(`addChildDeviceTypeWithClusterServer: ${CYAN}${endpointName}${db}`);
|
|
225
|
-
let child = this.
|
|
359
|
+
let child = this.getChildEndpointByName(endpointName);
|
|
226
360
|
if (!child) {
|
|
227
|
-
|
|
228
|
-
|
|
361
|
+
if ('tagList' in options) {
|
|
362
|
+
for (const tag of options.tagList) {
|
|
363
|
+
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}`);
|
|
364
|
+
}
|
|
365
|
+
child = new MatterbridgeEndpoint(deviceTypes[0], { uniqueStorageKey: endpointName, taglist: options.tagList }, debug);
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
child = new MatterbridgeEndpoint(deviceTypes[0], { uniqueStorageKey: endpointName }, debug);
|
|
369
|
+
}
|
|
229
370
|
}
|
|
230
371
|
deviceTypes.forEach((deviceType) => {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
372
|
+
this.log.debug(`- with deviceType: ${zb}${'0x' + deviceType.code.toString(16).padStart(4, '0')}${db}-${zb}${deviceType.name}${db}`);
|
|
373
|
+
deviceType.requiredServerClusters.forEach((clusterId) => {
|
|
374
|
+
if (!includeServerList.includes(clusterId))
|
|
375
|
+
includeServerList.push(clusterId);
|
|
376
|
+
});
|
|
235
377
|
});
|
|
236
378
|
includeServerList.forEach((clusterId) => {
|
|
237
|
-
|
|
379
|
+
this.log.debug(`- with cluster: ${hk}${'0x' + clusterId.toString(16).padStart(4, '0')}${db}-${hk}${getClusterNameById(clusterId)}${db}`);
|
|
238
380
|
});
|
|
239
381
|
this.addClusterServerFromList(child, includeServerList);
|
|
240
|
-
this.
|
|
382
|
+
if (this.lifecycle.isInstalled) {
|
|
383
|
+
this.log.debug(`- with lifecycle installed`);
|
|
384
|
+
this.add(child);
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
this.log.debug(`- with lifecycle NOT installed`);
|
|
388
|
+
this.parts.add(child);
|
|
389
|
+
}
|
|
241
390
|
return child;
|
|
242
|
-
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Retrieves a child endpoint by its name.
|
|
394
|
+
*
|
|
395
|
+
* @param {string} endpointName - The name of the endpoint to retrieve.
|
|
396
|
+
* @returns {Endpoint | undefined} The child endpoint with the specified name, or undefined if not found.
|
|
397
|
+
*/
|
|
398
|
+
getChildEndpointByName(endpointName) {
|
|
399
|
+
return this.parts.find((part) => part.id === endpointName);
|
|
400
|
+
}
|
|
401
|
+
getChildEndpoint(endpointNumber) {
|
|
402
|
+
return this.parts.find((part) => part.number === endpointNumber);
|
|
403
|
+
}
|
|
404
|
+
getChildEndpoints() {
|
|
405
|
+
return Array.from(this.parts);
|
|
406
|
+
}
|
|
407
|
+
getDeviceTypes() {
|
|
408
|
+
return Array.from(this.deviceTypes.values());
|
|
409
|
+
}
|
|
410
|
+
setDeviceTypes(deviceTypes) {
|
|
411
|
+
deviceTypes.forEach((deviceType) => {
|
|
412
|
+
this.addDeviceType(deviceType);
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
hasClusterServer(cluster) {
|
|
416
|
+
return this.clusterServers.has(cluster.id);
|
|
243
417
|
}
|
|
244
418
|
getClusterServer(cluster) {
|
|
245
419
|
const clusterServer = this.clusterServers.get(cluster.id);
|
|
@@ -250,21 +424,35 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
250
424
|
getClusterServerById(clusterId) {
|
|
251
425
|
return this.clusterServers.get(clusterId);
|
|
252
426
|
}
|
|
427
|
+
addTagList(endpoint, mfgCode, namespaceId, tag, label) {
|
|
428
|
+
// Do nothing here
|
|
429
|
+
}
|
|
253
430
|
addClusterServer(cluster) {
|
|
254
431
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
255
432
|
const options = {};
|
|
256
433
|
for (const attribute of Object.values(cluster.attributes)) {
|
|
434
|
+
// console.error('Attribute:', (attribute as any).id, (attribute as any).name, (attribute as any).value);
|
|
257
435
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
258
436
|
if (attribute.id < 0xfff0) {
|
|
259
|
-
// No issue here for value, as cluster here is just a definition without getter setter
|
|
260
437
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
261
438
|
options[attribute.name] = attribute.value;
|
|
262
439
|
}
|
|
263
440
|
}
|
|
264
|
-
this.log.debug(`addClusterServer: ${hk}${cluster.id}${db}-${hk}${getClusterNameById(cluster.id)}${db} with options: ${debugStringify(options)}${rs}`);
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
441
|
+
this.log.debug(`addClusterServer: ${hk}${'0x' + cluster.id.toString(16).padStart(4, '0')}${db}-${hk}${getClusterNameById(cluster.id)}${db} with options: ${debugStringify(options)}${rs}`);
|
|
442
|
+
let type = undefined;
|
|
443
|
+
if (cluster.id === SwitchCluster.id && cluster.isEventSupportedByName('multiPressComplete'))
|
|
444
|
+
type = 'MomentarySwitch';
|
|
445
|
+
if (cluster.id === SwitchCluster.id && cluster.isEventSupportedByName('switchLatched'))
|
|
446
|
+
type = 'LatchingSwitch';
|
|
447
|
+
if (cluster.id === PowerSourceCluster.id && cluster.isAttributeSupportedByName('wiredCurrentType'))
|
|
448
|
+
type = 'WiredPowerSource';
|
|
449
|
+
if (cluster.id === PowerSourceCluster.id && cluster.isAttributeSupportedByName('batReplacementDescription'))
|
|
450
|
+
type = 'BatteryReplaceablePowerSource';
|
|
451
|
+
if (cluster.id === PowerSourceCluster.id && cluster.isAttributeSupportedByName('batChargeState'))
|
|
452
|
+
type = 'BatteryRechargeablePowerSource';
|
|
453
|
+
const behavior = MatterbridgeEndpoint.getBehaviourTypeFromClusterServerId(cluster.id, type);
|
|
454
|
+
if (cluster.id !== BasicInformationCluster.id)
|
|
455
|
+
this.behaviors.require(behavior, options);
|
|
268
456
|
this.clusterServers.set(cluster.id, cluster);
|
|
269
457
|
}
|
|
270
458
|
/**
|
|
@@ -279,21 +467,18 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
279
467
|
endpoint.addClusterServer(this.getDefaultIdentifyClusterServer());
|
|
280
468
|
if (includeServerList.includes(Groups.Cluster.id))
|
|
281
469
|
endpoint.addClusterServer(this.getDefaultGroupsClusterServer());
|
|
282
|
-
// if (includeServerList.includes(Scenes.Cluster.id)) endpoint.addClusterServer(this.getDefaultScenesClusterServer());
|
|
283
470
|
if (includeServerList.includes(OnOff.Cluster.id))
|
|
284
471
|
endpoint.addClusterServer(this.getDefaultOnOffClusterServer());
|
|
285
472
|
if (includeServerList.includes(LevelControl.Cluster.id))
|
|
286
473
|
endpoint.addClusterServer(this.getDefaultLevelControlClusterServer());
|
|
287
474
|
if (includeServerList.includes(ColorControl.Cluster.id))
|
|
288
|
-
endpoint.addClusterServer(this.
|
|
475
|
+
endpoint.addClusterServer(this.getDefaultColorControlClusterServer());
|
|
289
476
|
if (includeServerList.includes(Switch.Cluster.id))
|
|
290
477
|
endpoint.addClusterServer(this.getDefaultSwitchClusterServer());
|
|
291
478
|
if (includeServerList.includes(DoorLock.Cluster.id))
|
|
292
479
|
endpoint.addClusterServer(this.getDefaultDoorLockClusterServer());
|
|
293
480
|
if (includeServerList.includes(Thermostat.Cluster.id))
|
|
294
481
|
endpoint.addClusterServer(this.getDefaultThermostatClusterServer());
|
|
295
|
-
if (includeServerList.includes(TimeSynchronization.Cluster.id))
|
|
296
|
-
endpoint.addClusterServer(this.getDefaultTimeSyncClusterServer());
|
|
297
482
|
if (includeServerList.includes(WindowCovering.Cluster.id))
|
|
298
483
|
endpoint.addClusterServer(this.getDefaultWindowCoveringClusterServer());
|
|
299
484
|
if (includeServerList.includes(FanControl.Cluster.id))
|
|
@@ -349,56 +534,71 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
349
534
|
// if (includeServerList.includes(DeviceEnergyManagement.Cluster.id)) endpoint.addClusterServer(this.getDefaultDeviceEnergyManagementClusterServer());
|
|
350
535
|
// if (includeServerList.includes(DeviceEnergyManagementMode.Cluster.id)) endpoint.addClusterServer(this.getDefaultDeviceEnergyManagementModeClusterServer());
|
|
351
536
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
537
|
+
async addFixedLabel(label, value) {
|
|
538
|
+
if (!this.clusterServers.get(FixedLabelCluster.id)) {
|
|
539
|
+
this.addClusterServer(ClusterServer(FixedLabelCluster, {
|
|
540
|
+
labelList: [{ label, value }],
|
|
541
|
+
}, {}));
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
const labelList = (this.getAttribute(FixedLabelCluster.id, 'labelList', this.log) ?? []).filter((entryLabel) => entryLabel.label !== label);
|
|
545
|
+
labelList.push({ label, value });
|
|
546
|
+
await this.setAttribute(FixedLabelCluster.id, 'labelList', labelList, this.log);
|
|
547
|
+
}
|
|
548
|
+
async addUserLabel(label, value) {
|
|
549
|
+
if (!this.clusterServers.get(UserLabelCluster.id)) {
|
|
550
|
+
this.addClusterServer(ClusterServer(UserLabelCluster, {
|
|
551
|
+
labelList: [{ label, value }],
|
|
552
|
+
}, {}));
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
const labelList = (this.getAttribute(UserLabelCluster.id, 'labelList', this.log) ?? []).filter((entryLabel) => entryLabel.label !== label);
|
|
556
|
+
labelList.push({ label, value });
|
|
557
|
+
await this.setAttribute(UserLabelCluster.id, 'labelList', labelList, this.log);
|
|
558
|
+
}
|
|
559
|
+
capitalizeFirstLetter(name) {
|
|
560
|
+
if (!name)
|
|
561
|
+
return name;
|
|
562
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
563
|
+
}
|
|
564
|
+
lowercaseFirstLetter(name) {
|
|
565
|
+
if (!name)
|
|
566
|
+
return name;
|
|
567
|
+
return name.charAt(0).toLowerCase() + name.slice(1);
|
|
364
568
|
}
|
|
365
|
-
*/
|
|
366
569
|
/**
|
|
367
570
|
* Retrieves the value of the specified attribute from the given endpoint and cluster.
|
|
368
571
|
*
|
|
369
572
|
* @param {ClusterId} clusterId - The ID of the cluster to retrieve the attribute from.
|
|
370
573
|
* @param {string} attribute - The name of the attribute to retrieve.
|
|
371
574
|
* @param {AnsiLogger} [log] - Optional logger for error and info messages.
|
|
372
|
-
* @param {
|
|
575
|
+
* @param {MatterbridgeEndpoint} [endpoint] - Optional the child endpoint to retrieve the attribute from.
|
|
373
576
|
* @returns {any} The value of the attribute, or undefined if the attribute is not found.
|
|
374
577
|
*/
|
|
375
|
-
|
|
376
|
-
getAttribute(clusterId
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
if (
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
log?.info(`${db}Get endpoint ${or}${endpoint.name}:${endpoint.number}${db} attribute ${hk}${clusterServer.name}.${capitalizedAttributeName}${db} value ${YELLOW}${typeof value === 'object' ? debugStringify(value) : value}${db}`);
|
|
399
|
-
return value;
|
|
578
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
579
|
+
getAttribute(clusterId, attribute, log, endpoint) {
|
|
580
|
+
if (!endpoint)
|
|
581
|
+
endpoint = this;
|
|
582
|
+
const clusterName = this.lowercaseFirstLetter(getClusterNameById(clusterId));
|
|
583
|
+
if (endpoint.construction.status !== Lifecycle.Status.Active) {
|
|
584
|
+
this.log.error(`getAttribute ${hk}${clusterName}.${attribute}${er} error: Endpoint ${or}${endpoint.id}${er} is in the ${BLUE}${endpoint.construction.status}${er} state`);
|
|
585
|
+
return undefined;
|
|
586
|
+
}
|
|
587
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
588
|
+
const state = endpoint.state;
|
|
589
|
+
if (!(clusterName in state)) {
|
|
590
|
+
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}`);
|
|
591
|
+
return undefined;
|
|
592
|
+
}
|
|
593
|
+
attribute = this.lowercaseFirstLetter(attribute);
|
|
594
|
+
if (!(attribute in state[clusterName])) {
|
|
595
|
+
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}`);
|
|
596
|
+
return undefined;
|
|
597
|
+
}
|
|
598
|
+
const value = state[clusterName][attribute];
|
|
599
|
+
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}`);
|
|
600
|
+
return value;
|
|
400
601
|
}
|
|
401
|
-
*/
|
|
402
602
|
/**
|
|
403
603
|
* Sets the value of an attribute on a cluster server endpoint.
|
|
404
604
|
*
|
|
@@ -406,110 +606,109 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
406
606
|
* @param {string} attribute - The name of the attribute.
|
|
407
607
|
* @param {any} value - The value to set for the attribute.
|
|
408
608
|
* @param {AnsiLogger} [log] - (Optional) The logger to use for logging errors and information.
|
|
409
|
-
* @param {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
setter(value);
|
|
443
|
-
log?.info(
|
|
444
|
-
`${db}Set endpoint ${or}${endpoint.name}:${endpoint.number}${db} attribute ${hk}${clusterServer.name}.${capitalizedAttributeName}${db} ` +
|
|
445
|
-
`from ${YELLOW}${typeof oldValue === 'object' ? debugStringify(oldValue) : oldValue}${db} ` +
|
|
446
|
-
`to ${YELLOW}${typeof value === 'object' ? debugStringify(value) : value}${db}`,
|
|
447
|
-
);
|
|
448
|
-
return true;
|
|
449
|
-
}
|
|
450
|
-
*/
|
|
609
|
+
* @param {MatterbridgeEndpoint} [endpoint] - (Optional) The endpoint to set the attribute on. If not provided, the attribute will be set on the current endpoint.
|
|
610
|
+
* @returns {Promise<boolean>} - A promise that resolves to a boolean indicating whether the attribute was successfully set.
|
|
611
|
+
*/
|
|
612
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
613
|
+
async setAttribute(clusterId, attribute, value, log, endpoint) {
|
|
614
|
+
if (!endpoint)
|
|
615
|
+
endpoint = this;
|
|
616
|
+
const clusterName = this.lowercaseFirstLetter(getClusterNameById(clusterId));
|
|
617
|
+
if (endpoint.construction.status !== Lifecycle.Status.Active) {
|
|
618
|
+
this.log.error(`setAttribute ${hk}${clusterName}.${attribute}${er} error: Endpoint ${or}${endpoint.id}${er} is in the ${BLUE}${endpoint.construction.status}${er} state`);
|
|
619
|
+
return false;
|
|
620
|
+
}
|
|
621
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
622
|
+
const state = endpoint.state;
|
|
623
|
+
if (!(clusterName in state)) {
|
|
624
|
+
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}`);
|
|
625
|
+
return false;
|
|
626
|
+
}
|
|
627
|
+
attribute = this.lowercaseFirstLetter(attribute);
|
|
628
|
+
if (!(attribute in state[clusterName])) {
|
|
629
|
+
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}`);
|
|
630
|
+
return false;
|
|
631
|
+
}
|
|
632
|
+
let oldValue = state[clusterName][attribute];
|
|
633
|
+
if (typeof oldValue === 'object')
|
|
634
|
+
oldValue = deepCopy(oldValue);
|
|
635
|
+
await endpoint.setStateOf(endpoint.behaviors.supported[clusterName], { [attribute]: value });
|
|
636
|
+
// await endpoint.set({ [clusterName]: { [attribute]: value } });
|
|
637
|
+
log?.info(`${db}Set endpoint ${or}${endpoint.id}${db}:${or}${endpoint.number}${db} attribute ${hk}${this.capitalizeFirstLetter(clusterName)}${db}.${hk}${attribute}${db} ` +
|
|
638
|
+
`from ${YELLOW}${typeof oldValue === 'object' ? debugStringify(oldValue) : oldValue}${db} ` +
|
|
639
|
+
`to ${YELLOW}${typeof value === 'object' ? debugStringify(value) : value}${db}`);
|
|
640
|
+
return true;
|
|
641
|
+
}
|
|
451
642
|
/**
|
|
452
643
|
* Subscribes to an attribute on a cluster.
|
|
453
644
|
*
|
|
454
645
|
* @param {ClusterId} clusterId - The ID of the cluster.
|
|
455
646
|
* @param {string} attribute - The name of the attribute to subscribe to.
|
|
456
647
|
* @param {(newValue: any, oldValue: any) => void} listener - A callback function that will be called when the attribute value changes.
|
|
457
|
-
* @param {AnsiLogger} log -
|
|
458
|
-
* @param {
|
|
459
|
-
* @returns A boolean indicating whether the subscription was successful.
|
|
460
|
-
*/
|
|
461
|
-
/*
|
|
462
|
-
subscribeAttribute(clusterId: ClusterId, attribute: string, listener: (newValue: any, oldValue: any) => void, log?: AnsiLogger, endpoint?: Endpoint): boolean {
|
|
463
|
-
if (!endpoint) endpoint = this as Endpoint;
|
|
464
|
-
|
|
465
|
-
const clusterServer = endpoint.getClusterServerById(clusterId);
|
|
466
|
-
if (!clusterServer) {
|
|
467
|
-
log?.error(`subscribeAttribute error: Cluster ${clusterId} not found on endpoint ${endpoint.name}:${endpoint.number}`);
|
|
468
|
-
return false;
|
|
469
|
-
}
|
|
470
|
-
const capitalizedAttributeName = attribute.charAt(0).toUpperCase() + attribute.slice(1);
|
|
471
|
-
if (!clusterServer.isAttributeSupportedByName(attribute) && !clusterServer.isAttributeSupportedByName(capitalizedAttributeName)) {
|
|
472
|
-
if (log) log.error(`subscribeAttribute error: Attribute ${attribute} not found on Cluster ${clusterServer.name} on endpoint ${endpoint.name}:${endpoint.number}`);
|
|
473
|
-
return false;
|
|
474
|
-
}
|
|
475
|
-
// Find the subscribe method
|
|
476
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
477
|
-
if (!(clusterServer as any)[`subscribe${capitalizedAttributeName}Attribute`]) {
|
|
478
|
-
log?.error(`subscribeAttribute error: subscribe${capitalizedAttributeName}Attribute not found on Cluster ${clusterServer.name} on endpoint ${endpoint.name}:${endpoint.number}`);
|
|
479
|
-
return false;
|
|
480
|
-
}
|
|
481
|
-
// Subscribe to the attribute
|
|
482
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-empty-object-type
|
|
483
|
-
const subscribe = (clusterServer as any)[`subscribe${capitalizedAttributeName}Attribute`] as (listener: (newValue: any, oldValue: any) => void) => {};
|
|
484
|
-
subscribe(listener);
|
|
485
|
-
log?.info(`${db}Subscribe endpoint ${or}${endpoint.name}:${endpoint.number}${db} attribute ${hk}${clusterServer.name}.${capitalizedAttributeName}${db}`);
|
|
486
|
-
return true;
|
|
487
|
-
}
|
|
488
|
-
*/
|
|
648
|
+
* @param {AnsiLogger} [log] - Optional logger for logging errors and information.
|
|
649
|
+
* @param {MatterbridgeEndpoint} [endpoint] - Optional endpoint to subscribe the attribute on. Defaults to the current endpoint.
|
|
650
|
+
* @returns {boolean} - A boolean indicating whether the subscription was successful.
|
|
651
|
+
*/
|
|
489
652
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
653
|
+
subscribeAttribute(clusterId, attribute, listener, log, endpoint) {
|
|
654
|
+
if (!endpoint)
|
|
655
|
+
endpoint = this;
|
|
656
|
+
const clusterName = this.lowercaseFirstLetter(getClusterNameById(clusterId));
|
|
657
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
658
|
+
const events = endpoint.events;
|
|
659
|
+
if (!(clusterName in events)) {
|
|
660
|
+
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}`);
|
|
494
661
|
return false;
|
|
495
662
|
}
|
|
496
|
-
|
|
497
|
-
|
|
663
|
+
attribute = this.lowercaseFirstLetter(attribute) + '$Changed';
|
|
664
|
+
if (!(attribute in events[clusterName])) {
|
|
665
|
+
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}`);
|
|
666
|
+
return false;
|
|
667
|
+
}
|
|
668
|
+
events[clusterName][attribute].on(listener);
|
|
669
|
+
log?.info(`${db}Subscribe endpoint ${or}${endpoint.id}${db}:${or}${endpoint.number}${db} attribute ${hk}${this.capitalizeFirstLetter(clusterName)}${db}.${hk}${attribute}${db}`);
|
|
670
|
+
return true;
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Triggers an event on the specified cluster.
|
|
674
|
+
*
|
|
675
|
+
* @param {ClusterId} clusterId - The ID of the cluster.
|
|
676
|
+
* @param {string} event - The name of the event to trigger.
|
|
677
|
+
* @param {Record<string, boolean | number | bigint | string | object | undefined | null>} payload - The payload to pass to the event.
|
|
678
|
+
* @param {AnsiLogger} [log] - Optional logger for logging information.
|
|
679
|
+
* @param {MatterbridgeEndpoint} [endpoint] - Optional endpoint to trigger the event on. Defaults to the current endpoint.
|
|
680
|
+
* @returns {Promise<boolean>} - A promise that resolves to a boolean indicating whether the event was successfully triggered.
|
|
681
|
+
*/
|
|
682
|
+
async triggerEvent(clusterId, event, payload, log, endpoint) {
|
|
683
|
+
if (!endpoint)
|
|
684
|
+
endpoint = this;
|
|
685
|
+
const clusterName = this.lowercaseFirstLetter(getClusterNameById(clusterId));
|
|
686
|
+
if (endpoint.construction.status !== Lifecycle.Status.Active) {
|
|
687
|
+
this.log.error(`triggerEvent ${hk}${clusterName}.${event}${er} error: Endpoint ${or}${endpoint.id}${er} is in the ${BLUE}${endpoint.construction.status}${er} state`);
|
|
498
688
|
return false;
|
|
499
689
|
}
|
|
500
|
-
// Find the command
|
|
501
690
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
502
|
-
const
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
value.handler = handler;
|
|
507
|
-
this.log.info(`${db}Command handler added for endpoint ${or}${this.id}:${this.number}${db} ${hk}${clusterServer.name}.${command}${db}`);
|
|
508
|
-
return true;
|
|
509
|
-
}
|
|
691
|
+
const events = endpoint.events;
|
|
692
|
+
if (!(clusterName in events) || !(event in events[clusterName])) {
|
|
693
|
+
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}`);
|
|
694
|
+
return false;
|
|
510
695
|
}
|
|
511
|
-
|
|
512
|
-
|
|
696
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
697
|
+
// @ts-ignore
|
|
698
|
+
await endpoint.act((agent) => agent[clusterName].events[event].emit(payload, agent.context));
|
|
699
|
+
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} `);
|
|
700
|
+
return true;
|
|
701
|
+
}
|
|
702
|
+
/**
|
|
703
|
+
* Adds a command handler for the specified command.
|
|
704
|
+
*
|
|
705
|
+
* @param {keyof MatterbridgeEndpointCommands} command - The command to add the handler for.
|
|
706
|
+
* @param {(data: any) => void} handler - The handler function to execute when the command is received.
|
|
707
|
+
* @returns {void}
|
|
708
|
+
*/
|
|
709
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
710
|
+
addCommandHandler(command, handler) {
|
|
711
|
+
this.commandHandler.addHandler(command, handler);
|
|
513
712
|
}
|
|
514
713
|
/**
|
|
515
714
|
* Serializes the Matterbridge device into a serialized object.
|
|
@@ -517,64 +716,69 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
517
716
|
* @param pluginName - The name of the plugin.
|
|
518
717
|
* @returns The serialized Matterbridge device object.
|
|
519
718
|
*/
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
719
|
+
serialize() {
|
|
720
|
+
return undefined;
|
|
721
|
+
/*
|
|
722
|
+
if (!this.serialNumber || !this.deviceName || !this.uniqueId) return;
|
|
723
|
+
const cluster = this.getClusterServer(BasicInformationCluster) ?? this.getClusterServer(BridgedDeviceBasicInformationCluster);
|
|
724
|
+
if (!cluster) return;
|
|
725
|
+
const serialized: SerializedMatterbridgeDevice = {
|
|
726
|
+
pluginName: this.plugin ?? 'Unknown',
|
|
727
|
+
serialNumber: this.serialNumber,
|
|
728
|
+
deviceName: this.deviceName,
|
|
729
|
+
uniqueId: this.uniqueId,
|
|
730
|
+
productName: cluster.attributes.productName?.getLocal(),
|
|
731
|
+
vendorId: cluster.attributes.vendorId?.getLocal(),
|
|
732
|
+
vendorName: cluster.attributes.vendorName?.getLocal(),
|
|
733
|
+
deviceTypes: Array.from(this.deviceTypes.values()),
|
|
734
|
+
endpoint: this.number,
|
|
735
|
+
endpointName: this.id,
|
|
736
|
+
clusterServersId: [],
|
|
737
|
+
};
|
|
738
|
+
this.getAllClusterServers().forEach((clusterServer) => {
|
|
739
|
+
serialized.clusterServersId.push(clusterServer.id);
|
|
740
|
+
});
|
|
741
|
+
return serialized;
|
|
742
|
+
*/
|
|
743
|
+
}
|
|
544
744
|
/**
|
|
545
745
|
* Deserializes the device into a serialized object.
|
|
546
746
|
*
|
|
547
747
|
* @returns The deserialized MatterbridgeDevice.
|
|
548
748
|
*/
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
749
|
+
static deserialize(serializedDevice) {
|
|
750
|
+
return undefined;
|
|
751
|
+
/*
|
|
752
|
+
const device = new MatterbridgeDevice(serializedDevice.deviceTypes);
|
|
753
|
+
device.serialNumber = serializedDevice.serialNumber;
|
|
754
|
+
device.deviceName = serializedDevice.deviceName;
|
|
755
|
+
device.uniqueId = serializedDevice.uniqueId;
|
|
756
|
+
for (const clusterId of serializedDevice.clusterServersId) {
|
|
757
|
+
if (clusterId === BasicInformationCluster.id)
|
|
758
|
+
device.createDefaultBasicInformationClusterServer(
|
|
759
|
+
serializedDevice.deviceName,
|
|
760
|
+
serializedDevice.serialNumber,
|
|
761
|
+
serializedDevice.vendorId ?? 0xfff1,
|
|
762
|
+
serializedDevice.vendorName ?? 'Matterbridge',
|
|
763
|
+
serializedDevice.productId ?? 0x8000,
|
|
764
|
+
serializedDevice.productName ?? 'Matterbridge device',
|
|
765
|
+
);
|
|
766
|
+
else if (clusterId === BridgedDeviceBasicInformationCluster.id)
|
|
767
|
+
device.createDefaultBridgedDeviceBasicInformationClusterServer(
|
|
768
|
+
serializedDevice.deviceName,
|
|
769
|
+
serializedDevice.serialNumber,
|
|
770
|
+
serializedDevice.vendorId ?? 0xfff1,
|
|
771
|
+
serializedDevice.vendorName ?? 'Matterbridge',
|
|
772
|
+
serializedDevice.productName ?? 'Matterbridge device',
|
|
773
|
+
);
|
|
774
|
+
else device.addClusterServerFromList(device, [clusterId]);
|
|
775
|
+
}
|
|
776
|
+
return device;
|
|
777
|
+
*/
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* From here copy paste from MatterbridgeDevice
|
|
781
|
+
*/
|
|
578
782
|
/**
|
|
579
783
|
* Get a default IdentifyCluster server.
|
|
580
784
|
*/
|
|
@@ -676,6 +880,18 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
676
880
|
* @param hardwareVersionString - The hardware version string of the device. Default is 'v.1.0.0'.
|
|
677
881
|
*/
|
|
678
882
|
getDefaultBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productId, productName, softwareVersion = 1, softwareVersionString = '1.0.0', hardwareVersion = 1, hardwareVersionString = '1.0.0') {
|
|
883
|
+
this.log.logName = deviceName;
|
|
884
|
+
this.deviceName = deviceName;
|
|
885
|
+
this.serialNumber = serialNumber;
|
|
886
|
+
this.uniqueId = this.createUniqueId(deviceName, serialNumber, vendorName, productName);
|
|
887
|
+
this.productId = productId;
|
|
888
|
+
this.productName = productName;
|
|
889
|
+
this.vendorId = vendorId;
|
|
890
|
+
this.vendorName = vendorName;
|
|
891
|
+
this.softwareVersion = softwareVersion;
|
|
892
|
+
this.softwareVersionString = softwareVersionString;
|
|
893
|
+
this.hardwareVersion = hardwareVersion;
|
|
894
|
+
this.hardwareVersionString = hardwareVersionString;
|
|
679
895
|
return ClusterServer(BasicInformationCluster, {
|
|
680
896
|
dataModelRevision: 1,
|
|
681
897
|
location: 'XX',
|
|
@@ -717,10 +933,8 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
717
933
|
* @param hardwareVersionString - The hardware version string of the device. Default is 'v.1.0.0'.
|
|
718
934
|
*/
|
|
719
935
|
createDefaultBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productId, productName, softwareVersion = 1, softwareVersionString = '1.0.0', hardwareVersion = 1, hardwareVersionString = '1.0.0') {
|
|
720
|
-
this.deviceName = deviceName;
|
|
721
|
-
this.serialNumber = serialNumber;
|
|
722
|
-
this.uniqueId = this.createUniqueId(deviceName, serialNumber, vendorName, productName);
|
|
723
936
|
if (MatterbridgeEndpoint.bridgeMode === 'bridge') {
|
|
937
|
+
this.addDeviceType(bridgedNode);
|
|
724
938
|
this.createDefaultBridgedDeviceBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productName, softwareVersion, softwareVersionString, hardwareVersion, hardwareVersionString);
|
|
725
939
|
return;
|
|
726
940
|
}
|
|
@@ -740,6 +954,18 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
740
954
|
* @param hardwareVersionString - The hardware version string of the device. Default is 'v.1.0.0'.
|
|
741
955
|
*/
|
|
742
956
|
getDefaultBridgedDeviceBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productName, softwareVersion = 1, softwareVersionString = '1.0.0', hardwareVersion = 1, hardwareVersionString = '1.0.0') {
|
|
957
|
+
this.log.logName = deviceName;
|
|
958
|
+
this.deviceName = deviceName;
|
|
959
|
+
this.serialNumber = serialNumber;
|
|
960
|
+
this.uniqueId = this.createUniqueId(deviceName, serialNumber, vendorName, productName);
|
|
961
|
+
this.productId = undefined;
|
|
962
|
+
this.productName = productName;
|
|
963
|
+
this.vendorId = vendorId;
|
|
964
|
+
this.vendorName = vendorName;
|
|
965
|
+
this.softwareVersion = softwareVersion;
|
|
966
|
+
this.softwareVersionString = softwareVersionString;
|
|
967
|
+
this.hardwareVersion = hardwareVersion;
|
|
968
|
+
this.hardwareVersionString = hardwareVersionString;
|
|
743
969
|
return ClusterServer(BridgedDeviceBasicInformationCluster, {
|
|
744
970
|
vendorId: vendorId !== undefined ? VendorId(vendorId) : undefined, // 4874
|
|
745
971
|
vendorName: vendorName.slice(0, 32),
|
|
@@ -774,9 +1000,6 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
774
1000
|
* @param hardwareVersionString - The hardware version string of the device. Default is 'v.1.0.0'.
|
|
775
1001
|
*/
|
|
776
1002
|
createDefaultBridgedDeviceBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productName, softwareVersion = 1, softwareVersionString = '1.0.0', hardwareVersion = 1, hardwareVersionString = '1.0.0') {
|
|
777
|
-
this.deviceName = deviceName;
|
|
778
|
-
this.serialNumber = serialNumber;
|
|
779
|
-
this.uniqueId = this.createUniqueId(deviceName, serialNumber, vendorName, productName);
|
|
780
1003
|
this.addClusterServer(this.getDefaultBridgedDeviceBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productName, softwareVersion, softwareVersionString, hardwareVersion, hardwareVersionString));
|
|
781
1004
|
}
|
|
782
1005
|
/**
|
|
@@ -821,7 +1044,7 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
821
1044
|
getDefaultElectricalPowerMeasurementClusterServer(voltage = null, current = null, power = null, frequency = null) {
|
|
822
1045
|
return ClusterServer(ElectricalPowerMeasurementCluster.with(ElectricalPowerMeasurement.Feature.AlternatingCurrent), {
|
|
823
1046
|
powerMode: ElectricalPowerMeasurement.PowerMode.Ac,
|
|
824
|
-
numberOfMeasurementTypes:
|
|
1047
|
+
numberOfMeasurementTypes: 4,
|
|
825
1048
|
accuracy: [
|
|
826
1049
|
{
|
|
827
1050
|
measurementType: MeasurementType.Voltage,
|
|
@@ -858,42 +1081,6 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
858
1081
|
frequency: frequency,
|
|
859
1082
|
}, {}, {});
|
|
860
1083
|
}
|
|
861
|
-
/**
|
|
862
|
-
* Creates a default Dummy Thread Network Diagnostics Cluster server.
|
|
863
|
-
* @deprecated This method is deprecated and is only used for testing.
|
|
864
|
-
*
|
|
865
|
-
* @remarks
|
|
866
|
-
* This method adds a cluster server used only to give the networkName to Eve app.
|
|
867
|
-
*
|
|
868
|
-
* @returns void
|
|
869
|
-
*/
|
|
870
|
-
createDefaultDummyThreadNetworkDiagnosticsClusterServer() {
|
|
871
|
-
this.addClusterServer(ClusterServer(ThreadNetworkDiagnosticsCluster.with(ThreadNetworkDiagnostics.Feature.PacketCounts, ThreadNetworkDiagnostics.Feature.ErrorCounts), {
|
|
872
|
-
channel: 1,
|
|
873
|
-
routingRole: ThreadNetworkDiagnostics.RoutingRole.Router,
|
|
874
|
-
networkName: 'MyMatterThread',
|
|
875
|
-
panId: 0,
|
|
876
|
-
extendedPanId: 0,
|
|
877
|
-
meshLocalPrefix: null,
|
|
878
|
-
neighborTable: [],
|
|
879
|
-
routeTable: [],
|
|
880
|
-
partitionId: null,
|
|
881
|
-
weighting: null,
|
|
882
|
-
dataVersion: null,
|
|
883
|
-
stableDataVersion: null,
|
|
884
|
-
leaderRouterId: null,
|
|
885
|
-
securityPolicy: null,
|
|
886
|
-
channelPage0Mask: null,
|
|
887
|
-
operationalDatasetComponents: null,
|
|
888
|
-
overrunCount: 0,
|
|
889
|
-
activeNetworkFaultsList: [],
|
|
890
|
-
}, {
|
|
891
|
-
resetCounts: async (data) => {
|
|
892
|
-
this.log.debug('Matter command: resetCounts');
|
|
893
|
-
await this.commandHandler.executeHandler('resetCounts', data);
|
|
894
|
-
},
|
|
895
|
-
}, {}));
|
|
896
|
-
}
|
|
897
1084
|
/**
|
|
898
1085
|
* Get a default OnOff cluster server.
|
|
899
1086
|
*
|
|
@@ -921,6 +1108,7 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
921
1108
|
* Creates a default OnOff cluster server.
|
|
922
1109
|
*
|
|
923
1110
|
* @param onOff - The initial state of the OnOff cluster (default: false).
|
|
1111
|
+
* @returns {void}
|
|
924
1112
|
*/
|
|
925
1113
|
createDefaultOnOffClusterServer(onOff = false) {
|
|
926
1114
|
this.addClusterServer(this.getDefaultOnOffClusterServer(onOff));
|
|
@@ -928,12 +1116,17 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
928
1116
|
/**
|
|
929
1117
|
* Get a default level control cluster server.
|
|
930
1118
|
*
|
|
931
|
-
* @param currentLevel - The current level (default:
|
|
1119
|
+
* @param currentLevel - The current level (default: 254).
|
|
1120
|
+
* @param minLevel - The minimum level (default: 0).
|
|
1121
|
+
* @param maxLevel - The maximum level (default: 254).
|
|
1122
|
+
* @param onLevel - The on level (default: null).
|
|
932
1123
|
*/
|
|
933
|
-
getDefaultLevelControlClusterServer(currentLevel = 0) {
|
|
1124
|
+
getDefaultLevelControlClusterServer(currentLevel = 254, minLevel = 0, maxLevel = 254, onLevel = null) {
|
|
934
1125
|
return ClusterServer(LevelControlCluster.with(LevelControl.Feature.OnOff), {
|
|
935
1126
|
currentLevel,
|
|
936
|
-
|
|
1127
|
+
minLevel,
|
|
1128
|
+
maxLevel,
|
|
1129
|
+
onLevel,
|
|
937
1130
|
options: {
|
|
938
1131
|
executeIfOff: false,
|
|
939
1132
|
coupleColorTempToLevel: false,
|
|
@@ -970,10 +1163,13 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
970
1163
|
/**
|
|
971
1164
|
* Creates a default level control cluster server.
|
|
972
1165
|
*
|
|
973
|
-
* @param currentLevel - The current level (default:
|
|
1166
|
+
* @param currentLevel - The current level (default: 254).
|
|
1167
|
+
* @param minLevel - The minimum level (default: 0).
|
|
1168
|
+
* @param maxLevel - The maximum level (default: 254).
|
|
1169
|
+
* @param onLevel - The on level (default: null).
|
|
974
1170
|
*/
|
|
975
|
-
createDefaultLevelControlClusterServer(currentLevel = 0) {
|
|
976
|
-
this.addClusterServer(this.getDefaultLevelControlClusterServer(currentLevel));
|
|
1171
|
+
createDefaultLevelControlClusterServer(currentLevel = 254, minLevel = 0, maxLevel = 254, onLevel = null) {
|
|
1172
|
+
this.addClusterServer(this.getDefaultLevelControlClusterServer(currentLevel, minLevel, maxLevel, onLevel));
|
|
977
1173
|
}
|
|
978
1174
|
/**
|
|
979
1175
|
* Get a default color control cluster server.
|
|
@@ -986,7 +1182,7 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
986
1182
|
* @param colorTempPhysicalMinMireds - The physical minimum color temperature in mireds.
|
|
987
1183
|
* @param colorTempPhysicalMaxMireds - The physical maximum color temperature in mireds.
|
|
988
1184
|
*/
|
|
989
|
-
|
|
1185
|
+
getDefaultColorControlClusterServer(currentX = 0, currentY = 0, currentHue = 0, currentSaturation = 0, colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
|
|
990
1186
|
return ClusterServer(ColorControlCluster.with(ColorControl.Feature.Xy, ColorControl.Feature.HueSaturation, ColorControl.Feature.ColorTemperature), {
|
|
991
1187
|
colorMode: ColorControl.ColorMode.CurrentHueAndCurrentSaturation,
|
|
992
1188
|
enhancedColorMode: ColorControl.EnhancedColorMode.CurrentHueAndCurrentSaturation,
|
|
@@ -1002,6 +1198,8 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1002
1198
|
colorTemperatureMireds,
|
|
1003
1199
|
colorTempPhysicalMinMireds,
|
|
1004
1200
|
colorTempPhysicalMaxMireds,
|
|
1201
|
+
coupleColorTempToLevelMinMireds: colorTempPhysicalMinMireds,
|
|
1202
|
+
startUpColorTemperatureMireds: null,
|
|
1005
1203
|
}, {
|
|
1006
1204
|
moveToColor: async (data) => {
|
|
1007
1205
|
this.log.debug('Matter command: moveToColor request:', data.request, 'attributes.currentX:', data.attributes.currentX.getLocal(), 'attributes.currentY:', data.attributes.currentY.getLocal());
|
|
@@ -1063,14 +1261,15 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1063
1261
|
* @param colorTempPhysicalMinMireds - The physical minimum color temperature in mireds.
|
|
1064
1262
|
* @param colorTempPhysicalMaxMireds - The physical maximum color temperature in mireds.
|
|
1065
1263
|
*/
|
|
1066
|
-
|
|
1067
|
-
this.addClusterServer(this.
|
|
1264
|
+
createDefaultColorControlClusterServer(currentX = 0, currentY = 0, currentHue = 0, currentSaturation = 0, colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
|
|
1265
|
+
this.addClusterServer(this.getDefaultColorControlClusterServer(currentX, currentY, currentHue, currentSaturation, colorTemperatureMireds, colorTempPhysicalMinMireds, colorTempPhysicalMaxMireds));
|
|
1068
1266
|
}
|
|
1267
|
+
isColorControlConfigured = false;
|
|
1069
1268
|
/**
|
|
1070
1269
|
* Configures the color control cluster for a device.
|
|
1071
1270
|
*
|
|
1072
|
-
* @remark This method must be called only after creating the cluster with
|
|
1073
|
-
* and before starting the matter
|
|
1271
|
+
* @remark This method must be called only after creating the cluster with getDefaultColorControlClusterServer or createDefaultColorControlClusterServer
|
|
1272
|
+
* and before starting the matter node.
|
|
1074
1273
|
*
|
|
1075
1274
|
* @param {boolean} hueSaturation - A boolean indicating whether the device supports hue and saturation control.
|
|
1076
1275
|
* @param {boolean} xy - A boolean indicating whether the device supports XY control.
|
|
@@ -1078,15 +1277,27 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1078
1277
|
* @param {ColorControl.ColorMode} colorMode - An optional parameter specifying the color mode of the device.
|
|
1079
1278
|
* @param {Endpoint} endpoint - An optional parameter specifying the endpoint to configure. If not provided, the device endpoint will be used.
|
|
1080
1279
|
*/
|
|
1081
|
-
configureColorControlCluster(hueSaturation, xy, colorTemperature, colorMode, endpoint) {
|
|
1280
|
+
async configureColorControlCluster(hueSaturation, xy, colorTemperature, colorMode, endpoint) {
|
|
1082
1281
|
if (!endpoint)
|
|
1083
1282
|
endpoint = this;
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
if (
|
|
1087
|
-
|
|
1088
|
-
|
|
1283
|
+
if (this.isColorControlConfigured)
|
|
1284
|
+
return;
|
|
1285
|
+
if (endpoint.construction.status !== Lifecycle.Status.Active) {
|
|
1286
|
+
this.log.debug(`**configureColorControlCluster() delaying for endpoint construction ${endpoint.construction.status}`);
|
|
1287
|
+
setTimeout(async () => {
|
|
1288
|
+
await endpoint.configureColorControlCluster(hueSaturation, xy, colorTemperature, colorMode, endpoint);
|
|
1289
|
+
this.isColorControlConfigured = true;
|
|
1290
|
+
}, 500);
|
|
1291
|
+
return;
|
|
1089
1292
|
}
|
|
1293
|
+
this.log.debug(`**configureColorControlCluster()`);
|
|
1294
|
+
await endpoint.setAttribute(ColorControlCluster.id, 'featureMap', { hueSaturation, enhancedHue: false, colorLoop: false, xy, colorTemperature }, this.log, endpoint);
|
|
1295
|
+
await endpoint.setAttribute(ColorControlCluster.id, 'colorCapabilities', { hueSaturation, enhancedHue: false, colorLoop: false, xy, colorTemperature }, this.log, endpoint);
|
|
1296
|
+
if (isValidNumber(colorMode, ColorControl.ColorMode.CurrentHueAndCurrentSaturation, ColorControl.ColorMode.ColorTemperatureMireds)) {
|
|
1297
|
+
await endpoint.setAttribute(ColorControlCluster.id, 'colorMode', colorMode, this.log, endpoint);
|
|
1298
|
+
await endpoint.setAttribute(ColorControlCluster.id, 'enhancedColorMode', colorMode, this.log, endpoint);
|
|
1299
|
+
}
|
|
1300
|
+
this.isColorControlConfigured = true;
|
|
1090
1301
|
}
|
|
1091
1302
|
/**
|
|
1092
1303
|
* Configures the color control mode for the device.
|
|
@@ -1094,18 +1305,18 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1094
1305
|
* @param {ColorControl.ColorMode} colorMode - The color mode to set.
|
|
1095
1306
|
* @param {Endpoint} endpoint - The optional endpoint to configure. If not provided, the method will configure the current endpoint.
|
|
1096
1307
|
*/
|
|
1097
|
-
configureColorControlMode(colorMode, endpoint) {
|
|
1308
|
+
async configureColorControlMode(colorMode, endpoint) {
|
|
1098
1309
|
if (!endpoint)
|
|
1099
1310
|
endpoint = this;
|
|
1100
|
-
if (colorMode
|
|
1101
|
-
endpoint.
|
|
1102
|
-
endpoint.
|
|
1311
|
+
if (isValidNumber(colorMode, ColorControl.ColorMode.CurrentHueAndCurrentSaturation, ColorControl.ColorMode.ColorTemperatureMireds)) {
|
|
1312
|
+
await endpoint.setAttribute(ColorControlCluster.id, 'colorMode', colorMode, this.log, endpoint);
|
|
1313
|
+
await endpoint.setAttribute(ColorControlCluster.id, 'enhancedColorMode', colorMode, this.log, endpoint);
|
|
1103
1314
|
}
|
|
1104
1315
|
}
|
|
1105
1316
|
/**
|
|
1106
1317
|
* Get a default window covering cluster server.
|
|
1107
1318
|
*
|
|
1108
|
-
* @param positionPercent100ths - The position percentage in 100ths (0-10000). Defaults to 0.
|
|
1319
|
+
* @param positionPercent100ths - The position percentage in 100ths (0-10000). Defaults to 0. Matter uses 10000 = fully closed 0 = fully opened.
|
|
1109
1320
|
*/
|
|
1110
1321
|
getDefaultWindowCoveringClusterServer(positionPercent100ths) {
|
|
1111
1322
|
return ClusterServer(WindowCoveringCluster.with(WindowCovering.Feature.Lift, WindowCovering.Feature.PositionAwareLift), {
|
|
@@ -1124,8 +1335,6 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1124
1335
|
mode: { motorDirectionReversed: false, calibrationMode: false, maintenanceMode: false, ledFeedback: false },
|
|
1125
1336
|
targetPositionLiftPercent100ths: positionPercent100ths ?? 0, // 0 Fully open 10000 fully closed
|
|
1126
1337
|
currentPositionLiftPercent100ths: positionPercent100ths ?? 0, // 0 Fully open 10000 fully closed
|
|
1127
|
-
// installedClosedLimitLift: 10000,
|
|
1128
|
-
// installedOpenLimitLift: 0,
|
|
1129
1338
|
}, {
|
|
1130
1339
|
upOrOpen: async (data) => {
|
|
1131
1340
|
this.log.debug('Matter command: upOrOpen');
|
|
@@ -1149,7 +1358,7 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1149
1358
|
/**
|
|
1150
1359
|
* Creates a default window covering cluster server.
|
|
1151
1360
|
*
|
|
1152
|
-
* @param positionPercent100ths - The position percentage in 100ths (0-10000). Defaults to 0.
|
|
1361
|
+
* @param positionPercent100ths - The position percentage in 100ths (0-10000). Defaults to 0. Matter uses 10000 = fully closed 0 = fully opened.
|
|
1153
1362
|
*/
|
|
1154
1363
|
createDefaultWindowCoveringClusterServer(positionPercent100ths) {
|
|
1155
1364
|
this.addClusterServer(this.getDefaultWindowCoveringClusterServer(positionPercent100ths));
|
|
@@ -1158,22 +1367,19 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1158
1367
|
* Sets the window covering target position as the current position and stops the movement.
|
|
1159
1368
|
* @param {Endpoint} endpoint - The endpoint on which to set the window covering (default the device endpoint).
|
|
1160
1369
|
*/
|
|
1161
|
-
setWindowCoveringTargetAsCurrentAndStopped(endpoint) {
|
|
1370
|
+
async setWindowCoveringTargetAsCurrentAndStopped(endpoint) {
|
|
1162
1371
|
if (!endpoint)
|
|
1163
1372
|
endpoint = this;
|
|
1164
|
-
const
|
|
1165
|
-
if (
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
tilt: WindowCovering.MovementStatus.Stopped,
|
|
1173
|
-
});
|
|
1174
|
-
}
|
|
1175
|
-
this.log.debug(`Set WindowCovering currentPositionLiftPercent100ths and targetPositionLiftPercent100ths to ${position} and operationalStatus to Stopped.`);
|
|
1373
|
+
const position = endpoint.getAttribute(WindowCoveringCluster.id, 'currentPositionLiftPercent100ths', this.log, endpoint); // windowCoveringCluster.getCurrentPositionLiftPercent100thsAttribute();
|
|
1374
|
+
if (position !== null) {
|
|
1375
|
+
await endpoint.setAttribute(WindowCoveringCluster.id, 'targetPositionLiftPercent100ths', position, this.log, endpoint);
|
|
1376
|
+
await endpoint.setAttribute(WindowCoveringCluster.id, 'operationalStatus', {
|
|
1377
|
+
global: WindowCovering.MovementStatus.Stopped,
|
|
1378
|
+
lift: WindowCovering.MovementStatus.Stopped,
|
|
1379
|
+
tilt: WindowCovering.MovementStatus.Stopped,
|
|
1380
|
+
}, this.log, endpoint);
|
|
1176
1381
|
}
|
|
1382
|
+
this.log.debug(`Set WindowCovering currentPositionLiftPercent100ths and targetPositionLiftPercent100ths to ${position} and operationalStatus to Stopped.`);
|
|
1177
1383
|
}
|
|
1178
1384
|
/**
|
|
1179
1385
|
* Sets the current and target status of a window covering.
|
|
@@ -1182,19 +1388,16 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1182
1388
|
* @param {WindowCovering.MovementStatus} status - The movement status of the window covering.
|
|
1183
1389
|
* @param {Endpoint} endpoint - The endpoint on which to set the window covering (default the device endpoint).
|
|
1184
1390
|
*/
|
|
1185
|
-
setWindowCoveringCurrentTargetStatus(current, target, status, endpoint) {
|
|
1391
|
+
async setWindowCoveringCurrentTargetStatus(current, target, status, endpoint) {
|
|
1186
1392
|
if (!endpoint)
|
|
1187
1393
|
endpoint = this;
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
tilt: status,
|
|
1196
|
-
});
|
|
1197
|
-
}
|
|
1394
|
+
await endpoint.setAttribute(WindowCoveringCluster.id, 'currentPositionLiftPercent100ths', current, this.log, endpoint);
|
|
1395
|
+
await endpoint.setAttribute(WindowCoveringCluster.id, 'targetPositionLiftPercent100ths', target, this.log, endpoint);
|
|
1396
|
+
await endpoint.setAttribute(WindowCoveringCluster.id, 'operationalStatus', {
|
|
1397
|
+
global: status,
|
|
1398
|
+
lift: status,
|
|
1399
|
+
tilt: status,
|
|
1400
|
+
}, this.log, endpoint);
|
|
1198
1401
|
this.log.debug(`Set WindowCovering currentPositionLiftPercent100ths: ${current}, targetPositionLiftPercent100ths: ${target} and operationalStatus: ${status}.`);
|
|
1199
1402
|
}
|
|
1200
1403
|
/**
|
|
@@ -1202,13 +1405,14 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1202
1405
|
* @param {WindowCovering.MovementStatus} status - The movement status to set.
|
|
1203
1406
|
* @param {Endpoint} endpoint - The endpoint on which to set the window covering (default the device endpoint).
|
|
1204
1407
|
*/
|
|
1205
|
-
setWindowCoveringStatus(status, endpoint) {
|
|
1408
|
+
async setWindowCoveringStatus(status, endpoint) {
|
|
1206
1409
|
if (!endpoint)
|
|
1207
1410
|
endpoint = this;
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1411
|
+
await endpoint.setAttribute(WindowCoveringCluster.id, 'operationalStatus', {
|
|
1412
|
+
global: status,
|
|
1413
|
+
lift: status,
|
|
1414
|
+
tilt: status,
|
|
1415
|
+
}, this.log, endpoint);
|
|
1212
1416
|
this.log.debug(`Set WindowCovering operationalStatus: ${status}`);
|
|
1213
1417
|
}
|
|
1214
1418
|
/**
|
|
@@ -1220,10 +1424,7 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1220
1424
|
getWindowCoveringStatus(endpoint) {
|
|
1221
1425
|
if (!endpoint)
|
|
1222
1426
|
endpoint = this;
|
|
1223
|
-
const
|
|
1224
|
-
if (!windowCovering)
|
|
1225
|
-
return undefined;
|
|
1226
|
-
const status = windowCovering.getOperationalStatusAttribute();
|
|
1427
|
+
const status = endpoint.getAttribute(WindowCoveringCluster.id, 'operationalStatus', this.log, endpoint);
|
|
1227
1428
|
this.log.debug(`Get WindowCovering operationalStatus: ${status.global}`);
|
|
1228
1429
|
return status.global;
|
|
1229
1430
|
}
|
|
@@ -1233,14 +1434,11 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1233
1434
|
* @param position - The position to set, specified as a number.
|
|
1234
1435
|
* @param {Endpoint} endpoint - The endpoint on which to set the window covering (default the device endpoint).
|
|
1235
1436
|
*/
|
|
1236
|
-
setWindowCoveringTargetAndCurrentPosition(position, endpoint) {
|
|
1437
|
+
async setWindowCoveringTargetAndCurrentPosition(position, endpoint) {
|
|
1237
1438
|
if (!endpoint)
|
|
1238
1439
|
endpoint = this;
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
return;
|
|
1242
|
-
windowCovering.setCurrentPositionLiftPercent100thsAttribute(position);
|
|
1243
|
-
windowCovering.setTargetPositionLiftPercent100thsAttribute(position);
|
|
1440
|
+
await endpoint.setAttribute(WindowCoveringCluster.id, 'currentPositionLiftPercent100ths', position, this.log, endpoint);
|
|
1441
|
+
await endpoint.setAttribute(WindowCoveringCluster.id, 'targetPositionLiftPercent100ths', position, this.log, endpoint);
|
|
1244
1442
|
this.log.debug(`Set WindowCovering currentPositionLiftPercent100ths: ${position} and targetPositionLiftPercent100ths: ${position}.`);
|
|
1245
1443
|
}
|
|
1246
1444
|
/**
|
|
@@ -1341,7 +1539,7 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1341
1539
|
* @param {Endpoint} endpoint - The endpoint on which to trigger the event (default the device endpoint).
|
|
1342
1540
|
* @returns {void}
|
|
1343
1541
|
*/
|
|
1344
|
-
triggerSwitchEvent(event, log, endpoint) {
|
|
1542
|
+
async triggerSwitchEvent(event, log, endpoint) {
|
|
1345
1543
|
if (!endpoint)
|
|
1346
1544
|
endpoint = this;
|
|
1347
1545
|
if (['Single', 'Double', 'Long'].includes(event)) {
|
|
@@ -1355,38 +1553,38 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1355
1553
|
return false;
|
|
1356
1554
|
}
|
|
1357
1555
|
if (event === 'Single') {
|
|
1358
|
-
cluster.
|
|
1359
|
-
cluster.
|
|
1360
|
-
cluster.
|
|
1361
|
-
cluster.
|
|
1362
|
-
cluster.
|
|
1363
|
-
cluster.
|
|
1556
|
+
await endpoint.setAttribute(cluster.id, 'currentPosition', 1, log);
|
|
1557
|
+
endpoint.triggerEvent(cluster.id, 'initialPress', { newPosition: 1 }, log);
|
|
1558
|
+
await endpoint.setAttribute(cluster.id, 'currentPosition', 0, log);
|
|
1559
|
+
endpoint.triggerEvent(cluster.id, 'shortRelease', { previousPosition: 1 }, log);
|
|
1560
|
+
await endpoint.setAttribute(cluster.id, 'currentPosition', 0, log);
|
|
1561
|
+
endpoint.triggerEvent(cluster.id, 'multiPressComplete', { previousPosition: 1, totalNumberOfPressesCounted: 1 }, log);
|
|
1364
1562
|
log?.info(`${db}Trigger endpoint ${or}${endpoint.id}:${endpoint.number}${db} event ${hk}${cluster.name}.SinglePress${db}`);
|
|
1365
1563
|
}
|
|
1366
1564
|
if (event === 'Double') {
|
|
1367
|
-
cluster.
|
|
1368
|
-
cluster.
|
|
1369
|
-
cluster.
|
|
1370
|
-
cluster.
|
|
1371
|
-
cluster.
|
|
1372
|
-
cluster.
|
|
1373
|
-
cluster.
|
|
1374
|
-
cluster.
|
|
1375
|
-
cluster.
|
|
1376
|
-
cluster.
|
|
1565
|
+
await endpoint.setAttribute(cluster.id, 'currentPosition', 1, log);
|
|
1566
|
+
endpoint.triggerEvent(cluster.id, 'initialPress', { newPosition: 1 }, log);
|
|
1567
|
+
await endpoint.setAttribute(cluster.id, 'currentPosition', 0, log);
|
|
1568
|
+
endpoint.triggerEvent(cluster.id, 'shortRelease', { previousPosition: 1 }, log);
|
|
1569
|
+
await endpoint.setAttribute(cluster.id, 'currentPosition', 1, log);
|
|
1570
|
+
endpoint.triggerEvent(cluster.id, 'initialPress', { newPosition: 1 }, log);
|
|
1571
|
+
endpoint.triggerEvent(cluster.id, 'multiPressOngoing', { newPosition: 1, currentNumberOfPressesCounted: 2 }, log);
|
|
1572
|
+
await endpoint.setAttribute(cluster.id, 'currentPosition', 0, log);
|
|
1573
|
+
endpoint.triggerEvent(cluster.id, 'shortRelease', { previousPosition: 1 }, log);
|
|
1574
|
+
endpoint.triggerEvent(cluster.id, 'multiPressComplete', { previousPosition: 1, totalNumberOfPressesCounted: 2 }, log);
|
|
1377
1575
|
log?.info(`${db}Trigger endpoint ${or}${endpoint.id}:${endpoint.number}${db} event ${hk}${cluster.name}.DoublePress${db}`);
|
|
1378
1576
|
}
|
|
1379
1577
|
if (event === 'Long') {
|
|
1380
|
-
cluster.
|
|
1381
|
-
cluster.
|
|
1382
|
-
cluster.
|
|
1383
|
-
cluster.
|
|
1384
|
-
cluster.
|
|
1578
|
+
await endpoint.setAttribute(cluster.id, 'currentPosition', 1, log);
|
|
1579
|
+
endpoint.triggerEvent(cluster.id, 'initialPress', { newPosition: 1 }, log);
|
|
1580
|
+
endpoint.triggerEvent(cluster.id, 'longPress', { newPosition: 1 }, log);
|
|
1581
|
+
await endpoint.setAttribute(cluster.id, 'currentPosition', 0, log);
|
|
1582
|
+
endpoint.triggerEvent(cluster.id, 'longRelease', { previousPosition: 1 }, log);
|
|
1385
1583
|
log?.info(`${db}Trigger endpoint ${or}${endpoint.id}:${endpoint.number}${db} event ${hk}${cluster.name}.LongPress${db}`);
|
|
1386
1584
|
}
|
|
1387
1585
|
}
|
|
1388
1586
|
if (['Press', 'Release'].includes(event)) {
|
|
1389
|
-
const cluster = endpoint.getClusterServer(Switch.
|
|
1587
|
+
const cluster = endpoint.getClusterServer(SwitchCluster.with(Switch.Feature.LatchingSwitch));
|
|
1390
1588
|
if (!cluster || !cluster.getFeatureMapAttribute().latchingSwitch) {
|
|
1391
1589
|
log?.error(`triggerSwitchEvent ${event} error: Switch cluster with LatchingSwitch not found on endpoint ${endpoint.id}:${endpoint.number}`);
|
|
1392
1590
|
return false;
|
|
@@ -1396,17 +1594,13 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1396
1594
|
return false;
|
|
1397
1595
|
}
|
|
1398
1596
|
if (event === 'Press') {
|
|
1399
|
-
cluster.
|
|
1400
|
-
|
|
1401
|
-
if (cluster.triggerSwitchLatchedEvent)
|
|
1402
|
-
cluster.triggerSwitchLatchedEvent({ newPosition: 1 });
|
|
1597
|
+
await endpoint.setAttribute(cluster.id, 'currentPosition', 1, log);
|
|
1598
|
+
endpoint.triggerEvent(cluster.id, 'switchLatched', { newPosition: 1 }, log);
|
|
1403
1599
|
log?.info(`${db}Trigger endpoint ${or}${endpoint.id}:${endpoint.number}${db} event ${hk}${cluster.name}.Press${db}`);
|
|
1404
1600
|
}
|
|
1405
1601
|
if (event === 'Release') {
|
|
1406
|
-
cluster.
|
|
1407
|
-
|
|
1408
|
-
if (cluster.triggerSwitchLatchedEvent)
|
|
1409
|
-
cluster.triggerSwitchLatchedEvent({ newPosition: 0 });
|
|
1602
|
+
await endpoint.setAttribute(cluster.id, 'currentPosition', 0, log);
|
|
1603
|
+
endpoint.triggerEvent(cluster.id, 'switchLatched', { newPosition: 0 }, log);
|
|
1410
1604
|
log?.info(`${db}Trigger endpoint ${or}${endpoint.id}:${endpoint.number}${db} event ${hk}${cluster.name}.Release${db}`);
|
|
1411
1605
|
}
|
|
1412
1606
|
}
|
|
@@ -1438,10 +1632,12 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1438
1632
|
/**
|
|
1439
1633
|
* Creates a default mode select cluster server.
|
|
1440
1634
|
*
|
|
1441
|
-
* @
|
|
1442
|
-
*
|
|
1443
|
-
*
|
|
1635
|
+
* @param description - The description of the cluster server.
|
|
1636
|
+
* @param supportedModes - The supported modes for the cluster server.
|
|
1637
|
+
* @param currentMode - The current mode of the cluster server. Defaults to 0.
|
|
1638
|
+
* @param startUpMode - The startup mode of the cluster server. Defaults to 0.
|
|
1444
1639
|
* @param endpoint - The endpoint to add the cluster server to. Defaults to `this` if not provided.
|
|
1640
|
+
*
|
|
1445
1641
|
*/
|
|
1446
1642
|
createDefaultModeSelectClusterServer(description, supportedModes, currentMode = 0, startUpMode = 0, endpoint) {
|
|
1447
1643
|
if (!endpoint)
|
|
@@ -1493,7 +1689,7 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1493
1689
|
/**
|
|
1494
1690
|
* Get a default flow measurement cluster server.
|
|
1495
1691
|
*
|
|
1496
|
-
* @param measuredValue - The measured value of the
|
|
1692
|
+
* @param measuredValue - The measured value of the flow in 10 x m/h.
|
|
1497
1693
|
*/
|
|
1498
1694
|
getDefaultFlowMeasurementClusterServer(measuredValue = 0) {
|
|
1499
1695
|
return ClusterServer(FlowMeasurementCluster, {
|
|
@@ -1506,7 +1702,7 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1506
1702
|
/**
|
|
1507
1703
|
* Creates a default flow measurement cluster server.
|
|
1508
1704
|
*
|
|
1509
|
-
* @param measuredValue - The measured value of the
|
|
1705
|
+
* @param measuredValue - The measured value of the flow in 10 x m/h.
|
|
1510
1706
|
*/
|
|
1511
1707
|
createDefaultFlowMeasurementClusterServer(measuredValue = 0) {
|
|
1512
1708
|
this.addClusterServer(this.getDefaultFlowMeasurementClusterServer(measuredValue));
|
|
@@ -1514,7 +1710,7 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1514
1710
|
/**
|
|
1515
1711
|
* Get a default temperature measurement cluster server.
|
|
1516
1712
|
*
|
|
1517
|
-
* @param measuredValue - The measured value of the temperature.
|
|
1713
|
+
* @param measuredValue - The measured value of the temperature x 100.
|
|
1518
1714
|
*/
|
|
1519
1715
|
getDefaultTemperatureMeasurementClusterServer(measuredValue = 0) {
|
|
1520
1716
|
return ClusterServer(TemperatureMeasurementCluster, {
|
|
@@ -1527,7 +1723,7 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1527
1723
|
/**
|
|
1528
1724
|
* Creates a default temperature measurement cluster server.
|
|
1529
1725
|
*
|
|
1530
|
-
* @param measuredValue - The measured value of the temperature.
|
|
1726
|
+
* @param measuredValue - The measured value of the temperature x 100.
|
|
1531
1727
|
*/
|
|
1532
1728
|
createDefaultTemperatureMeasurementClusterServer(measuredValue = 0) {
|
|
1533
1729
|
this.addClusterServer(this.getDefaultTemperatureMeasurementClusterServer(measuredValue));
|
|
@@ -1535,7 +1731,7 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1535
1731
|
/**
|
|
1536
1732
|
* Get a default RelativeHumidityMeasurementCluster server.
|
|
1537
1733
|
*
|
|
1538
|
-
* @param measuredValue - The measured value of the relative humidity.
|
|
1734
|
+
* @param measuredValue - The measured value of the relative humidity x 100.
|
|
1539
1735
|
*/
|
|
1540
1736
|
getDefaultRelativeHumidityMeasurementClusterServer(measuredValue = 0) {
|
|
1541
1737
|
return ClusterServer(RelativeHumidityMeasurementCluster, {
|
|
@@ -1548,7 +1744,7 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1548
1744
|
/**
|
|
1549
1745
|
* Creates a default RelativeHumidityMeasurementCluster server.
|
|
1550
1746
|
*
|
|
1551
|
-
* @param measuredValue - The measured value of the relative humidity.
|
|
1747
|
+
* @param measuredValue - The measured value of the relative humidity x 100.
|
|
1552
1748
|
*/
|
|
1553
1749
|
createDefaultRelativeHumidityMeasurementClusterServer(measuredValue = 0) {
|
|
1554
1750
|
this.addClusterServer(this.getDefaultRelativeHumidityMeasurementClusterServer(measuredValue));
|
|
@@ -1769,6 +1965,80 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1769
1965
|
createDefaultTvocMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
|
|
1770
1966
|
this.addClusterServer(this.getDefaultTvocMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
|
|
1771
1967
|
}
|
|
1968
|
+
/**
|
|
1969
|
+
* Get a default heating thermostat cluster server with the specified parameters.
|
|
1970
|
+
* @param {number} [localTemperature] - The local temperature value in degrees Celsius. Defaults to 23°.
|
|
1971
|
+
* @param {number} [occupiedHeatingSetpoint] - The occupied heating setpoint value in degrees Celsius. Defaults to 21°.
|
|
1972
|
+
* @param {number} [minHeatSetpointLimit] - The minimum heat setpoint limit value. Defaults to 0°.
|
|
1973
|
+
* @param {number} [maxHeatSetpointLimit] - The maximum heat setpoint limit value. Defaults to 50°.
|
|
1974
|
+
* @returns {ThermostatClusterServer} A default thermostat cluster server configured with the specified parameters.
|
|
1975
|
+
*/
|
|
1976
|
+
getDefaultHeatingThermostatClusterServer(localTemperature = 23, occupiedHeatingSetpoint = 21, minHeatSetpointLimit = 0, maxHeatSetpointLimit = 50) {
|
|
1977
|
+
return ClusterServer(ThermostatCluster.with(Thermostat.Feature.Heating), {
|
|
1978
|
+
localTemperature: localTemperature * 100,
|
|
1979
|
+
systemMode: Thermostat.SystemMode.Heat,
|
|
1980
|
+
controlSequenceOfOperation: Thermostat.ControlSequenceOfOperation.HeatingOnly,
|
|
1981
|
+
// Thermostat.Feature.Heating
|
|
1982
|
+
occupiedHeatingSetpoint: occupiedHeatingSetpoint * 100,
|
|
1983
|
+
minHeatSetpointLimit: minHeatSetpointLimit * 100,
|
|
1984
|
+
maxHeatSetpointLimit: maxHeatSetpointLimit * 100,
|
|
1985
|
+
absMinHeatSetpointLimit: minHeatSetpointLimit * 100,
|
|
1986
|
+
absMaxHeatSetpointLimit: maxHeatSetpointLimit * 100,
|
|
1987
|
+
}, {
|
|
1988
|
+
setpointRaiseLower: async (data) => {
|
|
1989
|
+
this.log.debug('Matter command: setpointRaiseLower', data.request);
|
|
1990
|
+
await this.commandHandler.executeHandler('setpointRaiseLower', data);
|
|
1991
|
+
},
|
|
1992
|
+
}, {});
|
|
1993
|
+
}
|
|
1994
|
+
/**
|
|
1995
|
+
* Creates and adds a default heating thermostat cluster server to the device.
|
|
1996
|
+
*
|
|
1997
|
+
* @param {number} [localTemperature] - The local temperature value in degrees Celsius. Defaults to 23°.
|
|
1998
|
+
* @param {number} [occupiedHeatingSetpoint] - The occupied heating setpoint value in degrees Celsius. Defaults to 21°.
|
|
1999
|
+
* @param {number} [minHeatSetpointLimit] - The minimum heat setpoint limit value. Defaults to 0°.
|
|
2000
|
+
* @param {number} [maxHeatSetpointLimit] - The maximum heat setpoint limit value. Defaults to 50°.
|
|
2001
|
+
*/
|
|
2002
|
+
createDefaultHeatingThermostatClusterServer(localTemperature = 23, occupiedHeatingSetpoint = 25, minHeatSetpointLimit = 0, maxHeatSetpointLimit = 50) {
|
|
2003
|
+
this.addClusterServer(this.getDefaultHeatingThermostatClusterServer(localTemperature, occupiedHeatingSetpoint, minHeatSetpointLimit, maxHeatSetpointLimit));
|
|
2004
|
+
}
|
|
2005
|
+
/**
|
|
2006
|
+
* Get a default cooling thermostat cluster server with the specified parameters.
|
|
2007
|
+
* @param {number} [localTemperature] - The local temperature value in degrees Celsius. Defaults to 23°.
|
|
2008
|
+
* @param {number} [occupiedCoolingSetpoint] - The occupied cooling setpoint value in degrees Celsius. Defaults to 25°.
|
|
2009
|
+
* @param {number} [minCoolSetpointLimit] - The minimum cool setpoint limit value. Defaults to 0°.
|
|
2010
|
+
* @param {number} [maxCoolSetpointLimit] - The maximum cool setpoint limit value. Defaults to 50°.
|
|
2011
|
+
* @returns {ThermostatClusterServer} A default thermostat cluster server configured with the specified parameters.
|
|
2012
|
+
*/
|
|
2013
|
+
getDefaultCoolingThermostatClusterServer(localTemperature = 23, occupiedCoolingSetpoint = 25, minCoolSetpointLimit = 0, maxCoolSetpointLimit = 50) {
|
|
2014
|
+
return ClusterServer(ThermostatCluster.with(Thermostat.Feature.Cooling), {
|
|
2015
|
+
localTemperature: localTemperature * 100,
|
|
2016
|
+
systemMode: Thermostat.SystemMode.Cool,
|
|
2017
|
+
controlSequenceOfOperation: Thermostat.ControlSequenceOfOperation.CoolingOnly,
|
|
2018
|
+
// Thermostat.Feature.Cooling
|
|
2019
|
+
occupiedCoolingSetpoint: occupiedCoolingSetpoint * 100,
|
|
2020
|
+
minCoolSetpointLimit: minCoolSetpointLimit * 100,
|
|
2021
|
+
maxCoolSetpointLimit: maxCoolSetpointLimit * 100,
|
|
2022
|
+
absMinCoolSetpointLimit: minCoolSetpointLimit * 100,
|
|
2023
|
+
absMaxCoolSetpointLimit: maxCoolSetpointLimit * 100,
|
|
2024
|
+
}, {
|
|
2025
|
+
setpointRaiseLower: async (data) => {
|
|
2026
|
+
this.log.debug('Matter command: setpointRaiseLower', data.request);
|
|
2027
|
+
await this.commandHandler.executeHandler('setpointRaiseLower', data);
|
|
2028
|
+
},
|
|
2029
|
+
}, {});
|
|
2030
|
+
}
|
|
2031
|
+
/**
|
|
2032
|
+
* Creates and adds a default cooling thermostat cluster server to the device.
|
|
2033
|
+
*
|
|
2034
|
+
* @param {number} [localTemperature] - The local temperature value in degrees Celsius. Defaults to 23°.
|
|
2035
|
+
* @param {number} [occupiedCoolingSetpoint] - The occupied cooling setpoint value in degrees Celsius. Defaults to 25°.
|
|
2036
|
+
* @param {number} [minCoolSetpointLimit] - The minimum cool setpoint limit value. Defaults to 0°.
|
|
2037
|
+
* @param {number} [maxCoolSetpointLimit] - The maximum cool setpoint limit value. Defaults to 50°.
|
|
2038
|
+
*/
|
|
2039
|
+
createDefaultCoolingThermostatClusterServer(localTemperature = 23, occupiedCoolingSetpoint = 25, minCoolSetpointLimit = 0, maxCoolSetpointLimit = 50) {
|
|
2040
|
+
this.addClusterServer(this.getDefaultCoolingThermostatClusterServer(localTemperature, occupiedCoolingSetpoint, minCoolSetpointLimit, maxCoolSetpointLimit));
|
|
2041
|
+
}
|
|
1772
2042
|
/**
|
|
1773
2043
|
* Get a default thermostat cluster server with the specified parameters.
|
|
1774
2044
|
*
|
|
@@ -1785,19 +2055,22 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1785
2055
|
getDefaultThermostatClusterServer(localTemperature = 23, occupiedHeatingSetpoint = 21, occupiedCoolingSetpoint = 25, minSetpointDeadBand = 1, minHeatSetpointLimit = 0, maxHeatSetpointLimit = 50, minCoolSetpointLimit = 0, maxCoolSetpointLimit = 50) {
|
|
1786
2056
|
return ClusterServer(ThermostatCluster.with(Thermostat.Feature.Heating, Thermostat.Feature.Cooling, Thermostat.Feature.AutoMode), {
|
|
1787
2057
|
localTemperature: localTemperature * 100,
|
|
2058
|
+
systemMode: Thermostat.SystemMode.Auto,
|
|
2059
|
+
controlSequenceOfOperation: Thermostat.ControlSequenceOfOperation.CoolingAndHeating,
|
|
2060
|
+
// Thermostat.Feature.Heating
|
|
1788
2061
|
occupiedHeatingSetpoint: occupiedHeatingSetpoint * 100,
|
|
1789
|
-
occupiedCoolingSetpoint: occupiedCoolingSetpoint * 100,
|
|
1790
2062
|
minHeatSetpointLimit: minHeatSetpointLimit * 100,
|
|
1791
2063
|
maxHeatSetpointLimit: maxHeatSetpointLimit * 100,
|
|
1792
2064
|
absMinHeatSetpointLimit: minHeatSetpointLimit * 100,
|
|
1793
2065
|
absMaxHeatSetpointLimit: maxHeatSetpointLimit * 100,
|
|
2066
|
+
// Thermostat.Feature.Cooling
|
|
2067
|
+
occupiedCoolingSetpoint: occupiedCoolingSetpoint * 100,
|
|
1794
2068
|
minCoolSetpointLimit: minCoolSetpointLimit * 100,
|
|
1795
2069
|
maxCoolSetpointLimit: maxCoolSetpointLimit * 100,
|
|
1796
2070
|
absMinCoolSetpointLimit: minCoolSetpointLimit * 100,
|
|
1797
2071
|
absMaxCoolSetpointLimit: maxCoolSetpointLimit * 100,
|
|
2072
|
+
// Thermostat.Feature.AutoMode
|
|
1798
2073
|
minSetpointDeadBand: minSetpointDeadBand * 100,
|
|
1799
|
-
systemMode: Thermostat.SystemMode.Off,
|
|
1800
|
-
controlSequenceOfOperation: Thermostat.ControlSequenceOfOperation.CoolingAndHeating,
|
|
1801
2074
|
thermostatRunningMode: Thermostat.ThermostatRunningMode.Off,
|
|
1802
2075
|
}, {
|
|
1803
2076
|
setpointRaiseLower: async (data) => {
|
|
@@ -1821,46 +2094,6 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
1821
2094
|
createDefaultThermostatClusterServer(localTemperature = 23, occupiedHeatingSetpoint = 21, occupiedCoolingSetpoint = 25, minSetpointDeadBand = 1, minHeatSetpointLimit = 0, maxHeatSetpointLimit = 50, minCoolSetpointLimit = 0, maxCoolSetpointLimit = 50) {
|
|
1822
2095
|
this.addClusterServer(this.getDefaultThermostatClusterServer(localTemperature, occupiedHeatingSetpoint, occupiedCoolingSetpoint, minSetpointDeadBand, minHeatSetpointLimit, maxHeatSetpointLimit, minCoolSetpointLimit, maxCoolSetpointLimit));
|
|
1823
2096
|
}
|
|
1824
|
-
/**
|
|
1825
|
-
* Get a default dummy time sync cluster server. Only needed to create a thermostat.
|
|
1826
|
-
*/
|
|
1827
|
-
getDefaultTimeSyncClusterServer() {
|
|
1828
|
-
return ClusterServer(TimeSynchronizationCluster.with(TimeSynchronization.Feature.TimeZone), {
|
|
1829
|
-
utcTime: null,
|
|
1830
|
-
granularity: TimeSynchronization.Granularity.NoTimeGranularity,
|
|
1831
|
-
timeZone: [{ offset: 0, validAt: 0 }],
|
|
1832
|
-
dstOffset: [],
|
|
1833
|
-
localTime: null,
|
|
1834
|
-
timeZoneDatabase: TimeSynchronization.TimeZoneDatabase.None,
|
|
1835
|
-
timeZoneListMaxSize: 1,
|
|
1836
|
-
dstOffsetListMaxSize: 1,
|
|
1837
|
-
}, {
|
|
1838
|
-
setTimeZone: async (data) => {
|
|
1839
|
-
this.log.debug('Matter command: setTimeZone', data.request);
|
|
1840
|
-
await this.commandHandler.executeHandler('setTimeZone', data);
|
|
1841
|
-
return { dstOffsetsRequired: false };
|
|
1842
|
-
},
|
|
1843
|
-
setDstOffset: async (data) => {
|
|
1844
|
-
this.log.debug('Matter command: setDstOffset', data.request);
|
|
1845
|
-
await this.commandHandler.executeHandler('setDstOffset', data);
|
|
1846
|
-
},
|
|
1847
|
-
setUtcTime: async (data) => {
|
|
1848
|
-
this.log.debug('Matter command: setUtcTime', data.request);
|
|
1849
|
-
await this.commandHandler.executeHandler('setUtcTime', data);
|
|
1850
|
-
},
|
|
1851
|
-
}, {
|
|
1852
|
-
dstTableEmpty: true,
|
|
1853
|
-
dstStatus: true,
|
|
1854
|
-
timeZoneStatus: true,
|
|
1855
|
-
timeFailure: true,
|
|
1856
|
-
});
|
|
1857
|
-
}
|
|
1858
|
-
/**
|
|
1859
|
-
* Creates a default dummy time sync cluster server. Only needed to create a thermostat.
|
|
1860
|
-
*/
|
|
1861
|
-
createDefaultTimeSyncClusterServer() {
|
|
1862
|
-
this.addClusterServer(this.getDefaultTimeSyncClusterServer());
|
|
1863
|
-
}
|
|
1864
2097
|
/**
|
|
1865
2098
|
* Returns the default SmokeCOAlarm Cluster Server.
|
|
1866
2099
|
*
|