diff --git a/README.md b/README.md index bcf59379..b3670f27 100644 --- a/README.md +++ b/README.md @@ -213,13 +213,19 @@ TBD --> ## Changelog + +### __WORK IN PROGRESS__ +* (@Apollon77) Uses plain matter.js logs for better readability +* (@Apollon77) Prevents ghost connection entries in the UI +* (@Apollon77) Adds some missing implementations for Controller of Door, Window, FloodAlarm and Motion + ### 0.2.1 (2024-11-27) * (@Apollon77) Adds Color Temperature conversion if unit is "mireds" * (@Apollon77) Fixes Color Temperature cluster initialization * (@Apollon77) Fixes Min/Max calculation when unit conversion is used ### 0.2.0 (2024-11-26) -* IMPORTANT: Breaking change!! Please decommission ALL devices and do a full factory reset of the adapter Matter storage before installing this version. Pair the devices new afterwards. +* IMPORTANT: Breaking change!! Please decommission ALL devices and do a full factory reset of the adapter Matter storage before installing this version. Pair the devices new afterward. * (@Apollon77) Finalizes Devices, Bridges and Controller functionality with a first set of 11 device types * (@Apollon77) Upgrades to new Matter.js version and API (breaks storage structure) * (@GermanBluefox) Moved build process of GUI to vite diff --git a/src-admin/package-lock.json b/src-admin/package-lock.json index 0445af94..b7688e65 100644 --- a/src-admin/package-lock.json +++ b/src-admin/package-lock.json @@ -12,7 +12,6 @@ "@iobroker/adapter-react-v5": "^7.4.2", "@iobroker/dm-gui-components": "~7.4.2", "@iobroker/type-detector": "^4.0.1", - "@rollup/rollup-linux-x64-gnu": "*", "@types/react-dom": "^18.3.1", "@types/uuid": "^10.0.0", "@vitejs/plugin-react": "^4.3.3", diff --git a/src-admin/src/Tabs/BridgesAndDevices.tsx b/src-admin/src/Tabs/BridgesAndDevices.tsx index b2a40cb2..9b933784 100644 --- a/src-admin/src/Tabs/BridgesAndDevices.tsx +++ b/src-admin/src/Tabs/BridgesAndDevices.tsx @@ -110,13 +110,19 @@ class BridgesAndDevices ); } - if (vendor === 'Apple Inc.') { + if (vendor === 'Apple Inc.' || vendor === 'Apple Keychain') { return ( ); } - if (vendor === 'Samsung') { + if (vendor === 'SmartThings, Inc.' || vendor === 'Samsung') { return ( {BridgesAndDevices.getVendorIcon(info.vendorId, this.props.themeType) || - info.vendorId} + BridgesAndDevices.getVendorName(info.vendorId)} {info.label ? ( { + if (!this.#getValueState) { + throw new Error('Value state not found'); + } + return this.#getValueState.updateValue(value); + } } export default Door; diff --git a/src/lib/devices/FloodAlarm.ts b/src/lib/devices/FloodAlarm.ts index 5bcd9c06..534274e4 100644 --- a/src/lib/devices/FloodAlarm.ts +++ b/src/lib/devices/FloodAlarm.ts @@ -26,6 +26,13 @@ class FloodAlarm 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); + } } export default FloodAlarm; diff --git a/src/lib/devices/Motion.ts b/src/lib/devices/Motion.ts index 0ae88929..f7e3680c 100644 --- a/src/lib/devices/Motion.ts +++ b/src/lib/devices/Motion.ts @@ -35,6 +35,13 @@ class Motion extends GenericDevice { return this.#getMotionState.value; } + updateMotion(value: boolean): Promise { + if (!this.#getMotionState) { + throw new Error('Value state not found'); + } + return this.#getMotionState.updateValue(value); + } + hasBrightness(): boolean { return this.propertyNames.includes(PropertyType.Brightness); } @@ -45,6 +52,13 @@ class Motion extends GenericDevice { } return this.#getBrightnessState.value; } + + updateBrightness(value: number): Promise { + if (!this.#getBrightnessState) { + throw new Error('Brightness state not found'); + } + return this.#getBrightnessState.updateValue(value); + } } export default Motion; diff --git a/src/lib/devices/Temperature.ts b/src/lib/devices/Temperature.ts index e35d3afe..6692b0a9 100644 --- a/src/lib/devices/Temperature.ts +++ b/src/lib/devices/Temperature.ts @@ -55,6 +55,13 @@ class Temperature extends GenericDevice { } return this.#getHumidityState.value; } + + updateHumidity(value: number): Promise { + if (!this.#getHumidityState) { + throw new Error('Humidity state not found'); + } + return this.#getHumidityState.updateValue(value); + } } export default Temperature; diff --git a/src/lib/devices/Window.ts b/src/lib/devices/Window.ts index 55f1a879..1be47f4d 100644 --- a/src/lib/devices/Window.ts +++ b/src/lib/devices/Window.ts @@ -26,6 +26,13 @@ class Window 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); + } } export default Window; diff --git a/src/main.ts b/src/main.ts index 56ec516b..1c56f1f0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,6 @@ import * as utils from '@iobroker/adapter-core'; import ChannelDetector, { type DetectorState, Types } from '@iobroker/type-detector'; -import { Environment, LogLevel, Logger, StorageService } from '@matter/main'; +import { Environment, LogLevel, LogFormat, Logger, StorageService } from '@matter/main'; import axios from 'axios'; import jwt from 'jsonwebtoken'; import fs from 'node:fs/promises'; @@ -340,6 +340,7 @@ export class MatterAdapter extends utils.Adapter { async prepareMatterEnvironment(): Promise { const config: MatterAdapterConfig = this.config as MatterAdapterConfig; Logger.defaultLogLevel = LogLevel.DEBUG; + Logger.format = LogFormat.PLAIN; Logger.log = (level: LogLevel, formattedLog: string) => { switch (level) { case LogLevel.DEBUG: diff --git a/src/matter/BaseServerNode.ts b/src/matter/BaseServerNode.ts index 0681acec..ac52c7d2 100644 --- a/src/matter/BaseServerNode.ts +++ b/src/matter/BaseServerNode.ts @@ -1,4 +1,4 @@ -import { Logger, type ServerNode, type SessionsBehavior } from '@matter/main'; +import { Logger, type ServerNode, type SessionsBehavior, serialize } from '@matter/main'; import type { MatterAdapter } from '../main'; import type { GeneralNode, MessageResponse } from './GeneralNode'; @@ -82,24 +82,13 @@ export abstract class BaseServerNode implements GeneralNode { const activeSessions = Object.values(this.serverNode.state.sessions.sessions); const fabrics = Object.values(this.serverNode.state.commissioning.fabrics); - const connectionInfo: ConnectionInfo[] = activeSessions.map(session => { - const vendorId = session?.fabric?.rootVendorId; - return { - vendorId, - connected: !!session.numberOfActiveSubscriptions, - label: session?.fabric?.label, - }; - }); - - fabrics.forEach(fabric => { - if (!activeSessions.find(session => session.fabric?.fabricId === fabric.fabricId)) { - connectionInfo.push({ - vendorId: fabric?.rootVendorId, - connected: false, - label: fabric?.label, - }); - } - }); + const connectionInfo: ConnectionInfo[] = fabrics.map(fabric => ({ + vendorId: fabric?.rootVendorId, + connected: activeSessions + .filter(session => session.fabric?.fabricId === fabric.fabricId) + .some(({ numberOfActiveSubscriptions }) => !!numberOfActiveSubscriptions), + label: fabric?.label, + })); if (connectionInfo.find(info => info.connected)) { this.adapter.log.debug(`${this.type} ${this.uuid} is already commissioned and connected with controller`); @@ -145,7 +134,7 @@ export abstract class BaseServerNode implements GeneralNode { } this.serverNode.events.commissioning.fabricsChanged.on(async fabricIndex => { this.adapter.log.debug( - `commissioningChangedCallback: Commissioning changed on Fabric ${fabricIndex}: ${JSON.stringify(this.serverNode?.state.operationalCredentials.fabrics.find(fabric => fabric.fabricIndex === fabricIndex))}`, + `commissioningChangedCallback: Commissioning changed on Fabric ${fabricIndex}: ${serialize(this.serverNode?.state.operationalCredentials.fabrics.find(fabric => fabric.fabricIndex === fabricIndex))}`, ); await this.updateUiState(); }); diff --git a/src/matter/to-matter/CtToMatter.ts b/src/matter/to-matter/CtToMatter.ts index 8b65dff9..88fc8159 100644 --- a/src/matter/to-matter/CtToMatter.ts +++ b/src/matter/to-matter/CtToMatter.ts @@ -105,7 +105,7 @@ export class CtToMatter extends GenericElectricityDataDeviceToMatter { } async registerIoBrokerHandlersAndInitialize(): Promise { - const { min = 2_000, max = 6_500 } = this.#ioBrokerDevice.getTemperatureMinMax() ?? {}; + const { min = 2_000, max = 6_536 } = this.#ioBrokerDevice.getTemperatureMinMax() ?? {}; // 153 till 500 mireds this.#ioBrokerDevice.onChange(async event => { switch (event.property) {