diff --git a/README.md b/README.md index ff639be..1357104 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,11 @@ With the ioBroker Matter Adapter, it is possible to map the following use cases: --> ## Changelog + +### __WORK IN PROGRESS__ +* (@Apollon77) Fixed caching issues in device type detection +* (@Apollon77) Added Debug info icon for Devices and Bridges + ### 0.4.10 (2025-01-27) * (@Apollon77) Fixed Thermostat limit initialization and Mode error * (@Apollon77) Fixed Matter Event handling when mapped to an ioBroker state (e.g.GenericSwitch) diff --git a/src-admin/src/Tabs/Bridges.tsx b/src-admin/src/Tabs/Bridges.tsx index a2f7ca3..4a69b25 100644 --- a/src-admin/src/Tabs/Bridges.tsx +++ b/src-admin/src/Tabs/Bridges.tsx @@ -4,6 +4,7 @@ import { v4 as uuidv4 } from 'uuid'; import { Add, + Article, AutoMode, Close, Delete, @@ -1251,25 +1252,56 @@ export class Bridges extends BridgesAndDevices {
{this.props.nodeStates?.[bridge.uuid] && bridge.enabled ? ( - - this.requestAdditionalInformation(e, bridge.uuid, device.uuid)} + <> + - {hasError ? : } - - + + this.requestAdditionalInformation( + 'deviceExtendedInfo', + e, + bridge.uuid, + device.uuid, + ) + } + > + {hasError ? : } + + + + + this.requestAdditionalInformation( + 'deviceDebugInfo', + e, + bridge.uuid, + device.uuid, + ) + } + > +
+ + + ) : null}
diff --git a/src-admin/src/Tabs/BridgesAndDevices.tsx b/src-admin/src/Tabs/BridgesAndDevices.tsx index 3251e9a..c691e49 100644 --- a/src-admin/src/Tabs/BridgesAndDevices.tsx +++ b/src-admin/src/Tabs/BridgesAndDevices.tsx @@ -11,6 +11,7 @@ import { Utils, } from '@iobroker/adapter-react-v5'; import { + Article, Close, ContentCopy, Delete, @@ -262,11 +263,16 @@ class BridgesAndDevices; } - requestAdditionalInformation(e: React.MouseEvent, uuid: string, bridgedDeviceUuid?: string): void { + requestAdditionalInformation( + message: 'deviceExtendedInfo' | 'deviceDebugInfo', + e: React.MouseEvent, + uuid: string, + bridgedDeviceUuid?: string, + ): void { e.stopPropagation(); this.props.socket - .sendTo(`matter.${this.props.instance}`, 'deviceExtendedInfo', { uuid, bridgedDeviceUuid }) + .sendTo(`matter.${this.props.instance}`, message, { uuid, bridgedDeviceUuid }) .then( ({ result: { schema, options }, @@ -283,7 +289,7 @@ class BridgesAndDevices this.props.showToast(`Cannot reset: ${e}`)); + .catch(e => this.props.showToast(`Cannot request additional information for "${message}": ${e}`)); } renderMessageDialog(): React.JSX.Element | null { @@ -315,16 +321,17 @@ class BridgesAndDevices @@ -375,15 +383,33 @@ class BridgesAndDevices { e.stopPropagation(); - this.requestAdditionalInformation(e, deviceOrBridge.uuid); + this.requestAdditionalInformation('deviceExtendedInfo', e, deviceOrBridge.uuid); }} > {hasError ? : } ); - - result[2] = extendedInfo; + result[3] = ( + + { + e.stopPropagation(); + this.requestAdditionalInformation('deviceDebugInfo', e, deviceOrBridge.uuid); + }} + > +
+ + + ); if ( this.props.nodeStates[deviceOrBridge.uuid].status && diff --git a/src-admin/src/i18n/de.json b/src-admin/src/i18n/de.json index 6bed7d7..667fe88 100644 --- a/src-admin/src/i18n/de.json +++ b/src-admin/src/i18n/de.json @@ -153,6 +153,7 @@ "Select/Unselect all devices in room": "Alle Geräte im Raum auswählen/abwählen", "Show QR Code for commissioning": "QR-Code zur Inbetriebnahme anzeigen", "Show additional information": "Weitere Informationen anzeigen", + "Show debug information": "Debug-Informationen anzeigen", "Show error": "Fehler anzeigen", "Show readme page": "Readme-Seite anzeigen", "Show unsupported devices": "Nicht unterstützte Geräte anzeigen", diff --git a/src-admin/src/i18n/en.json b/src-admin/src/i18n/en.json index f1616a2..5dc3bd9 100644 --- a/src-admin/src/i18n/en.json +++ b/src-admin/src/i18n/en.json @@ -153,6 +153,7 @@ "Select/Unselect all devices in room": "Select/Unselect all devices in room", "Show QR Code for commissioning": "Show QR Code for commissioning", "Show additional information": "Show additional information", + "Show debug information": "Show debug information", "Show error": "Show error", "Show readme page": "Show readme page", "Show unsupported devices": "Show unsupported devices", diff --git a/src-admin/src/i18n/es.json b/src-admin/src/i18n/es.json index 0c76284..6b564b8 100644 --- a/src-admin/src/i18n/es.json +++ b/src-admin/src/i18n/es.json @@ -153,6 +153,7 @@ "Select/Unselect all devices in room": "Seleccionar/deseleccionar todos los dispositivos en la habitación", "Show QR Code for commissioning": "Mostrar código QR para puesta en servicio", "Show additional information": "Mostrar información adicional", + "Show debug information": "Mostrar información de depuración", "Show error": "Mostrar error", "Show readme page": "Mostrar página readme", "Show unsupported devices": "Mostrar dispositivos no compatibles", diff --git a/src-admin/src/i18n/fr.json b/src-admin/src/i18n/fr.json index 545a41e..e09698e 100644 --- a/src-admin/src/i18n/fr.json +++ b/src-admin/src/i18n/fr.json @@ -153,6 +153,7 @@ "Select/Unselect all devices in room": "Sélectionner/Désélectionner tous les appareils de la pièce", "Show QR Code for commissioning": "Afficher le code QR pour la mise en service", "Show additional information": "Afficher des informations supplémentaires", + "Show debug information": "Afficher les informations de débogage", "Show error": "Afficher l'erreur", "Show readme page": "Afficher la page readme", "Show unsupported devices": "Afficher les appareils non pris en charge", diff --git a/src-admin/src/i18n/it.json b/src-admin/src/i18n/it.json index 5b4245b..ce9ed36 100644 --- a/src-admin/src/i18n/it.json +++ b/src-admin/src/i18n/it.json @@ -153,6 +153,7 @@ "Select/Unselect all devices in room": "Seleziona/Deseleziona tutti i dispositivi nella stanza", "Show QR Code for commissioning": "Mostra il codice QR per la messa in servizio", "Show additional information": "Mostra informazioni aggiuntive", + "Show debug information": "Mostra informazioni di debug", "Show error": "Mostra errore", "Show readme page": "Mostra la pagina Leggimi", "Show unsupported devices": "Mostra i dispositivi non supportati", diff --git a/src-admin/src/i18n/nl.json b/src-admin/src/i18n/nl.json index 27a508c..ffdbe79 100644 --- a/src-admin/src/i18n/nl.json +++ b/src-admin/src/i18n/nl.json @@ -153,6 +153,7 @@ "Select/Unselect all devices in room": "Selecteer/deselecteer alle apparaten in de kamer", "Show QR Code for commissioning": "QR-code weergeven voor inbedrijfstelling", "Show additional information": "Toon aanvullende informatie", + "Show debug information": "Debug-informatie weergeven", "Show error": "Fout weergeven", "Show readme page": "Leesmij-pagina weergeven", "Show unsupported devices": "Toon niet-ondersteunde apparaten", diff --git a/src-admin/src/i18n/pl.json b/src-admin/src/i18n/pl.json index d64ce95..45f6b52 100644 --- a/src-admin/src/i18n/pl.json +++ b/src-admin/src/i18n/pl.json @@ -153,6 +153,7 @@ "Select/Unselect all devices in room": "Zaznacz/odznacz wszystkie urządzenia w pokoju", "Show QR Code for commissioning": "Pokaż kod QR do uruchomienia", "Show additional information": "Pokaż dodatkowe informacje", + "Show debug information": "Pokaż informacje debugowania", "Show error": "Pokaż błąd", "Show readme page": "Pokaż stronę readme", "Show unsupported devices": "Pokaż nieobsługiwane urządzenia", diff --git a/src-admin/src/i18n/pt.json b/src-admin/src/i18n/pt.json index 9e08a3e..ad93ce1 100644 --- a/src-admin/src/i18n/pt.json +++ b/src-admin/src/i18n/pt.json @@ -153,6 +153,7 @@ "Select/Unselect all devices in room": "Selecionar/desmarcar todos os dispositivos na sala", "Show QR Code for commissioning": "Mostrar código QR para comissionamento", "Show additional information": "Mostrar informações adicionais", + "Show debug information": "Mostrar informações de depuração", "Show error": "Mostrar erro", "Show readme page": "Mostrar página leia-me", "Show unsupported devices": "Mostrar dispositivos não suportados", diff --git a/src-admin/src/i18n/ru.json b/src-admin/src/i18n/ru.json index 8a348ee..8c9ea1b 100644 --- a/src-admin/src/i18n/ru.json +++ b/src-admin/src/i18n/ru.json @@ -153,6 +153,7 @@ "Select/Unselect all devices in room": "Выбрать/отменить выбор всех устройств в комнате", "Show QR Code for commissioning": "Показать QR-код для ввода в эксплуатацию", "Show additional information": "Показать дополнительную информацию", + "Show debug information": "Показать отладочную информацию", "Show error": "Показать ошибку", "Show readme page": "Показать страницу readme", "Show unsupported devices": "Показать неподдерживаемые устройства", diff --git a/src-admin/src/i18n/uk.json b/src-admin/src/i18n/uk.json index b93ce0c..7d85178 100644 --- a/src-admin/src/i18n/uk.json +++ b/src-admin/src/i18n/uk.json @@ -153,6 +153,7 @@ "Select/Unselect all devices in room": "Виберіть/Скасуйте вибір усіх пристроїв у кімнаті", "Show QR Code for commissioning": "Показати QR-код для введення в експлуатацію", "Show additional information": "Показати додаткову інформацію", + "Show debug information": "", "Show error": "Показати помилку", "Show readme page": "Показати сторінку readme", "Show unsupported devices": "Показати непідтримувані пристрої", diff --git a/src-admin/src/i18n/zh-cn.json b/src-admin/src/i18n/zh-cn.json index 660e28b..bddf6dd 100644 --- a/src-admin/src/i18n/zh-cn.json +++ b/src-admin/src/i18n/zh-cn.json @@ -153,6 +153,7 @@ "Select/Unselect all devices in room": "选择/取消选择房间中的所有设备", "Show QR Code for commissioning": "显示二维码进行调试", "Show additional information": "显示更多信息", + "Show debug information": "显示调试信息", "Show error": "显示错误", "Show readme page": "显示自述文件页面", "Show unsupported devices": "显示不支持的设备", diff --git a/src/lib/devices/GenericDevice.ts b/src/lib/devices/GenericDevice.ts index 024d949..73a5543 100644 --- a/src/lib/devices/GenericDevice.ts +++ b/src/lib/devices/GenericDevice.ts @@ -666,7 +666,7 @@ export abstract class GenericDevice extends EventEmitter { } else if (valueType === ValueType.Enum) { return 'select'; } else if (valueType === ValueType.String && property === PropertyType.Rgb) { - //return 'color'; // Add again once works in DM + return 'color'; // Add again once works in DM } return 'input'; } diff --git a/src/main.ts b/src/main.ts index b01eba3..3140c67 100644 --- a/src/main.ts +++ b/src/main.ts @@ -819,6 +819,7 @@ export class MatterAdapter extends utils.Adapter { let controls = detector.detect(options); if (!controls?.length) { delete options.allowedTypes; + const detector = new ChannelDetector(); controls = detector.detect(options); } if (controls?.length) { diff --git a/src/matter/BaseServerNode.ts b/src/matter/BaseServerNode.ts index a589b90..a9d963e 100644 --- a/src/matter/BaseServerNode.ts +++ b/src/matter/BaseServerNode.ts @@ -8,6 +8,7 @@ import { PowerSource } from '@matter/main/clusters'; import type { GenericDevice } from '../lib/devices/GenericDevice'; import { PropertyType } from '../lib/devices/DeviceStateObject'; import { BatteryPowerSourceServer } from './behaviors/PowerSourceServer'; +import type { JsonFormSchema } from '@iobroker/dm-utils'; export enum NodeStates { Creating = 'creating', @@ -160,6 +161,31 @@ export abstract class BaseServerNode implements GeneralNode { }, }; } + case 'deviceDebugInfo': { + const { data, schema } = this.getDeviceDebugInfo(message); + return { + result: { + schema, + options: { + data, + maxWidth: 'md', + minWidth: 610, + title: `${this.type === 'bridges' && !('bridgedDeviceUuid' in message) ? 'Bridge' : 'Device'} Debug information`, + buttons: [ + { + type: 'copyToClipboard', + label: this.adapter.getText('Copy to clipboard'), + copyToClipboardAttr: 'debugInfos', + }, + { + type: 'close', + label: this.adapter.getText('Close'), + }, + ], + }, + }, + }; + } } return { error: `Unknown command "${command}"` }; @@ -190,6 +216,33 @@ export abstract class BaseServerNode implements GeneralNode { abstract getDeviceDetails(message: ioBroker.MessagePayload): StructuredJsonFormData; + getDeviceDebugInfo(_message: ioBroker.MessagePayload): { schema: JsonFormSchema; data: any } { + return { + schema: { + type: 'panel', + items: { + _instructions: { + type: 'staticText', + text: this.adapter.getText( + 'In case of issues with this node please copy and post these details together with Debug logs to the issue.', + ), + }, + debugInfos: { + type: 'text', + label: this.adapter.getText('Debug Infos'), + minRows: 30, + sm: 12, + readOnly: true, + copyToClipboard: true, + trim: false, + noClearButton: true, + }, + }, + }, + data: null, + }; + } + /** * Initializes the reachable state handler for a device and map it to the Basic Information Cluster of the Matter + * device. diff --git a/src/matter/BridgedDevicesNode.ts b/src/matter/BridgedDevicesNode.ts index 9c2b98e..28a877c 100644 --- a/src/matter/BridgedDevicesNode.ts +++ b/src/matter/BridgedDevicesNode.ts @@ -1,4 +1,4 @@ -import { Endpoint, ServerNode, VendorId } from '@matter/main'; +import { Endpoint, ServerNode, VendorId, EndpointServer } from '@matter/main'; import { BridgedDeviceBasicInformationServer, NetworkCommissioningServer } from '@matter/main/behaviors'; import { AggregatorEndpoint, BridgedNodeEndpoint } from '@matter/main/endpoints'; import { NetworkCommissioning } from '@matter/main/clusters'; @@ -12,6 +12,8 @@ import matterDeviceFactory from './to-matter/matterFactory'; import type { GenericDeviceToMatter } from './to-matter/GenericDeviceToMatter'; import type { StructuredJsonFormData } from '../lib/JsonConfigUtils'; import { IoBrokerCommissioningServer } from './behaviors/IoBrokerCommissioningServer'; +import { logEndpoint } from './EndpointStructureInspector'; +import type { JsonFormSchema } from '@iobroker/dm-utils'; export interface BridgeCreateOptions { parameters: BridgeOptions; @@ -463,6 +465,27 @@ class BridgedDevices extends BaseServerNode { return details; } + + override getDeviceDebugInfo(message: ioBroker.MessagePayload): { schema: JsonFormSchema; data: any } { + const bridgedDeviceUuid = message.bridgedDeviceUuid; + let debugInfos: string; + if (bridgedDeviceUuid === undefined) { + debugInfos = this.serverNode + ? logEndpoint(EndpointServer.forEndpoint(this.serverNode)) + : 'Server Node not initialized yet.'; + } else { + const endpoints = this.#deviceEndpoints.get(bridgedDeviceUuid); + if (endpoints) { + debugInfos = endpoints + .map(endpoint => logEndpoint(EndpointServer.forEndpoint(endpoint))) + .join('\r\n\r\n'); + } else { + debugInfos = `Device ${bridgedDeviceUuid} not found in bridge`; + } + } + const { schema } = super.getDeviceDebugInfo(message); + return { schema, data: { debugInfos } }; + } } export default BridgedDevices; diff --git a/src/matter/DeviceNode.ts b/src/matter/DeviceNode.ts index 2203d24..9058c69 100644 --- a/src/matter/DeviceNode.ts +++ b/src/matter/DeviceNode.ts @@ -1,4 +1,4 @@ -import { ServerNode, VendorId } from '@matter/main'; +import { ServerNode, VendorId, EndpointServer } from '@matter/main'; import { NetworkCommissioningServer } from '@matter/main/behaviors'; import { NetworkCommissioning } from '@matter/main/clusters'; import { inspect } from 'util'; @@ -11,6 +11,8 @@ import matterDeviceFactory from './to-matter/matterFactory'; import type { GenericDeviceToMatter } from './to-matter/GenericDeviceToMatter'; import type { StructuredJsonFormData } from '../lib/JsonConfigUtils'; import { IoBrokerCommissioningServer } from './behaviors/IoBrokerCommissioningServer'; +import { logEndpoint } from './EndpointStructureInspector'; +import type { JsonFormSchema } from '@iobroker/dm-utils'; export interface DeviceCreateOptions { parameters: DeviceOptions; @@ -255,6 +257,14 @@ class Device extends BaseServerNode { ...this.#mappingDevice?.getDeviceDetails(), }; } + + override getDeviceDebugInfo(message: ioBroker.MessagePayload): { schema: JsonFormSchema; data: any } { + const debugInfos = this.serverNode + ? logEndpoint(EndpointServer.forEndpoint(this.serverNode)) + : 'Server Node not initialized yet.'; + const { schema } = super.getDeviceDebugInfo(message); + return { schema, data: { debugInfos } }; + } } export default Device; diff --git a/src/matter/to-iobroker/GenericDeviceToIoBroker.ts b/src/matter/to-iobroker/GenericDeviceToIoBroker.ts index 181cf62..7201811 100644 --- a/src/matter/to-iobroker/GenericDeviceToIoBroker.ts +++ b/src/matter/to-iobroker/GenericDeviceToIoBroker.ts @@ -405,9 +405,6 @@ export abstract class GenericDeviceToIoBroker { }): Promise { const pathId = eventPathToString(data); const pathProperty = this.#matterMappings.get(pathId); - this.#adapter.log.debug( - `Handle event ${pathId} with property type ${typeof pathProperty === 'function' ? 'function' : pathProperty}`, - ); if (pathProperty === undefined) { return; } @@ -425,7 +422,6 @@ export abstract class GenericDeviceToIoBroker { for (const event of data.events) { const value = await convertValue(pathProperty, event); if (value !== undefined) { - this.#adapter.log.debug(`Update state for ${pathId} and type ${pathProperty} with value ${value}`); try { await this.ioBrokerDevice.updatePropertyValue(pathProperty, value); } catch (e) {