Skip to content

Commit

Permalink
Syncing Multi-protocol Endpoint Type Attribute Default Values (projec…
Browse files Browse the repository at this point in the history
…t-chip#1410)

* Syncing the endpoint type attribute default values across endpoints as per the multi-protocol.json and attribute_mapping table
- Adding a trigger to sync endpoint type attribute default values across the same endpoint identifiers when it belongs to the attribute mapping table(multi-protocol.json)
- Adding unit tests for the above into multi-protocol.test.js
- Bumping the required feature level and supported electron versions
- JIRA: ZAPP-1384
  • Loading branch information
brdandu authored Aug 22, 2024
1 parent efae34c commit 5d67834
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 3 deletions.
2 changes: 1 addition & 1 deletion apack.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "Graphical configuration tool for application and libraries based on Zigbee Cluster Library.",
"path": [".", "node_modules/.bin/", "ZAP.app/Contents/MacOS"],
"requiredFeatureLevel": "apack.core:9",
"featureLevel": 103,
"featureLevel": 104,
"uc.triggerExtension": "zap",
"executable": {
"zap:win32.x86_64": {
Expand Down
4 changes: 3 additions & 1 deletion src-electron/db/query-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -1452,7 +1452,8 @@ SELECT
ETA.INCLUDED_REPORTABLE,
ETA.MIN_INTERVAL,
ETA.MAX_INTERVAL,
ETA.REPORTABLE_CHANGE
ETA.REPORTABLE_CHANGE,
ETA.ENDPOINT_TYPE_ATTRIBUTE_ID
FROM
CLUSTER AS C
JOIN
Expand All @@ -1477,6 +1478,7 @@ ORDER BY
.then((rows) =>
rows.map((row) => {
return {
endpointTypeAttributeId: row.ENDPOINT_TYPE_ATTRIBUTE_ID,
name: row.NAME,
attributeCode: row.ATTRIBUTE_CODE,
clusterCode: row.CLUSTER_CODE,
Expand Down
145 changes: 145 additions & 0 deletions src-electron/db/zap-schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -1296,6 +1296,151 @@ CREATE TABLE IF NOT EXISTS "ENDPOINT_TYPE_ATTRIBUTE" (
)
);

/**
SQL Trigger for a multi-protocol Endpoint Type Attribute default value.
If the default value of a multi-protocol endpoint attribute is updated
then the corresponding attribute's default value in the other protocol
is also updated on the same endpoint identifier
Eg: If Matter's on/off attribute is updated then so will Zigbee's on/off
attribute be toggled as well.
*/
CREATE TRIGGER
UPDATE_MULTIPROTOCOL_ATTRIBUTES_ACROSS_ENDPOINT_TYPES
AFTER
UPDATE ON ENDPOINT_TYPE_ATTRIBUTE
WHEN
(
(
SELECT
COUNT()
FROM
ENDPOINT_TYPE_ATTRIBUTE
INNER JOIN
ATTRIBUTE
ON
ENDPOINT_TYPE_ATTRIBUTE.ATTRIBUTE_REF = ATTRIBUTE.ATTRIBUTE_ID
INNER JOIN
ATTRIBUTE_MAPPING
ON
ATTRIBUTE.ATTRIBUTE_ID = ATTRIBUTE_MAPPING.ATTRIBUTE_LEFT_REF
OR ATTRIBUTE.ATTRIBUTE_ID = ATTRIBUTE_MAPPING.ATTRIBUTE_RIGHT_REF
WHERE
ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_ATTRIBUTE_ID = new.ENDPOINT_TYPE_ATTRIBUTE_ID
) > 0
AND
(
SELECT EXISTS
(SELECT
ENDPOINT.ENDPOINT_IDENTIFIER,
ENDPOINT.SESSION_REF,
(
SELECT
COUNT()
FROM
ENDPOINT
WHERE
ENDPOINT_IDENTIFIER = ENDPOINT.ENDPOINT_IDENTIFIER
AND
SESSION_REF = ENDPOINT.SESSION_REF
) AS ENDPOINT_COUNT
FROM
ENDPOINT_TYPE_ATTRIBUTE
INNER JOIN
ENDPOINT_TYPE_CLUSTER
ON
ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF
INNER JOIN
ENDPOINT_TYPE
ON
ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_REF
INNER JOIN
ENDPOINT
ON
ENDPOINT.ENDPOINT_TYPE_REF = ENDPOINT_TYPE.ENDPOINT_TYPE_ID
WHERE
ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_ATTRIBUTE_ID = new.ENDPOINT_TYPE_ATTRIBUTE_ID
AND
ENDPOINT_COUNT > 1)
)
)
BEGIN
UPDATE
ENDPOINT_TYPE_ATTRIBUTE
SET
DEFAULT_VALUE = new.DEFAULT_VALUE
WHERE
ENDPOINT_TYPE_ATTRIBUTE_ID
IN
(
SELECT
CASE
WHEN new.ENDPOINT_TYPE_ATTRIBUTE_ID = ETA1.ENDPOINT_TYPE_ATTRIBUTE_ID THEN ETA2.ENDPOINT_TYPE_ATTRIBUTE_ID
WHEN new.ENDPOINT_TYPE_ATTRIBUTE_ID = ETA2.ENDPOINT_TYPE_ATTRIBUTE_ID THEN ETA1.ENDPOINT_TYPE_ATTRIBUTE_ID
END AS ENDPOINT_TYPE_ATTRIBUTE_ID
FROM
ENDPOINT AS E1
INNER JOIN
ENDPOINT_TYPE AS ET1
ON
ET1.ENDPOINT_TYPE_ID = E1.ENDPOINT_TYPE_REF
INNER JOIN
ENDPOINT_TYPE_CLUSTER AS ETC1
ON
ETC1.ENDPOINT_TYPE_REF = ET1.ENDPOINT_TYPE_ID
INNER JOIN
ENDPOINT_TYPE_ATTRIBUTE AS ETA1
ON
ETA1.ENDPOINT_TYPE_CLUSTER_REF = ETC1.ENDPOINT_TYPE_CLUSTER_ID
INNER JOIN
ATTRIBUTE_MAPPING AS AM
ON
AM.ATTRIBUTE_LEFT_REF = ETA1.ATTRIBUTE_REF
INNER JOIN
ENDPOINT_TYPE_ATTRIBUTE AS ETA2
ON
AM.ATTRIBUTE_RIGHT_REF = ETA2.ATTRIBUTE_REF
INNER JOIN
ENDPOINT_TYPE_CLUSTER AS ETC2
ON
ETA2.ENDPOINT_TYPE_CLUSTER_REF = ETC2.ENDPOINT_TYPE_CLUSTER_ID
INNER JOIN
ENDPOINT_TYPE AS ET2
ON
ETC2.ENDPOINT_TYPE_REF = ET2.ENDPOINT_TYPE_ID
INNER JOIN
ENDPOINT AS E2
ON
ET2.ENDPOINT_TYPE_ID = E2.ENDPOINT_TYPE_REF
WHERE
E1.ENDPOINT_IDENTIFIER = E2.ENDPOINT_IDENTIFIER
AND
new.ENDPOINT_TYPE_ATTRIBUTE_ID IN (ETA1.ENDPOINT_TYPE_ATTRIBUTE_ID, ETA2.ENDPOINT_TYPE_ATTRIBUTE_ID)
AND
(
SELECT
ENDPOINT.SESSION_REF
FROM
ENDPOINT_TYPE_ATTRIBUTE
INNER JOIN
ENDPOINT_TYPE_CLUSTER
ON
ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF
INNER JOIN
ENDPOINT_TYPE
ON
ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_REF
INNER JOIN
ENDPOINT
ON
ENDPOINT.ENDPOINT_TYPE_REF = ENDPOINT_TYPE.ENDPOINT_TYPE_ID
WHERE
ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_ATTRIBUTE_ID = new.ENDPOINT_TYPE_ATTRIBUTE_ID
) IN (E1.SESSION_REF, E2.SESSION_REF)
AND
E1.SESSION_REF = E2.SESSION_REF
);
END;

/*
SQL Trigger for Device Type attribute Compliance.
This trigger is used to add a warning to the notification table when an
Expand Down
8 changes: 7 additions & 1 deletion src-electron/util/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,13 @@ export function isMatchingVersion(versionsArray, providedVersion) {
*/
export function versionsCheck() {
let expectedNodeVersion = ['v14.x.x', 'v16.x.x', 'v18.x.x']
let expectedElectronVersion = ['17.4.x', '18.x.x', '24.x.x', '27.x.x']
let expectedElectronVersion = [
'17.4.x',
'18.x.x',
'24.x.x',
'27.x.x',
'31.x.x'
]
let nodeVersion = process.version
let electronVersion = process.versions.electron
let ret = true
Expand Down
93 changes: 93 additions & 0 deletions test/multi-protocol.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const querySessionNotice = require('../src-electron/db/query-session-notificatio
const zclLoader = require('../src-electron/zcl/zcl-loader')
const importJs = require('../src-electron/importexport/import')
const testUtil = require('./test-util')
const queryConfig = require('../src-electron/db/query-config')

const zigbeeTemplateCount = testUtil.testTemplate.zigbee2Count
const matterTemplateCount = testUtil.testTemplate.matter2Count
Expand Down Expand Up @@ -208,3 +209,95 @@ test(
},
testUtil.timeout.long()
)

// Test to check that the default values of corresponding attributes is updated on one endpoint
// Make sure the above does not affect other endpoints.
// Make sure other attribute's values are not affected as well.
// Test both sides matter to zigbee and zigbee to matter
test(
`Test Endpoint Type Attribute default value syncing between 2 protocols ${multiProtocolTestFile}`,
async () => {
let importRes = await importJs.importDataFromFile(
db,
multiProtocolTestFile,
{ sessionId: null },
)

// Get all session attributes
let allEndpointTypeAttributes =
await queryConfig.selectAllSessionAttributes(db, importRes.sessionId)
let zigbeeEndpointTypeAttribute = ''
let matterEndpointTypeAttribute = ''

// Get all on/off endpoint type attribute values for zigbee and matter
for (const eta of allEndpointTypeAttributes) {
if (eta.name.toLowerCase() == 'on/off') {
zigbeeEndpointTypeAttribute = eta
}
if (eta.name.toLowerCase() == 'onoff') {
matterEndpointTypeAttribute = eta
}
}

// Check both of them are the same
expect(parseInt(zigbeeEndpointTypeAttribute.defaultValue)).toEqual(0)
expect(parseInt(zigbeeEndpointTypeAttribute.defaultValue)).toEqual(
parseInt(matterEndpointTypeAttribute.defaultValue),
)

// Change zigbee ETA and check for the change in the corresponding Matter ETA.
await queryConfig.updateEndpointTypeAttribute(
db,
zigbeeEndpointTypeAttribute.endpointTypeAttributeId,
[['defaultValue', 1]],
)
let allEndpointTypeAttributesAfterChange =
await queryConfig.selectAllSessionAttributes(db, importRes.sessionId)
for (const eta of allEndpointTypeAttributesAfterChange) {
if (eta.name.toLowerCase() == 'on/off') {
zigbeeEndpointTypeAttribute = eta
}
if (eta.name.toLowerCase() == 'onoff') {
matterEndpointTypeAttribute = eta
}
}
expect(parseInt(zigbeeEndpointTypeAttribute.defaultValue)).toEqual(1)
expect(parseInt(zigbeeEndpointTypeAttribute.defaultValue)).toEqual(
parseInt(matterEndpointTypeAttribute.defaultValue),
)

// Negative test: Check that none of the other Endpoint Type Attribute values are not changed. Only the ones intended i.e. on/off
for (let i = 0; i < allEndpointTypeAttributes.length; i++) {
if (
allEndpointTypeAttributes[i].name.toLowerCase() != 'on/off' &&
allEndpointTypeAttributes[i].name.toLowerCase() != 'onoff'
) {
expect(allEndpointTypeAttributes[i].defaultValue).toEqual(
allEndpointTypeAttributesAfterChange[i].defaultValue,
)
}
}

// Also test change of matter ETA and check for the change in the corresponding Zigbee ETA.
await queryConfig.updateEndpointTypeAttribute(
db,
matterEndpointTypeAttribute.endpointTypeAttributeId,
[['defaultValue', 0]],
)
allEndpointTypeAttributesAfterChange =
await queryConfig.selectAllSessionAttributes(db, importRes.sessionId)
for (const eta of allEndpointTypeAttributesAfterChange) {
if (eta.name.toLowerCase() == 'on/off') {
zigbeeEndpointTypeAttribute = eta
}
if (eta.name.toLowerCase() == 'onoff') {
matterEndpointTypeAttribute = eta
}
}
expect(parseInt(matterEndpointTypeAttribute.defaultValue)).toEqual(0)
expect(parseInt(matterEndpointTypeAttribute.defaultValue)).toEqual(
parseInt(zigbeeEndpointTypeAttribute.defaultValue),
)
},
testUtil.timeout.long(),
)

0 comments on commit 5d67834

Please sign in to comment.