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..70e76e2e 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,41 @@ class App { }); } } + + if (driver.connectivity && driver.connectivity.includes('matter')) { + if (!driver.matter) { + 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' configuration, 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')); + const deviceMjsExists = await this._fileExistsCaseSensitive(join('drivers', driver.id, 'device.mjs')); + + 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 || driverMjsExists) { + throw new Error(`drivers.${driver.id}: using a driver.${driverJsExists ? 'js' : 'mjs'} file is not supported for Matter drivers.`); + } + } + + if (driver.matter && !(driver.connectivity && driver.connectivity.includes('matter'))) { + throw new Error(`drivers.${driver.id} Matter drivers require 'connectivity' to include 'matter'.`); + } } }