Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/feature map attribute and device type conformance/zapp 1346 #1300

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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": 101,
"featureLevel": 102,
"uc.triggerExtension": "zap",
"executable": {
"zap:win32.x86_64": {
Expand Down
4,216 changes: 2,107 additions & 2,109 deletions docs/zap-schema.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions src-electron/db/db-mapping.js
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,24 @@ exports.map = {
deviceVersion: x.DEVICE_VERSION,
}
},
endpointTypeDeviceExtended: (x) => {
if (x == null) return undefined
return {
id: x.ENDPOINT_TYPE_DEVICE_ID,
deviceTypeRef: x.DEVICE_TYPE_REF,
endpointTypeRef: x.ENDPOINT_TYPE_REF,
endpointTypeId: x.ENDPOINT_TYPE_REF,
deviceTypeOrder: x.DEVICE_TYPE_ORDER,
deviceIdentifier: x.DEVICE_IDENTIFIER,
deviceId: x.DEVICE_IDENTIFIER,
deviceVersion: x.DEVICE_VERSION,
featureId: x.FEATURE_ID,
featureCode: x.FEATURE_CODE,
featureName: x.FEATURE_NAME,
featureBit: x.FEATURE_BIT,
clusterId: x.CLUSTER_REF,
}
},
endpointTypeCluster: (x) => {
if (x == null) return undefined
return {
Expand Down
34 changes: 28 additions & 6 deletions src-electron/db/query-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,28 @@ async function insertOrUpdateAttributeState(
attributeId,
clusterRef
)
// Looking for the feature map attribute in matter and setting it as per
// the device types if default value is 0
if (
staticAttribute.code == 0xfffc &&
staticAttribute.name == 'FeatureMap' &&
staticAttribute.defaultValue == 0
) {
let featureMapDefaultValue = staticAttribute.defaultValue
let mandatoryFeaturesOnEndpointTypeAndCluster =
await queryDeviceType.selectDeviceTypeFeaturesByEndpointTypeIdAndClusterId(
db,
endpointTypeId,
clusterRef
)
let featureMapBitsToBeEnabled =
mandatoryFeaturesOnEndpointTypeAndCluster.map((f) => f.featureBit)
featureMapBitsToBeEnabled.forEach(
(featureBit) =>
(featureMapDefaultValue = featureMapDefaultValue | (1 << featureBit))
)
staticAttribute.defaultValue = featureMapDefaultValue
}
let forcedExternal = await queryUpgrade.getForcedExternalStorage(db)
staticAttribute.storagePolicy =
await queryUpgrade.computeStoragePolicyNewConfig(
Expand Down Expand Up @@ -314,7 +336,7 @@ async function updateEndpointTypeAttribute(db, id, keyValuePairs) {
})
args.push(id)

let query = `UPDATE ENDPOINT_TYPE_ATTRIBUTE SET
let query = `UPDATE ENDPOINT_TYPE_ATTRIBUTE SET
${columns}
WHERE ENDPOINT_TYPE_ATTRIBUTE_ID = ?`
return dbApi.dbUpdate(db, query, args)
Expand Down Expand Up @@ -508,7 +530,7 @@ INTO ENDPOINT_TYPE_EVENT (
db,
`
UPDATE ENDPOINT_TYPE_EVENT
SET INCLUDED = ?
SET INCLUDED = ?
WHERE ENDPOINT_TYPE_REF = ?
AND ENDPOINT_TYPE_CLUSTER_REF = ?
AND EVENT_REF = ? `,
Expand Down Expand Up @@ -1372,17 +1394,17 @@ async function selectEndpointTypeAttributeId(
let rows = await dbApi.dbAll(
db,
`
SELECT
SELECT
ENDPOINT_TYPE_ATTRIBUTE_ID
FROM
FROM
ENDPOINT_TYPE_ATTRIBUTE AS ETA
INNER JOIN
ATTRIBUTE AS A
ON
ETA.ATTRIBUTE_REF = A.ATTRIBUTE_ID
ETA.ATTRIBUTE_REF = A.ATTRIBUTE_ID
INNER JOIN
CLUSTER AS C
ON
ON
C.CLUSTER_ID = A.CLUSTER_REF
WHERE
ETA.ENDPOINT_TYPE_REF = ?
Expand Down
100 changes: 99 additions & 1 deletion src-electron/db/query-device-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,45 @@ WHERE
)
}

/**
* After loading up device type feature table with the names,
* this method links the refererence to actual feature reference.
*
* @param {*} db
* @returns promise of completion
*/
async function updateFeatureReferencesForDeviceTypeReferences(db, packageId) {
return dbApi.dbUpdate(
db,
`
UPDATE
DEVICE_TYPE_FEATURE
SET
FEATURE_REF =
( SELECT
FEATURE.FEATURE_ID
FROM
FEATURE
WHERE
upper(FEATURE.CODE) = upper(DEVICE_TYPE_FEATURE.FEATURE_CODE)
AND
FEATURE.CLUSTER_REF = (
SELECT
DEVICE_TYPE_CLUSTER.CLUSTER_REF
FROM
DEVICE_TYPE_CLUSTER
WHERE
DEVICE_TYPE_CLUSTER_ID = DEVICE_TYPE_FEATURE.DEVICE_TYPE_CLUSTER_REF
)
AND
FEATURE.PACKAGE_REF = ?
)
WHERE
DEVICE_TYPE_FEATURE.FEATURE_REF IS NULL`,
[packageId]
)
}

/**
* This method returns the promise of linking the device type clusters
* commands and attributes to the correct IDs in the cluster, attribute
Expand All @@ -326,7 +365,8 @@ WHERE
async function updateDeviceTypeEntityReferences(db, packageId) {
await updateClusterReferencesForDeviceTypeClusters(db, packageId)
await updateAttributeReferencesForDeviceTypeReferences(db, packageId)
return updateCommandReferencesForDeviceTypeReferences(db, packageId)
await updateCommandReferencesForDeviceTypeReferences(db, packageId)
return updateFeatureReferencesForDeviceTypeReferences(db, packageId)
}

/**
Expand Down Expand Up @@ -355,6 +395,62 @@ async function selectDeviceTypesByEndpointTypeId(db, endpointTypeId) {
return rows.map(dbMapping.map.endpointTypeDevice)
}

/**
* Retrieves the device type features associated to an endpoint type id and cluster id
* Note: Use clusterId as 'all' to get all features for an endpoint type id.
* @param {*} db
* @param {*} endpointTypeId
* @param {*} clusterId
* @returns promise with zcl device type feature information based on endpoint type id and cluster id
*/
async function selectDeviceTypeFeaturesByEndpointTypeIdAndClusterId(
db,
endpointTypeId,
clusterId
) {
let rows = await dbApi.dbAll(
db,
`
SELECT
ETD.ENDPOINT_TYPE_DEVICE_ID,
ETD.DEVICE_TYPE_REF,
ETD.ENDPOINT_TYPE_REF,
ETD.DEVICE_TYPE_ORDER,
ETD.DEVICE_IDENTIFIER,
ETD.DEVICE_VERSION,
FEATURE.FEATURE_ID,
FEATURE.NAME AS FEATURE_NAME,
FEATURE.CODE AS FEATURE_CODE,
FEATURE.BIT AS FEATURE_BIT,
DEVICE_TYPE_CLUSTER.CLUSTER_REF
FROM
ENDPOINT_TYPE_DEVICE AS ETD
INNER JOIN
DEVICE_TYPE
ON
ETD.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID
INNER JOIN
DEVICE_TYPE_CLUSTER
ON
DEVICE_TYPE_CLUSTER.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID
INNER JOIN
DEVICE_TYPE_FEATURE
ON
DEVICE_TYPE_FEATURE.DEVICE_TYPE_CLUSTER_REF = DEVICE_TYPE_CLUSTER.DEVICE_TYPE_CLUSTER_ID
INNER JOIN
FEATURE
ON
FEATURE.FEATURE_ID = DEVICE_TYPE_FEATURE.FEATURE_REF
WHERE
ETD.ENDPOINT_TYPE_REF = ${endpointTypeId}` +
(clusterId != 'all'
? ` AND
DEVICE_TYPE_CLUSTER.CLUSTER_REF = ${clusterId}`
: ``)
)
return rows.map(dbMapping.map.endpointTypeDeviceExtended)
}

exports.selectAllDeviceTypes = selectAllDeviceTypes
exports.selectDeviceTypeById = selectDeviceTypeById
exports.selectDeviceTypeByCodeAndName = selectDeviceTypeByCodeAndName
Expand All @@ -369,3 +465,5 @@ exports.selectDeviceTypeCommandsByDeviceTypeRef =
selectDeviceTypeCommandsByDeviceTypeRef
exports.updateDeviceTypeEntityReferences = updateDeviceTypeEntityReferences
exports.selectDeviceTypesByEndpointTypeId = selectDeviceTypesByEndpointTypeId
exports.selectDeviceTypeFeaturesByEndpointTypeIdAndClusterId =
selectDeviceTypeFeaturesByEndpointTypeIdAndClusterId
51 changes: 49 additions & 2 deletions src-electron/db/query-endpoint-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,53 @@ WHERE
return rows.map(mapFunction)
}

