diff --git a/README.md b/README.md index f2c63a3..c4d907c 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,12 @@ With the ioBroker Matter Adapter, it is possible to map the following use cases: --> ## Changelog + +### __WORK IN PROGRESS__ +* (@Apollon77) Fixed Thermostat limit initialization and Mode error +* (@Apollon77) Fixed Matter Event handling when mapped to an ioBroker state (e.g.GenericSwitch) +* (@Apollon77) Fixed Device type detection by really preferring the preferred type + ### 0.4.9 (2025-01-26) * (@Apollon77) Enhanced error and invalid devices display for UI * (@Apollon77) Fixed Button Press Controller support diff --git a/src-admin/package-lock.json b/src-admin/package-lock.json index dc30895..2a3b8c9 100644 --- a/src-admin/package-lock.json +++ b/src-admin/package-lock.json @@ -1,16 +1,16 @@ { "name": "iobroker.matter", - "version": "0.4.8", + "version": "0.4.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "iobroker.matter", - "version": "0.4.8", + "version": "0.4.9", "dependencies": { "@foxriver76/iob-component-lib": "^0.2.0", - "@iobroker/adapter-react-v5": "^7.4.18", - "@iobroker/dm-gui-components": "^7.4.18", + "@iobroker/adapter-react-v5": "^7.4.19", + "@iobroker/dm-gui-components": "^7.4.19", "@iobroker/type-detector": "^4.1.1", "@types/react-dom": "^18.3.5", "@types/uuid": "^10.0.0", @@ -988,9 +988,9 @@ } }, "node_modules/@iobroker/adapter-react-v5": { - "version": "7.4.18", - "resolved": "https://registry.npmjs.org/@iobroker/adapter-react-v5/-/adapter-react-v5-7.4.18.tgz", - "integrity": "sha512-Lll02b7P8YdtEqsQLBE1OtPhC58ZP6JMWsoDlr0InC6RTvzvNtG0YPWI6W3rqqmXtLhF0V+oGTMSUQqz5pC1hw==", + "version": "7.4.19", + "resolved": "https://registry.npmjs.org/@iobroker/adapter-react-v5/-/adapter-react-v5-7.4.19.tgz", + "integrity": "sha512-ewO9LOdxocUSkQsV3hz/pdEK9OIn1w08j57V9JdhRucw08pSp+mt80pnjJ7ZgvQc0jSzAVVO9DjDjbQ71arLYw==", "license": "MIT", "dependencies": { "@emotion/react": "^11.14.0", @@ -1003,6 +1003,7 @@ "@mui/material": "^6.4.1", "@sentry/browser": "^8.51.0", "cronstrue": "^2.53.0", + "file-selector": "^2.1.2", "react-color": "^2.19.3", "react-colorful": "^5.6.1", "react-cropper": "^2.3.3", @@ -1119,13 +1120,13 @@ } }, "node_modules/@iobroker/dm-gui-components": { - "version": "7.4.18", - "resolved": "https://registry.npmjs.org/@iobroker/dm-gui-components/-/dm-gui-components-7.4.18.tgz", - "integrity": "sha512-qJpjyMd/h8Kh5O9p6nDxo0HOkWzgNQfMELcH8ZcAMiN3UtuaJCAjtUlXCgoeNJGAdxazh7FqyjUs2ifklIS75A==", + "version": "7.4.19", + "resolved": "https://registry.npmjs.org/@iobroker/dm-gui-components/-/dm-gui-components-7.4.19.tgz", + "integrity": "sha512-5GoEhlDrJH6hSG1jB2//NoOJappqMrxn3Pj6ZzNw7qRgUDWV+2Omn7LvcdHqN6juyBNafLSM+tYcxYAEvhkVmQ==", "license": "MIT", "dependencies": { - "@iobroker/adapter-react-v5": "7.4.18", - "@iobroker/json-config": "7.4.18" + "@iobroker/adapter-react-v5": "7.4.19", + "@iobroker/json-config": "7.4.19" } }, "node_modules/@iobroker/js-controller-common": { @@ -1185,11 +1186,11 @@ } }, "node_modules/@iobroker/json-config": { - "version": "7.4.18", - "resolved": "https://registry.npmjs.org/@iobroker/json-config/-/json-config-7.4.18.tgz", - "integrity": "sha512-8FzFubBPLNsRdQ6ker+E+3c8w+ygQQc/EILzCmkEbPPmI/jKI8Xt9lCLx7U0xUWkRdob4Wl21TpBwt4Z/oIMvw==", + "version": "7.4.19", + "resolved": "https://registry.npmjs.org/@iobroker/json-config/-/json-config-7.4.19.tgz", + "integrity": "sha512-TtHCP1H2jP1uNKh14o2yNil91+KMEN2GuaY0YRKbMVIQaKYabWsxbx2+4WOZNvLjY1CONKtWZc6CbWIniUJvzg==", "dependencies": { - "@iobroker/adapter-react-v5": "7.4.18", + "@iobroker/adapter-react-v5": "7.4.19", "@mui/x-date-pickers": "^7.24.1", "crypto-js": "^4.2.0", "react-ace": "^13.0.0", @@ -2636,9 +2637,9 @@ "license": "MIT" }, "node_modules/file-selector": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-2.1.0.tgz", - "integrity": "sha512-ZuXAqGePcSPz4JuerOY06Dzzq0hrmQ6VGoXVzGyFI1npeOfBgqGIKKpznfYWRkSLJlXutkqVC5WvGZtkFVhu9Q==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-2.1.2.tgz", + "integrity": "sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==", "license": "MIT", "dependencies": { "tslib": "^2.7.0" diff --git a/src-admin/package.json b/src-admin/package.json index 18ef399..72df798 100644 --- a/src-admin/package.json +++ b/src-admin/package.json @@ -7,8 +7,8 @@ }, "dependencies": { "@foxriver76/iob-component-lib": "^0.2.0", - "@iobroker/adapter-react-v5": "^7.4.18", - "@iobroker/dm-gui-components": "^7.4.18", + "@iobroker/adapter-react-v5": "^7.4.19", + "@iobroker/dm-gui-components": "^7.4.19", "@iobroker/type-detector": "^4.1.1", "@types/react-dom": "^18.3.5", "@types/uuid": "^10.0.0", @@ -51,4 +51,4 @@ } ] ] -} \ No newline at end of file +} diff --git a/src-admin/src/Tabs/Bridges.tsx b/src-admin/src/Tabs/Bridges.tsx index e71d0f6..a2f7ca3 100644 --- a/src-admin/src/Tabs/Bridges.tsx +++ b/src-admin/src/Tabs/Bridges.tsx @@ -1250,7 +1250,7 @@ export class Bridges extends BridgesAndDevices {
{`${I18n.t('Device type')}: ${I18n.t(device.type)}`}
- {this.props.nodeStates?.[bridge.uuid] ? ( + {this.props.nodeStates?.[bridge.uuid] && bridge.enabled ? ( { + if (!this.#modeState) { + throw new Error('Mode state not found'); + } + return this.#modeState.updateValue(mode); + } + hasMode(): boolean { return !!this.#modeState; } diff --git a/src/main.ts b/src/main.ts index 8a4276e..b01eba3 100644 --- a/src/main.ts +++ b/src/main.ts @@ -83,7 +83,6 @@ export class MatterAdapter extends utils.Adapter { readonly #bridges = new Map(); #controller?: MatterController; #sendControllerUpdateTimeout?: NodeJS.Timeout; - #detector: ChannelDetector; #_guiSubscribes: { clientId: string; ts: number }[] | null = null; readonly #matterEnvironment: Environment; #stateTimeout?: NodeJS.Timeout; @@ -130,7 +129,6 @@ export class MatterAdapter extends utils.Adapter { this.#deviceManagement = new MatterAdapterDeviceManagement(this); this.#matterEnvironment = Environment.default; - this.#detector = new ChannelDetector(); this.t = (word: string, ..._args: (string | number | boolean | null)[]): string => word; this.getText = (_word: string, ..._args: (string | number | boolean | null)[]): ioBroker.Translated => ({}) as ioBroker.Translated; @@ -813,8 +811,16 @@ export class MatterAdapter extends utils.Adapter { _usedIdsOptional: usedIds, ignoreIndicators, excludedTypes: [Types.info], + allowedTypes: preferredType ? [preferredType as Types] : undefined, + //ignoreCache: true }; - const controls = this.#detector.detect(options); + + const detector = new ChannelDetector(); + let controls = detector.detect(options); + if (!controls?.length) { + delete options.allowedTypes; + controls = detector.detect(options); + } if (controls?.length) { let controlsToCheck = controls.filter((control: PatternControl) => control.states.some(({ id: foundId }) => foundId === id), diff --git a/src/matter/BridgedDevicesNode.ts b/src/matter/BridgedDevicesNode.ts index 22e5b4c..9c2b98e 100644 --- a/src/matter/BridgedDevicesNode.ts +++ b/src/matter/BridgedDevicesNode.ts @@ -225,7 +225,7 @@ class BridgedDevices extends BaseServerNode { productId, serialNumber: uniqueId, uniqueId: md5(uniqueId), - hardwareVersion: versions.versionNum, + hardwareVersion: 1, hardwareVersionString: versions.versionStr, softwareVersion: versions.versionNum, softwareVersionString: versions.versionStr, diff --git a/src/matter/DeviceNode.ts b/src/matter/DeviceNode.ts index ad83b93..2203d24 100644 --- a/src/matter/DeviceNode.ts +++ b/src/matter/DeviceNode.ts @@ -125,7 +125,7 @@ class Device extends BaseServerNode { productId, serialNumber: uniqueId, uniqueId: md5(uniqueId), - hardwareVersion: versions.versionNum, + hardwareVersion: 1, hardwareVersionString: versions.versionStr, softwareVersion: versions.versionNum, softwareVersionString: versions.versionStr, diff --git a/src/matter/to-iobroker/GenericDeviceToIoBroker.ts b/src/matter/to-iobroker/GenericDeviceToIoBroker.ts index ea10369..181cf62 100644 --- a/src/matter/to-iobroker/GenericDeviceToIoBroker.ts +++ b/src/matter/to-iobroker/GenericDeviceToIoBroker.ts @@ -312,7 +312,7 @@ export abstract class GenericDeviceToIoBroker { eventId = cluster.events[eventName].id; } - if (stateData.id !== undefined) { + if (stateData.id === undefined) { stateData.id = `${this.baseId}.`; } const pathId = eventPathToString({ endpointId, clusterId, eventName }); diff --git a/src/matter/to-matter/ThermostatToMatter.ts b/src/matter/to-matter/ThermostatToMatter.ts index b8ee947..028064c 100644 --- a/src/matter/to-matter/ThermostatToMatter.ts +++ b/src/matter/to-matter/ThermostatToMatter.ts @@ -115,7 +115,7 @@ export class ThermostatToMatter extends GenericDeviceToMatter { adapter: ioBrokerDevice.adapter, }, thermostat: { - // Values are potentially corrected later again + // Values are corrected later again with real values systemMode: hasHeating ? MatterThermostat.SystemMode.Heat : MatterThermostat.SystemMode.Cool, controlSequenceOfOperation: hasHeating && hasCooling @@ -124,10 +124,10 @@ export class ThermostatToMatter extends GenericDeviceToMatter { ? MatterThermostat.ControlSequenceOfOperation.CoolingOnly : MatterThermostat.ControlSequenceOfOperation.HeatingOnly, minSetpointDeadBand: clusterModes.includes(MatterThermostat.Feature.AutoMode) ? 0 : undefined, - absMinHeatSetpointLimit: hasHeating ? this.convertTemperatureValue(7) : undefined, - absMaxHeatSetpointLimit: hasHeating ? this.convertTemperatureValue(30) : undefined, - absMinCoolSetpointLimit: hasCooling ? this.convertTemperatureValue(16) : undefined, - absMaxCoolSetpointLimit: hasCooling ? this.convertTemperatureValue(32) : undefined, + absMinHeatSetpointLimit: hasHeating ? this.convertTemperatureValue(0) : undefined, + absMaxHeatSetpointLimit: hasHeating ? this.convertTemperatureValue(50) : undefined, + absMinCoolSetpointLimit: hasCooling ? this.convertTemperatureValue(0) : undefined, + absMaxCoolSetpointLimit: hasCooling ? this.convertTemperatureValue(50) : undefined, }, }, ); @@ -242,8 +242,10 @@ export class ThermostatToMatter extends GenericDeviceToMatter { const minMax = this.#ioBrokerDevice.getSetpointMinMax() ?? { min: 7, max: 30 }; await this.#matterEndpointThermostat.setStateOf(IoThermostatServer, { // should be HeatingThermostatServer - // @ts-expect-error Workaround a .js instancing/typing error - occupiedHeatingSetpoint: this.convertTemperatureValue(setpointTemperature), + // @ts-expect-error Workaround a matter.js instancing/typing error + occupiedHeatingSetpoint: this.convertTemperatureValue( + this.#ioBrokerDevice.cropValue(setpointTemperature, minMax.min, minMax.max, true), + ), absMinHeatSetpointLimit: this.convertTemperatureValue(minMax.min), absMaxHeatSetpointLimit: this.convertTemperatureValue(minMax.max), }); @@ -252,7 +254,9 @@ export class ThermostatToMatter extends GenericDeviceToMatter { const minMax = this.#ioBrokerDevice.getSetpointMinMax() ?? { min: 16, max: 32 }; await this.#matterEndpointThermostat.setStateOf(IoThermostatServer, { // @ts-expect-error Workaround a matter.js instancing/typing error - occupiedCoolingSetpoint: this.convertTemperatureValue(setpointTemperature), + occupiedCoolingSetpoint: this.convertTemperatureValue( + this.#ioBrokerDevice.cropValue(setpointTemperature, minMax.min, minMax.max, true), + ), absMinCoolSetpointLimit: this.convertTemperatureValue(minMax.min), absMaxCoolSetpointLimit: this.convertTemperatureValue(minMax.max), });