Merge branch 'master' into asuppercamelcase
diff --git a/.github/workflows/matter.yml b/.github/workflows/matter.yml index be52be3..50420f3 100644 --- a/.github/workflows/matter.yml +++ b/.github/workflows/matter.yml
@@ -192,7 +192,7 @@ # CHIP container required because clang-format version needs to match container: - image: connectedhomeip/chip-build:0.6.11 + image: ghcr.io/project-chip/chip-build:125 steps: - uses: actions/download-artifact@v4
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 78c3c0d..72a9247 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml
@@ -333,6 +333,76 @@ - name: ZAP binary check (Linux) - unzip cleanup if: startsWith(matrix.os, 'ubuntu') run: rm -rf dist/zap-linux + - name: Verify zap.png exists in package's base directory + if: startsWith(matrix.os, 'ubuntu') + uses: GuillaumeFalourd/assert-command-line-output@v2.1 + with: + command_line: ./node_modules/7zip-bin/linux/x64/7za l ./dist/zap-linux-x64.zip | grep zap.png + contains: 'zap.png' + + - name: Verify zap.png exists in package's app.asar archive + if: startsWith(matrix.os, 'ubuntu') + uses: GuillaumeFalourd/assert-command-line-output@v2.1 + with: + command_line: npx asar l ./dist/linux-unpacked/resources/app.asar | grep zap.png + contains: 'zap.png' + + - name: Verify zap.png exists in Windows x64 .zip package + if: startsWith(matrix.os, 'macos') + uses: GuillaumeFalourd/assert-command-line-output@v2.1 + with: + command_line: 7za l ./dist/zap-win-x64.zip | grep zap.png + contains: 'zap.png' + + - name: Verify zap.png exists in Windows x64 .zip package's app.asar archive + if: startsWith(matrix.os, 'macos') + uses: GuillaumeFalourd/assert-command-line-output@v2.1 + with: + command_line: npx asar l ./dist/win-unpacked/resources/app.asar | grep zap.png + contains: 'zap.png' + + - name: Verify zap.png exists in Windows arm64 .zip package + if: startsWith(matrix.os, 'macos') + uses: GuillaumeFalourd/assert-command-line-output@v2.1 + with: + command_line: 7za l ./dist/zap-win-arm64.zip | grep zap.png + contains: 'zap.png' + + - name: Verify zap.png exists in Windows arm64 .zip package's app.asar archive + if: startsWith(matrix.os, 'macos') + uses: GuillaumeFalourd/assert-command-line-output@v2.1 + with: + command_line: npx asar l ./dist/win-arm64-unpacked/resources/app.asar | grep zap.png + contains: 'zap.png' + + - name: Verify zap.png exists in macOS x64 .zip package + if: startsWith(matrix.os, 'macos') + uses: GuillaumeFalourd/assert-command-line-output@v2.1 + with: + command_line: 7za l ./dist/zap-mac-x64.zip | grep zap.png + contains: 'zap.png' + + - name: Verify zap.png exists in macOS x64 .zip package's app-x64.asar archive + if: startsWith(matrix.os, 'macos') + uses: GuillaumeFalourd/assert-command-line-output@v2.1 + with: + command_line: npx asar l ./dist/mac/zap.app/Contents/Resources/app-x64.asar | grep zap.png + contains: 'zap.png' + + - name: Verify zap.png exists in macOS arm64 .zip package + if: startsWith(matrix.os, 'macos') + uses: GuillaumeFalourd/assert-command-line-output@v2.1 + with: + command_line: 7za l ./dist/zap-mac-arm64.zip | grep zap.png + contains: 'zap.png' + + - name: Verify zap.png exists in macOS arm64 .zip package's app-arm64.asar archive + if: startsWith(matrix.os, 'macos') + uses: GuillaumeFalourd/assert-command-line-output@v2.1 + with: + command_line: npx asar l ./dist/mac-arm64/zap.app/Contents/Resources/app-arm64.asar | grep zap.png + contains: 'zap.png' + - name: Verify apack.json exists in package's base directory if: startsWith(matrix.os, 'ubuntu') uses: GuillaumeFalourd/assert-command-line-output@v2.1
diff --git a/apack.json b/apack.json index 6d5bae0..6c5bb2c 100644 --- a/apack.json +++ b/apack.json
@@ -55,6 +55,7 @@ "id": "ZAP", "category": "tools", "label": "ZCL Advanced Platform", + "icon": "zap.png", "launchUiFunction": "launchZAP", "toolTip": "ZCL Advanced Platform" }
diff --git a/cypress/e2e/clusters/cluster-filter.cy.js b/cypress/e2e/clusters/cluster-filter.cy.js index cf2619b..a694e1c 100644 --- a/cypress/e2e/clusters/cluster-filter.cy.js +++ b/cypress/e2e/clusters/cluster-filter.cy.js
@@ -13,7 +13,9 @@ }) cy.setZclProperties() cy.fixture('data').then((data) => { - cy.addEndpoint(data.endpoint1, data.cluster1) + // Selecting SE Range Extender for Zigbee + // Selecting Matter Dimmable Light (0x0101) for Matter + cy.addEndpoint(data.endpoint9) }) }) it( @@ -21,11 +23,84 @@ { retries: { runMode: 2, openMode: 2 } }, () => { cy.get('[data-test="filter-input"]').click() + // Selecting Enabled clusters cy.get('.q-virtual-scroll__content > :nth-child(3)').click({ force: true }) cy.fixture('data').then((data) => { - cy.get('tbody').children().contains(data.cluster2).should('not.exist') + // Power Configurator for Zigbee is disabled and should not show up + // Occupancy Sensing for Matter is disabled and should not exist + cy.get('tbody').children().contains(data.cluster10).should('not.exist') + // Basic for Zigbee is enabled and should show up + // Identify for Matter is enabled and should show up + cy.get('tbody').children().contains(data.cluster11).should('exist') + }) + } + ) + it( + 'filter legal clusters and check clusters', + { retries: { runMode: 2, openMode: 2 } }, + () => { + cy.get('[data-test="filter-input"]').click() + // Selecting Legal Clusters + cy.get('.q-virtual-scroll__content > :nth-child(4)').click({ + force: true + }) + cy.fixture('data').then((data) => { + // Power Configurator for Zigbee is legal and should show up + // Occupancy Sensing for Matter is legal and should show up + if (data.cluster10 == 'Power Configuration') { + cy.get('tbody') + .children() + .contains(data.cluster10) + .should('exist') + .parents('tr') + .within(() => { + cy.get('div[role="checkbox"][aria-label="Client"]') + .should('have.attr', 'aria-checked', 'false') + .click({ force: true }) + .should('have.attr', 'aria-checked', 'false') // Even when clicking on the client checkbox it should not be enabled because of legal cluster filter setting does not allow non Device type clusters to be enabled. + }) + cy.get('tbody') + .children() + .contains(data.cluster10) + .should('exist') + .parents('tr') + .within(() => { + cy.get('div[role="checkbox"][aria-label="Server"]') + .should('have.attr', 'aria-checked', 'false') + .click({ force: true }) + .should('have.attr', 'aria-checked', 'true') // when clicking on the server checkbox it should be enabled because of legal cluster filter setting allows it to be selected + }) + } else { + // Occupancy Sensing + cy.get('tbody') + .children() + .contains(data.cluster10) + .should('exist') + .parents('tr') + .within(() => { + cy.get('div[role="checkbox"][aria-label="Client"]') + .should('have.attr', 'aria-checked', 'false') + .click({ force: true }) + .should('have.attr', 'aria-checked', 'true') // when clicking on the server checkbox it should be enabled because of legal cluster filter setting allows it to be selected + }) + cy.get('tbody') + .children() + .contains(data.cluster10) + .should('exist') + .parents('tr') + .within(() => { + cy.get('div[role="checkbox"][aria-label="Server"]') + .should('have.attr', 'aria-checked', 'false') + .click({ force: true }) + .should('have.attr', 'aria-checked', 'false') // Even when clicking on the client checkbox it should not be enabled because of legal cluster filter setting does not allow non Device type clusters to be enabled. + }) + } + + // Basic for Zigbee is legal and should show up + // Identify for Matter is legal and should show up + cy.get('tbody').children().contains(data.cluster11).should('exist') }) } )
diff --git a/cypress/fixtures/data.json b/cypress/fixtures/data.json index c09ce42..e1b52cb 100644 --- a/cypress/fixtures/data.json +++ b/cypress/fixtures/data.json
@@ -7,6 +7,7 @@ "endpoint6": "LO Dimmable Light (0x0101)", "endpoint7": "Billing Unit (0x0203)", "endpoint8": "Billing Unit (0x0203)", + "endpoint9": "SE Range Extender (0x0008)", "cluster1": "General", "cluster2": "Power Configuration", "cluster3": "Basic", @@ -16,6 +17,8 @@ "cluster7": "Identify", "cluster8": "Data Sharing", "cluster9": "General", + "cluster10": "Power Configuration", + "cluster11": "Basic", "attribute1": "ZCL version", "attribute2": "application version", "attribute3": "OTA Upgrade Server ID",
diff --git a/cypress/matterFixtures/data.json b/cypress/matterFixtures/data.json index 4326dd2..a899f86 100644 --- a/cypress/matterFixtures/data.json +++ b/cypress/matterFixtures/data.json
@@ -7,6 +7,7 @@ "endpoint6": "Matter Dimmable Light (0x0101)", "endpoint7": "Matter Control Bridge", "endpoint8": "Matter Color Temperature Light (0x010C)", + "endpoint9": "Matter Dimmable Light (0x0101)", "cluster1": "General", "cluster2": "On/off Switch Configuration", "cluster3": "Basic", @@ -16,6 +17,8 @@ "cluster7": "Identify", "cluster8": "Pulse Width Modulation", "cluster9": "General", + "cluster10": "Occupancy Sensing", + "cluster11": "Identify", "attribute1": "GeneratedCommandList", "attribute2": "IdentifyTime", "attribute3": "ClusterRevision",
diff --git a/docs/api.md b/docs/api.md index 2d8291a..83fa303 100644 --- a/docs/api.md +++ b/docs/api.md
@@ -35,7 +35,7 @@ <dd><p>This module provides queries related to attributes.</p> </dd> <dt><a href="#module_DB API_ zcl database access">DB API: zcl database access</a></dt> -<dd><p>This module provides queries for enums.</p> +<dd><p>This module provides queries for bitmaps.</p> </dd> <dt><a href="#module_DB API_ cluster queries.">DB API: cluster queries.</a></dt> <dd><p>This module provides queries related to cluster.</p> @@ -877,6 +877,7 @@ * [~selectAllBitmaps(db)](#module_DB API_ zcl database access..selectAllBitmaps) ⇒ * [~selectBitmapByName(db, packageIds, name)](#module_DB API_ zcl database access..selectBitmapByName) ⇒ * [~selectBitmapByNameAndClusterId(db, name, clusterId, packageIds)](#module_DB API_ zcl database access..selectBitmapByNameAndClusterId) ⇒ + * [~selectBitmapByNameAndClusterName(db, name, clusterName, packageIds)](#module_DB API_ zcl database access..selectBitmapByNameAndClusterName) ⇒ * [~selectBitmapById(db, id)](#module_DB API_ zcl database access..selectBitmapById) ⇒ * [~selectSessionClusterByCode(db, sessionId, code, mfgCode)](#module_DB API_ zcl database access..selectSessionClusterByCode) ⇒ * [~selectAllSessionClusters(db, sessionId)](#module_DB API_ zcl database access..selectAllSessionClusters) ⇒ @@ -886,8 +887,10 @@ * [~selectStructById(db, id)](#module_DB API_ zcl database access..selectStructById) ⇒ * [~selectStructByName(db, name, packageIds)](#module_DB API_ zcl database access..selectStructByName) ⇒ * [~selectStructByNameAndClusterId(db, name, clusterId, packageIds)](#module_DB API_ zcl database access..selectStructByNameAndClusterId) ⇒ + * [~selectStructByNameAndClusterName(db, name, clusterName, packageIds)](#module_DB API_ zcl database access..selectStructByNameAndClusterName) ⇒ * [~selectStructsWithClusterAssociation(db, packageIds, groupByStructName)](#module_DB API_ zcl database access..selectStructsWithClusterAssociation) ⇒ * [~sqlQueryForDataTypeByNameAndClusterId(typeDiscriminator, clusterId, packageIds)](#module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterId) ⇒ + * [~sqlQueryForDataTypeByNameAndClusterName(typeDiscriminator, name, clusterName, packageIds, options)](#module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterName) ⇒ * [~selectClusterBitmaps(db, packageId, clusterId)](#module_DB API_ zcl database access..selectClusterBitmaps) ⇒ * [~selectAllBitmapFieldsById(db, id)](#module_DB API_ zcl database access..selectAllBitmapFieldsById) ⇒ * [~selectAllBitmapFields(db, packageId)](#module_DB API_ zcl database access..selectAllBitmapFields) ⇒ @@ -1093,6 +1096,22 @@ | clusterId | <code>\*</code> | | packageIds | <code>\*</code> | +<a name="module_DB API_ zcl database access..selectBitmapByNameAndClusterName"></a> + +### DB API: zcl database access~selectBitmapByNameAndClusterName(db, name, clusterName, packageIds) ⇒ +Select a bitmap matched by name and cluster name +Note: Use selectBitmapByNameAndClusterId but this was needed for backwards compatibility. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: bitmap information or undefined + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| name | <code>\*</code> | +| clusterName | <code>\*</code> | +| packageIds | <code>\*</code> | + <a name="module_DB API_ zcl database access..selectBitmapById"></a> ### DB API: zcl database access~selectBitmapById(db, id) ⇒ @@ -1222,6 +1241,22 @@ | clusterId | <code>\*</code> | | packageIds | <code>\*</code> | +<a name="module_DB API_ zcl database access..selectStructByNameAndClusterName"></a> + +### DB API: zcl database access~selectStructByNameAndClusterName(db, name, clusterName, packageIds) ⇒ +Select a struct matched by name and cluster name +Note: Use selectStructByNameAndClusterId but this was needed for backwards compatibility. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: struct information or undefined + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| name | <code>\*</code> | +| clusterName | <code>\*</code> | +| packageIds | <code>\*</code> | + <a name="module_DB API_ zcl database access..selectStructsWithClusterAssociation"></a> ### DB API: zcl database access~selectStructsWithClusterAssociation(db, packageIds, groupByStructName) ⇒ @@ -1252,6 +1287,22 @@ | clusterId | <code>\*</code> | <code></code> | | packageIds | <code>\*</code> | | +<a name="module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterName"></a> + +### DB API: zcl database access~sqlQueryForDataTypeByNameAndClusterName(typeDiscriminator, name, clusterName, packageIds, options) ⇒ +Formulate a sqlite query string for a data type from the given cluster name and package IDs. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: SQLite query string + +| Param | Type | Description | +| --- | --- | --- | +| typeDiscriminator | <code>\*</code> | | +| name | <code>\*</code> | data type name | +| clusterName | <code>\*</code> | | +| packageIds | <code>\*</code> | | +| options | <code>\*</code> | | + <a name="module_DB API_ zcl database access..selectClusterBitmaps"></a> ### DB API: zcl database access~selectClusterBitmaps(db, packageId, clusterId) ⇒ @@ -1681,6 +1732,7 @@ * [~selectAllBitmaps(db)](#module_DB API_ zcl database access..selectAllBitmaps) ⇒ * [~selectBitmapByName(db, packageIds, name)](#module_DB API_ zcl database access..selectBitmapByName) ⇒ * [~selectBitmapByNameAndClusterId(db, name, clusterId, packageIds)](#module_DB API_ zcl database access..selectBitmapByNameAndClusterId) ⇒ + * [~selectBitmapByNameAndClusterName(db, name, clusterName, packageIds)](#module_DB API_ zcl database access..selectBitmapByNameAndClusterName) ⇒ * [~selectBitmapById(db, id)](#module_DB API_ zcl database access..selectBitmapById) ⇒ * [~selectSessionClusterByCode(db, sessionId, code, mfgCode)](#module_DB API_ zcl database access..selectSessionClusterByCode) ⇒ * [~selectAllSessionClusters(db, sessionId)](#module_DB API_ zcl database access..selectAllSessionClusters) ⇒ @@ -1690,8 +1742,10 @@ * [~selectStructById(db, id)](#module_DB API_ zcl database access..selectStructById) ⇒ * [~selectStructByName(db, name, packageIds)](#module_DB API_ zcl database access..selectStructByName) ⇒ * [~selectStructByNameAndClusterId(db, name, clusterId, packageIds)](#module_DB API_ zcl database access..selectStructByNameAndClusterId) ⇒ + * [~selectStructByNameAndClusterName(db, name, clusterName, packageIds)](#module_DB API_ zcl database access..selectStructByNameAndClusterName) ⇒ * [~selectStructsWithClusterAssociation(db, packageIds, groupByStructName)](#module_DB API_ zcl database access..selectStructsWithClusterAssociation) ⇒ * [~sqlQueryForDataTypeByNameAndClusterId(typeDiscriminator, clusterId, packageIds)](#module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterId) ⇒ + * [~sqlQueryForDataTypeByNameAndClusterName(typeDiscriminator, name, clusterName, packageIds, options)](#module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterName) ⇒ * [~selectClusterBitmaps(db, packageId, clusterId)](#module_DB API_ zcl database access..selectClusterBitmaps) ⇒ * [~selectAllBitmapFieldsById(db, id)](#module_DB API_ zcl database access..selectAllBitmapFieldsById) ⇒ * [~selectAllBitmapFields(db, packageId)](#module_DB API_ zcl database access..selectAllBitmapFields) ⇒ @@ -1897,6 +1951,22 @@ | clusterId | <code>\*</code> | | packageIds | <code>\*</code> | +<a name="module_DB API_ zcl database access..selectBitmapByNameAndClusterName"></a> + +### DB API: zcl database access~selectBitmapByNameAndClusterName(db, name, clusterName, packageIds) ⇒ +Select a bitmap matched by name and cluster name +Note: Use selectBitmapByNameAndClusterId but this was needed for backwards compatibility. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: bitmap information or undefined + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| name | <code>\*</code> | +| clusterName | <code>\*</code> | +| packageIds | <code>\*</code> | + <a name="module_DB API_ zcl database access..selectBitmapById"></a> ### DB API: zcl database access~selectBitmapById(db, id) ⇒ @@ -2026,6 +2096,22 @@ | clusterId | <code>\*</code> | | packageIds | <code>\*</code> | +<a name="module_DB API_ zcl database access..selectStructByNameAndClusterName"></a> + +### DB API: zcl database access~selectStructByNameAndClusterName(db, name, clusterName, packageIds) ⇒ +Select a struct matched by name and cluster name +Note: Use selectStructByNameAndClusterId but this was needed for backwards compatibility. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: struct information or undefined + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| name | <code>\*</code> | +| clusterName | <code>\*</code> | +| packageIds | <code>\*</code> | + <a name="module_DB API_ zcl database access..selectStructsWithClusterAssociation"></a> ### DB API: zcl database access~selectStructsWithClusterAssociation(db, packageIds, groupByStructName) ⇒ @@ -2056,6 +2142,22 @@ | clusterId | <code>\*</code> | <code></code> | | packageIds | <code>\*</code> | | +<a name="module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterName"></a> + +### DB API: zcl database access~sqlQueryForDataTypeByNameAndClusterName(typeDiscriminator, name, clusterName, packageIds, options) ⇒ +Formulate a sqlite query string for a data type from the given cluster name and package IDs. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: SQLite query string + +| Param | Type | Description | +| --- | --- | --- | +| typeDiscriminator | <code>\*</code> | | +| name | <code>\*</code> | data type name | +| clusterName | <code>\*</code> | | +| packageIds | <code>\*</code> | | +| options | <code>\*</code> | | + <a name="module_DB API_ zcl database access..selectClusterBitmaps"></a> ### DB API: zcl database access~selectClusterBitmaps(db, packageId, clusterId) ⇒ @@ -2461,7 +2563,7 @@ <a name="module_DB API_ zcl database access"></a> ## DB API: zcl database access -This module provides queries for enums. +This module provides queries for bitmaps. * [DB API: zcl database access](#module_DB API_ zcl database access) @@ -2480,6 +2582,7 @@ * [~selectAllBitmaps(db)](#module_DB API_ zcl database access..selectAllBitmaps) ⇒ * [~selectBitmapByName(db, packageIds, name)](#module_DB API_ zcl database access..selectBitmapByName) ⇒ * [~selectBitmapByNameAndClusterId(db, name, clusterId, packageIds)](#module_DB API_ zcl database access..selectBitmapByNameAndClusterId) ⇒ + * [~selectBitmapByNameAndClusterName(db, name, clusterName, packageIds)](#module_DB API_ zcl database access..selectBitmapByNameAndClusterName) ⇒ * [~selectBitmapById(db, id)](#module_DB API_ zcl database access..selectBitmapById) ⇒ * [~selectSessionClusterByCode(db, sessionId, code, mfgCode)](#module_DB API_ zcl database access..selectSessionClusterByCode) ⇒ * [~selectAllSessionClusters(db, sessionId)](#module_DB API_ zcl database access..selectAllSessionClusters) ⇒ @@ -2489,8 +2592,10 @@ * [~selectStructById(db, id)](#module_DB API_ zcl database access..selectStructById) ⇒ * [~selectStructByName(db, name, packageIds)](#module_DB API_ zcl database access..selectStructByName) ⇒ * [~selectStructByNameAndClusterId(db, name, clusterId, packageIds)](#module_DB API_ zcl database access..selectStructByNameAndClusterId) ⇒ + * [~selectStructByNameAndClusterName(db, name, clusterName, packageIds)](#module_DB API_ zcl database access..selectStructByNameAndClusterName) ⇒ * [~selectStructsWithClusterAssociation(db, packageIds, groupByStructName)](#module_DB API_ zcl database access..selectStructsWithClusterAssociation) ⇒ * [~sqlQueryForDataTypeByNameAndClusterId(typeDiscriminator, clusterId, packageIds)](#module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterId) ⇒ + * [~sqlQueryForDataTypeByNameAndClusterName(typeDiscriminator, name, clusterName, packageIds, options)](#module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterName) ⇒ * [~selectClusterBitmaps(db, packageId, clusterId)](#module_DB API_ zcl database access..selectClusterBitmaps) ⇒ * [~selectAllBitmapFieldsById(db, id)](#module_DB API_ zcl database access..selectAllBitmapFieldsById) ⇒ * [~selectAllBitmapFields(db, packageId)](#module_DB API_ zcl database access..selectAllBitmapFields) ⇒ @@ -2696,6 +2801,22 @@ | clusterId | <code>\*</code> | | packageIds | <code>\*</code> | +<a name="module_DB API_ zcl database access..selectBitmapByNameAndClusterName"></a> + +### DB API: zcl database access~selectBitmapByNameAndClusterName(db, name, clusterName, packageIds) ⇒ +Select a bitmap matched by name and cluster name +Note: Use selectBitmapByNameAndClusterId but this was needed for backwards compatibility. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: bitmap information or undefined + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| name | <code>\*</code> | +| clusterName | <code>\*</code> | +| packageIds | <code>\*</code> | + <a name="module_DB API_ zcl database access..selectBitmapById"></a> ### DB API: zcl database access~selectBitmapById(db, id) ⇒ @@ -2825,6 +2946,22 @@ | clusterId | <code>\*</code> | | packageIds | <code>\*</code> | +<a name="module_DB API_ zcl database access..selectStructByNameAndClusterName"></a> + +### DB API: zcl database access~selectStructByNameAndClusterName(db, name, clusterName, packageIds) ⇒ +Select a struct matched by name and cluster name +Note: Use selectStructByNameAndClusterId but this was needed for backwards compatibility. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: struct information or undefined + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| name | <code>\*</code> | +| clusterName | <code>\*</code> | +| packageIds | <code>\*</code> | + <a name="module_DB API_ zcl database access..selectStructsWithClusterAssociation"></a> ### DB API: zcl database access~selectStructsWithClusterAssociation(db, packageIds, groupByStructName) ⇒ @@ -2855,6 +2992,22 @@ | clusterId | <code>\*</code> | <code></code> | | packageIds | <code>\*</code> | | +<a name="module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterName"></a> + +### DB API: zcl database access~sqlQueryForDataTypeByNameAndClusterName(typeDiscriminator, name, clusterName, packageIds, options) ⇒ +Formulate a sqlite query string for a data type from the given cluster name and package IDs. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: SQLite query string + +| Param | Type | Description | +| --- | --- | --- | +| typeDiscriminator | <code>\*</code> | | +| name | <code>\*</code> | data type name | +| clusterName | <code>\*</code> | | +| packageIds | <code>\*</code> | | +| options | <code>\*</code> | | + <a name="module_DB API_ zcl database access..selectClusterBitmaps"></a> ### DB API: zcl database access~selectClusterBitmaps(db, packageId, clusterId) ⇒ @@ -3287,16 +3440,19 @@ * [~selectAllDeviceTypes(db, packageId)](#module_DB API_ device type database access..selectAllDeviceTypes) ⇒ * [~selectDeviceTypeById(db, id)](#module_DB API_ device type database access..selectDeviceTypeById) ⇒ * [~selectDeviceTypeByCodeAndName(db, packageId, code, name)](#module_DB API_ device type database access..selectDeviceTypeByCodeAndName) ⇒ - * [~selectDeviceTypeByCode(db, packageId, code, name)](#module_DB API_ device type database access..selectDeviceTypeByCode) ⇒ + * [~selectDeviceTypeByCode(db, packageId, code)](#module_DB API_ device type database access..selectDeviceTypeByCode) ⇒ * [~selectDeviceTypeClustersByDeviceTypeRef(db, deviceTypeRef)](#module_DB API_ device type database access..selectDeviceTypeClustersByDeviceTypeRef) ⇒ * [~selectDeviceTypeClusterByDeviceTypeClusterId(db, deviceTypeClusterId)](#module_DB API_ device type database access..selectDeviceTypeClusterByDeviceTypeClusterId) ⇒ * [~selectDeviceTypeAttributesByDeviceTypeRef(db, deviceTypeRef)](#module_DB API_ device type database access..selectDeviceTypeAttributesByDeviceTypeRef) ⇒ * [~selectDeviceTypeCommandsByDeviceTypeRef(db, deviceTypeRef)](#module_DB API_ device type database access..selectDeviceTypeCommandsByDeviceTypeRef) ⇒ - * [~updateClusterReferencesForDeviceTypeClusters(db)](#module_DB API_ device type database access..updateClusterReferencesForDeviceTypeClusters) ⇒ - * [~updateAttributeReferencesForDeviceTypeReferences(db)](#module_DB API_ device type database access..updateAttributeReferencesForDeviceTypeReferences) ⇒ - * [~updateCommandReferencesForDeviceTypeReferences(db)](#module_DB API_ device type database access..updateCommandReferencesForDeviceTypeReferences) ⇒ - * [~updateFeatureReferencesForDeviceTypeReferences(db)](#module_DB API_ device type database access..updateFeatureReferencesForDeviceTypeReferences) ⇒ + * [~updateClusterReferencesForDeviceTypeClusters(db, packageId, sessionPackages)](#module_DB API_ device type database access..updateClusterReferencesForDeviceTypeClusters) ⇒ + * [~updateAttributeReferencesForDeviceTypeReferences(db, packageId, sessionPackages)](#module_DB API_ device type database access..updateAttributeReferencesForDeviceTypeReferences) ⇒ + * [~updateCommandReferencesForDeviceTypeReferences(db, packageId, sessionPackages)](#module_DB API_ device type database access..updateCommandReferencesForDeviceTypeReferences) ⇒ + * [~updateFeatureReferencesForDeviceTypeReferences(db, packageId)](#module_DB API_ device type database access..updateFeatureReferencesForDeviceTypeReferences) ⇒ * [~updateDeviceTypeEntityReferences(db)](#module_DB API_ device type database access..updateDeviceTypeEntityReferences) ⇒ + * [~updateDeviceTypeReferencesForCustomXml(db, packageId, sessionPackages, sessionId)](#module_DB API_ device type database access..updateDeviceTypeReferencesForCustomXml) ⇒ + * [~deleteUnlinkedDeviceTypeClusters(db, packageId)](#module_DB API_ device type database access..deleteUnlinkedDeviceTypeClusters) + * [~warnUnlinkedDeviceTypeClusters(db, packageId, sessionId)](#module_DB API_ device type database access..warnUnlinkedDeviceTypeClusters) * [~selectDeviceTypesWithCompositionByEndpointTypeId(db, endpointTypeId)](#module_DB API_ device type database access..selectDeviceTypesWithCompositionByEndpointTypeId) ⇒ <code>Promise.<Array></code> * [~selectDeviceTypesByEndpointTypeId(db, endpointTypeId)](#module_DB API_ device type database access..selectDeviceTypesByEndpointTypeId) ⇒ * [~selectDeviceTypeFeaturesByEndpointTypeIdAndClusterId(db, endpointTypeId, clusterId)](#module_DB API_ device type database access..selectDeviceTypeFeaturesByEndpointTypeIdAndClusterId) ⇒ @@ -3344,7 +3500,7 @@ <a name="module_DB API_ device type database access..selectDeviceTypeByCode"></a> -### DB API: device type database access~selectDeviceTypeByCode(db, packageId, code, name) ⇒ +### DB API: device type database access~selectDeviceTypeByCode(db, packageId, code) ⇒ Retrieves the device type by the package, code and name. **Kind**: inner method of [<code>DB API: device type database access</code>](#module_DB API_ device type database access) @@ -3355,7 +3511,6 @@ | db | <code>\*</code> | | packageId | <code>\*</code> | | code | <code>\*</code> | -| name | <code>\*</code> | <a name="module_DB API_ device type database access..selectDeviceTypeClustersByDeviceTypeRef"></a> @@ -3411,48 +3566,54 @@ <a name="module_DB API_ device type database access..updateClusterReferencesForDeviceTypeClusters"></a> -### DB API: device type database access~updateClusterReferencesForDeviceTypeClusters(db) ⇒ +### DB API: device type database access~updateClusterReferencesForDeviceTypeClusters(db, packageId, sessionPackages) ⇒ After loading up device type cluster table with the names, -this method links the refererence to actual cluster reference. +this method links the reference to actual cluster reference. **Kind**: inner method of [<code>DB API: device type database access</code>](#module_DB API_ device type database access) **Returns**: promise of completion -| Param | Type | -| --- | --- | -| db | <code>\*</code> | +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| db | <code>\*</code> | | | +| packageId | <code>\*</code> | | | +| sessionPackages | <code>\*</code> | <code></code> | (if processing custom xml file it might need to reference clusters from primary zcl or other custom xml) | <a name="module_DB API_ device type database access..updateAttributeReferencesForDeviceTypeReferences"></a> -### DB API: device type database access~updateAttributeReferencesForDeviceTypeReferences(db) ⇒ +### DB API: device type database access~updateAttributeReferencesForDeviceTypeReferences(db, packageId, sessionPackages) ⇒ After loading up device type attribute table with the names, -this method links the refererence to actual attribute reference. +this method links the references to actual attribute reference. **Kind**: inner method of [<code>DB API: device type database access</code>](#module_DB API_ device type database access) **Returns**: promise of completion -| Param | Type | -| --- | --- | -| db | <code>\*</code> | +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| db | <code>\*</code> | | | +| packageId | <code>\*</code> | | | +| sessionPackages | <code>\*</code> | <code></code> | (if processing custom xml file it might need to reference attributes from primary zcl or other custom xml) | <a name="module_DB API_ device type database access..updateCommandReferencesForDeviceTypeReferences"></a> -### DB API: device type database access~updateCommandReferencesForDeviceTypeReferences(db) ⇒ +### DB API: device type database access~updateCommandReferencesForDeviceTypeReferences(db, packageId, sessionPackages) ⇒ After loading up device type command table with the names, -this method links the refererence to actual command reference. +this method links the reference to actual command reference. **Kind**: inner method of [<code>DB API: device type database access</code>](#module_DB API_ device type database access) **Returns**: promise of completion -| Param | Type | -| --- | --- | -| db | <code>\*</code> | +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| db | <code>\*</code> | | | +| packageId | <code>\*</code> | | | +| sessionPackages | <code>\*</code> | <code></code> | (if processing custom xml file it might need to reference commands from primary zcl or other custom xml) | <a name="module_DB API_ device type database access..updateFeatureReferencesForDeviceTypeReferences"></a> -### DB API: device type database access~updateFeatureReferencesForDeviceTypeReferences(db) ⇒ +### DB API: device type database access~updateFeatureReferencesForDeviceTypeReferences(db, packageId) ⇒ After loading up device type feature table with the names, -this method links the refererence to actual feature reference. +this method links the reference to actual feature reference. **Kind**: inner method of [<code>DB API: device type database access</code>](#module_DB API_ device type database access) **Returns**: promise of completion @@ -3460,6 +3621,7 @@ | Param | Type | | --- | --- | | db | <code>\*</code> | +| packageId | <code>\*</code> | <a name="module_DB API_ device type database access..updateDeviceTypeEntityReferences"></a> @@ -3478,6 +3640,50 @@ | --- | --- | | db | <code>\*</code> | +<a name="module_DB API_ device type database access..updateDeviceTypeReferencesForCustomXml"></a> + +### DB API: device type database access~updateDeviceTypeReferencesForCustomXml(db, packageId, sessionPackages, sessionId) ⇒ +Device types defined in custom xml files might refer to cluster, commands and attributes +from the primary zcl file and other custom xml in the session. + +This method returns the promise of linking the device type entities to the correct +foreign keys in such cases. + +**Kind**: inner method of [<code>DB API: device type database access</code>](#module_DB API_ device type database access) +**Returns**: promise of completed linking + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| packageId | <code>\*</code> | +| sessionPackages | <code>\*</code> | +| sessionId | <code>\*</code> | + +<a name="module_DB API_ device type database access..deleteUnlinkedDeviceTypeClusters"></a> + +### DB API: device type database access~deleteUnlinkedDeviceTypeClusters(db, packageId) +This method deletes all device type clusters that are not linked to any cluster. + +**Kind**: inner method of [<code>DB API: device type database access</code>](#module_DB API_ device type database access) + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| packageId | <code>\*</code> | + +<a name="module_DB API_ device type database access..warnUnlinkedDeviceTypeClusters"></a> + +### DB API: device type database access~warnUnlinkedDeviceTypeClusters(db, packageId, sessionId) +This method adds warnings for all device type clusters that are not linked to any cluster. + +**Kind**: inner method of [<code>DB API: device type database access</code>](#module_DB API_ device type database access) + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| packageId | <code>\*</code> | +| sessionId | <code>\*</code> | + <a name="module_DB API_ device type database access..selectDeviceTypesWithCompositionByEndpointTypeId"></a> ### DB API: device type database access~selectDeviceTypesWithCompositionByEndpointTypeId(db, endpointTypeId) ⇒ <code>Promise.<Array></code> @@ -3546,6 +3752,7 @@ * [~selectEnumById(db, id)](#module_DB API_ zcl database enum access..selectEnumById) ⇒ * [~selectEnumByName(db, name, packageIds)](#module_DB API_ zcl database enum access..selectEnumByName) ⇒ * [~selectEnumByNameAndClusterId(db, name, clusterId, packageIds)](#module_DB API_ zcl database enum access..selectEnumByNameAndClusterId) ⇒ + * [~selectEnumByNameAndClusterName(db, name, clusterName, packageIds)](#module_DB API_ zcl database enum access..selectEnumByNameAndClusterName) ⇒ <a name="module_DB API_ zcl database enum access..selectAllEnums"></a> @@ -3642,6 +3849,22 @@ | clusterId | <code>\*</code> | | packageIds | <code>\*</code> | +<a name="module_DB API_ zcl database enum access..selectEnumByNameAndClusterName"></a> + +### DB API: zcl database enum access~selectEnumByNameAndClusterName(db, name, clusterName, packageIds) ⇒ +Select a enum matched by name and cluster name +Note: Use selectEnumByNameAndClusterId but this was needed for backwards compatibility. + +**Kind**: inner method of [<code>DB API: zcl database enum access</code>](#module_DB API_ zcl database enum access) +**Returns**: enum information or undefined + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| name | <code>\*</code> | +| clusterName | <code>\*</code> | +| packageIds | <code>\*</code> | + <a name="module_DB API_ event queries."></a> ## DB API: event queries. @@ -3754,6 +3977,8 @@ * [~getEndpointCompositionIdByCode(db, deviceType)](#module_DB API_ zcl loading queries..getEndpointCompositionIdByCode) ⇒ <code>Promise.<(number\|null)></code> * [~insertDeviceComposition(db, deviceType, endpointCompositionId)](#module_DB API_ zcl loading queries..insertDeviceComposition) ⇒ <code>Promise</code> * [~insertDeviceTypes(db, packageId, data)](#module_DB API_ zcl loading queries..insertDeviceTypes) ⇒ + * [~reloadDeviceTypes(db, packageId, data, sessionPackages)](#module_DB API_ zcl loading queries..reloadDeviceTypes) + * [~isDeviceTypeClusterInsertRequired(db, deviceTypeId, clusterName, packageId, sessionPackages)](#module_DB API_ zcl loading queries..isDeviceTypeClusterInsertRequired) ⇒ <code>Promise.<boolean></code> * [~insertDeviceTypeFeatures(db, dtClusterRefDataPairs)](#module_DB API_ zcl loading queries..insertDeviceTypeFeatures) * [~insertDeviceTypeAttributes(db, dtClusterRefDataPairs)](#module_DB API_ zcl loading queries..insertDeviceTypeAttributes) * [~insertDeviceTypeCommands(db, dtClusterRefDataPairs)](#module_DB API_ zcl loading queries..insertDeviceTypeCommands) @@ -4158,6 +4383,38 @@ | packageId | <code>\*</code> | | | data | <code>\*</code> | an array of objects that must contain: domain, code, profileId, name, description | +<a name="module_DB API_ zcl loading queries..reloadDeviceTypes"></a> + +### DB API: zcl loading queries~reloadDeviceTypes(db, packageId, data, sessionPackages) +Reloads device types into the database. +This function is responsible for inserting new device type entities as required +when a previously loaded custom xml file (containing a device type) is added to a session. + +**Kind**: inner method of [<code>DB API: zcl loading queries</code>](#module_DB API_ zcl loading queries) + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| packageId | <code>\*</code> | +| data | <code>\*</code> | +| sessionPackages | <code>\*</code> | + +<a name="module_DB API_ zcl loading queries..isDeviceTypeClusterInsertRequired"></a> + +### DB API: zcl loading queries~isDeviceTypeClusterInsertRequired(db, deviceTypeId, clusterName, packageId, sessionPackages) ⇒ <code>Promise.<boolean></code> +Checks if a device type cluster insert is required on device type reload. + +**Kind**: inner method of [<code>DB API: zcl loading queries</code>](#module_DB API_ zcl loading queries) +**Returns**: <code>Promise.<boolean></code> - - Returns true if the insert is required, false otherwise. + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| deviceTypeId | <code>\*</code> | +| clusterName | <code>\*</code> | +| packageId | <code>\*</code> | +| sessionPackages | <code>\*</code> | + <a name="module_DB API_ zcl loading queries..insertDeviceTypeFeatures"></a> ### DB API: zcl loading queries~insertDeviceTypeFeatures(db, dtClusterRefDataPairs) @@ -4563,6 +4820,7 @@ * [~selectAllBitmaps(db)](#module_DB API_ zcl database access..selectAllBitmaps) ⇒ * [~selectBitmapByName(db, packageIds, name)](#module_DB API_ zcl database access..selectBitmapByName) ⇒ * [~selectBitmapByNameAndClusterId(db, name, clusterId, packageIds)](#module_DB API_ zcl database access..selectBitmapByNameAndClusterId) ⇒ + * [~selectBitmapByNameAndClusterName(db, name, clusterName, packageIds)](#module_DB API_ zcl database access..selectBitmapByNameAndClusterName) ⇒ * [~selectBitmapById(db, id)](#module_DB API_ zcl database access..selectBitmapById) ⇒ * [~selectSessionClusterByCode(db, sessionId, code, mfgCode)](#module_DB API_ zcl database access..selectSessionClusterByCode) ⇒ * [~selectAllSessionClusters(db, sessionId)](#module_DB API_ zcl database access..selectAllSessionClusters) ⇒ @@ -4572,8 +4830,10 @@ * [~selectStructById(db, id)](#module_DB API_ zcl database access..selectStructById) ⇒ * [~selectStructByName(db, name, packageIds)](#module_DB API_ zcl database access..selectStructByName) ⇒ * [~selectStructByNameAndClusterId(db, name, clusterId, packageIds)](#module_DB API_ zcl database access..selectStructByNameAndClusterId) ⇒ + * [~selectStructByNameAndClusterName(db, name, clusterName, packageIds)](#module_DB API_ zcl database access..selectStructByNameAndClusterName) ⇒ * [~selectStructsWithClusterAssociation(db, packageIds, groupByStructName)](#module_DB API_ zcl database access..selectStructsWithClusterAssociation) ⇒ * [~sqlQueryForDataTypeByNameAndClusterId(typeDiscriminator, clusterId, packageIds)](#module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterId) ⇒ + * [~sqlQueryForDataTypeByNameAndClusterName(typeDiscriminator, name, clusterName, packageIds, options)](#module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterName) ⇒ * [~selectClusterBitmaps(db, packageId, clusterId)](#module_DB API_ zcl database access..selectClusterBitmaps) ⇒ * [~selectAllBitmapFieldsById(db, id)](#module_DB API_ zcl database access..selectAllBitmapFieldsById) ⇒ * [~selectAllBitmapFields(db, packageId)](#module_DB API_ zcl database access..selectAllBitmapFields) ⇒ @@ -4779,6 +5039,22 @@ | clusterId | <code>\*</code> | | packageIds | <code>\*</code> | +<a name="module_DB API_ zcl database access..selectBitmapByNameAndClusterName"></a> + +### DB API: zcl database access~selectBitmapByNameAndClusterName(db, name, clusterName, packageIds) ⇒ +Select a bitmap matched by name and cluster name +Note: Use selectBitmapByNameAndClusterId but this was needed for backwards compatibility. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: bitmap information or undefined + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| name | <code>\*</code> | +| clusterName | <code>\*</code> | +| packageIds | <code>\*</code> | + <a name="module_DB API_ zcl database access..selectBitmapById"></a> ### DB API: zcl database access~selectBitmapById(db, id) ⇒ @@ -4908,6 +5184,22 @@ | clusterId | <code>\*</code> | | packageIds | <code>\*</code> | +<a name="module_DB API_ zcl database access..selectStructByNameAndClusterName"></a> + +### DB API: zcl database access~selectStructByNameAndClusterName(db, name, clusterName, packageIds) ⇒ +Select a struct matched by name and cluster name +Note: Use selectStructByNameAndClusterId but this was needed for backwards compatibility. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: struct information or undefined + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| name | <code>\*</code> | +| clusterName | <code>\*</code> | +| packageIds | <code>\*</code> | + <a name="module_DB API_ zcl database access..selectStructsWithClusterAssociation"></a> ### DB API: zcl database access~selectStructsWithClusterAssociation(db, packageIds, groupByStructName) ⇒ @@ -4938,6 +5230,22 @@ | clusterId | <code>\*</code> | <code></code> | | packageIds | <code>\*</code> | | +<a name="module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterName"></a> + +### DB API: zcl database access~sqlQueryForDataTypeByNameAndClusterName(typeDiscriminator, name, clusterName, packageIds, options) ⇒ +Formulate a sqlite query string for a data type from the given cluster name and package IDs. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: SQLite query string + +| Param | Type | Description | +| --- | --- | --- | +| typeDiscriminator | <code>\*</code> | | +| name | <code>\*</code> | data type name | +| clusterName | <code>\*</code> | | +| packageIds | <code>\*</code> | | +| options | <code>\*</code> | | + <a name="module_DB API_ zcl database access..selectClusterBitmaps"></a> ### DB API: zcl database access~selectClusterBitmaps(db, packageId, clusterId) ⇒ @@ -5408,6 +5716,7 @@ * [~selectAllBitmaps(db)](#module_DB API_ zcl database access..selectAllBitmaps) ⇒ * [~selectBitmapByName(db, packageIds, name)](#module_DB API_ zcl database access..selectBitmapByName) ⇒ * [~selectBitmapByNameAndClusterId(db, name, clusterId, packageIds)](#module_DB API_ zcl database access..selectBitmapByNameAndClusterId) ⇒ + * [~selectBitmapByNameAndClusterName(db, name, clusterName, packageIds)](#module_DB API_ zcl database access..selectBitmapByNameAndClusterName) ⇒ * [~selectBitmapById(db, id)](#module_DB API_ zcl database access..selectBitmapById) ⇒ * [~selectSessionClusterByCode(db, sessionId, code, mfgCode)](#module_DB API_ zcl database access..selectSessionClusterByCode) ⇒ * [~selectAllSessionClusters(db, sessionId)](#module_DB API_ zcl database access..selectAllSessionClusters) ⇒ @@ -5417,8 +5726,10 @@ * [~selectStructById(db, id)](#module_DB API_ zcl database access..selectStructById) ⇒ * [~selectStructByName(db, name, packageIds)](#module_DB API_ zcl database access..selectStructByName) ⇒ * [~selectStructByNameAndClusterId(db, name, clusterId, packageIds)](#module_DB API_ zcl database access..selectStructByNameAndClusterId) ⇒ + * [~selectStructByNameAndClusterName(db, name, clusterName, packageIds)](#module_DB API_ zcl database access..selectStructByNameAndClusterName) ⇒ * [~selectStructsWithClusterAssociation(db, packageIds, groupByStructName)](#module_DB API_ zcl database access..selectStructsWithClusterAssociation) ⇒ * [~sqlQueryForDataTypeByNameAndClusterId(typeDiscriminator, clusterId, packageIds)](#module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterId) ⇒ + * [~sqlQueryForDataTypeByNameAndClusterName(typeDiscriminator, name, clusterName, packageIds, options)](#module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterName) ⇒ * [~selectClusterBitmaps(db, packageId, clusterId)](#module_DB API_ zcl database access..selectClusterBitmaps) ⇒ * [~selectAllBitmapFieldsById(db, id)](#module_DB API_ zcl database access..selectAllBitmapFieldsById) ⇒ * [~selectAllBitmapFields(db, packageId)](#module_DB API_ zcl database access..selectAllBitmapFields) ⇒ @@ -5624,6 +5935,22 @@ | clusterId | <code>\*</code> | | packageIds | <code>\*</code> | +<a name="module_DB API_ zcl database access..selectBitmapByNameAndClusterName"></a> + +### DB API: zcl database access~selectBitmapByNameAndClusterName(db, name, clusterName, packageIds) ⇒ +Select a bitmap matched by name and cluster name +Note: Use selectBitmapByNameAndClusterId but this was needed for backwards compatibility. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: bitmap information or undefined + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| name | <code>\*</code> | +| clusterName | <code>\*</code> | +| packageIds | <code>\*</code> | + <a name="module_DB API_ zcl database access..selectBitmapById"></a> ### DB API: zcl database access~selectBitmapById(db, id) ⇒ @@ -5753,6 +6080,22 @@ | clusterId | <code>\*</code> | | packageIds | <code>\*</code> | +<a name="module_DB API_ zcl database access..selectStructByNameAndClusterName"></a> + +### DB API: zcl database access~selectStructByNameAndClusterName(db, name, clusterName, packageIds) ⇒ +Select a struct matched by name and cluster name +Note: Use selectStructByNameAndClusterId but this was needed for backwards compatibility. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: struct information or undefined + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| name | <code>\*</code> | +| clusterName | <code>\*</code> | +| packageIds | <code>\*</code> | + <a name="module_DB API_ zcl database access..selectStructsWithClusterAssociation"></a> ### DB API: zcl database access~selectStructsWithClusterAssociation(db, packageIds, groupByStructName) ⇒ @@ -5783,6 +6126,22 @@ | clusterId | <code>\*</code> | <code></code> | | packageIds | <code>\*</code> | | +<a name="module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterName"></a> + +### DB API: zcl database access~sqlQueryForDataTypeByNameAndClusterName(typeDiscriminator, name, clusterName, packageIds, options) ⇒ +Formulate a sqlite query string for a data type from the given cluster name and package IDs. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: SQLite query string + +| Param | Type | Description | +| --- | --- | --- | +| typeDiscriminator | <code>\*</code> | | +| name | <code>\*</code> | data type name | +| clusterName | <code>\*</code> | | +| packageIds | <code>\*</code> | | +| options | <code>\*</code> | | + <a name="module_DB API_ zcl database access..selectClusterBitmaps"></a> ### DB API: zcl database access~selectClusterBitmaps(db, packageId, clusterId) ⇒ @@ -6203,6 +6562,7 @@ * [~selectAllBitmaps(db)](#module_DB API_ zcl database access..selectAllBitmaps) ⇒ * [~selectBitmapByName(db, packageIds, name)](#module_DB API_ zcl database access..selectBitmapByName) ⇒ * [~selectBitmapByNameAndClusterId(db, name, clusterId, packageIds)](#module_DB API_ zcl database access..selectBitmapByNameAndClusterId) ⇒ + * [~selectBitmapByNameAndClusterName(db, name, clusterName, packageIds)](#module_DB API_ zcl database access..selectBitmapByNameAndClusterName) ⇒ * [~selectBitmapById(db, id)](#module_DB API_ zcl database access..selectBitmapById) ⇒ * [~selectSessionClusterByCode(db, sessionId, code, mfgCode)](#module_DB API_ zcl database access..selectSessionClusterByCode) ⇒ * [~selectAllSessionClusters(db, sessionId)](#module_DB API_ zcl database access..selectAllSessionClusters) ⇒ @@ -6212,8 +6572,10 @@ * [~selectStructById(db, id)](#module_DB API_ zcl database access..selectStructById) ⇒ * [~selectStructByName(db, name, packageIds)](#module_DB API_ zcl database access..selectStructByName) ⇒ * [~selectStructByNameAndClusterId(db, name, clusterId, packageIds)](#module_DB API_ zcl database access..selectStructByNameAndClusterId) ⇒ + * [~selectStructByNameAndClusterName(db, name, clusterName, packageIds)](#module_DB API_ zcl database access..selectStructByNameAndClusterName) ⇒ * [~selectStructsWithClusterAssociation(db, packageIds, groupByStructName)](#module_DB API_ zcl database access..selectStructsWithClusterAssociation) ⇒ * [~sqlQueryForDataTypeByNameAndClusterId(typeDiscriminator, clusterId, packageIds)](#module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterId) ⇒ + * [~sqlQueryForDataTypeByNameAndClusterName(typeDiscriminator, name, clusterName, packageIds, options)](#module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterName) ⇒ * [~selectClusterBitmaps(db, packageId, clusterId)](#module_DB API_ zcl database access..selectClusterBitmaps) ⇒ * [~selectAllBitmapFieldsById(db, id)](#module_DB API_ zcl database access..selectAllBitmapFieldsById) ⇒ * [~selectAllBitmapFields(db, packageId)](#module_DB API_ zcl database access..selectAllBitmapFields) ⇒ @@ -6419,6 +6781,22 @@ | clusterId | <code>\*</code> | | packageIds | <code>\*</code> | +<a name="module_DB API_ zcl database access..selectBitmapByNameAndClusterName"></a> + +### DB API: zcl database access~selectBitmapByNameAndClusterName(db, name, clusterName, packageIds) ⇒ +Select a bitmap matched by name and cluster name +Note: Use selectBitmapByNameAndClusterId but this was needed for backwards compatibility. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: bitmap information or undefined + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| name | <code>\*</code> | +| clusterName | <code>\*</code> | +| packageIds | <code>\*</code> | + <a name="module_DB API_ zcl database access..selectBitmapById"></a> ### DB API: zcl database access~selectBitmapById(db, id) ⇒ @@ -6548,6 +6926,22 @@ | clusterId | <code>\*</code> | | packageIds | <code>\*</code> | +<a name="module_DB API_ zcl database access..selectStructByNameAndClusterName"></a> + +### DB API: zcl database access~selectStructByNameAndClusterName(db, name, clusterName, packageIds) ⇒ +Select a struct matched by name and cluster name +Note: Use selectStructByNameAndClusterId but this was needed for backwards compatibility. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: struct information or undefined + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| name | <code>\*</code> | +| clusterName | <code>\*</code> | +| packageIds | <code>\*</code> | + <a name="module_DB API_ zcl database access..selectStructsWithClusterAssociation"></a> ### DB API: zcl database access~selectStructsWithClusterAssociation(db, packageIds, groupByStructName) ⇒ @@ -6578,6 +6972,22 @@ | clusterId | <code>\*</code> | <code></code> | | packageIds | <code>\*</code> | | +<a name="module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterName"></a> + +### DB API: zcl database access~sqlQueryForDataTypeByNameAndClusterName(typeDiscriminator, name, clusterName, packageIds, options) ⇒ +Formulate a sqlite query string for a data type from the given cluster name and package IDs. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: SQLite query string + +| Param | Type | Description | +| --- | --- | --- | +| typeDiscriminator | <code>\*</code> | | +| name | <code>\*</code> | data type name | +| clusterName | <code>\*</code> | | +| packageIds | <code>\*</code> | | +| options | <code>\*</code> | | + <a name="module_DB API_ zcl database access..selectClusterBitmaps"></a> ### DB API: zcl database access~selectClusterBitmaps(db, packageId, clusterId) ⇒ @@ -6997,6 +7407,7 @@ * [~selectAllBitmaps(db)](#module_DB API_ zcl database access..selectAllBitmaps) ⇒ * [~selectBitmapByName(db, packageIds, name)](#module_DB API_ zcl database access..selectBitmapByName) ⇒ * [~selectBitmapByNameAndClusterId(db, name, clusterId, packageIds)](#module_DB API_ zcl database access..selectBitmapByNameAndClusterId) ⇒ + * [~selectBitmapByNameAndClusterName(db, name, clusterName, packageIds)](#module_DB API_ zcl database access..selectBitmapByNameAndClusterName) ⇒ * [~selectBitmapById(db, id)](#module_DB API_ zcl database access..selectBitmapById) ⇒ * [~selectSessionClusterByCode(db, sessionId, code, mfgCode)](#module_DB API_ zcl database access..selectSessionClusterByCode) ⇒ * [~selectAllSessionClusters(db, sessionId)](#module_DB API_ zcl database access..selectAllSessionClusters) ⇒ @@ -7006,8 +7417,10 @@ * [~selectStructById(db, id)](#module_DB API_ zcl database access..selectStructById) ⇒ * [~selectStructByName(db, name, packageIds)](#module_DB API_ zcl database access..selectStructByName) ⇒ * [~selectStructByNameAndClusterId(db, name, clusterId, packageIds)](#module_DB API_ zcl database access..selectStructByNameAndClusterId) ⇒ + * [~selectStructByNameAndClusterName(db, name, clusterName, packageIds)](#module_DB API_ zcl database access..selectStructByNameAndClusterName) ⇒ * [~selectStructsWithClusterAssociation(db, packageIds, groupByStructName)](#module_DB API_ zcl database access..selectStructsWithClusterAssociation) ⇒ * [~sqlQueryForDataTypeByNameAndClusterId(typeDiscriminator, clusterId, packageIds)](#module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterId) ⇒ + * [~sqlQueryForDataTypeByNameAndClusterName(typeDiscriminator, name, clusterName, packageIds, options)](#module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterName) ⇒ * [~selectClusterBitmaps(db, packageId, clusterId)](#module_DB API_ zcl database access..selectClusterBitmaps) ⇒ * [~selectAllBitmapFieldsById(db, id)](#module_DB API_ zcl database access..selectAllBitmapFieldsById) ⇒ * [~selectAllBitmapFields(db, packageId)](#module_DB API_ zcl database access..selectAllBitmapFields) ⇒ @@ -7213,6 +7626,22 @@ | clusterId | <code>\*</code> | | packageIds | <code>\*</code> | +<a name="module_DB API_ zcl database access..selectBitmapByNameAndClusterName"></a> + +### DB API: zcl database access~selectBitmapByNameAndClusterName(db, name, clusterName, packageIds) ⇒ +Select a bitmap matched by name and cluster name +Note: Use selectBitmapByNameAndClusterId but this was needed for backwards compatibility. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: bitmap information or undefined + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| name | <code>\*</code> | +| clusterName | <code>\*</code> | +| packageIds | <code>\*</code> | + <a name="module_DB API_ zcl database access..selectBitmapById"></a> ### DB API: zcl database access~selectBitmapById(db, id) ⇒ @@ -7342,6 +7771,22 @@ | clusterId | <code>\*</code> | | packageIds | <code>\*</code> | +<a name="module_DB API_ zcl database access..selectStructByNameAndClusterName"></a> + +### DB API: zcl database access~selectStructByNameAndClusterName(db, name, clusterName, packageIds) ⇒ +Select a struct matched by name and cluster name +Note: Use selectStructByNameAndClusterId but this was needed for backwards compatibility. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: struct information or undefined + +| Param | Type | +| --- | --- | +| db | <code>\*</code> | +| name | <code>\*</code> | +| clusterName | <code>\*</code> | +| packageIds | <code>\*</code> | + <a name="module_DB API_ zcl database access..selectStructsWithClusterAssociation"></a> ### DB API: zcl database access~selectStructsWithClusterAssociation(db, packageIds, groupByStructName) ⇒ @@ -7372,6 +7817,22 @@ | clusterId | <code>\*</code> | <code></code> | | packageIds | <code>\*</code> | | +<a name="module_DB API_ zcl database access..sqlQueryForDataTypeByNameAndClusterName"></a> + +### DB API: zcl database access~sqlQueryForDataTypeByNameAndClusterName(typeDiscriminator, name, clusterName, packageIds, options) ⇒ +Formulate a sqlite query string for a data type from the given cluster name and package IDs. + +**Kind**: inner method of [<code>DB API: zcl database access</code>](#module_DB API_ zcl database access) +**Returns**: SQLite query string + +| Param | Type | Description | +| --- | --- | --- | +| typeDiscriminator | <code>\*</code> | | +| name | <code>\*</code> | data type name | +| clusterName | <code>\*</code> | | +| packageIds | <code>\*</code> | | +| options | <code>\*</code> | | + <a name="module_DB API_ zcl database access..selectClusterBitmaps"></a> ### DB API: zcl database access~selectClusterBitmaps(db, packageId, clusterId) ⇒ @@ -7774,6 +8235,7 @@ ## JS API: generator logic * [JS API: generator logic](#module_JS API_ generator logic) + * [~findAndReadJsonFiles(obj, basePath)](#module_JS API_ generator logic..findAndReadJsonFiles) ⇒ <code>Promise.<string></code> * [~loadGenTemplateFromFile(templatePath)](#module_JS API_ generator logic..loadGenTemplateFromFile) ⇒ * [~recordPackageIfNonexistent(db, packagePath, parentId, packageType, version, category, description)](#module_JS API_ generator logic..recordPackageIfNonexistent) ⇒ * [~loadTemplateOptionsFromJsonFile(db, packageId, category, externalPath)](#module_JS API_ generator logic..loadTemplateOptionsFromJsonFile) ⇒ @@ -7821,6 +8283,19 @@ * [~templatePromise(global, promise)](#module_JS API_ generator logic..templatePromise) * [~deprecatedHelper(fn, explanation)](#module_JS API_ generator logic..deprecatedHelper) ⇒ +<a name="module_JS API_ generator logic..findAndReadJsonFiles"></a> + +### JS API: generator logic~findAndReadJsonFiles(obj, basePath) ⇒ <code>Promise.<string></code> +Finds and reads JSON files referenced in a nested object. + +**Kind**: inner method of [<code>JS API: generator logic</code>](#module_JS API_ generator logic) +**Returns**: <code>Promise.<string></code> - - A promise that resolves to the concatenated content of all JSON files. + +| Param | Type | Description | +| --- | --- | --- | +| obj | <code>Object</code> | The object to search for JSON file references. | +| basePath | <code>string</code> | The base directory to resolve relative paths. | + <a name="module_JS API_ generator logic..loadGenTemplateFromFile"></a> ### JS API: generator logic~loadGenTemplateFromFile(templatePath) ⇒ @@ -13112,6 +13587,7 @@ ## JS API: generator logic * [JS API: generator logic](#module_JS API_ generator logic) + * [~findAndReadJsonFiles(obj, basePath)](#module_JS API_ generator logic..findAndReadJsonFiles) ⇒ <code>Promise.<string></code> * [~loadGenTemplateFromFile(templatePath)](#module_JS API_ generator logic..loadGenTemplateFromFile) ⇒ * [~recordPackageIfNonexistent(db, packagePath, parentId, packageType, version, category, description)](#module_JS API_ generator logic..recordPackageIfNonexistent) ⇒ * [~loadTemplateOptionsFromJsonFile(db, packageId, category, externalPath)](#module_JS API_ generator logic..loadTemplateOptionsFromJsonFile) ⇒ @@ -13159,6 +13635,19 @@ * [~templatePromise(global, promise)](#module_JS API_ generator logic..templatePromise) * [~deprecatedHelper(fn, explanation)](#module_JS API_ generator logic..deprecatedHelper) ⇒ +<a name="module_JS API_ generator logic..findAndReadJsonFiles"></a> + +### JS API: generator logic~findAndReadJsonFiles(obj, basePath) ⇒ <code>Promise.<string></code> +Finds and reads JSON files referenced in a nested object. + +**Kind**: inner method of [<code>JS API: generator logic</code>](#module_JS API_ generator logic) +**Returns**: <code>Promise.<string></code> - - A promise that resolves to the concatenated content of all JSON files. + +| Param | Type | Description | +| --- | --- | --- | +| obj | <code>Object</code> | The object to search for JSON file references. | +| basePath | <code>string</code> | The base directory to resolve relative paths. | + <a name="module_JS API_ generator logic..loadGenTemplateFromFile"></a> ### JS API: generator logic~loadGenTemplateFromFile(templatePath) ⇒ @@ -13774,6 +14263,7 @@ ## JS API: generator logic * [JS API: generator logic](#module_JS API_ generator logic) + * [~findAndReadJsonFiles(obj, basePath)](#module_JS API_ generator logic..findAndReadJsonFiles) ⇒ <code>Promise.<string></code> * [~loadGenTemplateFromFile(templatePath)](#module_JS API_ generator logic..loadGenTemplateFromFile) ⇒ * [~recordPackageIfNonexistent(db, packagePath, parentId, packageType, version, category, description)](#module_JS API_ generator logic..recordPackageIfNonexistent) ⇒ * [~loadTemplateOptionsFromJsonFile(db, packageId, category, externalPath)](#module_JS API_ generator logic..loadTemplateOptionsFromJsonFile) ⇒ @@ -13821,6 +14311,19 @@ * [~templatePromise(global, promise)](#module_JS API_ generator logic..templatePromise) * [~deprecatedHelper(fn, explanation)](#module_JS API_ generator logic..deprecatedHelper) ⇒ +<a name="module_JS API_ generator logic..findAndReadJsonFiles"></a> + +### JS API: generator logic~findAndReadJsonFiles(obj, basePath) ⇒ <code>Promise.<string></code> +Finds and reads JSON files referenced in a nested object. + +**Kind**: inner method of [<code>JS API: generator logic</code>](#module_JS API_ generator logic) +**Returns**: <code>Promise.<string></code> - - A promise that resolves to the concatenated content of all JSON files. + +| Param | Type | Description | +| --- | --- | --- | +| obj | <code>Object</code> | The object to search for JSON file references. | +| basePath | <code>string</code> | The base directory to resolve relative paths. | + <a name="module_JS API_ generator logic..loadGenTemplateFromFile"></a> ### JS API: generator logic~loadGenTemplateFromFile(templatePath) ⇒ @@ -18166,7 +18669,7 @@ the string into tokens. Differs from `toCamelCase` by different handling of "." inside names, -so that results are always usable as a code-compatibe name (e.g. +so that results are always usable as a code-compatible name (e.g. "Foo 2.5" becomes "Foo25" rather than "Foo2.5"). **Kind**: inner method of [<code>JS API: string utilities</code>](#module_JS API_ string utilities) @@ -18814,6 +19317,7 @@ * [~commandComparator(a, b)](#module_REST API_ various zcl utilities..commandComparator) ⇒ * [~eventComparator(a, b)](#module_REST API_ various zcl utilities..eventComparator) ⇒ * [~findStructByName(structs, name)](#module_REST API_ various zcl utilities..findStructByName) ⇒ + * [~sortStructsByDependencyHelper()](#module_REST API_ various zcl utilities..sortStructsByDependencyHelper) * [~sortStructsByDependency(structs)](#module_REST API_ various zcl utilities..sortStructsByDependency) ⇒ * [~calculateBytes(res, options, db, packageIds, isStructType)](#module_REST API_ various zcl utilities..calculateBytes) * [~optionsHashOrDefault(options, optionsKey, defaultValue)](#module_REST API_ various zcl utilities..optionsHashOrDefault) @@ -18897,6 +19401,12 @@ | structs | <code>\*</code> | | name | <code>\*</code> | +<a name="module_REST API_ various zcl utilities..sortStructsByDependencyHelper"></a> + +### REST API: various zcl utilities~sortStructsByDependencyHelper() +Non-exported helper for sortStructsByDependency. + +**Kind**: inner method of [<code>REST API: various zcl utilities</code>](#module_REST API_ various zcl utilities) <a name="module_REST API_ various zcl utilities..sortStructsByDependency"></a> ### REST API: various zcl utilities~sortStructsByDependency(structs) ⇒ @@ -20289,6 +20799,7 @@ * [~processStructItems(db, filePath, packageIds, data)](#module_Loader API_ Loader APIs..processStructItems) ⇒ * [~prepareDeviceType(deviceType)](#module_Loader API_ Loader APIs..prepareDeviceType) ⇒ <code>Object</code> * [~processDeviceTypes(db, filePath, packageId, data, context)](#module_Loader API_ Loader APIs..processDeviceTypes) ⇒ <code>Promise</code> + * [~processReloadDeviceTypes()](#module_Loader API_ Loader APIs..processReloadDeviceTypes) ⇒ <code>Promise</code> * [~processDataTypes(db, filePath, packageId, knownPackages, toplevel)](#module_Loader API_ Loader APIs..processDataTypes) ⇒ * [~processAtomicTypes(db, filePath, packageId, knownPackages, toplevel)](#module_Loader API_ Loader APIs..processAtomicTypes) ⇒ * [~processNonAtomicTypes(db, filePath, packageId, knownPackages, toplevel, featureClusters)](#module_Loader API_ Loader APIs..processNonAtomicTypes) ⇒ @@ -21669,6 +22180,14 @@ | data | <code>Array</code> | The array of device types to be processed. | | context | <code>\*</code> | Additional context that might be required for processing. | +<a name="module_Loader API_ Loader APIs..processReloadDeviceTypes"></a> + +### Loader API: Loader APIs~processReloadDeviceTypes() ⇒ <code>Promise</code> +Processes and reloads device type entities in the database. +This function is called when a custom xml with device types is reloaded. + +**Kind**: inner method of [<code>Loader API: Loader APIs</code>](#module_Loader API_ Loader APIs) +**Returns**: <code>Promise</code> - A promise that resolves after all device types have been reloaded. <a name="module_Loader API_ Loader APIs..processDataTypes"></a> ### Loader API: Loader APIs~processDataTypes(db, filePath, packageId, knownPackages, toplevel) ⇒ @@ -22141,6 +22660,7 @@ * [~processStructItems(db, filePath, packageIds, data)](#module_Loader API_ Loader APIs..processStructItems) ⇒ * [~prepareDeviceType(deviceType)](#module_Loader API_ Loader APIs..prepareDeviceType) ⇒ <code>Object</code> * [~processDeviceTypes(db, filePath, packageId, data, context)](#module_Loader API_ Loader APIs..processDeviceTypes) ⇒ <code>Promise</code> + * [~processReloadDeviceTypes()](#module_Loader API_ Loader APIs..processReloadDeviceTypes) ⇒ <code>Promise</code> * [~processDataTypes(db, filePath, packageId, knownPackages, toplevel)](#module_Loader API_ Loader APIs..processDataTypes) ⇒ * [~processAtomicTypes(db, filePath, packageId, knownPackages, toplevel)](#module_Loader API_ Loader APIs..processAtomicTypes) ⇒ * [~processNonAtomicTypes(db, filePath, packageId, knownPackages, toplevel, featureClusters)](#module_Loader API_ Loader APIs..processNonAtomicTypes) ⇒ @@ -23521,6 +24041,14 @@ | data | <code>Array</code> | The array of device types to be processed. | | context | <code>\*</code> | Additional context that might be required for processing. | +<a name="module_Loader API_ Loader APIs..processReloadDeviceTypes"></a> + +### Loader API: Loader APIs~processReloadDeviceTypes() ⇒ <code>Promise</code> +Processes and reloads device type entities in the database. +This function is called when a custom xml with device types is reloaded. + +**Kind**: inner method of [<code>Loader API: Loader APIs</code>](#module_Loader API_ Loader APIs) +**Returns**: <code>Promise</code> - A promise that resolves after all device types have been reloaded. <a name="module_Loader API_ Loader APIs..processDataTypes"></a> ### Loader API: Loader APIs~processDataTypes(db, filePath, packageId, knownPackages, toplevel) ⇒ @@ -23993,6 +24521,7 @@ * [~processStructItems(db, filePath, packageIds, data)](#module_Loader API_ Loader APIs..processStructItems) ⇒ * [~prepareDeviceType(deviceType)](#module_Loader API_ Loader APIs..prepareDeviceType) ⇒ <code>Object</code> * [~processDeviceTypes(db, filePath, packageId, data, context)](#module_Loader API_ Loader APIs..processDeviceTypes) ⇒ <code>Promise</code> + * [~processReloadDeviceTypes()](#module_Loader API_ Loader APIs..processReloadDeviceTypes) ⇒ <code>Promise</code> * [~processDataTypes(db, filePath, packageId, knownPackages, toplevel)](#module_Loader API_ Loader APIs..processDataTypes) ⇒ * [~processAtomicTypes(db, filePath, packageId, knownPackages, toplevel)](#module_Loader API_ Loader APIs..processAtomicTypes) ⇒ * [~processNonAtomicTypes(db, filePath, packageId, knownPackages, toplevel, featureClusters)](#module_Loader API_ Loader APIs..processNonAtomicTypes) ⇒ @@ -25373,6 +25902,14 @@ | data | <code>Array</code> | The array of device types to be processed. | | context | <code>\*</code> | Additional context that might be required for processing. | +<a name="module_Loader API_ Loader APIs..processReloadDeviceTypes"></a> + +### Loader API: Loader APIs~processReloadDeviceTypes() ⇒ <code>Promise</code> +Processes and reloads device type entities in the database. +This function is called when a custom xml with device types is reloaded. + +**Kind**: inner method of [<code>Loader API: Loader APIs</code>](#module_Loader API_ Loader APIs) +**Returns**: <code>Promise</code> - A promise that resolves after all device types have been reloaded. <a name="module_Loader API_ Loader APIs..processDataTypes"></a> ### Loader API: Loader APIs~processDataTypes(db, filePath, packageId, knownPackages, toplevel) ⇒ @@ -25845,6 +26382,7 @@ * [~processStructItems(db, filePath, packageIds, data)](#module_Loader API_ Loader APIs..processStructItems) ⇒ * [~prepareDeviceType(deviceType)](#module_Loader API_ Loader APIs..prepareDeviceType) ⇒ <code>Object</code> * [~processDeviceTypes(db, filePath, packageId, data, context)](#module_Loader API_ Loader APIs..processDeviceTypes) ⇒ <code>Promise</code> + * [~processReloadDeviceTypes()](#module_Loader API_ Loader APIs..processReloadDeviceTypes) ⇒ <code>Promise</code> * [~processDataTypes(db, filePath, packageId, knownPackages, toplevel)](#module_Loader API_ Loader APIs..processDataTypes) ⇒ * [~processAtomicTypes(db, filePath, packageId, knownPackages, toplevel)](#module_Loader API_ Loader APIs..processAtomicTypes) ⇒ * [~processNonAtomicTypes(db, filePath, packageId, knownPackages, toplevel, featureClusters)](#module_Loader API_ Loader APIs..processNonAtomicTypes) ⇒ @@ -27225,6 +27763,14 @@ | data | <code>Array</code> | The array of device types to be processed. | | context | <code>\*</code> | Additional context that might be required for processing. | +<a name="module_Loader API_ Loader APIs..processReloadDeviceTypes"></a> + +### Loader API: Loader APIs~processReloadDeviceTypes() ⇒ <code>Promise</code> +Processes and reloads device type entities in the database. +This function is called when a custom xml with device types is reloaded. + +**Kind**: inner method of [<code>Loader API: Loader APIs</code>](#module_Loader API_ Loader APIs) +**Returns**: <code>Promise</code> - A promise that resolves after all device types have been reloaded. <a name="module_Loader API_ Loader APIs..processDataTypes"></a> ### Loader API: Loader APIs~processDataTypes(db, filePath, packageId, knownPackages, toplevel) ⇒
diff --git a/src-electron/db/db-mapping.js b/src-electron/db/db-mapping.js index b32f72d..2bc1a0c 100644 --- a/src-electron/db/db-mapping.js +++ b/src-electron/db/db-mapping.js
@@ -149,7 +149,10 @@ clusterCode2: x.C2_CODE, clusterMfgCode2: x.C2_MANUFACTURER_CODE, clusterName1: x.C1_NAME, - clusterName2: x.C2_NAME + clusterName2: x.C2_NAME, + clusterMappingIndex: x.CLUSTER_MAPPING_INDEX, + totalClusterMappedAttributes: x.TOTAL_CLUSTER_MAPPED_ATTRIBUTES, + isLastPartition: dbApi.fromDbBool(x.IS_LAST_CLUSTER_PARTITION) } }, @@ -159,6 +162,7 @@ fieldIdentifier: x.FIELD_IDENTIFIER, name: x.NAME, type: x.TYPE, + defaultValue: x.DEFAULT_VALUE, isArray: dbApi.fromDbBool(x.IS_ARRAY), isNullable: dbApi.fromDbBool(x.IS_NULLABLE), isOptional: dbApi.fromDbBool(x.IS_OPTIONAL) @@ -206,6 +210,7 @@ clusterDefineName: x.CLUSTER_DEFINE_NAME, argName: x.ARG_NAME, argType: x.ARG_TYPE, + argDefaultValue: x.ARG_DEFAULT_VALUE, argIsArray: dbApi.fromDbBool(x.ARG_IS_ARRAY), argPresentIf: x.ARG_PRESENT_IF, argCountArg: x.ARG_COUNT_ARG, @@ -238,6 +243,7 @@ max: x.MAX, minLength: x.MIN_LENGTH, maxLength: x.MAX_LENGTH, + defaultValue: x.DEFAULT_VALUE, code: x.CODE, isArray: dbApi.fromDbBool(x.IS_ARRAY), presentIf: x.PRESENT_IF, @@ -387,6 +393,7 @@ type: x.TYPE, minLength: x.MIN_LENGTH, maxLength: x.MAX_LENGTH, + defaultValue: x.DEFAULT_VALUE, isArray: dbApi.fromDbBool(x.IS_ARRAY), isEnum: dbApi.fromDbBool(x.IS_ENUM), isWritable: dbApi.fromDbBool(x.IS_WRITABLE),
diff --git a/src-electron/db/query-attribute.js b/src-electron/db/query-attribute.js index 87035aa..9ac2916 100644 --- a/src-electron/db/query-attribute.js +++ b/src-electron/db/query-attribute.js
@@ -1219,7 +1219,28 @@ C1.NAME AS C1_NAME, C2.CODE AS C2_CODE, COALESCE(C2.MANUFACTURER_CODE, 0) AS C2_MANUFACTURER_CODE, - C2.NAME AS C2_NAME + C2.NAME AS C2_NAME, + ROW_NUMBER() OVER ( + PARTITION BY C1.CODE, COALESCE(C1.MANUFACTURER_CODE, 0), C2.CODE, COALESCE(C2.MANUFACTURER_CODE, 0) + ORDER BY C1.CODE, COALESCE(C1.MANUFACTURER_CODE, 0), C2.CODE, COALESCE(C2.MANUFACTURER_CODE, 0) + ) AS CLUSTER_MAPPING_INDEX, + COUNT(*) OVER ( + PARTITION BY C1.CODE, COALESCE(C1.MANUFACTURER_CODE, 0), C2.CODE, COALESCE(C2.MANUFACTURER_CODE, 0) + ) AS TOTAL_CLUSTER_MAPPED_ATTRIBUTES, + CASE + WHEN + ( + RANK() OVER ( + ORDER BY C1.CODE, COALESCE(C1.MANUFACTURER_CODE, 0), C2.CODE, COALESCE(C2.MANUFACTURER_CODE, 0) + ) + + + COUNT(*) OVER ( + PARTITION BY C1.CODE, COALESCE(C1.MANUFACTURER_CODE, 0), C2.CODE, COALESCE(C2.MANUFACTURER_CODE, 0) + ) + ) > COUNT(*) OVER () + THEN 1 + ELSE 0 + END AS IS_LAST_CLUSTER_PARTITION FROM ATTRIBUTE_MAPPING INNER JOIN @@ -1242,7 +1263,7 @@ A1.PACKAGE_REF IN (${dbApi.toInClause(packageIds)}) OR A2.PACKAGE_REF IN (${dbApi.toInClause(packageIds)}) - + ORDER BY C1_CODE, C1_MANUFACTURER_CODE, C2_CODE, C2_MANUFACTURER_CODE, A1_CODE, A1_MANUFACTURER_CODE, A2_CODE, A2_MANUFACTURER_CODE ` ) return rows.map(dbMapping.map.attributeMapping)
diff --git a/src-electron/db/query-bitmap.js b/src-electron/db/query-bitmap.js index 44b70b8..ea4ed06 100644 --- a/src-electron/db/query-bitmap.js +++ b/src-electron/db/query-bitmap.js
@@ -16,7 +16,7 @@ */ /** - * This module provides queries for enums. + * This module provides queries for bitmaps. * * @module DB API: zcl database access */ @@ -25,6 +25,7 @@ const dbCache = require('./db-cache') const dbMapping = require('./db-mapping') const queryUtil = require('./query-util') +const dbEnum = require('../../src-shared/db-enum') /** * Retrieves all the bitmaps in the database. @@ -89,12 +90,12 @@ */ async function selectBitmapByNameAndClusterId(db, name, clusterId, packageIds) { let queryWithoutClusterId = queryUtil.sqlQueryForDataTypeByNameAndClusterId( - 'bitmap', + dbEnum.zclType.bitmap, null, packageIds ) let queryWithClusterId = queryUtil.sqlQueryForDataTypeByNameAndClusterId( - 'bitmap', + dbEnum.zclType.bitmap, clusterId, packageIds ) @@ -113,6 +114,48 @@ } /** + * Select a bitmap matched by name and cluster name + * Note: Use selectBitmapByNameAndClusterId but this was needed for backwards compatibility. + * @param {*} db + * @param {*} name + * @param {*} clusterName + * @param {*} packageIds + * @returns bitmap information or undefined + */ +async function selectBitmapByNameAndClusterName( + db, + name, + clusterName, + packageIds +) { + let queryWithClusterName = queryUtil.sqlQueryForDataTypeByNameAndClusterName( + dbEnum.zclType.bitmap, + name, + clusterName, + packageIds + ) + let res = await dbApi + .dbAll(db, queryWithClusterName) + .then((rows) => rows.map(dbMapping.map.bitmap)) + if (res && res.length == 1) { + return res[0] + } else if (res && res.length > 1) { + throw new Error( + `More than one bitmap ${name} exists with same name for ${clusterName} cluster.` + ) + } else { + queryWithClusterName = queryUtil.sqlQueryForDataTypeByNameAndClusterName( + dbEnum.zclType.bitmap, + name, + null, // Retrieving global data types since cluster specific ones were not found. + packageIds + ) + res = await dbApi.dbGet(db, queryWithClusterName).then(dbMapping.map.bitmap) + return res + } +} + +/** * Get Bitmap information by Bitmap ID. * @param {*} db * @param {*} id @@ -141,3 +184,4 @@ exports.selectBitmapByNameAndClusterId = dbCache.cacheQuery( selectBitmapByNameAndClusterId ) +exports.selectBitmapByNameAndClusterName = selectBitmapByNameAndClusterName
diff --git a/src-electron/db/query-command.js b/src-electron/db/query-command.js index 40dc6f3..05b031b 100644 --- a/src-electron/db/query-command.js +++ b/src-electron/db/query-command.js
@@ -880,19 +880,19 @@ 0 END AS OUTGOING, COUNT(COMMAND.MANUFACTURER_CODE) OVER () AS MANUFACTURING_SPECIFIC_COMMAND_COUNT -FROM +FROM COMMAND -INNER JOIN +INNER JOIN ENDPOINT_TYPE_COMMAND -ON +ON ENDPOINT_TYPE_COMMAND.COMMAND_REF = COMMAND.COMMAND_ID -INNER JOIN +INNER JOIN ENDPOINT_TYPE_CLUSTER -ON +ON ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = ENDPOINT_TYPE_COMMAND.ENDPOINT_TYPE_CLUSTER_REF -INNER JOIN +INNER JOIN CLUSTER -ON +ON ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID WHERE ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_REF IN (${endpointTypeIds}) @@ -1139,6 +1139,7 @@ argMax: x.ARG_MAX, argMinLength: x.ARG_MIN_LENGTH, argMaxLength: x.ARG_MAX_LENGTH, + argDefaultValue: x.ARG_DEFAULT_VALUE, argFieldId: x.FIELD_IDENTIFIER, argIsArray: dbApi.fromDbBool(x.ARG_IS_ARRAY), argPresentIf: x.ARG_PRESENT_IF, @@ -1175,6 +1176,7 @@ CA.MAX as ARG_MAX, CA.MIN_LENGTH as ARG_MIN_LENGTH, CA.MAX_LENGTH as ARG_MAX_LENGTH, + CA.DEFAULT_VALUE AS ARG_DEFAULT_VALUE, CA.FIELD_IDENTIFIER, CA.IS_ARRAY AS ARG_IS_ARRAY, CA.PRESENT_IF AS ARG_PRESENT_IF, @@ -1212,6 +1214,7 @@ max: x.max, minLength: x.minLength, maxLength: x.maxLength, + defaultValue: x.argDefaultValue, fieldId: x.argFieldId, isArray: x.argIsArray, presentIf: x.argPresentIf, @@ -1228,6 +1231,7 @@ delete x.argMax delete x.argMinLength delete x.argMaxLength + delete x.argDefaultValue delete x.argFieldId delete x.argIsArray delete x.argPresentIf @@ -1496,12 +1500,12 @@ IS_FABRIC_SCOPED, RESPONSE_REF, RESPONSE_NAME -FROM +FROM COMMAND -WHERE - CLUSTER_REF IS NOT NULL +WHERE + CLUSTER_REF IS NOT NULL AND PACKAGE_REF = ? -ORDER BY +ORDER BY CODE`, [packageId] ) @@ -1528,6 +1532,7 @@ COMMAND_ARG.MAX, COMMAND_ARG.MIN_LENGTH, COMMAND_ARG.MAX_LENGTH, + COMMAND_ARG.DEFAULT_VALUE, COMMAND_ARG.IS_ARRAY, COMMAND_ARG.PRESENT_IF, COMMAND_ARG.IS_NULLABLE, @@ -1585,6 +1590,7 @@ MAX, MIN_LENGTH, MAX_LENGTH, + DEFAULT_VALUE, IS_ARRAY, PRESENT_IF, IS_NULLABLE, @@ -1639,6 +1645,7 @@ CA.MAX AS ARG_MAX, CA.MIN_LENGTH AS ARG_MIN_LENGTH, CA.MAX_LENGTH AS ARG_MAX_LENGTH, + CA.DEFAULT_VALUE AS ARG_DEFAULT_VALUE, CA.IS_ARRAY AS ARG_IS_ARRAY, CA.PRESENT_IF AS ARG_PRESENT_IF, CA.IS_NULLABLE AS ARG_IS_NULLABLE, @@ -1764,20 +1771,20 @@ CLUSTER.CLUSTER_ID, ENDPOINT_TYPE_CLUSTER.ENABLED, ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID - FROM + FROM COMMAND - INNER JOIN + INNER JOIN CLUSTER - ON + ON COMMAND.CLUSTER_REF = CLUSTER.CLUSTER_ID - INNER JOIN + INNER JOIN ENDPOINT_TYPE_CLUSTER - ON + ON CLUSTER.CLUSTER_ID = ENDPOINT_TYPE_CLUSTER.CLUSTER_REF WHERE ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID IN (${endpointTypeClusterRef}) AND COMMAND.PACKAGE_REF IN (${dbApi.toInClause(packageIds)}) - GROUP BY + GROUP BY COMMAND.NAME ` )
diff --git a/src-electron/db/query-config.js b/src-electron/db/query-config.js index 35a757b..233ecca 100644 --- a/src-electron/db/query-config.js +++ b/src-electron/db/query-config.js
@@ -150,16 +150,16 @@ * Promise that resolves after inserting the defaults associated with the clusterside to the database. * @param {*} db * @param {*} endpointTypeId - * @param {*} clusterRef - * @param {*} side + * @param {*} packageIds + * @param {*} cluster */ -async function insertClusterDefaults(db, endpointTypeId, packageId, cluster) { +async function insertClusterDefaults(db, endpointTypeId, packageIds, cluster) { let promises = [] promises.push( - resolveDefaultAttributes(db, endpointTypeId, packageId, [cluster]) + resolveDefaultAttributes(db, endpointTypeId, packageIds, [cluster]) ) promises.push( - resolveNonOptionalCommands(db, endpointTypeId, [cluster], packageId) + resolveNonOptionalCommands(db, endpointTypeId, [cluster], packageIds) ) return Promise.all(promises) } @@ -937,14 +937,12 @@ if (doTransaction) { await dbApi.dbBeginTransaction(db) } - let pkgs = await queryPackage.getSessionPackagesByType( + let zclPropertiesPkgs = await queryPackage.getSessionPackagesByType( db, sessionId, dbEnum.packageType.zclProperties ) - if (pkgs == null || pkgs.length < 1) - throw new Error('Could not locate package id for a given session.') - + // Filter on category if available let deviceTypeInfo = await querySession.selectDeviceTypePackageInfoFromDeviceTypeId( db, @@ -952,13 +950,23 @@ ) let endpointTypeCategory = deviceTypeInfo.length > 0 ? deviceTypeInfo[0].category : null - let packageId = pkgs[0].id - for (let i = 0; i < pkgs.length; i++) { - if (pkgs[i].category == endpointTypeCategory) { - packageId = pkgs[i].id - break - } + if (endpointTypeCategory) { + zclPropertiesPkgs = zclPropertiesPkgs.filter((pkg) => { + return pkg.category == endpointTypeCategory + }) } + if (zclPropertiesPkgs == null || zclPropertiesPkgs.length < 1) + throw new Error('Could not locate package id for a given session.') + + let zclXmlStandalonePkgs = await queryPackage.getSessionPackagesByType( + db, + sessionId, + dbEnum.packageType.zclXmlStandalone + ) + // Relevant packages are zcl file (filtered by category) and all custom xmls in the session + let pkgs = zclPropertiesPkgs.concat(zclXmlStandalonePkgs) + let packageIds = pkgs.map((pkg) => pkg.id) + let clusters = await queryDeviceType.selectDeviceTypeClustersByDeviceTypeRef( db, deviceTypeRef @@ -973,8 +981,8 @@ promises.push( resolveDefaultDeviceTypeAttributes(db, endpointTypeId, deviceTypeRef), resolveDefaultDeviceTypeCommands(db, endpointTypeId, deviceTypeRef), - resolveDefaultAttributes(db, endpointTypeId, packageId, defaultClusters), - resolveNonOptionalCommands(db, endpointTypeId, defaultClusters, packageId) + resolveDefaultAttributes(db, endpointTypeId, packageIds, defaultClusters), + resolveNonOptionalCommands(db, endpointTypeId, defaultClusters, packageIds) ) return Promise.all(promises).finally(() => { @@ -1212,14 +1220,14 @@ * Resolve attribute defaults for endpoint type clusters. * @param {*} db * @param {*} endpointTypeId - * @param {*} packageId + * @param {*} packageIds * @param {*} endpointClusters * @returns Array of promises for endpointClusters with attributes */ async function resolveDefaultAttributes( db, endpointTypeId, - packageId, + packageIds, endpointClusters ) { let endpointClustersPromises = endpointClusters.map((cluster) => @@ -1227,7 +1235,7 @@ .selectAttributesByClusterIdAndSideIncludingGlobal( db, cluster.clusterRef, - [packageId], + packageIds, cluster.side ) .then((attributes) => {
diff --git a/src-electron/db/query-device-type.js b/src-electron/db/query-device-type.js index 3ba55e3..f47c98a 100644 --- a/src-electron/db/query-device-type.js +++ b/src-electron/db/query-device-type.js
@@ -23,6 +23,7 @@ const dbApi = require('./db-api') const dbMapping = require('./db-mapping') +const querySessionNotification = require('./query-session-notification') /** * Retrieves all the device types in the database. @@ -83,7 +84,6 @@ * @param {*} db * @param {*} packageId * @param {*} code - * @param {*} name * @returns Device type */ async function selectDeviceTypeByCode(db, packageId, code) { @@ -182,7 +182,7 @@ DEVICE_TYPE_CLUSTER AS C ON C.DEVICE_TYPE_CLUSTER_ID = AT.DEVICE_TYPE_CLUSTER_REF - LEFT JOIN + LEFT JOIN ATTRIBUTE ON AT.ATTRIBUTE_REF = ATTRIBUTE.ATTRIBUTE_ID @@ -218,7 +218,7 @@ DEVICE_TYPE_CLUSTER AS C ON C.DEVICE_TYPE_CLUSTER_ID = CMD.DEVICE_TYPE_CLUSTER_REF - LEFT JOIN + LEFT JOIN COMMAND ON CMD.COMMAND_REF = COMMAND.COMMAND_ID @@ -231,12 +231,19 @@ /** * After loading up device type cluster table with the names, - * this method links the refererence to actual cluster reference. + * this method links the reference to actual cluster reference. * * @param {*} db + * @param {*} packageId + * @param {*} sessionPackages (if processing custom xml file it might need to reference clusters from primary zcl or other custom xml) * @returns promise of completion */ -async function updateClusterReferencesForDeviceTypeClusters(db, packageId) { +async function updateClusterReferencesForDeviceTypeClusters( + db, + packageId, + sessionPackages = null +) { + let knownPackages = sessionPackages ? sessionPackages : [packageId] return dbApi.dbUpdate( db, ` @@ -251,25 +258,33 @@ WHERE lower(CLUSTER.NAME) = lower(DEVICE_TYPE_CLUSTER.CLUSTER_NAME) AND - CLUSTER.PACKAGE_REF = ? + CLUSTER.PACKAGE_REF IN (${dbApi.toInClause(knownPackages)}) ) WHERE - ( SELECT PACKAGE_REF + CLUSTER_REF IS NULL + AND ( SELECT PACKAGE_REF FROM DEVICE_TYPE WHERE DEVICE_TYPE_ID = DEVICE_TYPE_CLUSTER.DEVICE_TYPE_REF ) = ?`, - [packageId, packageId] + [packageId] ) } /** * After loading up device type attribute table with the names, - * this method links the refererence to actual attribute reference. + * this method links the references to actual attribute reference. * * @param {*} db + * @param {*} packageId + * @param {*} sessionPackages (if processing custom xml file it might need to reference attributes from primary zcl or other custom xml) * @returns promise of completion */ -async function updateAttributeReferencesForDeviceTypeReferences(db, packageId) { +async function updateAttributeReferencesForDeviceTypeReferences( + db, + packageId, + sessionPackages = null +) { + let knownPackages = sessionPackages ? sessionPackages : [packageId] return dbApi.dbUpdate( db, ` @@ -293,23 +308,30 @@ DEVICE_TYPE_CLUSTER_ID = DEVICE_TYPE_ATTRIBUTE.DEVICE_TYPE_CLUSTER_REF ) AND - ATTRIBUTE.PACKAGE_REF = ? + ATTRIBUTE.PACKAGE_REF IN (${dbApi.toInClause(knownPackages)}) ) WHERE DEVICE_TYPE_ATTRIBUTE.ATTRIBUTE_REF IS NULL `, - [packageId] + [] ) } /** * After loading up device type command table with the names, - * this method links the refererence to actual command reference. + * this method links the reference to actual command reference. * * @param {*} db + * @param {*} packageId + * @param {*} sessionPackages (if processing custom xml file it might need to reference commands from primary zcl or other custom xml) * @returns promise of completion */ -async function updateCommandReferencesForDeviceTypeReferences(db, packageId) { +async function updateCommandReferencesForDeviceTypeReferences( + db, + packageId, + sessionPackages = null +) { + let knownPackages = sessionPackages ? sessionPackages : [packageId] return dbApi.dbUpdate( db, ` @@ -333,19 +355,20 @@ DEVICE_TYPE_CLUSTER_ID = DEVICE_TYPE_COMMAND.DEVICE_TYPE_CLUSTER_REF ) AND - COMMAND.PACKAGE_REF = ? + COMMAND.PACKAGE_REF IN (${dbApi.toInClause(knownPackages)}) ) WHERE DEVICE_TYPE_COMMAND.COMMAND_REF IS NULL`, - [packageId] + [] ) } /** * After loading up device type feature table with the names, - * this method links the refererence to actual feature reference. + * this method links the reference to actual feature reference. * * @param {*} db + * @param {*} packageId * @returns promise of completion */ async function updateFeatureReferencesForDeviceTypeReferences(db, packageId) { @@ -399,6 +422,125 @@ } /** + * Device types defined in custom xml files might refer to cluster, commands and attributes + * from the primary zcl file and other custom xml in the session. + * + * This method returns the promise of linking the device type entities to the correct + * foreign keys in such cases. + * + * @param {*} db + * @param {*} packageId + * @param {*} sessionPackages + * @param {*} sessionId + * @returns promise of completed linking + */ +async function updateDeviceTypeReferencesForCustomXml( + db, + packageId, + sessionPackages, + sessionId +) { + // update the references for device type clusters, attributes and commands + await updateClusterReferencesForDeviceTypeClusters( + db, + packageId, + sessionPackages + ) + await updateAttributeReferencesForDeviceTypeReferences( + db, + packageId, + sessionPackages + ) + await updateCommandReferencesForDeviceTypeReferences( + db, + packageId, + sessionPackages + ) + + // add warnings for unlinked device type clusters + await warnUnlinkedDeviceTypeClusters(db, packageId, sessionId) + + // delete unlinked device type clusters + return deleteUnlinkedDeviceTypeClusters(db, packageId) +} + +/** + * This method deletes all device type clusters that are not linked to any cluster. + * + * @param {*} db + * @param {*} packageId + */ +async function deleteUnlinkedDeviceTypeClusters(db, packageId) { + return dbApi.dbRemove( + db, + ` + DELETE FROM + DEVICE_TYPE_CLUSTER + WHERE + CLUSTER_REF IS NULL + AND + DEVICE_TYPE_REF IN ( + SELECT + DEVICE_TYPE_ID + FROM + DEVICE_TYPE + WHERE + PACKAGE_REF = ? + ) + `, + [packageId] + ) +} + +/** + * This method adds warnings for all device type clusters that are not linked to any cluster. + * + * @param {*} db + * @param {*} packageId + * @param {*} sessionId + */ +async function warnUnlinkedDeviceTypeClusters(db, packageId, sessionId) { + let unlinkedDtClusters = await dbApi.dbAll( + db, + ` + SELECT + DTC.CLUSTER_NAME, + DT.NAME + FROM + DEVICE_TYPE_CLUSTER AS DTC + JOIN + DEVICE_TYPE AS DT ON DTC.DEVICE_TYPE_REF = DT.DEVICE_TYPE_ID + WHERE + CLUSTER_REF IS NULL + AND + DT.PACKAGE_REF = ? + `, + [packageId] + ) + let packagePath = await dbApi.dbGet( + db, + ` + SELECT + PATH + FROM + PACKAGE + WHERE + PACKAGE_ID = ?`, + [packageId] + ) + for (const dtCluster of unlinkedDtClusters) { + querySessionNotification.setNotification( + db, + 'ERROR', + `Cluster "${dtCluster.CLUSTER_NAME}" in device type ${dtCluster.NAME} is not found in the current session - "${packagePath.PATH}"`, + sessionId, + 1, + 0 + ) + } +} + +/** * Asynchronously selects device types with their compositions by a specific endpoint type ID. * * This function queries the database for device types associated with a given endpoint type ID, @@ -532,6 +674,8 @@ exports.selectDeviceTypeCommandsByDeviceTypeRef = selectDeviceTypeCommandsByDeviceTypeRef exports.updateDeviceTypeEntityReferences = updateDeviceTypeEntityReferences +exports.updateDeviceTypeReferencesForCustomXml = + updateDeviceTypeReferencesForCustomXml exports.selectDeviceTypesByEndpointTypeId = selectDeviceTypesByEndpointTypeId exports.selectDeviceTypeFeaturesByEndpointTypeIdAndClusterId = selectDeviceTypeFeaturesByEndpointTypeIdAndClusterId
diff --git a/src-electron/db/query-endpoint.js b/src-electron/db/query-endpoint.js index fc453e6..b446489 100644 --- a/src-electron/db/query-endpoint.js +++ b/src-electron/db/query-endpoint.js
@@ -50,7 +50,7 @@ ENDPOINT AS E1 LEFT JOIN ENDPOINT AS E2 -ON +ON E2.ENDPOINT_ID = E1.PARENT_ENDPOINT_REF WHERE E1.SESSION_REF = ? ORDER BY E1.ENDPOINT_IDENTIFIER @@ -70,18 +70,18 @@ */ async function getRootNode(db, packageIds) { const query = ` - SELECT - EC.DEVICE_TYPE_REF, - EC.CODE, + SELECT + EC.DEVICE_TYPE_REF, + EC.CODE, EC.TYPE, - DT.NAME, + DT.NAME, DT.PACKAGE_REF - FROM + FROM ENDPOINT_COMPOSITION EC - JOIN + JOIN DEVICE_TYPE DT ON EC.DEVICE_TYPE_REF = DT.DEVICE_TYPE_ID - WHERE - EC.TYPE = ? AND + WHERE + EC.TYPE = ? AND DT.PACKAGE_REF IN (${packageIds.map(() => '?').join(', ')}) ` @@ -124,7 +124,7 @@ ENDPOINT AS E1 LEFT JOIN ENDPOINT AS E2 -ON +ON E2.ENDPOINT_ID = E1.PARENT_ENDPOINT_REF INNER JOIN ENDPOINT_TYPE @@ -145,12 +145,12 @@ WHERE E1.SESSION_REF = ? AND - PACKAGE.CATEGORY = ? + ((PACKAGE.CATEGORY = ?) OR (PACKAGE.CATEGORY IS NULL AND PACKAGE.TYPE = ?)) GROUP BY E1.ENDPOINT_IDENTIFIER ORDER BY E1.ENDPOINT_IDENTIFIER `, - [sessionId, templateCategory] + [sessionId, templateCategory, dbEnum.packageType.zclXmlStandalone] ) // if now rows are found then return all endpoints in the session. This can @@ -559,7 +559,7 @@ NETWORK_IDENTIFIER, PROFILE ) - SELECT + SELECT SESSION_REF, ?, ?, @@ -605,7 +605,7 @@ ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF = E1.ENDPOINT_TYPE_REF LEFT JOIN ENDPOINT AS E2 -ON +ON E2.ENDPOINT_ID = E1.PARENT_ENDPOINT_REF WHERE E1.ENDPOINT_ID = ?`,
diff --git a/src-electron/db/query-enum.js b/src-electron/db/query-enum.js index 91949ef..58ecfe5 100644 --- a/src-electron/db/query-enum.js +++ b/src-electron/db/query-enum.js
@@ -25,6 +25,7 @@ const dbCache = require('./db-cache') const dbMapping = require('./db-mapping') const queryUtil = require('./query-util') +const dbEnum = require('../../src-shared/db-enum') /** * Retrieves all the enums in the database. @@ -226,12 +227,12 @@ */ async function selectEnumByNameAndClusterId(db, name, clusterId, packageIds) { let queryWithoutClusterId = queryUtil.sqlQueryForDataTypeByNameAndClusterId( - 'enum', + dbEnum.zclType.enum, null, packageIds ) let queryWithClusterId = queryUtil.sqlQueryForDataTypeByNameAndClusterId( - 'enum', + dbEnum.zclType.enum, clusterId, packageIds ) @@ -248,6 +249,48 @@ } } +/** + * Select a enum matched by name and cluster name + * Note: Use selectEnumByNameAndClusterId but this was needed for backwards compatibility. + * @param {*} db + * @param {*} name + * @param {*} clusterName + * @param {*} packageIds + * @returns enum information or undefined + */ +async function selectEnumByNameAndClusterName( + db, + name, + clusterName, + packageIds +) { + let queryWithClusterName = queryUtil.sqlQueryForDataTypeByNameAndClusterName( + dbEnum.zclType.enum, + name, + clusterName, + packageIds + ) + let res = await dbApi + .dbAll(db, queryWithClusterName) + .then((rows) => rows.map(dbMapping.map.enum)) + if (res && res.length == 1) { + return res[0] + } else if (res && res.length > 1) { + throw new Error( + `More than one enum ${name} exists with same name for ${clusterName} cluster.` + ) + } else { + queryWithClusterName = queryUtil.sqlQueryForDataTypeByNameAndClusterName( + dbEnum.zclType.enum, + name, + null, // Retrieving global data types since cluster specific ones were not found. + packageIds + ) + res = await dbApi.dbGet(db, queryWithClusterName).then(dbMapping.map.enum) + return res + } +} + // exports exports.selectAllEnums = selectAllEnums exports.selectEnumByName = dbCache.cacheQuery(selectEnumByName) @@ -258,3 +301,4 @@ exports.selectClusterEnums = selectClusterEnums exports.selectAllEnumItemsById = selectAllEnumItemsById exports.selectAllEnumItems = selectAllEnumItems +exports.selectEnumByNameAndClusterName = selectEnumByNameAndClusterName
diff --git a/src-electron/db/query-event.js b/src-electron/db/query-event.js index eb89d5d..6e52285 100644 --- a/src-electron/db/query-event.js +++ b/src-electron/db/query-event.js
@@ -218,6 +218,7 @@ FIELD_IDENTIFIER, NAME, TYPE, + DEFAULT_VALUE, IS_ARRAY, IS_NULLABLE, IS_OPTIONAL
diff --git a/src-electron/db/query-loader.js b/src-electron/db/query-loader.js index c9bfd6a..26c11be 100644 --- a/src-electron/db/query-loader.js +++ b/src-electron/db/query-loader.js
@@ -77,13 +77,14 @@ FIELD_IDENTIFIER, NAME, TYPE, + DEFAULT_VALUE, IS_ARRAY, IS_NULLABLE, IS_OPTIONAL, INTRODUCED_IN_REF, REMOVED_IN_REF ) VALUES ( - ?, ?, ?, ?, ?, ?, ?, + ?, ?, ?, ?, ?, ?, ?, ?, (SELECT SPEC_ID FROM SPEC WHERE CODE = ? AND PACKAGE_REF = ?), (SELECT SPEC_ID FROM SPEC WHERE CODE = ? AND PACKAGE_REF = ?) ) @@ -122,6 +123,7 @@ MAX, MIN_LENGTH, MAX_LENGTH, + DEFAULT_VALUE, IS_ARRAY, PRESENT_IF, IS_NULLABLE, @@ -131,7 +133,7 @@ INTRODUCED_IN_REF, REMOVED_IN_REF ) VALUES ( - ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, + ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, (SELECT SPEC_ID FROM SPEC WHERE CODE = ? AND PACKAGE_REF = ?), (SELECT SPEC_ID FROM SPEC WHERE CODE = ? AND PACKAGE_REF = ?) )` @@ -333,6 +335,7 @@ field.fieldIdentifier, field.name, field.type, + field.defaultValue, dbApi.toDbBool(field.isArray), dbApi.toDbBool(field.isNullable), dbApi.toDbBool(field.isOptional), @@ -360,6 +363,7 @@ arg.max, arg.minLength, arg.maxLength, + arg.defaultValue, dbApi.toDbBool(arg.isArray), arg.presentIf, dbApi.toDbBool(arg.isNullable), @@ -1266,7 +1270,7 @@ if ('clusters' in data[i]) { let lastId = lastIdsArray[i] let clusters = data[i].clusters - // This is an array that links the generated deviceTyepRef to the cluster via generating an array of arrays, + // This is an array that links the generated deviceTypeRef to the cluster via generating an array of arrays, zclIdsPromises = Promise.all( clusters.map((cluster) => dbApi @@ -1331,6 +1335,122 @@ } /** + * Reloads device types into the database. + * This function is responsible for inserting new device type entities as required + * when a previously loaded custom xml file (containing a device type) is added to a session. + * + * @param {*} db + * @param {*} packageId + * @param {*} data + * @param {*} sessionPackages + */ +async function reloadDeviceTypes(db, packageId, data, sessionPackages) { + let zclIdsPromises = [] + for (let dt of data) { + // Find the DEVICE_TYPE_ID for the current device type + const query = ` + SELECT + DEVICE_TYPE_ID + FROM + DEVICE_TYPE + WHERE + PACKAGE_REF = ? AND CODE = ?` + const result = await dbApi.dbGet(db, query, [packageId, dt.code]) + + if (result) { + const existingId = result.DEVICE_TYPE_ID + + if ('clusters' in dt) { + const clusters = dt.clusters + + // Process clusters for the existing device type + const clusterPromises = [] + for (const cluster of clusters) { + const isInsertRequired = await isDeviceTypeClusterInsertRequired( + db, + existingId, + cluster.clusterName, + packageId, + sessionPackages + ) + // Only inserting new device type cluster if required + if (isInsertRequired) { + const promise = dbApi + .dbInsert( + db, + 'INSERT INTO DEVICE_TYPE_CLUSTER (DEVICE_TYPE_REF, CLUSTER_NAME, INCLUDE_CLIENT, INCLUDE_SERVER, LOCK_CLIENT, LOCK_SERVER) VALUES (?,?,?,?,?,?)', + [ + existingId, + cluster.clusterName, + cluster.client, + cluster.server, + cluster.clientLocked, + cluster.serverLocked + ], + true + ) + .then((deviceTypeClusterRef) => ({ + dtClusterRef: deviceTypeClusterRef, + clusterData: cluster + })) + clusterPromises.push(promise) + } + } + + const dtClusterRefDataPairs = await Promise.all(clusterPromises) + + // Insert attributes, commands, and features for the device type + await Promise.all([ + insertDeviceTypeAttributes(db, dtClusterRefDataPairs), + insertDeviceTypeCommands(db, dtClusterRefDataPairs) + ]) + } + } + } + return zclIdsPromises +} + +/** + * Checks if a device type cluster insert is required on device type reload. + * + * @param {*} db + * @param {*} deviceTypeId + * @param {*} clusterName + * @param {*} packageId + * @param {*} sessionPackages + * @returns {Promise<boolean>} - Returns true if the insert is required, false otherwise. + */ +async function isDeviceTypeClusterInsertRequired( + db, + deviceTypeId, + clusterName, + packageId, + sessionPackages +) { + let knownPackages = sessionPackages.concat(packageId) + const query = ` + SELECT + DEVICE_TYPE_CLUSTER_ID + FROM + DEVICE_TYPE_CLUSTER + WHERE + DEVICE_TYPE_REF = ? + AND + CLUSTER_NAME = ? + AND + CLUSTER_REF IN + (SELECT + CLUSTER_ID + FROM + CLUSTER + WHERE + PACKAGE_REF IN (${dbApi.toInClause(knownPackages)})) + ` + const result = await dbApi.dbGet(db, query, [deviceTypeId, clusterName]) + return result === undefined +} + +/** * This handles the loading of device type feature requirements into the database. * There is a need to post-process to attach the actual feature ref after the fact * @param {*} db @@ -2282,7 +2402,7 @@ db, ` INSERT INTO - STRUCT_ITEM (STRUCT_REF, NAME, FIELD_IDENTIFIER, IS_ARRAY, IS_ENUM, MIN_LENGTH, MAX_LENGTH, IS_WRITABLE, IS_NULLABLE, IS_OPTIONAL, IS_FABRIC_SENSITIVE, SIZE, DATA_TYPE_REF) + STRUCT_ITEM (STRUCT_REF, NAME, FIELD_IDENTIFIER, IS_ARRAY, IS_ENUM, MIN_LENGTH, MAX_LENGTH, DEFAULT_VALUE, IS_WRITABLE, IS_NULLABLE, IS_OPTIONAL, IS_FABRIC_SENSITIVE, SIZE, DATA_TYPE_REF) VALUES ( (SELECT CASE @@ -2306,6 +2426,7 @@ ?, ?, ?, + ?, (SELECT DATA_TYPE_ID FROM @@ -2329,6 +2450,7 @@ at.isEnum, at.minLength, at.maxLength, + at.defaultValue, at.isWritable, at.isNullable, at.isOptional, @@ -2347,6 +2469,7 @@ exports.insertGlobalAttributeDefault = insertGlobalAttributeDefault exports.insertAtomics = insertAtomics exports.insertDeviceTypes = insertDeviceTypes +exports.reloadDeviceTypes = reloadDeviceTypes exports.insertTags = insertTags exports.insertAccessModifiers = insertAccessModifiers exports.insertAccessOperations = insertAccessOperations
diff --git a/src-electron/db/query-package.js b/src-electron/db/query-package.js index be35153..954a9f6 100644 --- a/src-electron/db/query-package.js +++ b/src-electron/db/query-package.js
@@ -533,7 +533,8 @@ SESSION_PARTITION.SESSION_REF, SESSION_PARTITION.SESSION_PARTITION_ID, SP.REQUIRED, - P.CATEGORY + P.CATEGORY, + P.TYPE FROM SESSION_PARTITION INNER JOIN @@ -686,7 +687,7 @@ CATEGORY, DESCRIPTION, PARENT_PACKAGE_REF - FROM + FROM PACKAGE WHERE IS_IN_SYNC = 1` @@ -734,7 +735,7 @@ po.OPTION_CODE = ? AND ${packageRefCondition} - UNION + UNION SELECT c.NAME AS OPTION_CATEGORY,
diff --git a/src-electron/db/query-struct.js b/src-electron/db/query-struct.js index 24b7b4b..5c9ada3 100644 --- a/src-electron/db/query-struct.js +++ b/src-electron/db/query-struct.js
@@ -25,6 +25,7 @@ const dbCache = require('./db-cache') const dbMapping = require('./db-mapping') const queryUtil = require('./query-util') +const dbEnum = require('../../src-shared/db-enum') /** * Get all structs from a given package ID. @@ -132,12 +133,12 @@ */ async function selectStructByNameAndClusterId(db, name, clusterId, packageIds) { let queryWithoutClusterId = queryUtil.sqlQueryForDataTypeByNameAndClusterId( - 'struct', + dbEnum.zclType.struct, null, packageIds ) let queryWithClusterId = queryUtil.sqlQueryForDataTypeByNameAndClusterId( - 'struct', + dbEnum.zclType.struct, clusterId, packageIds ) @@ -155,6 +156,48 @@ } /** + * Select a struct matched by name and cluster name + * Note: Use selectStructByNameAndClusterId but this was needed for backwards compatibility. + * @param {*} db + * @param {*} name + * @param {*} clusterName + * @param {*} packageIds + * @returns struct information or undefined + */ +async function selectStructByNameAndClusterName( + db, + name, + clusterName, + packageIds +) { + let queryWithClusterName = queryUtil.sqlQueryForDataTypeByNameAndClusterName( + dbEnum.zclType.struct, + name, + clusterName, + packageIds + ) + let res = await dbApi + .dbAll(db, queryWithClusterName) + .then((rows) => rows.map(dbMapping.map.struct)) + if (res && res.length == 1) { + return res[0] + } else if (res && res.length > 1) { + throw new Error( + `More than one struct ${name} exists with same name for ${clusterName} cluster.` + ) + } else { + queryWithClusterName = queryUtil.sqlQueryForDataTypeByNameAndClusterName( + dbEnum.zclType.struct, + name, + null, // Retrieving global data types since cluster specific ones were not found. + packageIds + ) + res = await dbApi.dbGet(db, queryWithClusterName).then(dbMapping.map.struct) + return res + } +} + +/** * Get all structs which have a cluster associated with them. If a struct is * present in more than one cluster then it can be grouped by struct name to * avoid additional rows. @@ -208,5 +251,6 @@ exports.selectStructByNameAndClusterId = dbCache.cacheQuery( selectStructByNameAndClusterId ) +exports.selectStructByNameAndClusterName = selectStructByNameAndClusterName exports.selectStructsWithClusterAssociation = selectStructsWithClusterAssociation
diff --git a/src-electron/db/query-util.js b/src-electron/db/query-util.js index 5adedae..6e325cd 100644 --- a/src-electron/db/query-util.js +++ b/src-electron/db/query-util.js
@@ -83,5 +83,71 @@ return clusterId ? queryWithClusterId : queryWithoutClusterId } +/** + * Formulate a sqlite query string for a data type from the given cluster name and package IDs. + * @param {*} typeDiscriminator + * @param {*} name data type name + * @param {*} clusterName + * @param {*} packageIds + * @param {*} options + * @returns SQLite query string + */ +function sqlQueryForDataTypeByNameAndClusterName( + typeDiscriminator, + name, + clusterName, + packageIds, + options = {} +) { + let typeTableName = typeDiscriminator.toUpperCase() + let numberExtensionString = + typeDiscriminator == 'number' ? 'NUMBER.IS_SIGNED, ' : '' + let checkLowerCaseString = + typeDiscriminator != 'number' && typeDiscriminator != 'struct' + ? `OR DATA_TYPE.NAME = '${name}'` + : '' + let structExtensionString = + typeDiscriminator == 'struct' + ? 'STRUCT.IS_FABRIC_SCOPED, DATA_TYPE.DISCRIMINATOR_REF, ' + : '' + let selectQueryString = ` + SELECT + ${typeTableName}.${typeTableName}_ID, + ${structExtensionString} + DATA_TYPE.NAME AS NAME, + (SELECT COUNT(1) FROM DATA_TYPE_CLUSTER WHERE DATA_TYPE_CLUSTER.DATA_TYPE_REF = ${typeTableName}.${typeTableName}_ID) AS ${typeTableName}_CLUSTER_COUNT, + ${numberExtensionString} + ${typeTableName}.SIZE AS SIZE, + CLUSTER.NAME AS CLUSTER_NAME + FROM ${typeTableName} + INNER JOIN + DATA_TYPE + ON + ${typeTableName}.${typeTableName}_ID = DATA_TYPE.DATA_TYPE_ID + LEFT JOIN + DATA_TYPE_CLUSTER + ON + DATA_TYPE_CLUSTER.DATA_TYPE_REF = ${typeTableName}.${typeTableName}_ID + LEFT JOIN + CLUSTER + ON + DATA_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID + WHERE + (DATA_TYPE.NAME = '${name}' ${checkLowerCaseString}) + AND + DATA_TYPE.PACKAGE_REF IN (${dbApi.toInClause(packageIds)}) ` + + let whereClause = !options.ignoreClusterWhereClause + ? clusterName + ? `AND CLUSTER.NAME = '${clusterName}'` + : `AND CLUSTER.NAME IS NULL` + : `` + + let resultingQuery = selectQueryString + whereClause + return resultingQuery +} + exports.sqlQueryForDataTypeByNameAndClusterId = sqlQueryForDataTypeByNameAndClusterId +exports.sqlQueryForDataTypeByNameAndClusterName = + sqlQueryForDataTypeByNameAndClusterName
diff --git a/src-electron/db/query-zcl.js b/src-electron/db/query-zcl.js index d7b8b33..377658b 100644 --- a/src-electron/db/query-zcl.js +++ b/src-electron/db/query-zcl.js
@@ -356,7 +356,7 @@ S.STRUCT_ID = SI.STRUCT_REF WHERE DT.PACKAGE_REF IN (${dbApi.toInClause(packageIds)}) - ORDER BY DT.NAME, SI.FIELD_IDENTIFIER` + ORDER BY DT.NAME, DT.DATA_TYPE_ID, SI.FIELD_IDENTIFIER` } else { query = ` SELECT @@ -395,18 +395,19 @@ DT.PACKAGE_REF IN (${dbApi.toInClause(packageIds)}) AND DTC.CLUSTER_REF = ? - ORDER BY DT.NAME, SI.FIELD_IDENTIFIER` + ORDER BY DT.NAME, DT.DATA_TYPE_ID, SI.FIELD_IDENTIFIER` args = [clusterId] } let rows = await dbApi.dbAll(db, query, args) return rows.reduce((acc, value) => { let objectToActOn - if (acc.length == 0 || acc[acc.length - 1].name != value.STRUCT_NAME) { + if (acc.length == 0 || acc[acc.length - 1].struct_id != value.STRUCT_ID) { // Create a new object objectToActOn = { id: value.STRUCT_ID, name: value.STRUCT_NAME, + struct_id: value.STRUCT_ID, isFabricScoped: dbApi.fromDbBool(value.IS_FABRIC_SCOPED), apiMaturity: value.API_MATURITY, label: value.STRUCT_NAME, @@ -459,6 +460,7 @@ STRUCT_ITEM.IS_ENUM, STRUCT_ITEM.MIN_LENGTH, STRUCT_ITEM.MAX_LENGTH, + STRUCT_ITEM.DEFAULT_VALUE, STRUCT_ITEM.IS_WRITABLE, STRUCT_ITEM.IS_NULLABLE, STRUCT_ITEM.IS_OPTIONAL, @@ -1332,6 +1334,12 @@ exports.selectStructByName = queryStruct.selectStructByName exports.selectStructByNameAndClusterId = queryStruct.selectStructByNameAndClusterId +exports.selectStructByNameAndClusterName = + queryStruct.selectStructByNameAndClusterName +exports.selectEnumByNameAndClusterName = + queryEnum.selectEnumByNameAndClusterName +exports.selectBitmapByNameAndClusterName = + queryBitmap.selectBitmapByNameAndClusterName exports.selectBitmapById = queryBitmap.selectBitmapById exports.selectAllBitmaps = queryBitmap.selectAllBitmaps
diff --git a/src-electron/db/zap-schema.sql b/src-electron/db/zap-schema.sql index 77341f7..f5eec24 100644 --- a/src-electron/db/zap-schema.sql +++ b/src-electron/db/zap-schema.sql
@@ -206,6 +206,7 @@ "MAX" text, "MIN_LENGTH" integer, "MAX_LENGTH" integer, + "DEFAULT_VALUE" text, "IS_ARRAY" integer, "PRESENT_IF" text, "IS_NULLABLE" integer, @@ -253,6 +254,7 @@ "FIELD_IDENTIFIER" integer, "NAME" text, "TYPE" text, + "DEFAULT_VALUE" text, "IS_ARRAY" integer, "IS_NULLABLE" integer, "IS_OPTIONAL" integer, @@ -624,7 +626,7 @@ DROP TABLE IF EXISTS "BITMAP_FIELD"; CREATE TABLE IF NOT EXISTS BITMAP_FIELD ( BITMAP_FIELD_ID integer NOT NULL PRIMARY KEY autoincrement, - BITMAP_REF integer, + BITMAP_REF integer NOT NULL, FIELD_IDENTIFIER integer, NAME text(100), MASK integer, @@ -647,7 +649,7 @@ DROP TABLE IF EXISTS "ENUM_ITEM"; CREATE TABLE IF NOT EXISTS "ENUM_ITEM" ( "ENUM_ITEM_ID" integer NOT NULL PRIMARY KEY autoincrement, - "ENUM_REF" integer, + "ENUM_REF" integer NOT NULL, "NAME" text, "DESCRIPTION" text, "FIELD_IDENTIFIER" integer, @@ -672,13 +674,14 @@ DROP TABLE IF EXISTS "STRUCT_ITEM"; CREATE TABLE IF NOT EXISTS STRUCT_ITEM ( STRUCT_ITEM_ID integer NOT NULL PRIMARY KEY autoincrement, - STRUCT_REF integer, + STRUCT_REF integer NOT NULL, FIELD_IDENTIFIER integer, NAME text(100), IS_ARRAY integer, IS_ENUM integer, MIN_LENGTH integer, MAX_LENGTH integer, + DEFAULT_VALUE text, IS_WRITABLE integer, IS_NULLABLE integer, IS_OPTIONAL integer, @@ -3433,7 +3436,7 @@ ON ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID WHERE - ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = new.ENDPOINT_TYPE_CLUSTER_REF + ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = new.ENDPOINT_TYPE_CLUSTER_REF ) || ( @@ -3551,7 +3554,7 @@ ON ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID WHERE - ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = new.ENDPOINT_TYPE_CLUSTER_REF + ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = new.ENDPOINT_TYPE_CLUSTER_REF ) || ( @@ -3578,7 +3581,7 @@ C1.RESPONSE_REF = ETC.COMMAND_REF WHERE ETC.ENDPOINT_TYPE_COMMAND_ID = new.ENDPOINT_TYPE_COMMAND_ID - ) + ) ); END; @@ -3663,7 +3666,7 @@ ON ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID WHERE - ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = new.ENDPOINT_TYPE_CLUSTER_REF + ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = new.ENDPOINT_TYPE_CLUSTER_REF ) || ( @@ -3794,7 +3797,7 @@ ON ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID WHERE - ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = new.ENDPOINT_TYPE_CLUSTER_REF + ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = new.ENDPOINT_TYPE_CLUSTER_REF ) || ( @@ -3821,7 +3824,7 @@ C2.COMMAND_ID = C1.RESPONSE_REF WHERE ETC.ENDPOINT_TYPE_COMMAND_ID = new.ENDPOINT_TYPE_COMMAND_ID - ) + ) ); END; @@ -3909,7 +3912,7 @@ ON ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID WHERE - ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = new.ENDPOINT_TYPE_CLUSTER_REF + ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = new.ENDPOINT_TYPE_CLUSTER_REF ) || ( @@ -4027,7 +4030,7 @@ ON ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID WHERE - ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = new.ENDPOINT_TYPE_CLUSTER_REF + ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = new.ENDPOINT_TYPE_CLUSTER_REF ) || ( @@ -4054,7 +4057,7 @@ C1.RESPONSE_REF = ETC.COMMAND_REF WHERE ETC.ENDPOINT_TYPE_COMMAND_ID = new.ENDPOINT_TYPE_COMMAND_ID - ) + ) ); END;
diff --git a/src-electron/generator/generation-engine.js b/src-electron/generator/generation-engine.js index f496fe5..73d23a9 100644 --- a/src-electron/generator/generation-engine.js +++ b/src-electron/generator/generation-engine.js
@@ -34,6 +34,30 @@ const queryNotification = require('../db/query-package-notification.js') /** + * Finds and reads JSON files referenced in a nested object. + * + * @param {Object} obj - The object to search for JSON file references. + * @param {string} basePath - The base directory to resolve relative paths. + * @returns {Promise<string>} - A promise that resolves to the concatenated content of all JSON files. + */ +async function findAndReadJsonFiles(obj, basePath) { + let additionalJsonContent = '' + for (const key in obj) { + if (typeof obj[key] === 'string' && obj[key].endsWith('.json')) { + // If the value is a JSON file reference, read its content + let jsonFilePath = path.resolve(path.join(basePath, obj[key])) + if (fs.existsSync(jsonFilePath)) { + additionalJsonContent += await fsPromise.readFile(jsonFilePath, 'utf8') + } + } else if (typeof obj[key] === 'object' && obj[key] !== null) { + // If the value is an object, recursively search for JSON file references + additionalJsonContent += await findAndReadJsonFiles(obj[key], basePath) + } + } + return additionalJsonContent +} + +/** * Given a path, it will read generation template object into memory. * * @param {*} templatePath @@ -42,34 +66,15 @@ async function loadGenTemplateFromFile(templatePath) { let ret = {} ret.data = await fsPromise.readFile(templatePath, 'utf8') - ret.crc = util.checksum(ret.data) ret.templateData = JSON.parse(ret.data) - let zclExtension = ret.templateData.zcl - let zclExtensionFileContent = '' - // Adding zcl extension files to the template json crc - if (zclExtension && typeof zclExtension === 'object') { - for (const key of Object.keys(zclExtension)) { - let extension = zclExtension[key] - for (const key2 of Object.keys(extension)) { - let defaultExtensionValue = extension[key2].defaults - if ( - typeof defaultExtensionValue === 'string' || - defaultExtensionValue instanceof String - ) { - // Data is a string, so we will treat it as a relative path to the JSON file. - let externalPath = path.resolve( - path.join(path.dirname(templatePath), defaultExtensionValue) - ) - zclExtensionFileContent += await fsPromise.readFile( - externalPath, - 'utf8' - ) - } - } - } - ret.crc = util.checksum(ret.data + zclExtensionFileContent) - } - + // Find the json files within the gen template json files and add them to the + // crc as well. + let allJsonContentInTemplatePath = await findAndReadJsonFiles( + ret.templateData, + path.dirname(templatePath) + ) + let checksumData = ret.data + allJsonContentInTemplatePath + ret.crc = util.checksum(checksumData) let requiredFeatureLevel = 0 if ('requiredFeatureLevel' in ret.templateData) { requiredFeatureLevel = ret.templateData.requiredFeatureLevel
diff --git a/src-electron/generator/helper-c.js b/src-electron/generator/helper-c.js index 2cb2c23..5664949 100644 --- a/src-electron/generator/helper-c.js +++ b/src-electron/generator/helper-c.js
@@ -69,7 +69,14 @@ return `0x${value.slice(2).toUpperCase()}` } else { let val = parseInt(value) - return `0x${val.toString(16).padStart(padding, '0').toUpperCase()}` + let paddingLength = padding + if (!paddingLength) { + paddingLength = + val.toString(16).length % 2 === 0 + ? val.toString(16).length + : val.toString(16).length + 1 + } + return `0x${val.toString(16).padStart(paddingLength, '0').toUpperCase()}` } }
diff --git a/src-electron/generator/matter/app/zap-templates/common/ClusterTestGeneration.js b/src-electron/generator/matter/app/zap-templates/common/ClusterTestGeneration.js index e4aa9ac..f99ebb3 100644 --- a/src-electron/generator/matter/app/zap-templates/common/ClusterTestGeneration.js +++ b/src-electron/generator/matter/app/zap-templates/common/ClusterTestGeneration.js
@@ -1454,6 +1454,9 @@ * @returns data type as String */ async function asTestType(type, isList) { + // NOTE: This is not used on current Matter tip, so the fact that it does not + // cluster-scope type names is not an issue. + if (isList) { return 'list'; }
diff --git a/src-electron/generator/matter/app/zap-templates/templates/app/helper.js b/src-electron/generator/matter/app/zap-templates/templates/app/helper.js index 71cecfe..84c8c30 100644 --- a/src-electron/generator/matter/app/zap-templates/templates/app/helper.js +++ b/src-electron/generator/matter/app/zap-templates/templates/app/helper.js
@@ -588,6 +588,52 @@ return ns; } +// Not to be exported. +// +// dataType can be "Enum", "Struct", or "Bitmap". +async function getClusterCountForType(db, pkgId, type, dataType, options) { + if (options.hash.cluster === '') { + // This is a non-global data type that is associated with multiple + // clusters: in that case our caller can pass in cluster="", and + // we know that clusterCount > 1, so just set it to 2. + return 2; + } + + const cluster = options.hash.cluster || options.hash.ns; + const typeObj = await zclQuery[`select${dataType}ByNameAndClusterName`]( + db, + type, + cluster, + pkgId + ); + if (typeObj) { + return typeObj[`${dataType.toLowerCase()}ClusterCount`]; + } + + if (options.hash.cluster === undefined) { + // Backwards-compat case: we were called without ns or cluster at all + // (not even cluster=""). Just get by name, since that's all we have to + // work with. It won't work right when names are not unique, but that's + // the best we can do. + // + // selectBitmapByName has different argument ordering from selectEnumByName + // and selectStructByName, so account for that here. + const isBitmap = dataType == 'Bitmap'; + const backwardsCompatTypeObj = await zclQuery[`select${dataType}ByName`]( + db, + isBitmap ? pkgId : type, + isBitmap ? type : pkgId + ); + return backwardsCompatTypeObj[`${dataType.toLowerCase()}ClusterCount`]; + } + + // Something is wrong here. Possibly the caller is passing in a munged + // cluster name. Just fail out instead of silently returning bad data. + throw new Error( + `Unable to find ${dataType.toLowerCase()} ${type} in cluster ${options.hash.cluster}` + ); +} + /* * @brief * @@ -641,12 +687,14 @@ return 'uint' + s[1] + '_t'; } - const enumObj = await zclQuery.selectEnumByName( + const clusterCount = await getClusterCountForType( this.global.db, + pkgId, type, - pkgId + 'Enum', + options ); - const ns = nsValueToNamespace(options.hash.ns, enumObj.enumClusterCount); + const ns = nsValueToNamespace(options.hash.ns, clusterCount); return ns + asUpperCamelCase.call(this, type, options); } @@ -657,15 +705,14 @@ return 'uint' + s[1] + '_t'; } - const bitmapObj = await zclQuery.selectBitmapByName( + const clusterCount = await getClusterCountForType( this.global.db, pkgId, - type + type, + 'Bitmap', + options ); - const ns = nsValueToNamespace( - options.hash.ns, - bitmapObj.bitmapClusterCount - ); + const ns = nsValueToNamespace(options.hash.ns, clusterCount); return ( 'chip::BitMask<' + ns + asUpperCamelCase.call(this, type, options) + '>' ); @@ -673,15 +720,14 @@ if (types.isStruct) { passByReference = true; - const structObj = await zclQuery.selectStructByName( + const clusterCount = await getClusterCountForType( this.global.db, + pkgId, type, - pkgId + 'Struct', + options ); - const ns = nsValueToNamespace( - options.hash.ns, - structObj.structClusterCount - ); + const ns = nsValueToNamespace(options.hash.ns, clusterCount); return ( ns + 'Structs::' + @@ -768,16 +814,14 @@ return 'uint'; } - const enumObj = await zclQuery.selectEnumByName( + const clusterCount = await getClusterCountForType( this.global.db, + pkgId, type, - pkgId + 'Enum', + options ); - - const ns = nsValueToPythonNamespace( - options.hash.ns, - enumObj.enumClusterCount - ); + const ns = nsValueToPythonNamespace(options.hash.ns, clusterCount); return ns + '.Enums.' + type; } @@ -787,16 +831,14 @@ } if (await typeChecker('isStruct')) { - const structObj = await zclQuery.selectStructByName( + const clusterCount = await getClusterCountForType( this.global.db, + pkgId, type, - pkgId + 'Struct', + options ); - - const ns = nsValueToPythonNamespace( - options.hash.ns, - structObj.structClusterCount - ); + const ns = nsValueToPythonNamespace(options.hash.ns, clusterCount); return ns + '.Structs.' + type; } @@ -887,16 +929,14 @@ } if (await typeChecker('isStruct')) { - const structObj = await zclQuery.selectStructByName( + const clusterCount = await getClusterCountForType( this.global.db, + pkgId, type, - pkgId + 'Struct', + options ); - - const ns = nsValueToPythonNamespace( - options.hash.ns, - structObj.structClusterCount - ); + const ns = nsValueToPythonNamespace(options.hash.ns, clusterCount); return 'field(default_factory=lambda: ' + ns + '.Structs.' + type + '())'; } @@ -1073,7 +1113,19 @@ // struct. async function if_is_fabric_scoped_struct(type, options) { let packageIds = await templateUtil.ensureZclPackageIds(this); - let st = await zclQuery.selectStructByName(this.global.db, type, packageIds); + let st; + if (options.hash.cluster) { + st = await zclQuery.selectStructByNameAndClusterName( + this.global.db, + type, + options.hash.cluster, + packageIds + ); + } else { + // Backwards compat case; will not work right when multiple structs share + // the same name. + st = await zclQuery.selectStructByName(this.global.db, type, packageIds); + } if (st && st.isFabricScoped) { return options.fn(this);
diff --git a/src-electron/generator/matter/darwin/Framework/CHIP/templates/helper.js b/src-electron/generator/matter/darwin/Framework/CHIP/templates/helper.js index b986e1e..de23bc6 100644 --- a/src-electron/generator/matter/darwin/Framework/CHIP/templates/helper.js +++ b/src-electron/generator/matter/darwin/Framework/CHIP/templates/helper.js
@@ -240,12 +240,27 @@ } if (isStruct) { - const structObj = await zclQuery.selectStructByName( + let structObj = await zclQuery.selectStructByNameAndClusterName( this.global.db, type, + cluster, pkgIds ); - if (structObj.structClusterCount == 0) { + + let isGlobalStruct; + if (!structObj) { + // Can end up here when our "cluster name" is a backwards compat name. + // Just fetch by struct name only in that case. + structObj = await zclQuery.selectStructByName( + this.global.db, + type, + pkgIds + ); + isGlobalStruct = structObj.structClusterCount == 0; + } else { + isGlobalStruct = !structObj.clusterName; + } + if (isGlobalStruct) { // This is a global struct. return `${ options.hash.structTypePrefix || 'MTR' @@ -297,7 +312,20 @@ } function asStructPropertyName(prop) { - prop = appHelper.asLowerCamelCase(prop); + prop = appHelper.asLowerCamelCase(prop, { hash: { preserveAcronyms: true } }); + + // If prop is now all-uppercase (which can happen, because we are preserving + // acronyms), lowercase it. + if (prop.match(/^[A-Z0-9]+$/)) { + prop = prop.toLowerCase(); + } + + // If prop is now all-uppercase, with at least two capital letters followed by + // a lowercase "s" (probably acronym being pluralized), just lowercase the + // whole thing. + if (prop.match(/^[A-Z][A-Z]+s$/)) { + prop = prop.toLowerCase(); + } // If prop is now "description", we need to rename it, because that's // reserved. @@ -307,8 +335,8 @@ // If prop starts with a sequence of capital letters (which can happen for // output of asLowerCamelCase if the original string started that way), - // lowercase all but the last one. - return prop.replace(/^([A-Z]+)([A-Z])/, (match, p1, p2) => { + // followed by a lowercase letter, lowercase all but the last capital letter. + return prop.replace(/^([A-Z]+)([A-Z][a-z])/, (match, p1, p2) => { return p1.toLowerCase() + p2; }); }
diff --git a/src-electron/importexport/import-json.js b/src-electron/importexport/import-json.js index 35c4624..0c265ee 100644 --- a/src-electron/importexport/import-json.js +++ b/src-electron/importexport/import-json.js
@@ -439,14 +439,10 @@ specMessageIndent ) { let relevantZclPackageIds = allZclPackageIds - // Get all custom xml packages since they will be relevant packages as well. let packageInfo = await queryPackage.getPackagesByPackageIds( db, allZclPackageIds ) - let customPackageInfo = packageInfo.filter( - (pkg) => pkg.type === dbEnum.packageType.zclXmlStandalone - ) let endpointTypeDeviceTypesInfo = await queryDeviceType.selectDeviceTypesByEndpointTypeId(db, endpointTypeId) let deviceTypeRefs = endpointTypeDeviceTypesInfo.map( @@ -457,12 +453,28 @@ db, deviceTypeRefs[0] ) - relevantZclPackageIds = [deviceTypeInfo.packageRef] - - // If custom packages exist then account for them during import. - if (customPackageInfo && customPackageInfo.length > 0) { - let customPackageInfoIds = customPackageInfo.map((cp) => cp.id) - relevantZclPackageIds = relevantZclPackageIds.concat(customPackageInfoIds) + let deviceTypePackageInfo = packageInfo.find( + (pkg) => pkg.id == deviceTypeInfo.packageRef + ) + if ( + deviceTypePackageInfo && + deviceTypePackageInfo.type === dbEnum.packageType.zclXmlStandalone + ) { + // If the device type comes from a custom xml, then we pass in all zcl and custom xml packages + relevantZclPackageIds = packageInfo + .filter( + (pkg) => + pkg.type === dbEnum.packageType.zclXmlStandalone || + pkg.type === dbEnum.packageType.zclProperties + ) + .map((pkg) => pkg.id) + } else { + // If the device types comes from the zcl file, then we pass in that zcl file and all custom xml packages + relevantZclPackageIds = [deviceTypeInfo.packageRef] + let customPackageIds = packageInfo + .filter((pkg) => pkg.type == dbEnum.packageType.zclXmlStandalone) + .map((pkg) => pkg.id) + relevantZclPackageIds = relevantZclPackageIds.concat(customPackageIds) } } let conformanceWarnings = ''
diff --git a/src-electron/rest/user-data.js b/src-electron/rest/user-data.js index 36672d9..4f58247 100644 --- a/src-electron/rest/user-data.js +++ b/src-electron/rest/user-data.js
@@ -330,17 +330,13 @@ let sessionId = request.zapSessionId try { - let packageId = await queryPackage - .getSessionPackagesByType( - db, - sessionId, - dbEnum.packageType.zclProperties - ) - .then((pkgs) => pkgs?.shift()?.id) // default to always picking first package - - if (packageId == null) { - throw new Error('Unable to find packageId') - } + let pkgs = await queryPackage.getSessionPackagesWithTypes(db, sessionId) + pkgs = pkgs.filter( + (pkg) => + pkg.type == dbEnum.packageType.zclProperties || + pkg.type == dbEnum.packageType.zclXmlStandalone + ) + let packageIds = pkgs.map((pkg) => pkg.packageRef) let insertDefault = await queryConfig .selectClusterState(db, endpointTypeId, id, side) @@ -355,10 +351,15 @@ ) if (insertDefault) { - await queryConfig.insertClusterDefaults(db, endpointTypeId, packageId, { - clusterRef: id, - side: side - }) + await queryConfig.insertClusterDefaults( + db, + endpointTypeId, + packageIds, + { + clusterRef: id, + side: side + } + ) } response
diff --git a/src-electron/util/zcl-util.js b/src-electron/util/zcl-util.js index a540f55..8ff2918 100644 --- a/src-electron/util/zcl-util.js +++ b/src-electron/util/zcl-util.js
@@ -110,16 +110,9 @@ } /** - * This method retrieves a bunch of structs sorted - * alphabetically. It's expected to resort the structs into a list - * where they are sorted in a way where dependency is observed. - * - * It uses the DFS-based topological sort algorithm. - * - * @param {*} structs - * @returns sorted structs according to topological search. + * Non-exported helper for sortStructsByDependency. */ -async function sortStructsByDependency(structs) { +function sortStructsByDependencyHelper(structs) { let allStructNames = structs.map((s) => s.name) let edges = [] @@ -147,6 +140,37 @@ } /** + * This method retrieves a bunch of structs sorted + * alphabetically. It's expected to resort the structs into a list + * where they are sorted in a way where dependency is observed. + * + * It uses the DFS-based topological sort algorithm. + * + * @param {*} structs + * @returns sorted structs according to topological search. + */ +async function sortStructsByDependency(structs) { + // Given global and non-global structs, the way dependencies work is this: + // + // 1) Global structs can only depend on other global structs. + // 2) Non-global structs can depend on either non-global or global structs. + // + // So we can output all global structs first (sorted by dependency), and then + // the non-global structs, again sorted by dependency. + // + // NOTE: the topological sort we use is not a stable sort, so adding some + // structs to the list can entirely change the order of all the structs. + let sortedGlobalStructs = sortStructsByDependencyHelper( + structs.filter((s) => s.struct_cluster_count == 0) + ) + let sortedNonGlobalStructs = sortStructsByDependencyHelper( + structs.filter((s) => s.struct_cluster_count != 0) + ) + + return sortedGlobalStructs.concat(sortedNonGlobalStructs) +} + +/** * This function calculates the number of bytes in the data type and based on * that returns the option specified in the template. * for eg: Given that options are as follows:
diff --git a/src-electron/zcl/zcl-loader-silabs.js b/src-electron/zcl/zcl-loader-silabs.js index 2ea3259..bf0549e 100644 --- a/src-electron/zcl/zcl-loader-silabs.js +++ b/src-electron/zcl/zcl-loader-silabs.js
@@ -254,6 +254,20 @@ returnObject.featureFlags = zclProps.featureFlags } + // ZCLDataTypes + if (zclProps.zclDataTypes) { + returnObject.ZCLDataTypes = zclProps.ZCLDataTypes + } else { + returnObject.ZCLDataTypes = [ + 'ARRAY', + 'BITMAP', + 'ENUM', + 'NUMBER', + 'STRING', + 'STRUCT' + ] + } + returnObject.supportCustomZclDevice = zclProps.supportCustomZclDevice returnObject.version = zclProps.version returnObject.description = zclProps.description @@ -524,6 +538,7 @@ max: arg.$.max, minLength: 0, maxLength: arg.$.length ? arg.$.length : null, + defaultValue: arg.$.default ? arg.$.default : null, isArray: arg.$.array == 'true' ? 1 : 0, presentIf: arg.$.presentIf, isNullable: arg.$.isNullable == 'true' ? true : false, @@ -571,6 +586,7 @@ ev.fields.push({ name: field.$.name, type: field.$.type, + defaultValue: field.$.default ? field.$.default : null, isArray: field.$.array == 'true' ? 1 : 0, isNullable: field.$.isNullable == 'true' ? true : false, isOptional: field.$.optional == 'true' ? true : false, @@ -1634,6 +1650,7 @@ fieldIdentifier: lastFieldId, minLength: 0, maxLength: item.$.length ? item.$.length : null, + defaultValue: item.$.default ? item.$.default : null, isWritable: item.$.writable == 'true', isArray: item.$.array == 'true' ? true : false, isEnum: item.$.enum == 'true' ? true : false, @@ -1779,6 +1796,22 @@ } /** + * Processes and reloads device type entities in the database. + * This function is called when a custom xml with device types is reloaded. + * + * @returns {Promise} A promise that resolves after all device types have been reloaded. + */ +async function processReloadDeviceTypes(db, packageId, data, sessionPackages) { + let deviceTypes = data.map((x) => prepareDeviceType(x)) + return queryLoader.reloadDeviceTypes( + db, + packageId, + deviceTypes, + sessionPackages + ) +} + +/** * Process promises for loading the data types * @param {*} db * @param {*} filePath @@ -2708,17 +2741,45 @@ if (result.data) { result.result = await util.parseXml(result.data) delete result.data - // Just adding the cluster attribute and command extensions for a cluster - // because they can be related to any top level package in the .zap config if ( result.customXmlReload && result.result.configurator && - result.result.configurator.clusterExtension + (result.result.configurator.clusterExtension || + result.result.configurator.deviceType) ) { - result.result = { - configurator: { - clusterExtension: result.result.configurator.clusterExtension + // If custom xml has device types, reload them so the device type entities are correctly linked + if (result.result.configurator.deviceType) { + let sessionPackages = await queryPackage.getSessionZclPackages( + db, + sessionId + ) + let knownPackages = sessionPackages + .filter((pkg) => + [ + dbEnum.packageType.zclProperties, + dbEnum.packageType.zclXmlStandalone + ].includes(pkg.type) + ) + .map((pkg) => pkg.packageRef) + await processReloadDeviceTypes( + db, + pkgId, + result.result.configurator.deviceType, + knownPackages + ) + } + // Reload cluster extension to link it to the correct top level package (if it exists) + if (result.result.configurator.clusterExtension) { + result.result = { + configurator: { + clusterExtension: result.result.configurator.clusterExtension + } } + } else { + env.logDebug( + `CRC match for file ${result.filePath} (${result.crc}), skipping parsing.` + ) + delete result.result } } else if ( result.customXmlReload && @@ -2731,6 +2792,7 @@ delete result.result } } + let sessionPackages = await queryPackage.getSessionZclPackages( db, sessionId @@ -2786,6 +2848,23 @@ await queryPackage.insertSessionPackage(db, sessionPartitionId, pkgId, true) await zclLoader.processZclPostLoading(db, pkgId) + + // additional post-processing for custom xml + let knownPackages = sessionPackages + .filter((pkg) => + [ + dbEnum.packageType.zclProperties, + dbEnum.packageType.zclXmlStandalone + ].includes(pkg.type) + ) + .map((pkg) => pkg.packageRef) + await queryDeviceType.updateDeviceTypeReferencesForCustomXml( + db, + pkgId, + knownPackages, + sessionId + ) + return { succeeded: true, packageId: pkgId } } catch (err) { env.logError(`Error reading xml file: ${filePath}\n` + err.message)
diff --git a/src-electron/zcl/zcl-loader.js b/src-electron/zcl/zcl-loader.js index d8e37e5..16527e9 100644 --- a/src-electron/zcl/zcl-loader.js +++ b/src-electron/zcl/zcl-loader.js
@@ -353,8 +353,9 @@ } } else { // This is executed if CRC is found in the database and matches the actual CRC. + // Sending data back when it is a custom xml - if (parentPackageId == null) { + if (packageType === dbEnum.packageType.zclXmlStandalone) { return { filePath: filePath, data: data, @@ -363,6 +364,7 @@ crc: actualCrc } } + env.logDebug( `CRC match for file ${pkg.path} (${pkg.crc}), skipping parsing.` )
diff --git a/src-script/pack-apack-mac.js b/src-script/pack-apack-mac.js index 459eeef..a873278 100644 --- a/src-script/pack-apack-mac.js +++ b/src-script/pack-apack-mac.js
@@ -5,31 +5,48 @@ const pathTo7zip = sevenBin.path7za exports.default = async function (buildResult) { - buildResult?.artifactPaths?.forEach((element) => { + for (const element of buildResult?.artifactPaths || []) { if ( (element.includes('mac') || element.includes('win') || element.includes('linux')) && element.endsWith('.zip') ) { - const myStream = Seven.add( - element, - path.join(buildResult.outDir, '../apack.json'), - { - $progress: true, - $bin: pathTo7zip - } - ) - // myStream.on('end', function () { - // console.log(myStream.info) - // }) + // Add apack.json first + await new Promise((resolve, reject) => { + const myStream1 = Seven.add( + element, // The .zip file (output) + path.join(buildResult.outDir, '../apack.json'), // Add apack.json + { + $progress: true, + $bin: pathTo7zip + } + ) - myStream.on('error', function (err) { - if (err) { - console.log(err.stderr) - throw err - } + myStream1.on('end', resolve) + myStream1.on('error', (err) => { + console.log('Error adding apack.json:', err.stderr) + reject(err) + }) + }) + + // Then add zap.png after apack.json is added + await new Promise((resolve, reject) => { + const myStream2 = Seven.add( + element, // The .zip file (output) + path.join(buildResult.outDir, '../src/assets/zap.png'), // Add zap.png + { + $progress: true, + $bin: pathTo7zip + } + ) + + myStream2.on('end', resolve) + myStream2.on('error', (err) => { + console.log('Error adding zap.png:', err.stderr) + reject(err) + }) }) } - }) + } }
diff --git a/src-script/pack-apack-win-linux.js b/src-script/pack-apack-win-linux.js index 0120f9f..7eaaedc 100644 --- a/src-script/pack-apack-win-linux.js +++ b/src-script/pack-apack-win-linux.js
@@ -6,12 +6,14 @@ context.electronPlatformName === 'win32' || context.electronPlatformName === 'linux' ) { - return scriptUtil.executeCmd({}, 'npx', [ + await scriptUtil.executeCmd({}, 'npx', [ 'copyfiles', '-V', '-f', path.resolve(context.outDir, '../apack.json'), + path.resolve(context.outDir, '../src/assets/zap.png'), context.appOutDir ]) + console.log('Files copied successfully.') } }
diff --git a/src/App.vue b/src/App.vue index 0a623e8..7798897 100644 --- a/src/App.vue +++ b/src/App.vue
@@ -248,6 +248,10 @@ } this.$store.dispatch('zap/updateSelectedEndpoint', endpoint.id) this.$store.commit('zap/toggleEndpointModal', false) + this.$store.dispatch( + 'zap/updateDeviceTypeClustersForSelectedEndpoint', + this.endpointDeviceTypeRef[this.endpointType[endpoint.id]] + ) } }, getAppData() {
diff --git a/src/components/ZclClusterManager.vue b/src/components/ZclClusterManager.vue index 7ea46d3..c55573b 100644 --- a/src/components/ZclClusterManager.vue +++ b/src/components/ZclClusterManager.vue
@@ -199,8 +199,9 @@ }, relevantClusters: { get() { + let relevantClusters = [] if (this.clusters.clusterData) { - return this.clusters.clusterData.filter((cluster) => + relevantClusters = this.clusters.clusterData.filter((cluster) => this.filterString == '' ? true : cluster.label @@ -208,7 +209,7 @@ .includes(this.filterString.toLowerCase()) ) } else { - return this.clusters.filter((cluster) => + relevantClusters = this.clusters.filter((cluster) => this.filterString == '' ? true : cluster.label @@ -216,6 +217,8 @@ .includes(this.filterString.toLowerCase()) ) } + this.$store.commit('zap/setRelevantClusters', relevantClusters) + return relevantClusters } }, enabledClusters: { @@ -227,6 +230,12 @@ return clusters } }, + deviceTypeClustersForSelectedEndpoint: { + get() { + return this.$store.state.zap.endpointTypeView + .deviceTypeClustersForSelectedEndpoint + } + }, filterOptions: { get() { return this.$store.state.zap.clusterManager.filterOptions @@ -302,7 +311,12 @@ .filter((a) => { return typeof this.filter.clusterFilterFn === 'function' ? this.filter.clusterFilterFn(a, { - enabledClusters: this.enabledClusters + enabledClusters: this.enabledClusters, + relevantClusters: this.relevantClusters, + deviceTypeRefsForSelectedEndpoint: + this.endpointDeviceTypeRef[this.selectedEndpointId], + deviceTypeClustersForSelectedEndpoint: + this.deviceTypeClustersForSelectedEndpoint }) : true }) @@ -339,7 +353,12 @@ changeDomainFilter(filter) { this.$store.dispatch('zap/setDomainFilter', { filter: filter, - enabledClusters: this.enabledClusters + enabledClusters: this.enabledClusters, + relevantClusters: this.relevantClusters, + deviceTypeRefsForSelectedEndpoint: + this.endpointDeviceTypeRef[this.selectedEndpointId], + deviceTypeClustersForSelectedEndpoint: + this.deviceTypeClustersForSelectedEndpoint }) }, doActionFilter(filter) {
diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index 04dbff0..b5f88e8 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue
@@ -780,6 +780,10 @@ deviceTypeRefs: deviceTypeRef, endpointTypeRef: res.id }) + this.$store.dispatch( + 'zap/updateDeviceTypeClustersForSelectedEndpoint', + this.endpointDeviceTypeRef[this.endpointType[res.id]] + ) }) }) .catch((err) => console.log('Error in newEpt: ' + err.message)) @@ -861,6 +865,10 @@ deviceTypeRefs: deviceTypeRef, endpointTypeRef: this.endpointReference }) + this.$store.dispatch( + 'zap/updateDeviceTypeClustersForSelectedEndpoint', + deviceTypeRef + ) }, getDeviceOptionLabel(item) { if (item == null || item.deviceTypeRef == null) return ''
diff --git a/src/components/ZclDomainClusterView.vue b/src/components/ZclDomainClusterView.vue index f74b16a..658e903 100644 --- a/src/components/ZclDomainClusterView.vue +++ b/src/components/ZclDomainClusterView.vue
@@ -166,6 +166,14 @@ :options="optionsForCheckboxes" color="primary" type="checkbox" + :disable="{ + client: + getClusterDisableStatus(props.row.id).client || + !getClusterEnableStatus(props.row.id).client, + server: + getClusterDisableStatus(props.row.id).server || + !getClusterEnableStatus(props.row.id).server + }" @update:model-value="handleClusterSelection(props.row.id, $event)" inline /> @@ -239,6 +247,11 @@ props: ['domainName', 'clusters'], mixins: [CommonMixin, uiOptions, EditableAttributesMixin], computed: { + isLegalClusterFilterActive() { + return ( + this.$store.state.zap.clusterManager.filter.label === 'Legal Clusters' + ) + }, isInStandalone: { get() { return this.$store.state.zap.standalone @@ -254,6 +267,18 @@ return this.$store.state.zap.clustersView.recommendedServers } }, + // Includes client clusters which are optional for a device type + optionalClients: { + get() { + return this.$store.state.zap.clustersView.optionalClients + } + }, + // Includes server clusters which are optional for a device type + optionalServers: { + get() { + return this.$store.state.zap.clustersView.optionalServers + } + }, visibleColumns: function () { let names = this.columns.map((x) => x.name) let statusColumn = 'status' @@ -281,6 +306,38 @@ } }, methods: { + getClusterEnableStatus(id) { + // Only enforce constraints if the active filter is "Legal Clusters" + if (!this.isLegalClusterFilterActive) { + return { client: true, server: true } // Allow all actions + } + let isClientRecommended = this.recommendedClients.includes(id) + let isServerRecommended = this.recommendedServers.includes(id) + let isClientOptional = this.optionalClients.includes(id) + let isServerOptional = this.optionalServers.includes(id) + let isClientEnabled = this.selectionClients.includes(id) + let isServerEnabled = this.selectionServers.includes(id) + + return { + client: isClientRecommended || isClientOptional || isClientEnabled, // Allow enabling only if recommended, optional, or already enabled + server: isServerRecommended || isServerOptional || isServerEnabled // Allow enabling only if recommended, optional, or already enabled + } + }, + getClusterDisableStatus(id) { + // Only enforce constraints if the active filter is "Legal Clusters" + if (!this.isLegalClusterFilterActive) { + return { client: false, server: false } // No constraints + } + + let isClientRecommended = this.recommendedClients.includes(id) + let isServerRecommended = this.recommendedServers.includes(id) + let isClientOptional = this.optionalClients.includes(id) + let isServerOptional = this.optionalServers.includes(id) + return { + client: isClientRecommended && !isClientOptional, // Disable if recommended and not optional + server: isServerRecommended && !isServerOptional // Disable if recommended and not optional + } + }, enableAllClusters() { this.clusters.forEach(async (singleCluster) => { await this.updateZclRolesByClusterSelection(singleCluster.id, [ @@ -499,6 +556,57 @@ return tmpEvent }, async handleClusterSelection(id, event) { + const activeFilter = this.$store.state.zap.clusterManager.filter.label + + // Only enforce constraints if the active filter is "Legal Clusters" + if (activeFilter === 'Legal Clusters') { + const disableStatus = this.getClusterDisableStatus(id) + const enableStatus = this.getClusterEnableStatus(id) + + // Prevent disabling recommended client + if (disableStatus.client && event.includes('client') === false) { + this.$q.notify({ + type: 'warning', + position: 'top', + message: + 'You cannot disable a required client cluster for the device types on this endpoint when using a Legal Clusters Filter.' + }) + return + } + + // Prevent disabling recommended server + if (disableStatus.server && event.includes('server') === false) { + this.$q.notify({ + type: 'warning', + position: 'top', + message: + 'You cannot disable a required server cluster for the device types on this endpoint when using a Legal Clusters Filter.' + }) + return + } + + // Prevent enabling non-recommended client + if (!enableStatus.client && event.includes('client') === true) { + this.$q.notify({ + type: 'warning', + position: 'top', + message: + 'You cannot enabled a client cluster not required by the device types on this endpoint when using a Legal Clusters Filter.' + }) + return + } + + // Prevent enabling non-recommended server + if (!enableStatus.server && event.includes('server') === true) { + this.$q.notify({ + type: 'warning', + position: 'top', + message: + 'You cannot enabled a server cluster not required by the device types on this endpoint when using a Legal Clusters Filter.' + }) + return + } + } let modifiedEvent = this.parseCheckboxEventToSelectionEvent(event) let selectionEvents = this.processZclSelectionEvent(id, modifiedEvent)
diff --git a/src/store/zap/actions.js b/src/store/zap/actions.js index f8e3606..4eba9f4 100644 --- a/src/store/zap/actions.js +++ b/src/store/zap/actions.js
@@ -405,27 +405,30 @@ context, endpointTypeIdDeviceTypeRefPair ) { - axiosRequests - .$serverGet( - `${restApi.uri.deviceTypeClusters}${endpointTypeIdDeviceTypeRefPair.deviceTypeRef}` + Promise.all( + endpointTypeIdDeviceTypeRefPair.deviceTypeRef.map((ref) => + axiosRequests.$serverGet(`${restApi.uri.deviceTypeClusters}${ref}`) ) - .then((res) => { - setRecommendedClusterList(context, res.data) - }) - axiosRequests - .$serverGet( - `${restApi.uri.deviceTypeAttributes}${endpointTypeIdDeviceTypeRefPair.deviceTypeRef}` + ).then((responses) => { + const allClusters = responses.flatMap((res) => res.data) + setRecommendedClusterList(context, allClusters) + }) + Promise.all( + endpointTypeIdDeviceTypeRefPair.deviceTypeRef.map((ref) => + axiosRequests.$serverGet(`${restApi.uri.deviceTypeAttributes}${ref}`) ) - .then((res) => { - setRequiredAttributes(context, res.data) - }) - axiosRequests - .$serverGet( - `${restApi.uri.deviceTypeCommands}${endpointTypeIdDeviceTypeRefPair.deviceTypeRef}` + ).then((responses) => { + const allAttributes = responses.flatMap((res) => res.data) + setRequiredAttributes(context, allAttributes) + }) + Promise.all( + endpointTypeIdDeviceTypeRefPair.deviceTypeRef.map((ref) => + axiosRequests.$serverGet(`${restApi.uri.deviceTypeCommands}${ref}`) ) - .then((res) => { - setRequiredCommands(context, res.data) - }) + ).then((responses) => { + const allCommands = responses.flatMap((res) => res.data) + setRequiredCommands(context, allCommands) + }) axiosRequests .$serverGet( @@ -709,33 +712,35 @@ setEventStateLists(context, res.data || []) }) ) - p.push( - axiosRequests - .$serverGet( - `${restApi.uri.deviceTypeClusters}${endpointTypeDeviceTypeRefPair.deviceTypeRef}` + Promise.all( + endpointTypeDeviceTypeRefPair.deviceTypeRef.map((ref) => + axiosRequests.$serverGet(`${restApi.uri.deviceTypeClusters}${ref}`) ) - .then((res) => { - setRecommendedClusterList(context, res.data) - }) + ).then((responses) => { + const allClusters = responses.flatMap((res) => res.data) + setRecommendedClusterList(context, allClusters) + }) ) p.push( - axiosRequests - .$serverGet( - `${restApi.uri.deviceTypeAttributes}${endpointTypeDeviceTypeRefPair.deviceTypeRef}` + Promise.all( + endpointTypeDeviceTypeRefPair.deviceTypeRef.map((ref) => + axiosRequests.$serverGet(`${restApi.uri.deviceTypeAttributes}${ref}`) ) - .then((res) => { - setRequiredAttributes(context, res.data) - }) + ).then((responses) => { + const allAttributes = responses.flatMap((res) => res.data) + setRequiredAttributes(context, allAttributes) + }) ) p.push( - axiosRequests - .$serverGet( - `${restApi.uri.deviceTypeCommands}${endpointTypeDeviceTypeRefPair.deviceTypeRef}` + Promise.all( + endpointTypeDeviceTypeRefPair.deviceTypeRef.map((ref) => + axiosRequests.$serverGet(`${restApi.uri.deviceTypeCommands}${ref}`) ) - .then((res) => { - setRequiredCommands(context, res.data) - }) + ).then((responses) => { + const allCommands = responses.flatMap((res) => res.data) + setRequiredCommands(context, allCommands) + }) ) context.commit( @@ -747,6 +752,25 @@ } /** + * + * @param {*} context + * @param {*} deviceTypeRefs + */ +export async function updateDeviceTypeClustersForSelectedEndpoint( + context, + deviceTypeRefs +) { + let res = await Promise.all( + deviceTypeRefs.map((ref) => + axiosRequests.$serverGet(`${restApi.uri.deviceTypeClusters}${ref}`) + ) + ).then((responses) => { + return responses.flatMap((response) => response.data) + }) + context.commit('updateDeviceTypeClustersForSelectedEndpoint', res) +} + +/** * set client and server cluster lists. * @param {*} context * @param {*} selectionContext @@ -886,14 +910,21 @@ // TODO (?) This does not handle/highlight prohibited clusters. For now we just keep it in here let recommendedClients = [] let recommendedServers = [] + // Collecting optional client and server clusters + let optionalClients = [] + let optionalServers = [] data.forEach((record) => { if (record.includeClient) recommendedClients.push(record.clusterRef) if (record.includeServer) recommendedServers.push(record.clusterRef) + if (!record.lockClient) optionalClients.push(record.clusterRef) + if (!record.lockServer) optionalServers.push(record.clusterRef) }) context.commit(`setRecommendedClusterList`, { recommendedClients: recommendedClients, - recommendedServers: recommendedServers + recommendedServers: recommendedServers, + optionalClients: optionalClients, + optionalServers: optionalServers }) }
diff --git a/src/store/zap/mutations.js b/src/store/zap/mutations.js index a8fa102..96a53b5 100644 --- a/src/store/zap/mutations.js +++ b/src/store/zap/mutations.js
@@ -524,6 +524,19 @@ } /** + * Update the device Type Clusters For Selected Endpoint in endpoint type view state. + * @param {*} state + * @param {*} deviceTypeClustersForSelectedEndpoint + */ +export function updateDeviceTypeClustersForSelectedEndpoint( + state, + deviceTypeClustersForSelectedEndpoint +) { + state.endpointTypeView.deviceTypeClustersForSelectedEndpoint = + deviceTypeClustersForSelectedEndpoint +} + +/** * Remove endpoint type details from the endpoint type view of the state. * @param {*} state * @param {*} endpointType @@ -644,6 +657,8 @@ export function setRecommendedClusterList(state, data) { vue3Set(state.clustersView, 'recommendedClients', data.recommendedClients) vue3Set(state.clustersView, 'recommendedServers', data.recommendedServers) + vue3Set(state.clustersView, 'optionalClients', data.optionalClients) + vue3Set(state.clustersView, 'optionalServers', data.optionalServers) } /** @@ -809,7 +824,12 @@ const openDomainValue = state.clusterManager.filterString === '' ? filter.domainFilterFn(domainName, state.clusterManager.openDomains, { - enabledClusters: filterEnabledClusterPair.enabledClusters + enabledClusters: filterEnabledClusterPair.enabledClusters, + relevantClusters: filterEnabledClusterPair.relevantClusters, + deviceTypeRefsForSelectedEndpoint: + filterEnabledClusterPair.deviceTypeRefsForSelectedEndpoint, + deviceTypeClustersForSelectedEndpoint: + filterEnabledClusterPair.deviceTypeClustersForSelectedEndpoint }) : true setOpenDomain(state, { @@ -1131,6 +1151,15 @@ } /** + * Set the relevant clusters of the state. + * @param {*} state + * @param {*} relevantClusters + */ +export function setRelevantClusters(state, relevantClusters) { + state.relevantClusters = relevantClusters +} + +/** * Updates the entire list of device type features. * @param {*} state * @param {*} data
diff --git a/src/store/zap/state.js b/src/store/zap/state.js index 85f5811..1c39e04 100644 --- a/src/store/zap/state.js +++ b/src/store/zap/state.js
@@ -85,10 +85,26 @@ }, { label: 'Legal Clusters', - domainFilterFn: (domain, currentOpenDomains, context) => - context.enabledClusters.map((a) => a.domainName).includes(domain), - clusterFilterFn: (cluster, context) => - context.enabledClusters.find((a) => cluster.id == a.id) != undefined + domainFilterFn: (domain, currentOpenDomains, context) => { + let clusterRefsFromDeviceTypes = + context.deviceTypeClustersForSelectedEndpoint.map( + (dtc) => dtc.clusterRef + ) + return context.relevantClusters + .filter((c) => clusterRefsFromDeviceTypes.includes(c.id)) + .map((a) => a.domainName) + .includes(domain) + }, + clusterFilterFn: (cluster, context) => { + let clusterRefsFromDeviceTypes = + context.deviceTypeClustersForSelectedEndpoint.map( + (dtc) => dtc.clusterRef + ) + return context.relevantClusters + .filter((c) => clusterRefsFromDeviceTypes.includes(c.id)) + .map((c) => c.id) + .includes(cluster.id) + } } ], actionOptions: [ @@ -115,7 +131,8 @@ name: {}, deviceTypeRef: {}, deviceVersion: {}, - deviceIdentifier: {} + deviceIdentifier: {}, + deviceTypeClustersForSelectedEndpoint: {} }, clustersView: { selected: [], @@ -123,7 +140,9 @@ selectedClients: [], // These are based off of the selected ZCL Endpoints Device Type recommendedClients: [], - recommendedServers: [] + recommendedServers: [], + optionalClients: [], + optionalServers: [] }, attributeView: { selectedAttributes: [], @@ -179,6 +198,7 @@ deviceIdentifier: null }, notificationCount: 0, - enabledClusters: [] + enabledClusters: [], + relevantClusters: [] } }
diff --git a/src/tutorials/CMPTour.vue b/src/tutorials/CMPTour.vue index 7c55009..62638fd 100644 --- a/src/tutorials/CMPTour.vue +++ b/src/tutorials/CMPTour.vue
@@ -202,6 +202,10 @@ } }) this.$store.dispatch('zap/updateSelectedEndpoint', res.id) + this.$store.dispatch( + 'zap/updateDeviceTypeClustersForSelectedEndpoint', + this.endpointDeviceTypeRef[this.endpointType[res.id]] + ) resolve() }) })
diff --git a/src/tutorials/EndpointTour.vue b/src/tutorials/EndpointTour.vue index 9df6d46..32b323d 100644 --- a/src/tutorials/EndpointTour.vue +++ b/src/tutorials/EndpointTour.vue
@@ -170,6 +170,10 @@ } }) this.$store.dispatch('zap/updateSelectedEndpoint', res.id) + this.$store.dispatch( + 'zap/updateDeviceTypeClustersForSelectedEndpoint', + this.endpointDeviceTypeRef[this.endpointType[res.id]] + ) resolve() }) })
diff --git a/src/util/common-mixin.js b/src/util/common-mixin.js index 4568940..22950c6 100644 --- a/src/util/common-mixin.js +++ b/src/util/common-mixin.js
@@ -40,6 +40,12 @@ return this.$store.state.zap.endpointTypeView.deviceTypeRef } }, + deviceTypeClustersForSelectedEndpoint: { + get() { + return this.$store.state.zap.endpointTypeView + .deviceTypeClustersForSelectedEndpoint + } + }, endpointDeviceVersion: { get() { return this.$store.state.zap.endpointTypeView.deviceVersion @@ -225,6 +231,10 @@ deviceTypeRefs: deviceTypeRefs, endpointTypeRef: endpointReference }) + this.$store.dispatch( + 'zap/updateDeviceTypeClustersForSelectedEndpoint', + deviceTypeRefs + ) }, sdkExtClusterCode(extEntry) { return extEntry ? extEntry.entityCode : '' @@ -402,7 +412,7 @@ return zclProperty.category } else { zclProperty = this.$store.state.zap.packages.find( - (item) => item.pkg.id === packageRef && item.pkg.category + (item) => item.pkg.id === packageRef ) return zclProperty.pkg?.category }
diff --git a/test/custom-matter-xml.test.js b/test/custom-matter-xml.test.js index 8bd1805..b0d5bc9 100644 --- a/test/custom-matter-xml.test.js +++ b/test/custom-matter-xml.test.js
@@ -114,7 +114,7 @@ let result = await zclLoader.loadIndividualFile( db, - testUtil.testMattterCustomXml, + testUtil.testMatterCustomXml, sid ) if (!result.succeeded) { @@ -169,7 +169,7 @@ // second xml adds 2 attributes and 2 commands to prevoiusly extended cluster let result = await zclLoader.loadIndividualFile( db, - testUtil.testMattterCustomXml2, + testUtil.testMatterCustomXml2, sid ) if (!result.succeeded) { @@ -204,7 +204,7 @@ let result = await zclLoader.loadIndividualFile( db, - testUtil.testMattterCustomXml, + testUtil.testMatterCustomXml, sid ) @@ -244,7 +244,7 @@ /* re-adding the custom xml package should re-enable it */ result = await zclLoader.loadIndividualFile( db, - testUtil.testMattterCustomXml, + testUtil.testMatterCustomXml, sid ) expect(result.succeeded).toBeTruthy() @@ -430,6 +430,8 @@ expect(sdkExt).toContain( "/ command: 0x0006 / 0xFFF201 => SampleMfgSpecificToggleWithTransition2, test extension: ''" ) + expect(sdkExt).toContain('transitionTime - int16u') + expect(sdkExt).toContain('transitionTime - int16u - default_value=0x0003') // checking if baseType for command arguments derived from custom xml is accurate expect(sdkExt).toContain( 'Sample Custom Cluster - AddArgumentsResponse\n returnValue - int8u' @@ -444,6 +446,10 @@ '{ (uint16_t)0x0, (uint16_t)0x0, (uint16_t)0xFFFF }, /* Sample Mfg Specific Attribute 2 */ \\' ) + let endpointOut = genResult.content['endpoints.out'] + expect(endpointOut).not.toBeNull() + expect(endpointOut).toContain('- SampleMfgSpecificOnWithTransition2: /') + // delete custom xml and generate again sessionPartitionInfo = await querySession.selectSessionPartitionInfoFromPackageId( @@ -493,18 +499,18 @@ expect(state.endpointTypes[0].clusters.length).toBe(8) // Modify custom xml and reupload - const originalData = fs.readFileSync(testUtil.testMattterCustomXml, 'utf8') + const originalData = fs.readFileSync(testUtil.testMatterCustomXml, 'utf8') try { const modifiedData = originalData.replace( '<name>Sample Custom Cluster</name>', '<name>Sample Custom Changed</name>' ) - fs.writeFileSync(testUtil.testMattterCustomXml, modifiedData, 'utf8') + fs.writeFileSync(testUtil.testMatterCustomXml, modifiedData, 'utf8') const result = await zclLoader.loadIndividualFile( db, - testUtil.testMattterCustomXml, + testUtil.testMatterCustomXml, sid ) expect(result.succeeded).toBeTruthy() @@ -541,7 +547,7 @@ let customXmlPackages = await dbApi.dbAll( db, 'SELECT * FROM PACKAGE WHERE PATH = ?', - [testUtil.testMattterCustomXml] + [testUtil.testMatterCustomXml] ) expect(customXmlPackages.length).toEqual(2) expect( @@ -549,7 +555,7 @@ ).toBeTruthy() } finally { // restore original custom xml - fs.writeFileSync(testUtil.testMattterCustomXml, originalData, 'utf8') + fs.writeFileSync(testUtil.testMatterCustomXml, originalData, 'utf8') } }, testUtil.timeout.long() @@ -561,7 +567,7 @@ // adding bad custom xml with type contradiction should throw warning let result = await zclLoader.loadIndividualFile( db, - testUtil.testBadMattterCustomXml, + testUtil.testBadMatterCustomXml, sid ) expect(result.succeeded).toBeTruthy() @@ -624,7 +630,7 @@ let result = await zclLoader.loadIndividualFile( db, - testUtil.testMattterCustomXml, + testUtil.testMatterCustomXml, conflictSid ) expect(result.succeeded).toBeTruthy()
diff --git a/test/custom-xml-device-type.test.js b/test/custom-xml-device-type.test.js new file mode 100644 index 0000000..b5a4a94 --- /dev/null +++ b/test/custom-xml-device-type.test.js
@@ -0,0 +1,286 @@ +/** + * + * Copyright (c) 2025 Silicon Labs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * @jest-environment node + */ + +/** + * This file tests device types through custom XML files. + * + * Tests are dependent on each other, please be cautious when changing or adding tests. + */ + +const fs = require('fs') +const dbApi = require('../src-electron/db/db-api') +const zclLoader = require('../src-electron/zcl/zcl-loader') +const env = require('../src-electron/util/env') +const testUtil = require('./test-util') +const testQuery = require('./test-query') +const querySession = require('../src-electron/db/query-session') +const queryPackage = require('../src-electron/db/query-package') +const queryPackageNotification = require('../src-electron/db/query-package-notification') +const querySessionNotification = require('../src-electron/db/query-session-notification') +const queryDeviceType = require('../src-electron/db/query-device-type') +const queryConfig = require('../src-electron/db/query-config') +const queryEndpoint = require('../src-electron/db/query-endpoint') +const queryZcl = require('../src-electron/db/query-zcl') +const queryAttribute = require('../src-electron/db/query-attribute') +const exportJs = require('../src-electron/importexport/export') +const util = require('../src-electron/util/util') +const restApi = require('../src-shared/rest-api.js') +const genEngine = require('../src-electron/generator/generation-engine') +const importJs = require('../src-electron/importexport/import') +const { + loadIndividualSilabsFile +} = require('../src-electron/zcl/zcl-loader-silabs.js') +let db +let sid +let mainPackageId +let customDeviceType +let templateContext + +beforeAll(async () => { + env.setDevelopmentEnv() + let file = env.sqliteTestFile('custom-xml-device-type') + db = await dbApi.initDatabaseAndLoadSchema( + file, + env.schemaFile(), + env.zapVersion() + ) + ctx = await zclLoader.loadZcl(db, env.builtinSilabsZclMetafile()) + mainPackageId = ctx.packageId + let uuid = util.createUuid() + sid = await testQuery.createSession( + db, + 'USER', + uuid, + env.builtinSilabsZclMetafile() + ) + // loading templates + templateContext = await genEngine.loadTemplates( + db, + testUtil.testTemplate.zigbee + ) +}, testUtil.timeout.medium()) + +afterAll(() => dbApi.closeDatabase(db), testUtil.timeout.short()) + +test('Load custom xml with Device Type', async () => { + // load first custom xml (device type being loaded refers to cluster from this file) + let result = await zclLoader.loadIndividualFile( + db, + testUtil.testCustomXml2, + sid + ) + expect(result.succeeded).toBe(true) + + // load custom xml with device type + result = await zclLoader.loadIndividualFile( + db, + testUtil.testCustomXmlDeviceType, + sid + ) + + // Check if device type is loaded into the database + customDeviceType = await queryDeviceType.selectDeviceTypeByCodeAndName( + db, + result.packageId, + 0x0001, + 'DUT-Client' + ) + expect(customDeviceType).not.toBeNull() + expect(customDeviceType.name).toBe('DUT-Client') + + // Check if device type clusters are correctly populated + let deviceTypeClusters = + await queryDeviceType.selectDeviceTypeClustersByDeviceTypeRef( + db, + customDeviceType.id + ) + expect(deviceTypeClusters.length).toBe(4) + + // Ensure each deviceTypeCluster has a non-null clusterRef + deviceTypeClusters.forEach((cluster) => { + expect(cluster.clusterRef).not.toBeNull() + }) + + let customDeviceTypeCluster = deviceTypeClusters.find( + (cluster) => cluster.clusterName === 'Custom Cluster' + ) + expect(customDeviceTypeCluster).not.toBeNull() + + let deviceTypeAttributes = + await queryDeviceType.selectDeviceTypeCommandsByDeviceTypeRef( + db, + customDeviceType.id + ) + + expect(deviceTypeAttributes.length).toBe(2) +}) + +test('Generation with custom xml with Device Type', async () => { + let sessionPartitionInfo = + await querySession.selectSessionPartitionInfoFromDeviceType( + db, + sid, + customDeviceType.id + ) + + // Inserting endpoint type with custom xml device type + let eptTypeId = await queryConfig.insertEndpointType( + db, + sessionPartitionInfo[0], + 'EPT', + customDeviceType.id, + customDeviceType.code, + 0, + true + ) + expect(eptTypeId).not.toBeNull() + + eptId = await queryEndpoint.insertEndpoint(db, sid, 1, eptTypeId, 0, 0) + + let genResult = await genEngine.generate( + db, + sid, + templateContext.packageId, + {}, + { + generateOnly: [ + 'sdk-extension.out', + 'zap-config.h', + 'zap-config-version-2.h' + ], + disableDeprecationWarnings: true + } + ) + expect(genResult.hasErrors).toBeFalsy() + + // Check if the generated files contain the expected content + let sdkExt = genResult.content['sdk-extension.out'] + expect(sdkExt).toContain( + "// device type: CUSTOM_DUT / 0x0001 => DUT-Client // extension: ''" + ) + expect(sdkExt).toContain( + "// device type: CUSTOM_DUT / 0x0002 => DUT-Server // extension: ''" + ) + + let zapConfig = genResult.content['zap-config.h'] + expect(zapConfig).toContain( + '{ 0x00000000, ZAP_ATTRIBUTE_INDEX(0), 0, 0, ZAP_CLUSTER_MASK(CLIENT), NULL }, /* Endpoint: 1, Cluster: Basic (client) */ \\' + ) + expect(zapConfig).toContain( + '{ 0x00000006, ZAP_ATTRIBUTE_INDEX(0), 0, 0, ZAP_CLUSTER_MASK(CLIENT), NULL }, /* Endpoint: 1, Cluster: On/off (client) */ \\' + ) + expect(zapConfig).toContain( + '{ 0x10E0FCA7, ZAP_ATTRIBUTE_INDEX(0), 0, 0, ZAP_CLUSTER_MASK(CLIENT), NULL }, /* Endpoint: 1, Cluster: Custom Cluster (client) */ \\' + ) + expect(zapConfig).toContain( + '{ 0xABCDFFCD, ZAP_ATTRIBUTE_INDEX(0), 0, 0, ZAP_CLUSTER_MASK(CLIENT), NULL }, /* Endpoint: 1, Cluster: Test Cluster - Device Type (client) */ \\' + ) + + let zapConfigVer2 = genResult.content['zap-config-version-2.h'] + expect(zapConfigVer2).toContain( + '{ 0x0302, ZCL_INT8U_ATTRIBUTE_TYPE, 1, (ATTRIBUTE_MASK_MANUFACTURER_SPECIFIC| ATTRIBUTE_MASK_CLIENT), { (uint8_t*)0 } }, /* 2 Cluster: Custom Cluster, Attribute: A9, Side: client*/ \\' + ) + expect(zapConfigVer2).toContain( + '{ 0x0006, 0x02, COMMAND_MASK_OUTGOING_CLIENT }, /* 2, Cluster: On/off, Command: Toggle*/ \\' + ) + expect(zapConfigVer2).toContain( + '{ 0xFFCD, 0x00, COMMAND_MASK_OUTGOING_CLIENT | COMMAND_MASK_MANUFACTURER_SPECIFIC }, /* 15, Cluster: Test Cluster - Device Type, Command: CommandOne*/ \\' + ) +}) + +test('Load same custom xml with different zcl file', async () => { + await zclLoader.loadZcl(db, env.builtinMatterZclMetafile()) + let uuid = util.createUuid() + let newSid = await testQuery.createSession( + db, + 'USER', + uuid, + env.builtinMatterZclMetafile() + ) + + // load custom xml with device type + result = await zclLoader.loadIndividualFile( + db, + testUtil.testCustomXmlDeviceType, + newSid + ) + expect(result.succeeded).toBe(true) + + // Check if new device type cluster is correctly added + // There should be a new device type cluster for on/off with clusterRef from the matter zcl file + let deviceTypeClusters = + await queryDeviceType.selectDeviceTypeClustersByDeviceTypeRef( + db, + customDeviceType.id + ) + expect(deviceTypeClusters.length).toBe(5) + + // Check if correct errors are thrown for unlinked clusters + let sessionNotif = await querySessionNotification.getNotification(db, newSid) + expect( + sessionNotif.some( + (notif) => + notif.type === 'ERROR' && + notif.message.includes( + 'Cluster "Basic" in device type DUT-Client is not found in the current session' + ) && + notif.message.includes('custom-device-type.xml') + ) + ).toBeTruthy() +}) + +test(`Load .zap file with custom xml with Device Type`, async () => { + let newSid = await querySession.createBlankSession(db) + + // importing a zap file that has an endpoint with custom xml device type + let importResult = await importJs.importDataFromFile( + db, + testUtil.testMatterCustomZap2, + { + sessionId: newSid + } + ) + + expect(importResult.templateIds.length).toBe(1) + + let genResult = await genEngine.generate( + db, + newSid, + importResult.templateIds[0], + {}, + { + generateOnly: ['endpoint-config.c', 'endpoints.out'], + disableDeprecationWarnings: true + } + ) + expect(genResult.hasErrors).toBeFalsy() + + // Check if the generated files contain the expected content + let endpoints = genResult.content['endpoints.out'] + expect(endpoints).toContain(' >> device: DUT-Server [2]') + + let endpointConfig = genResult.content['endpoint-config.c'] + expect(endpointConfig).toContain( + '{ 0x00000000, ZAP_TYPE(BOOLEAN), 1, 0, ZAP_SIMPLE_DEFAULT(0) }, /* OnOff */ \\' + ) + expect(endpointConfig).toContain( + '/* Endpoint: 1, Cluster: Test Cluster - Device Type (server) */ \\' + ) +})
diff --git a/test/gen-matter-1.test.js b/test/gen-matter-1.test.js index 93e6190..590c42c 100644 --- a/test/gen-matter-1.test.js +++ b/test/gen-matter-1.test.js
@@ -293,6 +293,21 @@ expect(simpleTest).toContain( 'zcl command arguments do not exist for AddSceneResponse command.' ) + + // Testing default values for command arguments, event fields and struct items + expect(sdkExt).toContain('ProductID - int16u - default_value=0x01') + expect(sdkExt).toContain( + 'RequestorCanConsent - boolean - default_value=false' + ) + expect(sdkExt).toContain( + 'Struct name: ChannelInfoStruct, Struct Item Name: MajorNumber, Struct Item Type: int16u, Struct Default Value: 0xFFFF' + ) + expect(sdkExt).not.toContain('SoftwareVersion - int32u - default_value=') + let eventOut = genResult.content['events.out'] + expect(eventOut).toContain( + '> Field: SoftwareVersion default_value=0x00000000' + ) + expect(eventOut).not.toContain('> Field: ProductID default_value=') }, testUtil.timeout.long() )
diff --git a/test/gen-matter-3-1.test.js b/test/gen-matter-3-1.test.js index 4920f70..90d53e3 100644 --- a/test/gen-matter-3-1.test.js +++ b/test/gen-matter-3-1.test.js
@@ -29,6 +29,7 @@ const queryEndpoint = require('../src-electron/db/query-endpoint') const queryEndpointType = require('../src-electron/db/query-endpoint-type') const queryConfig = require('../src-electron/db/query-config') +const queryZcl = require('../src-electron/db/query-zcl') const queryDeviceType = require('../src-electron/db/query-device-type') const util = require('../src-electron/util/util') const testQuery = require('./test-query') @@ -521,6 +522,51 @@ 'SemanticTagStruct item 3 from Identify cluster: Label' ) expect(ept).not.toContain('SemanticTagStruct item 4 from Identify cluster') + + // Testing selectStructByNameAndClusterName for struct names + let globalStruct = await queryZcl.selectStructByNameAndClusterName( + db, + 'SemanticTagStruct', + 'Descriptor', + zclPackageId + ) + let clusterStruct = await await queryZcl.selectStructByNameAndClusterName( + db, + 'SemanticTagStruct', + 'Mode Select', + zclPackageId + ) + expect(globalStruct.id).not.toEqual(clusterStruct.id) + + // Testing selectEnumByNameAndClusterName for enum names + let globalEnum = await queryZcl.selectEnumByNameAndClusterName( + db, + 'enumTest', + 'Descriptor', + zclPackageId + ) + let clusterEnum = await queryZcl.selectEnumByNameAndClusterName( + db, + 'enumTest', + 'Mode Select', + zclPackageId + ) + expect(globalEnum.id).not.toEqual(clusterEnum.id) + + // Testing selectBitmapByNameAndClusterName for bitmap names + let globalBitmap = await queryZcl.selectBitmapByNameAndClusterName( + db, + 'bitmapTest', + 'Descriptor', + zclPackageId + ) + let clusterBitmap = await queryZcl.selectBitmapByNameAndClusterName( + db, + 'bitmapTest', + 'Mode Select', + zclPackageId + ) + expect(globalBitmap.id).not.toEqual(clusterBitmap.id) }, testUtil.timeout.long() )
diff --git a/test/gen-template/matter/events.zapt b/test/gen-template/matter/events.zapt index a6dd685..d1b6053 100644 --- a/test/gen-template/matter/events.zapt +++ b/test/gen-template/matter/events.zapt
@@ -3,6 +3,6 @@ {{#zcl_events}} >> Event: {{name}} {{#zcl_event_fields}} - > Field: {{name}} {{#if_is_enum type}}[ENUM]{{/if_is_enum}}{{#if_is_bitmap type}}[BITMAP]{{/if_is_bitmap}} + > Field: {{name}} {{#if_is_enum type}}[ENUM]{{/if_is_enum}}{{#if_is_bitmap type}}[BITMAP]{{/if_is_bitmap}} {{#if defaultValue}}default_value={{defaultValue}}{{/if}} {{/zcl_event_fields}} {{/zcl_events}} \ No newline at end of file
diff --git a/test/gen-template/matter/sdk-ext.zapt b/test/gen-template/matter/sdk-ext.zapt index 8f097d6..4a436ac 100644 --- a/test/gen-template/matter/sdk-ext.zapt +++ b/test/gen-template/matter/sdk-ext.zapt
@@ -23,7 +23,7 @@ {{#zcl_commands_with_arguments sortBy="signature"}} {{clusterName}} - {{commandName}} {{#zcl_command_arguments}} - {{label}} - {{baseType}} + {{label}} - {{baseType}} {{#if defaultValue}}- default_value={{defaultValue}}{{/if}} {{/zcl_command_arguments}} {{/zcl_commands_with_arguments}} @@ -54,3 +54,9 @@ IMPLEMENTED_COMMANDS2>{{#all_user_clusters}}{{#all_user_cluster_commands_irrespective_of_manufaturing_specification name side}}{{#if_command_extension_true property="implementedCommands"}}{{name}},{{/if_command_extension_true}}{{/all_user_cluster_commands_irrespective_of_manufaturing_specification}}{{/all_user_clusters}}<END2 +------------------- Structs ------------------- +{{#zcl_structs}} +{{#zcl_struct_items}} +Struct name: {{../name}}, Struct Item Name: {{./name}}, Struct Item Type: {{./type}}, {{#if defaultValue}}Struct Default Value: {{defaultValue}}{{/if}} +{{/zcl_struct_items}} +{{/zcl_structs}} \ No newline at end of file
diff --git a/test/gen-zigbee-7.test.js b/test/gen-zigbee-7.test.js index 4579b65..94b19a0 100644 --- a/test/gen-zigbee-7.test.js +++ b/test/gen-zigbee-7.test.js
@@ -148,7 +148,7 @@ db, customDeviceType.id ) - expect(deviceTypeClusters.length).toBe(2) // 2 device type clusters associated with this device type. + expect(deviceTypeClusters.length).toBe(4) // 4 device type clusters associated with this device type. }, testUtil.timeout.long() )
diff --git a/test/helpers.test.js b/test/helpers.test.js index 7f0fab1..bf949a1 100644 --- a/test/helpers.test.js +++ b/test/helpers.test.js
@@ -479,6 +479,28 @@ ) test( + 'Generated Macro for 4 byte integer little endian', + () => { + let options = { hash: { endian: 'little' } } + return zclHelper + .as_generated_default_macro('1600', 4, options) + .then((res) => expect(res).toBe('0x40, 0x06, 0x00, 0x00,')) + }, + testUtil.timeout.short() +) + +test( + 'Generated Macro for 4 byte integer big endian', + () => { + let options = { hash: { endian: 'big' } } + return zclHelper + .as_generated_default_macro('1600', 4, options) + .then((res) => expect(res).toBe('0x00, 0x00, 0x06, 0x40,')) + }, + testUtil.timeout.short() +) + +test( 'Generated Macro for string', () => { let options = { hash: { endian: 'big' } }
diff --git a/test/resource/custom-cluster/custom-device-type.xml b/test/resource/custom-cluster/custom-device-type.xml index 869574e..cd1271f 100644 --- a/test/resource/custom-cluster/custom-device-type.xml +++ b/test/resource/custom-cluster/custom-device-type.xml
@@ -8,8 +8,19 @@ <profileId editable="false">0xC001</profileId> <deviceId editable="false">0x0001</deviceId> <clusters lockOthers="true"> - <include client="true" server="false" clientLocked="true" serverLocked="true" >Test Cluster</include> + <!-- Cluster from same file --> + <include cluster="Test Cluster - Device Type" client="true" server="false" clientLocked="true" serverLocked="true" > + <requireCommand>CommandOne</requireCommand> + </include> + + <!-- Cluster from primary zcl file --> <include cluster="Basic" client="true" server="false" clientLocked="true" serverLocked="true"></include> + <include cluster="On/Off" client="true" server="false" clientLocked="true" serverLocked="true"></include> + + <!-- Cluster from other custom xml --> + <include cluster="Custom Cluster" client="true" server="false" clientLocked="true" serverLocked="true"> + <requireCommand>C1</requireCommand> + </include> </clusters> </deviceType> <deviceType> @@ -20,8 +31,38 @@ <profileId editable="false">0xC001</profileId> <deviceId editable="false">0x0002</deviceId> <clusters lockOthers="true"> - <include client="false" server="true" clientLocked="true" serverLocked="true" >Test Cluster</include> + <!-- Cluster from same file --> + <include cluster="Test Cluster - Device Type" client="false" server="true" clientLocked="true" serverLocked="true" > + <requireAttribute>sample attribute</requireAttribute> + </include> + + <!-- Cluster from primary zcl file --> <include cluster="Basic" client="false" server="true" clientLocked="true" serverLocked="true"></include> + <include cluster="On/Off" client="false" server="true" clientLocked="true" serverLocked="true"></include> + + <!-- Cluster from other custom xml --> + <include cluster="Custom Cluster" client="false" server="true" clientLocked="true" serverLocked="true"></include> </clusters> - </deviceType> + </deviceType> + + <cluster manufacturerCode="0xABCD"> + <name>Test Cluster - Device Type</name> + <domain>Ember</domain> + <description> This cluster is used to test device types through custom xml file + </description> + <!-- Cluster Id must be within the mfg spec range 0xfc00 - 0xffff --> + <code>0xFFCD</code> + <define>TEST_CLUSTER_DEVICE_TYPE</define> + <client init="false" tick="false">true</client> + <server init="false" tick="false">true</server> + <attribute side="server" code="0x0000" define="ATTRIBUTE_ONE" type="INT8U" min="0x00" max="0xFF" writable="true" default="0x00" optional="true">sample attribute</attribute> + <attribute side="server" code="0x0001" define="ATTRIBUTE_TWO" type="INT8U" min="0x00" max="0xFF" writable="true" default="0x00" optional="true">sample attribute 2</attribute> + <command source="client" code="0x00" name="CommandOne" optional="true"> + <description> + A sample manufacturer specific command within the sample cluster. + </description> + <arg name="argOne" type="INT8U"/> + </command> + </cluster> + </configurator>
diff --git a/test/resource/custom-cluster/custom-dut.xml b/test/resource/custom-cluster/custom-dut.xml index f11c568..e9821b7 100644 --- a/test/resource/custom-cluster/custom-dut.xml +++ b/test/resource/custom-cluster/custom-dut.xml
@@ -129,6 +129,10 @@ type="INT16U" min="0" writable="false" default="0" optional="true">A8</attribute> + <attribute manufacturerCode="0x10e0" side="client" code="0x0302" define="A9" + type="INT8U" min="0" max="0xFF" writable="false" + default="0" optional="false">A9</attribute> + <!-- COMMANDS --> <!-- Client Commands --> <command source="client" code="0x00"
diff --git a/test/resource/custom-cluster/matter-custom.xml b/test/resource/custom-cluster/matter-custom.xml index beda6e9..67c1468 100644 --- a/test/resource/custom-cluster/matter-custom.xml +++ b/test/resource/custom-cluster/matter-custom.xml
@@ -15,7 +15,7 @@ limitations under the License. --> <configurator> -<domain name="CHIP"/> +<domain name="CHIP"/> <cluster> <domain>General</domain> <name>Sample Custom Cluster</name> @@ -24,9 +24,9 @@ <description>The Sample MEI cluster showcases cluster manufacturer extensions</description> <!-- Attributes --> <!-- A simple boolean attribute that flips or flops --> - <attribute side="server" code="0x0000" define="FLIP_FLOP" type="BOOLEAN" writable="true" default="false" optional="false">FlipFlop</attribute> + <attribute side="server" code="0x0000" define="FLIP_FLOP" type="BOOLEAN" writable="true" default="false">FlipFlop</attribute> <!-- Command Responses --> - <command source="server" code="0x01" name="AddArgumentsResponse" optional="false" disableDefaultResponse="true"> + <command source="server" code="0x01" name="AddArgumentsResponse" disableDefaultResponse="true"> <description> Response for AddArguments that returns the sum. </description> @@ -34,7 +34,7 @@ </command> <!-- Commands --> - <command source="client" code="0x02" name="AddArguments" response="AddArgumentsResponse" optional="false"> + <command source="client" code="0x02" name="AddArguments" response="AddArgumentsResponse"> <description> Command that takes two uint8 arguments and returns their sum. </description> @@ -42,7 +42,7 @@ <arg name="arg2" type="INT8U"/> </command> - <command source="client" code="0x00" name="Ping" optional="false"> + <command source="client" code="0x00" name="Ping"> <description> Simple command without any parameters and without a response. </description> @@ -54,9 +54,11 @@ <clusterExtension code="0x0006"> <attribute side="server" code="0xFFF10000" define="SAMPLE_MFG_SPECIFIC_TRANSITION_TIME_2" type="INT8U" min="0x0000" max="0xFFFF" writable="true" default="0x0000" optional="true">Sample Mfg Specific Attribute 2</attribute> <attribute side="server" code="0xFFF10001" define="SAMPLE_MFG_SPECIFIC_TRANSITION_TIME_4" type="INT16U" min="0x0000" max="0xFFFF" writable="true" default="0x0000" optional="true">Sample Mfg Specific Attribute 4</attribute> - <command source="client" code="0xFFF100" name="SampleMfgSpecificOnWithTransition2" optional="true"> + <command source="client" code="0xFFF100" name="SampleMfgSpecificOnWithTransition2"> <description>Client command that turns the device on with a transition given by the transition time in the Ember Sample transition time attribute.</description> + <arg name="transitionMode" type="INT8U"/> + <arg name="transitionTime" type="INT16U" default="0x0003"/> </command> <command source="client" code="0xFFF101" name="SampleMfgSpecificToggleWithTransition2" optional="true"> <description>Client command that toggles the device with a transition given
diff --git a/test/resource/custom-cluster/matterCustomDeviceType.zap b/test/resource/custom-cluster/matterCustomDeviceType.zap new file mode 100644 index 0000000..138bf54 --- /dev/null +++ b/test/resource/custom-cluster/matterCustomDeviceType.zap
@@ -0,0 +1,2691 @@ +{ + "fileFormat": 2, + "featureLevel": 106, + "creator": "zap", + "keyValuePairs": [ + { + "key": "commandDiscovery", + "value": "1" + }, + { + "key": "defaultResponsePolicy", + "value": "always" + }, + { + "key": "manufacturerCodes", + "value": "0x1002" + } + ], + "package": [ + { + "pathRelativity": "relativeToZap", + "path": "../../../zcl-builtin/matter/zcl.json", + "type": "zcl-properties", + "category": "matter", + "version": 1, + "description": "Matter SDK ZCL data" + }, + { + "pathRelativity": "relativeToZap", + "path": "../../gen-template/matter/gen-test.json", + "type": "gen-templates-json", + "category": "matter", + "version": "test-matter" + }, + { + "pathRelativity": "relativeToZap", + "path": "custom-device-type.xml", + "type": "zcl-xml-standalone" + } + ], + "endpointTypes": [ + { + "id": 1, + "name": "MA-rootdevice", + "deviceTypeRef": { + "code": 22, + "profileId": 259, + "label": "MA-rootdevice", + "name": "MA-rootdevice", + "deviceTypeOrder": 0 + }, + "deviceTypes": [ + { + "code": 22, + "profileId": 259, + "label": "MA-rootdevice", + "name": "MA-rootdevice", + "deviceTypeOrder": 0 + } + ], + "deviceVersions": [ + 1 + ], + "deviceIdentifiers": [ + 22 + ], + "deviceTypeName": "MA-rootdevice", + "deviceTypeCode": 22, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Access Control", + "code": 31, + "mfgCode": null, + "define": "ACCESS_CONTROL_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "ACL", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Extension", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SubjectsPerAccessControlEntry", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TargetsPerAccessControlEntry", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AccessControlEntriesPerFabric", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Basic Information", + "code": 40, + "mfgCode": null, + "define": "BASIC_INFORMATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DataModelRevision", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "VendorName", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "VendorID", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "vendor_id", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ProductName", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ProductID", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NodeLabel", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Location", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "HardwareVersion", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "HardwareVersionString", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SoftwareVersion", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SoftwareVersionString", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CapabilityMinima", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "CapabilityMinimaStruct", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 1, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 1, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Localization Configuration", + "code": 43, + "mfgCode": null, + "define": "LOCALIZATION_CONFIGURATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "ActiveLocale", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportedLocales", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Time Format Localization", + "code": 44, + "mfgCode": null, + "define": "TIME_FORMAT_LOCALIZATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "HourFormat", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "HourFormat", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Unit Localization", + "code": 45, + "mfgCode": null, + "define": "UNIT_LOCALIZATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "General Commissioning", + "code": 48, + "mfgCode": null, + "define": "GENERAL_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "ArmFailSafe", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ArmFailSafeResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "SetRegulatoryConfig", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "SetRegulatoryConfigResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CommissioningComplete", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CommissioningCompleteResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "Breadcrumb", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BasicCommissioningInfo", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "BasicCommissioningInfo", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RegulatoryConfig", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "RegulatoryLocationType", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LocationCapability", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "RegulatoryLocationType", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportsConcurrentConnection", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Network Commissioning", + "code": 49, + "mfgCode": null, + "define": "NETWORK_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "MaxNetworks", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Networks", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "InterfaceEnabled", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastNetworkingStatus", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "NetworkCommissioningStatus", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastNetworkID", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastConnectErrorValue", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int32s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "General Diagnostics", + "code": 51, + "mfgCode": null, + "define": "GENERAL_DIAGNOSTICS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "TestEventTrigger", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "NetworkInterfaces", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RebootCount", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TestEventTriggersEnabled", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Administrator Commissioning", + "code": 60, + "mfgCode": null, + "define": "ADMINISTRATOR_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "OpenCommissioningWindow", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RevokeCommissioning", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "WindowStatus", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "CommissioningWindowStatusEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AdminFabricIndex", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "fabric_idx", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AdminVendorId", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Operational Credentials", + "code": 62, + "mfgCode": null, + "define": "OPERATIONAL_CREDENTIALS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "AttestationRequest", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AttestationResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CertificateChainRequest", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CertificateChainResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CSRRequest", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CSRResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "AddNOC", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "UpdateNOC", + "code": 7, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "NOCResponse", + "code": 8, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "UpdateFabricLabel", + "code": 9, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RemoveFabric", + "code": 10, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AddTrustedRootCertificate", + "code": 11, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "NOCs", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Fabrics", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportedFabrics", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CommissionedFabrics", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TrustedRootCertificates", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentFabricIndex", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Group Key Management", + "code": 63, + "mfgCode": null, + "define": "GROUP_KEY_MANAGEMENT_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "KeySetWrite", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetRead", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "KeySetRemove", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadAllIndices", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadAllIndicesResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "GroupKeyMap", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GroupTable", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxGroupsPerFabric", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxGroupKeysPerFabric", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + } + ] + }, + { + "id": 2, + "name": "Anonymous Endpoint Type", + "deviceTypeRef": { + "code": 2, + "profileId": 49153, + "label": "DUT-Server", + "name": "DUT-Server", + "deviceTypeOrder": 0 + }, + "deviceTypes": [ + { + "code": 2, + "profileId": 49153, + "label": "DUT-Server", + "name": "DUT-Server", + "deviceTypeOrder": 0 + } + ], + "deviceVersions": [ + 1 + ], + "deviceIdentifiers": [ + 2 + ], + "deviceTypeName": "DUT-Server", + "deviceTypeCode": 2, + "deviceTypeProfileId": 49153, + "clusters": [ + { + "name": "On/Off", + "code": 6, + "mfgCode": null, + "define": "ON_OFF_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "Off", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "On", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "Toggle", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "OnOff", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Test Cluster - Device Type", + "code": 65485, + "mfgCode": 43981, + "define": "TEST_CLUSTER_DEVICE_TYPE", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + } + ] + } + ], + "endpoints": [ + { + "endpointTypeName": "MA-rootdevice", + "endpointTypeIndex": 0, + "profileId": 259, + "endpointId": 0, + "networkId": null, + "parentEndpointIdentifier": null + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 1, + "profileId": 49153, + "endpointId": 1, + "networkId": 0, + "parentEndpointIdentifier": null + } + ] +} \ No newline at end of file
diff --git a/test/test-util.js b/test/test-util.js index d562b64..bb256ca 100644 --- a/test/test-util.js +++ b/test/test-util.js
@@ -159,11 +159,10 @@ './test/resource/custom-cluster/custom-bead-cluster.xml' exports.badTestCustomXml = './test/resource/custom-cluster/bad-test-custom.xml' -exports.testMattterCustomXml = - './test/resource/custom-cluster/matter-custom.xml' -exports.testMattterCustomXml2 = +exports.testMatterCustomXml = './test/resource/custom-cluster/matter-custom.xml' +exports.testMatterCustomXml2 = './test/resource/custom-cluster/matter-custom2.xml' -exports.testBadMattterCustomXml = +exports.testBadMatterCustomXml = './test/resource/custom-cluster/matter-bad-custom.xml' exports.testMatterConflict = './test/resource/custom-cluster/matter-conflict.xml' @@ -171,6 +170,8 @@ './test/resource/custom-cluster/matterMissingCustomXml.zap' exports.testMatterCustomZap = './test/resource/custom-cluster/matterCustomXml.zap' +exports.testMatterCustomZap2 = + './test/resource/custom-cluster/matterCustomDeviceType.zap' exports.totalClusterCount = 111 exports.totalDomainCount = 20
diff --git a/zcl-builtin/matter/data-model/chip/channel-cluster.xml b/zcl-builtin/matter/data-model/chip/channel-cluster.xml index 47ac01d..5969ec4 100644 --- a/zcl-builtin/matter/data-model/chip/channel-cluster.xml +++ b/zcl-builtin/matter/data-model/chip/channel-cluster.xml
@@ -54,7 +54,7 @@ <struct name="ChannelInfoStruct"> <cluster code="0x0504"/> - <item name="MajorNumber" type="INT16U"/> + <item name="MajorNumber" type="INT16U" default="0xFFFF"/> <item name="MinorNumber" type="INT16U"/> <item name="Name" type="CHAR_STRING" optional="true"/> <item name="CallSign" type="CHAR_STRING" optional="true"/>
diff --git a/zcl-builtin/matter/data-model/chip/chip-ota.xml b/zcl-builtin/matter/data-model/chip/chip-ota.xml index f14d6df..5fb7197 100644 --- a/zcl-builtin/matter/data-model/chip/chip-ota.xml +++ b/zcl-builtin/matter/data-model/chip/chip-ota.xml
@@ -47,7 +47,7 @@ <command source="client" code="0x00" name="QueryImage" response="QueryImageResponse" optional="false" cli="chip ota queryimage"> <description>Determine availability of a new Software Image</description> <arg name="VendorID" type="vendor_id"/> - <arg name="ProductID" type="INT16U"/> + <arg name="ProductID" type="INT16U" default="0x01"/> <arg name="SoftwareVersion" type="INT32U"/> <arg name="ProtocolsSupported" type="OTADownloadProtocol" array="true"/> <arg name="HardwareVersion" type="INT16U" optional="true"/> @@ -95,10 +95,10 @@ <item name="Querying" value="0x2"/> <item name="DelayedOnQuery" value="0x3"/> <item name="Downloading" value="0x4"/> - <item name="Applying" value="0x5"/> + <item name="Applying" value="0x5"/> <item name="DelayedOnApply" value="0x6"/> <item name="RollingBack" value="0x7"/> - <item name="DelayedOnUserConsent" value="0x8"/> + <item name="DelayedOnUserConsent" value="0x8"/> </enum> <enum name="OTAChangeReasonEnum" type="ENUM8"> <cluster code="0x002a"/> @@ -139,18 +139,18 @@ <field id="1" name="NewState" type="OTAUpdateStateEnum"/> <field id="2" name="Reason" type="OTAChangeReasonEnum"/> <field id="3" name="TargetSoftwareVersion" type="INT32U" isNullable="true"/> - </event> + </event> <event side="server" code="0x01" name="VersionApplied" priority="critical" optional="false"> <description>This event SHALL be generated whenever a new version starts executing after being applied due to a software update.</description> - <field id="0" name="SoftwareVersion" type="INT32U"/> + <field id="0" name="SoftwareVersion" type="INT32U" default="0x00000000"/> <field id="1" name="ProductID" type="INT16U"/> </event> <event side="server" code="0x02" name="DownloadError" priority="info" optional="false"> <description>This event SHALL be generated whenever an error occurs during OTA Requestor download operation.</description> - <field id="0" name="SoftwareVersion" type="INT32U"/> + <field id="0" name="SoftwareVersion" type="INT32U"/> <field id="1" name="BytesDownloaded" type="INT64U"/> <field id="2" name="ProgressPercent" type="INT8U" min="0" max="100" isNullable="true"/> <field id="3" name="PlatformCode" type="INT64S" isNullable="true"/> - </event> + </event> </cluster> </configurator>
diff --git a/zcl-builtin/matter/data-model/chip/descriptor-cluster.xml b/zcl-builtin/matter/data-model/chip/descriptor-cluster.xml index e91beba..ef8d357 100644 --- a/zcl-builtin/matter/data-model/chip/descriptor-cluster.xml +++ b/zcl-builtin/matter/data-model/chip/descriptor-cluster.xml
@@ -30,6 +30,16 @@ <item name="Revision" type="INT16U"/> </struct> + <enum name="enumTest" type="ENUM8"> + <item name="enumTest1" value="0x0"/> + <item name="enumTest2" value="0x1"/> + </enum> + + <bitmap name="bitmapTest" type="BITMAP8"> + <field name="bitmapFieldTest1" mask="0x1"/> + <field name="bitmapFieldTest2" mask="0x2"/> + </bitmap> + <cluster> <domain>General</domain> <name>Descriptor</name>
diff --git a/zcl-builtin/matter/data-model/chip/mode-select-cluster.xml b/zcl-builtin/matter/data-model/chip/mode-select-cluster.xml index b4ff95c..cc4fc5d 100644 --- a/zcl-builtin/matter/data-model/chip/mode-select-cluster.xml +++ b/zcl-builtin/matter/data-model/chip/mode-select-cluster.xml
@@ -30,6 +30,16 @@ <item name="SemanticTags" type="SemanticTagStruct" array="true" optional="false"/> </struct> + <enum name="enumTest" type="ENUM8"> + <cluster code="0x0050"/> + <item name="enumTest1" value="0x0"/> + </enum> + + <bitmap name="bitmapTest" type="BITMAP8"> + <cluster code="0x0050"/> + <field name="bitmapFieldTest1" mask="0x1"/> + </bitmap> + <cluster> <domain>General</domain> <name>Mode Select</name>