/**
* Given the endpoint type cluster id and attribute code, extract the value
* endpoint type attribute information for that attribute within the endpoint
* type cluster.
* @param {*} db
* @param {*} endpointTypeClusterId
* @param {*} attributeCode
* @param {*} attributeMfgCode
*/
async function selectEndpointTypeAttributeFromEndpointTypeClusterId(
db,
endpointTypeClusterId,
attributeCode,
attributeMfgCode
) {
let eta = await dbApi.dbGet(
db,
`
SELECT
ETC.ENDPOINT_TYPE_REF,
ETC.CLUSTER_REF,
ETA.INCLUDED,
ETA.STORAGE_OPTION,
ETA.SINGLETON,
ETA.DEFAULT_VALUE
FROM
ATTRIBUTE AS A
INNER JOIN
ENDPOINT_TYPE_ATTRIBUTE AS ETA
ON
ETA.ATTRIBUTE_REF = A.ATTRIBUTE_ID
INNER JOIN
ENDPOINT_TYPE_CLUSTER AS ETC
ON
ETA.ENDPOINT_TYPE_CLUSTER_REF = ETC.ENDPOINT_TYPE_CLUSTER_ID
WHERE
ETC.ENDPOINT_TYPE_CLUSTER_ID = ${endpointTypeClusterId}
AND
A.CODE = ${attributeCode}
` +
(attributeMfgCode
? ` AND A.MANUFACTURER_CODE = ${attributeMfgCode}`
: ` AND A.MANUFACTURER_CODE IS NULL`)
)
return dbMapping.map.endpointTypeAttribute(eta)
}

