From 387908060ff252c03183b3249970129e5e382e9f Mon Sep 17 00:00:00 2001
From: Paul Regan <64710345+paulr34@users.noreply.github.com>
Date: Fri, 22 Nov 2024 09:46:24 -0500
Subject: [PATCH] Enable Multiple Endpoints and Device Types in Device
Composition Insertion (#1489)
* enabling ZAP to load multiple devices for an endpoint composition
* fixing code so there can be multiple endpoints with different consraints and conformance if necessary
* remove debug test
* PR review cleanup
---
docs/api.md | 9 ++--
src-electron/db/query-loader.js | 72 ++++++++++++++++++++-------
src-electron/zcl/zcl-loader-silabs.js | 7 +--
3 files changed, 61 insertions(+), 27 deletions(-)
diff --git a/docs/api.md b/docs/api.md
index e6a1d62c51..8b08d79495 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -4066,16 +4066,17 @@ Retrieves the endpoint composition ID for a given device type code.
### DB API: zcl loading queries~insertDeviceComposition(db, deviceType, endpointCompositionId) ⇒ Promise
-Inserts a device composition record into the DEVICE_COMPOSITION table.
+Inserts device composition records for each deviceType into the DEVICE_COMPOSITION table
+for all endpoints in the deviceType, including endpoint-specific constraint and conformance values.
This function constructs an SQL INSERT query to add a new record to the
-DEVICE_COMPOSITION table. It handles the insertion of the device code,
-endpoint composition reference, conformance, and constraint values.
+DEVICE_COMPOSITION table for each deviceType in each endpoint. It handles the insertion
+of the device code, endpoint composition reference, conformance, and constraint values.
Note that the "CONSTRAINT" column name is escaped with double quotes
to avoid conflicts with the SQL reserved keyword.
**Kind**: inner method of [DB API: zcl loading queries
](#module_DB API_ zcl loading queries)
-**Returns**: Promise
- A promise that resolves when the insertion is complete.
+**Returns**: Promise
- A promise that resolves when all insertions are complete.
| Param | Type | Description |
| --- | --- | --- |
diff --git a/src-electron/db/query-loader.js b/src-electron/db/query-loader.js
index d770c913f8..95f1bbe127 100644
--- a/src-electron/db/query-loader.js
+++ b/src-electron/db/query-loader.js
@@ -1151,35 +1151,73 @@ async function getEndpointCompositionIdByCode(db, deviceType) {
}
/**
- * Inserts a device composition record into the DEVICE_COMPOSITION table.
+ * Inserts device composition records for each deviceType into the DEVICE_COMPOSITION table
+ * for all endpoints in the deviceType, including endpoint-specific constraint and conformance values.
*
* This function constructs an SQL INSERT query to add a new record to the
- * DEVICE_COMPOSITION table. It handles the insertion of the device code,
- * endpoint composition reference, conformance, and constraint values.
+ * DEVICE_COMPOSITION table for each deviceType in each endpoint. It handles the insertion
+ * of the device code, endpoint composition reference, conformance, and constraint values.
* Note that the "CONSTRAINT" column name is escaped with double quotes
* to avoid conflicts with the SQL reserved keyword.
*
* @param {Object} db - The database connection object.
* @param {Object} deviceType - The device type object containing the data to be inserted.
* @param {number} endpointCompositionId - The ID of the endpoint composition.
- * @returns {Promise} A promise that resolves when the insertion is complete.
+ * @returns {Promise} A promise that resolves when all insertions are complete.
*/
function insertDeviceComposition(db, deviceType, endpointCompositionId) {
- const insertQuery = `
- INSERT INTO DEVICE_COMPOSITION (CODE, ENDPOINT_COMPOSITION_REF, CONFORMANCE, DEVICE_CONSTRAINT)
- VALUES (?, ?, ?, ?)
- `
- try {
- return dbApi.dbInsert(db, insertQuery, [
- parseInt(deviceType.childDeviceId, 16),
- endpointCompositionId,
- deviceType.conformance,
+ // Ensure that deviceType and its necessary properties are defined
+ if (!deviceType?.composition?.endpoint) {
+ throw new Error('Invalid deviceType object or endpoint data')
+ }
+
+ // Make sure 'deviceType.composition.endpoint' is always an array, even if there's only one endpoint
+ const endpoints = Array.isArray(deviceType.composition.endpoint)
+ ? deviceType.composition.endpoint
+ : [deviceType.composition.endpoint]
+
+ // Prepare an array to hold all insert queries
+ const insertQueries = []
+
+ // Iterate over all endpoints in the deviceType and their respective deviceTypes
+ for (let endpoint of endpoints) {
+ // Ensure deviceType is present and handle both single value or array
+ const deviceTypes = Array.isArray(endpoint.deviceType)
+ ? endpoint.deviceType
+ : endpoint.deviceType
+ ? [endpoint.deviceType]
+ : [] // Default to empty array if undefined
+
+ // Use the $ to get the endpoint-specific conformance and constraint values
+ const endpointConformance =
+ endpoint.endpointComposition?.endpoint?.$.conformance ||
+ deviceType.conformance
+ const endpointConstraint =
+ endpoint.endpointComposition?.endpoint?.$.constraint ||
deviceType.constraint
- ])
- } catch (error) {
- console.error('Error inserting device composition:', error)
- throw error // Re-throw the error after logging it
+
+ // Create insert queries for each deviceType in this endpoint and add them to the insertQueries array
+ for (let device of deviceTypes) {
+ insertQueries.push(
+ dbApi.dbInsert(
+ db,
+ `
+ INSERT INTO DEVICE_COMPOSITION (CODE, ENDPOINT_COMPOSITION_REF, CONFORMANCE, DEVICE_CONSTRAINT)
+ VALUES (?, ?, ?, ?)
+ `,
+ [
+ parseInt(device, 16), // Convert deviceType to integer, assuming it is hex
+ endpointCompositionId,
+ endpointConformance, // Use the endpoint's specific conformance if available
+ endpointConstraint // Use the endpoint's specific constraint if available
+ ]
+ )
+ )
+ }
}
+
+ // Return the promise for executing all queries concurrently
+ return Promise.all(insertQueries)
}
/**
diff --git a/src-electron/zcl/zcl-loader-silabs.js b/src-electron/zcl/zcl-loader-silabs.js
index 5a2a89b1da..2fe6022982 100644
--- a/src-electron/zcl/zcl-loader-silabs.js
+++ b/src-electron/zcl/zcl-loader-silabs.js
@@ -1665,12 +1665,7 @@ function prepareDeviceType(deviceType) {
if ('endpointComposition' in deviceType) {
try {
ret.compositionType = deviceType.endpointComposition[0].compositionType[0]
- ret.conformance =
- deviceType.endpointComposition[0].endpoint[0].$.conformance
- ret.constraint =
- deviceType.endpointComposition[0].endpoint[0].$.constraint
- ret.childDeviceId =
- deviceType.endpointComposition[0].endpoint[0].deviceType[0]
+ ret.composition = deviceType.endpointComposition[0]
} catch (error) {
console.error('Error processing endpoint composition:', error)
}