diff --git a/bundles/org.openhab.binding.matter/README.md b/bundles/org.openhab.binding.matter/README.md index 4c1232e3805..c6ac3eb4f7a 100644 --- a/bundles/org.openhab.binding.matter/README.md +++ b/bundles/org.openhab.binding.matter/README.md @@ -2,6 +2,8 @@ The Matter Binding for openHAB allows seamless integration with Matter-compatible devices. +It currently supports version 1.4.1 of the Matter specification and earlier. + ## Supported functionality This binding supports two different types of Matter functionality which operate independently of each other. @@ -17,7 +19,7 @@ For more information on the Matter specification, see the [Matter Ecosystem Over ## Matter.JS Runtime -This binding uses the excellent [matter.js](https://github.com/project-chip/matter.js) implementation of the the Matter 1.4 protocol. +This binding uses the excellent [matter.js](https://github.com/project-chip/matter.js) implementation of the the Matter 1.4.1 protocol. As such, this binding requires NodesJS 18+ and will attempt to download and cache an appropriate version when started if a version is not already installed on the system. Alpine Linux users (typically docker) and those on older Linux distributions will need to install this manually as the official NodeJS versions are not compatible. @@ -38,7 +40,7 @@ This describes the Matter controller functionality for discovering and controlli The Matter Binding supports the following types of things: - `controller`: The main controller that interfaces with Matter devices. -It requires the configuration parameter `nodeId` which sets the local Matter node ID for this controller (must be unique in the fabric). +It requires the configuration parameter `nodeId` which sets the local Matter node ID for this controller (must be unique in the fabric). **This must be added manually.** - `node`: Represents an individual Node within the Matter network. The only configuration parameter is `nodeId`. diff --git a/bundles/org.openhab.binding.matter/code-gen/package-lock.json b/bundles/org.openhab.binding.matter/code-gen/package-lock.json index 9bcb26008df..1705b5117fc 100644 --- a/bundles/org.openhab.binding.matter/code-gen/package-lock.json +++ b/bundles/org.openhab.binding.matter/code-gen/package-lock.json @@ -8,10 +8,12 @@ "name": "code-gen", "version": "0.1.0", "dependencies": { - "@matter/main": "v0.14.0-alpha.0-20250531-7ed2d6da8", + "@matter/main": "v0.14.0", "handlebars": "^4.7.8" }, "devDependencies": { + "prettier": "^3.5.3", + "prettier-plugin-organize-imports": "^4.1.0", "ts-loader": "^9.4.4", "ts-node": "^10.9.2", "typescript": "^5.2.2" @@ -122,85 +124,85 @@ } }, "node_modules/@matter/general": { - "version": "0.14.0-alpha.0-20250531-7ed2d6da8", - "resolved": "https://registry.npmjs.org/@matter/general/-/general-0.14.0-alpha.0-20250531-7ed2d6da8.tgz", - "integrity": "sha512-0rkdLhn/ETSW5w/MQqJQnYRPtOwFx2VKRHAiu5w1lHS7TIVtJ4emPLq2HMSiQ2HMAEDz9eYzfIO4OueEhCbW4A==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@matter/general/-/general-0.14.0.tgz", + "integrity": "sha512-lTaJgeWRlwr+4JZr0RcuwSMqbZMa/uPpDWG5P2RC7N/QvmL3fPoRjfdWYjCKXZkGfeG2XXIezQGCkp0z2BWLLQ==", "dependencies": { "@noble/curves": "^1.9.1" } }, "node_modules/@matter/main": { - "version": "0.14.0-alpha.0-20250531-7ed2d6da8", - "resolved": "https://registry.npmjs.org/@matter/main/-/main-0.14.0-alpha.0-20250531-7ed2d6da8.tgz", - "integrity": "sha512-tu/XAD3wK0kzI9PfXHUK5T0z4Y2vNUMZhbxNe7kSB4kHHjWCHitv1NMG0/uEIWRkSrm4/e82WCdJUrWxLgtm0g==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@matter/main/-/main-0.14.0.tgz", + "integrity": "sha512-fBXQtBm5+ySWg7yA4FyiCl/olbirWeBSt8ExXCBoMX2blByiYgKdj7HiHWUK0ksgNGXwh8qX62jS3+VFEdWNBQ==", "dependencies": { - "@matter/general": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/model": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/node": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/protocol": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/types": "0.14.0-alpha.0-20250531-7ed2d6da8" + "@matter/general": "0.14.0", + "@matter/model": "0.14.0", + "@matter/node": "0.14.0", + "@matter/protocol": "0.14.0", + "@matter/types": "0.14.0" }, "optionalDependencies": { - "@matter/nodejs": "0.14.0-alpha.0-20250531-7ed2d6da8" + "@matter/nodejs": "0.14.0" } }, "node_modules/@matter/model": { - "version": "0.14.0-alpha.0-20250531-7ed2d6da8", - "resolved": "https://registry.npmjs.org/@matter/model/-/model-0.14.0-alpha.0-20250531-7ed2d6da8.tgz", - "integrity": "sha512-NvXbecY1WUjXVuXSzZX78uP50rixPNKM8mKP6JRzUpO8sKys1JwZIiJl3kGKPdTuvwot2hwpFJURtnReDam/MA==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@matter/model/-/model-0.14.0.tgz", + "integrity": "sha512-m4j+AY4lJCi9VE5bikUMwRIVuNWfjFIjhjD6VonTuYWVvqMGttWRQ3jTZV9qszkgur9YvOW2REmCJKvzB/KPqw==", "dependencies": { - "@matter/general": "0.14.0-alpha.0-20250531-7ed2d6da8" + "@matter/general": "0.14.0" } }, "node_modules/@matter/node": { - "version": "0.14.0-alpha.0-20250531-7ed2d6da8", - "resolved": "https://registry.npmjs.org/@matter/node/-/node-0.14.0-alpha.0-20250531-7ed2d6da8.tgz", - "integrity": "sha512-dJt1HoFeomJKfBwcEkK2iAETLJfUVebYzCZ9Ie2qJ37uNc7DfhRomy/Dvj+deHS2Icfalm/COrkMiJQf2G3SvA==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@matter/node/-/node-0.14.0.tgz", + "integrity": "sha512-QlK8Dg4YRD3db+CNZGnp0KVC1PsIbBwMzIAGh4TiO4ln68ltjRiOjNwYxb62F9YTSQhTuEQNxxiSfhK2nkYe2A==", "dependencies": { - "@matter/general": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/model": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/protocol": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/types": "0.14.0-alpha.0-20250531-7ed2d6da8" + "@matter/general": "0.14.0", + "@matter/model": "0.14.0", + "@matter/protocol": "0.14.0", + "@matter/types": "0.14.0" } }, "node_modules/@matter/nodejs": { - "version": "0.14.0-alpha.0-20250531-7ed2d6da8", - "resolved": "https://registry.npmjs.org/@matter/nodejs/-/nodejs-0.14.0-alpha.0-20250531-7ed2d6da8.tgz", - "integrity": "sha512-TTI7HfubBUQEZjcQAmcikoEerTfEt5iCy7ctSwzvt+M0PMToLyj3UrOgDEezezYw+hPzTBmitLWyb/VBnSpk0g==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@matter/nodejs/-/nodejs-0.14.0.tgz", + "integrity": "sha512-/XkBV5yX8ZH2SOkR4DDLoBivSONpEKk88QNf7AcTCf2wDadvM+hETsQ0Kli6U8pInpKTG/vghec+0bQ50nvO/A==", "optional": true, "dependencies": { - "@matter/general": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/node": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/protocol": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/types": "0.14.0-alpha.0-20250531-7ed2d6da8" + "@matter/general": "0.14.0", + "@matter/node": "0.14.0", + "@matter/protocol": "0.14.0", + "@matter/types": "0.14.0" }, "engines": { "node": ">=18.0.0" } }, "node_modules/@matter/protocol": { - "version": "0.14.0-alpha.0-20250531-7ed2d6da8", - "resolved": "https://registry.npmjs.org/@matter/protocol/-/protocol-0.14.0-alpha.0-20250531-7ed2d6da8.tgz", - "integrity": "sha512-y3PNdjtuiA1mAHnfpA3U30y29zQsxW3BOB3anYmGnpKTLTQia6hpmtp3FGHMBMi8rMNW5+PgQT9Gx2f/G+WwFg==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@matter/protocol/-/protocol-0.14.0.tgz", + "integrity": "sha512-lmnXEXiO9/dEKOL/0n4jTXnEhwDwZvkRIu9QU6miuETMjBoG0spUkV6+EPWbE1+j/vXr21m65NoIvUtDoS2SKw==", "dependencies": { - "@matter/general": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/model": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/types": "0.14.0-alpha.0-20250531-7ed2d6da8" + "@matter/general": "0.14.0", + "@matter/model": "0.14.0", + "@matter/types": "0.14.0" } }, "node_modules/@matter/types": { - "version": "0.14.0-alpha.0-20250531-7ed2d6da8", - "resolved": "https://registry.npmjs.org/@matter/types/-/types-0.14.0-alpha.0-20250531-7ed2d6da8.tgz", - "integrity": "sha512-72AgxSd1PQ5jxILMqt3JJ0Eg+duBekM/Bbjy7RIsXAB6eKPwXvvGypC4jjHn/FrAFbS7s0UVIvezT+xvxQM1gg==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@matter/types/-/types-0.14.0.tgz", + "integrity": "sha512-xOm/Mbs2Uqota4jJwAjl8kzsz8l1wIA216FslzSpS4TmzCskQNI8j7JIROlGkJbdMeZvBhFLirYnwilLYfQ6zw==", "dependencies": { - "@matter/general": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/model": "0.14.0-alpha.0-20250531-7ed2d6da8" + "@matter/general": "0.14.0", + "@matter/model": "0.14.0" } }, "node_modules/@noble/curves": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", - "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.2.tgz", + "integrity": "sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==", "dependencies": { "@noble/hashes": "1.8.0" }, @@ -1099,6 +1101,37 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/prettier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-organize-imports": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz", + "integrity": "sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==", + "dev": true, + "peerDependencies": { + "prettier": ">=2.0", + "typescript": ">=2.9", + "vue-tsc": "^2.1.0" + }, + "peerDependenciesMeta": { + "vue-tsc": { + "optional": true + } + } + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", diff --git a/bundles/org.openhab.binding.matter/code-gen/package.json b/bundles/org.openhab.binding.matter/code-gen/package.json index 1223eadfb97..94c5eb2c6ae 100644 --- a/bundles/org.openhab.binding.matter/code-gen/package.json +++ b/bundles/org.openhab.binding.matter/code-gen/package.json @@ -18,7 +18,7 @@ "prettier-plugin-organize-imports": "^4.1.0" }, "dependencies": { - "@matter/main": "v0.14.0-alpha.0-20250531-7ed2d6da8", + "@matter/main": "v0.14.0", "handlebars": "^4.7.8" }, "files": [ diff --git a/bundles/org.openhab.binding.matter/matter-server/package-lock.json b/bundles/org.openhab.binding.matter/matter-server/package-lock.json index ed1fce301ad..4044940ffc8 100644 --- a/bundles/org.openhab.binding.matter/matter-server/package-lock.json +++ b/bundles/org.openhab.binding.matter/matter-server/package-lock.json @@ -8,9 +8,9 @@ "name": "matter-server", "version": "0.1.0", "dependencies": { - "@matter/main": "v0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/node": "v0.14.0-alpha.0-20250531-7ed2d6da8", - "@project-chip/matter.js": "v0.14.0-alpha.0-20250531-7ed2d6da8", + "@matter/main": "v0.14.0", + "@matter/node": "v0.14.0", + "@project-chip/matter.js": "v0.14.0", "uuid": "^9.0.1", "ws": "^8.18.0", "yargs": "^17.7.2" @@ -424,85 +424,93 @@ } }, "node_modules/@matter/general": { - "version": "0.14.0-alpha.0-20250531-7ed2d6da8", - "resolved": "https://registry.npmjs.org/@matter/general/-/general-0.14.0-alpha.0-20250531-7ed2d6da8.tgz", - "integrity": "sha512-0rkdLhn/ETSW5w/MQqJQnYRPtOwFx2VKRHAiu5w1lHS7TIVtJ4emPLq2HMSiQ2HMAEDz9eYzfIO4OueEhCbW4A==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@matter/general/-/general-0.14.0.tgz", + "integrity": "sha512-lTaJgeWRlwr+4JZr0RcuwSMqbZMa/uPpDWG5P2RC7N/QvmL3fPoRjfdWYjCKXZkGfeG2XXIezQGCkp0z2BWLLQ==", + "license": "Apache-2.0", "dependencies": { "@noble/curves": "^1.9.1" } }, "node_modules/@matter/main": { - "version": "0.14.0-alpha.0-20250531-7ed2d6da8", - "resolved": "https://registry.npmjs.org/@matter/main/-/main-0.14.0-alpha.0-20250531-7ed2d6da8.tgz", - "integrity": "sha512-tu/XAD3wK0kzI9PfXHUK5T0z4Y2vNUMZhbxNe7kSB4kHHjWCHitv1NMG0/uEIWRkSrm4/e82WCdJUrWxLgtm0g==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@matter/main/-/main-0.14.0.tgz", + "integrity": "sha512-fBXQtBm5+ySWg7yA4FyiCl/olbirWeBSt8ExXCBoMX2blByiYgKdj7HiHWUK0ksgNGXwh8qX62jS3+VFEdWNBQ==", + "license": "Apache-2.0", "dependencies": { - "@matter/general": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/model": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/node": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/protocol": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/types": "0.14.0-alpha.0-20250531-7ed2d6da8" + "@matter/general": "0.14.0", + "@matter/model": "0.14.0", + "@matter/node": "0.14.0", + "@matter/protocol": "0.14.0", + "@matter/types": "0.14.0" }, "optionalDependencies": { - "@matter/nodejs": "0.14.0-alpha.0-20250531-7ed2d6da8" + "@matter/nodejs": "0.14.0" } }, "node_modules/@matter/model": { - "version": "0.14.0-alpha.0-20250531-7ed2d6da8", - "resolved": "https://registry.npmjs.org/@matter/model/-/model-0.14.0-alpha.0-20250531-7ed2d6da8.tgz", - "integrity": "sha512-NvXbecY1WUjXVuXSzZX78uP50rixPNKM8mKP6JRzUpO8sKys1JwZIiJl3kGKPdTuvwot2hwpFJURtnReDam/MA==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@matter/model/-/model-0.14.0.tgz", + "integrity": "sha512-m4j+AY4lJCi9VE5bikUMwRIVuNWfjFIjhjD6VonTuYWVvqMGttWRQ3jTZV9qszkgur9YvOW2REmCJKvzB/KPqw==", + "license": "Apache-2.0", "dependencies": { - "@matter/general": "0.14.0-alpha.0-20250531-7ed2d6da8" + "@matter/general": "0.14.0" } }, "node_modules/@matter/node": { - "version": "0.14.0-alpha.0-20250531-7ed2d6da8", - "resolved": "https://registry.npmjs.org/@matter/node/-/node-0.14.0-alpha.0-20250531-7ed2d6da8.tgz", - "integrity": "sha512-dJt1HoFeomJKfBwcEkK2iAETLJfUVebYzCZ9Ie2qJ37uNc7DfhRomy/Dvj+deHS2Icfalm/COrkMiJQf2G3SvA==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@matter/node/-/node-0.14.0.tgz", + "integrity": "sha512-QlK8Dg4YRD3db+CNZGnp0KVC1PsIbBwMzIAGh4TiO4ln68ltjRiOjNwYxb62F9YTSQhTuEQNxxiSfhK2nkYe2A==", + "license": "Apache-2.0", "dependencies": { - "@matter/general": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/model": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/protocol": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/types": "0.14.0-alpha.0-20250531-7ed2d6da8" + "@matter/general": "0.14.0", + "@matter/model": "0.14.0", + "@matter/protocol": "0.14.0", + "@matter/types": "0.14.0" } }, "node_modules/@matter/nodejs": { - "version": "0.14.0-alpha.0-20250531-7ed2d6da8", - "resolved": "https://registry.npmjs.org/@matter/nodejs/-/nodejs-0.14.0-alpha.0-20250531-7ed2d6da8.tgz", - "integrity": "sha512-TTI7HfubBUQEZjcQAmcikoEerTfEt5iCy7ctSwzvt+M0PMToLyj3UrOgDEezezYw+hPzTBmitLWyb/VBnSpk0g==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@matter/nodejs/-/nodejs-0.14.0.tgz", + "integrity": "sha512-/XkBV5yX8ZH2SOkR4DDLoBivSONpEKk88QNf7AcTCf2wDadvM+hETsQ0Kli6U8pInpKTG/vghec+0bQ50nvO/A==", + "license": "Apache-2.0", "optional": true, "dependencies": { - "@matter/general": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/node": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/protocol": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/types": "0.14.0-alpha.0-20250531-7ed2d6da8" + "@matter/general": "0.14.0", + "@matter/node": "0.14.0", + "@matter/protocol": "0.14.0", + "@matter/types": "0.14.0" }, "engines": { "node": ">=18.0.0" } }, "node_modules/@matter/protocol": { - "version": "0.14.0-alpha.0-20250531-7ed2d6da8", - "resolved": "https://registry.npmjs.org/@matter/protocol/-/protocol-0.14.0-alpha.0-20250531-7ed2d6da8.tgz", - "integrity": "sha512-y3PNdjtuiA1mAHnfpA3U30y29zQsxW3BOB3anYmGnpKTLTQia6hpmtp3FGHMBMi8rMNW5+PgQT9Gx2f/G+WwFg==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@matter/protocol/-/protocol-0.14.0.tgz", + "integrity": "sha512-lmnXEXiO9/dEKOL/0n4jTXnEhwDwZvkRIu9QU6miuETMjBoG0spUkV6+EPWbE1+j/vXr21m65NoIvUtDoS2SKw==", + "license": "Apache-2.0", "dependencies": { - "@matter/general": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/model": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/types": "0.14.0-alpha.0-20250531-7ed2d6da8" + "@matter/general": "0.14.0", + "@matter/model": "0.14.0", + "@matter/types": "0.14.0" } }, "node_modules/@matter/types": { - "version": "0.14.0-alpha.0-20250531-7ed2d6da8", - "resolved": "https://registry.npmjs.org/@matter/types/-/types-0.14.0-alpha.0-20250531-7ed2d6da8.tgz", - "integrity": "sha512-72AgxSd1PQ5jxILMqt3JJ0Eg+duBekM/Bbjy7RIsXAB6eKPwXvvGypC4jjHn/FrAFbS7s0UVIvezT+xvxQM1gg==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@matter/types/-/types-0.14.0.tgz", + "integrity": "sha512-xOm/Mbs2Uqota4jJwAjl8kzsz8l1wIA216FslzSpS4TmzCskQNI8j7JIROlGkJbdMeZvBhFLirYnwilLYfQ6zw==", + "license": "Apache-2.0", "dependencies": { - "@matter/general": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/model": "0.14.0-alpha.0-20250531-7ed2d6da8" + "@matter/general": "0.14.0", + "@matter/model": "0.14.0" } }, "node_modules/@noble/curves": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", - "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.2.tgz", + "integrity": "sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==", + "license": "MIT", "dependencies": { "@noble/hashes": "1.8.0" }, @@ -517,6 +525,7 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", "engines": { "node": "^14.21.3 || >=16" }, @@ -563,15 +572,16 @@ } }, "node_modules/@project-chip/matter.js": { - "version": "0.14.0-alpha.0-20250531-7ed2d6da8", - "resolved": "https://registry.npmjs.org/@project-chip/matter.js/-/matter.js-0.14.0-alpha.0-20250531-7ed2d6da8.tgz", - "integrity": "sha512-CewVH1Ug1eSZBetCICpDs0HJbhi8uAKLMgdiMmkFrf2FwcQb9whdCwQ1FmB0cHThZCNsHLicStqv1S5poS9QkQ==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@project-chip/matter.js/-/matter.js-0.14.0.tgz", + "integrity": "sha512-w2aTSC3YbCbASBv/5YJvo9wIevRcfuuSP9mQwPnJVMlNiK8ocReVhS0L2xLqIrZVbA3SILATRnD6g7skT/G5wg==", + "license": "Apache-2.0", "dependencies": { - "@matter/general": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/model": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/node": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/protocol": "0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/types": "0.14.0-alpha.0-20250531-7ed2d6da8" + "@matter/general": "0.14.0", + "@matter/model": "0.14.0", + "@matter/node": "0.14.0", + "@matter/protocol": "0.14.0", + "@matter/types": "0.14.0" } }, "node_modules/@tsconfig/node10": { diff --git a/bundles/org.openhab.binding.matter/matter-server/package.json b/bundles/org.openhab.binding.matter/matter-server/package.json index 5f7b51471a7..72df724a129 100644 --- a/bundles/org.openhab.binding.matter/matter-server/package.json +++ b/bundles/org.openhab.binding.matter/matter-server/package.json @@ -38,9 +38,9 @@ "webpack-cli": "^5.1.4" }, "dependencies": { - "@matter/main": "v0.14.0-alpha.0-20250531-7ed2d6da8", - "@matter/node": "v0.14.0-alpha.0-20250531-7ed2d6da8", - "@project-chip/matter.js": "v0.14.0-alpha.0-20250531-7ed2d6da8", + "@matter/main": "v0.14.0", + "@matter/node": "v0.14.0", + "@project-chip/matter.js": "v0.14.0", "uuid": "^9.0.1", "ws": "^8.18.0", "yargs": "^17.7.2" diff --git a/bundles/org.openhab.binding.matter/matter-server/src/Controller.ts b/bundles/org.openhab.binding.matter/matter-server/src/Controller.ts index 65035d5bd75..5e08224eda0 100644 --- a/bundles/org.openhab.binding.matter/matter-server/src/Controller.ts +++ b/bundles/org.openhab.binding.matter/matter-server/src/Controller.ts @@ -44,21 +44,20 @@ export abstract class Controller { try { const result = this.executeCommand(namespace, functionName, args || []); if (result instanceof Promise) { - result - .then(asyncResult => { - this.ws.sendResponse(MessageType.ResultSuccess, id, asyncResult); - }) - .catch(error => { - printError(logger, error, functionName); - this.ws.sendResponse(MessageType.ResultError, id, undefined, error.message); - }); + const asyncResult = await result; + this.ws.sendResponse(MessageType.ResultSuccess, id, asyncResult); } else { this.ws.sendResponse(MessageType.ResultSuccess, id, result); } } catch (error) { if (error instanceof Error) { printError(logger, error, functionName); - this.ws.sendResponse(MessageType.ResultError, id, undefined, error.message); + let errorId: string | undefined; + // instances of a MatterError has an id property + if ("id" in error) { + errorId = (error as any).id; + } + this.ws.sendResponse(MessageType.ResultError, id, undefined, error.message, errorId); } else { logger.error(`Unexpected error executing function ${functionName}: ${error}`); this.ws.sendResponse(MessageType.ResultError, id, undefined, String(error)); diff --git a/bundles/org.openhab.binding.matter/matter-server/src/MessageTypes.ts b/bundles/org.openhab.binding.matter/matter-server/src/MessageTypes.ts index dea3467fb4e..02d7212eca4 100644 --- a/bundles/org.openhab.binding.matter/matter-server/src/MessageTypes.ts +++ b/bundles/org.openhab.binding.matter/matter-server/src/MessageTypes.ts @@ -31,7 +31,6 @@ export interface Message { } export enum MessageType { - Result = "result", ResultError = "resultError", ResultSuccess = "resultSuccess", } diff --git a/bundles/org.openhab.binding.matter/matter-server/src/app.ts b/bundles/org.openhab.binding.matter/matter-server/src/app.ts index 3b5d3f34f28..789158c2b50 100644 --- a/bundles/org.openhab.binding.matter/matter-server/src/app.ts +++ b/bundles/org.openhab.binding.matter/matter-server/src/app.ts @@ -6,8 +6,10 @@ import { hideBin } from "yargs/helpers"; import { BridgeController } from "./bridge/BridgeController"; import { ClientController } from "./client/ClientController"; import { Controller } from "./Controller"; -import { Message, MessageType, Request } from "./MessageTypes"; +import { Message, Request } from "./MessageTypes"; import { printError } from "./util/error"; +import { toJSON } from "./util/Json"; + const argv: any = yargs(hideBin(process.argv)).argv; const logger = Logger.get("matter"); @@ -72,7 +74,7 @@ const shutdownHandler = async (signal: string) => { export interface WebSocketSession extends WebSocket { controller?: Controller; - sendResponse(type: string, id: string, result?: any, error?: string): void; + sendResponse(type: string, id: string, result?: any, error?: string, errorId?: string): void; sendEvent(type: string, data?: any): void; } @@ -80,7 +82,7 @@ const socketPort = argv.port ? parseInt(argv.port) : 8888; const wss: Server = new WebSocket.Server({ port: socketPort, host: argv.host }); wss.on("connection", (ws: WebSocketSession, req: IncomingMessage) => { - ws.sendResponse = (type: string, id: string, result?: any, error?: string) => { + ws.sendResponse = (type: string, id: string, result?: any, error?: string, errorId?: string) => { const message: Message = { type: "response", message: { @@ -88,10 +90,11 @@ wss.on("connection", (ws: WebSocketSession, req: IncomingMessage) => { id, result, error, + errorId, }, }; - logger.debug(`Sending response: ${Logger.toJSON(message)}`); - ws.send(Logger.toJSON(message)); + logger.debug(`Sending response: ${toJSON(message)}`); + ws.send(toJSON(message)); }; ws.sendEvent = (type: string, data?: any) => { @@ -102,8 +105,8 @@ wss.on("connection", (ws: WebSocketSession, req: IncomingMessage) => { data, }, }; - logger.debug(`Sending event: ${Logger.toJSON(message)}`); - ws.send(Logger.toJSON(message)); + logger.debug(`Sending event: ${toJSON(message)}`); + ws.send(toJSON(message)); }; ws.on("open", () => { @@ -111,17 +114,9 @@ wss.on("connection", (ws: WebSocketSession, req: IncomingMessage) => { }); ws.on("message", (message: string) => { - try { - const request: Request = JSON.parse(message); - if (ws.controller) { - void ws.controller.handleRequest(request).catch((error: Error) => { - ws.sendResponse(MessageType.ResultError, "", undefined, error.message); - }); - } - } catch (error) { - if (error instanceof Error) { - ws.sendResponse(MessageType.ResultError, "", undefined, error.message); - } + const request: Request = JSON.parse(message); + if (ws.controller) { + void ws.controller.handleRequest(request); } }); diff --git a/bundles/org.openhab.binding.matter/matter-server/src/client/ClientController.ts b/bundles/org.openhab.binding.matter/matter-server/src/client/ClientController.ts index 16221d30437..95a9942a6f4 100644 --- a/bundles/org.openhab.binding.matter/matter-server/src/client/ClientController.ts +++ b/bundles/org.openhab.binding.matter/matter-server/src/client/ClientController.ts @@ -1,6 +1,7 @@ import { Logger } from "@matter/general"; import { WebSocketSession } from "../app"; import { Controller } from "../Controller"; +import { toJSON } from "../util/Json"; import { ControllerNode } from "./ControllerNode"; import { Clusters } from "./namespaces/Clusters"; import { Nodes } from "./namespaces/Nodes"; @@ -53,7 +54,7 @@ export class ClientController extends Controller { } executeCommand(namespace: string, functionName: string, args: any[]): any | Promise { - logger.debug(`Executing function ${namespace}.${functionName}(${Logger.toJSON(args)})`); + logger.debug(`Executing function ${namespace}.${functionName}(${toJSON(args)})`); const controllerAny: any = this; diff --git a/bundles/org.openhab.binding.matter/matter-server/src/client/namespaces/Clusters.ts b/bundles/org.openhab.binding.matter/matter-server/src/client/namespaces/Clusters.ts index cc616f696af..1e54b33a604 100644 --- a/bundles/org.openhab.binding.matter/matter-server/src/client/namespaces/Clusters.ts +++ b/bundles/org.openhab.binding.matter/matter-server/src/client/namespaces/Clusters.ts @@ -2,7 +2,7 @@ import { Logger } from "@matter/general"; import { ClusterId, ValidationError } from "@matter/main/types"; import { ClusterModel, MatterModel } from "@matter/model"; import { SupportedAttributeClient } from "@matter/protocol"; -import { convertJsonDataWithModel } from "../../util/Json"; +import { convertJsonDataWithModel, toJSON } from "../../util/Json"; import { capitalize } from "../../util/String"; import { ControllerNode } from "../ControllerNode"; @@ -28,7 +28,7 @@ export class Clusters { * @throws Error if the cluster or command is not found on the device. */ async command(nodeId: number, endpointId: number, clusterName: string, commandName: string, args: any) { - logger.debug(`command ${nodeId} ${endpointId} ${clusterName} ${commandName} ${Logger.toJSON(args)}`); + logger.debug(`command ${nodeId} ${endpointId} ${clusterName} ${commandName} ${toJSON(args)}`); const device = this.controllerNode.getNode(nodeId).getDeviceById(endpointId); if (device == undefined) { throw new Error(`Endpoint ${endpointId} not found`); @@ -114,15 +114,15 @@ export class Clusters { parsedValue = convertJsonDataWithModel(attribute, parsedValue); await attributeClient.set(parsedValue); console.log( - `Attribute ${attributeName} ${nodeId}/${endpointId}/${clusterName}/${attributeName} set to ${Logger.toJSON(value)}`, + `Attribute ${attributeName} ${nodeId}/${endpointId}/${clusterName}/${attributeName} set to ${toJSON(value)}`, ); } catch (error) { if (error instanceof ValidationError) { throw new Error( - `Could not validate data for attribute ${attributeName} to ${Logger.toJSON(parsedValue)}: ${error}${error.fieldName !== undefined ? ` in field ${error.fieldName}` : ""}`, + `Could not validate data for attribute ${attributeName} to ${toJSON(parsedValue)}: ${error}${error.fieldName !== undefined ? ` in field ${error.fieldName}` : ""}`, ); } else { - throw new Error(`Could not set attribute ${attributeName} to ${Logger.toJSON(parsedValue)}: ${error}`); + throw new Error(`Could not set attribute ${attributeName} to ${toJSON(parsedValue)}: ${error}`); } } } diff --git a/bundles/org.openhab.binding.matter/matter-server/src/util/error.ts b/bundles/org.openhab.binding.matter/matter-server/src/util/error.ts index 46197b5bad8..427bb5d2d56 100644 --- a/bundles/org.openhab.binding.matter/matter-server/src/util/error.ts +++ b/bundles/org.openhab.binding.matter/matter-server/src/util/error.ts @@ -11,6 +11,9 @@ export function printError(logger: Logger, error: Error, functionName: string) { if ("name" in error) { logger.error(`Error name: ${(error as any).name}`); } + if ("id" in error) { + logger.error(`Error id: ${(error as any).id}`); + } // Fallback: log the entire error object in case there are other useful details logger.error(`Full error object: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`); diff --git a/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/actions/MatterControllerActions.java b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/actions/MatterControllerActions.java index 9adfe01a8ef..c591225a6dd 100644 --- a/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/actions/MatterControllerActions.java +++ b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/actions/MatterControllerActions.java @@ -17,6 +17,8 @@ import java.util.concurrent.ExecutionException; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.matter.internal.MatterBindingConstants; +import org.openhab.binding.matter.internal.client.MatterErrorCode; +import org.openhab.binding.matter.internal.client.MatterRequestException; import org.openhab.binding.matter.internal.handler.ControllerHandler; import org.openhab.binding.matter.internal.util.TranslationService; import org.openhab.core.automation.annotation.ActionInput; @@ -72,9 +74,21 @@ public class MatterControllerActions implements ThingActions { try { handler.startScan(code).get(); return translationService.getTranslation(MatterBindingConstants.THING_ACTION_RESULT_DEVICE_ADDED); - } catch (InterruptedException | ExecutionException e) { - return handler.getTranslation(MatterBindingConstants.THING_ACTION_RESULT_PAIRING_FAILED) - + e.getLocalizedMessage(); + } catch (InterruptedException e) { + return handler.getTranslation(MatterBindingConstants.THING_ACTION_RESULT_PAIRING_FAILED, + e.getLocalizedMessage()); + } catch (ExecutionException e) { + if (e.getCause() instanceof MatterRequestException matterRequestException) { + MatterErrorCode errorCode = matterRequestException.getErrorCode(); + if (errorCode != null) { + return handler.getTranslation(errorCode.getTranslationKey()); + } else { + return handler.getTranslation(MatterBindingConstants.THING_ACTION_RESULT_PAIRING_FAILED, + matterRequestException.getErrorMessage()); + } + } + return handler.getTranslation(MatterBindingConstants.THING_ACTION_RESULT_PAIRING_FAILED, + e.getLocalizedMessage()); } } return translationService.getTranslation(MatterBindingConstants.THING_ACTION_RESULT_NO_HANDLER); diff --git a/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/client/MatterErrorCode.java b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/client/MatterErrorCode.java new file mode 100644 index 00000000000..a79da901294 --- /dev/null +++ b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/client/MatterErrorCode.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2010-2025 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.openhab.binding.matter.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * Error codes and translation keys for Matter errors events. + * + * @author Dan Cunningham - Initial contribution + */ +@NonNullByDefault +public enum MatterErrorCode { + COMMISSIONING("commissioning", "matterjs.error.commissioning"), + MAXIMUM_COMMISSIONED_FABRICS_REACHED("maximum-commissioned-fabrics-reached", + "matterjs.error.maximum-commissioned-fabrics-reached"), + COMMISSIONING_TIMEOUT("commissioning-timeout", "matterjs.error.commissioning-timeout"), + DEVICE_ALREADY_COMMISSIONED_TO_THIS_FABRIC("device-already-commissioned-to-this-fabric", + "matterjs.error.device-already-commissioned-to-this-fabric"), + FABRIC_LABEL_CONFLICT("fabric-label-conflict", "matterjs.error.fabric-label-conflict"), + WIFI_OR_THREAD_NETWORK_CREDENTIALS_NOT_CONFIGURED("wifi-or-thread-network-credentials-not-configured", + "matterjs.error.wifi-or-thread-network-credentials-not-configured"), + WIFI_NETWORK_SETUP_FAILED("wifi-network-setup-failed", "matterjs.error.wifi-network-setup-failed"), + THREAD_NETWORK_SETUP_FAILED("thread-network-setup-failed", "matterjs.error.thread-network-setup-failed"), + NODE_ID_CONFLICT("node-id-conflict", "matterjs.error.node-id-conflict"), + COMMISSIONABLE_DEVICE_DISCOVERY_FAILED("commissionable-device-discovery-failed", + "matterjs.error.commissionable-device-discovery-failed"), + OPERATIVE_CONNECTION_FAILED("operative-connection-failed", "matterjs.error.operative-connection-failed"); + + private final String errorId; + private final String translationKey; + + MatterErrorCode(String errorId, String translationKey) { + this.errorId = errorId; + this.translationKey = translationKey; + } + + public String getErrorId() { + return errorId; + } + + public String getTranslationKey() { + return translationKey; + } + + public static @Nullable MatterErrorCode fromErrorId(String errorId) { + for (MatterErrorCode error : values()) { + if (error.errorId.equals(errorId)) { + return error; + } + } + return null; + } +} diff --git a/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/client/MatterRequestException.java b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/client/MatterRequestException.java new file mode 100644 index 00000000000..d8a4257602a --- /dev/null +++ b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/client/MatterRequestException.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010-2025 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.matter.internal.client; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * Exception thrown when a request to the Matter server fails. + * + * @author Dan Cunningham - Initial contribution + */ +@NonNullByDefault +public class MatterRequestException extends Exception { + private static final long serialVersionUID = 1L; + private final String errorMessage; + private final @Nullable MatterErrorCode errorCode; + + public MatterRequestException(String message, @Nullable MatterErrorCode errorCode) { + super(message); + this.errorMessage = message; + this.errorCode = errorCode; + } + + public String getErrorMessage() { + return errorMessage; + } + + public @Nullable MatterErrorCode getErrorCode() { + return errorCode; + } +} diff --git a/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/client/MatterWebsocketClient.java b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/client/MatterWebsocketClient.java index 7f137f8a42b..264ee5031b7 100644 --- a/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/client/MatterWebsocketClient.java +++ b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/client/MatterWebsocketClient.java @@ -58,6 +58,7 @@ import org.openhab.binding.matter.internal.client.dto.ws.NodeStateMessage; import org.openhab.binding.matter.internal.client.dto.ws.Path; import org.openhab.binding.matter.internal.client.dto.ws.Request; import org.openhab.binding.matter.internal.client.dto.ws.Response; +import org.openhab.binding.matter.internal.client.dto.ws.ResponseType; import org.openhab.binding.matter.internal.client.dto.ws.TriggerEvent; import org.openhab.core.common.ThreadPoolManager; import org.slf4j.Logger; @@ -261,8 +262,9 @@ public class MatterWebsocketClient implements WebSocketListener, MatterWebsocket return; } logger.debug("result type: {} ", response.type); - if (!"resultSuccess".equals(response.type)) { - future.completeExceptionally(new Exception(response.error)); + if (response.type != ResponseType.RESULT_SUCCESS) { + future.completeExceptionally( + new MatterRequestException(response.error, MatterErrorCode.fromErrorId(response.errorId))); } else { future.complete(response.result); } diff --git a/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/client/dto/ws/Response.java b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/client/dto/ws/Response.java index 64321f70bce..9c7fc93e982 100644 --- a/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/client/dto/ws/Response.java +++ b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/client/dto/ws/Response.java @@ -20,8 +20,9 @@ import com.google.gson.JsonElement; * @author Dan Cunningham - Initial contribution */ public class Response { - public String type; + public ResponseType type; public String id; public JsonElement result; public String error; + public String errorId; } diff --git a/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/client/dto/ws/ResponseType.java b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/client/dto/ws/ResponseType.java new file mode 100644 index 00000000000..c51f25153b2 --- /dev/null +++ b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/client/dto/ws/ResponseType.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010-2025 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.matter.internal.client.dto.ws; + +import com.google.gson.annotations.SerializedName; + +/** + * Websocket message response types. + * + * @author Dan Cunningham - Initial contribution + */ +public enum ResponseType { + + @SerializedName("resultError") + RESULT_ERROR("resultError"), + + @SerializedName("resultSuccess") + RESULT_SUCCESS("resultSuccess"); + + private final String value; + + ResponseType(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + + public String getValue() { + return value; + } +} diff --git a/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/controller/MatterControllerClient.java b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/controller/MatterControllerClient.java index 1a3a2064981..ccb65a48c7f 100644 --- a/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/controller/MatterControllerClient.java +++ b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/controller/MatterControllerClient.java @@ -53,6 +53,7 @@ public class MatterControllerClient extends MatterWebsocketClient { * Get all nodes that are commissioned / paired to this controller * * @return a future that returns a list of node IDs + * @throws MatterRequestException if the request fails */ public CompletableFuture> getCommissionedNodeIds() { CompletableFuture future = sendMessage("nodes", "listNodes", new Object[0]); @@ -69,6 +70,7 @@ public class MatterControllerClient extends MatterWebsocketClient { * @param nodeId the node ID to initialize * @param connectionTimeoutMilliseconds the timeout in milliseconds to wait for the node to connect * @return a future that completes when the node is initialized + * @throws MatterRequestException if the request fails */ public CompletableFuture initializeNode(BigInteger nodeId, Integer connectionTimeoutMilliseconds) { // add 1 second delay to the message timeout to allow the function to complete @@ -85,6 +87,7 @@ public class MatterControllerClient extends MatterWebsocketClient { * * @param nodeId the node ID to request data for * @return a future that completes when the data is requested + * @throws MatterRequestException if the request fails */ public CompletableFuture requestAllNodeData(BigInteger nodeId) { CompletableFuture future = sendMessage("nodes", "requestAllData", new Object[] { nodeId }); @@ -99,6 +102,7 @@ public class MatterControllerClient extends MatterWebsocketClient { * @param nodeId the node ID to request data for * @param endpointId the endpoint ID to request data for * @return a future that completes when the data is requested + * @throws MatterRequestException if the request fails */ public CompletableFuture requestEndpointData(BigInteger nodeId, Integer endpointId) { CompletableFuture future = sendMessage("nodes", "requestEndpointData", @@ -113,6 +117,7 @@ public class MatterControllerClient extends MatterWebsocketClient { * * @param code the pairing code to pair with * @return a future that completes when the node is paired (or fails) + * @throws MatterRequestException if the request fails */ public CompletableFuture pairNode(String code) { String[] parts = code.trim().split(" "); @@ -134,6 +139,7 @@ public class MatterControllerClient extends MatterWebsocketClient { * * @param nodeId the node ID to remove * @return a future that completes when the node is removed + * @throws MatterRequestException if the request fails */ public CompletableFuture removeNode(BigInteger nodeId) { CompletableFuture future = sendMessage("nodes", "removeNode", new Object[] { nodeId }); @@ -147,6 +153,7 @@ public class MatterControllerClient extends MatterWebsocketClient { * * @param nodeId the node ID to reconnect * @return a future that completes when the node is reconnected + * @throws MatterRequestException if the request fails */ public CompletableFuture reconnectNode(BigInteger nodeId) { CompletableFuture future = sendMessage("nodes", "reconnectNode", new Object[] { nodeId }); @@ -161,6 +168,7 @@ public class MatterControllerClient extends MatterWebsocketClient { * @param nodeId the node ID to get the pairing codes for * @return a future that completes when the pairing codes are retrieved * @throws JsonParseException when completing the future if the pairing codes cannot be deserialized + * @throws MatterRequestException if the request fails */ public CompletableFuture enhancedCommissioningWindow(BigInteger nodeId) { CompletableFuture future = sendMessage("nodes", "enhancedCommissioningWindow", @@ -179,6 +187,7 @@ public class MatterControllerClient extends MatterWebsocketClient { * * @param nodeId the node ID to disconnect * @return a future that completes when the node is disconnected + * @throws MatterRequestException if the request fails */ public CompletableFuture disconnectNode(BigInteger nodeId) { CompletableFuture future = sendMessage("nodes", "disconnectNode", new Object[] { nodeId }); @@ -193,6 +202,7 @@ public class MatterControllerClient extends MatterWebsocketClient { * @param nodeId the node ID to get the fabrics for * @return a future that completes when the fabrics are retrieved or an exception is thrown * @throws JsonParseException when completing the future if the fabrics cannot be deserialized + * @throws MatterRequestException if the request fails */ public CompletableFuture> getFabrics(BigInteger nodeId) { Object[] clusterArgs = { String.valueOf(nodeId) }; @@ -214,6 +224,7 @@ public class MatterControllerClient extends MatterWebsocketClient { * @param nodeId the node ID to remove the fabric from * @param index the index of the fabric to remove * @return a future that completes when the fabric is removed + * @throws MatterRequestException if the request fails */ public CompletableFuture removeFabric(BigInteger nodeId, Integer index) { CompletableFuture future = sendMessage("nodes", "removeFabric", new Object[] { nodeId, index }); @@ -230,6 +241,8 @@ public class MatterControllerClient extends MatterWebsocketClient { * @param clusterName the cluster name to send the command to * @param command the command to send * @return a future that completes when the command is sent + * @throws MatterRequestException if the request fails + * @throws JsonParseException when completing the future if the command cannot be deserialized */ public CompletableFuture clusterCommand(BigInteger nodeId, Integer endpointId, String clusterName, ClusterCommand command) { @@ -247,6 +260,7 @@ public class MatterControllerClient extends MatterWebsocketClient { * @param attributeName the attribute name to write * @param value the value to write * @return a future that completes when the attribute is written + * @throws MatterRequestException if the request fails */ public CompletableFuture clusterWriteAttribute(BigInteger nodeId, Integer endpointId, String clusterName, String attributeName, String value) { @@ -266,6 +280,7 @@ public class MatterControllerClient extends MatterWebsocketClient { * @param clusterId the cluster ID to read the cluster from * @return a future that completes when the cluster is read * @throws JsonParseException when completing the future if the cluster cannot be deserialized + * @throws MatterRequestException if the request fails */ public CompletableFuture readCluster(Class type, BigInteger nodeId, Integer endpointId, Integer clusterId) { @@ -289,6 +304,7 @@ public class MatterControllerClient extends MatterWebsocketClient { * @param clusterName the cluster name to read the attribute from * @param attributeName the attribute name to read * @return a future that completes when the attribute is read + * @throws MatterRequestException if the request fails */ public CompletableFuture clusterReadAttribute(BigInteger nodeId, Integer endpointId, String clusterName, String attributeName) { @@ -304,6 +320,7 @@ public class MatterControllerClient extends MatterWebsocketClient { * * @return a future that completes when the session information is retrieved * @throws JsonParseException when completing the future if the session information cannot be deserialized + * @throws MatterRequestException if the request fails */ public CompletableFuture getSessionInformation() { CompletableFuture future = sendMessage("nodes", "sessionInformation", new Object[0]); diff --git a/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/handler/ControllerHandler.java b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/handler/ControllerHandler.java index b728f0619b9..d695bfb7c39 100644 --- a/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/handler/ControllerHandler.java +++ b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/handler/ControllerHandler.java @@ -270,8 +270,8 @@ public class ControllerHandler extends BaseBridgeHandler implements MatterClient linkedNodes.keySet().forEach(nodeId -> updateNode(nodeId)); } - public String getTranslation(String key) { - return translationService.getTranslation(key); + public String getTranslation(String key, Object... args) { + return translationService.getTranslation(key, args); } public MatterControllerClient getClient() { diff --git a/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/util/TranslationService.java b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/util/TranslationService.java index 9a956f2ceff..9ac2162fe81 100644 --- a/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/util/TranslationService.java +++ b/bundles/org.openhab.binding.matter/src/main/java/org/openhab/binding/matter/internal/util/TranslationService.java @@ -12,6 +12,8 @@ */ package org.openhab.binding.matter.internal.util; +import java.util.Arrays; + import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.core.i18n.LocaleProvider; import org.openhab.core.i18n.TranslationProvider; @@ -51,10 +53,10 @@ public class TranslationService { * @param key the key to get the translation for (with or without the @text/ prefix) * @return the translation */ - public String getTranslation(String key) { + public String getTranslation(String key, Object... args) { String lookupKey = key.replace("@text/", ""); - String result = translationProvider.getText(bundle, lookupKey, lookupKey, localeProvider.getLocale()); - return result == null ? lookupKey : result; + String result = translationProvider.getText(bundle, lookupKey, lookupKey, localeProvider.getLocale(), args); + return result == null ? lookupKey + " " + Arrays.toString(args) : result; } public LocaleProvider getLocaleProvider() { diff --git a/bundles/org.openhab.binding.matter/src/main/resources/OH-INF/i18n/matter.properties b/bundles/org.openhab.binding.matter/src/main/resources/OH-INF/i18n/matter.properties index ee56ca5130b..f8fe3362479 100644 --- a/bundles/org.openhab.binding.matter/src/main/resources/OH-INF/i18n/matter.properties +++ b/bundles/org.openhab.binding.matter/src/main/resources/OH-INF/i18n/matter.properties @@ -324,3 +324,17 @@ thing-action.result.pairing-failed = Failed to pair device: {0} thing-status.detail.controller.waitingForData = Waiting for data thing-status.detail.endpoint.thingNotReachable = Bridge reports device as not reachable + +# matterjs error messages + +matterjs.error.commissioning = General commissioning error +matterjs.error.maximum-commissioned-fabrics-reached = Maximum number of commissioned fabrics reached on device, please remove a fabric from another controller or reset the device +matterjs.error.commissioning-timeout = The commissioning process could not be finished within the maximum allowed time frame +matterjs.error.device-already-commissioned-to-this-fabric = The device is already commissioned to this fabric, either remove this fabric using another controller or reset the device +matterjs.error.fabric-label-conflict = The device is already commissioned to another fabric with the same label, please remove the fabric using another controller or reset the device +matterjs.error.wifi-or-thread-network-credentials-not-configured = Wi-Fi or Thread network credentials not configured +matterjs.error.wifi-network-setup-failed = Wi-Fi network setup failed +matterjs.error.thread-network-setup-failed = Thread network setup failed +matterjs.error.node-id-conflict = Node ID conflict, reset the device and try again +matterjs.error.commissionable-device-discovery-failed = The device could not be discovered using the provided code +matterjs.error.operative-connection-failed = The reconnection process for the device failed, please reset the device and try again