From 084baf0886d04df6933a7c5c24a287df09bb4a72 Mon Sep 17 00:00:00 2001
From: Luligu <132135057+Luligu@users.noreply.github.com>
Date: Mon, 1 Jul 2024 12:28:58 +0200
Subject: [PATCH 1/2] Fixed nodeLabel in childbridge mode
---
.github/workflows/docker-buildx-main.yml | 2 +-
CHANGELOG.md | 9 +++++++++
package-lock.json | 4 ++--
package.json | 2 +-
src/matterbridge.ts | 20 ++++++++++++++++----
5 files changed, 29 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/docker-buildx-main.yml b/.github/workflows/docker-buildx-main.yml
index 0e36dc2c..0107ef25 100644
--- a/.github/workflows/docker-buildx-main.yml
+++ b/.github/workflows/docker-buildx-main.yml
@@ -39,7 +39,7 @@ jobs:
--platform linux/amd64,linux/arm64,linux/arm/v7 \
-f docker/Dockerfile.main \
-t luligu/matterbridge:latest \
- -t luligu/matterbridge:1.3.8 \
+ -t luligu/matterbridge:1.3.9 \
--push .
docker manifest inspect luligu/matterbridge:latest
timeout-minutes: 60
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2a9249cc..bd725090 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
If you like this project and find it useful, please consider giving it a star on GitHub at https://github.com/Luligu/matterbridge and sponsoring it.
+## [1.3.9] - 2024-07-02
+
+### Fixed
+- [matterbridge]: Fixed nodeLabel in childbridge mode
+
+
+
+
+
## [1.3.8] - 2024-07-01
### Fixed
diff --git a/package-lock.json b/package-lock.json
index cd192b3d..e8efd70f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "matterbridge",
- "version": "1.3.7",
+ "version": "1.3.8",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "matterbridge",
- "version": "1.3.7",
+ "version": "1.3.8",
"license": "Apache-2.0",
"dependencies": {
"@project-chip/matter-node.js": "^0.9.3",
diff --git a/package.json b/package.json
index 1f9392d0..a2e54480 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "matterbridge",
- "version": "1.3.8",
+ "version": "1.3.9",
"description": "Matterbridge plugin manager for Matter",
"author": "https://github.com/Luligu",
"license": "Apache-2.0",
diff --git a/src/matterbridge.ts b/src/matterbridge.ts
index 531f7ecc..98533d44 100644
--- a/src/matterbridge.ts
+++ b/src/matterbridge.ts
@@ -192,6 +192,8 @@ export class Matterbridge extends EventEmitter {
private mdnsInterface: string | undefined; // matter server mdnsInterface: 'eth0' or 'wlan0' or 'WiFi'
private port = 5540; // first commissioning server port
+ private passcode?: number; // first commissioning server passcode
+ private discriminator?: number; // first commissioning server discriminator
private log!: AnsiLogger;
private hasCleanupStarted = false;
// private plugins = new Map();
@@ -395,6 +397,10 @@ export class Matterbridge extends EventEmitter {
// Set the first port to use for the commissioning server
this.port = getIntParameter('port') ?? 5540;
+ // Set the first passcode to use for the commissioning server
+ this.passcode = getIntParameter('passcode');
+ // Set the first discriminator to use for the commissioning server
+ this.discriminator = getIntParameter('discriminator');
// Set the restart mode
if (hasParameter('service')) this.restartMode = 'service';
@@ -1147,7 +1153,8 @@ export class Matterbridge extends EventEmitter {
if (!plugin.locked) {
plugin.locked = true;
this.log.debug(`Creating commissioning server context for ${plg}${plugin.name}${db}`);
- plugin.storageContext = await this.createCommissioningServerContext(plugin.name, 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Dynamic Platform');
+ // plugin.storageContext = await this.createCommissioningServerContext(plugin.name, 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Dynamic Platform');
+ plugin.storageContext = await this.createCommissioningServerContext(plugin.name, 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, plugin.description);
this.log.debug(`Creating commissioning server for ${plg}${plugin.name}${db}`);
plugin.commissioningServer = await this.createCommisioningServer(plugin.storageContext, plugin.name);
this.log.debug(`Creating aggregator for plugin ${plg}${plugin.name}${db}`);
@@ -1986,6 +1993,7 @@ export class Matterbridge extends EventEmitter {
this.log.error('importCommissioningServerContext error: no storage manager initialized');
process.exit(1);
}
+
this.log.debug(`Importing commissioning server storage context for ${plg}${pluginName}${db}`);
const storageContext = this.storageManager.createContext(pluginName);
await storageContext.set('deviceName', basic.getNodeLabelAttribute());
@@ -2233,16 +2241,17 @@ export class Matterbridge extends EventEmitter {
const hardwareVersion = await context.get('hardwareVersion', 1);
const hardwareVersionString = await context.get('hardwareVersionString', '1.0.0');
- this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with deviceName ${deviceName} deviceType ${deviceType}(0x${deviceType.toString(16).padStart(4, '0')})`);
+ this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with deviceName '${deviceName}' deviceType ${deviceType}(0x${deviceType.toString(16).padStart(4, '0')})`);
this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with uniqueId ${uniqueId} serialNumber ${serialNumber}`);
this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with softwareVersion ${softwareVersion} softwareVersionString ${softwareVersionString}`);
this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with hardwareVersion ${hardwareVersion} hardwareVersionString ${hardwareVersionString}`);
+ this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with nodeLabel '${productName}' port ${this.port} passcode ${this.passcode} discriminator ${this.discriminator}`);
const commissioningServer = new CommissioningServer({
port: this.port++,
// listeningAddressIpv4
// listeningAddressIpv6
- passcode: undefined,
- discriminator: undefined,
+ passcode: this.passcode,
+ discriminator: this.discriminator,
deviceName,
deviceType,
basicInformation: {
@@ -2341,6 +2350,9 @@ export class Matterbridge extends EventEmitter {
}
},
});
+ if (this.passcode !== undefined) this.passcode++;
+ if (this.discriminator !== undefined) this.discriminator++;
+
commissioningServer.addCommandHandler('testEventTrigger', async ({ request: { enableKey, eventTrigger } }) => this.log.info(`testEventTrigger called on GeneralDiagnostic cluster: ${enableKey} ${eventTrigger}`));
return commissioningServer;
}
From c43fef6f38f501d5e68c2c5c82f1268d618894ea Mon Sep 17 00:00:00 2001
From: Luligu <132135057+Luligu@users.noreply.github.com>
Date: Mon, 1 Jul 2024 19:18:53 +0200
Subject: [PATCH 2/2] Fixed MeasurementClusters
---
CHANGELOG.md | 1 +
.../ElectricalPowerMeasurementCluster.ts | 8 +-
src/matterbridgeDeviceV8.ts | 2253 -----------------
src/matterbridgeV8.ts | 785 ------
4 files changed, 5 insertions(+), 3042 deletions(-)
delete mode 100644 src/matterbridgeDeviceV8.ts
delete mode 100644 src/matterbridgeV8.ts
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bd725090..cd19c7be 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@ If you like this project and find it useful, please consider giving it a star on
### Fixed
- [matterbridge]: Fixed nodeLabel in childbridge mode
+- [matterbridge]: Fixed MeasurementClusters
diff --git a/src/cluster/ElectricalPowerMeasurementCluster.ts b/src/cluster/ElectricalPowerMeasurementCluster.ts
index cbfbd258..efbcf2eb 100644
--- a/src/cluster/ElectricalPowerMeasurementCluster.ts
+++ b/src/cluster/ElectricalPowerMeasurementCluster.ts
@@ -479,7 +479,7 @@ export namespace ElectricalPowerMeasurement {
*
* @see {@link MatterSpecification.v13.Cluster} § 2.13.6.19
*/
- neutralCurrent: OptionalAttribute(0x12, TlvNullable(TlvInt64.bound({ min: -262, max: 262 })), { default: null }),
+ neutralCurrent: OptionalAttribute(0x12, TlvNullable(TlvInt64.bound({ min: -(2 ** 62), max: 2 ** 62 })), { default: null }),
},
});
@@ -649,7 +649,7 @@ export namespace ElectricalPowerMeasurement {
*
* @see {@link MatterSpecification.v13.Cluster} § 2.13.6.5
*/
- voltage: OptionalAttribute(0x4, TlvNullable(TlvInt64.bound({ min: -262, max: 262 })), { default: null }),
+ voltage: OptionalAttribute(0x4, TlvNullable(TlvInt64.bound({ min: -(2 ** 62), max: 2 ** 62 })), { default: null }),
/**
* This shall indicate the most recent ActiveCurrent reading in milliamps (mA).
@@ -670,7 +670,7 @@ export namespace ElectricalPowerMeasurement {
*
* @see {@link MatterSpecification.v13.Cluster} § 2.13.6.6
*/
- activeCurrent: OptionalAttribute(0x5, TlvNullable(TlvInt64.bound({ min: -262, max: 262 })), { default: null }),
+ activeCurrent: OptionalAttribute(0x5, TlvNullable(TlvInt64.bound({ min: -(2 ** 62), max: 2 ** 62 })), { default: null }),
/**
* This shall indicate the most recent ActivePower reading in milliwatts (mW). If the power cannot be
@@ -692,7 +692,7 @@ export namespace ElectricalPowerMeasurement {
*
* @see {@link MatterSpecification.v13.Cluster} § 2.13.6.9
*/
- activePower: Attribute(0x8, TlvNullable(TlvInt64.bound({ min: -262, max: 262 })), { default: null }),
+ activePower: Attribute(0x8, TlvNullable(TlvInt64.bound({ min: -(2 ** 62), max: 2 ** 62 })), { default: null }),
},
events: {
diff --git a/src/matterbridgeDeviceV8.ts b/src/matterbridgeDeviceV8.ts
deleted file mode 100644
index 56606b56..00000000
--- a/src/matterbridgeDeviceV8.ts
+++ /dev/null
@@ -1,2253 +0,0 @@
-/* eslint-disable @typescript-eslint/no-unused-vars */
-// New API imports
-import { Endpoint, EndpointServer } from '@project-chip/matter.js/endpoint';
-import { OnOffLightDevice } from '@project-chip/matter.js/devices/OnOffLightDevice';
-import { AggregatorEndpoint } from '@project-chip/matter.js/endpoints/AggregatorEndpoint';
-import { BridgedNodeEndpoint } from '@project-chip/matter.js/endpoints/BridgedNodeEndpoint';
-import { MutableEndpoint, EndpointType } from '@project-chip/matter.js/endpoint/type';
-import { Behavior } from '@project-chip/matter.js/behavior';
-import { SupportedBehaviors } from '@project-chip/matter.js/endpoint/properties';
-import { IdentifyServer, IdentifyBehavior } from '@project-chip/matter.js/behavior/definitions/identify';
-import { GroupsServer, GroupsBehavior } from '@project-chip/matter.js/behavior/definitions/groups';
-import { ScenesServer, ScenesBehavior } from '@project-chip/matter.js/behavior/definitions/scenes';
-import { OnOffServer, OnOffBehavior } from '@project-chip/matter.js/behavior/definitions/on-off';
-import { TemperatureMeasurementServer } from '@project-chip/matter.js/behavior/definitions/temperature-measurement';
-import { RelativeHumidityMeasurementServer } from '@project-chip/matter.js/behavior/definitions/relative-humidity-measurement';
-import { BridgedDeviceBasicInformationServer, BridgedDeviceBasicInformationBehavior } from '@project-chip/matter.js/behavior/definitions/bridged-device-basic-information';
-
-// Old API imports
-import { DeviceTypeDefinition, DeviceTypes, EndpointOptions } from '@project-chip/matter-node.js/device';
-import {
- AttributeServer,
- Attributes,
- BasicInformationCluster,
- BooleanState,
- BooleanStateCluster,
- BridgedDeviceBasicInformation,
- BridgedDeviceBasicInformationCluster,
- Cluster,
- ClusterClientObj,
- ClusterServer,
- ClusterServerObj,
- ColorControl,
- ColorControlCluster,
- Commands,
- DoorLock,
- DoorLockCluster,
- ElectricalMeasurement,
- ElectricalMeasurementCluster,
- Events,
- FanControl,
- FanControlCluster,
- FlowMeasurement,
- FlowMeasurementCluster,
- Groups,
- Identify,
- IdentifyCluster,
- IlluminanceMeasurement,
- IlluminanceMeasurementCluster,
- LevelControl,
- LevelControlCluster,
- OccupancySensing,
- OccupancySensingCluster,
- OnOff,
- OnOffCluster,
- PowerSource,
- PowerSourceCluster,
- PowerSourceConfigurationCluster,
- PressureMeasurement,
- PressureMeasurementCluster,
- RelativeHumidityMeasurement,
- RelativeHumidityMeasurementCluster,
- Scenes,
- Switch,
- SwitchCluster,
- TemperatureMeasurement,
- TemperatureMeasurementCluster,
- Thermostat,
- ThermostatCluster,
- ThreadNetworkDiagnostics,
- ThreadNetworkDiagnosticsCluster,
- TimeSync,
- TimeSyncCluster,
- WindowCovering,
- WindowCoveringCluster,
- createDefaultGroupsClusterServer,
- createDefaultScenesClusterServer,
- getClusterNameById,
-} from '@project-chip/matter-node.js/cluster';
-import { AtLeastOne } from '@project-chip/matter-node.js/util';
-import { ClusterId, EndpointNumber, VendorId } from '@project-chip/matter-node.js/datatype';
-
-// Matterbridge imports
-import { AnsiLogger, CYAN, TimestampFormat, db, hk, zb } from 'node-ansi-logger';
-import { BooleanStateConfiguration, BooleanStateConfigurationCluster } from './cluster/BooleanStateConfigurationCluster.js';
-import { PowerTopology, PowerTopologyCluster } from './cluster/PowerTopologyCluster.js';
-import { ElectricalPowerMeasurement, ElectricalPowerMeasurementCluster } from './cluster/ElectricalPowerMeasurementCluster.js';
-import { ElectricalEnergyMeasurement, ElectricalEnergyMeasurementCluster } from './cluster/ElectricalEnergyMeasurementCluster.js';
-import { SmokeCoAlarm, SmokeCoAlarmCluster } from './cluster/SmokeCoAlarmCluster.js';
-import { AirQuality, AirQualityCluster } from './cluster/AirQualityCluster.js';
-import { CarbonMonoxideConcentrationMeasurement, CarbonMonoxideConcentrationMeasurementCluster } from './cluster/CarbonMonoxideConcentrationMeasurementCluster.js';
-import { CarbonDioxideConcentrationMeasurement, CarbonDioxideConcentrationMeasurementCluster } from './cluster/CarbonDioxideConcentrationMeasurementCluster.js';
-import { NitrogenDioxideConcentrationMeasurement, NitrogenDioxideConcentrationMeasurementCluster } from './cluster/NitrogenDioxideConcentrationMeasurementCluster.js';
-import { OzoneConcentrationMeasurement, OzoneConcentrationMeasurementCluster } from './cluster/OzoneConcentrationMeasurementCluster.js';
-import { FormaldehydeConcentrationMeasurement, FormaldehydeConcentrationMeasurementCluster } from './cluster/FormaldehydeConcentrationMeasurementCluster.js';
-import { Pm1ConcentrationMeasurement, Pm1ConcentrationMeasurementCluster } from './cluster/Pm1ConcentrationMeasurementCluster.js';
-import { Pm25ConcentrationMeasurement, Pm25ConcentrationMeasurementCluster } from './cluster/Pm25ConcentrationMeasurementCluster.js';
-import { Pm10ConcentrationMeasurement, Pm10ConcentrationMeasurementCluster } from './cluster/Pm10ConcentrationMeasurementCluster.js';
-import { RadonConcentrationMeasurement, RadonConcentrationMeasurementCluster } from './cluster/RadonConcentrationMeasurementCluster.js';
-import { TvocMeasurement, TvocMeasurementCluster } from './cluster/TvocCluster.js';
-import { DeviceEnergyManagement, DeviceEnergyManagementCluster } from './cluster/DeviceEnergyManagementCluster.js';
-import { DeviceEnergyManagementMode, DeviceEnergyManagementModeCluster } from './cluster/DeviceEnergyManagementModeCluster.js';
-import { EveHistory, EveHistoryCluster } from 'matter-history';
-import { createHash } from 'crypto';
-import { MeasurementType } from './cluster/MeasurementType.js';
-import { ConcentrationMeasurement } from './cluster/ConcentrationMeasurementCluster.js';
-import { BitSchema, TypeFromPartialBitSchema } from '@project-chip/matter-node.js/schema';
-
-export class MatterbridgeDeviceV8 extends Endpoint {
- public static bridgeMode = '';
- log: AnsiLogger;
- serialNumber: string | undefined = undefined;
- deviceName: string | undefined = undefined;
- uniqueId: string | undefined = undefined;
-
- // Maps matter endpoints to endpointV8
- private readonly deviceTypes = new Map();
- private readonly clusterServers = new Map>();
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- private readonly clusterClients = new Map>();
-
- /**
- * Represents a Matterbridge device.
- * @constructor
- * @param {DeviceTypeDefinition} definition - The definition of the device.
- * @param {EndpointOptions} [options={}] - The options for the device.
- */
- constructor(definition: DeviceTypeDefinition, options: EndpointOptions = {}) {
- // Convert the DeviceTypeDefinition to a EndpointType.Options
- const deviceTypeDefinitionV8: EndpointType.Options = {
- name: definition.name.replace('-', '_'),
- deviceType: definition.code,
- deviceRevision: definition.revision,
- deviceClass: definition.deviceClass,
- requirements: {
- server: {
- mandatory: SupportedBehaviors(...MatterbridgeDeviceV8.getBehaviourTypesFromClusterServerIds(definition.requiredServerClusters)),
- optional: SupportedBehaviors(...MatterbridgeDeviceV8.getBehaviourTypesFromClusterServerIds(definition.optionalServerClusters)),
- },
- client: {
- mandatory: SupportedBehaviors(...MatterbridgeDeviceV8.getBehaviourTypesFromClusterClientIds(definition.requiredClientClusters)),
- optional: SupportedBehaviors(...MatterbridgeDeviceV8.getBehaviourTypesFromClusterClientIds(definition.optionalClientClusters)),
- },
- },
- behaviors: SupportedBehaviors(...MatterbridgeDeviceV8.getBehaviourTypesFromClusterServerIds(definition.requiredServerClusters)),
- };
- const endpointV8 = MutableEndpoint(deviceTypeDefinitionV8);
- const optionsV8: Endpoint.Options = {
- id: options.uniqueStorageKey,
- };
- super(endpointV8, optionsV8);
- this.log = new AnsiLogger({ logName: 'MatterbridgeDevice', logTimestampFormat: TimestampFormat.TIME_MILLIS, logDebug: true });
- this.deviceTypes.set(definition.code, definition);
- }
-
- static getBehaviourTypesFromClusterServerIds(clusterServerList: ClusterId[]) {
- // Map ClusterId to Behavior.Type
- const behaviorTypes: Behavior.Type[] = [];
- clusterServerList.forEach((clusterId) => {
- if (clusterId === Identify.Cluster.id) behaviorTypes.push(IdentifyServer);
- if (clusterId === Groups.Cluster.id) behaviorTypes.push(GroupsServer);
- if (clusterId === Scenes.Cluster.id) behaviorTypes.push(ScenesServer);
- if (clusterId === OnOff.Cluster.id) behaviorTypes.push(OnOffServer);
- if (clusterId === TemperatureMeasurement.Cluster.id) behaviorTypes.push(TemperatureMeasurementServer);
- if (clusterId === RelativeHumidityMeasurement.Cluster.id) behaviorTypes.push(RelativeHumidityMeasurementServer);
- if (clusterId === BridgedDeviceBasicInformation.Cluster.id) behaviorTypes.push(BridgedDeviceBasicInformationServer);
- });
- return behaviorTypes;
- }
-
- static getBehaviourTypesFromClusterClientIds(clusterServerList: ClusterId[]) {
- // Map ClusterId to Behavior.Type
- const behaviorTypes: Behavior.Type[] = [];
- clusterServerList.forEach((clusterId) => {
- //
- });
- return behaviorTypes;
- }
-
- /**
- * Loads an instance of the MatterbridgeDevice class.
- *
- * @param {DeviceTypeDefinition} definition - The DeviceTypeDefinition of the device.
- * @returns MatterbridgeDevice instance.
- */
- static async loadInstance(definition: DeviceTypeDefinition, options: EndpointOptions = {}) {
- return new MatterbridgeDeviceV8(definition, options);
- }
-
- /**
- * Adds a device type to the list of device types.
- * If the device type is not already present in the list, it will be added.
- *
- * @param {DeviceTypeDefinition} deviceType - The device type to add.
- */
- addDeviceType(deviceType: DeviceTypeDefinition) {
- if (!this.deviceTypes.has(deviceType.code)) {
- this.log.debug(`addDeviceType: ${zb}${deviceType.code}${db}-${zb}${deviceType.name}${db}`);
- this.deviceTypes.set(deviceType.code, deviceType);
- }
- }
-
- /**
- * Adds one or more device types with the required cluster servers and the specified cluster servers.
- *
- * @param {AtLeastOne} deviceTypes - The device types to add.
- * @param {ClusterId[]} includeServerList - The list of cluster IDs to include.
- */
- addDeviceTypeWithClusterServer(deviceTypes: AtLeastOne, includeServerList: ClusterId[]) {
- this.log.debug('addDeviceTypeWithClusterServer:');
- deviceTypes.forEach((deviceType) => {
- this.addDeviceType(deviceType);
- this.log.debug(`- with deviceType: ${zb}${deviceType.code}${db}-${zb}${deviceType.name}${db}`);
- deviceType.requiredServerClusters.forEach((clusterId) => {
- if (!includeServerList.includes(clusterId)) includeServerList.push(clusterId);
- });
- });
- includeServerList.forEach((clusterId) => {
- this.log.debug(`- with cluster: ${hk}${clusterId}${db}-${hk}${getClusterNameById(clusterId)}${db}`);
- });
- this.addClusterServerFromList(this, includeServerList);
- }
-
- /**
- * Adds a child endpoint with one or more device types with the required cluster servers and the specified cluster servers.
- * If the child endpoint is not already present in the childEndpoints, it will be added.
- * If the child endpoint is already present in the childEndpoints, the device types and cluster servers will be added to the existing child endpoint.
- *
- * @param {string} endpointName - The name of the new enpoint to add.
- * @param {AtLeastOne} deviceTypes - The device types to add.
- * @param {ClusterId[]} includeServerList - The list of cluster IDs to include.
- * @returns {Endpoint} - The child endpoint that was found or added.
- */
- addChildDeviceTypeWithClusterServer(endpointName: string, deviceTypes: AtLeastOne, includeServerList: ClusterId[]) {
- /*
- this.log.debug(`addChildDeviceTypeWithClusterServer: ${CYAN}${endpointName}${db}`);
- let child = this.getChildEndpoints().find((endpoint) => endpoint.uniqueStorageKey === endpointName);
- if (!child) {
- child = new Endpoint(deviceTypes, { uniqueStorageKey: endpointName });
- child.addFixedLabel('endpointName', endpointName);
- }
- deviceTypes.forEach((deviceType) => {
- this.log.debug(`- with deviceType: ${zb}${deviceType.code}${db}-${zb}${deviceType.name}${db}`);
- deviceType.requiredServerClusters.forEach((clusterId) => {
- if (!includeServerList.includes(clusterId)) includeServerList.push(clusterId);
- });
- });
- includeServerList.forEach((clusterId) => {
- this.log.debug(`- with cluster: ${hk}${clusterId}${db}-${hk}${getClusterNameById(clusterId)}${db}`);
- });
- this.addClusterServerFromList(child, includeServerList);
- this.addChildEndpoint(child);
- return child;
- */
- }
-
- getClusterServer, A extends Attributes, C extends Commands, E extends Events>(cluster: Cluster): ClusterServerObj | undefined {
- const clusterServer = this.clusterServers.get(cluster.id);
- if (clusterServer !== undefined) {
- return clusterServer as unknown as ClusterServerObj;
- }
- }
-
- addClusterServer(cluster: ClusterServerObj) {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- const options: Record = {};
- for (const attribute of Object.values(cluster.attributes)) {
- if ((attribute as AttributeServer).id < 0xfff0) {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- options[(attribute as AttributeServer).name] = (attribute as any).value;
- }
- }
- this.log.debug(`addClusterServer: ${cluster.name} with options:`, options);
- const behaviorTypes = MatterbridgeDeviceV8.getBehaviourTypesFromClusterServerIds([cluster.id]);
- this.behaviors.require(behaviorTypes[0], options);
- this.clusterServers.set(cluster.id, cluster);
- }
-
- /**
- * Adds cluster servers to the specified endpoint based on the provided server list.
- *
- * @param {Endpoint} endpoint - The endpoint to add cluster servers to.
- * @param {ClusterId[]} includeServerList - The list of cluster IDs to include.
- * @returns void
- */
- addClusterServerFromList(endpoint: MatterbridgeDeviceV8, includeServerList: ClusterId[]): void {
- if (includeServerList.includes(Identify.Cluster.id)) endpoint.addClusterServer(this.getDefaultIdentifyClusterServer());
- if (includeServerList.includes(Groups.Cluster.id)) endpoint.addClusterServer(this.getDefaultGroupsClusterServer());
- if (includeServerList.includes(Scenes.Cluster.id)) endpoint.addClusterServer(this.getDefaultScenesClusterServer());
- if (includeServerList.includes(OnOff.Cluster.id)) endpoint.addClusterServer(this.getDefaultOnOffClusterServer());
- if (includeServerList.includes(LevelControl.Cluster.id)) endpoint.addClusterServer(this.getDefaultLevelControlClusterServer());
- if (includeServerList.includes(ColorControl.Cluster.id)) endpoint.addClusterServer(this.getDefaultColorControlClusterServer());
- if (includeServerList.includes(Switch.Cluster.id)) endpoint.addClusterServer(this.getDefaultSwitchClusterServer());
- if (includeServerList.includes(DoorLock.Cluster.id)) endpoint.addClusterServer(this.getDefaultDoorLockClusterServer());
- if (includeServerList.includes(Thermostat.Cluster.id)) endpoint.addClusterServer(this.getDefaultThermostatClusterServer());
- if (includeServerList.includes(TimeSync.Cluster.id)) endpoint.addClusterServer(this.getDefaultTimeSyncClusterServer());
- if (includeServerList.includes(WindowCovering.Cluster.id)) endpoint.addClusterServer(this.getDefaultWindowCoveringClusterServer());
- if (includeServerList.includes(TemperatureMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultTemperatureMeasurementClusterServer());
- if (includeServerList.includes(RelativeHumidityMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultRelativeHumidityMeasurementClusterServer());
- if (includeServerList.includes(PressureMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultPressureMeasurementClusterServer());
- if (includeServerList.includes(FlowMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultFlowMeasurementClusterServer());
- if (includeServerList.includes(BooleanState.Cluster.id)) endpoint.addClusterServer(this.getDefaultBooleanStateClusterServer());
- if (includeServerList.includes(BooleanStateConfiguration.Cluster.id)) endpoint.addClusterServer(this.getDefaultBooleanStateConfigurationClusterServer());
- if (includeServerList.includes(OccupancySensing.Cluster.id)) endpoint.addClusterServer(this.getDefaultOccupancySensingClusterServer());
- if (includeServerList.includes(IlluminanceMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultIlluminanceMeasurementClusterServer());
- if (includeServerList.includes(PowerSource.Cluster.id)) endpoint.addClusterServer(this.getDefaultPowerSourceWiredClusterServer());
- if (includeServerList.includes(EveHistory.Cluster.id)) endpoint.addClusterServer(this.getDefaultStaticEveHistoryClusterServer());
- if (includeServerList.includes(ElectricalMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultElectricalMeasurementClusterServer());
- if (includeServerList.includes(PowerTopology.Cluster.id)) endpoint.addClusterServer(this.getDefaultPowerTopologyClusterServer());
- if (includeServerList.includes(ElectricalPowerMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultElectricalPowerMeasurementClusterServer());
- if (includeServerList.includes(ElectricalEnergyMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultElectricalEnergyMeasurementClusterServer());
- if (includeServerList.includes(SmokeCoAlarm.Cluster.id)) endpoint.addClusterServer(this.getDefaultSmokeCOAlarmClusterServer());
- if (includeServerList.includes(AirQuality.Cluster.id)) endpoint.addClusterServer(this.getDefaultAirQualityClusterServer());
- if (includeServerList.includes(CarbonMonoxideConcentrationMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultCarbonMonoxideConcentrationMeasurementClusterServer());
- if (includeServerList.includes(CarbonDioxideConcentrationMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultCarbonDioxideConcentrationMeasurementClusterServer());
- if (includeServerList.includes(NitrogenDioxideConcentrationMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultNitrogenDioxideConcentrationMeasurementClusterServer());
- if (includeServerList.includes(OzoneConcentrationMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultOzoneConcentrationMeasurementClusterServer());
- if (includeServerList.includes(FormaldehydeConcentrationMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultFormaldehydeConcentrationMeasurementClusterServer());
- if (includeServerList.includes(Pm1ConcentrationMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultPm1ConcentrationMeasurementClusterServer());
- if (includeServerList.includes(Pm25ConcentrationMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultPm25ConcentrationMeasurementClusterServer());
- if (includeServerList.includes(Pm10ConcentrationMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultPm10ConcentrationMeasurementClusterServer());
- if (includeServerList.includes(RadonConcentrationMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultRadonConcentrationMeasurementClusterServer());
- if (includeServerList.includes(TvocMeasurement.Cluster.id)) endpoint.addClusterServer(this.getDefaultTvocMeasurementClusterServer());
- if (includeServerList.includes(FanControl.Cluster.id)) endpoint.addClusterServer(this.getDefaultFanControlClusterServer());
- if (includeServerList.includes(DeviceEnergyManagement.Cluster.id)) endpoint.addClusterServer(this.getDefaultDeviceEnergyManagementClusterServer());
- if (includeServerList.includes(DeviceEnergyManagementMode.Cluster.id)) endpoint.addClusterServer(this.getDefaultDeviceEnergyManagementModeClusterServer());
- }
-
- /**
- * Returns a default static EveHistoryClusterServer object with the specified voltage, current, power, and consumption values.
- * This shows up in HA as a static sensor!
- * @param voltage - The voltage value (default: 0).
- * @param current - The current value (default: 0).
- * @param power - The power value (default: 0).
- * @param consumption - The consumption value (default: 0).
- * @returns The default static EveHistoryClusterServer object.
- */
- getDefaultStaticEveHistoryClusterServer(voltage = 0, current = 0, power = 0, consumption = 0) {
- return ClusterServer(
- EveHistoryCluster.with(EveHistory.Feature.EveEnergy),
- {
- // Dynamic attributes
- ConfigDataGet: Uint8Array.fromHex(''),
- ConfigDataSet: Uint8Array.fromHex(''),
- HistoryStatus: Uint8Array.fromHex(''),
- HistoryEntries: Uint8Array.fromHex(''),
- HistoryRequest: Uint8Array.fromHex(''),
- HistorySetTime: Uint8Array.fromHex(''),
- LastEvent: 0,
- ResetTotal: 0,
- // Normal attributes
- Voltage: voltage,
- Current: current,
- Consumption: power,
- TotalConsumption: consumption,
- EnergyUnknown: 1,
- ChildLock: false,
- RLoc: 46080,
- },
- {},
- {},
- );
- }
-
- /**
- * Get a default IdentifyCluster server.
- */
- getDefaultIdentifyClusterServer() {
- return ClusterServer(
- IdentifyCluster,
- {
- identifyTime: 0,
- identifyType: Identify.IdentifyType.None,
- },
- {
- identify: async (data) => {
- this.log.debug('Matter command: Identify');
- // await this.commandHandler.executeHandler('identify', data);
- },
- },
- );
- }
-
- /**
- * Creates a default IdentifyCluster server.
- */
- createDefaultIdentifyClusterServer() {
- this.addClusterServer(this.getDefaultIdentifyClusterServer());
- }
-
- /**
- * Get a default IdentifyCluster server.
- */
- getDefaultGroupsClusterServer() {
- return createDefaultGroupsClusterServer();
- }
-
- /**
- * Creates a default groups cluster server and adds it to the device.
- */
- createDefaultGroupsClusterServer() {
- this.addClusterServer(this.getDefaultGroupsClusterServer());
- }
-
- /**
- * Get a default scenes cluster server and adds it to the current instance.
- */
- getDefaultScenesClusterServer() {
- return createDefaultScenesClusterServer();
- }
-
- /**
- * Creates a default scenes cluster server and adds it to the current instance.
- */
- createDefaultScenesClusterServer() {
- this.addClusterServer(this.getDefaultScenesClusterServer());
- }
-
- /**
- * Creates a unique identifier based on the provided parameters.
- * @param param1 - The first parameter.
- * @param param2 - The second parameter.
- * @param param3 - The third parameter.
- * @param param4 - The fourth parameter.
- * @returns A unique identifier generated using the MD5 hash algorithm.
- */
- private createUniqueId(param1: string, param2: string, param3: string, param4: string) {
- const hash = createHash('md5');
- hash.update(param1 + param2 + param3 + param4);
- return hash.digest('hex');
- }
-
- /**
- * Get a default Basic Information Cluster Server.
- *
- * @param deviceName - The name of the device.
- * @param serialNumber - The serial number of the device.
- * @param vendorId - The vendor ID of the device.
- * @param vendorName - The vendor name of the device.
- * @param productId - The product ID of the device.
- * @param productName - The product name of the device.
- * @param softwareVersion - The software version of the device. Default is 1.
- * @param softwareVersionString - The software version string of the device. Default is 'v.1.0.0'.
- * @param hardwareVersion - The hardware version of the device. Default is 1.
- * @param hardwareVersionString - The hardware version string of the device. Default is 'v.1.0.0'.
- */
- getDefaultBasicInformationClusterServer(
- deviceName: string,
- serialNumber: string,
- vendorId: number,
- vendorName: string,
- productId: number,
- productName: string,
- softwareVersion = 1,
- softwareVersionString = '1.0.0',
- hardwareVersion = 1,
- hardwareVersionString = '1.0.0',
- ) {
- return ClusterServer(
- BasicInformationCluster,
- {
- dataModelRevision: 1,
- location: 'XX',
- vendorId: VendorId(vendorId),
- vendorName: vendorName.slice(0, 32),
- productId: productId,
- productName: productName.slice(0, 32),
- productLabel: deviceName.slice(0, 64),
- nodeLabel: deviceName.slice(0, 32),
- serialNumber: serialNumber.slice(0, 32),
- uniqueId: this.createUniqueId(deviceName, serialNumber, vendorName, productName),
- softwareVersion,
- softwareVersionString: softwareVersionString.slice(0, 64),
- hardwareVersion,
- hardwareVersionString: hardwareVersionString.slice(0, 64),
- reachable: true,
- capabilityMinima: { caseSessionsPerFabric: 3, subscriptionsPerFabric: 3 },
- },
- {},
- {
- startUp: true,
- shutDown: true,
- leave: true,
- reachableChanged: true,
- },
- );
- }
- /**
- * Creates a default Basic Information Cluster Server.
- *
- * @param deviceName - The name of the device.
- * @param serialNumber - The serial number of the device.
- * @param vendorId - The vendor ID of the device.
- * @param vendorName - The vendor name of the device.
- * @param productId - The product ID of the device.
- * @param productName - The product name of the device.
- * @param softwareVersion - The software version of the device. Default is 1.
- * @param softwareVersionString - The software version string of the device. Default is 'v.1.0.0'.
- * @param hardwareVersion - The hardware version of the device. Default is 1.
- * @param hardwareVersionString - The hardware version string of the device. Default is 'v.1.0.0'.
- */
- createDefaultBasicInformationClusterServer(
- deviceName: string,
- serialNumber: string,
- vendorId: number,
- vendorName: string,
- productId: number,
- productName: string,
- softwareVersion = 1,
- softwareVersionString = '1.0.0',
- hardwareVersion = 1,
- hardwareVersionString = '1.0.0',
- ) {
- this.deviceName = deviceName;
- this.serialNumber = serialNumber;
- this.uniqueId = this.createUniqueId(deviceName, serialNumber, vendorName, productName);
- if (MatterbridgeDeviceV8.bridgeMode === 'bridge') {
- this.createDefaultBridgedDeviceBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productName, softwareVersion, softwareVersionString, hardwareVersion, hardwareVersionString);
- return;
- }
- this.addClusterServer(this.getDefaultBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productId, productName, softwareVersion, softwareVersionString, hardwareVersion, hardwareVersionString));
- }
-
- /**
- * Get a default BridgedDeviceBasicInformationClusterServer.
- *
- * @param deviceName - The name of the device.
- * @param serialNumber - The serial number of the device.
- * @param vendorId - The vendor ID of the device.
- * @param vendorName - The name of the vendor.
- * @param productName - The name of the product.
- * @param softwareVersion - The software version of the device. Default is 1.
- * @param softwareVersionString - The software version string of the device. Default is 'v.1.0.0'.
- * @param hardwareVersion - The hardware version of the device. Default is 1.
- * @param hardwareVersionString - The hardware version string of the device. Default is 'v.1.0.0'.
- */
- getDefaultBridgedDeviceBasicInformationClusterServer(
- deviceName: string,
- serialNumber: string,
- vendorId: number,
- vendorName: string,
- productName: string,
- softwareVersion = 1,
- softwareVersionString = '1.0.0',
- hardwareVersion = 1,
- hardwareVersionString = '1.0.0',
- ) {
- return ClusterServer(
- BridgedDeviceBasicInformationCluster,
- {
- vendorId: vendorId !== undefined ? VendorId(vendorId) : undefined, // 4874
- vendorName: vendorName.slice(0, 32),
- // productId: 0x8000,
- productName: productName.slice(0, 32),
- productLabel: deviceName.slice(0, 64),
- nodeLabel: deviceName.slice(0, 32),
- serialNumber: serialNumber.slice(0, 32),
- uniqueId: this.createUniqueId(deviceName, serialNumber, vendorName, productName),
- softwareVersion,
- softwareVersionString: softwareVersionString.slice(0, 64),
- hardwareVersion,
- hardwareVersionString: hardwareVersionString.slice(0, 64),
- reachable: true,
- },
- {},
- {
- reachableChanged: true,
- },
- );
- }
-
- /**
- * Creates a default BridgedDeviceBasicInformationClusterServer.
- *
- * @param deviceName - The name of the device.
- * @param serialNumber - The serial number of the device.
- * @param vendorId - The vendor ID of the device.
- * @param vendorName - The name of the vendor.
- * @param productName - The name of the product.
- * @param softwareVersion - The software version of the device. Default is 1.
- * @param softwareVersionString - The software version string of the device. Default is 'v.1.0.0'.
- * @param hardwareVersion - The hardware version of the device. Default is 1.
- * @param hardwareVersionString - The hardware version string of the device. Default is 'v.1.0.0'.
- */
- createDefaultBridgedDeviceBasicInformationClusterServer(
- deviceName: string,
- serialNumber: string,
- vendorId: number,
- vendorName: string,
- productName: string,
- softwareVersion = 1,
- softwareVersionString = '1.0.0',
- hardwareVersion = 1,
- hardwareVersionString = '1.0.0',
- ) {
- this.deviceName = deviceName;
- this.serialNumber = serialNumber;
- this.uniqueId = this.createUniqueId(deviceName, serialNumber, vendorName, productName);
- this.addClusterServer(this.getDefaultBridgedDeviceBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productName, softwareVersion, softwareVersionString, hardwareVersion, hardwareVersionString));
- }
-
- /**
- * Get a default Electrical Energy Measurement Cluster Server.
- *
- * @param energy - The total consumption value.
- */
- getDefaultPowerTopologyClusterServer() {
- return ClusterServer(PowerTopologyCluster.with(PowerTopology.Feature.TreeTopology), {}, {}, {});
- }
-
- /**
- * Get a default Electrical Energy Measurement Cluster Server.
- *
- * @param energy - The total consumption value.
- */
- getDefaultElectricalEnergyMeasurementClusterServer(energy = 0) {
- return ClusterServer(
- ElectricalEnergyMeasurementCluster.with(ElectricalEnergyMeasurement.Feature.ImportedEnergy, ElectricalEnergyMeasurement.Feature.ExportedEnergy, ElectricalEnergyMeasurement.Feature.CumulativeEnergy),
- {
- accuracy: {
- measurementType: MeasurementType.ElectricalEnergy,
- measured: true,
- minMeasuredValue: 0,
- maxMeasuredValue: 0,
- accuracyRanges: [{ rangeMin: 0, rangeMax: 2 ** 62, fixedMin: 10, fixedMax: 10, fixedTypical: 0 }],
- },
- cumulativeEnergyImported: { energy },
- cumulativeEnergyExported: null,
- },
- {},
- {
- cumulativeEnergyMeasured: true,
- },
- );
- }
-
- /**
- * Get a default Electrical Power Measurement Cluster Server.
- *
- * @param energy - The total consumption value.
- */
- getDefaultElectricalPowerMeasurementClusterServer(voltage = 0, current = 0, power = 0) {
- return ClusterServer(
- ElectricalPowerMeasurementCluster.with(ElectricalPowerMeasurement.Feature.AlternatingCurrent),
- {
- powerMode: ElectricalPowerMeasurement.PowerMode.Ac,
- numberOfMeasurementTypes: 3,
- accuracy: [
- {
- measurementType: MeasurementType.Voltage,
- measured: true,
- minMeasuredValue: 0,
- maxMeasuredValue: 100,
- accuracyRanges: [{ rangeMin: 0, rangeMax: 2 ** 62, fixedMin: 10, fixedMax: 10, fixedTypical: 0 }],
- },
- {
- measurementType: MeasurementType.ActiveCurrent,
- measured: true,
- minMeasuredValue: 0,
- maxMeasuredValue: 100,
- accuracyRanges: [{ rangeMin: 0, rangeMax: 2 ** 62, fixedMin: 10, fixedMax: 10, fixedTypical: 0 }],
- },
- {
- measurementType: MeasurementType.ActivePower,
- measured: true,
- minMeasuredValue: 0,
- maxMeasuredValue: 100,
- accuracyRanges: [{ rangeMin: 0, rangeMax: 2 ** 62, fixedMin: 10, fixedMax: 10, fixedTypical: 0 }],
- },
- ],
- voltage: voltage,
- activeCurrent: current,
- activePower: power,
- },
- {},
- {},
- );
- }
-
- /**
- * @deprecated This method is deprecated and will be removed in a future version.
- * Get a default Electrical Measurement Cluster Server.
- *
- * @param voltage - The RMS voltage value.
- * @param current - The RMS current value.
- * @param power - The active power value.
- * @param consumption - The total active power consumption value.
- */
- getDefaultElectricalMeasurementClusterServer(voltage = 0, current = 0, power = 0, consumption = 0) {
- return ClusterServer(
- ElectricalMeasurementCluster,
- {
- rmsVoltage: voltage,
- rmsCurrent: current,
- activePower: power,
- totalActivePower: consumption,
- },
- {},
- {},
- );
- }
-
- /**
- * @deprecated This method is deprecated and will be removed in a future version.
- * Creates a default Electrical Measurement Cluster Server.
- *
- * @param voltage - The RMS voltage value.
- * @param current - The RMS current value.
- * @param power - The active power value.
- * @param consumption - The total active power consumption value.
- */
- createDefaultElectricalMeasurementClusterServer(voltage = 0, current = 0, power = 0, consumption = 0) {
- this.addClusterServer(this.getDefaultElectricalMeasurementClusterServer(voltage, current, power, consumption));
- }
-
- /**
- * Creates a default Dummy Thread Network Diagnostics Cluster server.
- *
- * @remarks
- * This method adds a cluster server used only to give the networkName to Eve app.
- *
- * @returns void
- */
- createDefaultDummyThreadNetworkDiagnosticsClusterServer() {
- this.addClusterServer(
- ClusterServer(
- ThreadNetworkDiagnosticsCluster.with(ThreadNetworkDiagnostics.Feature.PacketCounts, ThreadNetworkDiagnostics.Feature.ErrorCounts),
- {
- channel: 1,
- routingRole: ThreadNetworkDiagnostics.RoutingRole.Router,
- networkName: 'MyMatterThread',
- panId: 0,
- extendedPanId: 0,
- meshLocalPrefix: null,
- neighborTable: [],
- routeTable: [],
- partitionId: null,
- weighting: null,
- dataVersion: null,
- stableDataVersion: null,
- leaderRouterId: null,
- securityPolicy: null,
- channelPage0Mask: null,
- operationalDatasetComponents: null,
- overrunCount: 0,
- activeNetworkFaults: [],
- },
- {
- resetCounts: async (data) => {
- this.log.debug('Matter command: resetCounts');
- // await this.commandHandler.executeHandler('resetCounts', data);
- },
- },
- {},
- ),
- );
- }
-
- /**
- * Get a default OnOff cluster server.
- *
- * @param onOff - The initial state of the OnOff cluster (default: false).
- */
- getDefaultOnOffClusterServer(onOff = false) {
- return ClusterServer(
- OnOffCluster,
- {
- onOff,
- },
- {
- on: async (data) => {
- this.log.debug('Matter command: on onOff:', data.attributes.onOff.getLocal());
- // await this.commandHandler.executeHandler('on', data);
- },
- off: async (data) => {
- this.log.debug('Matter command: off onOff:', data.attributes.onOff.getLocal());
- // await this.commandHandler.executeHandler('off', data);
- },
- toggle: async (data) => {
- this.log.debug('Matter command: toggle onOff:', data.attributes.onOff.getLocal());
- // await this.commandHandler.executeHandler('toggle', data);
- },
- },
- {},
- );
- }
-
- /**
- * Creates a default OnOff cluster server.
- *
- * @param onOff - The initial state of the OnOff cluster (default: false).
- */
- createDefaultOnOffClusterServer(onOff = false) {
- this.addClusterServer(this.getDefaultOnOffClusterServer(onOff));
- }
-
- /**
- * Get a default level control cluster server.
- *
- * @param currentLevel - The current level (default: 0).
- */
- getDefaultLevelControlClusterServer(currentLevel = 0) {
- return ClusterServer(
- LevelControlCluster.with(LevelControl.Feature.OnOff),
- {
- currentLevel,
- onLevel: 0,
- options: {
- executeIfOff: false,
- coupleColorTempToLevel: false,
- },
- },
- {
- moveToLevel: async ({ request, attributes, endpoint }) => {
- this.log.debug('Matter command: moveToLevel request:', request, 'attributes.currentLevel:', attributes.currentLevel.getLocal());
- // await this.commandHandler.executeHandler('moveToLevel', { request, attributes, endpoint });
- },
- move: async () => {
- this.log.error('Matter command: move not implemented');
- },
- step: async () => {
- this.log.error('Matter command: step not implemented');
- },
- stop: async () => {
- this.log.error('Matter command: stop not implemented');
- },
- moveToLevelWithOnOff: async ({ request, attributes, endpoint }) => {
- this.log.debug('Matter command: moveToLevelWithOnOff request:', request, 'attributes.currentLevel:', attributes.currentLevel.getLocal());
- // await this.commandHandler.executeHandler('moveToLevelWithOnOff', { request, attributes, endpoint });
- },
- moveWithOnOff: async () => {
- this.log.error('Matter command: moveWithOnOff not implemented');
- },
- stepWithOnOff: async () => {
- this.log.error('Matter command: stepWithOnOff not implemented');
- },
- stopWithOnOff: async () => {
- this.log.error('Matter command: stopWithOnOff not implemented');
- },
- },
- );
- }
-
- /**
- * Creates a default level control cluster server.
- *
- * @param currentLevel - The current level (default: 0).
- */
- createDefaultLevelControlClusterServer(currentLevel = 0) {
- this.addClusterServer(this.getDefaultLevelControlClusterServer(currentLevel));
- }
-
- /**
- * Get a default color control cluster server.
- *
- * @param currentHue - The current hue value.
- * @param currentSaturation - The current saturation value.
- * @param colorTemperatureMireds - The color temperature in mireds.
- * @param colorTempPhysicalMinMireds - The physical minimum color temperature in mireds.
- * @param colorTempPhysicalMaxMireds - The physical maximum color temperature in mireds.
- */
- getDefaultColorControlClusterServer(currentHue = 0, currentSaturation = 0, colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
- return ClusterServer(
- ColorControlCluster.with(ColorControl.Feature.HueSaturation, ColorControl.Feature.ColorTemperature),
- {
- colorMode: ColorControl.ColorMode.CurrentHueAndCurrentSaturation,
- options: {
- executeIfOff: false,
- },
- numberOfPrimaries: null,
- enhancedColorMode: ColorControl.EnhancedColorMode.CurrentHueAndCurrentSaturation,
- colorCapabilities: { xy: false, hueSaturation: true, colorLoop: false, enhancedHue: false, colorTemperature: true },
- currentHue,
- currentSaturation,
- colorTemperatureMireds,
- colorTempPhysicalMinMireds,
- colorTempPhysicalMaxMireds,
- },
- {
- moveToHue: async ({ request, attributes, endpoint }) => {
- this.log.debug('Matter command: moveToHue request:', request, 'attributes.currentHue:', attributes.currentHue.getLocal());
- // attributes.currentHue.setLocal(request.hue);
- // this.commandHandler.executeHandler('moveToHue', { request, attributes, endpoint });
- },
- moveHue: async () => {
- this.log.error('Matter command: moveHue not implemented');
- },
- stepHue: async () => {
- this.log.error('Matter command: stepHue not implemented');
- },
- moveToSaturation: async ({ request, attributes, endpoint }) => {
- this.log.debug('Matter command: moveToSaturation request:', request, 'attributes.currentSaturation:', attributes.currentSaturation.getLocal());
- // attributes.currentSaturation.setLocal(request.saturation);
- // this.commandHandler.executeHandler('moveToSaturation', { request, attributes, endpoint });
- },
- moveSaturation: async () => {
- this.log.error('Matter command: moveSaturation not implemented');
- },
- stepSaturation: async () => {
- this.log.error('Matter command: stepSaturation not implemented');
- },
- moveToHueAndSaturation: async ({ request, attributes, endpoint }) => {
- this.log.debug('Matter command: moveToHueAndSaturation request:', request, 'attributes.currentHue:', attributes.currentHue.getLocal(), 'attributes.currentSaturation:', attributes.currentSaturation.getLocal());
- // attributes.currentHue.setLocal(request.hue);
- // attributes.currentSaturation.setLocal(request.saturation);
- // this.commandHandler.executeHandler('moveToHueAndSaturation', { request, attributes, endpoint });
- },
- stopMoveStep: async () => {
- this.log.error('Matter command: stopMoveStep not implemented');
- },
- moveToColorTemperature: async ({ request, attributes, endpoint }) => {
- this.log.debug('Matter command: moveToColorTemperature request:', request, 'attributes.colorTemperatureMireds:', attributes.colorTemperatureMireds.getLocal());
- // attributes.colorTemperatureMireds.setLocal(request.colorTemperatureMireds);
- // this.commandHandler.executeHandler('moveToColorTemperature', { request, attributes, endpoint });
- },
- moveColorTemperature: async () => {
- this.log.error('Matter command: moveColorTemperature not implemented');
- },
- stepColorTemperature: async () => {
- this.log.error('Matter command: stepColorTemperature not implemented');
- },
- },
- {},
- );
- }
- /**
- * Creates a default color control cluster server.
- *
- * @param currentHue - The current hue value.
- * @param currentSaturation - The current saturation value.
- * @param colorTemperatureMireds - The color temperature in mireds.
- * @param colorTempPhysicalMinMireds - The physical minimum color temperature in mireds.
- * @param colorTempPhysicalMaxMireds - The physical maximum color temperature in mireds.
- */
- createDefaultColorControlClusterServer(currentHue = 0, currentSaturation = 0, colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
- this.addClusterServer(this.getDefaultColorControlClusterServer(currentHue, currentSaturation, colorTemperatureMireds, colorTempPhysicalMinMireds, colorTempPhysicalMaxMireds));
- }
-
- /**
- * Get a default color control cluster server.
- *
- * @param currentHue - The current hue value.
- * @param currentSaturation - The current saturation value.
- * @param colorTemperatureMireds - The color temperature in mireds.
- * @param colorTempPhysicalMinMireds - The physical minimum color temperature in mireds.
- * @param colorTempPhysicalMaxMireds - The physical maximum color temperature in mireds.
- */
- getDefaultXYColorControlClusterServer(currentX = 0, currentY = 0, colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
- return ClusterServer(
- ColorControlCluster.with(ColorControl.Feature.Xy, ColorControl.Feature.HueSaturation, ColorControl.Feature.ColorTemperature),
- {
- colorMode: ColorControl.ColorMode.CurrentHueAndCurrentSaturation,
- options: {
- executeIfOff: false,
- },
- numberOfPrimaries: null,
- enhancedColorMode: ColorControl.EnhancedColorMode.CurrentHueAndCurrentSaturation,
- colorCapabilities: { xy: true, hueSaturation: true, colorLoop: false, enhancedHue: false, colorTemperature: true },
- currentHue: 0,
- currentSaturation: 0,
- currentX,
- currentY,
- colorTemperatureMireds,
- colorTempPhysicalMinMireds,
- colorTempPhysicalMaxMireds,
- },
- {
- moveToColor: async (data) => {
- this.log.debug('Matter command: moveToColor request:', data.request, 'attributes.currentHue:', data.attributes.currentX.getLocal(), data.attributes.currentY.getLocal());
- // this.commandHandler.executeHandler('moveToColor', data);
- },
- moveColor: async () => {
- this.log.error('Matter command: moveColor not implemented');
- },
- stepColor: async () => {
- this.log.error('Matter command: stepColor not implemented');
- },
- moveToHue: async ({ request, attributes, endpoint }) => {
- this.log.debug('Matter command: moveToHue request:', request, 'attributes.currentHue:', attributes.currentHue.getLocal());
- // this.commandHandler.executeHandler('moveToHue', { request, attributes, endpoint });
- },
- moveHue: async () => {
- this.log.error('Matter command: moveHue not implemented');
- },
- stepHue: async () => {
- this.log.error('Matter command: stepHue not implemented');
- },
- moveToSaturation: async ({ request, attributes, endpoint }) => {
- this.log.debug('Matter command: moveToSaturation request:', request, 'attributes.currentSaturation:', attributes.currentSaturation.getLocal());
- // this.commandHandler.executeHandler('moveToSaturation', { request, attributes, endpoint });
- },
- moveSaturation: async () => {
- this.log.error('Matter command: moveSaturation not implemented');
- },
- stepSaturation: async () => {
- this.log.error('Matter command: stepSaturation not implemented');
- },
- moveToHueAndSaturation: async ({ request, attributes, endpoint }) => {
- this.log.debug('Matter command: moveToHueAndSaturation request:', request, 'attributes.currentHue:', attributes.currentHue.getLocal(), 'attributes.currentSaturation:', attributes.currentSaturation.getLocal());
- // this.commandHandler.executeHandler('moveToHueAndSaturation', { request, attributes, endpoint });
- },
- stopMoveStep: async () => {
- this.log.error('Matter command: stopMoveStep not implemented');
- },
- moveToColorTemperature: async ({ request, attributes, endpoint }) => {
- this.log.debug('Matter command: moveToColorTemperature request:', request, 'attributes.colorTemperatureMireds:', attributes.colorTemperatureMireds.getLocal());
- // this.commandHandler.executeHandler('moveToColorTemperature', { request, attributes, endpoint });
- },
- moveColorTemperature: async () => {
- this.log.error('Matter command: moveColorTemperature not implemented');
- },
- stepColorTemperature: async () => {
- this.log.error('Matter command: stepColorTemperature not implemented');
- },
- },
- {},
- );
- }
- /**
- * Creates a default color control cluster server.
- *
- * @param currentHue - The current hue value.
- * @param currentSaturation - The current saturation value.
- * @param colorTemperatureMireds - The color temperature in mireds.
- * @param colorTempPhysicalMinMireds - The physical minimum color temperature in mireds.
- * @param colorTempPhysicalMaxMireds - The physical maximum color temperature in mireds.
- */
- createDefaultXYColorControlClusterServer(currentX = 0, currentY = 0, colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
- this.addClusterServer(this.getDefaultXYColorControlClusterServer(currentX, currentY, colorTemperatureMireds, colorTempPhysicalMinMireds, colorTempPhysicalMaxMireds));
- }
-
- /**
- * Get a default window covering cluster server.
- *
- * @param positionPercent100ths - The position percentage in 100ths (0-10000). Defaults to 0.
- */
- getDefaultWindowCoveringClusterServer(positionPercent100ths?: number) {
- return ClusterServer(
- WindowCoveringCluster.with(WindowCovering.Feature.Lift, WindowCovering.Feature.PositionAwareLift, WindowCovering.Feature.AbsolutePosition),
- {
- type: WindowCovering.WindowCoveringType.Rollershade,
- configStatus: {
- operational: true,
- onlineReserved: true,
- liftMovementReversed: false,
- liftPositionAware: true,
- tiltPositionAware: false,
- liftEncoderControlled: false,
- tiltEncoderControlled: false,
- },
- operationalStatus: { global: WindowCovering.MovementStatus.Stopped, lift: WindowCovering.MovementStatus.Stopped, tilt: WindowCovering.MovementStatus.Stopped },
- endProductType: WindowCovering.EndProductType.RollerShade,
- mode: { motorDirectionReversed: false, calibrationMode: false, maintenanceMode: false, ledFeedback: false },
- targetPositionLiftPercent100ths: positionPercent100ths ?? 0, // 0 Fully open 10000 fully closed
- currentPositionLiftPercent100ths: positionPercent100ths ?? 0, // 0 Fully open 10000 fully closed
- installedClosedLimitLift: 10000,
- installedOpenLimitLift: 0,
- },
- {
- upOrOpen: async (data) => {
- this.log.debug('Matter command: upOrOpen');
- // await this.commandHandler.executeHandler('upOrOpen', data);
- },
- downOrClose: async (data) => {
- this.log.debug('Matter command: downOrClose');
- // await this.commandHandler.executeHandler('downOrClose', data);
- },
- stopMotion: async (data) => {
- this.log.debug('Matter command: stopMotion');
- // await this.commandHandler.executeHandler('stopMotion', data);
- },
- goToLiftPercentage: async (data) => {
- this.log.debug(
- `Matter command: goToLiftPercentage: ${data.request.liftPercent100thsValue} current: ${data.attributes.currentPositionLiftPercent100ths?.getLocal()} ` +
- `target: ${data.attributes.targetPositionLiftPercent100ths?.getLocal()} status: ${data.attributes.operationalStatus.getLocal().lift}`,
- );
- // await this.commandHandler.executeHandler('goToLiftPercentage', data);
- },
- },
- {},
- );
- }
- /**
- * Creates a default window covering cluster server.
- *
- * @param positionPercent100ths - The position percentage in 100ths (0-10000). Defaults to 0.
- */
- createDefaultWindowCoveringClusterServer(positionPercent100ths?: number) {
- this.addClusterServer(this.getDefaultWindowCoveringClusterServer(positionPercent100ths));
- }
-
- /**
- * Sets the window covering target position as the current position and stops the movement.
- */
- setWindowCoveringTargetAsCurrentAndStopped(endpoint?: MatterbridgeDeviceV8) {
- if (!endpoint) endpoint = this as MatterbridgeDeviceV8;
- const windowCoveringCluster = endpoint.getClusterServer(WindowCoveringCluster.with(WindowCovering.Feature.Lift, WindowCovering.Feature.PositionAwareLift, WindowCovering.Feature.AbsolutePosition));
- if (windowCoveringCluster) {
- const position = windowCoveringCluster.getCurrentPositionLiftPercent100thsAttribute();
- if (position !== null) {
- windowCoveringCluster.setTargetPositionLiftPercent100thsAttribute(position);
- windowCoveringCluster.setOperationalStatusAttribute({
- global: WindowCovering.MovementStatus.Stopped,
- lift: WindowCovering.MovementStatus.Stopped,
- tilt: 0,
- });
- }
- this.log.debug(`Set WindowCovering currentPositionLiftPercent100ths and targetPositionLiftPercent100ths to ${position} and operationalStatus to Stopped.`);
- }
- }
-
- /**
- * Sets the current and target status of a window covering.
- * @param current - The current position of the window covering.
- * @param target - The target position of the window covering.
- * @param status - The movement status of the window covering.
- */
- setWindowCoveringCurrentTargetStatus(current: number, target: number, status: WindowCovering.MovementStatus, endpoint?: MatterbridgeDeviceV8) {
- if (!endpoint) endpoint = this as MatterbridgeDeviceV8;
- const windowCoveringCluster = endpoint.getClusterServer(WindowCoveringCluster.with(WindowCovering.Feature.Lift, WindowCovering.Feature.PositionAwareLift, WindowCovering.Feature.AbsolutePosition));
- if (windowCoveringCluster) {
- windowCoveringCluster.setCurrentPositionLiftPercent100thsAttribute(current);
- windowCoveringCluster.setTargetPositionLiftPercent100thsAttribute(target);
- windowCoveringCluster.setOperationalStatusAttribute({
- global: status,
- lift: status,
- tilt: 0,
- });
- }
- this.log.debug(`Set WindowCovering currentPositionLiftPercent100ths: ${current}, targetPositionLiftPercent100ths: ${target} and operationalStatus: ${status}.`);
- }
-
- /**
- * Sets the status of the window covering.
- * @param {WindowCovering.MovementStatus} status - The movement status to set.
- */
- setWindowCoveringStatus(status: WindowCovering.MovementStatus, endpoint?: MatterbridgeDeviceV8) {
- if (!endpoint) endpoint = this as MatterbridgeDeviceV8;
- const windowCovering = endpoint.getClusterServer(WindowCoveringCluster.with(WindowCovering.Feature.Lift, WindowCovering.Feature.PositionAwareLift, WindowCovering.Feature.AbsolutePosition));
- if (!windowCovering) return;
- windowCovering.setOperationalStatusAttribute({ global: status, lift: status, tilt: 0 });
- this.log.debug(`Set WindowCovering operationalStatus: ${status}`);
- }
-
- /**
- * Retrieves the status of the window covering.
- * @returns The global operational status of the window covering.
- */
- getWindowCoveringStatus(endpoint?: MatterbridgeDeviceV8) {
- if (!endpoint) endpoint = this as MatterbridgeDeviceV8;
- const windowCovering = endpoint.getClusterServer(WindowCoveringCluster.with(WindowCovering.Feature.Lift, WindowCovering.Feature.PositionAwareLift, WindowCovering.Feature.AbsolutePosition));
- if (!windowCovering) return undefined;
- const status = windowCovering.getOperationalStatusAttribute();
- this.log.debug(`Get WindowCovering operationalStatus: ${status.global}`);
- return status.global;
- }
-
- /**
- * Sets the target and current position of the window covering.
- *
- * @param position - The position to set, specified as a number.
- */
- setWindowCoveringTargetAndCurrentPosition(position: number, endpoint?: MatterbridgeDeviceV8) {
- if (!endpoint) endpoint = this as MatterbridgeDeviceV8;
- const windowCovering = endpoint.getClusterServer(WindowCoveringCluster.with(WindowCovering.Feature.Lift, WindowCovering.Feature.PositionAwareLift));
- if (!windowCovering) return;
- windowCovering.setCurrentPositionLiftPercent100thsAttribute(position);
- windowCovering.setTargetPositionLiftPercent100thsAttribute(position);
- this.log.debug(`Set WindowCovering currentPositionLiftPercent100ths: ${position} and targetPositionLiftPercent100ths: ${position}.`);
- }
-
- /**
- * Get a default door lock cluster server.
- *
- * @remarks
- * This method adds a cluster server for a door lock cluster with default settings.
- *
- */
- getDefaultDoorLockClusterServer(lockState = DoorLock.LockState.Locked, lockType = DoorLock.LockType.Deadbolt) {
- return ClusterServer(
- DoorLockCluster,
- {
- operatingMode: DoorLock.OperatingMode.Normal,
- lockState,
- lockType,
- actuatorEnabled: false,
- supportedOperatingModes: { normal: true, vacation: false, privacy: false, noRemoteLockUnlock: false, passage: false },
- },
- {
- lockDoor: async (data) => {
- this.log.debug('Matter command: lockDoor', data.request);
- // await this.commandHandler.executeHandler('lockDoor', data);
- },
- unlockDoor: async (data) => {
- this.log.debug('Matter command: unlockDoor', data.request);
- // await this.commandHandler.executeHandler('unlockDoor', data);
- },
- },
- {
- doorLockAlarm: true,
- lockOperation: true,
- lockOperationError: true,
- },
- );
- }
- /**
- * Creates a default door lock cluster server.
- *
- * @remarks
- * This method adds a cluster server for a door lock cluster with default settings.
- *
- */
- createDefaultDoorLockClusterServer(lockState = DoorLock.LockState.Locked, lockType = DoorLock.LockType.Deadbolt) {
- this.addClusterServer(this.getDefaultDoorLockClusterServer(lockState, lockType));
- }
-
- /**
- * Get a default momentary switch cluster server.
- *
- * @remarks
- * This method adds a cluster server with default momentary switch features and configurations suitable for (AppleHome) Single Double Long automations.
- */
- getDefaultSwitchClusterServer() {
- return ClusterServer(
- SwitchCluster.with(Switch.Feature.MomentarySwitch, Switch.Feature.MomentarySwitchRelease, Switch.Feature.MomentarySwitchLongPress, Switch.Feature.MomentarySwitchMultiPress),
- {
- numberOfPositions: 2,
- currentPosition: 0,
- multiPressMax: 2,
- },
- {},
- {
- initialPress: true,
- longPress: true,
- shortRelease: true,
- longRelease: true,
- multiPressOngoing: true,
- multiPressComplete: true,
- },
- );
- }
-
- /**
- * Creates a default momentary switch cluster server.
- *
- * @remarks
- * This method adds a cluster server with default momentary switch features and configurations.
- */
- createDefaultSwitchClusterServer() {
- this.addClusterServer(this.getDefaultSwitchClusterServer());
- // this.addFixedLabel('orientation', 'Switch');
- // this.addFixedLabel('label', 'Switch');
- }
-
- /**
- * Get a default latching switch cluster server.
- *
- * @remarks
- * This method adds a cluster server with default latching switch features and configuration.
- */
- getDefaultLatchingSwitchClusterServer() {
- return ClusterServer(
- SwitchCluster.with(Switch.Feature.LatchingSwitch),
- {
- numberOfPositions: 2,
- currentPosition: 0,
- },
- {},
- {
- switchLatched: true,
- },
- );
- }
-
- /**
- * Creates a default latching switch cluster server.
- *
- * @remarks
- * This method adds a cluster server with default latching switch features and configuration.
- */
- createDefaultLatchingSwitchClusterServer() {
- this.addClusterServer(this.getDefaultLatchingSwitchClusterServer());
- // this.addFixedLabel('orientation', 'Switch');
- // this.addFixedLabel('label', 'Switch');
- }
-
- /*
- getDefaultModeSelectClusterServer(description: string, supportedModes: ModeSelect.ModeOptionStruct[], currentMode = 0, startUpMode = 0) {
- return ClusterServer(
- ModeSelectCluster,
- {
- description: description,
- standardNamespace: null,
- supportedModes: supportedModes,
- currentMode: currentMode,
- startUpMode: startUpMode,
- },
- {
- changeToMode: async (data) => {
- this.log.debug('Matter command: changeToMode', data.request);
- await this.commandHandler.executeHandler('changeToMode', data);
- },
- },
- );
- }
- createDefaultModeSelectClusterServer(endpoint?: Endpoint) {
- if (!endpoint) endpoint = this as Endpoint;
- endpoint.addClusterServer(
- this.getDefaultModeSelectClusterServer('Mode select', [
- { label: 'Mode 0', mode: 0, semanticTags: [{ mfgCode: VendorId(0xfff1), value: 0 }] },
- { label: 'Mode 1', mode: 1, semanticTags: [{ mfgCode: VendorId(0xfff1), value: 1 }] },
- ]),
- );
- }
- */
-
- /**
- * Get a default occupancy sensing cluster server.
- *
- * @param occupied - A boolean indicating whether the occupancy is occupied or not. Default is false.
- */
- getDefaultOccupancySensingClusterServer(occupied = false) {
- return ClusterServer(
- OccupancySensingCluster,
- {
- occupancy: { occupied },
- occupancySensorType: OccupancySensing.OccupancySensorType.Pir,
- occupancySensorTypeBitmap: { pir: true, ultrasonic: false, physicalContact: false },
- pirOccupiedToUnoccupiedDelay: 30,
- },
- {},
- );
- }
- /**
- * Creates a default occupancy sensing cluster server.
- *
- * @param occupied - A boolean indicating whether the occupancy is occupied or not. Default is false.
- */
- createDefaultOccupancySensingClusterServer(occupied = false) {
- this.addClusterServer(this.getDefaultOccupancySensingClusterServer(occupied));
- }
-
- /**
- * Get a default Illuminance Measurement Cluster Server.
- *
- * @param measuredValue - The measured value of illuminance.
- */
- getDefaultIlluminanceMeasurementClusterServer(measuredValue = 0) {
- return ClusterServer(
- IlluminanceMeasurementCluster,
- {
- measuredValue,
- minMeasuredValue: null,
- maxMeasuredValue: null,
- tolerance: 0,
- },
- {},
- {},
- );
- }
- /**
- * Creates a default Illuminance Measurement Cluster Server.
- *
- * @param measuredValue - The measured value of illuminance.
- */
- createDefaultIlluminanceMeasurementClusterServer(measuredValue = 0) {
- this.addClusterServer(this.getDefaultIlluminanceMeasurementClusterServer(measuredValue));
- }
-
- /**
- * Get a default flow measurement cluster server.
- *
- * @param measuredValue - The measured value of the temperature.
- */
- getDefaultFlowMeasurementClusterServer(measuredValue = 0) {
- return ClusterServer(
- FlowMeasurementCluster,
- {
- measuredValue,
- minMeasuredValue: null,
- maxMeasuredValue: null,
- tolerance: 0,
- },
- {},
- {},
- );
- }
-
- /**
- * Creates a default flow measurement cluster server.
- *
- * @param measuredValue - The measured value of the temperature.
- */
- createDefaultFlowMeasurementClusterServer(measuredValue = 0) {
- this.addClusterServer(this.getDefaultFlowMeasurementClusterServer(measuredValue));
- }
-
- /**
- * Get a default temperature measurement cluster server.
- *
- * @param measuredValue - The measured value of the temperature.
- */
- getDefaultTemperatureMeasurementClusterServer(measuredValue = 0) {
- return ClusterServer(
- TemperatureMeasurementCluster,
- {
- measuredValue,
- minMeasuredValue: null,
- maxMeasuredValue: null,
- tolerance: 0,
- },
- {},
- {},
- );
- }
-
- /**
- * Creates a default temperature measurement cluster server.
- *
- * @param measuredValue - The measured value of the temperature.
- */
- createDefaultTemperatureMeasurementClusterServer(measuredValue = 0) {
- this.addClusterServer(this.getDefaultTemperatureMeasurementClusterServer(measuredValue));
- }
-
- /**
- * Get a default RelativeHumidityMeasurementCluster server.
- *
- * @param measuredValue - The measured value of the relative humidity.
- */
- getDefaultRelativeHumidityMeasurementClusterServer(measuredValue = 0) {
- return ClusterServer(
- RelativeHumidityMeasurementCluster,
- {
- measuredValue,
- minMeasuredValue: null,
- maxMeasuredValue: null,
- tolerance: 0,
- },
- {},
- {},
- );
- }
- /**
- * Creates a default RelativeHumidityMeasurementCluster server.
- *
- * @param measuredValue - The measured value of the relative humidity.
- */
- createDefaultRelativeHumidityMeasurementClusterServer(measuredValue = 0) {
- this.addClusterServer(this.getDefaultRelativeHumidityMeasurementClusterServer(measuredValue));
- }
-
- /**
- * Get a default Pressure Measurement Cluster Server.
- *
- * @param measuredValue - The measured value for the pressure.
- */
- getDefaultPressureMeasurementClusterServer(measuredValue = 1000) {
- return ClusterServer(
- PressureMeasurementCluster,
- {
- measuredValue,
- minMeasuredValue: null,
- maxMeasuredValue: null,
- tolerance: 0,
- },
- {},
- {},
- );
- }
- /**
- * Creates a default Pressure Measurement Cluster Server.
- *
- * @param measuredValue - The measured value for the pressure.
- */
- createDefaultPressureMeasurementClusterServer(measuredValue = 1000) {
- this.addClusterServer(this.getDefaultPressureMeasurementClusterServer(measuredValue));
- }
-
- /**
- * Get a default boolean state cluster server.
- *
- * @param contact - Optional boolean value indicating the contact state. Defaults to `true` if not provided.
- */
- getDefaultBooleanStateClusterServer(contact?: boolean) {
- return ClusterServer(
- BooleanStateCluster,
- {
- stateValue: contact ?? true, // true=contact false=no_contact
- },
- {},
- {
- stateChange: true,
- },
- );
- }
-
- /**
- * Creates a default boolean state configuration cluster server.
- *
- * @param contact - Optional boolean value indicating the contact state. Defaults to `true` if not provided.
- */
- createDefaultBooleanStateClusterServer(contact?: boolean) {
- this.addClusterServer(this.getDefaultBooleanStateClusterServer(contact));
- }
-
- /**
- * Get a default boolean state configuration cluster server.
- *
- * @param contact - Optional boolean value indicating the sensor fault state. Defaults to `false` if not provided.
- */
- getDefaultBooleanStateConfigurationClusterServer(sensorFault = false) {
- return ClusterServer(
- BooleanStateConfigurationCluster.with(BooleanStateConfiguration.Feature.Visual, BooleanStateConfiguration.Feature.Audible, BooleanStateConfiguration.Feature.SensitivityLevel),
- {
- currentSensitivityLevel: 0,
- supportedSensitivityLevels: 2,
- defaultSensitivityLevel: 0,
- alarmsActive: { visual: false, audible: false },
- alarmsEnabled: { visual: false, audible: false },
- alarmsSupported: { visual: true, audible: true },
- // alarmsSuppressed: { visual: false, audible: false },
- sensorFault: { generalFault: sensorFault },
- },
- {
- enableDisableAlarm: async ({ request, attributes }) => {
- this.log.debug('Matter command: enableDisableAlarm', request);
- // await this.commandHandler.executeHandler('enableDisableAlarm', { request, attributes });
- },
- },
- {
- alarmsStateChanged: true,
- sensorFault: true,
- },
- );
- }
- /**
- * Creates a default boolean state configuration cluster server.
- *
- * @param contact - Optional boolean value indicating the sensor fault state. Defaults to `false` if not provided.
- */
- createDefaultBooleanStateConfigurationClusterServer(sensorFault = false) {
- this.addClusterServer(this.getDefaultBooleanStateConfigurationClusterServer(sensorFault));
- }
-
- /**
- * Get a default power source replaceable battery cluster server.
- *
- * @param batPercentRemaining - The remaining battery percentage (default: 100).
- * @param batChargeLevel - The battery charge level (default: PowerSource.BatChargeLevel.Ok).
- * @param batVoltage - The battery voltage (default: 1500).
- * @param batReplacementDescription - The battery replacement description (default: 'Battery type').
- * @param batQuantity - The battery quantity (default: 1).
- */
- getDefaultPowerSourceReplaceableBatteryClusterServer(batPercentRemaining = 100, batChargeLevel: PowerSource.BatChargeLevel = PowerSource.BatChargeLevel.Ok, batVoltage = 1500, batReplacementDescription = 'Battery type', batQuantity = 1) {
- return ClusterServer(
- PowerSourceCluster.with(PowerSource.Feature.Battery, PowerSource.Feature.Replaceable),
- {
- status: PowerSource.PowerSourceStatus.Active,
- order: 0,
- description: 'Primary battery',
- batVoltage,
- batPercentRemaining: Math.min(Math.max(batPercentRemaining * 2, 0), 200),
- batChargeLevel,
- batReplacementNeeded: false,
- batReplaceability: PowerSource.BatReplaceability.UserReplaceable,
- activeBatFaults: undefined,
- batReplacementDescription,
- batQuantity,
- },
- {},
- {},
- );
- }
-
- /**
- * Creates a default power source replaceable battery cluster server.
- *
- * @param batPercentRemaining - The remaining battery percentage (default: 100).
- * @param batChargeLevel - The battery charge level (default: PowerSource.BatChargeLevel.Ok).
- * @param batVoltage - The battery voltage (default: 1500).
- * @param batReplacementDescription - The battery replacement description (default: 'Battery type').
- * @param batQuantity - The battery quantity (default: 1).
- */
- createDefaultPowerSourceReplaceableBatteryClusterServer(batPercentRemaining = 100, batChargeLevel: PowerSource.BatChargeLevel = PowerSource.BatChargeLevel.Ok, batVoltage = 1500, batReplacementDescription = 'Battery type', batQuantity = 1) {
- this.addClusterServer(this.getDefaultPowerSourceReplaceableBatteryClusterServer(batPercentRemaining, batChargeLevel, batVoltage, batReplacementDescription, batQuantity));
- }
-
- /**
- * Get a default power source rechargeable battery cluster server.
- *
- * @param batPercentRemaining - The remaining battery percentage (default: 100).
- * @param batChargeLevel - The battery charge level (default: PowerSource.BatChargeLevel.Ok).
- * @param batVoltage - The battery voltage (default: 1500).
- */
- getDefaultPowerSourceRechargeableBatteryClusterServer(batPercentRemaining = 100, batChargeLevel: PowerSource.BatChargeLevel = PowerSource.BatChargeLevel.Ok, batVoltage = 1500) {
- return ClusterServer(
- PowerSourceCluster.with(PowerSource.Feature.Battery, PowerSource.Feature.Rechargeable),
- {
- status: PowerSource.PowerSourceStatus.Active,
- order: 0,
- description: 'Primary battery',
- batVoltage,
- batPercentRemaining: Math.min(Math.max(batPercentRemaining * 2, 0), 200),
- batTimeRemaining: 1,
- batChargeLevel,
- batReplacementNeeded: false,
- batReplaceability: PowerSource.BatReplaceability.Unspecified,
- activeBatFaults: undefined,
- batChargeState: PowerSource.BatChargeState.IsNotCharging,
- batFunctionalWhileCharging: true,
- },
- {},
- {},
- );
- }
-
- /**
- * Creates a default power source rechargeable battery cluster server.
- *
- * @param batPercentRemaining - The remaining battery percentage (default: 100).
- * @param batChargeLevel - The battery charge level (default: PowerSource.BatChargeLevel.Ok).
- * @param batVoltage - The battery voltage (default: 1500).
- */
- createDefaultPowerSourceRechargeableBatteryClusterServer(batPercentRemaining = 100, batChargeLevel: PowerSource.BatChargeLevel = PowerSource.BatChargeLevel.Ok, batVoltage = 1500) {
- this.addClusterServer(this.getDefaultPowerSourceRechargeableBatteryClusterServer(batPercentRemaining, batChargeLevel, batVoltage));
- }
-
- /**
- * Get a default power source wired cluster server.
- *
- * @param wiredCurrentType - The type of wired current (default: PowerSource.WiredCurrentType.Ac)
- */
- getDefaultPowerSourceWiredClusterServer(wiredCurrentType: PowerSource.WiredCurrentType = PowerSource.WiredCurrentType.Ac) {
- return ClusterServer(
- PowerSourceCluster.with(PowerSource.Feature.Wired),
- {
- wiredCurrentType,
- description: wiredCurrentType === PowerSource.WiredCurrentType.Ac ? 'AC Power' : 'DC Power',
- status: PowerSource.PowerSourceStatus.Active,
- order: 0,
- },
- {},
- {},
- );
- }
-
- /**
- * Creates a default power source wired cluster server.
- *
- * @param wiredCurrentType - The type of wired current (default: PowerSource.WiredCurrentType.Ac)
- */
- createDefaultPowerSourceWiredClusterServer(wiredCurrentType: PowerSource.WiredCurrentType = PowerSource.WiredCurrentType.Ac) {
- this.addClusterServer(this.getDefaultPowerSourceWiredClusterServer(wiredCurrentType));
- }
-
- /**
- * @deprecated This function is deprecated by Matter 1.3 spec and will be removed in a future version.
- */
- createDefaultPowerSourceConfigurationClusterServer(endpointNumber?: number) {
- this.addClusterServer(
- ClusterServer(
- PowerSourceConfigurationCluster,
- {
- sources: endpointNumber ? [EndpointNumber(endpointNumber)] : [],
- },
- {},
- {},
- ),
- );
- }
-
- /**
- * Get a default air quality cluster server.
- *
- * @param airQuality The air quality type. Defaults to `AirQuality.AirQualityType.Unknown`.
- */
- getDefaultAirQualityClusterServer(airQuality = AirQuality.AirQualityType.Unknown) {
- return ClusterServer(
- AirQualityCluster.with(AirQuality.Feature.FairAirQuality, AirQuality.Feature.ModerateAirQuality, AirQuality.Feature.VeryPoorAirQuality),
- {
- airQuality,
- },
- {},
- {},
- );
- }
- /**
- * Creates a default air quality cluster server.
- *
- * @param airQuality The air quality type. Defaults to `AirQuality.AirQualityType.Unknown`.
- */
- createDefaultAirQualityClusterServer(airQuality = AirQuality.AirQualityType.Unknown) {
- this.addClusterServer(this.getDefaultAirQualityClusterServer(airQuality));
- }
-
- /**
- * Get a default TVOC measurement cluster server.
- *
- * @param measuredValue - The measured value for TVOC.
- */
- getDefaultTvocMeasurementClusterServer(measuredValue = 0) {
- return ClusterServer(
- TvocMeasurementCluster.with(TvocMeasurement.Feature.NumericMeasurement),
- {
- measuredValue,
- minMeasuredValue: null,
- maxMeasuredValue: null,
- },
- {},
- {},
- );
- }
-
- /**
- * Creates a default TVOC measurement cluster server.
- *
- * @param measuredValue - The measured value for TVOC.
- */
- createDefaultTvocMeasurementClusterServer(measuredValue = 0) {
- this.addClusterServer(this.getDefaultTvocMeasurementClusterServer(measuredValue));
- }
-
- /**
- * Get a default thermostat cluster server with the specified parameters.
- *
- * @param localTemperature - The local temperature value in degrees Celsius. Defaults to 23.
- * @param occupiedHeatingSetpoint - The occupied heating setpoint value in degrees Celsius. Defaults to 21.
- * @param occupiedCoolingSetpoint - The occupied cooling setpoint value in degrees Celsius. Defaults to 25.
- * @param minSetpointDeadBand - The minimum setpoint dead band value.
- */
- getDefaultThermostatClusterServer(localTemperature = 23, occupiedHeatingSetpoint = 21, occupiedCoolingSetpoint = 25, minSetpointDeadBand = 1) {
- return ClusterServer(
- ThermostatCluster.with(Thermostat.Feature.Heating, Thermostat.Feature.Cooling, Thermostat.Feature.AutoMode),
- {
- localTemperature: localTemperature * 100,
- occupiedHeatingSetpoint: occupiedHeatingSetpoint * 100,
- occupiedCoolingSetpoint: occupiedCoolingSetpoint * 100,
- minHeatSetpointLimit: 0,
- maxHeatSetpointLimit: 5000,
- absMinHeatSetpointLimit: 0,
- absMaxHeatSetpointLimit: 5000,
- minCoolSetpointLimit: 0,
- maxCoolSetpointLimit: 5000,
- absMinCoolSetpointLimit: 0,
- absMaxCoolSetpointLimit: 5000,
- minSetpointDeadBand,
- systemMode: Thermostat.SystemMode.Off,
- controlSequenceOfOperation: Thermostat.ControlSequenceOfOperation.CoolingAndHeating,
- thermostatRunningMode: Thermostat.ThermostatRunningMode.Off,
- },
- {
- setpointRaiseLower: async ({ request, attributes }) => {
- this.log.debug('Matter command: setpointRaiseLower', request);
- // await this.commandHandler.executeHandler('setpointRaiseLower', { request, attributes });
- },
- },
- {},
- );
- }
-
- /**
- * Creates and adds a default thermostat cluster server to the device.
- *
- * @param localTemperature - The local temperature value.
- * @param occupiedHeatingSetpoint - The occupied heating setpoint value.
- * @param occupiedCoolingSetpoint - The occupied cooling setpoint value.
- * @param minSetpointDeadBand - The minimum setpoint dead band value.
- */
- createDefaultThermostatClusterServer(localTemperature = 23, occupiedHeatingSetpoint = 21, occupiedCoolingSetpoint = 25, minSetpointDeadBand = 1) {
- this.addClusterServer(this.getDefaultThermostatClusterServer(localTemperature, occupiedHeatingSetpoint, occupiedCoolingSetpoint, minSetpointDeadBand));
- }
-
- /**
- * Get a default dummy time sync cluster server. Only needed to create a thermostat.
- */
- getDefaultTimeSyncClusterServer() {
- return ClusterServer(
- TimeSyncCluster.with(TimeSync.Feature.TimeZone),
- {
- utcTime: null,
- granularity: TimeSync.Granularity.NoTimeGranularity,
- timeZone: [{ offset: 0, validAt: 0 }],
- trustedTimeNodeId: null,
- dstOffset: [],
- localTime: null,
- timeZoneDatabase: true,
- },
- {
- setUtcTime: async ({ request, attributes }) => {
- this.log.debug('Matter command: setUtcTime', request);
- // await this.commandHandler.executeHandler('setUtcTime', { request, attributes });
- },
- },
- {
- dstTableEmpty: true,
- dstStatus: true,
- timeZoneStatus: true,
- },
- );
- }
- /**
- * Creates a default dummy time sync cluster server. Only needed to create a thermostat.
- */
- createDefaultTimeSyncClusterServer() {
- this.addClusterServer(this.getDefaultTimeSyncClusterServer());
- }
-
- /**
- * Returns the default SmokeCOAlarm Cluster Server.
- *
- * @param smokeState - The state of the smoke alarm. Defaults to SmokeCoAlarm.AlarmState.Normal.
- * @param coState - The state of the CO alarm. Defaults to SmokeCoAlarm.AlarmState.Normal.
- * @returns The default SmokeCOAlarmClusterServer.
- */
- getDefaultSmokeCOAlarmClusterServer(smokeState = SmokeCoAlarm.AlarmState.Normal, coState = SmokeCoAlarm.AlarmState.Normal) {
- return ClusterServer(
- SmokeCoAlarmCluster.with(SmokeCoAlarm.Feature.SmokeAlarm, SmokeCoAlarm.Feature.CoAlarm),
- {
- smokeState,
- coState,
- expressedState: SmokeCoAlarm.ExpressedState.Normal,
- batteryAlert: SmokeCoAlarm.AlarmState.Normal,
- deviceMuted: SmokeCoAlarm.MuteState.NotMuted,
- testInProgress: false,
- hardwareFaultAlert: false,
- endOfServiceAlert: SmokeCoAlarm.EndOfService.Normal,
- interconnectSmokeAlarm: SmokeCoAlarm.AlarmState.Normal,
- interconnectCoAlarm: SmokeCoAlarm.AlarmState.Normal,
- },
- {
- selfTestRequest: async ({ request, attributes }) => {
- this.log.debug('Matter command: selfTestRequest');
- // await this.commandHandler.executeHandler('selfTestRequest', { request, attributes });
- },
- },
- {
- smokeAlarm: true,
- interconnectSmokeAlarm: true,
- coAlarm: true,
- interconnectCoAlarm: true,
- lowBattery: true,
- hardwareFault: true,
- endOfService: true,
- selfTestComplete: true,
- alarmMuted: true,
- muteEnded: true,
- allClear: true,
- },
- );
- }
- /**
- * Create the default SmokeCOAlarm Cluster Server.
- *
- * @param smokeState - The state of the smoke alarm. Defaults to SmokeCoAlarm.AlarmState.Normal.
- * @param coState - The state of the CO alarm. Defaults to SmokeCoAlarm.AlarmState.Normal.
- * @returns The default SmokeCOAlarmClusterServer.
- */
- createDefaultSmokeCOAlarmClusterServer(smokeState = SmokeCoAlarm.AlarmState.Normal, coState = SmokeCoAlarm.AlarmState.Normal) {
- this.addClusterServer(this.getDefaultSmokeCOAlarmClusterServer(smokeState, coState));
- }
-
- /**
- * Returns the default Carbon Monoxide Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
- */
- getDefaultCarbonMonoxideConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- return ClusterServer(
- CarbonMonoxideConcentrationMeasurementCluster.with('NumericMeasurement'),
- {
- measuredValue,
- minMeasuredValue: null,
- maxMeasuredValue: null,
- uncertainty: 0,
- measurementUnit,
- measurementMedium,
- },
- {},
- {},
- );
- }
- /**
- * Create the default Carbon Monoxide Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- */
- createDefaultCarbonMonoxideConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- this.addClusterServer(this.getDefaultCarbonMonoxideConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
- }
-
- /**
- * Returns the default Carbon Dioxide Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
- */
- getDefaultCarbonDioxideConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- return ClusterServer(
- CarbonDioxideConcentrationMeasurementCluster.with('NumericMeasurement'),
- {
- measuredValue,
- minMeasuredValue: null,
- maxMeasuredValue: null,
- uncertainty: 0,
- measurementUnit,
- measurementMedium,
- },
- {},
- {},
- );
- }
- /**
- * Create the default Carbon Dioxide Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- */
- createDefaultCarbonDioxideConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- this.addClusterServer(this.getDefaultCarbonDioxideConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
- }
-
- /**
- * Returns the default Formaldehyde Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
- */
- getDefaultFormaldehydeConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- return ClusterServer(
- FormaldehydeConcentrationMeasurementCluster.with('NumericMeasurement'),
- {
- measuredValue,
- minMeasuredValue: null,
- maxMeasuredValue: null,
- uncertainty: 0,
- measurementUnit,
- measurementMedium,
- },
- {},
- {},
- );
- }
- /**
- * Create the default Formaldehyde Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- */
- createDefaultFormaldehydeConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- this.addClusterServer(this.getDefaultFormaldehydeConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
- }
-
- /**
- * Returns the default Pm1 Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
- */
- getDefaultPm1ConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- return ClusterServer(
- Pm1ConcentrationMeasurementCluster.with('NumericMeasurement'),
- {
- measuredValue,
- minMeasuredValue: null,
- maxMeasuredValue: null,
- uncertainty: 0,
- measurementUnit,
- measurementMedium,
- },
- {},
- {},
- );
- }
- /**
- * Create the default Pm1 Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- */
- createDefaulPm1ConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- this.addClusterServer(this.getDefaultPm1ConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
- }
-
- /**
- * Returns the default Pm25 Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
- */
- getDefaultPm25ConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- return ClusterServer(
- Pm25ConcentrationMeasurementCluster.with('NumericMeasurement'),
- {
- measuredValue,
- minMeasuredValue: null,
- maxMeasuredValue: null,
- uncertainty: 0,
- measurementUnit,
- measurementMedium,
- },
- {},
- {},
- );
- }
- /**
- * Create the default Pm25 Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- */
- createDefaulPm25ConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- this.addClusterServer(this.getDefaultPm25ConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
- }
-
- /**
- * Returns the default Pm10 Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
- */
- getDefaultPm10ConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- return ClusterServer(
- Pm10ConcentrationMeasurementCluster.with('NumericMeasurement'),
- {
- measuredValue,
- minMeasuredValue: null,
- maxMeasuredValue: null,
- uncertainty: 0,
- measurementUnit,
- measurementMedium,
- },
- {},
- {},
- );
- }
- /**
- * Create the default Pm10 Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- */
- createDefaulPm10ConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- this.addClusterServer(this.getDefaultPm10ConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
- }
-
- /**
- * Returns the default Ozone Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
- */
- getDefaultOzoneConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ugm3, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- return ClusterServer(
- OzoneConcentrationMeasurementCluster.with('NumericMeasurement'),
- {
- measuredValue,
- minMeasuredValue: null,
- maxMeasuredValue: null,
- uncertainty: 0,
- measurementUnit,
- measurementMedium,
- },
- {},
- {},
- );
- }
- /**
- * Create the default Ozone Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- */
- createDefaulOzoneConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ugm3, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- this.addClusterServer(this.getDefaultOzoneConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
- }
-
- /**
- * Returns the default Radon Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
- */
- getDefaultRadonConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- return ClusterServer(
- RadonConcentrationMeasurementCluster.with('NumericMeasurement'),
- {
- measuredValue,
- minMeasuredValue: null,
- maxMeasuredValue: null,
- uncertainty: 0,
- measurementUnit,
- measurementMedium,
- },
- {},
- {},
- );
- }
- /**
- * Create the default Radon Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- */
- createDefaulRadonConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ppm, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- this.addClusterServer(this.getDefaultRadonConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
- }
-
- /**
- * Returns the default Nitrogen Dioxide Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- * @returns {ClusterServer} - The default Carbon Monoxide Concentration Measurement Cluster Server.
- */
- getDefaultNitrogenDioxideConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ugm3, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- return ClusterServer(
- NitrogenDioxideConcentrationMeasurementCluster.with('NumericMeasurement'),
- {
- measuredValue,
- minMeasuredValue: null,
- maxMeasuredValue: null,
- uncertainty: 0,
- measurementUnit,
- measurementMedium,
- },
- {},
- {},
- );
- }
- /**
- * Create the default Nitrogen Dioxide Concentration Measurement Cluster Server.
- *
- * @param {number} measuredValue - The measured value of the concentration.
- * @param {ConcentrationMeasurement.MeasurementUnit} measurementUnit - The unit of measurement.
- * @param {ConcentrationMeasurement.MeasurementMedium} measurementMedium - The medium of measurement.
- */
- createDefaulNitrogenDioxideConcentrationMeasurementClusterServer(measuredValue = 0, measurementUnit = ConcentrationMeasurement.MeasurementUnit.Ugm3, measurementMedium = ConcentrationMeasurement.MeasurementMedium.Air) {
- this.addClusterServer(this.getDefaultNitrogenDioxideConcentrationMeasurementClusterServer(measuredValue, measurementUnit, measurementMedium));
- }
-
- /**
- * Returns the default fan control cluster server rev 2.
- *
- * @param fanMode The fan mode to set. Defaults to `FanControl.FanMode.Off`.
- * @returns The default fan control cluster server.
- */
- getDefaultFanControlClusterServer(fanMode = FanControl.FanMode.Off) {
- return ClusterServer(
- FanControlCluster.with(FanControl.Feature.MultiSpeed, FanControl.Feature.Auto /* , FanControl.Feature.Step*/),
- {
- fanMode,
- fanModeSequence: FanControl.FanModeSequence.OffLowMedHighAuto,
- percentSetting: 0,
- percentCurrent: 0,
- speedMax: 100,
- speedSetting: 0,
- speedCurrent: 0,
- },
- {
- /*
- step: async ({ request, attributes }) => {
- this.log.debug('Matter command: step', request);
- await this.commandHandler.executeHandler('step', { request, attributes });
- },
- */
- },
- {},
- );
- }
- /**
- * Create the default fan control cluster server rev 2.
- *
- * @param fanMode The fan mode to set. Defaults to `FanControl.FanMode.Off`.
- * @returns The default fan control cluster server.
- */
- createDefaultFanControlClusterServer(fanMode = FanControl.FanMode.Off) {
- this.addClusterServer(this.getDefaultFanControlClusterServer(fanMode));
- }
-
- // NOTE Support of Device Energy Management Cluster is provisional.
- getDefaultDeviceEnergyManagementClusterServer() {
- return ClusterServer(
- DeviceEnergyManagementCluster.with(DeviceEnergyManagement.Feature.Pausable, DeviceEnergyManagement.Feature.PowerForecastReporting, DeviceEnergyManagement.Feature.StateForecastReporting),
- {
- esaType: DeviceEnergyManagement.EsaType.Other,
- esaCanGenerate: false,
- esaState: DeviceEnergyManagement.EsaState.Online,
- absMinPower: 0,
- absMaxPower: 0,
- optOutState: DeviceEnergyManagement.OptOutState.NoOptOut,
- forecast: null,
- },
- {
- pauseRequest: async ({ request, attributes }) => {
- this.log.debug('Matter command: pauseRequest', request);
- // await this.commandHandler.executeHandler('pauseRequest', { request, attributes });
- },
- resumeRequest: async () => {
- this.log.debug('Matter command: resumeRequest');
- // await this.commandHandler.executeHandler('resumeRequest');
- },
- },
- {
- paused: true,
- resumed: true,
- },
- );
- }
-
- // NOTE Support of Device Energy Management Mode Cluster is provisional.
- getDefaultDeviceEnergyManagementModeClusterServer() {
- return ClusterServer(
- DeviceEnergyManagementModeCluster,
- {
- esaType: DeviceEnergyManagement.EsaType.Other,
- esaCanGenerate: false,
- esaState: DeviceEnergyManagement.EsaState.Online,
- absMinPower: 0,
- absMaxPower: 0,
- optOutState: DeviceEnergyManagement.OptOutState.NoOptOut,
- },
- {},
- {},
- );
- }
-}
diff --git a/src/matterbridgeV8.ts b/src/matterbridgeV8.ts
deleted file mode 100644
index 5d946e0f..00000000
--- a/src/matterbridgeV8.ts
+++ /dev/null
@@ -1,785 +0,0 @@
-/* eslint-disable no-console */
-/* eslint-disable @typescript-eslint/no-unused-vars */
-/**
- * This file contains the class NewMatterbridge. Test of new matter.js api
- *
- * @file matterbridgeNewApi.ts
- * @author Luca Liguori
- * @date 2024-06-01
- * @version 1.0.0
- *
- * Copyright 2024 Luca Liguori.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License. *
- */
-
-/**
- * Import needed modules from @project-chip/matter-node.js
- */
-// Include this first to auto-register Crypto, Network and Time Node.js implementations
-import '@project-chip/matter-node.js';
-import { CryptoNode } from '@project-chip/matter-node.js/crypto';
-import { DeviceTypeId, FabricIndex, VendorId } from '@project-chip/matter-node.js/datatype';
-import { Format, Level, Logger, createFileLogger } from '@project-chip/matter-node.js/log';
-import { Storage, StorageContext, StorageManager } from '@project-chip/matter-node.js/storage';
-import { Environment, StorageService } from '@project-chip/matter.js/environment';
-import { ServerNode } from '@project-chip/matter.js/node';
-import { DeviceTypeDefinition, DeviceTypes, logEndpoint } from '@project-chip/matter-node.js/device';
-import { QrCode } from '@project-chip/matter-node.js/schema';
-import { FabricAction } from '@project-chip/matter-node.js/fabric';
-import { Endpoint, EndpointServer } from '@project-chip/matter.js/endpoint';
-import { EndpointType } from '@project-chip/matter.js/endpoint/type';
-
-import { AggregatorEndpoint } from '@project-chip/matter.js/endpoints/AggregatorEndpoint';
-import { BridgedNodeEndpoint } from '@project-chip/matter.js/endpoints/BridgedNodeEndpoint';
-
-// Behaviour servers
-import { IdentifyServer } from '@project-chip/matter.js/behavior/definitions/identify';
-import { OnOffServer } from '@project-chip/matter.js/behavior/definitions/on-off';
-import { GroupsServer } from '@project-chip/matter.js/behavior/definitions/groups';
-import { ScenesServer } from '@project-chip/matter.js/behavior/definitions/scenes';
-import { BridgedDeviceBasicInformationServer } from '@project-chip/matter.js/behavior/definitions/bridged-device-basic-information';
-import { TemperatureMeasurementServer } from '@project-chip/matter.js/behavior/definitions/temperature-measurement';
-import { RelativeHumidityMeasurementServer } from '@project-chip/matter.js/behavior/definitions/relative-humidity-measurement';
-import { SwitchServer } from '@project-chip/matter.js/behavior/definitions/switch';
-
-import { ActionContext } from '@project-chip/matter.js/behavior/context';
-
-// Device definitions
-import { ColorDimmerSwitchDevice } from '@project-chip/matter.js/devices/ColorDimmerSwitchDevice';
-import { OnOffLightDevice } from '@project-chip/matter.js/devices/OnOffLightDevice';
-import { GenericSwitchDevice } from '@project-chip/matter.js/devices/GenericSwitchDevice';
-
-import { MutableEndpoint } from '@project-chip/matter.js/endpoint/type';
-import { SupportedBehaviors } from '@project-chip/matter.js/endpoint/properties';
-
-import { AnsiLogger, BRIGHT, RESET, TimestampFormat, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, stringify, er, nf, rs, wr, RED, GREEN, zb, CYAN } from 'node-ansi-logger';
-import { NodeStorageManager, NodeStorage } from 'node-persist-manager';
-
-import EventEmitter from 'events';
-import path from 'path';
-import { promises as fs } from 'fs';
-import { MatterbridgeDeviceV8 } from './matterbridgeDeviceV8.js';
-import { Actions, BasicInformationCluster, Identify, RelativeHumidityMeasurement, SwitchCluster, TemperatureMeasurement } from '@project-chip/matter-node.js/cluster';
-import { bridgedNode, dimmableSwitch } from './matterbridgeDevice.js';
-import { RegisteredPlugin } from './matterbridge.js';
-import { MatterbridgePlatform, PlatformConfig } from './matterbridgePlatform.js';
-import { pathToFileURL } from 'url';
-import { shelly_config, somfytahoma_config, zigbee2mqtt_config } from './defaultConfigSchema.js';
-
-const plg = '\u001B[38;5;33m';
-const dev = '\u001B[38;5;79m';
-const typ = '\u001B[38;5;207m';
-
-const log = Logger.get('Matterbridge');
-
-/**
- * Represents the Matterbridge application.
- */
-export class MatterbridgeV8 extends EventEmitter {
- private environment = Environment.default;
-
- public matterbridgeVersion = '';
- public osVersion = '';
- public matterbridgeDirectory = '';
- public matterbridgePluginDirectory = '';
- public globalModulesDirectory = '';
- public matterbridgeLogFile = '';
- private registeredPlugins: RegisteredPlugin[] = [];
-
- // Node storage
- private nodeStorage: NodeStorageManager | undefined;
- private nodeContext: NodeStorage | undefined;
-
- // Matter storage
- public matterStorageService?: StorageService;
- public matterStorageManager?: StorageManager;
- public matterStorageContext?: StorageContext;
-
- public matterServerNode?: ServerNode;
- public matterAggregator?: Endpoint;
-
- public matterLogger?: Logger;
-
- private constructor() {
- super();
- }
-
- static async create() {
- const matterbridge = new MatterbridgeV8();
- await matterbridge.initialize();
- return matterbridge;
- }
-
- async initialize() {
- // Set up the temporary Matterbridge environment
- this.matterbridgeVersion = '2.0.0';
- this.osVersion = '10.0.22631';
- this.matterbridgeDirectory = 'C:\\Users\\lligu\\.matterbridge';
- this.matterbridgePluginDirectory = 'C:\\Users\\lligu\\Matterbridge';
- this.globalModulesDirectory = 'C:\\Users\\lligu\\AppData\\Roaming\\npm\\node_modules';
- this.matterbridgeLogFile = 'matterbridge.log';
-
- this.matterLogger = Logger.get('Matterbridge');
- await this.deleteMatterLogfile(this.matterbridgeLogFile);
- await this.setupMatterFileLogger(this.matterbridgeLogFile);
- this.matterLogger?.notice(`Starting Matterbridge v${this.matterbridgeVersion} on Node.js ${process.version} (${process.platform} ${process.arch})`);
-
- this.setupMatterVars(Level.DEBUG, Format.ANSI);
-
- await this.setupMatterStorage();
-
- await this.setupNodeStorage();
-
- // Get the plugins from node storage
- if (!this.nodeStorage) throw new Error('No node storage initialized');
- if (!this.nodeContext) throw new Error('No node storage context initialized');
- this.registeredPlugins = await this.nodeContext.get('plugins', []);
- for (const plugin of this.registeredPlugins) {
- plugin.nodeContext = await this.nodeStorage.createStorage(plugin.name);
- await plugin.nodeContext.set('name', plugin.name);
- await plugin.nodeContext.set('type', plugin.type);
- await plugin.nodeContext.set('path', plugin.path);
- await plugin.nodeContext.set('version', plugin.version);
- await plugin.nodeContext.set('description', plugin.description);
- await plugin.nodeContext.set('author', plugin.author);
- this.matterLogger?.notice(`Created node storage context for plugin ${plugin.name}`);
- }
- }
-
- private setupMatterVars(level: Level, format: Format.Type) {
- this.environment.vars.set('log.level', level);
- this.environment.vars.set('log.format', format);
- this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, 'matterstorage'));
- this.environment.vars.set('runtime.signals', false);
- this.environment.vars.set('runtime.exitcode', false);
- }
-
- private async setupMatterStorage() {
- this.matterStorageService = this.environment.get(StorageService);
- this.matterLogger?.notice(`Storage service created: ${this.matterStorageService.location}`);
-
- this.matterStorageManager = await this.matterStorageService.open('Matterbridge');
- this.matterLogger?.notice('Storage manager "Matterbridge" created');
-
- this.matterStorageContext = this.matterStorageManager.createContext('persist');
- this.matterLogger?.notice('Storage context "Matterbridge.persist" created');
- }
-
- private async setupNodeStorage() {
- this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, 'storage'), logging: false });
- this.matterLogger?.notice(`Created node storage manager: ${path.join(this.matterbridgeDirectory, 'storage')}`);
- this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
- this.matterLogger?.notice('Created node storage context "matterbridge"');
- }
-
- private async deleteMatterLogfile(filename: string) {
- try {
- await fs.unlink(path.join(this.matterbridgeDirectory, filename));
- } catch (err) {
- this.matterLogger?.error(`Error deleting old log file: ${err}`);
- }
- }
-
- private async setupMatterFileLogger(filename: string) {
- Logger.addLogger('filelogger', await createFileLogger(path.join(this.matterbridgeDirectory, filename)), {
- defaultLogLevel: Level.DEBUG,
- });
- this.matterLogger?.notice('File logger created: ' + path.join(this.matterbridgeDirectory, filename));
- }
-
- /**
- * Creates a server node storage context.
- *
- * @param pluginName - The name of the plugin.
- * @param deviceName - The name of the device.
- * @param deviceType - The deviceType of the device.
- * @param vendorId - The vendor ID.
- * @param vendorName - The vendor name.
- * @param productId - The product ID.
- * @param productName - The product name.
- * @param serialNumber - The serial number of the device (optional).
- * @param uniqueId - The unique ID of the device (optional).
- * @param softwareVersion - The software version of the device (optional).
- * @param softwareVersionString - The software version string of the device (optional).
- * @param hardwareVersion - The hardware version of the device (optional).
- * @param hardwareVersionString - The hardware version string of the device (optional).
- * @returns The storage context for the commissioning server.
- */
- async createServerNodeContext(pluginName: string, deviceName: string, deviceType: DeviceTypeId, vendorId: number, vendorName: string, productId: number, productName: string, serialNumber?: string): Promise> {
- if (!this.matterLogger) throw new Error('No logger initialized');
- const log = this.matterLogger;
- if (!this.matterStorageService) throw new Error('No storage service initialized');
-
- log.notice(`Creating server node storage context "${pluginName}.persist" for ${pluginName}...`);
- const storageManager = await this.matterStorageService.open(pluginName);
- const storageContext = storageManager.createContext('persist');
- const random = 'SN' + CryptoNode.getRandomData(8).toHex();
- await storageContext.set('storeId', pluginName);
- await storageContext.set('deviceName', deviceName);
- await storageContext.set('deviceType', deviceType);
- await storageContext.set('vendorId', vendorId);
- await storageContext.set('vendorName', vendorName.slice(0, 32));
- await storageContext.set('productId', productId);
- await storageContext.set('productName', productName.slice(0, 32));
- await storageContext.set('nodeLabel', productName.slice(0, 32));
- await storageContext.set('productLabel', productName.slice(0, 32));
- await storageContext.set('serialNumber', await storageContext.get('serialNumber', serialNumber ? serialNumber.slice(0, 32) : random));
- await storageContext.set('uniqueId', await storageContext.get('uniqueId', random));
- await storageContext.set('softwareVersion', this.matterbridgeVersion && this.matterbridgeVersion.includes('.') ? parseInt(this.matterbridgeVersion.split('.')[0], 10) : 1);
- await storageContext.set('softwareVersionString', this.matterbridgeVersion ?? '1.0.0');
- await storageContext.set('hardwareVersion', this.osVersion && this.osVersion.includes('.') ? parseInt(this.osVersion.split('.')[0], 10) : 1);
- await storageContext.set('hardwareVersionString', this.osVersion ?? '1.0.0');
-
- log.debug(`Created server node storage context "${pluginName}.persist" for ${pluginName}:`);
- log.debug(`- deviceName: ${await storageContext.get('deviceName')} deviceType: ${await storageContext.get('deviceType')}(0x${(await storageContext.get('deviceType'))?.toString(16).padStart(4, '0')})`);
- log.debug(`- serialNumber: ${await storageContext.get('serialNumber')} uniqueId: ${await storageContext.get('uniqueId')}`);
- log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
- log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
- return storageContext;
- }
-
- async createServerNode(storageContext: StorageContext, port = 5540, passcode = 20242025, discriminator = 3850) {
- if (!this.matterLogger) throw new Error('No logger initialized');
- const log = this.matterLogger;
-
- log.notice(`Creating server node for ${await storageContext.get('storeId')}`);
-
- /**
- * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
- */
- const serverNode = await ServerNode.create({
- // Required: Give the Node a unique ID which is used to store the state of this node
- id: await storageContext.get('storeId'),
-
- // Provide Network relevant configuration like the port
- // Optional when operating only one device on a host, Default port is 5540
- network: {
- port,
- },
-
- // Provide Commissioning relevant settings
- // Optional for development/testing purposes
- commissioning: {
- passcode,
- discriminator,
- },
-
- // Provide Node announcement settings
- // Optional: If Ommitted some development defaults are used
- productDescription: {
- name: await storageContext.get('deviceName'),
- deviceType: DeviceTypeId(await storageContext.get('deviceType')),
- },
-
- // Provide defaults for the BasicInformation cluster on the Root endpoint
- // Optional: If Omitted some development defaults are used
- basicInformation: {
- vendorId: VendorId(await storageContext.get('vendorId')),
- vendorName: await storageContext.get('vendorName'),
-
- productId: await storageContext.get('productId'),
- productName: await storageContext.get('productName'),
- productLabel: await storageContext.get('productName'),
- nodeLabel: await storageContext.get('productName'),
-
- serialNumber: await storageContext.get('serialNumber'),
- uniqueId: await storageContext.get('uniqueId'),
-
- softwareVersion: await storageContext.get('softwareVersion'),
- softwareVersionString: await storageContext.get('softwareVersionString'),
- hardwareVersion: await storageContext.get('hardwareVersion'),
- hardwareVersionString: await storageContext.get('hardwareVersionString'),
- },
- });
-
- /**
- * This event is triggered when the device is initially commissioned successfully.
- * This means: It is added to the first fabric.
- */
- serverNode.lifecycle.commissioned.on(() => log.notice('Server was initially commissioned successfully!'));
-
- /** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
- serverNode.lifecycle.decommissioned.on(() => log.notice('Server was fully decommissioned successfully!'));
-
- /** This event is triggered when the device went online. This means that it is discoverable in the network. */
- serverNode.lifecycle.online.on(() => log.notice('Server is online'));
-
- /** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
- serverNode.lifecycle.offline.on(() => log.notice('Server is offline'));
-
- /**
- * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
- * information is needed.
- */
- serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
- let action = '';
- switch (fabricAction) {
- case FabricAction.Added:
- action = 'added';
- break;
- case FabricAction.Removed:
- action = 'removed';
- break;
- case FabricAction.Updated:
- action = 'updated';
- break;
- }
- log.notice(`Commissioned Fabrics changed event (${action}) for ${fabricIndex} triggered`);
- log.notice(this.matterServerNode?.state.commissioning.fabrics[fabricIndex]);
- });
-
- /**
- * This event is triggered when an operative new session was opened by a Controller.
- * It is not triggered for the initial commissioning process, just afterwards for real connections.
- */
- serverNode.events.sessions.opened.on((session) => log.notice('Session opened', session));
-
- /**
- * This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
- */
- serverNode.events.sessions.closed.on((session) => log.notice('Session closed', session));
-
- /** This event is triggered when a subscription gets added or removed on an operative session. */
- serverNode.events.sessions.subscriptionsChanged.on((session) => {
- log.notice('Session subscriptions changed', session);
- log.notice('Status of all sessions', this.matterServerNode?.state.sessions.sessions);
- });
-
- return serverNode;
- }
-
- showServerNodeQR() {
- if (!this.matterServerNode || !this.matterLogger) return;
- const log = this.matterLogger;
- if (!this.matterServerNode.lifecycle.isCommissioned) {
- const { qrPairingCode, manualPairingCode } = this.matterServerNode.state.commissioning.pairingCodes;
- console.log(QrCode.get(qrPairingCode));
- log.notice(`QR Code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=${qrPairingCode}`);
- log.notice(`Manual pairing code: ${manualPairingCode}`);
- } else {
- log.notice('Device is already commissioned. Waiting for controllers to connect ...');
- log.notice('Fabrics:', this.matterServerNode.state.commissioning.fabrics);
- for (const key in this.matterServerNode.state.commissioning.fabrics) {
- const fabric = this.matterServerNode.state.commissioning.fabrics[FabricIndex(Number(key))];
- log.notice(`- index ${fabric.fabricIndex} id ${fabric.fabricId} nodeId ${fabric.nodeId} rootVendor ${fabric.rootVendorId} rootNodeId ${fabric.rootNodeId}`);
- }
- }
- }
-
- async startServerNode(storageContext: StorageContext) {
- if (!this.matterLogger) throw new Error('No logger initialized');
- const log = this.matterLogger;
-
- if (!this.matterServerNode) return;
- log.notice(`Starting ${await storageContext.get('storeId')} server node`);
- await this.matterServerNode.bringOnline();
- }
-
- async stopServerNode(storageContext: StorageContext) {
- if (!this.matterLogger) throw new Error('No logger initialized');
- const log = this.matterLogger;
-
- if (!this.matterServerNode) return;
- log.notice(`Stopping ${await storageContext.get('storeId')} server node`);
- await this.matterServerNode.close();
- this.matterServerNode = undefined;
- }
-
- async createAggregator(storageContext: StorageContext) {
- if (!this.matterLogger) throw new Error('No logger initialized');
- const log = this.matterLogger;
-
- log.notice(`Creating ${await storageContext.get('storeId')} aggregator `);
-
- const aggregator = new Endpoint(AggregatorEndpoint, { id: `${await storageContext.get('storeId')} aggregator` });
- return aggregator;
- }
-
- async startBridge() {
- if (!this.matterLogger) throw new Error('No logger initialized');
- const log = this.matterLogger;
-
- const storageContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', AggregatorEndpoint.deviceType, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Aggregator');
-
- this.matterServerNode = await this.createServerNode(storageContext);
-
- this.matterAggregator = await this.createAggregator(storageContext);
-
- log.notice(`Adding ${await storageContext.get('storeId')} aggregator to ${await storageContext.get('storeId')} server node`);
- await this.matterServerNode.add(this.matterAggregator);
-
- /*
- for (const plugin of this.registeredPlugins) {
- if (!plugin.enabled) {
- log.info(`Plugin ${plg}${plugin.name}${nf} not enabled`);
- continue;
- }
- plugin.error = false;
- plugin.loaded = false;
- plugin.started = false;
- plugin.configured = false;
- plugin.connected = undefined;
- plugin.qrPairingCode = undefined;
- plugin.manualPairingCode = undefined;
- this.loadPlugin(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
- }
- */
-
- log.notice(`Adding lightEndpoint1 to ${await storageContext.get('storeId')} aggregator`);
- const lightEndpoint1 = new Endpoint(OnOffLightDevice.with(BridgedDeviceBasicInformationServer), {
- id: 'OnOffLight',
- bridgedDeviceBasicInformation: {
- vendorId: VendorId(await storageContext.get('vendorId')),
- vendorName: await storageContext.get('vendorName'),
-
- productName: 'Light',
- productLabel: 'Light',
- nodeLabel: 'Light',
-
- serialNumber: '0x123456789',
- uniqueId: '0x123456789',
- reachable: true,
- },
- });
- await this.matterAggregator.add(lightEndpoint1);
-
- log.notice(`Adding switchEnpoint2 to ${await storageContext.get('storeId')} aggregator`);
- const switchEnpoint2 = new Endpoint(GenericSwitchDevice.with(BridgedDeviceBasicInformationServer, SwitchServer.with('MomentarySwitch', 'MomentarySwitchLongPress', 'MomentarySwitchMultiPress', 'MomentarySwitchRelease')), {
- id: 'GenericSwitch',
- bridgedDeviceBasicInformation: {
- vendorId: VendorId(await storageContext.get('vendorId')),
- vendorName: await storageContext.get('vendorName'),
-
- productName: 'GenericSwitch',
- productLabel: 'GenericSwitch',
- nodeLabel: 'GenericSwitch',
-
- serialNumber: '0x123456739',
- uniqueId: '0x123456739',
- reachable: true,
- },
- switch: {
- numberOfPositions: 2,
- currentPosition: 0,
- multiPressMax: 2,
- },
- });
- await this.matterAggregator.add(switchEnpoint2);
- switchEnpoint2.events.identify.startIdentifying.on(() => log.notice('GenericSwitch.identify logic, ideally blink a light every 0.5s ...'));
- switchEnpoint2.events.switch.currentPosition$Changed.on(() => log.notice('GenericSwitch.currentPosition changed ...'));
- // switchEnpoint2.act((agent) => agent.switch.events.initialPress.emit({ newPosition: 1 }, agent.context));
- // switchEnpoint2.events.switch.emit('initialPress', { newPosition: 1 }, switchEnpoint2.events.switch.context);
-
- log.notice(`Adding matterbridge device to ${await storageContext.get('storeId')} aggregator`);
- const matterbridgeDevice3 = new MatterbridgeDeviceV8(DeviceTypes.TEMPERATURE_SENSOR, { uniqueStorageKey: 'TemperatureSensor' });
- matterbridgeDevice3.addDeviceTypeWithClusterServer([DeviceTypes.HUMIDITY_SENSOR], [TemperatureMeasurement.Cluster.id, RelativeHumidityMeasurement.Cluster.id]);
- /*
- matterbridgeDevice3.behaviors.require(IdentifyServer, {
- identifyTime: 5,
- });
- matterbridgeDevice3.behaviors.require(TemperatureMeasurementServer, {
- measuredValue: 25.0,
- minMeasuredValue: null,
- maxMeasuredValue: null,
- });
- */
- matterbridgeDevice3.behaviors.require(BridgedDeviceBasicInformationServer, {
- vendorId: VendorId(await storageContext.get('vendorId')),
- vendorName: await storageContext.get('vendorName'),
-
- productName: 'TemperatureSensor',
- productLabel: 'TemperatureSensor',
- nodeLabel: 'TemperatureSensor',
-
- serialNumber: '0x145456739',
- uniqueId: '0x124556739',
- reachable: true,
- });
- await this.matterAggregator.add(matterbridgeDevice3);
-
- await this.startServerNode(storageContext);
-
- // logEndpoint(EndpointServer.forEndpoint(matterbridgeDevice3));
-
- await lightEndpoint1.set({
- onOff: {
- onOff: true,
- },
- });
- await matterbridgeDevice3.set({
- temperatureMeasurement: {
- measuredValue: 20 * 100,
- },
- relativeHumidityMeasurement: {
- measuredValue: 50 * 100,
- },
- });
- await switchEnpoint2.set({
- switch: {
- currentPosition: 1,
- },
- });
- switchEnpoint2.act((agent) => agent.switch.events.initialPress.emit({ newPosition: 1 }, agent.context));
-
- // logEndpoint(EndpointServer.forEndpoint(matterbridgeDevice3));
-
- /*
- logEndpoint(EndpointServer.forEndpoint(this.matterServerNode));
- logEndpoint(EndpointServer.forEndpoint(matterbridgeDevice3));
- console.log('matterbridgeDevice3\n', matterbridgeDevice3);
- console.log('matterbridgeDevice3.events\n', matterbridgeDevice3.events);
- console.log('matterbridgeDevice3.events.identify\n', matterbridgeDevice3.eventsOf(IdentifyServer));
- console.log('matterbridgeDevice3.state\n', matterbridgeDevice3.state);
- console.log('matterbridgeDevice3.state.temperatureMeasurement\n', matterbridgeDevice3.stateOf(TemperatureMeasurementServer));
- // matterbridgeDevice3.eventsOf(IdentifyServer);
- // matterbridgeDevice3.events.identify.startIdentifying.on(() => log.notice('Run identify logic, ideally blink a light every 0.5s ...'));
- */
-
- this.showServerNodeQR();
- }
-
- async startChildbridge() {
- //
- }
-
- async startController() {
- //
- }
-
- /**
- * Adds a bridged device to the Matterbridge.
- * @param pluginName - The name of the plugin.
- * @param device - The bridged device to add.
- * @returns {Promise} - A promise that resolves when the storage process is started.
- */
- async addBridgedDevice(pluginName: string, device: MatterbridgeDeviceV8): Promise {
- log.info(`Adding bridged device ${dev}${device.deviceName}${nf} for plugin ${plg}${pluginName}${nf}`);
- }
-
- /**
- * Loads a plugin and returns the corresponding MatterbridgePlatform instance.
- * @param plugin - The plugin to load.
- * @param start - Optional flag indicating whether to start the plugin after loading. Default is false.
- * @param message - Optional message to pass to the plugin when starting.
- * @returns A Promise that resolves to the loaded MatterbridgePlatform instance.
- * @throws An error if the plugin is not enabled, already loaded, or fails to load.
- */
- private async loadPlugin(plugin: RegisteredPlugin, start = false, message = ''): Promise {
- if (!plugin.enabled) {
- return Promise.reject(new Error(`Plugin ${plg}${plugin.name}${er} not enabled`));
- }
- if (plugin.platform) {
- return Promise.resolve(plugin.platform);
- }
- log.info(`Loading plugin ${plg}${plugin.name}${nf} type ${typ}${plugin.type}${nf}`);
- try {
- // Load the package.json of the plugin
- const packageJson = JSON.parse(await fs.readFile(plugin.path, 'utf8'));
- // Resolve the main module path relative to package.json
- const pluginEntry = path.resolve(path.dirname(plugin.path), packageJson.main);
- // Dynamically import the plugin
- const pluginUrl = pathToFileURL(pluginEntry);
- log.debug(`Importing plugin ${plg}${plugin.name}${db} from ${pluginUrl.href}`);
- const pluginInstance = await import(pluginUrl.href);
- log.debug(`Imported plugin ${plg}${plugin.name}${db} from ${pluginUrl.href}`);
-
- // Call the default export function of the plugin, passing this MatterBridge instance, the log and the config
- if (pluginInstance.default) {
- const config: PlatformConfig = await this.loadPluginConfig(plugin);
- const log = new AnsiLogger({ logName: plugin.description, logTimestampFormat: TimestampFormat.TIME_MILLIS, logDebug: true });
- const platform = pluginInstance.default(this, log, config) as MatterbridgePlatform;
- platform.name = packageJson.name;
- platform.config = config;
- platform.version = packageJson.version;
- plugin.name = packageJson.name;
- plugin.description = packageJson.description;
- plugin.version = packageJson.version;
- plugin.author = packageJson.author;
- plugin.type = platform.type;
- plugin.platform = platform;
- plugin.loaded = true;
- plugin.registeredDevices = 0;
- plugin.addedDevices = 0;
- // Save the updated plugin data in the node storage
- // await this.nodeContext?.set('plugins', await this.getBaseRegisteredPlugins());
-
- // await this.getPluginLatestVersion(plugin);
-
- log.info(`Loaded plugin ${plg}${plugin.name}${nf} type ${typ}${platform.type} ${db}(entrypoint ${UNDERLINE}${pluginEntry}${UNDERLINEOFF})`);
- if (start) this.startPlugin(plugin, message); // No await do it asyncronously
- return Promise.resolve(platform);
- } else {
- plugin.error = true;
- return Promise.reject(new Error(`Plugin ${plg}${plugin.name}${er} does not provide a default export`));
- }
- } catch (err) {
- plugin.error = true;
- return Promise.reject(new Error(`Failed to load plugin ${plg}${plugin.name}${er}: ${err}`));
- }
- }
-
- /**
- * Starts a plugin.
- *
- * @param {RegisteredPlugin} plugin - The plugin to start.
- * @param {string} [message] - Optional message to pass to the plugin's onStart method.
- * @param {boolean} [configure=false] - Indicates whether to configure the plugin after starting.
- * @returns {Promise} A promise that resolves when the plugin is started successfully, or rejects with an error if starting the plugin fails.
- */
- private async startPlugin(plugin: RegisteredPlugin, message?: string, configure = false): Promise {
- if (!plugin.loaded || !plugin.platform) {
- return Promise.reject(new Error(`Plugin ${plg}${plugin.name}${er} not loaded or no platform`));
- }
- if (plugin.started) {
- log.debug(`Plugin ${plg}${plugin.name}${db} already started`);
- return Promise.resolve();
- }
- log.info(`Starting plugin ${plg}${plugin.name}${db} type ${typ}${plugin.type}${db}`);
- try {
- plugin.platform
- .onStart(message)
- .then(() => {
- plugin.started = true;
- log.info(`Started plugin ${plg}${plugin.name}${db} type ${typ}${plugin.type}${db}`);
- if (configure) this.configurePlugin(plugin); // No await do it asyncronously
- return Promise.resolve();
- })
- .catch((err) => {
- plugin.error = true;
- return Promise.reject(new Error(`Failed to start plugin ${plg}${plugin.name}${er}: ${err}`));
- });
- } catch (err) {
- plugin.error = true;
- return Promise.reject(new Error(`Failed to start plugin ${plg}${plugin.name}${er}: ${err}`));
- }
- }
-
- /**
- * Configures a plugin.
- *
- * @param {RegisteredPlugin} plugin - The plugin to configure.
- * @returns {Promise} A promise that resolves when the plugin is configured successfully, or rejects with an error if configuration fails.
- */
- private async configurePlugin(plugin: RegisteredPlugin): Promise {
- if (!plugin.loaded || !plugin.started || !plugin.platform) {
- return Promise.reject(new Error(`Plugin ${plg}${plugin.name}${er} not loaded (${plugin.loaded}) or not started (${plugin.started}) or not platform (${plugin.platform?.name})`));
- }
- if (plugin.configured) {
- log.info(`Plugin ${plg}${plugin.name}${nf} already configured`);
- return Promise.resolve();
- }
- log.info(`Configuring plugin ${plg}${plugin.name}${db} type ${typ}${plugin.type}${db}`);
- try {
- plugin.platform
- .onConfigure()
- .then(() => {
- plugin.configured = true;
- log.info(`Configured plugin ${plg}${plugin.name}${db} type ${typ}${plugin.type}${db}`);
- // this.savePluginConfig(plugin);
- return Promise.resolve();
- })
- .catch((err) => {
- plugin.error = true;
- return Promise.reject(new Error(`Failed to configure plugin ${plg}${plugin.name}${er}: ${err}`));
- });
- } catch (err) {
- plugin.error = true;
- return Promise.reject(new Error(`Failed to configure plugin ${plg}${plugin.name}${er}: ${err}`));
- }
- }
-
- /**
- * Loads the configuration for a plugin.
- * If the configuration file exists, it reads the file and returns the parsed JSON data.
- * If the configuration file does not exist, it creates a new file with default configuration and returns it.
- * If any error occurs during file access or creation, it logs an error and rejects the promise with the error.
- *
- * @param plugin - The plugin for which to load the configuration.
- * @returns A promise that resolves to the loaded or created configuration.
- */
- private async loadPluginConfig(plugin: RegisteredPlugin): Promise {
- const configFile = path.join(this.matterbridgeDirectory, `${plugin.name}.config.json`);
- try {
- await fs.access(configFile);
- const data = await fs.readFile(configFile, 'utf8');
- const config = JSON.parse(data) as PlatformConfig;
- // this.log.debug(`Config file found: ${configFile}.\nConfig:${rs}\n`, config);
- log.debug(`Config file found: ${configFile}.`);
- /* The first time a plugin is added to the system, the config file is created with the plugin name and type "".*/
- config.name = plugin.name;
- config.type = plugin.type;
- return config;
- } catch (err) {
- if (err instanceof Error) {
- const nodeErr = err as NodeJS.ErrnoException;
- if (nodeErr.code === 'ENOENT') {
- let config: PlatformConfig;
- if (plugin.name === 'matterbridge-zigbee2mqtt') config = zigbee2mqtt_config;
- else if (plugin.name === 'matterbridge-somfy-tahoma') config = somfytahoma_config;
- else if (plugin.name === 'matterbridge-shelly') config = shelly_config;
- else config = { name: plugin.name, type: plugin.type, unregisterOnShutdown: false };
- try {
- await this.writeFile(configFile, JSON.stringify(config, null, 2));
- log.debug(`Created config file: ${configFile}.`);
- // this.log.debug(`Created config file: ${configFile}.\nConfig:${rs}\n`, config);
- return config;
- } catch (err) {
- log.error(`Error creating config file ${configFile}: ${err}`);
- return config;
- }
- } else {
- log.error(`Error accessing config file ${configFile}: ${err}`);
- return {};
- }
- }
- log.error(`Error loading config file ${configFile}: ${err}`);
- return {};
- }
- }
-
- /**
- * Writes data to a file.
- *
- * @param {string} filePath - The path of the file to write to.
- * @param {string} data - The data to write to the file.
- * @returns {Promise} - A promise that resolves when the data is successfully written to the file.
- */
- private async writeFile(filePath: string, data: string): Promise {
- // Write the data to a file
- await fs
- .writeFile(`${filePath}`, data, 'utf8')
- .then(() => {
- log.debug(`Successfully wrote to ${filePath}`);
- })
- .catch((error) => {
- log.error(`Error writing to ${filePath}:`, error);
- });
- }
-}
-
-// node dist/matterbridgeV8.js MatterbridgeV8
-if (process.argv.includes('MatterbridgeV8')) {
- const matterbridge = await MatterbridgeV8.create();
-
- if (process.argv.includes('-bridge')) await matterbridge.startBridge();
- if (process.argv.includes('-childbridge')) await matterbridge.startChildbridge();
- if (process.argv.includes('-controller')) await matterbridge.startController();
-
- process.on('SIGINT', async function () {
- console.log('Caught interrupt signal');
- if (!matterbridge || !matterbridge.matterServerNode || !matterbridge.matterStorageContext) return;
- await matterbridge.stopServerNode(matterbridge.matterStorageContext);
- process.exit();
- });
-}