exports.deleteEndpointType = deleteEndpointType
exports.selectAllEndpointTypes = selectAllEndpointTypes
exports.selectEndpointTypeIds = selectEndpointTypeIds
Expand All @@ -652,13 +699,13 @@ exports.selectAllClustersDetailsFromEndpointTypes =
selectAllClustersDetailsFromEndpointTypes
exports.selectEndpointDetailsFromAddedEndpoints =
selectEndpointDetailsFromAddedEndpoints

exports.selectAllClustersNamesFromEndpointTypes =
selectAllClustersNamesFromEndpointTypes
exports.selectAllClustersDetailsIrrespectiveOfSideFromEndpointTypes =
selectAllClustersDetailsIrrespectiveOfSideFromEndpointTypes
exports.selectCommandDetailsFromAllEndpointTypeCluster =
selectCommandDetailsFromAllEndpointTypeCluster

exports.selectClustersAndEndpointDetailsFromEndpointTypes =
selectClustersAndEndpointDetailsFromEndpointTypes
exports.selectEndpointTypeAttributeFromEndpointTypeClusterId =
selectEndpointTypeAttributeFromEndpointTypeClusterId
55 changes: 55 additions & 0 deletions src-electron/db/query-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ async function insertClusters(db, packageId, data) {
access: [],
}
let pTags = null
let pFeatures = null

let i
for (i = 0; i < lastIdsArray.length; i++) {
Expand All @@ -642,16 +643,45 @@ async function insertClusters(db, packageId, data) {
if ('tags' in data[i]) {
pTags = insertTags(db, packageId, data[i].tags, lastId)
}

if ('features' in data[i]) {
pFeatures = insertFeatures(db, packageId, data[i].features, lastId)
}
}
let pCommand = insertCommands(db, packageId, commands)
let pAttribute = insertAttributes(db, packageId, attributes)
let pEvent = insertEvents(db, packageId, events)
let pArray = [pCommand, pAttribute, pEvent]
if (pTags != null) pArray.push(pTags)
if (pFeatures != null) pArray.push(pFeatures)
return Promise.all(pArray)
})
}

/**
* Inserts features into the database.
* @param {*} db
* @param {*} packageId
* @param {*} data
* @returns A promise that resolves with array of rowids.
*/
async function insertFeatures(db, packageId, data, clusterId) {
return dbApi.dbMultiInsert(
db,
'INSERT INTO FEATURE (PACKAGE_REF, NAME, CODE, BIT, DEFAULT_VALUE, DESCRIPTION, CONFORMANCE, CLUSTER_REF) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
data.map((feature) => [
packageId,
feature.name,
feature.code,
feature.bit,
feature.defaultValue,
feature.description,
feature.conformance,
clusterId,
])
)
}

/**
* Inserts tags into the database.
* data is an array of objects, containing 'name' and 'description'
Expand Down Expand Up @@ -895,6 +925,7 @@ async function insertDeviceTypes(db, packageId, data) {
let promises = []
promises.push(insertDeviceTypeAttributes(db, dtClusterRefDataPairs))
promises.push(insertDeviceTypeCommands(db, dtClusterRefDataPairs))
promises.push(insertDeviceTypeFeatures(db, dtClusterRefDataPairs))
return Promise.all(promises)
})
}
Expand All @@ -903,6 +934,30 @@ async function insertDeviceTypes(db, packageId, data) {
})
}

/**
* 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
* @param {*} dtClusterRefDataPairs
*/
async function insertDeviceTypeFeatures(db, dtClusterRefDataPairs) {
let features = []
dtClusterRefDataPairs.map((dtClusterRefDataPair) => {
let dtClusterRef = dtClusterRefDataPair.dtClusterRef
let clusterData = dtClusterRefDataPair.clusterData
if ('features' in clusterData && clusterData.features.length > 0) {
clusterData.features.forEach((featureCode) => {
features.push([dtClusterRef, featureCode])
})
}
})
return dbApi.dbMultiInsert(
db,
'INSERT INTO DEVICE_TYPE_FEATURE (DEVICE_TYPE_CLUSTER_REF, FEATURE_CODE) VALUES (?, ?)',
features
)
}

/**
* This handles the loading of device type attribute requirements into the database.
* There is a need to post-process to attach the actual attribute ref after the fact
Expand Down
Loading
Loading