From a38041cea90380b28afa98dd6b6dd319410d2636 Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Thu, 23 Jan 2025 19:33:23 +0100 Subject: [PATCH] Add SmokeCO2Alarm Controller device type (#333) --- README.md | 12 +- package-lock.json | 118 +++++++++--------- package.json | 8 +- src-admin/package-lock.json | 4 +- src/lib/devices/FireAlarm.ts | 7 ++ src/matter/ControllerNode.ts | 8 +- .../ColorTemperatureLightToIoBroker.ts | 8 +- src/matter/to-iobroker/DimmableToIoBroker.ts | 4 +- .../ExtendedColorLightToIoBroker.ts | 16 +-- .../to-iobroker/SmokeCoAlarmToIoBroker.ts | 59 +++++++++ src/matter/to-iobroker/SpeakerToIoBroker.ts | 4 +- src/matter/to-iobroker/ioBrokerFactory.ts | 4 + 12 files changed, 166 insertions(+), 86 deletions(-) create mode 100644 src/matter/to-iobroker/SmokeCoAlarmToIoBroker.ts diff --git a/README.md b/README.md index 924e9c1b..8d065f54 100644 --- a/README.md +++ b/README.md @@ -38,9 +38,9 @@ With the ioBroker Matter Adapter it is possible to map the following use cases: * (2+) fireAlarm * (-2) mediaPlayer * warning - how? - * gate - aka blinds? - * windowTilt - how? - * levelSlider - how? + * gate - aka blinds because matter has no other device type? + * windowTilt - as discussed as composed device with two contact sensors ... one for open close and one for tilt + * levelSlider - ideally as non-lighting dimmed socket? * Matter device types * (7) Fan -> airCondition? * (4+) Air Quality Sensor -> ??? @@ -50,7 +50,6 @@ With the ioBroker Matter Adapter it is possible to map the following use cases: * (3+) Robot Vacuum cleaner -> vacuumCleaner * (3) Flow Sensor -> ??? DEF * (3) Room Air Conditioner -> airCondition - * (2+) Smoke & CO Alarm -> fireAlarm? warning? * (2+) Dishwasher-> ??? * (2) Basic Video Player -> mediaPlayer * (2) Laundry Washer -> ??? @@ -77,6 +76,11 @@ With the ioBroker Matter Adapter it is possible to map the following use cases: --> ## Changelog +### __WORK IN PROGRESS__ +* (@Apollon77) Added SmokeCO2Alarm -> FireAlarm to Controller device types +* (@Apollon77) Detects BLE only QR codes and respond with error message +* (@Apollon77) For Dimming and Color changes direct the device to execute the changes also when device is off + ### 0.4.1 (2025-01-22) * (@bluefox) Optimized UI * (@Apollon77) Improved handling for Power Source cluster on root endpoint diff --git a/package-lock.json b/package-lock.json index 4cb8d70f..6742af3b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,9 +13,9 @@ "@iobroker/dm-utils": "^1.0.6", "@iobroker/i18n": "^0.3.1", "@iobroker/type-detector": "^4.1.1", - "@matter/main": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/nodejs": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@project-chip/matter.js": "0.12.0-alpha.0-20250121-0ab1b29a1", + "@matter/main": "0.12.0", + "@matter/nodejs": "0.12.0", + "@project-chip/matter.js": "0.12.0", "axios": "^1.7.9", "jsonwebtoken": "^9.0.2" }, @@ -40,7 +40,7 @@ "node": ">=18" }, "optionalDependencies": { - "@matter/nodejs-ble": "0.12.0-alpha.0-20250121-0ab1b29a1" + "@matter/nodejs-ble": "0.12.0" } }, "node_modules/@alcalzone/pak": { @@ -874,64 +874,64 @@ } }, "node_modules/@matter/general": { - "version": "0.12.0-alpha.0-20250121-0ab1b29a1", - "resolved": "https://registry.npmjs.org/@matter/general/-/general-0.12.0-alpha.0-20250121-0ab1b29a1.tgz", - "integrity": "sha512-NflxKytbLdnPFlN+mUh2U9/bAit+WtraKBcaUoowlDHRtTlxEfPXXwIanj8dCxNd7XtFJ2vaOPeFGLd0Ep37KQ==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@matter/general/-/general-0.12.0.tgz", + "integrity": "sha512-D6XkH/17qbvbNclw8IG82QzBGXGkDTBCaHe3zIDsMBraVUcQzKbTFrSQIP4tzqU6R2NC7nkmMsqFBV7HRVwwyQ==", "license": "Apache-2.0", "dependencies": { "@noble/curves": "^1.8.1" } }, "node_modules/@matter/main": { - "version": "0.12.0-alpha.0-20250121-0ab1b29a1", - "resolved": "https://registry.npmjs.org/@matter/main/-/main-0.12.0-alpha.0-20250121-0ab1b29a1.tgz", - "integrity": "sha512-frK2xqrpzHIO5fzbIyj5QQm5mpNuyta01kCK0gdID7xJNWLEIctq9tvUJZnGVbXRn7SsSOsDo2n6BVIu0wZnSg==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@matter/main/-/main-0.12.0.tgz", + "integrity": "sha512-cqliR5nnFJCEXKUKcwI9rxPZQNcrJ8iFpd6bOOEQ2v85+dYFZGDOxOWHMo70EoQOqsu7lGozGWRq4m642iXIRw==", "license": "Apache-2.0", "dependencies": { - "@matter/general": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/model": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/node": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/protocol": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/types": "0.12.0-alpha.0-20250121-0ab1b29a1", + "@matter/general": "0.12.0", + "@matter/model": "0.12.0", + "@matter/node": "0.12.0", + "@matter/protocol": "0.12.0", + "@matter/types": "0.12.0", "@noble/curves": "^1.8.1" }, "optionalDependencies": { - "@matter/nodejs": "0.12.0-alpha.0-20250121-0ab1b29a1" + "@matter/nodejs": "0.12.0" } }, "node_modules/@matter/model": { - "version": "0.12.0-alpha.0-20250121-0ab1b29a1", - "resolved": "https://registry.npmjs.org/@matter/model/-/model-0.12.0-alpha.0-20250121-0ab1b29a1.tgz", - "integrity": "sha512-/+u3lfQqaezt0hgeu2bMqttvYfTca1rmWUuKxjwqNmMkSNu95kh5WLlWHJUNY5jz3ylgGvF33Kfh7rSyGySCtg==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@matter/model/-/model-0.12.0.tgz", + "integrity": "sha512-uJhdwWpSFV0wl84Q9nIj1Je8y2Y223XEqomVRNlzDEK450MxaQ/MAK1nEvi3BBTvoiNvAtSij+pIrzu5fYxnlg==", "license": "Apache-2.0", "dependencies": { - "@matter/general": "0.12.0-alpha.0-20250121-0ab1b29a1", + "@matter/general": "0.12.0", "@noble/curves": "^1.8.1" } }, "node_modules/@matter/node": { - "version": "0.12.0-alpha.0-20250121-0ab1b29a1", - "resolved": "https://registry.npmjs.org/@matter/node/-/node-0.12.0-alpha.0-20250121-0ab1b29a1.tgz", - "integrity": "sha512-TNDvRQKyX+mxkVneUq3IMJm8r5GKJvEeVVqCEZLvMnbkFAsh97zA2jWtUGdvDG+/efuF7/w2LCGxc3nBE4db/A==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@matter/node/-/node-0.12.0.tgz", + "integrity": "sha512-J/wQaXSuN3/fZnyTpOE8brmv5mZE2co2yajTg9DmZDgi0EXWXCF97+2vemlPh6BXAszDas7FdN/1kXu2MEA9/Q==", "license": "Apache-2.0", "dependencies": { - "@matter/general": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/model": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/protocol": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/types": "0.12.0-alpha.0-20250121-0ab1b29a1", + "@matter/general": "0.12.0", + "@matter/model": "0.12.0", + "@matter/protocol": "0.12.0", + "@matter/types": "0.12.0", "@noble/curves": "^1.8.1" } }, "node_modules/@matter/nodejs": { - "version": "0.12.0-alpha.0-20250121-0ab1b29a1", - "resolved": "https://registry.npmjs.org/@matter/nodejs/-/nodejs-0.12.0-alpha.0-20250121-0ab1b29a1.tgz", - "integrity": "sha512-6hjM22O2xg8jDhIXA2GhoANs7R2RhblGr4ITB4wbf8IPw/JisISydOs6QSxENCfP9zR7fpQ1CfTcVj4c4SMKrQ==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@matter/nodejs/-/nodejs-0.12.0.tgz", + "integrity": "sha512-VZtZcW2UzXiAnYAwJ+9XPDqCfO3amlzgCPBDTXpUKti4HrO0v6U5LmydNRGoGkNUB9QABxLpiAmEId+URZ2r9Q==", "license": "Apache-2.0", "dependencies": { - "@matter/general": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/node": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/protocol": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/types": "0.12.0-alpha.0-20250121-0ab1b29a1", + "@matter/general": "0.12.0", + "@matter/node": "0.12.0", + "@matter/protocol": "0.12.0", + "@matter/types": "0.12.0", "node-localstorage": "^3.0.5" }, "engines": { @@ -939,15 +939,15 @@ } }, "node_modules/@matter/nodejs-ble": { - "version": "0.12.0-alpha.0-20250121-0ab1b29a1", - "resolved": "https://registry.npmjs.org/@matter/nodejs-ble/-/nodejs-ble-0.12.0-alpha.0-20250121-0ab1b29a1.tgz", - "integrity": "sha512-1Ppz2pJwyLyc6zPjjpN4MUSDnhnAizu9kk6JXsnqwo48+lxcy2siBZd7JxFO3OsFgiayqvqAhMxZ7pQ7ffkFGQ==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@matter/nodejs-ble/-/nodejs-ble-0.12.0.tgz", + "integrity": "sha512-Tz7ugttTnKAiSyj0ZtE3cr9n0fm1fcII3/8/YBllS4xEcMZQlsLEc/3qncIrN6ca16U71IcJ1r9gMLkHwf2wlA==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@matter/general": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/protocol": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/types": "0.12.0-alpha.0-20250121-0ab1b29a1" + "@matter/general": "0.12.0", + "@matter/protocol": "0.12.0", + "@matter/types": "0.12.0" }, "engines": { "node": ">=18.0.0" @@ -958,25 +958,25 @@ } }, "node_modules/@matter/protocol": { - "version": "0.12.0-alpha.0-20250121-0ab1b29a1", - "resolved": "https://registry.npmjs.org/@matter/protocol/-/protocol-0.12.0-alpha.0-20250121-0ab1b29a1.tgz", - "integrity": "sha512-y2nX5obGB5xpFDu+JRUeTu4GJnjq3fQPNjWTUxpW1P6UOa4kd0vOjkw7WIHl+KIitulVcU5PNqzrUGS6z9G0Vw==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@matter/protocol/-/protocol-0.12.0.tgz", + "integrity": "sha512-wtDZR/APxMWdf7hErRshWlgnjisnID66GQ9Xxlkq6U1BciXf8qIb8UyWxKN6LWWUhOLPJe6rcn8SnXt6t/q1mA==", "license": "Apache-2.0", "dependencies": { - "@matter/general": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/model": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/types": "0.12.0-alpha.0-20250121-0ab1b29a1", + "@matter/general": "0.12.0", + "@matter/model": "0.12.0", + "@matter/types": "0.12.0", "@noble/curves": "^1.8.1" } }, "node_modules/@matter/types": { - "version": "0.12.0-alpha.0-20250121-0ab1b29a1", - "resolved": "https://registry.npmjs.org/@matter/types/-/types-0.12.0-alpha.0-20250121-0ab1b29a1.tgz", - "integrity": "sha512-Cqnrfd0ZXg43AJIWR6a+6HvQsLnSFi0JLJLezLNqelCa+6woYd4m61s/bscZK0xdp3FxcTFCE8jaCJ/tMlndAw==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@matter/types/-/types-0.12.0.tgz", + "integrity": "sha512-tS5amwLRymfnqMuVwJ+xYkXGthoBpYb6Dg6GE1IKvZeccl3xGQIYEvIw0rB806h/WkK97T6mB39hHNHliMLAIg==", "license": "Apache-2.0", "dependencies": { - "@matter/general": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/model": "0.12.0-alpha.0-20250121-0ab1b29a1", + "@matter/general": "0.12.0", + "@matter/model": "0.12.0", "@noble/curves": "^1.8.1" } }, @@ -1139,16 +1139,16 @@ } }, "node_modules/@project-chip/matter.js": { - "version": "0.12.0-alpha.0-20250121-0ab1b29a1", - "resolved": "https://registry.npmjs.org/@project-chip/matter.js/-/matter.js-0.12.0-alpha.0-20250121-0ab1b29a1.tgz", - "integrity": "sha512-Y5fg5wikxGzjCCm6BjxFZgwEu9B/NXi5qOvV3virHJE9tvT+tDwtPYyTLKeLhciiMO2avUzqC7gJkc2SzqfFyQ==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@project-chip/matter.js/-/matter.js-0.12.0.tgz", + "integrity": "sha512-7WO7/h4eIOApXYd6ZGFkNp5GlDScQPpqDJALJCnUbB2Z6+d01PpJ9d6Q2Z7OC/vooCXod/nebyj2YCQtGK7VOQ==", "license": "Apache-2.0", "dependencies": { - "@matter/general": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/model": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/node": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/protocol": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/types": "0.12.0-alpha.0-20250121-0ab1b29a1", + "@matter/general": "0.12.0", + "@matter/model": "0.12.0", + "@matter/node": "0.12.0", + "@matter/protocol": "0.12.0", + "@matter/types": "0.12.0", "@noble/curves": "^1.8.1" } }, diff --git a/package.json b/package.json index 8c40535f..f56a151a 100644 --- a/package.json +++ b/package.json @@ -23,16 +23,16 @@ "url": "https://github.com/ioBroker/ioBroker.matter" }, "optionalDependencies": { - "@matter/nodejs-ble": "0.12.0-alpha.0-20250121-0ab1b29a1" + "@matter/nodejs-ble": "0.12.0" }, "dependencies": { "@iobroker/adapter-core": "^3.2.3", "@iobroker/i18n": "^0.3.1", "@iobroker/dm-utils": "^1.0.6", "@iobroker/type-detector": "^4.1.1", - "@matter/main": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@matter/nodejs": "0.12.0-alpha.0-20250121-0ab1b29a1", - "@project-chip/matter.js": "0.12.0-alpha.0-20250121-0ab1b29a1", + "@matter/main": "0.12.0", + "@matter/nodejs": "0.12.0", + "@project-chip/matter.js": "0.12.0", "axios": "^1.7.9", "jsonwebtoken": "^9.0.2" }, diff --git a/src-admin/package-lock.json b/src-admin/package-lock.json index 58e574c9..674dc2e6 100644 --- a/src-admin/package-lock.json +++ b/src-admin/package-lock.json @@ -1,12 +1,12 @@ { "name": "iobroker.matter", - "version": "0.4.0", + "version": "0.4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "iobroker.matter", - "version": "0.4.0", + "version": "0.4.1", "dependencies": { "@foxriver76/iob-component-lib": "^0.2.0", "@iobroker/adapter-react-v5": "^7.4.15", diff --git a/src/lib/devices/FireAlarm.ts b/src/lib/devices/FireAlarm.ts index c7566feb..6dde44a9 100644 --- a/src/lib/devices/FireAlarm.ts +++ b/src/lib/devices/FireAlarm.ts @@ -26,4 +26,11 @@ export class FireAlarm extends GenericDevice { } return this.#getValueState.value; } + + updateValue(value: boolean): Promise { + if (!this.#getValueState) { + throw new Error('Value state not found'); + } + return this.#getValueState.updateValue(value); + } } diff --git a/src/matter/ControllerNode.ts b/src/matter/ControllerNode.ts index 5ac29a08..e8505426 100644 --- a/src/matter/ControllerNode.ts +++ b/src/matter/ControllerNode.ts @@ -7,7 +7,7 @@ import { type DiscoveryData, CommissioningError, } from '@matter/main/protocol'; -import { ManualPairingCodeCodec, QrPairingCodeCodec } from '@matter/main/types'; +import { ManualPairingCodeCodec, QrPairingCodeCodec, DiscoveryCapabilitiesSchema } from '@matter/main/types'; import { NodeJsBle } from '@matter/nodejs-ble'; import { CommissioningController, type NodeCommissioningOptions } from '@project-chip/matter.js'; import { @@ -388,6 +388,12 @@ class Controller implements GeneralNode { } else if ('qrCode' in data && data.qrCode.length > 0) { const pairingCodeCodec = QrPairingCodeCodec.decode(data.qrCode); // TODO handle the case where multiple devices are included + const capabilities = DiscoveryCapabilitiesSchema.decode(pairingCodeCodec[0].discoveryCapabilities); + if (!capabilities.onIpNetwork && capabilities.ble && !this.#useBle) { + throw new Error( + 'This device can only be paired using BLE but BLE is disabled. Please use the ioBroker Visu App to pair this device or enable the Host BLE.', + ); + } longDiscriminator = pairingCodeCodec[0].discriminator; shortDiscriminator = undefined; passcode = pairingCodeCodec[0].passcode; diff --git a/src/matter/to-iobroker/ColorTemperatureLightToIoBroker.ts b/src/matter/to-iobroker/ColorTemperatureLightToIoBroker.ts index 29fefe93..3cfba886 100644 --- a/src/matter/to-iobroker/ColorTemperatureLightToIoBroker.ts +++ b/src/matter/to-iobroker/ColorTemperatureLightToIoBroker.ts @@ -105,8 +105,8 @@ export class ColorTemperatureLightToIoBroker extends GenericElectricityDataDevic await this.appEndpoint.getClusterClient(LevelControl.Complete)?.moveToLevel({ level, transitionTime: transitionTime !== null ? Math.round(transitionTime / 100) : null, - optionsMask: {}, - optionsOverride: {}, + optionsMask: { executeIfOff: true }, + optionsOverride: { executeIfOff: true }, }); }, convertValue: value => Math.round((value / 254) * 100), @@ -127,8 +127,8 @@ export class ColorTemperatureLightToIoBroker extends GenericElectricityDataDevic await this.appEndpoint.getClusterClient(ColorControl.Complete)?.moveToColorTemperature({ colorTemperatureMireds, transitionTime, - optionsMask: {}, - optionsOverride: {}, + optionsMask: { executeIfOff: true }, + optionsOverride: { executeIfOff: true }, }); }, convertValue: value => Math.round(miredsToKelvin(value)), diff --git a/src/matter/to-iobroker/DimmableToIoBroker.ts b/src/matter/to-iobroker/DimmableToIoBroker.ts index 88961ca9..c7bc4e13 100644 --- a/src/matter/to-iobroker/DimmableToIoBroker.ts +++ b/src/matter/to-iobroker/DimmableToIoBroker.ts @@ -92,8 +92,8 @@ export class DimmableToIoBroker extends GenericElectricityDataDeviceToIoBroker { await this.appEndpoint.getClusterClient(LevelControl.Complete)?.moveToLevel({ level, transitionTime: transitionTime !== null ? Math.round(transitionTime / 100) : null, - optionsMask: {}, - optionsOverride: {}, + optionsMask: { executeIfOff: true }, + optionsOverride: { executeIfOff: true }, }); }, convertValue: value => Math.round((value / 254) * 100), diff --git a/src/matter/to-iobroker/ExtendedColorLightToIoBroker.ts b/src/matter/to-iobroker/ExtendedColorLightToIoBroker.ts index 149e3754..017364e5 100644 --- a/src/matter/to-iobroker/ExtendedColorLightToIoBroker.ts +++ b/src/matter/to-iobroker/ExtendedColorLightToIoBroker.ts @@ -141,8 +141,8 @@ export class ExtendedColorLightToIoBroker extends GenericElectricityDataDeviceTo hue: matterHue, saturation: matterSaturation, transitionTime, - optionsMask: {}, - optionsOverride: {}, + optionsMask: { executeIfOff: true }, + optionsOverride: { executeIfOff: true }, }); } @@ -163,8 +163,8 @@ export class ExtendedColorLightToIoBroker extends GenericElectricityDataDeviceTo colorX: matterX, colorY: matterY, transitionTime, - optionsMask: {}, - optionsOverride: {}, + optionsMask: { executeIfOff: true }, + optionsOverride: { executeIfOff: true }, }); }, }); @@ -231,8 +231,8 @@ export class ExtendedColorLightToIoBroker extends GenericElectricityDataDeviceTo await this.appEndpoint.getClusterClient(LevelControl.Complete)?.moveToLevel({ level, transitionTime: transitionTime !== null ? Math.round(transitionTime / 100) : null, - optionsMask: {}, - optionsOverride: {}, + optionsMask: { executeIfOff: true }, + optionsOverride: { executeIfOff: true }, }); }, convertValue: value => Math.round((value / 254) * 100), @@ -253,8 +253,8 @@ export class ExtendedColorLightToIoBroker extends GenericElectricityDataDeviceTo await this.appEndpoint.getClusterClient(ColorControl.Complete)?.moveToColorTemperature({ colorTemperatureMireds, transitionTime, - optionsMask: {}, - optionsOverride: {}, + optionsMask: { executeIfOff: true }, + optionsOverride: { executeIfOff: true }, }); }, convertValue: value => Math.round(miredsToKelvin(value)), diff --git a/src/matter/to-iobroker/SmokeCoAlarmToIoBroker.ts b/src/matter/to-iobroker/SmokeCoAlarmToIoBroker.ts new file mode 100644 index 00000000..70fdb7a6 --- /dev/null +++ b/src/matter/to-iobroker/SmokeCoAlarmToIoBroker.ts @@ -0,0 +1,59 @@ +import ChannelDetector from '@iobroker/type-detector'; +import { SmokeCoAlarm } from '@matter/main/clusters'; +import type { Endpoint, PairedNode } from '@project-chip/matter.js/device'; +import { PropertyType } from '../../lib/devices/DeviceStateObject'; +import type { DetectedDevice, DeviceOptions } from '../../lib/devices/GenericDevice'; +import { GenericDeviceToIoBroker } from './GenericDeviceToIoBroker'; +import { FireAlarm } from '../../lib'; + +export class SmokeCoAlarmToIoBroker extends GenericDeviceToIoBroker { + readonly #ioBrokerDevice: FireAlarm; + + constructor( + node: PairedNode, + endpoint: Endpoint, + rootEndpoint: Endpoint, + adapter: ioBroker.Adapter, + endpointDeviceBaseId: string, + deviceTypeName: string, + defaultConnectionStateId: string, + defaultName: string, + ) { + super( + adapter, + node, + endpoint, + rootEndpoint, + endpointDeviceBaseId, + deviceTypeName, + defaultConnectionStateId, + defaultName, + ); + + this.#ioBrokerDevice = new FireAlarm( + { ...ChannelDetector.getPatterns().fireAlarm, isIoBrokerDevice: false } as DetectedDevice, + adapter, + this.enableDeviceTypeStates(), + ); + const smokeAlarm = this.appEndpoint.getClusterClient(SmokeCoAlarm.Complete); + if (smokeAlarm && !smokeAlarm.supportedFeatures.smokeAlarm) { + adapter.log.info( + 'Smoke alarm is not supported by device, but ioBroker does not support CO2 alarm currently.', + ); + } + } + + protected enableDeviceTypeStates(): DeviceOptions { + this.enableDeviceTypeStateForAttribute(PropertyType.Value, { + endpointId: this.appEndpoint.getNumber(), + clusterId: SmokeCoAlarm.Cluster.id, + attributeName: 'smokeState', + convertValue: (value: SmokeCoAlarm.AlarmState) => value !== SmokeCoAlarm.AlarmState.Normal, + }); + return super.enableDeviceTypeStates(); + } + + get ioBrokerDevice(): FireAlarm { + return this.#ioBrokerDevice; + } +} diff --git a/src/matter/to-iobroker/SpeakerToIoBroker.ts b/src/matter/to-iobroker/SpeakerToIoBroker.ts index a6621f8a..9746af45 100644 --- a/src/matter/to-iobroker/SpeakerToIoBroker.ts +++ b/src/matter/to-iobroker/SpeakerToIoBroker.ts @@ -83,8 +83,8 @@ export class SpeakerToIoBroker extends GenericElectricityDataDeviceToIoBroker { await this.appEndpoint.getClusterClient(LevelControl.Complete)?.moveToLevel({ level, transitionTime: null, - optionsMask: {}, - optionsOverride: {}, + optionsMask: { executeIfOff: true }, + optionsOverride: { executeIfOff: true }, }); }, convertValue: value => Math.round((value / 254) * 100), diff --git a/src/matter/to-iobroker/ioBrokerFactory.ts b/src/matter/to-iobroker/ioBrokerFactory.ts index f28fc47d..b80aa6c1 100644 --- a/src/matter/to-iobroker/ioBrokerFactory.ts +++ b/src/matter/to-iobroker/ioBrokerFactory.ts @@ -21,6 +21,7 @@ import { ExtendedColorLightToIoBroker } from './ExtendedColorLightToIoBroker'; import { WindowCoveringToIoBroker } from './WindowCoveringToIoBroker'; import { SpeakerToIoBroker } from './SpeakerToIoBroker'; import { ThermostatToIoBroker } from './ThermostatToIoBroker'; +import { SmokeCoAlarmToIoBroker } from './SmokeCoAlarmToIoBroker'; export function identifyDeviceTypes(endpoint: Endpoint): { utilityTypes: { deviceType: DeviceTypeModel; revision: number }[]; @@ -103,6 +104,9 @@ async function ioBrokerDeviceFabric( case Devices.OnOffPlugInUnitDeviceDefinition.deviceType: DeviceType = OnOffPlugInUnitToIoBroker; break; + case Devices.SmokeCoAlarmDeviceDefinition.deviceType: + DeviceType = SmokeCoAlarmToIoBroker; + break; case Devices.SpeakerDeviceDefinition.deviceType: DeviceType = SpeakerToIoBroker; break;