From e720eca78edf7be8f0967f7b6f626bcfd82f9b85 Mon Sep 17 00:00:00 2001 From: Niels de Boer Date: Wed, 17 Apr 2024 13:31:46 +0200 Subject: [PATCH 1/3] feat(matter): add matter driver validation --- assets/app/schema.json | 94 +++++++++++++++++++++++++++++++++++++++++- lib/App/index.js | 37 ++++++++++++++++- 2 files changed, 128 insertions(+), 3 deletions(-) diff --git a/assets/app/schema.json b/assets/app/schema.json index 8c35fb6d..ef183c8d 100755 --- a/assets/app/schema.json +++ b/assets/app/schema.json @@ -747,6 +747,94 @@ ] } }, + "matterDevice": { + "type": "object", + "required": ["vendorId", "productId"], + "properties": { + "vendorId": { + "oneOf": [ + { + "type": "number", + "minimum": 1, + "maximum": 65520 + }, + { + "type": "array", + "items": { + "type": "number", + "minimum": 1, + "maximum": 65520 + } + } + ] + }, + "productId": { + "oneOf": [ + { + "type": "number", + "minimum": 1, + "maximum": 65535 + }, + { + "type": "array", + "items": { + "type": "number", + "minimum": 1, + "maximum": 65535 + } + } + ] + }, + "deviceVendorId": { + "oneOf": [ + { + "type": "number", + "minimum": 1, + "maximum": 65520 + }, + { + "type": "array", + "items": { + "type": "number", + "minimum": 1, + "maximum": 65520 + } + } + ] + }, + "deviceProductName": { + "oneOf": [ + { + "type": "string", + "minLength": 1, + "maxLength": 32 + }, + { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 32 + } + } + ] + }, + "learnmode": { + "type": "object", + "required": [ + "instruction" + ], + "properties": { + "image": { + "type": "string" + }, + "instruction": { + "$ref": "#/definitions/i18nObject" + } + } + } + } + }, "zigbeeDevice": { "type": "object", "required": [ @@ -1322,6 +1410,9 @@ } ] }, + "matter": { + "$ref": "#/definitions/matterDevice" + }, "zwave": { "$ref": "#/definitions/zwaveDevice" }, @@ -1368,7 +1459,8 @@ "zigbee", "infrared", "rf433", - "rf868" + "rf868", + "matter" ] } } diff --git a/lib/App/index.js b/lib/App/index.js index 094a91e9..46deb7b9 100644 --- a/lib/App/index.js +++ b/lib/App/index.js @@ -342,9 +342,9 @@ class App { } // validate `appJson.drivers[].connectivity` - if (driver.connectivity && (driver.connectivity.includes('lan') || driver.connectivity.includes('rf868'))) { + if (driver.connectivity && (driver.connectivity.includes('lan') || driver.connectivity.includes('rf868') || driver.connectivity.includes('matter'))) { if (driver.platforms && driver.platforms.includes('cloud')) { - throw new Error(`drivers.${driver.id} invalid 'connectivity': Platform 'cloud' does not support 'lan' or 'rf868'.`); + throw new Error(`drivers.${driver.id} invalid 'connectivity': Platform 'cloud' does not support 'lan', 'matter' or 'rf868'.`); } } @@ -365,6 +365,39 @@ class App { }); } } + + if (driver.connectivity && driver.connectivity.includes('matter')) { + if (!driver.matter) { + throw new Error(`drivers.${driver.id} invalid 'connectivity': 'matter' requires a 'matter' object.`); + } + + if (driver.pair) { + throw new Error(`drivers.${driver.id} invalid 'pair': matter drivers do not support custom pairing views.`); + } + + if ( + (driver.matter.deviceVendorId === undefined && driver.matter.deviceProductName !== undefined) || + (driver.matter.deviceVendorId !== undefined && driver.matter.deviceProductName === undefined) + ) { + throw new Error(`drivers.${driver.id} invalid 'matter': 'deviceVendorId' and 'deviceProductName' must be defined together.`); + } + + const deviceJsExists = await this._fileExistsCaseSensitive(join('drivers', driver.id, 'device.js')); + + if (deviceJsExists) { + throw new Error(`drivers.${driver.id}: using a device.js file is not supported for Matter drivers.`); + } + + const driverJsExists = await this._fileExistsCaseSensitive(join('drivers', driver.id, 'driver.js')); + + if (driverJsExists) { + throw new Error(`drivers.${driver.id}: using a driver.js file is not supported for Matter drivers.`); + } + } + + if (driver.matter && !(driver.connectivity && driver.connectivity.includes('matter'))) { + throw new Error(`drivers.${driver.id} invalid 'matter': 'matter' requires 'connectivity' to include 'matter'.`); + } } } From 825019894874016216dc12644d4b77852f762c77 Mon Sep 17 00:00:00 2001 From: Niels de Boer Date: Thu, 18 Apr 2024 11:13:10 +0200 Subject: [PATCH 2/3] feature(matter): update error strings --- lib/App/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/App/index.js b/lib/App/index.js index 46deb7b9..06c50252 100644 --- a/lib/App/index.js +++ b/lib/App/index.js @@ -368,11 +368,11 @@ class App { if (driver.connectivity && driver.connectivity.includes('matter')) { if (!driver.matter) { - throw new Error(`drivers.${driver.id} invalid 'connectivity': 'matter' requires a 'matter' object.`); + throw new Error(`drivers.${driver.id} has 'connectivity': 'matter' and therefore requires a 'matter' object.`); } if (driver.pair) { - throw new Error(`drivers.${driver.id} invalid 'pair': matter drivers do not support custom pairing views.`); + throw new Error(`drivers.${driver.id} invalid 'pair' configuration, Matter drivers do not support custom pairing views.`); } if ( @@ -396,7 +396,7 @@ class App { } if (driver.matter && !(driver.connectivity && driver.connectivity.includes('matter'))) { - throw new Error(`drivers.${driver.id} invalid 'matter': 'matter' requires 'connectivity' to include 'matter'.`); + throw new Error(`drivers.${driver.id} Matter drivers require 'connectivity' to include 'matter'.`); } } } From 8c8185346e243a43c526e5d62440bbaaec3d5da6 Mon Sep 17 00:00:00 2001 From: Niels de Boer Date: Thu, 18 Apr 2024 11:15:40 +0200 Subject: [PATCH 3/3] feature(matter): validate driver/device.mjs --- lib/App/index.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/App/index.js b/lib/App/index.js index 06c50252..70e76e2e 100644 --- a/lib/App/index.js +++ b/lib/App/index.js @@ -383,15 +383,17 @@ class App { } const deviceJsExists = await this._fileExistsCaseSensitive(join('drivers', driver.id, 'device.js')); + const deviceMjsExists = await this._fileExistsCaseSensitive(join('drivers', driver.id, 'device.mjs')); - if (deviceJsExists) { - throw new Error(`drivers.${driver.id}: using a device.js file is not supported for Matter drivers.`); + if (deviceJsExists || deviceMjsExists) { + throw new Error(`drivers.${driver.id}: using a device.${deviceJsExists ? 'js' : 'mjs'} file is not supported for Matter drivers.`); } const driverJsExists = await this._fileExistsCaseSensitive(join('drivers', driver.id, 'driver.js')); + const driverMjsExists = await this._fileExistsCaseSensitive(join('drivers', driver.id, 'driver.mjs')); - if (driverJsExists) { - throw new Error(`drivers.${driver.id}: using a driver.js file is not supported for Matter drivers.`); + if (driverJsExists || driverMjsExists) { + throw new Error(`drivers.${driver.id}: using a driver.${driverJsExists ? 'js' : 'mjs'} file is not supported for Matter drivers.`); } }