From 9cee1270c1b50340a93bdfb837fbbc8f6ddbdc65 Mon Sep 17 00:00:00 2001 From: Gergely Kiss Date: Fri, 19 May 2023 14:13:26 +0200 Subject: [PATCH 01/40] Support multiple device type with primary input --- src/components/ZclCreateModifyEndpoint.vue | 74 ++++++++++--- src/components/ZclEndpointCard.vue | 119 +++++++++++++-------- 2 files changed, 133 insertions(+), 60 deletions(-) diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index 7d74c30f6f..e12f9f58c6 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -32,7 +32,7 @@ limitations under the License. min="0" /> - - + /> +
0 ? newValue[0] : newValue + const { deviceTypeRef, deviceIdentifier } = value + + // Set device pair + if (this.devicePair == undefined) { + this.devicePair = {} + } + this.devicePair.deviceTypeRef = deviceTypeRef + this.devicePair.deviceIdentifier = deviceIdentifier + + // Set primary device if necessary + if (this.enablePrimaryDevice) { + if (this.primaryDeviceType === null) { + this.primaryDeviceType = value + } else { + if (Array.isArray(newValue)) { + if ( + !newValue.includes( + (device) => + device.deviceTypeRef === + this.primaryDeviceType.deviceTypeRef && + device.deviceIdentifier === + this.primaryDeviceType.deviceIdentifier + ) + ) { + this.primaryDeviceType = value + } + } + } + } + let profileId = this.shownEndpoint.profileIdentifier // On change of device type, reset the profileId to the current deviceType _unless_ the default profileId is custom if (this.shownEndpoint.profileIdentifier != null) { @@ -257,8 +305,6 @@ export default { profileId = this.asHex(this.zclDeviceTypes[deviceTypeRef].profileId, 4) } this.shownEndpoint.profileIdentifier = profileId - this.devicePair.deviceTypeRef = value.deviceTypeRef - this.devicePair.deviceIdentifier = value.deviceIdentifier }, saveOrCreateHandler() { let profile = this.$store.state.zap.isProfileIdShown diff --git a/src/components/ZclEndpointCard.vue b/src/components/ZclEndpointCard.vue index a1af2c4ee8..ad56714747 100644 --- a/src/components/ZclEndpointCard.vue +++ b/src/components/ZclEndpointCard.vue @@ -84,52 +84,73 @@ limitations under the License. />
- - - -
Device
-
- {{ getDeviceOptionLabel() }} -
-
- -
Network
-
- {{ networkId[endpointReference] }} -
-
- -
Profile ID
-
- {{ asHex(profileId[endpointReference], 4) }} -
-
- -
Version
-
- {{ endpointVersion[endpointReference] }} -
-
- -
Enabled Clusters
-
- {{ selectedServers.length }} -
-
- -
Enabled Attributes
-
- {{ selectedAttributes.length }} -
-
- -
Enabled Reporting
-
- {{ selectedReporting.length }} -
-
-
-
+ +
+ +
+ Device +
+
+ {{ getDeviceOptionLabel() }} +
+
+ +
+ Primary Device +
+
+ {{ getPrimaryDeviceOptionLabel() }} +
+
+ +
+ Network +
+
+ {{ networkId[endpointReference] }} +
+
+ +
+ Profile ID +
+
+ {{ asHex(profileId[endpointReference], 4) }} +
+
+ +
+ Version +
+
+ {{ endpointVersion[endpointReference] }} +
+
+ +
+ Enabled Clusters +
+
+ {{ selectedServers.length }} +
+
+ +
+ Enabled Attributes +
+
+ {{ selectedAttributes.length }} +
+
+ +
+ Enabled Reporting +
+
+ {{ selectedReporting.length }} +
+
+
Date: Mon, 22 May 2023 19:39:29 +0200 Subject: [PATCH 02/40] Support multiple device type with array input --- src/components/ZclCreateModifyEndpoint.vue | 163 ++++++++++++--------- src/store/zap/actions.js | 60 ++++---- 2 files changed, 126 insertions(+), 97 deletions(-) diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index e12f9f58c6..7f2c87e0c9 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -51,9 +51,10 @@ limitations under the License. :multiple="enableMultipleDevice" :use-chips="enableMultipleDevice" :options="deviceTypeOptions" - v-model="devicePair" - @update:model-value="setDeviceTypeCallback" - :rules="[(val) => val != null || '* Required']" + v-model="deviceType" + :rules="[ + (val) => !(val == null || val?.length == 0) || '* Required', + ]" :option-label="getDeviceOptionLabel" @filter="filterDeviceTypes" data-test="select-endpoint-input" @@ -153,14 +154,21 @@ export default { this.shownEndpoint.deviceVersion = parseInt( this.endpointVersion[this.endpointReference] ) - this.devicePair = { + // TODO refactor this after API change + const firstDeviceType = { deviceTypeRef: this.endpointDeviceTypeRef[this.endpointType[this.endpointReference]], deviceIdentifier: this.endpointDeviceId[this.endpointReference], } + // Set device types only in edit mode + this.deviceTypeTmp = [firstDeviceType] // TODO make device pair to be array and set it here from the store + this.primaryDeviceTypeTmp = null // TODO set it here from the store } else { this.shownEndpoint.endpointIdentifier = this.getSmallestUnusedEndpointId() } + const enableMultiDeviceFeatures = true + this.enableMultipleDevice = enableMultiDeviceFeatures // TODO make it data driven from the store + this.enablePrimaryDevice = enableMultiDeviceFeatures // TODO make it data driven from the store }, data() { return { @@ -172,10 +180,10 @@ export default { deviceVersion: 1, }, saveOrCreateCloseFlag: false, - deviceType: null, - primaryDeviceType: null, - enableMultipleDevice: true, // TODO make it data driven - enablePrimaryDevice: true, // TODO make it data driven + deviceTypeTmp: [], // Temp store for the selected device types + primaryDeviceTypeTmp: null, // Temp store for the selected primary device type + enableMultipleDevice: false, // TODO make it data driven + enablePrimaryDevice: false, // TODO make it data driven } }, computed: { @@ -250,61 +258,84 @@ export default { ] }, }, - }, - methods: { - // This function will close the endpoint modal - toggleCreateEndpointModal() { - this.$store.commit('zap/toggleEndpointModal', false) - }, - setProfileId(value) { - this.shownEndpoint.profileIdentifier = value - }, - setDeviceTypeCallback(newValue) { - console.log(newValue) - const value = - Array.isArray(newValue) && newValue.length > 0 ? newValue[0] : newValue - const { deviceTypeRef, deviceIdentifier } = value + deviceType: { + get() { + // New temporary variable + return this.enableMultipleDevice + ? this.deviceTypeTmp + : this.deviceTypeTmp[0] + }, + set(newValue) { + const value = !Array.isArray(newValue) ? [newValue] : newValue - // Set device pair - if (this.devicePair == undefined) { - this.devicePair = {} - } - this.devicePair.deviceTypeRef = deviceTypeRef - this.devicePair.deviceIdentifier = deviceIdentifier + // New temporary variable + this.deviceTypeTmp = value - // Set primary device if necessary - if (this.enablePrimaryDevice) { - if (this.primaryDeviceType === null) { - this.primaryDeviceType = value - } else { - if (Array.isArray(newValue)) { + // Existing logic + this.setDeviceTypeCallback(value) + + // Set primary device if necessary + const newPrimaryDeviceType = + Array.isArray(value) && value.length > 0 ? value[0] : null + if (this.enablePrimaryDevice) { + if (this.primaryDeviceType === null) { + this.primaryDeviceType = newPrimaryDeviceType + } else { if ( - !newValue.includes( - (device) => - device.deviceTypeRef === + !value.includes( + (deviceType) => + deviceType.deviceTypeRef === this.primaryDeviceType.deviceTypeRef && - device.deviceIdentifier === + deviceType.deviceIdentifier === this.primaryDeviceType.deviceIdentifier ) ) { - this.primaryDeviceType = value + this.primaryDeviceType = newPrimaryDeviceType } } } - } + }, + }, + primaryDeviceType: { + get() { + return this.primaryDeviceTypeTmp + }, + set(value) { + this.primaryDeviceTypeTmp = value - let profileId = this.shownEndpoint.profileIdentifier - // On change of device type, reset the profileId to the current deviceType _unless_ the default profileId is custom - if (this.shownEndpoint.profileIdentifier != null) { - profileId = - this.zclDeviceTypes[deviceTypeRef].profileId == - DbEnum.customDevice.profileId - ? this.asHex(profileId, 4) - : this.asHex(this.zclDeviceTypes[deviceTypeRef].profileId, 4) - } else { - profileId = this.asHex(this.zclDeviceTypes[deviceTypeRef].profileId, 4) + // TODO write back to the store and backend here + }, + }, + }, + methods: { + // This function will close the endpoint modal + toggleCreateEndpointModal() { + this.$store.commit('zap/toggleEndpointModal', false) + }, + setProfileId(value) { + this.shownEndpoint.profileIdentifier = value + }, + setDeviceTypeCallback(value) { + const firstValue = Array.isArray(value) ? value[0] : value + // Check deviceTypreRef truthy - at least 1 item selected + if (firstValue) { + const { deviceTypeRef } = firstValue + let profileId = this.shownEndpoint.profileIdentifier + // On change of device type, reset the profileId to the current deviceType _unless_ the default profileId is custom + if (this.shownEndpoint.profileIdentifier != null) { + profileId = + this.zclDeviceTypes[deviceTypeRef].profileId == + DbEnum.customDevice.profileId + ? this.asHex(profileId, 4) + : this.asHex(this.zclDeviceTypes[deviceTypeRef].profileId, 4) + } else { + profileId = this.asHex( + this.zclDeviceTypes[deviceTypeRef].profileId, + 4 + ) + } + this.shownEndpoint.profileIdentifier = profileId } - this.shownEndpoint.profileIdentifier = profileId }, saveOrCreateHandler() { let profile = this.$store.state.zap.isProfileIdShown @@ -348,7 +379,9 @@ export default { this.$store .dispatch(`zap/addEndpointType`, { name: 'Anonymous Endpoint Type', - deviceTypeRef: this.devicePair.deviceTypeRef, + deviceTypeRef: this.deviceTypeTmp?.map?.( + (dt) => dt.deviceTypeRef + )?.[0], }) .then((response) => { this.$store @@ -358,7 +391,9 @@ export default { profileId: parseInt(this.shownEndpoint.profileIdentifier), endpointType: response.id, endpointVersion: this.shownEndpoint.deviceVersion, - deviceIdentifier: this.devicePair.deviceIdentifier, + deviceIdentifier: this.deviceTypeTmp?.map?.( + (dt) => dt.deviceIdentifier + )?.[0], }) .then((res) => { if (this.shareClusterStatesAcrossEndpoints()) { @@ -401,7 +436,7 @@ export default { this.$store.dispatch('zap/updateEndpointType', { endpointTypeId: endpointTypeReference, updatedKey: RestApi.updateKey.deviceTypeRef, - updatedValue: this.devicePair.deviceTypeRef, + updatedValue: this.deviceTypeTmp?.map?.((dt) => dt.deviceTypeRef)?.[0], }) this.$store.dispatch('zap/updateEndpoint', { @@ -425,7 +460,9 @@ export default { }, { updatedKey: RestApi.updateKey.deviceId, - value: parseInt(this.devicePair.deviceIdentifier), + value: parseInt( + this.deviceTypeTmp?.map?.((dt) => dt.deviceIdentifier)?.[0] + ), }, ], }) @@ -469,22 +506,6 @@ export default { ) } }, - createValue(val, done) { - try { - done( - { - deviceTypeRef: this.devicePair.deviceTypeRef - ? this.devicePair.deviceTypeRef - : this.customDeviceIdReference, - deviceIdentifier: parseInt(val), - }, - 'add-unique' - ) - } catch (err) { - //Catch bad inputs. - console.log(err) - } - }, filterDeviceTypes(val, update) { if (val === '') { update(() => { diff --git a/src/store/zap/actions.js b/src/store/zap/actions.js index 1133401d36..0920c48342 100644 --- a/src/store/zap/actions.js +++ b/src/store/zap/actions.js @@ -227,6 +227,7 @@ export function updateSelectedEndpoint(context, endpoint) { } export function updateEndpointType(context, endpointType) { + // TODO this uri should handle deviceTypeRef as array axiosRequests .$serverPatch(restApi.uri.endpointType, endpointType) .then((res) => { @@ -234,7 +235,7 @@ export function updateEndpointType(context, endpointType) { if (arg.updatedKey === 'deviceTypeRef') { setDeviceTypeReference(context, { endpointId: arg.endpointTypeId, - deviceTypeRef: arg.updatedValue, + deviceTypeRef: arg.updatedValue, // TODO this should be an array }) } }) @@ -296,6 +297,7 @@ export function setDeviceTypeReference(context, endpointIdDeviceTypeRefPair) { } export function updateEndpoint(context, endpoint) { + // TODO this uri should handle deviceIdentifier as array axiosRequests.$serverPatch(restApi.uri.endpoint, endpoint).then((res) => { let arg = res.data context.commit('updateEndpoint', { @@ -308,36 +310,42 @@ export function updateEndpoint(context, endpoint) { } export function addEndpoint(context, newEndpointContext) { - return axiosRequests - .$serverPost(restApi.uri.endpoint, newEndpointContext) - .then((res) => { - let arg = res.data - context.commit('addEndpoint', { - id: arg.id, - endpointId: arg.endpointId, - endpointTypeRef: arg.endpointType, - networkId: arg.networkId, - profileId: arg.profileId, - deviceIdentifier: arg.deviceId, - endpointVersion: arg.endpointVersion, - endpointIdValidationIssues: arg.validationIssues.endpointId, - networkIdValidationIssues: arg.validationIssues.networkId, + return ( + axiosRequests + // TODO this uri should handle deviceIdentifier as array + .$serverPost(restApi.uri.endpoint, newEndpointContext) + .then((res) => { + let arg = res.data + context.commit('addEndpoint', { + id: arg.id, + endpointId: arg.endpointId, + endpointTypeRef: arg.endpointType, + networkId: arg.networkId, + profileId: arg.profileId, + deviceIdentifier: arg.deviceId, // TODO this should be array too + endpointVersion: arg.endpointVersion, + endpointIdValidationIssues: arg.validationIssues.endpointId, + networkIdValidationIssues: arg.validationIssues.networkId, + }) + return arg }) - return arg - }) + ) } export function addEndpointType(context, endpointTypeData) { - return axiosRequests - .$serverPost(restApi.uri.endpointType, endpointTypeData) - .then((res) => { - context.commit('addEndpointType', { - id: res.data.id, - name: res.data.name, - deviceTypeRef: res.data.deviceTypeRef, + return ( + axiosRequests + // TODO this uri should handle deviceTypeRef as array + .$serverPost(restApi.uri.endpointType, endpointTypeData) + .then((res) => { + context.commit('addEndpointType', { + id: res.data.id, + name: res.data.name, + deviceTypeRef: res.data.deviceTypeRef, // TODO array should be returned + }) + return res.data }) - return res.data - }) + ) } export function duplicateEndpointType(context, { endpointTypeId }) { From 5d2081eebcb06be932bd4f20ffce7114bbbd854a Mon Sep 17 00:00:00 2001 From: Bharat Dandu Date: Wed, 24 May 2023 16:44:13 -0400 Subject: [PATCH 03/40] Enabling multiple zcl device types per endpoint draft commit. Edit this comment later Github: ZAP#862 --- src-electron/db/query-config.js | 100 ++++++++++++++------- src-electron/db/query-endpoint-type.js | 39 ++++++-- src-electron/db/query-endpoint.js | 41 ++++----- src-electron/db/query-impexp.js | 8 +- src-electron/db/zap-schema.sql | 21 ++++- src/components/ZclCreateModifyEndpoint.vue | 43 +++++---- src/components/ZclEndpointCard.vue | 88 +++++++++++------- src/store/zap/actions.js | 24 +++-- 8 files changed, 235 insertions(+), 129 deletions(-) diff --git a/src-electron/db/query-config.js b/src-electron/db/query-config.js index 5052b4f0d4..20c882e959 100644 --- a/src-electron/db/query-config.js +++ b/src-electron/db/query-config.js @@ -70,19 +70,18 @@ DO UPDATE SET ENABLED = ?`, * @param {*} db * @param {*} endpointTypeId */ - async function selectEndpointClusters(db, endpointTypeId) { - let rows = await dbApi - .dbAll( - db, - ` +async function selectEndpointClusters(db, endpointTypeId) { + let rows = await dbApi.dbAll( + db, + ` SELECT * FROM ENDPOINT_TYPE_CLUSTER WHERE ENDPOINT_TYPE_REF = ? `, - [endpointTypeId] - ) - - return rows.map(dbMapping.map.endpointTypeCluster) + [endpointTypeId] + ) + + return rows.map(dbMapping.map.endpointTypeCluster) } /** @@ -523,42 +522,68 @@ async function insertEndpointType( db, sessionId, name, - deviceTypeRef, + deviceTypeRefs, doTransaction = true ) { + // Insert endpoint type let newEndpointTypeId = await dbApi.dbInsert( db, - 'INSERT OR REPLACE INTO ENDPOINT_TYPE ( SESSION_REF, NAME, DEVICE_TYPE_REF ) VALUES ( ?, ?, ?)', - [sessionId, name, deviceTypeRef] + 'INSERT OR REPLACE INTO ENDPOINT_TYPE ( SESSION_REF, NAME ) VALUES ( ?, ?)', + [sessionId, name] ) - await setEndpointDefaults( + + // Creating endpoint type and device type ref combinations along with order of insertion + let newEndpointTypeIdDeviceCombination = [] + for (let i = 0; i < deviceTypeRefs.length; i++) { + let endpointTypeDevice = [newEndpointTypeId, deviceTypeRefs[i], i] + newEndpointTypeIdDeviceCombination.push(endpointTypeDevice) + } + + // Insert into endpoint_type_device + await dbApi.dbMultiInsert( db, - sessionId, - newEndpointTypeId, - deviceTypeRef, - doTransaction + 'INSERT INTO ENDPOINT_TYPE_DEVICE (ENDPOINT_TYPE_REF, DEVICE_TYPE_REF, DEVICE_TYPE_ORDER) VALUES (?, ?, ?)', + newEndpointTypeIdDeviceCombination ) + + // Resolve endpointDefaults based on device type order. Reversing the order + // such that the device type defaults are maintained based on the order from + // deviceTypeRefs + let deviceTypeRefsReversed = deviceTypeRefs.reverse() + for (const dtRef of deviceTypeRefsReversed) { + await setEndpointDefaults( + db, + sessionId, + newEndpointTypeId, + dtRef, + doTransaction + ) + } return newEndpointTypeId } /** -* Promises to duplicate an endpoint type. -* -* @export -* @param {*} db -* @param {*} endpointTypeId -* @returns Promise to duplicate endpoint type. -*/ -async function duplicateEndpointType( - db, - endpointTypeId - ) { + * Promises to duplicate an endpoint type. + * + * @export + * @param {*} db + * @param {*} endpointTypeId + * @returns Promise to duplicate endpoint type. + */ +async function duplicateEndpointType(db, endpointTypeId) { let newEndpointTypeId = await dbApi.dbInsert( db, `INSERT INTO ENDPOINT_TYPE (SESSION_REF, NAME, DEVICE_TYPE_REF) - select SESSION_REF, NAME, DEVICE_TYPE_REF - from ENDPOINT_TYPE - where ENDPOINT_TYPE_ID = ?`, + SELECT + ENDPOINT_TYPE.SESSION_REF, ENDPOINT_TYPE.NAME, ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF + FROM + ENDPOINT_TYPE + INNER JOIN + ENDPOINT_TYPE_DEVICE + ON + ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF + WHERE + ENDPOINT_TYPE_ID = ?`, [endpointTypeId] ) @@ -583,12 +608,21 @@ async function updateEndpointType( let param = convertRestKeyToDbColumn(updateKey) let wasPresent = await dbApi.dbGet( db, - 'SELECT DEVICE_TYPE_REF FROM ENDPOINT_TYPE WHERE ENDPOINT_TYPE_ID = ? AND SESSION_REF = ?', + ` + SELECT + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF + FROM + ENDPOINT_TYPE + INNER JOIN + ENDPOINT_TYPE_DEVICE + ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF + WHERE + ENDPOINT_TYPE_ID = ? AND SESSION_REF = ?`, [endpointTypeId, sessionId] ) let newEndpointId = await dbApi.dbUpdate( - db, + db, // Check for update with schema change `UPDATE ENDPOINT_TYPE SET ${param} = ? WHERE ENDPOINT_TYPE_ID = ? AND SESSION_REF = ?`, [updatedValue, endpointTypeId, sessionId] ) diff --git a/src-electron/db/query-endpoint-type.js b/src-electron/db/query-endpoint-type.js index e28ea19a04..056b42a049 100644 --- a/src-electron/db/query-endpoint-type.js +++ b/src-electron/db/query-endpoint-type.js @@ -51,12 +51,16 @@ async function selectAllEndpointTypes(db, sessionId) { db, ` SELECT - ENDPOINT_TYPE_ID, - NAME, - DEVICE_TYPE_REF, - SESSION_REF + ENDPOINT_TYPE.ENDPOINT_TYPE_ID, + ENDPOINT_TYPE.NAME, + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF, + ENDPOINT_TYPE.SESSION_REF FROM ENDPOINT_TYPE +INNER JOIN + ENDPOINT_TYPE_DEVICE +ON + ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF WHERE SESSION_REF = ? ORDER BY NAME`, [sessionId] ) @@ -85,10 +89,14 @@ SELECT ENDPOINT_TYPE.ENDPOINT_TYPE_ID FROM ENDPOINT_TYPE +INNER JOIN + ENDPOINT_TYPE_DEVICE +ON + ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF LEFT JOIN DEVICE_TYPE ON - ENDPOINT_TYPE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID WHERE ENDPOINT_TYPE.SESSION_REF = ? ORDER BY ENDPOINT_TYPE.NAME`, @@ -125,10 +133,14 @@ INNER JOIN ENDPOINT ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT.ENDPOINT_TYPE_REF +INNER JOIN + ENDPOINT_TYPE_DEVICE +ON + ENDPOINT_TYPE.ENDPOINT_TYPE = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF LEFT JOIN DEVICE_TYPE ON - ENDPOINT_TYPE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID WHERE ENDPOINT_TYPE.SESSION_REF = ? ORDER BY ENDPOINT_TYPE.NAME`, @@ -148,7 +160,20 @@ async function selectEndpointType(db, id) { return dbApi .dbGet( db, - `SELECT ENDPOINT_TYPE_ID, SESSION_REF, NAME, DEVICE_TYPE_REF FROM ENDPOINT_TYPE WHERE ENDPOINT_TYPE_ID = ?`, + ` + SELECT + ENDPOINT_TYPE.ENDPOINT_TYPE_ID, + ENDPOINT_TYPE.SESSION_REF, + ENDPOINT_TYPE.NAME, + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF + FROM + ENDPOINT_TYPE + INNER JOIN + ENDPOINT_TYPE_DEVICE + ON + ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF + WHERE + ENDPOINT_TYPE_ID = ?`, [id] ) .then(dbMapping.map.endpointType) diff --git a/src-electron/db/query-endpoint.js b/src-electron/db/query-endpoint.js index 6d958a9d14..3b95e00047 100644 --- a/src-electron/db/query-endpoint.js +++ b/src-electron/db/query-endpoint.js @@ -274,9 +274,10 @@ ORDER BY C.CODE * @returns promise that resolves into endpoint cluster events */ async function selectEndpointClusterEvents(db, clusterId, endpointTypeId) { - return dbApi.dbAll( - db, - ` + return dbApi + .dbAll( + db, + ` SELECT E.EVENT_ID, E.CLUSTER_REF, @@ -299,9 +300,9 @@ WHERE AND ETE.ENDPOINT_TYPE_REF = ? ORDER BY E.MANUFACTURER_CODE, E.CODE `, - [clusterId, endpointTypeId] - ) - .then((rows) => rows.map(dbMapping.map.event)) + [clusterId, endpointTypeId] + ) + .then((rows) => rows.map(dbMapping.map.event)) } /** @@ -337,6 +338,9 @@ async function insertEndpoint( endpointVersion, deviceIdentifier ) { + let primaryDeviceIdentifierForEndpoint = Array.isArray(deviceIdentifier) + ? deviceIdentifier[0] + : deviceIdentifier return dbApi.dbInsert( db, ` @@ -356,31 +360,28 @@ INTO ENDPOINT ( endpointTypeRef, networkIdentifier, endpointVersion, - deviceIdentifier, + primaryDeviceIdentifierForEndpoint, profileIdentifier, ] ) } /** -* @export -* @param {*} db -* @param {*} id -* @param {*} endpointIdentifier -* @returns Promise to duplicate an endpoint. -*/ -async function duplicateEndpoint( db, id, endpointIdentifier, endpointTypeId ) { - return dbApi.dbInsert( db, + * @export + * @param {*} db + * @param {*} id + * @param {*} endpointIdentifier + * @returns Promise to duplicate an endpoint. + */ +async function duplicateEndpoint(db, id, endpointIdentifier, endpointTypeId) { + return dbApi.dbInsert( + db, ` insert into ENDPOINT (SESSION_REF,ENDPOINT_IDENTIFIER,ENDPOINT_TYPE_REF,NETWORK_IDENTIFIER,DEVICE_VERSION,DEVICE_IDENTIFIER,PROFILE) select SESSION_REF, ? , ? ,NETWORK_IDENTIFIER,DEVICE_VERSION,DEVICE_IDENTIFIER,PROFILE from ENDPOINT where ENDPOINT_ID = ?`, - [ - endpointIdentifier, - endpointTypeId, - id - ] + [endpointIdentifier, endpointTypeId, id] ) } diff --git a/src-electron/db/query-impexp.js b/src-electron/db/query-impexp.js index 3ded761c29..c108a4178a 100644 --- a/src-electron/db/query-impexp.js +++ b/src-electron/db/query-impexp.js @@ -141,12 +141,16 @@ async function exportEndpointTypes(db, sessionId) { SELECT DISTINCT ENDPOINT_TYPE.ENDPOINT_TYPE_ID, ENDPOINT_TYPE.NAME, - ENDPOINT_TYPE.DEVICE_TYPE_REF, + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF, DEVICE_TYPE.CODE AS DEVICE_TYPE_CODE, DEVICE_TYPE.PROFILE_ID as DEVICE_TYPE_PROFILE_ID, DEVICE_TYPE.NAME AS DEVICE_TYPE_NAME FROM ENDPOINT_TYPE +INNER JOIN + ENDPOINT_TYPE_DEVICE +ON + ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF LEFT JOIN ENDPOINT ON @@ -154,7 +158,7 @@ ON LEFT JOIN DEVICE_TYPE ON - ENDPOINT_TYPE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID WHERE ENDPOINT_TYPE.SESSION_REF = ? ORDER BY diff --git a/src-electron/db/zap-schema.sql b/src-electron/db/zap-schema.sql index 78d123a12e..ed47185de0 100644 --- a/src-electron/db/zap-schema.sql +++ b/src-electron/db/zap-schema.sql @@ -715,10 +715,25 @@ CREATE TABLE IF NOT EXISTS "ENDPOINT_TYPE" ( "ENDPOINT_TYPE_ID" integer primary key autoincrement, "SESSION_REF" integer, "NAME" text, - "DEVICE_TYPE_REF" integer, - foreign key (SESSION_REF) references SESSION(SESSION_ID) on delete cascade, - foreign key(DEVICE_TYPE_REF) references DEVICE_TYPE(DEVICE_TYPE_ID) + foreign key (SESSION_REF) references SESSION(SESSION_ID) on delete cascade +); + +/* + ENDPOINT_TYPE_DEVICE: many-to-many relationship between endpoint type and + device type. + */ +DROP TABLE IF EXISTS "ENDPOINT_TYPE_DEVICE"; +CREATE TABLE IF NOT EXISTS "ENDPOINT_TYPE_DEVICE" ( + "ENDPOINT_TYPE_DEVICE_ID" integer primary key autoincrement, + "DEVICE_TYPE_REF" INTEGER, + "ENDPOINT_TYPE_REF" INTEGER, + "DEVICE_TYPE_ORDER" INTEGER, + foreign key(DEVICE_TYPE_REF) references DEVICE_TYPE(DEVICE_TYPE_ID) on delete cascade, + foreign key (ENDPOINT_TYPE_REF) references ENDPOINT_TYPE(ENDPOINT_TYPE_ID) on delete + set NULL, + UNIQUE("ENDPOINT_TYPE_REF", "DEVICE_TYPE_REF") ); + /* ENDPOINT table contains the toplevel configured endpoints. */ diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index 7f2c87e0c9..c431a593a8 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -379,9 +379,7 @@ export default { this.$store .dispatch(`zap/addEndpointType`, { name: 'Anonymous Endpoint Type', - deviceTypeRef: this.deviceTypeTmp?.map?.( - (dt) => dt.deviceTypeRef - )?.[0], + deviceTypeRef: this.deviceTypeTmp?.map?.((dt) => dt.deviceTypeRef), }) .then((response) => { this.$store @@ -393,7 +391,7 @@ export default { endpointVersion: this.shownEndpoint.deviceVersion, deviceIdentifier: this.deviceTypeTmp?.map?.( (dt) => dt.deviceIdentifier - )?.[0], + ), }) .then((res) => { if (this.shareClusterStatesAcrossEndpoints()) { @@ -436,7 +434,7 @@ export default { this.$store.dispatch('zap/updateEndpointType', { endpointTypeId: endpointTypeReference, updatedKey: RestApi.updateKey.deviceTypeRef, - updatedValue: this.deviceTypeTmp?.map?.((dt) => dt.deviceTypeRef)?.[0], + updatedValue: this.deviceTypeTmp?.map?.((dt) => dt.deviceTypeRef), }) this.$store.dispatch('zap/updateEndpoint', { @@ -461,7 +459,7 @@ export default { { updatedKey: RestApi.updateKey.deviceId, value: parseInt( - this.deviceTypeTmp?.map?.((dt) => dt.deviceIdentifier)?.[0] + this.deviceTypeTmp?.map?.((dt) => dt.deviceIdentifier) ), }, ], @@ -493,17 +491,30 @@ export default { }, getDeviceOptionLabel(item) { if (item == null || item.deviceTypeRef == null) return '' - if ( - item.deviceIdentifier != this.zclDeviceTypes[item.deviceTypeRef].code - ) { - return this.asHex(item.deviceIdentifier, 4) - } else { - return ( - this.zclDeviceTypes[item.deviceTypeRef].description + - ' (' + - this.asHex(this.zclDeviceTypes[item.deviceTypeRef].code, 4) + - ')' + if (Array.isArray(item.deviceTypeRef)) { + let deviceOptionLabels = [] + item.deviceTypeRef.forEach((d) => + deviceOptionLabels.push( + this.zclDeviceTypes[d].description + + ' (' + + this.asHex(this.zclDeviceTypes[d].code, 4) + + ')' + ) ) + return deviceOptionLabels + } else { + if ( + item.deviceIdentifier != this.zclDeviceTypes[item.deviceTypeRef].code + ) { + return this.asHex(item.deviceIdentifier, 4) + } else { + return ( + this.zclDeviceTypes[item.deviceTypeRef].description + + ' (' + + this.asHex(this.zclDeviceTypes[item.deviceTypeRef].code, 4) + + ')' + ) + } } }, filterDeviceTypes(val, update) { diff --git a/src/components/ZclEndpointCard.vue b/src/components/ZclEndpointCard.vue index ad56714747..08f9caa037 100644 --- a/src/components/ZclEndpointCard.vue +++ b/src/components/ZclEndpointCard.vue @@ -90,11 +90,18 @@ limitations under the License.
Device
-
- {{ getDeviceOptionLabel() }} +
+
  • + {{ `${dev.description} (${asHex(dev.code, 4)})` }} +
  • +
    +
    + {{ + `${deviceType[0].description} (${asHex(deviceType[0].code, 4)})` + }}
    - +
    Primary Device
    @@ -126,30 +133,6 @@ limitations under the License. {{ endpointVersion[endpointReference] }}
    - -
    - Enabled Clusters -
    -
    - {{ selectedServers.length }} -
    -
    - -
    - Enabled Attributes -
    -
    - {{ selectedAttributes.length }} -
    -
    - -
    - Enabled Reporting -
    -
    - {{ selectedReporting.length }} -
    -
    + deviceOptionLabels.push( + d.description + '(' + this.asHex(d.code, 4) + ')' + ) + ) + return deviceOptionLabels } else { return ( this.deviceType.description + @@ -293,7 +282,22 @@ export default { } }, getPrimaryDeviceOptionLabel() { - return '' // TODO + if (this.deviceType == null) return '' + if (Array.isArray(this.deviceType)) { + return ( + this.deviceType[0].description + + ' (' + + this.asHex(this.deviceType[0].code, 4) + + ')' + ) + } else { + return ( + this.deviceType.description + + ' (' + + this.asHex(this.deviceType.code, 4) + + ')' + ) + } }, handleDeletionDialog() { if (this.getStorageParam() == 'true') { @@ -373,13 +377,29 @@ export default { }, deviceType: { get() { - return this.zclDeviceTypes[ + let refs = this.endpointDeviceTypeRef[this.endpointType[this.endpointReference]] - ] + let deviceTypes = [] + if (refs.length > 0) { + refs.forEach((ref) => deviceTypes.push(this.zclDeviceTypes[ref])) + return deviceTypes + } else { + return this.zclDeviceTypes[ + this.endpointDeviceTypeRef[ + this.endpointType[this.endpointReference] + ] + ] + } }, }, - primaryDeviceType() { - return '' // TODO + isDeviceTypeArray: { + get() { + return ( + Array.isArray(this.deviceType) && + this.deviceType && + this.deviceType.length > 1 + ) + }, }, networkId: { get() { diff --git a/src/store/zap/actions.js b/src/store/zap/actions.js index 0920c48342..dc05e654aa 100644 --- a/src/store/zap/actions.js +++ b/src/store/zap/actions.js @@ -227,7 +227,6 @@ export function updateSelectedEndpoint(context, endpoint) { } export function updateEndpointType(context, endpointType) { - // TODO this uri should handle deviceTypeRef as array axiosRequests .$serverPatch(restApi.uri.endpointType, endpointType) .then((res) => { @@ -235,7 +234,7 @@ export function updateEndpointType(context, endpointType) { if (arg.updatedKey === 'deviceTypeRef') { setDeviceTypeReference(context, { endpointId: arg.endpointTypeId, - deviceTypeRef: arg.updatedValue, // TODO this should be an array + deviceTypeRef: arg.updatedValue, }) } }) @@ -333,19 +332,16 @@ export function addEndpoint(context, newEndpointContext) { } export function addEndpointType(context, endpointTypeData) { - return ( - axiosRequests - // TODO this uri should handle deviceTypeRef as array - .$serverPost(restApi.uri.endpointType, endpointTypeData) - .then((res) => { - context.commit('addEndpointType', { - id: res.data.id, - name: res.data.name, - deviceTypeRef: res.data.deviceTypeRef, // TODO array should be returned - }) - return res.data + return axiosRequests + .$serverPost(restApi.uri.endpointType, endpointTypeData) + .then((res) => { + context.commit('addEndpointType', { + id: res.data.id, + name: res.data.name, + deviceTypeRef: res.data.deviceTypeRef, }) - ) + return res.data + }) } export function duplicateEndpointType(context, { endpointTypeId }) { From 041d79883dc6959153e35b8b33eaf8a7cb4fff0b Mon Sep 17 00:00:00 2001 From: Gergely Kiss Date: Thu, 25 May 2023 20:19:13 +0200 Subject: [PATCH 04/40] Unify array usage for DeviceType and DeviceIndentifier --- src/components/ZclCreateModifyEndpoint.vue | 106 ++++++++++++++------- src/components/ZclEndpointCard.vue | 33 +++---- 2 files changed, 86 insertions(+), 53 deletions(-) diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index c431a593a8..bfef7b17f8 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -154,15 +154,28 @@ export default { this.shownEndpoint.deviceVersion = parseInt( this.endpointVersion[this.endpointReference] ) - // TODO refactor this after API change - const firstDeviceType = { - deviceTypeRef: - this.endpointDeviceTypeRef[this.endpointType[this.endpointReference]], - deviceIdentifier: this.endpointDeviceId[this.endpointReference], + + const deviceTypeRefs = + this.endpointDeviceTypeRef[this.endpointType[this.endpointReference]] + const deviceIdentifiers = this.endpointDeviceId[this.endpointReference] + const deviceTypes = [] + if (Array.isArray(deviceTypeRefs)) { + for (let i = 0; i < deviceTypeRefs.length; i++) { + deviceTypes.push({ + deviceTypeRef: deviceTypeRefs[i], + deviceIdentifier: deviceIdentifiers[i], + }) + } + } else { + deviceTypes.push({ + deviceTypeRef: deviceTypeRefs, + deviceIdentifier: deviceIdentifiers, + }) } + // Set device types only in edit mode - this.deviceTypeTmp = [firstDeviceType] // TODO make device pair to be array and set it here from the store - this.primaryDeviceTypeTmp = null // TODO set it here from the store + this.deviceTypeTmp = deviceTypes + this.primaryDeviceTypeTmp = deviceTypes[0] ?? null // TODO set it here from the store } else { this.shownEndpoint.endpointIdentifier = this.getSmallestUnusedEndpointId() } @@ -376,12 +389,20 @@ export default { ) }, newEpt() { + const deviceTypeRef = [] + this.deviceTypeTmp.forEach((dt) => { + deviceTypeRef.push(dt.deviceTypeRef) + }) this.$store .dispatch(`zap/addEndpointType`, { name: 'Anonymous Endpoint Type', - deviceTypeRef: this.deviceTypeTmp?.map?.((dt) => dt.deviceTypeRef), + deviceTypeRef, }) .then((response) => { + const deviceIdentifier = [] + this.deviceTypeTmp.forEach((dt) => + deviceIdentifier.push(dt.deviceIdentifier) + ) this.$store .dispatch(`zap/addEndpoint`, { endpointId: parseInt(this.shownEndpoint.endpointIdentifier), @@ -389,9 +410,7 @@ export default { profileId: parseInt(this.shownEndpoint.profileIdentifier), endpointType: response.id, endpointVersion: this.shownEndpoint.deviceVersion, - deviceIdentifier: this.deviceTypeTmp?.map?.( - (dt) => dt.deviceIdentifier - ), + deviceIdentifier, }) .then((res) => { if (this.shareClusterStatesAcrossEndpoints()) { @@ -431,10 +450,18 @@ export default { editEpt(shownEndpoint, endpointReference) { let endpointTypeReference = this.endpointType[this.endpointReference] + const deviceTypeRef = [] + const deviceIdentifier = [] + + this.deviceTypeTmp.forEach((dt) => { + deviceTypeRef.push(dt.deviceTypeRef) + deviceIdentifier.push(parseInt(dt.deviceIdentifier)) + }) + this.$store.dispatch('zap/updateEndpointType', { endpointTypeId: endpointTypeReference, updatedKey: RestApi.updateKey.deviceTypeRef, - updatedValue: this.deviceTypeTmp?.map?.((dt) => dt.deviceTypeRef), + updatedValue: deviceTypeRef, }) this.$store.dispatch('zap/updateEndpoint', { @@ -458,9 +485,7 @@ export default { }, { updatedKey: RestApi.updateKey.deviceId, - value: parseInt( - this.deviceTypeTmp?.map?.((dt) => dt.deviceIdentifier) - ), + value: deviceIdentifier, }, ], }) @@ -491,31 +516,38 @@ export default { }, getDeviceOptionLabel(item) { if (item == null || item.deviceTypeRef == null) return '' - if (Array.isArray(item.deviceTypeRef)) { - let deviceOptionLabels = [] - item.deviceTypeRef.forEach((d) => - deviceOptionLabels.push( - this.zclDeviceTypes[d].description + - ' (' + - this.asHex(this.zclDeviceTypes[d].code, 4) + - ')' - ) + // if (Array.isArray(item.deviceTypeRef)) { + // let deviceOptionLabels = [] + // item.deviceTypeRef.forEach((d) => + // deviceOptionLabels.push( + // this.zclDeviceTypes[d].description + + // ' (' + + // this.asHex(this.zclDeviceTypes[d].code, 4) + + // ')' + // ) + // ) + // return deviceOptionLabels + // } else { + if ( + item.deviceIdentifier != this.zclDeviceTypes[item.deviceTypeRef].code + ) { + console.log( + item.deviceIdentifier, + '-', + item.deviceTypeRef, + '-', + this.zclDeviceTypes[item.deviceTypeRef] ) - return deviceOptionLabels + return this.asHex(item.deviceIdentifier, 4) } else { - if ( - item.deviceIdentifier != this.zclDeviceTypes[item.deviceTypeRef].code - ) { - return this.asHex(item.deviceIdentifier, 4) - } else { - return ( - this.zclDeviceTypes[item.deviceTypeRef].description + - ' (' + - this.asHex(this.zclDeviceTypes[item.deviceTypeRef].code, 4) + - ')' - ) - } + return ( + this.zclDeviceTypes[item.deviceTypeRef].description + + ' (' + + this.asHex(this.zclDeviceTypes[item.deviceTypeRef].code, 4) + + ')' + ) } + // } }, filterDeviceTypes(val, update) { if (val === '') { diff --git a/src/components/ZclEndpointCard.vue b/src/components/ZclEndpointCard.vue index 08f9caa037..fa8eecddf2 100644 --- a/src/components/ZclEndpointCard.vue +++ b/src/components/ZclEndpointCard.vue @@ -87,18 +87,21 @@ limitations under the License.
    -
    +
    Device -
    -
  • {{ `${dev.description} (${asHex(dev.code, 4)})` }}
  • -
    - {{ - `${deviceType[0].description} (${asHex(deviceType[0].code, 4)})` - }} +
    +
    + Device +
    +
    + {{ + `${deviceType[0].description} (${asHex(deviceType[0].code, 4)})` + }} +
    @@ -384,21 +387,19 @@ export default { refs.forEach((ref) => deviceTypes.push(this.zclDeviceTypes[ref])) return deviceTypes } else { - return this.zclDeviceTypes[ - this.endpointDeviceTypeRef[ - this.endpointType[this.endpointReference] - ] + return [ + this.zclDeviceTypes[ + this.endpointDeviceTypeRef[ + this.endpointType[this.endpointReference] + ] + ], ] } }, }, isDeviceTypeArray: { get() { - return ( - Array.isArray(this.deviceType) && - this.deviceType && - this.deviceType.length > 1 - ) + return Array.isArray(this.deviceType) && this.deviceType.length > 1 }, }, networkId: { From 89fea30efc849cb63e0f7696452a798e9dedda0b Mon Sep 17 00:00:00 2001 From: Bharat Dandu Date: Wed, 31 May 2023 09:58:25 -0400 Subject: [PATCH 05/40] Updating updateEndpoint and duplicateEndpoint based on the schema change with the introduction of Endpoint_type_device table Github: ZAP#682 --- src-electron/db/query-config.js | 82 +++++++++++++++++++--- src-electron/db/query-device-type.js | 6 +- src/components/ZclCreateModifyEndpoint.vue | 9 +-- 3 files changed, 76 insertions(+), 21 deletions(-) diff --git a/src-electron/db/query-config.js b/src-electron/db/query-config.js index 20c882e959..41d016e060 100644 --- a/src-electron/db/query-config.js +++ b/src-electron/db/query-config.js @@ -351,6 +351,8 @@ function getAllParamValuePairArrayClauses(paramValuePairArray) { currentString += false } else if (paramValuePair.value == null) { currentString += 'null' + } else if (Array.isArray(paramValuePair.value)) { + currentString += paramValuePair.value[0] } else { if (paramValuePair.type == 'text') { currentString += "'" + paramValuePair.value + "'" @@ -549,7 +551,7 @@ async function insertEndpointType( // Resolve endpointDefaults based on device type order. Reversing the order // such that the device type defaults are maintained based on the order from // deviceTypeRefs - let deviceTypeRefsReversed = deviceTypeRefs.reverse() + let deviceTypeRefsReversed = deviceTypeRefs for (const dtRef of deviceTypeRefsReversed) { await setEndpointDefaults( db, @@ -571,9 +573,10 @@ async function insertEndpointType( * @returns Promise to duplicate endpoint type. */ async function duplicateEndpointType(db, endpointTypeId) { - let newEndpointTypeId = await dbApi.dbInsert( + // Extract all the device types based on endpoint type id + let endpointTypeDeviceInfo = await dbApi.dbAll( db, - `INSERT INTO ENDPOINT_TYPE (SESSION_REF, NAME, DEVICE_TYPE_REF) + ` SELECT ENDPOINT_TYPE.SESSION_REF, ENDPOINT_TYPE.NAME, ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF FROM @@ -583,10 +586,41 @@ async function duplicateEndpointType(db, endpointTypeId) { ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF WHERE - ENDPOINT_TYPE_ID = ?`, + ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF = ?`, [endpointTypeId] ) + let newEndpointTypeId = 0 + if (endpointTypeDeviceInfo && endpointTypeDeviceInfo.length > 0) { + // Enter into the endpoint_type table + newEndpointTypeId = await dbApi.dbInsert( + db, + `INSERT INTO ENDPOINT_TYPE (SESSION_REF, NAME) + VALUES (?, ?)`, + [endpointTypeDeviceInfo[0].SESSION_REF, endpointTypeDeviceInfo[0].NAME] + ) + + // Enter into the endpoint_type_device table to establish the endpoint_type + // and device type relationship + let endpointTypeDeviceInfoValues = [] + endpointTypeDeviceInfo.forEach((dt, index) => + endpointTypeDeviceInfoValues.push([ + newEndpointTypeId, + dt.DEVICE_TYPE_REF, + index, + ]) + ) + await dbApi.dbMultiInsert( + db, + ` + INSERT INTO + ENDPOINT_TYPE_DEVICE (ENDPOINT_TYPE_REF, DEVICE_TYPE_REF, DEVICE_TYPE_ORDER) + VALUES + (?, ?, ?)`, + endpointTypeDeviceInfoValues + ) + } + return newEndpointTypeId } @@ -606,7 +640,7 @@ async function updateEndpointType( updatedValue ) { let param = convertRestKeyToDbColumn(updateKey) - let wasPresent = await dbApi.dbGet( + let existingDeviceTypes = await dbApi.dbAll( db, ` SELECT @@ -620,14 +654,42 @@ async function updateEndpointType( ENDPOINT_TYPE_ID = ? AND SESSION_REF = ?`, [endpointTypeId, sessionId] ) + let newEndpointId = endpointTypeId + if (param != 'DEVICE_TYPE_REF') { + newEndpointId = await dbApi.dbUpdate( + db, // Check for update with schema change + `UPDATE ENDPOINT_TYPE SET ${param} = ? WHERE ENDPOINT_TYPE_ID = ? AND SESSION_REF = ?`, + [updatedValue, endpointTypeId, sessionId] + ) + } + + existingDeviceTypes = existingDeviceTypes.map((dt) => dt[param]) + // Delete the endpoint_type_device references based on endpoint_type_id + await dbApi.dbRemove( + db, + 'DELETE FROM ENDPOINT_TYPE_DEVICE WHERE ENDPOINT_TYPE_REF = ?', + endpointTypeId + ) - let newEndpointId = await dbApi.dbUpdate( - db, // Check for update with schema change - `UPDATE ENDPOINT_TYPE SET ${param} = ? WHERE ENDPOINT_TYPE_ID = ? AND SESSION_REF = ?`, - [updatedValue, endpointTypeId, sessionId] + //Re-insert endpoint_type_device references with the new references to device types + let endpointTypeDeviceInfoValues = [] + existingDeviceTypes.forEach((dt, index) => + endpointTypeDeviceInfoValues.push([endpointTypeId, dt, index]) + ) + await dbApi.dbMultiInsert( + db, + ` + INSERT INTO + ENDPOINT_TYPE_DEVICE (ENDPOINT_TYPE_REF, DEVICE_TYPE_REF, DEVICE_TYPE_ORDER) + VALUES + (?, ?, ?)`, + endpointTypeDeviceInfoValues ) - if (param === 'DEVICE_TYPE_REF' && wasPresent[param] != updatedValue) { + let isDeviceTypeRefsUpdated = + existingDeviceTypes.length === updatedValue.length && + existingDeviceTypes.every((value, index) => value == updatedValue[index]) + if (param === 'DEVICE_TYPE_REF' && isDeviceTypeRefsUpdated) { await setEndpointDefaults(db, sessionId, endpointTypeId, updatedValue) } return newEndpointId diff --git a/src-electron/db/query-device-type.js b/src-electron/db/query-device-type.js index 46306d8faa..129c50213d 100644 --- a/src-electron/db/query-device-type.js +++ b/src-electron/db/query-device-type.js @@ -92,7 +92,7 @@ async function selectDeviceTypeClustersByDeviceTypeRef(db, deviceTypeRef) { FROM DEVICE_TYPE_CLUSTER WHERE - DEVICE_TYPE_REF = ? + DEVICE_TYPE_REF IN (?) ORDER BY CLUSTER_NAME`, [deviceTypeRef] ) @@ -146,7 +146,7 @@ async function selectDeviceTypeAttributesByDeviceTypeRef(db, deviceTypeRef) { ON AT.ATTRIBUTE_REF = ATTRIBUTE.ATTRIBUTE_ID WHERE - C.DEVICE_TYPE_REF = ?`, + C.DEVICE_TYPE_REF IN (?)`, [deviceTypeRef] ) return rows.map(dbMapping.map.deviceTypeAttribute) @@ -174,7 +174,7 @@ async function selectDeviceTypeCommandsByDeviceTypeRef(db, deviceTypeRef) { ON CMD.COMMAND_REF = COMMAND.COMMAND_ID WHERE - C.DEVICE_TYPE_REF = ?`, + C.DEVICE_TYPE_REF IN (?)`, [deviceTypeRef] ) return rows.map(dbMapping.map.deviceTypeCommand) diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index bfef7b17f8..6d701a634c 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -132,7 +132,7 @@ const _ = require('lodash') export default { name: 'ZclCreateModifyEndpoint', props: ['endpointReference'], - emits: ['saveOrCreateValidated'], + emits: ['saveOrCreateValidated', 'updateData'], mixins: [CommonMixin], watch: { deviceTypeRefAndDeviceIdPair(val) { @@ -531,13 +531,6 @@ export default { if ( item.deviceIdentifier != this.zclDeviceTypes[item.deviceTypeRef].code ) { - console.log( - item.deviceIdentifier, - '-', - item.deviceTypeRef, - '-', - this.zclDeviceTypes[item.deviceTypeRef] - ) return this.asHex(item.deviceIdentifier, 4) } else { return ( From b47e73ce16a1e5a5069eb00fd0b958c9048e54f4 Mon Sep 17 00:00:00 2001 From: Bharat Dandu Date: Wed, 31 May 2023 15:58:03 -0400 Subject: [PATCH 06/40] Updating import/export endpoint type apis to handle multiple zcl device types per endpoint Github: ZAP#862 --- src-electron/db/db-mapping.js | 2 + src-electron/db/query-config.js | 7 +- src-electron/db/query-impexp.js | 168 +++++++++++++++++--------------- 3 files changed, 91 insertions(+), 86 deletions(-) diff --git a/src-electron/db/db-mapping.js b/src-electron/db/db-mapping.js index f3c59e4378..cb3d2d7ad8 100644 --- a/src-electron/db/db-mapping.js +++ b/src-electron/db/db-mapping.js @@ -377,6 +377,7 @@ exports.map = { profileId: x.PROFILE_ID, domain: x.DOMAIN, label: x.NAME, + name: x.NAME, caption: x.DESCRIPTION, } }, @@ -440,6 +441,7 @@ exports.map = { sessionRef: x.SESSION_REF, name: x.NAME, deviceTypeRef: x.DEVICE_TYPE_REF, + deviceTypes: x.deviceTypes, } }, endpointTypeCluster: (x) => { diff --git a/src-electron/db/query-config.js b/src-electron/db/query-config.js index 41d016e060..6b275f092d 100644 --- a/src-electron/db/query-config.js +++ b/src-electron/db/query-config.js @@ -548,11 +548,8 @@ async function insertEndpointType( newEndpointTypeIdDeviceCombination ) - // Resolve endpointDefaults based on device type order. Reversing the order - // such that the device type defaults are maintained based on the order from - // deviceTypeRefs - let deviceTypeRefsReversed = deviceTypeRefs - for (const dtRef of deviceTypeRefsReversed) { + // Resolve endpointDefaults based on device type order. + for (const dtRef of deviceTypeRefs) { await setEndpointDefaults( db, sessionId, diff --git a/src-electron/db/query-impexp.js b/src-electron/db/query-impexp.js index c108a4178a..b87bd9d07d 100644 --- a/src-electron/db/query-impexp.js +++ b/src-electron/db/query-impexp.js @@ -22,6 +22,8 @@ */ const dbApi = require('./db-api') const dbEnums = require('../../src-shared/db-enum') +const dbMapping = require('./db-mapping.js') + /** * Imports a single endpoint * @param {} db @@ -125,50 +127,62 @@ ORDER BY E.ENDPOINT_IDENTIFIER * @returns promise that resolves into rows in the database table. */ async function exportEndpointTypes(db, sessionId) { - let mapFunction = (x) => { - return { - endpointTypeId: x.ENDPOINT_TYPE_ID, - name: x.NAME, - deviceTypeName: x.DEVICE_TYPE_NAME, - deviceTypeCode: x.DEVICE_TYPE_CODE, - deviceTypeProfileId: x.DEVICE_TYPE_PROFILE_ID, - } - } - return dbApi + // retreive all endpoint types + let endpointTypes = await dbApi .dbAll( db, ` -SELECT DISTINCT +SELECT ENDPOINT_TYPE.ENDPOINT_TYPE_ID, - ENDPOINT_TYPE.NAME, - ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF, - DEVICE_TYPE.CODE AS DEVICE_TYPE_CODE, - DEVICE_TYPE.PROFILE_ID as DEVICE_TYPE_PROFILE_ID, - DEVICE_TYPE.NAME AS DEVICE_TYPE_NAME + ENDPOINT_TYPE.NAME FROM ENDPOINT_TYPE -INNER JOIN - ENDPOINT_TYPE_DEVICE -ON - ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF LEFT JOIN ENDPOINT ON ENDPOINT.ENDPOINT_TYPE_REF = ENDPOINT_TYPE.ENDPOINT_TYPE_ID -LEFT JOIN - DEVICE_TYPE -ON - ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID WHERE ENDPOINT_TYPE.SESSION_REF = ? ORDER BY ENDPOINT.ENDPOINT_IDENTIFIER, - ENDPOINT_TYPE.NAME, - DEVICE_TYPE_CODE, - DEVICE_TYPE_PROFILE_ID`, + ENDPOINT_TYPE.NAME`, [sessionId] ) - .then((rows) => rows.map(mapFunction)) + .then((rows) => rows.map(dbMapping.map.endpointType)) + + //Associate each endpoint type to the device types + for (let et of endpointTypes) { + et.deviceTypes = await dbApi + .dbAll( + db, + ` + SELECT + DEVICE_TYPE.DEVICE_TYPE_ID, + DEVICE_TYPE.CODE, + DEVICE_TYPE.NAME, + DEVICE_TYPE.PROFILE_ID + FROM + DEVICE_TYPE + LEFT JOIN + ENDPOINT_TYPE_DEVICE + ON + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID + INNER JOIN + ENDPOINT_TYPE + ON + ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF + WHERE + ENDPOINT_TYPE.SESSION_REF = ? + AND ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF = ? + ORDER BY + DEVICE_TYPE.NAME, + DEVICE_TYPE.CODE, + DEVICE_TYPE.PROFILE_ID`, + [sessionId, et.endpointTypeId] + ) + .then((rows) => rows.map(dbMapping.map.deviceType)) + } + return endpointTypes } /** @@ -181,66 +195,58 @@ ORDER BY * @returns Promise of endpoint insertion. */ async function importEndpointType(db, sessionId, packageIds, endpointType) { - let multipleDeviceIds = await dbApi.dbAll( + // Insert endpoint type + let endpointTypeId = await dbApi.dbInsert( db, - `SELECT DEVICE_TYPE_ID FROM DEVICE_TYPE WHERE CODE = "${parseInt( - endpointType.deviceTypeCode - )}" AND PROFILE_ID = "${parseInt( - endpointType.deviceTypeProfileId - )}" AND PACKAGE_REF IN ("${packageIds}")` + ` + INSERT INTO + ENDPOINT_TYPE ( + SESSION_REF, + NAME + ) VALUES (?, ?)`, + [sessionId, endpointType.name] ) - if (multipleDeviceIds != null && multipleDeviceIds.length > 1) { - // Each endpoint has: 'name', 'deviceTypeName', 'deviceTypeCode', `deviceTypeProfileId`, 'clusters', 'commands', 'attributes' - let deviceTypeId = await dbApi - .dbAll( - db, - `SELECT DEVICE_TYPE_ID,PACKAGE_REF FROM DEVICE_TYPE WHERE CODE = ? AND PROFILE_ID = ? AND NAME = ? AND PACKAGE_REF IN (${dbApi.toInClause( - packageIds - )})`, - [ - parseInt(endpointType.deviceTypeCode), - parseInt(endpointType.deviceTypeProfileId), - endpointType.deviceTypeName, - ] - ) - .then((matchedPackageIds) => matchedPackageIds.shift()?.DEVICE_TYPE_ID) - return dbApi.dbInsert( - db, - ` - INSERT INTO ENDPOINT_TYPE ( - SESSION_REF, - NAME, - DEVICE_TYPE_REF - ) VALUES(?, ?, ?)`, - [sessionId, endpointType.name, deviceTypeId] - ) + // Process device types + let deviceTypes = [] + if (endpointType.deviceTypes) { + deviceTypes = endpointType.deviceTypes } else { - // Each endpoint has: 'name', 'deviceTypeName', 'deviceTypeCode', `deviceTypeProfileId`, 'clusters', 'commands', 'attributes' - let deviceTypeId = await dbApi - .dbAll( - db, - `SELECT DEVICE_TYPE_ID,PACKAGE_REF FROM DEVICE_TYPE WHERE CODE = ? AND PROFILE_ID = ? AND PACKAGE_REF IN (${dbApi.toInClause( - packageIds - )})`, - [ - parseInt(endpointType.deviceTypeCode), - parseInt(endpointType.deviceTypeProfileId), - ] - ) - .then((matchedPackageIds) => matchedPackageIds.shift()?.DEVICE_TYPE_ID) - - return dbApi.dbInsert( + deviceTypes = [ + { + name: endpointType.deviceTypeName, + code: endpointType.deviceTypeCode, + profileId: endpointType.deviceTypeProfileId, + }, + ] + } + let promises = [] + for (let i = 0; i < deviceTypes.length; i++) { + // Get deviceType IDs + let rows = await dbApi.dbAll( db, - ` - INSERT INTO ENDPOINT_TYPE ( - SESSION_REF, - NAME, - DEVICE_TYPE_REF - ) VALUES( ?, ?, ?)`, - [sessionId, endpointType.name, deviceTypeId] + `SELECT DEVICE_TYPE_ID FROM DEVICE_TYPE WHERE CODE = ? AND PROFILE_ID = ? AND NAME = ? AND PACKAGE_REF IN (${packageIds})`, + [ + parseInt(deviceTypes[i].code), + parseInt(deviceTypes[i].profileId), + deviceTypes[i].name, + ] ) + + // Associate deviceTypes with the endpointType + for (let row of rows) { + promises.push( + dbApi.dbInsert( + db, + 'INSERT OR REPLACE INTO ENDPOINT_TYPE_DEVICE(ENDPOINT_TYPE_REF, DEVICE_TYPE_REF, DEVICE_TYPE_ORDER) VALUES(?, ?, ?)', + [endpointTypeId, row.DEVICE_TYPE_ID, i] + ) + ) + } } + + await Promise.all(promises) + return endpointTypeId } /** From 19a02a4eb58c6042cf9ada271a5a9e26fcdcbb44 Mon Sep 17 00:00:00 2001 From: Bharat Dandu Date: Thu, 1 Jun 2023 13:40:22 -0400 Subject: [PATCH 07/40] Updating selectAllEndpointTypes and selectEndpointType such that they update the multiple zcl device types correctly Github: ZAP#862 --- src-electron/db/query-endpoint-type.js | 102 ++++++++++++++++--------- 1 file changed, 68 insertions(+), 34 deletions(-) diff --git a/src-electron/db/query-endpoint-type.js b/src-electron/db/query-endpoint-type.js index 056b42a049..4e3d2e30d5 100644 --- a/src-electron/db/query-endpoint-type.js +++ b/src-electron/db/query-endpoint-type.js @@ -47,24 +47,54 @@ async function deleteEndpointType(db, id) { * @returns promise that resolves into rows in the database table. */ async function selectAllEndpointTypes(db, sessionId) { - let rows = await dbApi.dbAll( - db, - ` + let endpointTypes = await dbApi + .dbAll( + db, + ` SELECT ENDPOINT_TYPE.ENDPOINT_TYPE_ID, ENDPOINT_TYPE.NAME, - ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF, ENDPOINT_TYPE.SESSION_REF FROM ENDPOINT_TYPE -INNER JOIN - ENDPOINT_TYPE_DEVICE -ON - ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF WHERE SESSION_REF = ? ORDER BY NAME`, - [sessionId] - ) - return rows.map(dbMapping.map.endpointType) + [sessionId] + ) + .then((rows) => rows.map(dbMapping.map.endpointType)) + + // Select deviceTypes for each endpointType + for (let et of endpointTypes) { + et.deviceTypeRef = await dbApi + .dbAll( + db, + ` + SELECT + DEVICE_TYPE.DEVICE_TYPE_ID, + DEVICE_TYPE.CODE, + DEVICE_TYPE.NAME, + DEVICE_TYPE.PROFILE_ID + FROM + DEVICE_TYPE + LEFT JOIN + ENDPOINT_TYPE_DEVICE + ON + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID + INNER JOIN + ENDPOINT_TYPE + ON + ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF + WHERE + ENDPOINT_TYPE.SESSION_REF = ? + AND ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF = ? + ORDER BY + DEVICE_TYPE.NAME, + DEVICE_TYPE.CODE, + DEVICE_TYPE.PROFILE_ID`, + [sessionId, et.endpointTypeId] + ) + .then((rows) => rows.map((x) => x.DEVICE_TYPE_ID)) + } + return endpointTypes } /** @@ -89,14 +119,6 @@ SELECT ENDPOINT_TYPE.ENDPOINT_TYPE_ID FROM ENDPOINT_TYPE -INNER JOIN - ENDPOINT_TYPE_DEVICE -ON - ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF -LEFT JOIN - DEVICE_TYPE -ON - ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID WHERE ENDPOINT_TYPE.SESSION_REF = ? ORDER BY ENDPOINT_TYPE.NAME`, @@ -133,14 +155,6 @@ INNER JOIN ENDPOINT ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT.ENDPOINT_TYPE_REF -INNER JOIN - ENDPOINT_TYPE_DEVICE -ON - ENDPOINT_TYPE.ENDPOINT_TYPE = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF -LEFT JOIN - DEVICE_TYPE -ON - ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID WHERE ENDPOINT_TYPE.SESSION_REF = ? ORDER BY ENDPOINT_TYPE.NAME`, @@ -157,26 +171,46 @@ ORDER BY ENDPOINT_TYPE.NAME`, * @returns endpoint type */ async function selectEndpointType(db, id) { - return dbApi + let endpointTypeId = await dbApi .dbGet( db, ` SELECT ENDPOINT_TYPE.ENDPOINT_TYPE_ID, ENDPOINT_TYPE.SESSION_REF, - ENDPOINT_TYPE.NAME, - ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF + ENDPOINT_TYPE.NAME FROM ENDPOINT_TYPE - INNER JOIN - ENDPOINT_TYPE_DEVICE - ON - ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF WHERE ENDPOINT_TYPE_ID = ?`, [id] ) .then(dbMapping.map.endpointType) + + // Device types for endpoint + endpointType.deviceTypes = await dbApi + .dbAll( + db, + ` + SELECT + DEVICE_TYPE.DEVICE_TYPE_ID + FROM + DEVICE_TYPE + LEFT JOIN + ENDPOINT_TYPE_DEVICE + ON + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID + WHERE + ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF = ? + ORDER BY + DEVICE_TYPE.NAME, + DEVICE_TYPE.CODE, + DEVICE_TYPE.PROFILE_ID`, + [id] + ) + .then((rows) => rows.map((row) => row.DEVICE_TYPE_ID)) + + return endpointType } /** From acd213cc3c86c3131c897d8c7d62e40add9724fe Mon Sep 17 00:00:00 2001 From: Bharat Dandu Date: Thu, 1 Jun 2023 16:04:02 -0400 Subject: [PATCH 08/40] Minor cleanup Github: ZAP#862 --- src-electron/db/db-mapping.js | 2 +- src-electron/db/query-config.js | 5 ++++- src-electron/db/query-endpoint-type.js | 5 ++++- src-electron/db/query-impexp.js | 3 +++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src-electron/db/db-mapping.js b/src-electron/db/db-mapping.js index cb3d2d7ad8..56b2985931 100644 --- a/src-electron/db/db-mapping.js +++ b/src-electron/db/db-mapping.js @@ -441,7 +441,7 @@ exports.map = { sessionRef: x.SESSION_REF, name: x.NAME, deviceTypeRef: x.DEVICE_TYPE_REF, - deviceTypes: x.deviceTypes, + deviceTypes: x.deviceTypes, // Populated outside the sql query mapping. } }, endpointTypeCluster: (x) => { diff --git a/src-electron/db/query-config.js b/src-electron/db/query-config.js index 6b275f092d..1278092c3c 100644 --- a/src-electron/db/query-config.js +++ b/src-electron/db/query-config.js @@ -524,9 +524,12 @@ async function insertEndpointType( db, sessionId, name, - deviceTypeRefs, + deviceTypeRef, doTransaction = true ) { + let deviceTypeRefs = Array.isArray(deviceTypeRef) + ? deviceTypeRef + : [deviceTypeRef] // Insert endpoint type let newEndpointTypeId = await dbApi.dbInsert( db, diff --git a/src-electron/db/query-endpoint-type.js b/src-electron/db/query-endpoint-type.js index 4e3d2e30d5..db67700021 100644 --- a/src-electron/db/query-endpoint-type.js +++ b/src-electron/db/query-endpoint-type.js @@ -171,7 +171,7 @@ ORDER BY ENDPOINT_TYPE.NAME`, * @returns endpoint type */ async function selectEndpointType(db, id) { - let endpointTypeId = await dbApi + let endpointType = await dbApi .dbGet( db, ` @@ -210,6 +210,9 @@ async function selectEndpointType(db, id) { ) .then((rows) => rows.map((row) => row.DEVICE_TYPE_ID)) + // Loading endpointTypeRef as primary endpointType for backwards compatibility + endpointType.deviceTypeRef = endpointType.deviceTypes[0] + return endpointType } diff --git a/src-electron/db/query-impexp.js b/src-electron/db/query-impexp.js index b87bd9d07d..4ec137560a 100644 --- a/src-electron/db/query-impexp.js +++ b/src-electron/db/query-impexp.js @@ -181,6 +181,9 @@ ORDER BY [sessionId, et.endpointTypeId] ) .then((rows) => rows.map(dbMapping.map.deviceType)) + + // Loading endpointTypeRef as primary endpointType for backwards compatibility + et.deviceTypeRef = et.deviceTypes[0] } return endpointTypes } From c7945ee835434877c7b2c342bd46be034e1a8caf Mon Sep 17 00:00:00 2001 From: Gergely Kiss Date: Fri, 2 Jun 2023 17:03:29 +0200 Subject: [PATCH 09/40] Add primary device type selection logic --- src/components/ZclCreateModifyEndpoint.vue | 46 ++++++++-------- src/components/ZclEndpointCard.vue | 62 ++++++++-------------- 2 files changed, 45 insertions(+), 63 deletions(-) diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index 6d701a634c..227e8eac96 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -175,13 +175,16 @@ export default { // Set device types only in edit mode this.deviceTypeTmp = deviceTypes - this.primaryDeviceTypeTmp = deviceTypes[0] ?? null // TODO set it here from the store + this.primaryDeviceTypeTmp = deviceTypes[0] ?? null // First item is the primary device type } else { this.shownEndpoint.endpointIdentifier = this.getSmallestUnusedEndpointId() } - const enableMultiDeviceFeatures = true - this.enableMultipleDevice = enableMultiDeviceFeatures // TODO make it data driven from the store - this.enablePrimaryDevice = enableMultiDeviceFeatures // TODO make it data driven from the store + + const enableMultiDeviceFeatures = + this.$store.state.zap.selectedZapConfig?.zclProperties?.category === + 'matter' + this.enableMultipleDevice = enableMultiDeviceFeatures + this.enablePrimaryDevice = enableMultiDeviceFeatures }, data() { return { @@ -291,19 +294,19 @@ export default { const newPrimaryDeviceType = Array.isArray(value) && value.length > 0 ? value[0] : null if (this.enablePrimaryDevice) { - if (this.primaryDeviceType === null) { - this.primaryDeviceType = newPrimaryDeviceType + if (this.primaryDeviceTypeTmp === null) { + this.primaryDeviceTypeTmp = newPrimaryDeviceType } else { if ( !value.includes( (deviceType) => deviceType.deviceTypeRef === - this.primaryDeviceType.deviceTypeRef && + this.primaryDeviceTypeTmp.deviceTypeRef && deviceType.deviceIdentifier === - this.primaryDeviceType.deviceIdentifier + this.primaryDeviceTypeTmp.deviceIdentifier ) ) { - this.primaryDeviceType = newPrimaryDeviceType + this.primaryDeviceTypeTmp = newPrimaryDeviceType } } } @@ -314,9 +317,16 @@ export default { return this.primaryDeviceTypeTmp }, set(value) { - this.primaryDeviceTypeTmp = value - - // TODO write back to the store and backend here + if (this.primaryDeviceTypeTmp?.deviceTypeRef == value?.deviceTypeRef) { + return + } + const newPrimaryDevice = value + let tempDeviceType = this.deviceType + tempDeviceType = tempDeviceType.filter( + (d) => d.deviceTypeRef !== newPrimaryDevice.deviceTypeRef + ) + tempDeviceType.unshift(newPrimaryDevice) + this.deviceType = tempDeviceType }, }, }, @@ -516,18 +526,6 @@ export default { }, getDeviceOptionLabel(item) { if (item == null || item.deviceTypeRef == null) return '' - // if (Array.isArray(item.deviceTypeRef)) { - // let deviceOptionLabels = [] - // item.deviceTypeRef.forEach((d) => - // deviceOptionLabels.push( - // this.zclDeviceTypes[d].description + - // ' (' + - // this.asHex(this.zclDeviceTypes[d].code, 4) + - // ')' - // ) - // ) - // return deviceOptionLabels - // } else { if ( item.deviceIdentifier != this.zclDeviceTypes[item.deviceTypeRef].code ) { diff --git a/src/components/ZclEndpointCard.vue b/src/components/ZclEndpointCard.vue index fa8eecddf2..582d1995a8 100644 --- a/src/components/ZclEndpointCard.vue +++ b/src/components/ZclEndpointCard.vue @@ -99,7 +99,10 @@ limitations under the License.
    {{ - `${deviceType[0].description} (${asHex(deviceType[0].code, 4)})` + `${deviceType[0]?.description} (${asHex( + deviceType[0]?.code, + 4 + )})` }}
    @@ -265,43 +268,6 @@ export default { ) this.deleteEpt() }, - getDeviceOptionLabel() { - if (this.deviceType == null) return '' - if (Array.isArray(this.deviceType)) { - let deviceOptionLabels = [] - this.deviceType.forEach((d, index) => - deviceOptionLabels.push( - d.description + '(' + this.asHex(d.code, 4) + ')' - ) - ) - return deviceOptionLabels - } else { - return ( - this.deviceType.description + - ' (' + - this.asHex(this.deviceType.code, 4) + - ')' - ) - } - }, - getPrimaryDeviceOptionLabel() { - if (this.deviceType == null) return '' - if (Array.isArray(this.deviceType)) { - return ( - this.deviceType[0].description + - ' (' + - this.asHex(this.deviceType[0].code, 4) + - ')' - ) - } else { - return ( - this.deviceType.description + - ' (' + - this.asHex(this.deviceType.code, 4) + - ')' - ) - } - }, handleDeletionDialog() { if (this.getStorageParam() == 'true') { this.deleteEpt() @@ -383,7 +349,7 @@ export default { let refs = this.endpointDeviceTypeRef[this.endpointType[this.endpointReference]] let deviceTypes = [] - if (refs.length > 0) { + if (refs?.length > 0) { refs.forEach((ref) => deviceTypes.push(this.zclDeviceTypes[ref])) return deviceTypes } else { @@ -397,6 +363,24 @@ export default { } }, }, + getPrimaryDeviceOptionLabel() { + if (this.deviceType == null) return '' + if (Array.isArray(this.deviceType)) { + return ( + this.deviceType[0].description + + ' (' + + this.asHex(this.deviceType[0].code, 4) + + ')' + ) + } else { + return ( + this.deviceType.description + + ' (' + + this.asHex(this.deviceType.code, 4) + + ')' + ) + } + }, isDeviceTypeArray: { get() { return Array.isArray(this.deviceType) && this.deviceType.length > 1 From 442b3e524670bfb531ce25bc874b4b381fb2280f Mon Sep 17 00:00:00 2001 From: Gergely Kiss Date: Fri, 2 Jun 2023 18:20:36 +0200 Subject: [PATCH 10/40] Add multi device type modification warning dialog --- src/components/ZclCreateModifyEndpoint.vue | 39 +++++++++++++++- src/components/ZclWarningDialog.vue | 52 ++++++++++++++++++++++ 2 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 src/components/ZclWarningDialog.vue diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index 227e8eac96..5818e9cd25 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -120,6 +120,20 @@ limitations under the License. /> + + + @@ -127,6 +141,7 @@ limitations under the License. import * as RestApi from '../../src-shared/rest-api' import * as DbEnum from '../../src-shared/db-enum' import CommonMixin from '../util/common-mixin' +import ZclWarningDialog from './ZclWarningDialog.vue' const _ = require('lodash') export default { @@ -134,6 +149,7 @@ export default { props: ['endpointReference'], emits: ['saveOrCreateValidated', 'updateData'], mixins: [CommonMixin], + components: { ZclWarningDialog }, watch: { deviceTypeRefAndDeviceIdPair(val) { this.setDeviceTypeCallback(val) @@ -175,6 +191,7 @@ export default { // Set device types only in edit mode this.deviceTypeTmp = deviceTypes + this.deviceTypeMountSnapshot = JSON.parse(JSON.stringify(deviceTypes)) this.primaryDeviceTypeTmp = deviceTypes[0] ?? null // First item is the primary device type } else { this.shownEndpoint.endpointIdentifier = this.getSmallestUnusedEndpointId() @@ -198,8 +215,11 @@ export default { saveOrCreateCloseFlag: false, deviceTypeTmp: [], // Temp store for the selected device types primaryDeviceTypeTmp: null, // Temp store for the selected primary device type - enableMultipleDevice: false, // TODO make it data driven - enablePrimaryDevice: false, // TODO make it data driven + enableMultipleDevice: false, + enablePrimaryDevice: false, + showWarningDialog: false, + warningDialogReturnValue: null, + deviceTypeMountSnapshot: null, } }, computed: { @@ -361,6 +381,21 @@ export default { } }, saveOrCreateHandler() { + // Check if warning dialog available for the given situation + if ( + this.endpointReference && + this.warningDialogReturnValue == null && + this.deviceType?.length > 1 + ) { + // Check if warning dialog should be shown + let deviceTypeChanged = true + // this.deviceTypeMountSnapshot + if (deviceTypeChanged) { + this.showWarningDialog = true + return + } + } + this.warningDialogReturnValue = null let profile = this.$store.state.zap.isProfileIdShown ? this.$refs.profile.validate() : true diff --git a/src/components/ZclWarningDialog.vue b/src/components/ZclWarningDialog.vue new file mode 100644 index 0000000000..d7038a131e --- /dev/null +++ b/src/components/ZclWarningDialog.vue @@ -0,0 +1,52 @@ + + + From 97eb6a778ad387575c49a52db877e40943a8ba61 Mon Sep 17 00:00:00 2001 From: Gergely Kiss Date: Fri, 2 Jun 2023 18:36:51 +0200 Subject: [PATCH 11/40] Generalize the warning message --- src/components/ZclCreateModifyEndpoint.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index 5818e9cd25..d6369e1d42 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -123,7 +123,7 @@ limitations under the License. - - @@ -141,7 +127,6 @@ limitations under the License. import * as RestApi from '../../src-shared/rest-api' import * as DbEnum from '../../src-shared/db-enum' import CommonMixin from '../util/common-mixin' -import ZclWarningDialog from './ZclWarningDialog.vue' const _ = require('lodash') export default { @@ -149,7 +134,6 @@ export default { props: ['endpointReference'], emits: ['saveOrCreateValidated', 'updateData'], mixins: [CommonMixin], - components: { ZclWarningDialog }, watch: { deviceTypeRefAndDeviceIdPair(val) { this.setDeviceTypeCallback(val) @@ -191,7 +175,6 @@ export default { // Set device types only in edit mode this.deviceTypeTmp = deviceTypes - this.deviceTypeMountSnapshot = JSON.parse(JSON.stringify(deviceTypes)) this.primaryDeviceTypeTmp = deviceTypes[0] ?? null // First item is the primary device type } else { this.shownEndpoint.endpointIdentifier = this.getSmallestUnusedEndpointId() @@ -217,10 +200,6 @@ export default { primaryDeviceTypeTmp: null, // Temp store for the selected primary device type enableMultipleDevice: false, enablePrimaryDevice: false, - warningMessage: '', - showWarningDialog: false, - warningDialogReturnValue: null, - deviceTypeMountSnapshot: null, } }, computed: { @@ -382,23 +361,6 @@ export default { } }, saveOrCreateHandler() { - // Check if warning dialog available for the given situation - if ( - this.endpointReference && - this.warningDialogReturnValue == null && - this.deviceType?.length > 1 - ) { - // Check if warning dialog should be shown - let deviceTypeChanged = true - // this.deviceTypeMountSnapshot - if (deviceTypeChanged) { - this.warningMessage = - 'ZCL device type is being modified which can cause all the configuration on the endpoint to be cleared and re-adjusted.' - this.showWarningDialog = true - return - } - } - this.warningDialogReturnValue = null let profile = this.$store.state.zap.isProfileIdShown ? this.$refs.profile.validate() : true @@ -466,7 +428,6 @@ export default { endpointTypeIdList: this.endpointTypeIdList, }) } - this.$store.dispatch('zap/updateSelectedEndpointType', { endpointType: this.endpointType[res.id], deviceTypeRef: @@ -557,8 +518,7 @@ export default { this.$store.dispatch('zap/updateSelectedEndpointType', { endpointType: endpointReference, - deviceTypeRef: - this.endpointDeviceTypeRef[this.endpointType[this.endpointReference]], + deviceTypeRef: deviceTypeRef, }) this.$store.dispatch('zap/updateSelectedEndpoint', this.endpointReference) }, diff --git a/src/components/ZclWarningDialog.vue b/src/components/ZclWarningDialog.vue deleted file mode 100644 index d7038a131e..0000000000 --- a/src/components/ZclWarningDialog.vue +++ /dev/null @@ -1,52 +0,0 @@ - - - From 7e6d38e39be96a25b1712de141aac9a40e806098 Mon Sep 17 00:00:00 2001 From: Bharat Dandu Date: Tue, 6 Jun 2023 15:06:24 -0400 Subject: [PATCH 14/40] Minor cleanup Github: ZAP#862 --- package.json | 1 + src/components/ZclEndpointCard.vue | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index b259ce7254..873e6e4026 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "zap-dotdot": "node src-script/zap-start.js --logToStdout --zcl ./zcl-builtin/dotdot/library.xml -g ./test/gen-template/dotdot/dotdot-templates.json", "zigbeezap-devserver": "node src-script/zap-start.js server --stateDirectory ~/.zap/zigbee-server/ --allowCors --logToStdout --gen ./test/gen-template/zigbee/gen-templates.json --reuseZapInstance", "matterzap-devserver": "node src-script/zap-start.js server --stateDirectory ~/.zap/matter-server/ --allowCors --logToStdout --zcl ./zcl-builtin/matter/zcl.json --gen ./test/resource/meta/gen-test.json --reuseZapInstance", + "matterzap-devserver2": "node src-script/zap-start.js server --stateDirectory --zcl ./zcl-builtin/matter/zcl.json --allowCors --logToStdout --gen ./test/gen-template/matter3/t.json --reuseZapInstance", "server": "node src-script/zap-start.js server --stateDirectory ~/.zap/server/ --allowCors --logToStdout --zcl ./zcl-builtin/silabs/zcl.json --zcl ./zcl-builtin/matter/zcl.json --gen ./test/gen-template/zigbee/gen-templates.json --gen ./test/gen-template/matter/gen-test.json ", "stop": "node src-script/zap-start.js stop --reuseZapInstance", "status": "node src-script/zap-start.js status --reuseZapInstance", diff --git a/src/components/ZclEndpointCard.vue b/src/components/ZclEndpointCard.vue index 582d1995a8..975e5b1955 100644 --- a/src/components/ZclEndpointCard.vue +++ b/src/components/ZclEndpointCard.vue @@ -90,7 +90,9 @@ limitations under the License.
    Device
  • - {{ `${dev.description} (${asHex(dev.code, 4)})` }} + {{ + `${dev.description} (${asHex(dev.code, 4)})` + }}
  • @@ -98,12 +100,12 @@ limitations under the License. Device
    - {{ + {{ `${deviceType[0]?.description} (${asHex( deviceType[0]?.code, 4 )})` - }} + }}
    @@ -112,7 +114,7 @@ limitations under the License. Primary Device
    - {{ getPrimaryDeviceOptionLabel() }} + {{ getPrimaryDeviceOptionLabel }}
    From ee417b6f40348c782061484675353c5aabad33db Mon Sep 17 00:00:00 2001 From: Bharat Dandu Date: Tue, 6 Jun 2023 15:50:24 -0400 Subject: [PATCH 15/40] Removing the UI pieces for this and the tests since this is not really useful in any way Github: ZAP#862 --- .../check_summary/enabled-attributes.spec.js | 49 ----------------- .../check_summary/enabled-clusters.spec.js | 54 ------------------- 2 files changed, 103 deletions(-) delete mode 100644 cypress/integration/check_summary/enabled-attributes.spec.js delete mode 100644 cypress/integration/check_summary/enabled-clusters.spec.js diff --git a/cypress/integration/check_summary/enabled-attributes.spec.js b/cypress/integration/check_summary/enabled-attributes.spec.js deleted file mode 100644 index e888eb2c1e..0000000000 --- a/cypress/integration/check_summary/enabled-attributes.spec.js +++ /dev/null @@ -1,49 +0,0 @@ -/// - -Cypress.on('uncaught:exception', (err, runnable) => { - // returning false here prevents Cypress from - // failing the test - return false -}) - -describe('Testing enabled attributes amount', () => { - it('create a new endpoint and enable an attribute', () => { - cy.fixture('baseurl').then((data) => { - cy.visit(data.baseurl) - }) - cy.setZclProperties() - cy.fixture('data').then((data) => { - cy.addEndpoint(data.endpoint1, data.cluster1) - cy.gotoAttributePage('', data.cluster1) - }) - cy.wait(1000) - cy.get('[data-test="endpoint-enabled-attributes-amount"]').then(($div) => { - const num1 = parseFloat($div.text()) - cy.fixture('data').then((data) => { - cy.get( - `:nth-child(2) > .toggle-box > .q-toggle > .q-toggle__inner` - ).click() - }) - cy.contains('close').click() - }) - }) - it( - 'checks if number is updated', - { retries: { runMode: 2, openMode: 2 } }, - () => { - cy.get('#Settings').click() - cy.wait(300) - cy.get('[data-test="go-back-button"').click() - cy.wait(300) - cy.fixture('data').then((data) => { - cy.wait(700) - cy.get('[data-test="endpoint-enabled-attributes-amount"]').then( - ($div2) => { - const num2 = parseFloat($div2.text()) - expect(num2).to.eq(Number(data.availableAttributes1)) - } - ) - }) - } - ) -}) diff --git a/cypress/integration/check_summary/enabled-clusters.spec.js b/cypress/integration/check_summary/enabled-clusters.spec.js deleted file mode 100644 index a767e19bfb..0000000000 --- a/cypress/integration/check_summary/enabled-clusters.spec.js +++ /dev/null @@ -1,54 +0,0 @@ -/// - -Cypress.on('uncaught:exception', (err, runnable) => { - // returning false here prevents Cypress from - // failing the test - return false -}) - -describe('Testing enabled clusters amount', () => { - it( - 'create a new endpoint and get amount of enabled clusters', - { retries: { runMode: 2, openMode: 2 } }, - () => { - cy.fixture('baseurl').then((data) => { - cy.visit(data.baseurl) - }) - cy.setZclProperties() - cy.fixture('data').then((data) => { - cy.addEndpoint(data.endpoint1, data.cluster1) - }) - cy.get('[data-test="endpoint-enabled-clusters-amount"]').then(($div) => { - const num1 = parseFloat($div.text()) - - cy.get('div').contains('General').click({ force: true }) - cy.get('div') - .children() - .contains('Server') - .its('length') - .then((res) => { - if (res > 0) { - cy.get('div').children().contains('Not Enabled').first().click() - cy.get('.q-virtual-scroll__content > :nth-child(3)') - .contains('Server') - .click() - } - }) - }) - } - ) - it( - 'checks if number is updated', - { retries: { runMode: 2, openMode: 2 } }, - () => { - cy.fixture('data').then((data) => { - cy.get('[data-test="endpoint-enabled-clusters-amount"]').then( - ($div2) => { - const num2 = parseFloat($div2.text()) - expect(num2).to.eq(Number(data.availableClusters1)) - } - ) - }) - } - ) -}) From 48e01174d5b954635e7634376441490ba1024b2b Mon Sep 17 00:00:00 2001 From: Bharat Dandu Date: Wed, 7 Jun 2023 10:52:02 -0400 Subject: [PATCH 16/40] Making sure that the device type clusters are added when an endpoint is edited and a new zcl device type is added to the endpoint Github: ZAP#862 --- src-electron/db/query-config.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src-electron/db/query-config.js b/src-electron/db/query-config.js index 7527977fd9..835e31338a 100644 --- a/src-electron/db/query-config.js +++ b/src-electron/db/query-config.js @@ -688,10 +688,16 @@ async function updateEndpointType( ) let isDeviceTypeRefsUpdated = - existingDeviceTypes.length === updatedValue.length && - existingDeviceTypes.every((value, index) => value == updatedValue[index]) + existingDeviceTypes.length !== updatedValue.length || + existingDeviceTypes.every((value, index) => value != updatedValue[index]) + + // When updating the zcl device types, overwrite on top of existing configuration + // Note: Here the existing selections are not removed. For eg: the clusters which + // came from a removed zcl device type continue to exist. if (param === 'DEVICE_TYPE_REF' && isDeviceTypeRefsUpdated) { - await setEndpointDefaults(db, sessionId, endpointTypeId, updatedValue) + for (const dtRef of updatedValue) { + await setEndpointDefaults(db, sessionId, endpointTypeId, dtRef) + } } return newEndpointId } From 70a9b9a82557f9979111521a3abf9c764606cd27 Mon Sep 17 00:00:00 2001 From: Bharat Dandu Date: Thu, 8 Jun 2023 11:58:41 -0400 Subject: [PATCH 17/40] When loading the old zap files and editing the endpoint the selected devices do not show up in the device UI. Updating deviceIdentifier with this.zclDeviceTypes[deviceTypeRefs[i]].code fixed it Github: ZAP#862 --- src/components/ZclCreateModifyEndpoint.vue | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index 453910fdfd..056056a41c 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -157,19 +157,18 @@ export default { const deviceTypeRefs = this.endpointDeviceTypeRef[this.endpointType[this.endpointReference]] - const deviceIdentifiers = this.endpointDeviceId[this.endpointReference] const deviceTypes = [] if (Array.isArray(deviceTypeRefs)) { for (let i = 0; i < deviceTypeRefs.length; i++) { deviceTypes.push({ deviceTypeRef: deviceTypeRefs[i], - deviceIdentifier: deviceIdentifiers[i], + deviceIdentifier: this.zclDeviceTypes[deviceTypeRefs[i]].code, }) } } else { deviceTypes.push({ deviceTypeRef: deviceTypeRefs, - deviceIdentifier: deviceIdentifiers, + deviceIdentifier: this.zclDeviceTypes[deviceTypeRefs].code, }) } From abe2ad772408e2c0938c0c52b235507b0d08625e Mon Sep 17 00:00:00 2001 From: Gergely Kiss Date: Fri, 19 May 2023 14:13:26 +0200 Subject: [PATCH 18/40] Support multiple device type with primary input --- src/components/ZclCreateModifyEndpoint.vue | 74 ++++++++++++++++++---- src/components/ZclEndpointCard.vue | 14 ++++ 2 files changed, 74 insertions(+), 14 deletions(-) diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index 7d74c30f6f..e12f9f58c6 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -32,7 +32,7 @@ limitations under the License. min="0" /> - -
    + /> +
    0 ? newValue[0] : newValue + const { deviceTypeRef, deviceIdentifier } = value + + // Set device pair + if (this.devicePair == undefined) { + this.devicePair = {} + } + this.devicePair.deviceTypeRef = deviceTypeRef + this.devicePair.deviceIdentifier = deviceIdentifier + + // Set primary device if necessary + if (this.enablePrimaryDevice) { + if (this.primaryDeviceType === null) { + this.primaryDeviceType = value + } else { + if (Array.isArray(newValue)) { + if ( + !newValue.includes( + (device) => + device.deviceTypeRef === + this.primaryDeviceType.deviceTypeRef && + device.deviceIdentifier === + this.primaryDeviceType.deviceIdentifier + ) + ) { + this.primaryDeviceType = value + } + } + } + } + let profileId = this.shownEndpoint.profileIdentifier // On change of device type, reset the profileId to the current deviceType _unless_ the default profileId is custom if (this.shownEndpoint.profileIdentifier != null) { @@ -257,8 +305,6 @@ export default { profileId = this.asHex(this.zclDeviceTypes[deviceTypeRef].profileId, 4) } this.shownEndpoint.profileIdentifier = profileId - this.devicePair.deviceTypeRef = value.deviceTypeRef - this.devicePair.deviceIdentifier = value.deviceIdentifier }, saveOrCreateHandler() { let profile = this.$store.state.zap.isProfileIdShown diff --git a/src/components/ZclEndpointCard.vue b/src/components/ZclEndpointCard.vue index a1af2c4ee8..c357d7ca4a 100644 --- a/src/components/ZclEndpointCard.vue +++ b/src/components/ZclEndpointCard.vue @@ -92,6 +92,14 @@ limitations under the License. {{ getDeviceOptionLabel() }}
    + +
    + Primary Device +
    +
    + {{ getPrimaryDeviceOptionLabel() }} +
    +
    Network
    @@ -271,6 +279,9 @@ export default { ) } }, + getPrimaryDeviceOptionLabel() { + return '' // TODO + }, handleDeletionDialog() { if (this.getStorageParam() == 'true') { this.deleteEpt() @@ -354,6 +365,9 @@ export default { ] }, }, + primaryDeviceType() { + return '' // TODO + }, networkId: { get() { return this.$store.state.zap.endpointView.networkId From 1786f0b6991fa0f3936ad86c81addf2bcdb9e0c3 Mon Sep 17 00:00:00 2001 From: Gergely Kiss Date: Mon, 22 May 2023 19:39:29 +0200 Subject: [PATCH 19/40] Support multiple device type with array input --- src/components/ZclCreateModifyEndpoint.vue | 163 ++++++++++++--------- src/store/zap/actions.js | 60 ++++---- 2 files changed, 126 insertions(+), 97 deletions(-) diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index e12f9f58c6..7f2c87e0c9 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -51,9 +51,10 @@ limitations under the License. :multiple="enableMultipleDevice" :use-chips="enableMultipleDevice" :options="deviceTypeOptions" - v-model="devicePair" - @update:model-value="setDeviceTypeCallback" - :rules="[(val) => val != null || '* Required']" + v-model="deviceType" + :rules="[ + (val) => !(val == null || val?.length == 0) || '* Required', + ]" :option-label="getDeviceOptionLabel" @filter="filterDeviceTypes" data-test="select-endpoint-input" @@ -153,14 +154,21 @@ export default { this.shownEndpoint.deviceVersion = parseInt( this.endpointVersion[this.endpointReference] ) - this.devicePair = { + // TODO refactor this after API change + const firstDeviceType = { deviceTypeRef: this.endpointDeviceTypeRef[this.endpointType[this.endpointReference]], deviceIdentifier: this.endpointDeviceId[this.endpointReference], } + // Set device types only in edit mode + this.deviceTypeTmp = [firstDeviceType] // TODO make device pair to be array and set it here from the store + this.primaryDeviceTypeTmp = null // TODO set it here from the store } else { this.shownEndpoint.endpointIdentifier = this.getSmallestUnusedEndpointId() } + const enableMultiDeviceFeatures = true + this.enableMultipleDevice = enableMultiDeviceFeatures // TODO make it data driven from the store + this.enablePrimaryDevice = enableMultiDeviceFeatures // TODO make it data driven from the store }, data() { return { @@ -172,10 +180,10 @@ export default { deviceVersion: 1, }, saveOrCreateCloseFlag: false, - deviceType: null, - primaryDeviceType: null, - enableMultipleDevice: true, // TODO make it data driven - enablePrimaryDevice: true, // TODO make it data driven + deviceTypeTmp: [], // Temp store for the selected device types + primaryDeviceTypeTmp: null, // Temp store for the selected primary device type + enableMultipleDevice: false, // TODO make it data driven + enablePrimaryDevice: false, // TODO make it data driven } }, computed: { @@ -250,61 +258,84 @@ export default { ] }, }, - }, - methods: { - // This function will close the endpoint modal - toggleCreateEndpointModal() { - this.$store.commit('zap/toggleEndpointModal', false) - }, - setProfileId(value) { - this.shownEndpoint.profileIdentifier = value - }, - setDeviceTypeCallback(newValue) { - console.log(newValue) - const value = - Array.isArray(newValue) && newValue.length > 0 ? newValue[0] : newValue - const { deviceTypeRef, deviceIdentifier } = value + deviceType: { + get() { + // New temporary variable + return this.enableMultipleDevice + ? this.deviceTypeTmp + : this.deviceTypeTmp[0] + }, + set(newValue) { + const value = !Array.isArray(newValue) ? [newValue] : newValue - // Set device pair - if (this.devicePair == undefined) { - this.devicePair = {} - } - this.devicePair.deviceTypeRef = deviceTypeRef - this.devicePair.deviceIdentifier = deviceIdentifier + // New temporary variable + this.deviceTypeTmp = value - // Set primary device if necessary - if (this.enablePrimaryDevice) { - if (this.primaryDeviceType === null) { - this.primaryDeviceType = value - } else { - if (Array.isArray(newValue)) { + // Existing logic + this.setDeviceTypeCallback(value) + + // Set primary device if necessary + const newPrimaryDeviceType = + Array.isArray(value) && value.length > 0 ? value[0] : null + if (this.enablePrimaryDevice) { + if (this.primaryDeviceType === null) { + this.primaryDeviceType = newPrimaryDeviceType + } else { if ( - !newValue.includes( - (device) => - device.deviceTypeRef === + !value.includes( + (deviceType) => + deviceType.deviceTypeRef === this.primaryDeviceType.deviceTypeRef && - device.deviceIdentifier === + deviceType.deviceIdentifier === this.primaryDeviceType.deviceIdentifier ) ) { - this.primaryDeviceType = value + this.primaryDeviceType = newPrimaryDeviceType } } } - } + }, + }, + primaryDeviceType: { + get() { + return this.primaryDeviceTypeTmp + }, + set(value) { + this.primaryDeviceTypeTmp = value - let profileId = this.shownEndpoint.profileIdentifier - // On change of device type, reset the profileId to the current deviceType _unless_ the default profileId is custom - if (this.shownEndpoint.profileIdentifier != null) { - profileId = - this.zclDeviceTypes[deviceTypeRef].profileId == - DbEnum.customDevice.profileId - ? this.asHex(profileId, 4) - : this.asHex(this.zclDeviceTypes[deviceTypeRef].profileId, 4) - } else { - profileId = this.asHex(this.zclDeviceTypes[deviceTypeRef].profileId, 4) + // TODO write back to the store and backend here + }, + }, + }, + methods: { + // This function will close the endpoint modal + toggleCreateEndpointModal() { + this.$store.commit('zap/toggleEndpointModal', false) + }, + setProfileId(value) { + this.shownEndpoint.profileIdentifier = value + }, + setDeviceTypeCallback(value) { + const firstValue = Array.isArray(value) ? value[0] : value + // Check deviceTypreRef truthy - at least 1 item selected + if (firstValue) { + const { deviceTypeRef } = firstValue + let profileId = this.shownEndpoint.profileIdentifier + // On change of device type, reset the profileId to the current deviceType _unless_ the default profileId is custom + if (this.shownEndpoint.profileIdentifier != null) { + profileId = + this.zclDeviceTypes[deviceTypeRef].profileId == + DbEnum.customDevice.profileId + ? this.asHex(profileId, 4) + : this.asHex(this.zclDeviceTypes[deviceTypeRef].profileId, 4) + } else { + profileId = this.asHex( + this.zclDeviceTypes[deviceTypeRef].profileId, + 4 + ) + } + this.shownEndpoint.profileIdentifier = profileId } - this.shownEndpoint.profileIdentifier = profileId }, saveOrCreateHandler() { let profile = this.$store.state.zap.isProfileIdShown @@ -348,7 +379,9 @@ export default { this.$store .dispatch(`zap/addEndpointType`, { name: 'Anonymous Endpoint Type', - deviceTypeRef: this.devicePair.deviceTypeRef, + deviceTypeRef: this.deviceTypeTmp?.map?.( + (dt) => dt.deviceTypeRef + )?.[0], }) .then((response) => { this.$store @@ -358,7 +391,9 @@ export default { profileId: parseInt(this.shownEndpoint.profileIdentifier), endpointType: response.id, endpointVersion: this.shownEndpoint.deviceVersion, - deviceIdentifier: this.devicePair.deviceIdentifier, + deviceIdentifier: this.deviceTypeTmp?.map?.( + (dt) => dt.deviceIdentifier + )?.[0], }) .then((res) => { if (this.shareClusterStatesAcrossEndpoints()) { @@ -401,7 +436,7 @@ export default { this.$store.dispatch('zap/updateEndpointType', { endpointTypeId: endpointTypeReference, updatedKey: RestApi.updateKey.deviceTypeRef, - updatedValue: this.devicePair.deviceTypeRef, + updatedValue: this.deviceTypeTmp?.map?.((dt) => dt.deviceTypeRef)?.[0], }) this.$store.dispatch('zap/updateEndpoint', { @@ -425,7 +460,9 @@ export default { }, { updatedKey: RestApi.updateKey.deviceId, - value: parseInt(this.devicePair.deviceIdentifier), + value: parseInt( + this.deviceTypeTmp?.map?.((dt) => dt.deviceIdentifier)?.[0] + ), }, ], }) @@ -469,22 +506,6 @@ export default { ) } }, - createValue(val, done) { - try { - done( - { - deviceTypeRef: this.devicePair.deviceTypeRef - ? this.devicePair.deviceTypeRef - : this.customDeviceIdReference, - deviceIdentifier: parseInt(val), - }, - 'add-unique' - ) - } catch (err) { - //Catch bad inputs. - console.log(err) - } - }, filterDeviceTypes(val, update) { if (val === '') { update(() => { diff --git a/src/store/zap/actions.js b/src/store/zap/actions.js index 1133401d36..0920c48342 100644 --- a/src/store/zap/actions.js +++ b/src/store/zap/actions.js @@ -227,6 +227,7 @@ export function updateSelectedEndpoint(context, endpoint) { } export function updateEndpointType(context, endpointType) { + // TODO this uri should handle deviceTypeRef as array axiosRequests .$serverPatch(restApi.uri.endpointType, endpointType) .then((res) => { @@ -234,7 +235,7 @@ export function updateEndpointType(context, endpointType) { if (arg.updatedKey === 'deviceTypeRef') { setDeviceTypeReference(context, { endpointId: arg.endpointTypeId, - deviceTypeRef: arg.updatedValue, + deviceTypeRef: arg.updatedValue, // TODO this should be an array }) } }) @@ -296,6 +297,7 @@ export function setDeviceTypeReference(context, endpointIdDeviceTypeRefPair) { } export function updateEndpoint(context, endpoint) { + // TODO this uri should handle deviceIdentifier as array axiosRequests.$serverPatch(restApi.uri.endpoint, endpoint).then((res) => { let arg = res.data context.commit('updateEndpoint', { @@ -308,36 +310,42 @@ export function updateEndpoint(context, endpoint) { } export function addEndpoint(context, newEndpointContext) { - return axiosRequests - .$serverPost(restApi.uri.endpoint, newEndpointContext) - .then((res) => { - let arg = res.data - context.commit('addEndpoint', { - id: arg.id, - endpointId: arg.endpointId, - endpointTypeRef: arg.endpointType, - networkId: arg.networkId, - profileId: arg.profileId, - deviceIdentifier: arg.deviceId, - endpointVersion: arg.endpointVersion, - endpointIdValidationIssues: arg.validationIssues.endpointId, - networkIdValidationIssues: arg.validationIssues.networkId, + return ( + axiosRequests + // TODO this uri should handle deviceIdentifier as array + .$serverPost(restApi.uri.endpoint, newEndpointContext) + .then((res) => { + let arg = res.data + context.commit('addEndpoint', { + id: arg.id, + endpointId: arg.endpointId, + endpointTypeRef: arg.endpointType, + networkId: arg.networkId, + profileId: arg.profileId, + deviceIdentifier: arg.deviceId, // TODO this should be array too + endpointVersion: arg.endpointVersion, + endpointIdValidationIssues: arg.validationIssues.endpointId, + networkIdValidationIssues: arg.validationIssues.networkId, + }) + return arg }) - return arg - }) + ) } export function addEndpointType(context, endpointTypeData) { - return axiosRequests - .$serverPost(restApi.uri.endpointType, endpointTypeData) - .then((res) => { - context.commit('addEndpointType', { - id: res.data.id, - name: res.data.name, - deviceTypeRef: res.data.deviceTypeRef, + return ( + axiosRequests + // TODO this uri should handle deviceTypeRef as array + .$serverPost(restApi.uri.endpointType, endpointTypeData) + .then((res) => { + context.commit('addEndpointType', { + id: res.data.id, + name: res.data.name, + deviceTypeRef: res.data.deviceTypeRef, // TODO array should be returned + }) + return res.data }) - return res.data - }) + ) } export function duplicateEndpointType(context, { endpointTypeId }) { From 456a56ef307b6df2867bd69f02c5bbf56bd230cf Mon Sep 17 00:00:00 2001 From: Bharat Dandu Date: Wed, 24 May 2023 16:44:13 -0400 Subject: [PATCH 20/40] Enabling multiple zcl device types per endpoint draft commit. Edit this comment later Github: ZAP#862 --- src-electron/db/query-config.js | 100 ++++++++++++++------- src-electron/db/query-endpoint-type.js | 39 ++++++-- src-electron/db/query-endpoint.js | 41 ++++----- src-electron/db/query-impexp.js | 8 +- src-electron/db/zap-schema.sql | 21 ++++- src/components/ZclCreateModifyEndpoint.vue | 43 +++++---- src/components/ZclEndpointCard.vue | 64 +++++++++++-- src/store/zap/actions.js | 24 +++-- 8 files changed, 236 insertions(+), 104 deletions(-) diff --git a/src-electron/db/query-config.js b/src-electron/db/query-config.js index 5052b4f0d4..20c882e959 100644 --- a/src-electron/db/query-config.js +++ b/src-electron/db/query-config.js @@ -70,19 +70,18 @@ DO UPDATE SET ENABLED = ?`, * @param {*} db * @param {*} endpointTypeId */ - async function selectEndpointClusters(db, endpointTypeId) { - let rows = await dbApi - .dbAll( - db, - ` +async function selectEndpointClusters(db, endpointTypeId) { + let rows = await dbApi.dbAll( + db, + ` SELECT * FROM ENDPOINT_TYPE_CLUSTER WHERE ENDPOINT_TYPE_REF = ? `, - [endpointTypeId] - ) - - return rows.map(dbMapping.map.endpointTypeCluster) + [endpointTypeId] + ) + + return rows.map(dbMapping.map.endpointTypeCluster) } /** @@ -523,42 +522,68 @@ async function insertEndpointType( db, sessionId, name, - deviceTypeRef, + deviceTypeRefs, doTransaction = true ) { + // Insert endpoint type let newEndpointTypeId = await dbApi.dbInsert( db, - 'INSERT OR REPLACE INTO ENDPOINT_TYPE ( SESSION_REF, NAME, DEVICE_TYPE_REF ) VALUES ( ?, ?, ?)', - [sessionId, name, deviceTypeRef] + 'INSERT OR REPLACE INTO ENDPOINT_TYPE ( SESSION_REF, NAME ) VALUES ( ?, ?)', + [sessionId, name] ) - await setEndpointDefaults( + + // Creating endpoint type and device type ref combinations along with order of insertion + let newEndpointTypeIdDeviceCombination = [] + for (let i = 0; i < deviceTypeRefs.length; i++) { + let endpointTypeDevice = [newEndpointTypeId, deviceTypeRefs[i], i] + newEndpointTypeIdDeviceCombination.push(endpointTypeDevice) + } + + // Insert into endpoint_type_device + await dbApi.dbMultiInsert( db, - sessionId, - newEndpointTypeId, - deviceTypeRef, - doTransaction + 'INSERT INTO ENDPOINT_TYPE_DEVICE (ENDPOINT_TYPE_REF, DEVICE_TYPE_REF, DEVICE_TYPE_ORDER) VALUES (?, ?, ?)', + newEndpointTypeIdDeviceCombination ) + + // Resolve endpointDefaults based on device type order. Reversing the order + // such that the device type defaults are maintained based on the order from + // deviceTypeRefs + let deviceTypeRefsReversed = deviceTypeRefs.reverse() + for (const dtRef of deviceTypeRefsReversed) { + await setEndpointDefaults( + db, + sessionId, + newEndpointTypeId, + dtRef, + doTransaction + ) + } return newEndpointTypeId } /** -* Promises to duplicate an endpoint type. -* -* @export -* @param {*} db -* @param {*} endpointTypeId -* @returns Promise to duplicate endpoint type. -*/ -async function duplicateEndpointType( - db, - endpointTypeId - ) { + * Promises to duplicate an endpoint type. + * + * @export + * @param {*} db + * @param {*} endpointTypeId + * @returns Promise to duplicate endpoint type. + */ +async function duplicateEndpointType(db, endpointTypeId) { let newEndpointTypeId = await dbApi.dbInsert( db, `INSERT INTO ENDPOINT_TYPE (SESSION_REF, NAME, DEVICE_TYPE_REF) - select SESSION_REF, NAME, DEVICE_TYPE_REF - from ENDPOINT_TYPE - where ENDPOINT_TYPE_ID = ?`, + SELECT + ENDPOINT_TYPE.SESSION_REF, ENDPOINT_TYPE.NAME, ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF + FROM + ENDPOINT_TYPE + INNER JOIN + ENDPOINT_TYPE_DEVICE + ON + ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF + WHERE + ENDPOINT_TYPE_ID = ?`, [endpointTypeId] ) @@ -583,12 +608,21 @@ async function updateEndpointType( let param = convertRestKeyToDbColumn(updateKey) let wasPresent = await dbApi.dbGet( db, - 'SELECT DEVICE_TYPE_REF FROM ENDPOINT_TYPE WHERE ENDPOINT_TYPE_ID = ? AND SESSION_REF = ?', + ` + SELECT + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF + FROM + ENDPOINT_TYPE + INNER JOIN + ENDPOINT_TYPE_DEVICE + ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF + WHERE + ENDPOINT_TYPE_ID = ? AND SESSION_REF = ?`, [endpointTypeId, sessionId] ) let newEndpointId = await dbApi.dbUpdate( - db, + db, // Check for update with schema change `UPDATE ENDPOINT_TYPE SET ${param} = ? WHERE ENDPOINT_TYPE_ID = ? AND SESSION_REF = ?`, [updatedValue, endpointTypeId, sessionId] ) diff --git a/src-electron/db/query-endpoint-type.js b/src-electron/db/query-endpoint-type.js index e28ea19a04..056b42a049 100644 --- a/src-electron/db/query-endpoint-type.js +++ b/src-electron/db/query-endpoint-type.js @@ -51,12 +51,16 @@ async function selectAllEndpointTypes(db, sessionId) { db, ` SELECT - ENDPOINT_TYPE_ID, - NAME, - DEVICE_TYPE_REF, - SESSION_REF + ENDPOINT_TYPE.ENDPOINT_TYPE_ID, + ENDPOINT_TYPE.NAME, + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF, + ENDPOINT_TYPE.SESSION_REF FROM ENDPOINT_TYPE +INNER JOIN + ENDPOINT_TYPE_DEVICE +ON + ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF WHERE SESSION_REF = ? ORDER BY NAME`, [sessionId] ) @@ -85,10 +89,14 @@ SELECT ENDPOINT_TYPE.ENDPOINT_TYPE_ID FROM ENDPOINT_TYPE +INNER JOIN + ENDPOINT_TYPE_DEVICE +ON + ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF LEFT JOIN DEVICE_TYPE ON - ENDPOINT_TYPE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID WHERE ENDPOINT_TYPE.SESSION_REF = ? ORDER BY ENDPOINT_TYPE.NAME`, @@ -125,10 +133,14 @@ INNER JOIN ENDPOINT ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT.ENDPOINT_TYPE_REF +INNER JOIN + ENDPOINT_TYPE_DEVICE +ON + ENDPOINT_TYPE.ENDPOINT_TYPE = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF LEFT JOIN DEVICE_TYPE ON - ENDPOINT_TYPE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID WHERE ENDPOINT_TYPE.SESSION_REF = ? ORDER BY ENDPOINT_TYPE.NAME`, @@ -148,7 +160,20 @@ async function selectEndpointType(db, id) { return dbApi .dbGet( db, - `SELECT ENDPOINT_TYPE_ID, SESSION_REF, NAME, DEVICE_TYPE_REF FROM ENDPOINT_TYPE WHERE ENDPOINT_TYPE_ID = ?`, + ` + SELECT + ENDPOINT_TYPE.ENDPOINT_TYPE_ID, + ENDPOINT_TYPE.SESSION_REF, + ENDPOINT_TYPE.NAME, + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF + FROM + ENDPOINT_TYPE + INNER JOIN + ENDPOINT_TYPE_DEVICE + ON + ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF + WHERE + ENDPOINT_TYPE_ID = ?`, [id] ) .then(dbMapping.map.endpointType) diff --git a/src-electron/db/query-endpoint.js b/src-electron/db/query-endpoint.js index 6d958a9d14..3b95e00047 100644 --- a/src-electron/db/query-endpoint.js +++ b/src-electron/db/query-endpoint.js @@ -274,9 +274,10 @@ ORDER BY C.CODE * @returns promise that resolves into endpoint cluster events */ async function selectEndpointClusterEvents(db, clusterId, endpointTypeId) { - return dbApi.dbAll( - db, - ` + return dbApi + .dbAll( + db, + ` SELECT E.EVENT_ID, E.CLUSTER_REF, @@ -299,9 +300,9 @@ WHERE AND ETE.ENDPOINT_TYPE_REF = ? ORDER BY E.MANUFACTURER_CODE, E.CODE `, - [clusterId, endpointTypeId] - ) - .then((rows) => rows.map(dbMapping.map.event)) + [clusterId, endpointTypeId] + ) + .then((rows) => rows.map(dbMapping.map.event)) } /** @@ -337,6 +338,9 @@ async function insertEndpoint( endpointVersion, deviceIdentifier ) { + let primaryDeviceIdentifierForEndpoint = Array.isArray(deviceIdentifier) + ? deviceIdentifier[0] + : deviceIdentifier return dbApi.dbInsert( db, ` @@ -356,31 +360,28 @@ INTO ENDPOINT ( endpointTypeRef, networkIdentifier, endpointVersion, - deviceIdentifier, + primaryDeviceIdentifierForEndpoint, profileIdentifier, ] ) } /** -* @export -* @param {*} db -* @param {*} id -* @param {*} endpointIdentifier -* @returns Promise to duplicate an endpoint. -*/ -async function duplicateEndpoint( db, id, endpointIdentifier, endpointTypeId ) { - return dbApi.dbInsert( db, + * @export + * @param {*} db + * @param {*} id + * @param {*} endpointIdentifier + * @returns Promise to duplicate an endpoint. + */ +async function duplicateEndpoint(db, id, endpointIdentifier, endpointTypeId) { + return dbApi.dbInsert( + db, ` insert into ENDPOINT (SESSION_REF,ENDPOINT_IDENTIFIER,ENDPOINT_TYPE_REF,NETWORK_IDENTIFIER,DEVICE_VERSION,DEVICE_IDENTIFIER,PROFILE) select SESSION_REF, ? , ? ,NETWORK_IDENTIFIER,DEVICE_VERSION,DEVICE_IDENTIFIER,PROFILE from ENDPOINT where ENDPOINT_ID = ?`, - [ - endpointIdentifier, - endpointTypeId, - id - ] + [endpointIdentifier, endpointTypeId, id] ) } diff --git a/src-electron/db/query-impexp.js b/src-electron/db/query-impexp.js index 3ded761c29..c108a4178a 100644 --- a/src-electron/db/query-impexp.js +++ b/src-electron/db/query-impexp.js @@ -141,12 +141,16 @@ async function exportEndpointTypes(db, sessionId) { SELECT DISTINCT ENDPOINT_TYPE.ENDPOINT_TYPE_ID, ENDPOINT_TYPE.NAME, - ENDPOINT_TYPE.DEVICE_TYPE_REF, + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF, DEVICE_TYPE.CODE AS DEVICE_TYPE_CODE, DEVICE_TYPE.PROFILE_ID as DEVICE_TYPE_PROFILE_ID, DEVICE_TYPE.NAME AS DEVICE_TYPE_NAME FROM ENDPOINT_TYPE +INNER JOIN + ENDPOINT_TYPE_DEVICE +ON + ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF LEFT JOIN ENDPOINT ON @@ -154,7 +158,7 @@ ON LEFT JOIN DEVICE_TYPE ON - ENDPOINT_TYPE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID WHERE ENDPOINT_TYPE.SESSION_REF = ? ORDER BY diff --git a/src-electron/db/zap-schema.sql b/src-electron/db/zap-schema.sql index 78d123a12e..ed47185de0 100644 --- a/src-electron/db/zap-schema.sql +++ b/src-electron/db/zap-schema.sql @@ -715,10 +715,25 @@ CREATE TABLE IF NOT EXISTS "ENDPOINT_TYPE" ( "ENDPOINT_TYPE_ID" integer primary key autoincrement, "SESSION_REF" integer, "NAME" text, - "DEVICE_TYPE_REF" integer, - foreign key (SESSION_REF) references SESSION(SESSION_ID) on delete cascade, - foreign key(DEVICE_TYPE_REF) references DEVICE_TYPE(DEVICE_TYPE_ID) + foreign key (SESSION_REF) references SESSION(SESSION_ID) on delete cascade +); + +/* + ENDPOINT_TYPE_DEVICE: many-to-many relationship between endpoint type and + device type. + */ +DROP TABLE IF EXISTS "ENDPOINT_TYPE_DEVICE"; +CREATE TABLE IF NOT EXISTS "ENDPOINT_TYPE_DEVICE" ( + "ENDPOINT_TYPE_DEVICE_ID" integer primary key autoincrement, + "DEVICE_TYPE_REF" INTEGER, + "ENDPOINT_TYPE_REF" INTEGER, + "DEVICE_TYPE_ORDER" INTEGER, + foreign key(DEVICE_TYPE_REF) references DEVICE_TYPE(DEVICE_TYPE_ID) on delete cascade, + foreign key (ENDPOINT_TYPE_REF) references ENDPOINT_TYPE(ENDPOINT_TYPE_ID) on delete + set NULL, + UNIQUE("ENDPOINT_TYPE_REF", "DEVICE_TYPE_REF") ); + /* ENDPOINT table contains the toplevel configured endpoints. */ diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index 7f2c87e0c9..c431a593a8 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -379,9 +379,7 @@ export default { this.$store .dispatch(`zap/addEndpointType`, { name: 'Anonymous Endpoint Type', - deviceTypeRef: this.deviceTypeTmp?.map?.( - (dt) => dt.deviceTypeRef - )?.[0], + deviceTypeRef: this.deviceTypeTmp?.map?.((dt) => dt.deviceTypeRef), }) .then((response) => { this.$store @@ -393,7 +391,7 @@ export default { endpointVersion: this.shownEndpoint.deviceVersion, deviceIdentifier: this.deviceTypeTmp?.map?.( (dt) => dt.deviceIdentifier - )?.[0], + ), }) .then((res) => { if (this.shareClusterStatesAcrossEndpoints()) { @@ -436,7 +434,7 @@ export default { this.$store.dispatch('zap/updateEndpointType', { endpointTypeId: endpointTypeReference, updatedKey: RestApi.updateKey.deviceTypeRef, - updatedValue: this.deviceTypeTmp?.map?.((dt) => dt.deviceTypeRef)?.[0], + updatedValue: this.deviceTypeTmp?.map?.((dt) => dt.deviceTypeRef), }) this.$store.dispatch('zap/updateEndpoint', { @@ -461,7 +459,7 @@ export default { { updatedKey: RestApi.updateKey.deviceId, value: parseInt( - this.deviceTypeTmp?.map?.((dt) => dt.deviceIdentifier)?.[0] + this.deviceTypeTmp?.map?.((dt) => dt.deviceIdentifier) ), }, ], @@ -493,17 +491,30 @@ export default { }, getDeviceOptionLabel(item) { if (item == null || item.deviceTypeRef == null) return '' - if ( - item.deviceIdentifier != this.zclDeviceTypes[item.deviceTypeRef].code - ) { - return this.asHex(item.deviceIdentifier, 4) - } else { - return ( - this.zclDeviceTypes[item.deviceTypeRef].description + - ' (' + - this.asHex(this.zclDeviceTypes[item.deviceTypeRef].code, 4) + - ')' + if (Array.isArray(item.deviceTypeRef)) { + let deviceOptionLabels = [] + item.deviceTypeRef.forEach((d) => + deviceOptionLabels.push( + this.zclDeviceTypes[d].description + + ' (' + + this.asHex(this.zclDeviceTypes[d].code, 4) + + ')' + ) ) + return deviceOptionLabels + } else { + if ( + item.deviceIdentifier != this.zclDeviceTypes[item.deviceTypeRef].code + ) { + return this.asHex(item.deviceIdentifier, 4) + } else { + return ( + this.zclDeviceTypes[item.deviceTypeRef].description + + ' (' + + this.asHex(this.zclDeviceTypes[item.deviceTypeRef].code, 4) + + ')' + ) + } } }, filterDeviceTypes(val, update) { diff --git a/src/components/ZclEndpointCard.vue b/src/components/ZclEndpointCard.vue index c357d7ca4a..d14eba5ffd 100644 --- a/src/components/ZclEndpointCard.vue +++ b/src/components/ZclEndpointCard.vue @@ -87,9 +87,18 @@ limitations under the License. -
    Device
    - {{ getDeviceOptionLabel() }} + Device +
    +
    +
  • + {{ `${dev.description} (${asHex(dev.code, 4)})` }} +
  • +
    +
    + {{ + `${deviceType[0].description} (${asHex(deviceType[0].code, 4)})` + }}
    @@ -268,8 +277,14 @@ export default { }, getDeviceOptionLabel() { if (this.deviceType == null) return '' - if (this.deviceId[this.endpointReference] != this.deviceType.code) { - return this.asHex(this.deviceId[this.endpointReference], 4) + if (Array.isArray(this.deviceType)) { + let deviceOptionLabels = [] + this.deviceType.forEach((d, index) => + deviceOptionLabels.push( + d.description + '(' + this.asHex(d.code, 4) + ')' + ) + ) + return deviceOptionLabels } else { return ( this.deviceType.description + @@ -280,7 +295,22 @@ export default { } }, getPrimaryDeviceOptionLabel() { - return '' // TODO + if (this.deviceType == null) return '' + if (Array.isArray(this.deviceType)) { + return ( + this.deviceType[0].description + + ' (' + + this.asHex(this.deviceType[0].code, 4) + + ')' + ) + } else { + return ( + this.deviceType.description + + ' (' + + this.asHex(this.deviceType.code, 4) + + ')' + ) + } }, handleDeletionDialog() { if (this.getStorageParam() == 'true') { @@ -360,13 +390,29 @@ export default { }, deviceType: { get() { - return this.zclDeviceTypes[ + let refs = this.endpointDeviceTypeRef[this.endpointType[this.endpointReference]] - ] + let deviceTypes = [] + if (refs.length > 0) { + refs.forEach((ref) => deviceTypes.push(this.zclDeviceTypes[ref])) + return deviceTypes + } else { + return this.zclDeviceTypes[ + this.endpointDeviceTypeRef[ + this.endpointType[this.endpointReference] + ] + ] + } }, }, - primaryDeviceType() { - return '' // TODO + isDeviceTypeArray: { + get() { + return ( + Array.isArray(this.deviceType) && + this.deviceType && + this.deviceType.length > 1 + ) + }, }, networkId: { get() { diff --git a/src/store/zap/actions.js b/src/store/zap/actions.js index 0920c48342..dc05e654aa 100644 --- a/src/store/zap/actions.js +++ b/src/store/zap/actions.js @@ -227,7 +227,6 @@ export function updateSelectedEndpoint(context, endpoint) { } export function updateEndpointType(context, endpointType) { - // TODO this uri should handle deviceTypeRef as array axiosRequests .$serverPatch(restApi.uri.endpointType, endpointType) .then((res) => { @@ -235,7 +234,7 @@ export function updateEndpointType(context, endpointType) { if (arg.updatedKey === 'deviceTypeRef') { setDeviceTypeReference(context, { endpointId: arg.endpointTypeId, - deviceTypeRef: arg.updatedValue, // TODO this should be an array + deviceTypeRef: arg.updatedValue, }) } }) @@ -333,19 +332,16 @@ export function addEndpoint(context, newEndpointContext) { } export function addEndpointType(context, endpointTypeData) { - return ( - axiosRequests - // TODO this uri should handle deviceTypeRef as array - .$serverPost(restApi.uri.endpointType, endpointTypeData) - .then((res) => { - context.commit('addEndpointType', { - id: res.data.id, - name: res.data.name, - deviceTypeRef: res.data.deviceTypeRef, // TODO array should be returned - }) - return res.data + return axiosRequests + .$serverPost(restApi.uri.endpointType, endpointTypeData) + .then((res) => { + context.commit('addEndpointType', { + id: res.data.id, + name: res.data.name, + deviceTypeRef: res.data.deviceTypeRef, }) - ) + return res.data + }) } export function duplicateEndpointType(context, { endpointTypeId }) { From 64e8936307d80fc27fce403432e7650f5b113ee0 Mon Sep 17 00:00:00 2001 From: Gergely Kiss Date: Thu, 25 May 2023 20:19:13 +0200 Subject: [PATCH 21/40] Unify array usage for DeviceType and DeviceIndentifier --- src/components/ZclCreateModifyEndpoint.vue | 106 ++++++++++++++------- src/components/ZclEndpointCard.vue | 36 +++---- 2 files changed, 89 insertions(+), 53 deletions(-) diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index c431a593a8..bfef7b17f8 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -154,15 +154,28 @@ export default { this.shownEndpoint.deviceVersion = parseInt( this.endpointVersion[this.endpointReference] ) - // TODO refactor this after API change - const firstDeviceType = { - deviceTypeRef: - this.endpointDeviceTypeRef[this.endpointType[this.endpointReference]], - deviceIdentifier: this.endpointDeviceId[this.endpointReference], + + const deviceTypeRefs = + this.endpointDeviceTypeRef[this.endpointType[this.endpointReference]] + const deviceIdentifiers = this.endpointDeviceId[this.endpointReference] + const deviceTypes = [] + if (Array.isArray(deviceTypeRefs)) { + for (let i = 0; i < deviceTypeRefs.length; i++) { + deviceTypes.push({ + deviceTypeRef: deviceTypeRefs[i], + deviceIdentifier: deviceIdentifiers[i], + }) + } + } else { + deviceTypes.push({ + deviceTypeRef: deviceTypeRefs, + deviceIdentifier: deviceIdentifiers, + }) } + // Set device types only in edit mode - this.deviceTypeTmp = [firstDeviceType] // TODO make device pair to be array and set it here from the store - this.primaryDeviceTypeTmp = null // TODO set it here from the store + this.deviceTypeTmp = deviceTypes + this.primaryDeviceTypeTmp = deviceTypes[0] ?? null // TODO set it here from the store } else { this.shownEndpoint.endpointIdentifier = this.getSmallestUnusedEndpointId() } @@ -376,12 +389,20 @@ export default { ) }, newEpt() { + const deviceTypeRef = [] + this.deviceTypeTmp.forEach((dt) => { + deviceTypeRef.push(dt.deviceTypeRef) + }) this.$store .dispatch(`zap/addEndpointType`, { name: 'Anonymous Endpoint Type', - deviceTypeRef: this.deviceTypeTmp?.map?.((dt) => dt.deviceTypeRef), + deviceTypeRef, }) .then((response) => { + const deviceIdentifier = [] + this.deviceTypeTmp.forEach((dt) => + deviceIdentifier.push(dt.deviceIdentifier) + ) this.$store .dispatch(`zap/addEndpoint`, { endpointId: parseInt(this.shownEndpoint.endpointIdentifier), @@ -389,9 +410,7 @@ export default { profileId: parseInt(this.shownEndpoint.profileIdentifier), endpointType: response.id, endpointVersion: this.shownEndpoint.deviceVersion, - deviceIdentifier: this.deviceTypeTmp?.map?.( - (dt) => dt.deviceIdentifier - ), + deviceIdentifier, }) .then((res) => { if (this.shareClusterStatesAcrossEndpoints()) { @@ -431,10 +450,18 @@ export default { editEpt(shownEndpoint, endpointReference) { let endpointTypeReference = this.endpointType[this.endpointReference] + const deviceTypeRef = [] + const deviceIdentifier = [] + + this.deviceTypeTmp.forEach((dt) => { + deviceTypeRef.push(dt.deviceTypeRef) + deviceIdentifier.push(parseInt(dt.deviceIdentifier)) + }) + this.$store.dispatch('zap/updateEndpointType', { endpointTypeId: endpointTypeReference, updatedKey: RestApi.updateKey.deviceTypeRef, - updatedValue: this.deviceTypeTmp?.map?.((dt) => dt.deviceTypeRef), + updatedValue: deviceTypeRef, }) this.$store.dispatch('zap/updateEndpoint', { @@ -458,9 +485,7 @@ export default { }, { updatedKey: RestApi.updateKey.deviceId, - value: parseInt( - this.deviceTypeTmp?.map?.((dt) => dt.deviceIdentifier) - ), + value: deviceIdentifier, }, ], }) @@ -491,31 +516,38 @@ export default { }, getDeviceOptionLabel(item) { if (item == null || item.deviceTypeRef == null) return '' - if (Array.isArray(item.deviceTypeRef)) { - let deviceOptionLabels = [] - item.deviceTypeRef.forEach((d) => - deviceOptionLabels.push( - this.zclDeviceTypes[d].description + - ' (' + - this.asHex(this.zclDeviceTypes[d].code, 4) + - ')' - ) + // if (Array.isArray(item.deviceTypeRef)) { + // let deviceOptionLabels = [] + // item.deviceTypeRef.forEach((d) => + // deviceOptionLabels.push( + // this.zclDeviceTypes[d].description + + // ' (' + + // this.asHex(this.zclDeviceTypes[d].code, 4) + + // ')' + // ) + // ) + // return deviceOptionLabels + // } else { + if ( + item.deviceIdentifier != this.zclDeviceTypes[item.deviceTypeRef].code + ) { + console.log( + item.deviceIdentifier, + '-', + item.deviceTypeRef, + '-', + this.zclDeviceTypes[item.deviceTypeRef] ) - return deviceOptionLabels + return this.asHex(item.deviceIdentifier, 4) } else { - if ( - item.deviceIdentifier != this.zclDeviceTypes[item.deviceTypeRef].code - ) { - return this.asHex(item.deviceIdentifier, 4) - } else { - return ( - this.zclDeviceTypes[item.deviceTypeRef].description + - ' (' + - this.asHex(this.zclDeviceTypes[item.deviceTypeRef].code, 4) + - ')' - ) - } + return ( + this.zclDeviceTypes[item.deviceTypeRef].description + + ' (' + + this.asHex(this.zclDeviceTypes[item.deviceTypeRef].code, 4) + + ')' + ) } + // } }, filterDeviceTypes(val, update) { if (val === '') { diff --git a/src/components/ZclEndpointCard.vue b/src/components/ZclEndpointCard.vue index d14eba5ffd..4adbf2a10d 100644 --- a/src/components/ZclEndpointCard.vue +++ b/src/components/ZclEndpointCard.vue @@ -87,18 +87,24 @@ limitations under the License. -
    +
    Device -
    -
  • {{ `${dev.description} (${asHex(dev.code, 4)})` }}
  • -
    - {{ - `${deviceType[0].description} (${asHex(deviceType[0].code, 4)})` - }} +
    +
    + Device +
    +
    + {{ + `${deviceType[0].description} (${asHex( + deviceType[0].code, + 4 + )})` + }} +
    @@ -397,21 +403,19 @@ export default { refs.forEach((ref) => deviceTypes.push(this.zclDeviceTypes[ref])) return deviceTypes } else { - return this.zclDeviceTypes[ - this.endpointDeviceTypeRef[ - this.endpointType[this.endpointReference] - ] + return [ + this.zclDeviceTypes[ + this.endpointDeviceTypeRef[ + this.endpointType[this.endpointReference] + ] + ], ] } }, }, isDeviceTypeArray: { get() { - return ( - Array.isArray(this.deviceType) && - this.deviceType && - this.deviceType.length > 1 - ) + return Array.isArray(this.deviceType) && this.deviceType.length > 1 }, }, networkId: { From b6f0a9b008b1ae7d9538cab728768c1fa26fb142 Mon Sep 17 00:00:00 2001 From: Bharat Dandu Date: Wed, 31 May 2023 09:58:25 -0400 Subject: [PATCH 22/40] Updating updateEndpoint and duplicateEndpoint based on the schema change with the introduction of Endpoint_type_device table Github: ZAP#682 --- src-electron/db/query-config.js | 82 +++++++++++++++++++--- src-electron/db/query-device-type.js | 6 +- src/components/ZclCreateModifyEndpoint.vue | 9 +-- 3 files changed, 76 insertions(+), 21 deletions(-) diff --git a/src-electron/db/query-config.js b/src-electron/db/query-config.js index 20c882e959..41d016e060 100644 --- a/src-electron/db/query-config.js +++ b/src-electron/db/query-config.js @@ -351,6 +351,8 @@ function getAllParamValuePairArrayClauses(paramValuePairArray) { currentString += false } else if (paramValuePair.value == null) { currentString += 'null' + } else if (Array.isArray(paramValuePair.value)) { + currentString += paramValuePair.value[0] } else { if (paramValuePair.type == 'text') { currentString += "'" + paramValuePair.value + "'" @@ -549,7 +551,7 @@ async function insertEndpointType( // Resolve endpointDefaults based on device type order. Reversing the order // such that the device type defaults are maintained based on the order from // deviceTypeRefs - let deviceTypeRefsReversed = deviceTypeRefs.reverse() + let deviceTypeRefsReversed = deviceTypeRefs for (const dtRef of deviceTypeRefsReversed) { await setEndpointDefaults( db, @@ -571,9 +573,10 @@ async function insertEndpointType( * @returns Promise to duplicate endpoint type. */ async function duplicateEndpointType(db, endpointTypeId) { - let newEndpointTypeId = await dbApi.dbInsert( + // Extract all the device types based on endpoint type id + let endpointTypeDeviceInfo = await dbApi.dbAll( db, - `INSERT INTO ENDPOINT_TYPE (SESSION_REF, NAME, DEVICE_TYPE_REF) + ` SELECT ENDPOINT_TYPE.SESSION_REF, ENDPOINT_TYPE.NAME, ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF FROM @@ -583,10 +586,41 @@ async function duplicateEndpointType(db, endpointTypeId) { ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF WHERE - ENDPOINT_TYPE_ID = ?`, + ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF = ?`, [endpointTypeId] ) + let newEndpointTypeId = 0 + if (endpointTypeDeviceInfo && endpointTypeDeviceInfo.length > 0) { + // Enter into the endpoint_type table + newEndpointTypeId = await dbApi.dbInsert( + db, + `INSERT INTO ENDPOINT_TYPE (SESSION_REF, NAME) + VALUES (?, ?)`, + [endpointTypeDeviceInfo[0].SESSION_REF, endpointTypeDeviceInfo[0].NAME] + ) + + // Enter into the endpoint_type_device table to establish the endpoint_type + // and device type relationship + let endpointTypeDeviceInfoValues = [] + endpointTypeDeviceInfo.forEach((dt, index) => + endpointTypeDeviceInfoValues.push([ + newEndpointTypeId, + dt.DEVICE_TYPE_REF, + index, + ]) + ) + await dbApi.dbMultiInsert( + db, + ` + INSERT INTO + ENDPOINT_TYPE_DEVICE (ENDPOINT_TYPE_REF, DEVICE_TYPE_REF, DEVICE_TYPE_ORDER) + VALUES + (?, ?, ?)`, + endpointTypeDeviceInfoValues + ) + } + return newEndpointTypeId } @@ -606,7 +640,7 @@ async function updateEndpointType( updatedValue ) { let param = convertRestKeyToDbColumn(updateKey) - let wasPresent = await dbApi.dbGet( + let existingDeviceTypes = await dbApi.dbAll( db, ` SELECT @@ -620,14 +654,42 @@ async function updateEndpointType( ENDPOINT_TYPE_ID = ? AND SESSION_REF = ?`, [endpointTypeId, sessionId] ) + let newEndpointId = endpointTypeId + if (param != 'DEVICE_TYPE_REF') { + newEndpointId = await dbApi.dbUpdate( + db, // Check for update with schema change + `UPDATE ENDPOINT_TYPE SET ${param} = ? WHERE ENDPOINT_TYPE_ID = ? AND SESSION_REF = ?`, + [updatedValue, endpointTypeId, sessionId] + ) + } + + existingDeviceTypes = existingDeviceTypes.map((dt) => dt[param]) + // Delete the endpoint_type_device references based on endpoint_type_id + await dbApi.dbRemove( + db, + 'DELETE FROM ENDPOINT_TYPE_DEVICE WHERE ENDPOINT_TYPE_REF = ?', + endpointTypeId + ) - let newEndpointId = await dbApi.dbUpdate( - db, // Check for update with schema change - `UPDATE ENDPOINT_TYPE SET ${param} = ? WHERE ENDPOINT_TYPE_ID = ? AND SESSION_REF = ?`, - [updatedValue, endpointTypeId, sessionId] + //Re-insert endpoint_type_device references with the new references to device types + let endpointTypeDeviceInfoValues = [] + existingDeviceTypes.forEach((dt, index) => + endpointTypeDeviceInfoValues.push([endpointTypeId, dt, index]) + ) + await dbApi.dbMultiInsert( + db, + ` + INSERT INTO + ENDPOINT_TYPE_DEVICE (ENDPOINT_TYPE_REF, DEVICE_TYPE_REF, DEVICE_TYPE_ORDER) + VALUES + (?, ?, ?)`, + endpointTypeDeviceInfoValues ) - if (param === 'DEVICE_TYPE_REF' && wasPresent[param] != updatedValue) { + let isDeviceTypeRefsUpdated = + existingDeviceTypes.length === updatedValue.length && + existingDeviceTypes.every((value, index) => value == updatedValue[index]) + if (param === 'DEVICE_TYPE_REF' && isDeviceTypeRefsUpdated) { await setEndpointDefaults(db, sessionId, endpointTypeId, updatedValue) } return newEndpointId diff --git a/src-electron/db/query-device-type.js b/src-electron/db/query-device-type.js index 46306d8faa..129c50213d 100644 --- a/src-electron/db/query-device-type.js +++ b/src-electron/db/query-device-type.js @@ -92,7 +92,7 @@ async function selectDeviceTypeClustersByDeviceTypeRef(db, deviceTypeRef) { FROM DEVICE_TYPE_CLUSTER WHERE - DEVICE_TYPE_REF = ? + DEVICE_TYPE_REF IN (?) ORDER BY CLUSTER_NAME`, [deviceTypeRef] ) @@ -146,7 +146,7 @@ async function selectDeviceTypeAttributesByDeviceTypeRef(db, deviceTypeRef) { ON AT.ATTRIBUTE_REF = ATTRIBUTE.ATTRIBUTE_ID WHERE - C.DEVICE_TYPE_REF = ?`, + C.DEVICE_TYPE_REF IN (?)`, [deviceTypeRef] ) return rows.map(dbMapping.map.deviceTypeAttribute) @@ -174,7 +174,7 @@ async function selectDeviceTypeCommandsByDeviceTypeRef(db, deviceTypeRef) { ON CMD.COMMAND_REF = COMMAND.COMMAND_ID WHERE - C.DEVICE_TYPE_REF = ?`, + C.DEVICE_TYPE_REF IN (?)`, [deviceTypeRef] ) return rows.map(dbMapping.map.deviceTypeCommand) diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index bfef7b17f8..6d701a634c 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -132,7 +132,7 @@ const _ = require('lodash') export default { name: 'ZclCreateModifyEndpoint', props: ['endpointReference'], - emits: ['saveOrCreateValidated'], + emits: ['saveOrCreateValidated', 'updateData'], mixins: [CommonMixin], watch: { deviceTypeRefAndDeviceIdPair(val) { @@ -531,13 +531,6 @@ export default { if ( item.deviceIdentifier != this.zclDeviceTypes[item.deviceTypeRef].code ) { - console.log( - item.deviceIdentifier, - '-', - item.deviceTypeRef, - '-', - this.zclDeviceTypes[item.deviceTypeRef] - ) return this.asHex(item.deviceIdentifier, 4) } else { return ( From 7298ada4f4512d43691b7282b2af9f53675dacbb Mon Sep 17 00:00:00 2001 From: Bharat Dandu Date: Wed, 31 May 2023 15:58:03 -0400 Subject: [PATCH 23/40] Updating import/export endpoint type apis to handle multiple zcl device types per endpoint Github: ZAP#862 --- src-electron/db/db-mapping.js | 2 + src-electron/db/query-config.js | 7 +- src-electron/db/query-impexp.js | 168 +++++++++++++++++--------------- 3 files changed, 91 insertions(+), 86 deletions(-) diff --git a/src-electron/db/db-mapping.js b/src-electron/db/db-mapping.js index f3c59e4378..cb3d2d7ad8 100644 --- a/src-electron/db/db-mapping.js +++ b/src-electron/db/db-mapping.js @@ -377,6 +377,7 @@ exports.map = { profileId: x.PROFILE_ID, domain: x.DOMAIN, label: x.NAME, + name: x.NAME, caption: x.DESCRIPTION, } }, @@ -440,6 +441,7 @@ exports.map = { sessionRef: x.SESSION_REF, name: x.NAME, deviceTypeRef: x.DEVICE_TYPE_REF, + deviceTypes: x.deviceTypes, } }, endpointTypeCluster: (x) => { diff --git a/src-electron/db/query-config.js b/src-electron/db/query-config.js index 41d016e060..6b275f092d 100644 --- a/src-electron/db/query-config.js +++ b/src-electron/db/query-config.js @@ -548,11 +548,8 @@ async function insertEndpointType( newEndpointTypeIdDeviceCombination ) - // Resolve endpointDefaults based on device type order. Reversing the order - // such that the device type defaults are maintained based on the order from - // deviceTypeRefs - let deviceTypeRefsReversed = deviceTypeRefs - for (const dtRef of deviceTypeRefsReversed) { + // Resolve endpointDefaults based on device type order. + for (const dtRef of deviceTypeRefs) { await setEndpointDefaults( db, sessionId, diff --git a/src-electron/db/query-impexp.js b/src-electron/db/query-impexp.js index c108a4178a..b87bd9d07d 100644 --- a/src-electron/db/query-impexp.js +++ b/src-electron/db/query-impexp.js @@ -22,6 +22,8 @@ */ const dbApi = require('./db-api') const dbEnums = require('../../src-shared/db-enum') +const dbMapping = require('./db-mapping.js') + /** * Imports a single endpoint * @param {} db @@ -125,50 +127,62 @@ ORDER BY E.ENDPOINT_IDENTIFIER * @returns promise that resolves into rows in the database table. */ async function exportEndpointTypes(db, sessionId) { - let mapFunction = (x) => { - return { - endpointTypeId: x.ENDPOINT_TYPE_ID, - name: x.NAME, - deviceTypeName: x.DEVICE_TYPE_NAME, - deviceTypeCode: x.DEVICE_TYPE_CODE, - deviceTypeProfileId: x.DEVICE_TYPE_PROFILE_ID, - } - } - return dbApi + // retreive all endpoint types + let endpointTypes = await dbApi .dbAll( db, ` -SELECT DISTINCT +SELECT ENDPOINT_TYPE.ENDPOINT_TYPE_ID, - ENDPOINT_TYPE.NAME, - ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF, - DEVICE_TYPE.CODE AS DEVICE_TYPE_CODE, - DEVICE_TYPE.PROFILE_ID as DEVICE_TYPE_PROFILE_ID, - DEVICE_TYPE.NAME AS DEVICE_TYPE_NAME + ENDPOINT_TYPE.NAME FROM ENDPOINT_TYPE -INNER JOIN - ENDPOINT_TYPE_DEVICE -ON - ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF LEFT JOIN ENDPOINT ON ENDPOINT.ENDPOINT_TYPE_REF = ENDPOINT_TYPE.ENDPOINT_TYPE_ID -LEFT JOIN - DEVICE_TYPE -ON - ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID WHERE ENDPOINT_TYPE.SESSION_REF = ? ORDER BY ENDPOINT.ENDPOINT_IDENTIFIER, - ENDPOINT_TYPE.NAME, - DEVICE_TYPE_CODE, - DEVICE_TYPE_PROFILE_ID`, + ENDPOINT_TYPE.NAME`, [sessionId] ) - .then((rows) => rows.map(mapFunction)) + .then((rows) => rows.map(dbMapping.map.endpointType)) + + //Associate each endpoint type to the device types + for (let et of endpointTypes) { + et.deviceTypes = await dbApi + .dbAll( + db, + ` + SELECT + DEVICE_TYPE.DEVICE_TYPE_ID, + DEVICE_TYPE.CODE, + DEVICE_TYPE.NAME, + DEVICE_TYPE.PROFILE_ID + FROM + DEVICE_TYPE + LEFT JOIN + ENDPOINT_TYPE_DEVICE + ON + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID + INNER JOIN + ENDPOINT_TYPE + ON + ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF + WHERE + ENDPOINT_TYPE.SESSION_REF = ? + AND ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF = ? + ORDER BY + DEVICE_TYPE.NAME, + DEVICE_TYPE.CODE, + DEVICE_TYPE.PROFILE_ID`, + [sessionId, et.endpointTypeId] + ) + .then((rows) => rows.map(dbMapping.map.deviceType)) + } + return endpointTypes } /** @@ -181,66 +195,58 @@ ORDER BY * @returns Promise of endpoint insertion. */ async function importEndpointType(db, sessionId, packageIds, endpointType) { - let multipleDeviceIds = await dbApi.dbAll( + // Insert endpoint type + let endpointTypeId = await dbApi.dbInsert( db, - `SELECT DEVICE_TYPE_ID FROM DEVICE_TYPE WHERE CODE = "${parseInt( - endpointType.deviceTypeCode - )}" AND PROFILE_ID = "${parseInt( - endpointType.deviceTypeProfileId - )}" AND PACKAGE_REF IN ("${packageIds}")` + ` + INSERT INTO + ENDPOINT_TYPE ( + SESSION_REF, + NAME + ) VALUES (?, ?)`, + [sessionId, endpointType.name] ) - if (multipleDeviceIds != null && multipleDeviceIds.length > 1) { - // Each endpoint has: 'name', 'deviceTypeName', 'deviceTypeCode', `deviceTypeProfileId`, 'clusters', 'commands', 'attributes' - let deviceTypeId = await dbApi - .dbAll( - db, - `SELECT DEVICE_TYPE_ID,PACKAGE_REF FROM DEVICE_TYPE WHERE CODE = ? AND PROFILE_ID = ? AND NAME = ? AND PACKAGE_REF IN (${dbApi.toInClause( - packageIds - )})`, - [ - parseInt(endpointType.deviceTypeCode), - parseInt(endpointType.deviceTypeProfileId), - endpointType.deviceTypeName, - ] - ) - .then((matchedPackageIds) => matchedPackageIds.shift()?.DEVICE_TYPE_ID) - return dbApi.dbInsert( - db, - ` - INSERT INTO ENDPOINT_TYPE ( - SESSION_REF, - NAME, - DEVICE_TYPE_REF - ) VALUES(?, ?, ?)`, - [sessionId, endpointType.name, deviceTypeId] - ) + // Process device types + let deviceTypes = [] + if (endpointType.deviceTypes) { + deviceTypes = endpointType.deviceTypes } else { - // Each endpoint has: 'name', 'deviceTypeName', 'deviceTypeCode', `deviceTypeProfileId`, 'clusters', 'commands', 'attributes' - let deviceTypeId = await dbApi - .dbAll( - db, - `SELECT DEVICE_TYPE_ID,PACKAGE_REF FROM DEVICE_TYPE WHERE CODE = ? AND PROFILE_ID = ? AND PACKAGE_REF IN (${dbApi.toInClause( - packageIds - )})`, - [ - parseInt(endpointType.deviceTypeCode), - parseInt(endpointType.deviceTypeProfileId), - ] - ) - .then((matchedPackageIds) => matchedPackageIds.shift()?.DEVICE_TYPE_ID) - - return dbApi.dbInsert( + deviceTypes = [ + { + name: endpointType.deviceTypeName, + code: endpointType.deviceTypeCode, + profileId: endpointType.deviceTypeProfileId, + }, + ] + } + let promises = [] + for (let i = 0; i < deviceTypes.length; i++) { + // Get deviceType IDs + let rows = await dbApi.dbAll( db, - ` - INSERT INTO ENDPOINT_TYPE ( - SESSION_REF, - NAME, - DEVICE_TYPE_REF - ) VALUES( ?, ?, ?)`, - [sessionId, endpointType.name, deviceTypeId] + `SELECT DEVICE_TYPE_ID FROM DEVICE_TYPE WHERE CODE = ? AND PROFILE_ID = ? AND NAME = ? AND PACKAGE_REF IN (${packageIds})`, + [ + parseInt(deviceTypes[i].code), + parseInt(deviceTypes[i].profileId), + deviceTypes[i].name, + ] ) + + // Associate deviceTypes with the endpointType + for (let row of rows) { + promises.push( + dbApi.dbInsert( + db, + 'INSERT OR REPLACE INTO ENDPOINT_TYPE_DEVICE(ENDPOINT_TYPE_REF, DEVICE_TYPE_REF, DEVICE_TYPE_ORDER) VALUES(?, ?, ?)', + [endpointTypeId, row.DEVICE_TYPE_ID, i] + ) + ) + } } + + await Promise.all(promises) + return endpointTypeId } /** From b3412d1fefff3ea0d89956489594dfee2eb89ad6 Mon Sep 17 00:00:00 2001 From: Bharat Dandu Date: Thu, 1 Jun 2023 13:40:22 -0400 Subject: [PATCH 24/40] Updating selectAllEndpointTypes and selectEndpointType such that they update the multiple zcl device types correctly Github: ZAP#862 --- src-electron/db/query-endpoint-type.js | 102 ++++++++++++++++--------- 1 file changed, 68 insertions(+), 34 deletions(-) diff --git a/src-electron/db/query-endpoint-type.js b/src-electron/db/query-endpoint-type.js index 056b42a049..4e3d2e30d5 100644 --- a/src-electron/db/query-endpoint-type.js +++ b/src-electron/db/query-endpoint-type.js @@ -47,24 +47,54 @@ async function deleteEndpointType(db, id) { * @returns promise that resolves into rows in the database table. */ async function selectAllEndpointTypes(db, sessionId) { - let rows = await dbApi.dbAll( - db, - ` + let endpointTypes = await dbApi + .dbAll( + db, + ` SELECT ENDPOINT_TYPE.ENDPOINT_TYPE_ID, ENDPOINT_TYPE.NAME, - ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF, ENDPOINT_TYPE.SESSION_REF FROM ENDPOINT_TYPE -INNER JOIN - ENDPOINT_TYPE_DEVICE -ON - ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF WHERE SESSION_REF = ? ORDER BY NAME`, - [sessionId] - ) - return rows.map(dbMapping.map.endpointType) + [sessionId] + ) + .then((rows) => rows.map(dbMapping.map.endpointType)) + + // Select deviceTypes for each endpointType + for (let et of endpointTypes) { + et.deviceTypeRef = await dbApi + .dbAll( + db, + ` + SELECT + DEVICE_TYPE.DEVICE_TYPE_ID, + DEVICE_TYPE.CODE, + DEVICE_TYPE.NAME, + DEVICE_TYPE.PROFILE_ID + FROM + DEVICE_TYPE + LEFT JOIN + ENDPOINT_TYPE_DEVICE + ON + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID + INNER JOIN + ENDPOINT_TYPE + ON + ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF + WHERE + ENDPOINT_TYPE.SESSION_REF = ? + AND ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF = ? + ORDER BY + DEVICE_TYPE.NAME, + DEVICE_TYPE.CODE, + DEVICE_TYPE.PROFILE_ID`, + [sessionId, et.endpointTypeId] + ) + .then((rows) => rows.map((x) => x.DEVICE_TYPE_ID)) + } + return endpointTypes } /** @@ -89,14 +119,6 @@ SELECT ENDPOINT_TYPE.ENDPOINT_TYPE_ID FROM ENDPOINT_TYPE -INNER JOIN - ENDPOINT_TYPE_DEVICE -ON - ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF -LEFT JOIN - DEVICE_TYPE -ON - ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID WHERE ENDPOINT_TYPE.SESSION_REF = ? ORDER BY ENDPOINT_TYPE.NAME`, @@ -133,14 +155,6 @@ INNER JOIN ENDPOINT ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT.ENDPOINT_TYPE_REF -INNER JOIN - ENDPOINT_TYPE_DEVICE -ON - ENDPOINT_TYPE.ENDPOINT_TYPE = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF -LEFT JOIN - DEVICE_TYPE -ON - ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID WHERE ENDPOINT_TYPE.SESSION_REF = ? ORDER BY ENDPOINT_TYPE.NAME`, @@ -157,26 +171,46 @@ ORDER BY ENDPOINT_TYPE.NAME`, * @returns endpoint type */ async function selectEndpointType(db, id) { - return dbApi + let endpointTypeId = await dbApi .dbGet( db, ` SELECT ENDPOINT_TYPE.ENDPOINT_TYPE_ID, ENDPOINT_TYPE.SESSION_REF, - ENDPOINT_TYPE.NAME, - ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF + ENDPOINT_TYPE.NAME FROM ENDPOINT_TYPE - INNER JOIN - ENDPOINT_TYPE_DEVICE - ON - ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF WHERE ENDPOINT_TYPE_ID = ?`, [id] ) .then(dbMapping.map.endpointType) + + // Device types for endpoint + endpointType.deviceTypes = await dbApi + .dbAll( + db, + ` + SELECT + DEVICE_TYPE.DEVICE_TYPE_ID + FROM + DEVICE_TYPE + LEFT JOIN + ENDPOINT_TYPE_DEVICE + ON + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID + WHERE + ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF = ? + ORDER BY + DEVICE_TYPE.NAME, + DEVICE_TYPE.CODE, + DEVICE_TYPE.PROFILE_ID`, + [id] + ) + .then((rows) => rows.map((row) => row.DEVICE_TYPE_ID)) + + return endpointType } /** From ab3ca363893e5c04f2937ef1bdaee3ee63f2fff8 Mon Sep 17 00:00:00 2001 From: Bharat Dandu Date: Thu, 1 Jun 2023 16:04:02 -0400 Subject: [PATCH 25/40] Minor cleanup Github: ZAP#862 --- src-electron/db/db-mapping.js | 2 +- src-electron/db/query-config.js | 5 ++++- src-electron/db/query-endpoint-type.js | 5 ++++- src-electron/db/query-impexp.js | 3 +++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src-electron/db/db-mapping.js b/src-electron/db/db-mapping.js index cb3d2d7ad8..56b2985931 100644 --- a/src-electron/db/db-mapping.js +++ b/src-electron/db/db-mapping.js @@ -441,7 +441,7 @@ exports.map = { sessionRef: x.SESSION_REF, name: x.NAME, deviceTypeRef: x.DEVICE_TYPE_REF, - deviceTypes: x.deviceTypes, + deviceTypes: x.deviceTypes, // Populated outside the sql query mapping. } }, endpointTypeCluster: (x) => { diff --git a/src-electron/db/query-config.js b/src-electron/db/query-config.js index 6b275f092d..1278092c3c 100644 --- a/src-electron/db/query-config.js +++ b/src-electron/db/query-config.js @@ -524,9 +524,12 @@ async function insertEndpointType( db, sessionId, name, - deviceTypeRefs, + deviceTypeRef, doTransaction = true ) { + let deviceTypeRefs = Array.isArray(deviceTypeRef) + ? deviceTypeRef + : [deviceTypeRef] // Insert endpoint type let newEndpointTypeId = await dbApi.dbInsert( db, diff --git a/src-electron/db/query-endpoint-type.js b/src-electron/db/query-endpoint-type.js index 4e3d2e30d5..db67700021 100644 --- a/src-electron/db/query-endpoint-type.js +++ b/src-electron/db/query-endpoint-type.js @@ -171,7 +171,7 @@ ORDER BY ENDPOINT_TYPE.NAME`, * @returns endpoint type */ async function selectEndpointType(db, id) { - let endpointTypeId = await dbApi + let endpointType = await dbApi .dbGet( db, ` @@ -210,6 +210,9 @@ async function selectEndpointType(db, id) { ) .then((rows) => rows.map((row) => row.DEVICE_TYPE_ID)) + // Loading endpointTypeRef as primary endpointType for backwards compatibility + endpointType.deviceTypeRef = endpointType.deviceTypes[0] + return endpointType } diff --git a/src-electron/db/query-impexp.js b/src-electron/db/query-impexp.js index b87bd9d07d..4ec137560a 100644 --- a/src-electron/db/query-impexp.js +++ b/src-electron/db/query-impexp.js @@ -181,6 +181,9 @@ ORDER BY [sessionId, et.endpointTypeId] ) .then((rows) => rows.map(dbMapping.map.deviceType)) + + // Loading endpointTypeRef as primary endpointType for backwards compatibility + et.deviceTypeRef = et.deviceTypes[0] } return endpointTypes } From 06dddcb6d03bc24c5a3b22ac6c2559c61243c8f4 Mon Sep 17 00:00:00 2001 From: Gergely Kiss Date: Fri, 2 Jun 2023 17:03:29 +0200 Subject: [PATCH 26/40] Add primary device type selection logic --- src/components/ZclCreateModifyEndpoint.vue | 46 ++++++++-------- src/components/ZclEndpointCard.vue | 64 +++++++++------------- 2 files changed, 47 insertions(+), 63 deletions(-) diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index 6d701a634c..227e8eac96 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -175,13 +175,16 @@ export default { // Set device types only in edit mode this.deviceTypeTmp = deviceTypes - this.primaryDeviceTypeTmp = deviceTypes[0] ?? null // TODO set it here from the store + this.primaryDeviceTypeTmp = deviceTypes[0] ?? null // First item is the primary device type } else { this.shownEndpoint.endpointIdentifier = this.getSmallestUnusedEndpointId() } - const enableMultiDeviceFeatures = true - this.enableMultipleDevice = enableMultiDeviceFeatures // TODO make it data driven from the store - this.enablePrimaryDevice = enableMultiDeviceFeatures // TODO make it data driven from the store + + const enableMultiDeviceFeatures = + this.$store.state.zap.selectedZapConfig?.zclProperties?.category === + 'matter' + this.enableMultipleDevice = enableMultiDeviceFeatures + this.enablePrimaryDevice = enableMultiDeviceFeatures }, data() { return { @@ -291,19 +294,19 @@ export default { const newPrimaryDeviceType = Array.isArray(value) && value.length > 0 ? value[0] : null if (this.enablePrimaryDevice) { - if (this.primaryDeviceType === null) { - this.primaryDeviceType = newPrimaryDeviceType + if (this.primaryDeviceTypeTmp === null) { + this.primaryDeviceTypeTmp = newPrimaryDeviceType } else { if ( !value.includes( (deviceType) => deviceType.deviceTypeRef === - this.primaryDeviceType.deviceTypeRef && + this.primaryDeviceTypeTmp.deviceTypeRef && deviceType.deviceIdentifier === - this.primaryDeviceType.deviceIdentifier + this.primaryDeviceTypeTmp.deviceIdentifier ) ) { - this.primaryDeviceType = newPrimaryDeviceType + this.primaryDeviceTypeTmp = newPrimaryDeviceType } } } @@ -314,9 +317,16 @@ export default { return this.primaryDeviceTypeTmp }, set(value) { - this.primaryDeviceTypeTmp = value - - // TODO write back to the store and backend here + if (this.primaryDeviceTypeTmp?.deviceTypeRef == value?.deviceTypeRef) { + return + } + const newPrimaryDevice = value + let tempDeviceType = this.deviceType + tempDeviceType = tempDeviceType.filter( + (d) => d.deviceTypeRef !== newPrimaryDevice.deviceTypeRef + ) + tempDeviceType.unshift(newPrimaryDevice) + this.deviceType = tempDeviceType }, }, }, @@ -516,18 +526,6 @@ export default { }, getDeviceOptionLabel(item) { if (item == null || item.deviceTypeRef == null) return '' - // if (Array.isArray(item.deviceTypeRef)) { - // let deviceOptionLabels = [] - // item.deviceTypeRef.forEach((d) => - // deviceOptionLabels.push( - // this.zclDeviceTypes[d].description + - // ' (' + - // this.asHex(this.zclDeviceTypes[d].code, 4) + - // ')' - // ) - // ) - // return deviceOptionLabels - // } else { if ( item.deviceIdentifier != this.zclDeviceTypes[item.deviceTypeRef].code ) { diff --git a/src/components/ZclEndpointCard.vue b/src/components/ZclEndpointCard.vue index 4adbf2a10d..6a1db037d0 100644 --- a/src/components/ZclEndpointCard.vue +++ b/src/components/ZclEndpointCard.vue @@ -112,7 +112,12 @@ limitations under the License. Primary Device
    - {{ getPrimaryDeviceOptionLabel() }} + {{ + `${deviceType[0]?.description} (${asHex( + deviceType[0]?.code, + 4 + )})` + }}
    @@ -281,43 +286,6 @@ export default { ) this.deleteEpt() }, - getDeviceOptionLabel() { - if (this.deviceType == null) return '' - if (Array.isArray(this.deviceType)) { - let deviceOptionLabels = [] - this.deviceType.forEach((d, index) => - deviceOptionLabels.push( - d.description + '(' + this.asHex(d.code, 4) + ')' - ) - ) - return deviceOptionLabels - } else { - return ( - this.deviceType.description + - ' (' + - this.asHex(this.deviceType.code, 4) + - ')' - ) - } - }, - getPrimaryDeviceOptionLabel() { - if (this.deviceType == null) return '' - if (Array.isArray(this.deviceType)) { - return ( - this.deviceType[0].description + - ' (' + - this.asHex(this.deviceType[0].code, 4) + - ')' - ) - } else { - return ( - this.deviceType.description + - ' (' + - this.asHex(this.deviceType.code, 4) + - ')' - ) - } - }, handleDeletionDialog() { if (this.getStorageParam() == 'true') { this.deleteEpt() @@ -399,7 +367,7 @@ export default { let refs = this.endpointDeviceTypeRef[this.endpointType[this.endpointReference]] let deviceTypes = [] - if (refs.length > 0) { + if (refs?.length > 0) { refs.forEach((ref) => deviceTypes.push(this.zclDeviceTypes[ref])) return deviceTypes } else { @@ -413,6 +381,24 @@ export default { } }, }, + getPrimaryDeviceOptionLabel() { + if (this.deviceType == null) return '' + if (Array.isArray(this.deviceType)) { + return ( + this.deviceType[0].description + + ' (' + + this.asHex(this.deviceType[0].code, 4) + + ')' + ) + } else { + return ( + this.deviceType.description + + ' (' + + this.asHex(this.deviceType.code, 4) + + ')' + ) + } + }, isDeviceTypeArray: { get() { return Array.isArray(this.deviceType) && this.deviceType.length > 1 From 95f21fe59c91627277940804b7bfb3f739bd345b Mon Sep 17 00:00:00 2001 From: Gergely Kiss Date: Fri, 2 Jun 2023 18:20:36 +0200 Subject: [PATCH 27/40] Add multi device type modification warning dialog --- src/components/ZclCreateModifyEndpoint.vue | 39 +++++++++++++++- src/components/ZclWarningDialog.vue | 52 ++++++++++++++++++++++ 2 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 src/components/ZclWarningDialog.vue diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index 227e8eac96..5818e9cd25 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -120,6 +120,20 @@ limitations under the License. /> + + +
    @@ -127,6 +141,7 @@ limitations under the License. import * as RestApi from '../../src-shared/rest-api' import * as DbEnum from '../../src-shared/db-enum' import CommonMixin from '../util/common-mixin' +import ZclWarningDialog from './ZclWarningDialog.vue' const _ = require('lodash') export default { @@ -134,6 +149,7 @@ export default { props: ['endpointReference'], emits: ['saveOrCreateValidated', 'updateData'], mixins: [CommonMixin], + components: { ZclWarningDialog }, watch: { deviceTypeRefAndDeviceIdPair(val) { this.setDeviceTypeCallback(val) @@ -175,6 +191,7 @@ export default { // Set device types only in edit mode this.deviceTypeTmp = deviceTypes + this.deviceTypeMountSnapshot = JSON.parse(JSON.stringify(deviceTypes)) this.primaryDeviceTypeTmp = deviceTypes[0] ?? null // First item is the primary device type } else { this.shownEndpoint.endpointIdentifier = this.getSmallestUnusedEndpointId() @@ -198,8 +215,11 @@ export default { saveOrCreateCloseFlag: false, deviceTypeTmp: [], // Temp store for the selected device types primaryDeviceTypeTmp: null, // Temp store for the selected primary device type - enableMultipleDevice: false, // TODO make it data driven - enablePrimaryDevice: false, // TODO make it data driven + enableMultipleDevice: false, + enablePrimaryDevice: false, + showWarningDialog: false, + warningDialogReturnValue: null, + deviceTypeMountSnapshot: null, } }, computed: { @@ -361,6 +381,21 @@ export default { } }, saveOrCreateHandler() { + // Check if warning dialog available for the given situation + if ( + this.endpointReference && + this.warningDialogReturnValue == null && + this.deviceType?.length > 1 + ) { + // Check if warning dialog should be shown + let deviceTypeChanged = true + // this.deviceTypeMountSnapshot + if (deviceTypeChanged) { + this.showWarningDialog = true + return + } + } + this.warningDialogReturnValue = null let profile = this.$store.state.zap.isProfileIdShown ? this.$refs.profile.validate() : true diff --git a/src/components/ZclWarningDialog.vue b/src/components/ZclWarningDialog.vue new file mode 100644 index 0000000000..d7038a131e --- /dev/null +++ b/src/components/ZclWarningDialog.vue @@ -0,0 +1,52 @@ + + + From 95f06e0a58cc25a15a99a990acfa0f051a13bc61 Mon Sep 17 00:00:00 2001 From: Gergely Kiss Date: Fri, 2 Jun 2023 18:36:51 +0200 Subject: [PATCH 28/40] Generalize the warning message --- src/components/ZclCreateModifyEndpoint.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index 5818e9cd25..d6369e1d42 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -123,7 +123,7 @@ limitations under the License.
    Device -
  • - {{ `${dev.description} (${asHex(dev.code, 4)})` }} +
  • + {{ + `${dev.description} (${asHex(dev.code, 4)})` + }}
  • @@ -98,12 +105,12 @@ limitations under the License. Device
    - {{ - `${deviceType[0].description} (${asHex( - deviceType[0].code, + {{ + `${deviceType[0]?.description} (${asHex( + deviceType[0]?.code, 4 )})` - }} + }}
    From b28057fd1039003a0ec9fd08c21c66c9612ab58b Mon Sep 17 00:00:00 2001 From: Gergely Kiss Date: Mon, 12 Jun 2023 17:46:54 +0200 Subject: [PATCH 30/40] Remove warning dialog code chunks --- src/components/ZclCreateModifyEndpoint.vue | 33 -------------- src/components/ZclWarningDialog.vue | 52 ---------------------- 2 files changed, 85 deletions(-) delete mode 100644 src/components/ZclWarningDialog.vue diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index 1937f7815a..056056a41c 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -120,20 +120,6 @@ limitations under the License. /> - - - @@ -141,7 +127,6 @@ limitations under the License. import * as RestApi from '../../src-shared/rest-api' import * as DbEnum from '../../src-shared/db-enum' import CommonMixin from '../util/common-mixin' -import ZclWarningDialog from './ZclWarningDialog.vue' const _ = require('lodash') export default { @@ -149,7 +134,6 @@ export default { props: ['endpointReference'], emits: ['saveOrCreateValidated', 'updateData'], mixins: [CommonMixin], - components: { ZclWarningDialog }, watch: { deviceTypeRefAndDeviceIdPair(val) { this.setDeviceTypeCallback(val) @@ -376,23 +360,6 @@ export default { } }, saveOrCreateHandler() { - // Check if warning dialog available for the given situation - if ( - this.endpointReference && - this.warningDialogReturnValue == null && - this.deviceType?.length > 1 - ) { - // Check if warning dialog should be shown - let deviceTypeChanged = true - // this.deviceTypeMountSnapshot - if (deviceTypeChanged) { - this.warningMessage = - 'ZCL device type is being modified which can cause all the configuration on the endpoint to be cleared and re-adjusted.' - this.showWarningDialog = true - return - } - } - this.warningDialogReturnValue = null let profile = this.$store.state.zap.isProfileIdShown ? this.$refs.profile.validate() : true diff --git a/src/components/ZclWarningDialog.vue b/src/components/ZclWarningDialog.vue deleted file mode 100644 index d7038a131e..0000000000 --- a/src/components/ZclWarningDialog.vue +++ /dev/null @@ -1,52 +0,0 @@ - - - From 1ba99fd7075453e713a855e24c5b6bdbd001577a Mon Sep 17 00:00:00 2001 From: Bharat Dandu Date: Tue, 13 Jun 2023 13:42:49 -0400 Subject: [PATCH 31/40] Add device type identifier and device type revision to endpoint_type_device junction table instead of keeping it in endpoint table such that multiple zcl device types can be added per endpoint. Schema change lead to the rest of the changes in queries for endpoint_type, endpoint_type_device and endpoint tables along with UI changes to vue files, actions and mutations. Github: ZAP#862 --- docs/zap-schema.svg | 4257 ++++++++++---------- src-electron/db/query-config.js | 30 +- src-electron/db/query-endpoint-type.js | 14 +- src-electron/db/query-endpoint.js | 74 +- src-electron/db/zap-schema.sql | 4 +- src-electron/rest/endpoint.js | 20 +- src/components/ZclCreateModifyEndpoint.vue | 6 + src/store/zap/actions.js | 3 +- src/store/zap/mutations.js | 4 +- src/tutorials/ZclTour.vue | 8 +- 10 files changed, 2146 insertions(+), 2274 deletions(-) diff --git a/docs/zap-schema.svg b/docs/zap-schema.svg index 43590daa06..164019c872 100644 --- a/docs/zap-schema.svg +++ b/docs/zap-schema.svg @@ -1,2667 +1,2490 @@ - - - + + SchemaCrawler_Diagram - -generated by -SchemaCrawler 16.16.18 -ZAP schema, Copyright (c) 2020 Silicon Labs, released under Apache 2.0 license. - + +generated by +SchemaCrawler 16.19.9 +generated on +2023-06-13 17:33:39 + access_72bb1dc3 - - -ACCESS - -[table] -ACCESS_ID - -INTEGER - -auto-incremented -OPERATION_REF - -INTEGER -ROLE_REF - -INTEGER -ACCESS_MODIFIER_REF - -INTEGER - + +ACCESS + +[table] +ACCESS_ID + +INTEGER + +auto-incremented +OPERATION_REF + +INTEGER +ROLE_REF + +INTEGER +ACCESS_MODIFIER_REF + +INTEGER + access_modifier_f63f3fb1 - - -ACCESS_MODIFIER - -[table] -ACCESS_MODIFIER_ID - -INTEGER - -auto-incremented -PACKAGE_REF - -INTEGER -NAME - -TEXT -DESCRIPTION - -TEXT - + +ACCESS_MODIFIER + +[table] +ACCESS_MODIFIER_ID + +INTEGER + +auto-incremented +PACKAGE_REF + +INTEGER +NAME + +TEXT +DESCRIPTION + +TEXT + access_72bb1dc3:w->access_modifier_f63f3fb1:e - - - - - - - + + + + +SCHCRWLR_F63ECB52_72BAA964 - + operation_93359a6 - - -OPERATION - -[table] -OPERATION_ID - -INTEGER - -auto-incremented -PACKAGE_REF - -INTEGER -NAME - -TEXT -DESCRIPTION - -TEXT - + +OPERATION + +[table] +OPERATION_ID + +INTEGER + +auto-incremented +PACKAGE_REF + +INTEGER +NAME + +TEXT +DESCRIPTION + +TEXT + - + access_72bb1dc3:w->operation_93359a6:e - - - - - - - + + + + +SCHCRWLR_0932E547_72BAA964 - + role_26ecd5 - - -ROLE - -[table] -ROLE_ID - -INTEGER - -auto-incremented -PACKAGE_REF - -INTEGER -LEVEL - -INTEGER -NAME - -TEXT -DESCRIPTION - -TEXT - + +ROLE + +[table] +ROLE_ID + +INTEGER + +auto-incremented +PACKAGE_REF + +INTEGER +LEVEL + +INTEGER +NAME + +TEXT +DESCRIPTION + +TEXT + - + access_72bb1dc3:w->role_26ecd5:e - - - - - - - + + + + +SCHCRWLR_00267876_72BAA964 attribute_access_b017dce6 - - -ATTRIBUTE_ACCESS - -[table] -ATTRIBUTE_REF - -INTEGER -ACCESS_REF - -INTEGER - + +ATTRIBUTE_ACCESS + +[table] +ATTRIBUTE_REF + +INTEGER +ACCESS_REF + +INTEGER + attribute_access_b017dce6:w->access_72bb1dc3:e - - - - - - - + + + + +SCHCRWLR_72BAA964_B0176887 attribute_a6e02edb - - -ATTRIBUTE - -[table] -ATTRIBUTE_ID - -INTEGER - -auto-incremented -CLUSTER_REF - -INTEGER -PACKAGE_REF - -INTEGER -CODE - -INTEGER -MANUFACTURER_CODE - -INTEGER -NAME - -TEXT -TYPE - -TEXT -SIDE - -TEXT -DEFINE - -TEXT -MIN - -TEXT -MAX - -TEXT -MIN_LENGTH - -INTEGER -MAX_LENGTH - -INTEGER -REPORT_MIN_INTERVAL - -INTEGER -REPORT_MAX_INTERVAL - -INTEGER -REPORTABLE_CHANGE - -TEXT -REPORTABLE_CHANGE_LENGTH - -INTEGER -IS_WRITABLE - -INTEGER -DEFAULT_VALUE - -TEXT -IS_SCENE_REQUIRED - -INTEGER -IS_OPTIONAL - -INTEGER -REPORTING_POLICY - -TEXT -STORAGE_POLICY - -TEXT -IS_NULLABLE - -INTEGER -ARRAY_TYPE - -TEXT -MUST_USE_TIMED_WRITE - -INTEGER -INTRODUCED_IN_REF - -INTEGER -REMOVED_IN_REF - -INTEGER - + +ATTRIBUTE + +[table] +ATTRIBUTE_ID + +INTEGER + +auto-incremented +CLUSTER_REF + +INTEGER +PACKAGE_REF + +INTEGER +CODE + +INTEGER +MANUFACTURER_CODE + +INTEGER +NAME + +TEXT +TYPE + +TEXT +SIDE + +TEXT +DEFINE + +TEXT +MIN + +TEXT +MAX + +TEXT +MIN_LENGTH + +INTEGER +MAX_LENGTH + +INTEGER +REPORT_MIN_INTERVAL + +INTEGER +REPORT_MAX_INTERVAL + +INTEGER +REPORTABLE_CHANGE + +TEXT +REPORTABLE_CHANGE_LENGTH + +INTEGER +IS_WRITABLE + +INTEGER +DEFAULT_VALUE + +TEXT +IS_SCENE_REQUIRED + +INTEGER +IS_OPTIONAL + +INTEGER +REPORTING_POLICY + +TEXT +STORAGE_POLICY + +TEXT +IS_NULLABLE + +INTEGER +ARRAY_TYPE + +TEXT +MUST_USE_TIMED_WRITE + +INTEGER +INTRODUCED_IN_REF + +INTEGER +REMOVED_IN_REF + +INTEGER + attribute_access_b017dce6:w->attribute_a6e02edb:e - - - - - - - + + + + +SCHCRWLR_A6DFBA7C_B0176887 cluster_access_38ea13c8 - - -CLUSTER_ACCESS - -[table] -CLUSTER_REF - -INTEGER -ACCESS_REF - -INTEGER - + +CLUSTER_ACCESS + +[table] +CLUSTER_REF + +INTEGER +ACCESS_REF + +INTEGER + cluster_access_38ea13c8:w->access_72bb1dc3:e - - - - - - - + + + + +SCHCRWLR_72BAA964_38E99F69 cluster_5ec71239 - - -CLUSTER - -[table] -CLUSTER_ID - -INTEGER - -auto-incremented -PACKAGE_REF - -INTEGER -DOMAIN_NAME - -TEXT -CODE - -INTEGER -MANUFACTURER_CODE - -INTEGER -NAME - -TEXT -DESCRIPTION - -TEXT -DEFINE - -TEXT -IS_SINGLETON - -INTEGER -REVISION - -INTEGER -INTRODUCED_IN_REF - -INTEGER -REMOVED_IN_REF - -INTEGER - + +CLUSTER + +[table] +CLUSTER_ID + +INTEGER + +auto-incremented +PACKAGE_REF + +INTEGER +DOMAIN_NAME + +TEXT +CODE + +INTEGER +MANUFACTURER_CODE + +INTEGER +NAME + +TEXT +DESCRIPTION + +TEXT +DEFINE + +TEXT +IS_SINGLETON + +INTEGER +REVISION + +INTEGER +INTRODUCED_IN_REF + +INTEGER +REMOVED_IN_REF + +INTEGER + - + cluster_access_38ea13c8:w->cluster_5ec71239:e - - - - - - - + + + + +SCHCRWLR_5EC69DDA_38E99F69 command_access_b02dd957 - - -COMMAND_ACCESS - -[table] -COMMAND_REF - -INTEGER -ACCESS_REF - -INTEGER - + +COMMAND_ACCESS + +[table] +COMMAND_REF + +INTEGER +ACCESS_REF + +INTEGER + command_access_b02dd957:w->access_72bb1dc3:e - - - - - - - + + + + +SCHCRWLR_72BAA964_B02D64F8 - + command_6371df8a - - -COMMAND - -[table] -COMMAND_ID - -INTEGER - -auto-incremented -CLUSTER_REF - -INTEGER -PACKAGE_REF - -INTEGER -CODE - -INTEGER -MANUFACTURER_CODE - -INTEGER -NAME - -TEXT -DESCRIPTION - -TEXT -SOURCE - -TEXT -IS_OPTIONAL - -INTEGER -MUST_USE_TIMED_INVOKE - -INTEGER -IS_FABRIC_SCOPED - -INTEGER -INTRODUCED_IN_REF - -INTEGER -REMOVED_IN_REF - -INTEGER -RESPONSE_NAME - -INTEGER -RESPONSE_REF - -INTEGER -IS_DEFAULT_RESPONSE_ENABLED - -INTEGER - + +COMMAND + +[table] +COMMAND_ID + +INTEGER + +auto-incremented +CLUSTER_REF + +INTEGER +PACKAGE_REF + +INTEGER +CODE + +INTEGER +MANUFACTURER_CODE + +INTEGER +NAME + +TEXT +DESCRIPTION + +TEXT +SOURCE + +TEXT +IS_OPTIONAL + +INTEGER +MUST_USE_TIMED_INVOKE + +INTEGER +IS_FABRIC_SCOPED + +INTEGER +INTRODUCED_IN_REF + +INTEGER +REMOVED_IN_REF + +INTEGER +RESPONSE_NAME + +INTEGER +RESPONSE_REF + +INTEGER +IS_DEFAULT_RESPONSE_ENABLED + +INTEGER + command_access_b02dd957:w->command_6371df8a:e - - - - - - - + + + + +SCHCRWLR_63716B2B_B02D64F8 default_access_7ba041a1 - - -DEFAULT_ACCESS - -[table] -PACKAGE_REF - -INTEGER -ENTITY_TYPE - -TEXT -ACCESS_REF - -INTEGER - + +DEFAULT_ACCESS + +[table] +PACKAGE_REF + +INTEGER +ENTITY_TYPE + +TEXT +ACCESS_REF + +INTEGER + default_access_7ba041a1:w->access_72bb1dc3:e - - - - - - - + + + + +SCHCRWLR_72BAA964_7B9FCD42 - + package_fab13485 - - -PACKAGE - -[table] -PACKAGE_ID - -INTEGER - -auto-incremented -PARENT_PACKAGE_REF - -INTEGER -PATH - -TEXT NOT NULL -TYPE - -TEXT -CRC - -INTEGER -VERSION - -INTEGER -CATEGORY - -TEXT -DESCRIPTION - -TEXT - + +PACKAGE + +[table] +PACKAGE_ID + +INTEGER + +auto-incremented +PARENT_PACKAGE_REF + +INTEGER +PATH + +TEXT NOT NULL +TYPE + +TEXT +CRC + +INTEGER +VERSION + +INTEGER +CATEGORY + +TEXT +DESCRIPTION + +TEXT + - + default_access_7ba041a1:w->package_fab13485:e - - - - - - - + + + + +SCHCRWLR_FAB0C026_7B9FCD42 event_access_4668c328 - - -EVENT_ACCESS - -[table] -EVENT_REF - -INTEGER -ACCESS_REF - -INTEGER - + +EVENT_ACCESS + +[table] +EVENT_REF + +INTEGER +ACCESS_REF + +INTEGER + event_access_4668c328:w->access_72bb1dc3:e - - - - - - - + + + + +SCHCRWLR_72BAA964_46684EC9 event_3f4eed9 - - -EVENT - -[table] -EVENT_ID - -INTEGER - -auto-incremented -CLUSTER_REF - -INTEGER -PACKAGE_REF - -INTEGER -CODE - -INTEGER -MANUFACTURER_CODE - -INTEGER -NAME - -TEXT -DESCRIPTION - -TEXT -SIDE - -TEXT -IS_OPTIONAL - -INTEGER -IS_FABRIC_SENSITIVE - -INTEGER -PRIORITY - -TEXT -INTRODUCED_IN_REF - -INTEGER -REMOVED_IN_REF - -INTEGER - + +EVENT + +[table] +EVENT_ID + +INTEGER + +auto-incremented +CLUSTER_REF + +INTEGER +PACKAGE_REF + +INTEGER +CODE + +INTEGER +MANUFACTURER_CODE + +INTEGER +NAME + +TEXT +DESCRIPTION + +TEXT +SIDE + +TEXT +IS_OPTIONAL + +INTEGER +IS_FABRIC_SENSITIVE + +INTEGER +PRIORITY + +TEXT +INTRODUCED_IN_REF + +INTEGER +REMOVED_IN_REF + +INTEGER + - + event_access_4668c328:w->event_3f4eed9:e - - - - - - - + + + + +SCHCRWLR_03F47A7A_46684EC9 - + access_modifier_f63f3fb1:w->package_fab13485:e - - - - - - - + + + + +SCHCRWLR_FAB0C026_F63ECB52 atomic_73b03e8a - - -"ATOMIC" - -[table] -ATOMIC_ID - -INTEGER - -auto-incremented -PACKAGE_REF - -INTEGER -NAME - -TEXT -DESCRIPTION - -TEXT -ATOMIC_IDENTIFIER - -INTEGER -ATOMIC_SIZE - -INTEGER -IS_DISCRETE - -INTEGER -IS_STRING - -INTEGER -IS_LONG - -INTEGER -IS_CHAR - -INTEGER -IS_SIGNED - -INTEGER - + +"ATOMIC" + +[table] +ATOMIC_ID + +INTEGER + +auto-incremented +PACKAGE_REF + +INTEGER +NAME + +TEXT +DESCRIPTION + +TEXT +ATOMIC_IDENTIFIER + +INTEGER +ATOMIC_SIZE + +INTEGER +IS_DISCRETE + +INTEGER +IS_STRING + +INTEGER +IS_LONG + +INTEGER +IS_CHAR + +INTEGER +IS_SIGNED + +INTEGER + - + atomic_73b03e8a:w->package_fab13485:e - - - - - - - + + + + +SCHCRWLR_FAB0C026_CE3170F5 - + attribute_a6e02edb:w->cluster_5ec71239:e - - - - - - - + + + + +SCHCRWLR_5EC69DDA_A6DFBA7C - + attribute_a6e02edb:w->package_fab13485:e - - - - - - - + + + + +SCHCRWLR_FAB0C026_A6DFBA7C - + spec_27641a - - -SPEC - -[table] -SPEC_ID - -INTEGER - -auto-incremented -PACKAGE_REF - -INTEGER -CODE - -TEXT NOT NULL -DESCRIPTION - -TEXT -CERTIFIABLE - -INTEGER - + +SPEC + +[table] +SPEC_ID + +INTEGER + +auto-incremented +PACKAGE_REF + +INTEGER +CODE + +TEXT NOT NULL +DESCRIPTION + +TEXT +CERTIFIABLE + +INTEGER + - + attribute_a6e02edb:w->spec_27641a:e - - - - - - - + + + + +SCHCRWLR_0026EFBB_A6DFBA7C - + attribute_a6e02edb:w->spec_27641a:e - - - - - - - + + + + +SCHCRWLR_0026EFBB_A6DFBA7C device_type_attribute_ce5151f - - -DEVICE_TYPE_ATTRIBUTE - -[table] -DEVICE_TYPE_CLUSTER_REF - -INTEGER -ATTRIBUTE_REF - -INTEGER -ATTRIBUTE_NAME - -TEXT - + +DEVICE_TYPE_ATTRIBUTE + +[table] +DEVICE_TYPE_CLUSTER_REF + +INTEGER +ATTRIBUTE_REF + +INTEGER +ATTRIBUTE_NAME + +TEXT + device_type_attribute_ce5151f:w->attribute_a6e02edb:e - - - - - - - + + + + +SCHCRWLR_A6DFBA7C_0CE4A0C0 - + device_type_cluster_7298b97d - - -DEVICE_TYPE_CLUSTER - -[table] -DEVICE_TYPE_CLUSTER_ID - -INTEGER - -auto-incremented -DEVICE_TYPE_REF - -INTEGER -CLUSTER_REF - -INTEGER -CLUSTER_NAME - -TEXT -INCLUDE_CLIENT - -INTEGER -INCLUDE_SERVER - -INTEGER -LOCK_CLIENT - -INTEGER -LOCK_SERVER - -INTEGER - + +DEVICE_TYPE_CLUSTER + +[table] +DEVICE_TYPE_CLUSTER_ID + +INTEGER + +auto-incremented +DEVICE_TYPE_REF + +INTEGER +CLUSTER_REF + +INTEGER +CLUSTER_NAME + +TEXT +INCLUDE_CLIENT + +INTEGER +INCLUDE_SERVER + +INTEGER +LOCK_CLIENT + +INTEGER +LOCK_SERVER + +INTEGER + device_type_attribute_ce5151f:w->device_type_cluster_7298b97d:e - - - - - - - - - - -global_attribute_default_73c65a21 - - -GLOBAL_ATTRIBUTE_DEFAULT - -[table] -GLOBAL_ATTRIBUTE_DEFAULT_ID - -INTEGER - -auto-incremented -CLUSTER_REF - -INTEGER NOT NULL -ATTRIBUTE_REF - -INTEGER NOT NULL -DEFAULT_VALUE - -TEXT - - - - -global_attribute_default_73c65a21:w->attribute_a6e02edb:e - - - - - - - - - - -global_attribute_default_73c65a21:w->cluster_5ec71239:e - - - - - - - + + + + +SCHCRWLR_7298451E_0CE4A0C0 - + endpoint_type_attribute_c265400 - - -ENDPOINT_TYPE_ATTRIBUTE - -[table] -ENDPOINT_TYPE_ATTRIBUTE_ID - -INTEGER - -auto-incremented -ENDPOINT_TYPE_REF - -INTEGER -ENDPOINT_TYPE_CLUSTER_REF - -INTEGER -ATTRIBUTE_REF - -INTEGER -INCLUDED - -INTEGER -STORAGE_OPTION - -TEXT -SINGLETON - -INTEGER -BOUNDED - -INTEGER -DEFAULT_VALUE - -TEXT -INCLUDED_REPORTABLE - -INTEGER -MIN_INTERVAL - -INTEGER -MAX_INTERVAL - -INTEGER -REPORTABLE_CHANGE - -INTEGER - + +ENDPOINT_TYPE_ATTRIBUTE + +[table] +ENDPOINT_TYPE_ATTRIBUTE_ID + +INTEGER + +auto-incremented +ENDPOINT_TYPE_REF + +INTEGER +ENDPOINT_TYPE_CLUSTER_REF + +INTEGER +ATTRIBUTE_REF + +INTEGER +INCLUDED + +INTEGER +STORAGE_OPTION + +TEXT +SINGLETON + +INTEGER +BOUNDED + +INTEGER +DEFAULT_VALUE + +TEXT +INCLUDED_REPORTABLE + +INTEGER +MIN_INTERVAL + +INTEGER +MAX_INTERVAL + +INTEGER +REPORTABLE_CHANGE + +INTEGER + - + endpoint_type_attribute_c265400:w->attribute_a6e02edb:e - - - - - - - + + + + +SCHCRWLR_A6DFBA7C_0C25DFA1 - + endpoint_type_cluster_c12e3c9e - - -ENDPOINT_TYPE_CLUSTER - -[table] -ENDPOINT_TYPE_CLUSTER_ID - -INTEGER - -auto-incremented -ENDPOINT_TYPE_REF - -INTEGER -CLUSTER_REF - -INTEGER -SIDE - -TEXT -ENABLED - -INTEGER - + +ENDPOINT_TYPE_CLUSTER + +[table] +ENDPOINT_TYPE_CLUSTER_ID + +INTEGER + +auto-incremented +ENDPOINT_TYPE_REF + +INTEGER +CLUSTER_REF + +INTEGER +SIDE + +TEXT +ENABLED + +INTEGER + - + endpoint_type_attribute_c265400:w->endpoint_type_cluster_c12e3c9e:e - - - - - - - + + + + +SCHCRWLR_C12DC83F_0C25DFA1 - + endpoint_type_9857dc03 - - -ENDPOINT_TYPE - -[table] -ENDPOINT_TYPE_ID - -INTEGER - -auto-incremented -SESSION_REF - -INTEGER -NAME - -TEXT -DEVICE_TYPE_REF - -INTEGER - + +ENDPOINT_TYPE + +[table] +ENDPOINT_TYPE_ID + +INTEGER + +auto-incremented +SESSION_REF + +INTEGER +NAME + +TEXT + - + endpoint_type_attribute_c265400:w->endpoint_type_9857dc03:e - - - - - - - + + + + +SCHCRWLR_985767A4_0C25DFA1 + + + +global_attribute_default_73c65a21 + +GLOBAL_ATTRIBUTE_DEFAULT + +[table] +GLOBAL_ATTRIBUTE_DEFAULT_ID + +INTEGER + +auto-incremented +CLUSTER_REF + +INTEGER NOT NULL +ATTRIBUTE_REF + +INTEGER NOT NULL +DEFAULT_VALUE + +TEXT + + + + +global_attribute_default_73c65a21:w->attribute_a6e02edb:e + + + + +SCHCRWLR_A6DFBA7C_73C5E5C2 + + + +global_attribute_default_73c65a21:w->cluster_5ec71239:e + + + + +SCHCRWLR_5EC69DDA_73C5E5C2 bitmap_74cc598e - - -BITMAP - -[table] -BITMAP_ID - -INTEGER NOT NULL -SIZE - -INTEGER - + +BITMAP + +[table] +BITMAP_ID + +INTEGER NOT NULL +SIZE + +INTEGER + data_type_9233070e - - -DATA_TYPE - -[table] -DATA_TYPE_ID - -INTEGER NOT NULL - -auto-incremented -NAME - -TEXT -DESCRIPTION - -TEXT -DISCRIMINATOR_REF - -INTEGER -PACKAGE_REF - -INTEGER - + +DATA_TYPE + +[table] +DATA_TYPE_ID + +INTEGER NOT NULL + +auto-incremented +NAME + +TEXT +DESCRIPTION + +TEXT +DISCRIMINATOR_REF + +INTEGER +PACKAGE_REF + +INTEGER + bitmap_74cc598e:w->data_type_9233070e:e - - - - - - - + + + + +SCHCRWLR_923292AF_74CBE52F bitmap_field_bfea8629 - - -BITMAP_FIELD - -[table] -BITMAP_FIELD_ID - -INTEGER NOT NULL - -auto-incremented -BITMAP_REF - -INTEGER -FIELD_IDENTIFIER - -INTEGER -NAME - -TEXT(100) -MASK - -INTEGER - + +BITMAP_FIELD + +[table] +BITMAP_FIELD_ID + +INTEGER NOT NULL + +auto-incremented +BITMAP_REF + +INTEGER +FIELD_IDENTIFIER + +INTEGER +NAME + +TEXT(100) +MASK + +INTEGER +TYPE + +TEXT(100) + bitmap_field_bfea8629:w->bitmap_74cc598e:e - - - - - - - + + + + +SCHCRWLR_74CBE52F_BFEA11CA - + cluster_5ec71239:w->package_fab13485:e - - - - - - - + + + + +SCHCRWLR_FAB0C026_5EC69DDA - + cluster_5ec71239:w->spec_27641a:e - - - - - - - + + + + +SCHCRWLR_0026EFBB_5EC69DDA - + cluster_5ec71239:w->spec_27641a:e - - - - - - - + + + + +SCHCRWLR_0026EFBB_5EC69DDA + + + +command_6371df8a:w->cluster_5ec71239:e + + + + +SCHCRWLR_5EC69DDA_63716B2B + + + +command_6371df8a:w->command_6371df8a:e + + + + +SCHCRWLR_63716B2B_63716B2B + + + +command_6371df8a:w->package_fab13485:e + + + + +SCHCRWLR_FAB0C026_63716B2B + + + +command_6371df8a:w->spec_27641a:e + + + + +SCHCRWLR_0026EFBB_63716B2B + + + +command_6371df8a:w->spec_27641a:e + + + + +SCHCRWLR_0026EFBB_63716B2B - + data_type_cluster_8d9f2ca9 - - -DATA_TYPE_CLUSTER - -[table] -DATA_TYPE_CLUSTER_ID - -INTEGER NOT NULL - -auto-incremented -CLUSTER_REF - -INTEGER -CLUSTER_CODE - -INTEGER -DATA_TYPE_REF - -INTEGER - + +DATA_TYPE_CLUSTER + +[table] +DATA_TYPE_CLUSTER_ID + +INTEGER NOT NULL + +auto-incremented +CLUSTER_REF + +INTEGER +CLUSTER_CODE + +INTEGER +DATA_TYPE_REF + +INTEGER + - + data_type_cluster_8d9f2ca9:w->cluster_5ec71239:e - - - - - - - + + + + +SCHCRWLR_5EC69DDA_8D9EB84A - + data_type_cluster_8d9f2ca9:w->data_type_9233070e:e - - - - - - - + + + + +SCHCRWLR_923292AF_8D9EB84A - + device_type_cluster_7298b97d:w->cluster_5ec71239:e - - - - - - - + + + + +SCHCRWLR_5EC69DDA_7298451E device_type_2620a7e2 - - -DEVICE_TYPE - -[table] -DEVICE_TYPE_ID - -INTEGER - -auto-incremented -PACKAGE_REF - -INTEGER -DOMAIN - -TEXT -CODE - -INTEGER -PROFILE_ID - -INTEGER -NAME - -TEXT -DESCRIPTION - -TEXT - + +DEVICE_TYPE + +[table] +DEVICE_TYPE_ID + +INTEGER + +auto-incremented +PACKAGE_REF + +INTEGER +DOMAIN + +TEXT +CODE + +INTEGER +PROFILE_ID + +INTEGER +NAME + +TEXT +DESCRIPTION + +TEXT + device_type_cluster_7298b97d:w->device_type_2620a7e2:e - - - - - - - + + + + +SCHCRWLR_26203383_7298451E - + endpoint_type_cluster_c12e3c9e:w->cluster_5ec71239:e - - - - - - - + + + + +SCHCRWLR_5EC69DDA_C12DC83F - + endpoint_type_cluster_c12e3c9e:w->endpoint_type_9857dc03:e - - - - - - - - - - -tag_1b7d9 - - -TAG - -[table] -TAG_ID - -INTEGER - -auto-incremented -PACKAGE_REF - -INTEGER -CLUSTER_REF - -INTEGER -NAME - -TEXT -DESCRIPTION - -TEXT - - - - -tag_1b7d9:w->cluster_5ec71239:e - - - - - - - - - - -tag_1b7d9:w->package_fab13485:e - - - - - - - + + + + +SCHCRWLR_985767A4_C12DC83F - + event_3f4eed9:w->cluster_5ec71239:e - - - - - - - + + + + +SCHCRWLR_5EC69DDA_03F47A7A - + event_3f4eed9:w->package_fab13485:e - - - - - - - + + + + +SCHCRWLR_FAB0C026_03F47A7A - + event_3f4eed9:w->spec_27641a:e - - - - - - - + + + + +SCHCRWLR_0026EFBB_03F47A7A - -event_3f4eed9:w->spec_27641a:e - - - - - - - - - - -command_6371df8a:w->cluster_5ec71239:e - - - - - - - - - - -command_6371df8a:w->command_6371df8a:e - - - - - - - - - - -command_6371df8a:w->package_fab13485:e - - - - - - - - - - -command_6371df8a:w->spec_27641a:e - - - - - - - - - -command_6371df8a:w->spec_27641a:e - - - - - - - +event_3f4eed9:w->spec_27641a:e + + + + +SCHCRWLR_0026EFBB_03F47A7A - - -device_type_command_774386ce - - -DEVICE_TYPE_COMMAND - -[table] -DEVICE_TYPE_CLUSTER_REF - -INTEGER -COMMAND_REF - -INTEGER -COMMAND_NAME - -TEXT - + + +tag_1b7d9 + +TAG + +[table] +TAG_ID + +INTEGER + +auto-incremented +PACKAGE_REF + +INTEGER +CLUSTER_REF + +INTEGER +NAME + +TEXT +DESCRIPTION + +TEXT + - - -device_type_command_774386ce:w->device_type_cluster_7298b97d:e - - - - - - - + + +tag_1b7d9:w->cluster_5ec71239:e + + + + +SCHCRWLR_5EC69DDA_0001437A - - -device_type_command_774386ce:w->command_6371df8a:e - - - - - - - + + +tag_1b7d9:w->package_fab13485:e + + + + +SCHCRWLR_FAB0C026_0001437A - + command_arg_294e7f81 - - -COMMAND_ARG - -[table] -COMMAND_REF - -INTEGER -FIELD_IDENTIFIER - -INTEGER -NAME - -TEXT -TYPE - -TEXT -MIN - -TEXT -MAX - -TEXT -MIN_LENGTH - -INTEGER -MAX_LENGTH - -INTEGER -IS_ARRAY - -INTEGER -PRESENT_IF - -TEXT -IS_NULLABLE - -INTEGER -IS_OPTIONAL - -INTEGER -COUNT_ARG - -TEXT -INTRODUCED_IN_REF - -INTEGER -REMOVED_IN_REF - -INTEGER - + +COMMAND_ARG + +[table] +COMMAND_REF + +INTEGER +FIELD_IDENTIFIER + +INTEGER +NAME + +TEXT +TYPE + +TEXT +MIN + +TEXT +MAX + +TEXT +MIN_LENGTH + +INTEGER +MAX_LENGTH + +INTEGER +IS_ARRAY + +INTEGER +PRESENT_IF + +TEXT +IS_NULLABLE + +INTEGER +IS_OPTIONAL + +INTEGER +COUNT_ARG + +TEXT +INTRODUCED_IN_REF + +INTEGER +REMOVED_IN_REF + +INTEGER + - + command_arg_294e7f81:w->command_6371df8a:e - - - - - - - + + + + +SCHCRWLR_63716B2B_294E0B22 - + command_arg_294e7f81:w->spec_27641a:e - - - - - - - + + + + +SCHCRWLR_0026EFBB_294E0B22 - + command_arg_294e7f81:w->spec_27641a:e - - - - - - - + + + + +SCHCRWLR_0026EFBB_294E0B22 + + + +device_type_command_774386ce + +DEVICE_TYPE_COMMAND + +[table] +DEVICE_TYPE_CLUSTER_REF + +INTEGER +COMMAND_REF + +INTEGER +COMMAND_NAME + +TEXT + + + + +device_type_command_774386ce:w->command_6371df8a:e + + + + +SCHCRWLR_63716B2B_7743126F + + + +device_type_command_774386ce:w->device_type_cluster_7298b97d:e + + + + +SCHCRWLR_7298451E_7743126F endpoint_type_command_c5d909ef - - -ENDPOINT_TYPE_COMMAND - -[table] -ENDPOINT_TYPE_COMMAND_ID - -INTEGER - -auto-incremented -ENDPOINT_TYPE_REF - -INTEGER -ENDPOINT_TYPE_CLUSTER_REF - -INTEGER -COMMAND_REF - -INTEGER -INCOMING - -INTEGER -OUTGOING - -INTEGER - - - - -endpoint_type_command_c5d909ef:w->endpoint_type_cluster_c12e3c9e:e - - - - - - - + +ENDPOINT_TYPE_COMMAND + +[table] +ENDPOINT_TYPE_COMMAND_ID + +INTEGER + +auto-incremented +ENDPOINT_TYPE_REF + +INTEGER +ENDPOINT_TYPE_CLUSTER_REF + +INTEGER +COMMAND_REF + +INTEGER +INCOMING + +INTEGER +OUTGOING + +INTEGER + endpoint_type_command_c5d909ef:w->command_6371df8a:e - - - - - - - + + + + +SCHCRWLR_63716B2B_C5D89590 + + + +endpoint_type_command_c5d909ef:w->endpoint_type_cluster_c12e3c9e:e + + + + +SCHCRWLR_C12DC83F_C5D89590 endpoint_type_command_c5d909ef:w->endpoint_type_9857dc03:e - - - - - - - + + + + +SCHCRWLR_985767A4_C5D89590 discriminator_4931d2db - - -DISCRIMINATOR - -[table] -DISCRIMINATOR_ID - -INTEGER NOT NULL - -auto-incremented -NAME - -TEXT -PACKAGE_REF - -INTEGER - + +DISCRIMINATOR + +[table] +DISCRIMINATOR_ID + +INTEGER NOT NULL + +auto-incremented +NAME + +TEXT +PACKAGE_REF + +INTEGER + data_type_9233070e:w->discriminator_4931d2db:e - - - - - - - + + + + +SCHCRWLR_49315E7C_923292AF - + data_type_9233070e:w->package_fab13485:e - - - - - - - + + + + +SCHCRWLR_FAB0C026_923292AF enum_210160 - - -ENUM - -[table] -ENUM_ID - -INTEGER NOT NULL -SIZE - -INTEGER - + +ENUM + +[table] +ENUM_ID + +INTEGER NOT NULL +SIZE + +INTEGER + - + enum_210160:w->data_type_9233070e:e - - - - - - - + + + + +SCHCRWLR_923292AF_00208D01 number_89ec43a8 - - -NUMBER - -[table] -NUMBER_ID - -INTEGER NOT NULL -SIZE - -INTEGER -IS_SIGNED - -INTEGER - + +NUMBER + +[table] +NUMBER_ID + +INTEGER NOT NULL +SIZE + +INTEGER +IS_SIGNED + +INTEGER + - + number_89ec43a8:w->data_type_9233070e:e - - - - - - - + + + + +SCHCRWLR_923292AF_89EBCF49 string_9268c870 - - -STRING - -[table] -STRING_ID - -INTEGER NOT NULL -IS_LONG - -INTEGER -SIZE - -INTEGER -IS_CHAR - -INTEGER - + +STRING + +[table] +STRING_ID + +INTEGER NOT NULL +IS_LONG + +INTEGER +SIZE + +INTEGER +IS_CHAR + +INTEGER + - + string_9268c870:w->data_type_9233070e:e - - - - - - - + + + + +SCHCRWLR_923292AF_92685411 struct_9268f434 - - -STRUCT - -[table] -STRUCT_ID - -INTEGER NOT NULL -IS_FABRIC_SCOPED - -INTEGER -SIZE - -INTEGER - + +STRUCT + +[table] +STRUCT_ID + +INTEGER NOT NULL +IS_FABRIC_SCOPED + +INTEGER +SIZE + +INTEGER + - + struct_9268f434:w->data_type_9233070e:e - - - - - - - + + + + +SCHCRWLR_923292AF_92687FD5 struct_item_d6e4bd9c - - -STRUCT_ITEM - -[table] -STRUCT_ITEM_ID - -INTEGER NOT NULL - -auto-incremented -STRUCT_REF - -INTEGER -FIELD_IDENTIFIER - -INTEGER -NAME - -TEXT(100) -IS_ARRAY - -INTEGER -IS_ENUM - -INTEGER -MIN_LENGTH - -INTEGER -MAX_LENGTH - -INTEGER -IS_WRITABLE - -INTEGER -IS_NULLABLE - -INTEGER -IS_OPTIONAL - -INTEGER -IS_FABRIC_SENSITIVE - -INTEGER -SIZE - -INTEGER -DATA_TYPE_REF - -INTEGER NOT NULL - + +STRUCT_ITEM + +[table] +STRUCT_ITEM_ID + +INTEGER NOT NULL + +auto-incremented +STRUCT_REF + +INTEGER +FIELD_IDENTIFIER + +INTEGER +NAME + +TEXT(100) +IS_ARRAY + +INTEGER +IS_ENUM + +INTEGER +MIN_LENGTH + +INTEGER +MAX_LENGTH + +INTEGER +IS_WRITABLE + +INTEGER +IS_NULLABLE + +INTEGER +IS_OPTIONAL + +INTEGER +IS_FABRIC_SENSITIVE + +INTEGER +SIZE + +INTEGER +DATA_TYPE_REF + +INTEGER NOT NULL + struct_item_d6e4bd9c:w->data_type_9233070e:e - - - - - - - + + + + +SCHCRWLR_923292AF_D6E4493D - + struct_item_d6e4bd9c:w->struct_9268f434:e - - - - - - - + + + + +SCHCRWLR_92687FD5_D6E4493D - + device_type_2620a7e2:w->package_fab13485:e - - - - - - - - - - -endpoint_type_9857dc03:w->device_type_2620a7e2:e - - - - - - - - - - -session_a11c82d5 - - -SESSION - -[table] -SESSION_ID - -INTEGER - -auto-incremented -USER_REF - -INTEGER -SESSION_KEY - -TEXT -CREATION_TIME - -INTEGER -DIRTY - -INTEGER - + + + + +SCHCRWLR_FAB0C026_26203383 - - -endpoint_type_9857dc03:w->session_a11c82d5:e - - - - - - - + + +endpoint_type_device_e685fbb0 + +ENDPOINT_TYPE_DEVICE + +[table] +ENDPOINT_TYPE_DEVICE_ID + +INTEGER + +auto-incremented +DEVICE_TYPE_REF + +INTEGER +ENDPOINT_TYPE_REF + +INTEGER +DEVICE_TYPE_ORDER + +INTEGER +DEVICE_IDENTIFIER + +INTEGER +DEVICE_VERSION + +INTEGER + + + + +endpoint_type_device_e685fbb0:w->device_type_2620a7e2:e + + + + +SCHCRWLR_26203383_E6858751 + + + +endpoint_type_device_e685fbb0:w->endpoint_type_9857dc03:e + + + + +SCHCRWLR_985767A4_E6858751 - + discriminator_4931d2db:w->package_fab13485:e - - - - - - - + + + + +SCHCRWLR_FAB0C026_49315E7C domain_78873d23 - - -DOMAIN - -[table] -DOMAIN_ID - -INTEGER - -auto-incremented -PACKAGE_REF - -INTEGER -NAME - -TEXT -LATEST_SPEC_REF - -INTEGER - + +DOMAIN + +[table] +DOMAIN_ID + +INTEGER + +auto-incremented +PACKAGE_REF + +INTEGER +NAME + +TEXT +LATEST_SPEC_REF + +INTEGER + - + domain_78873d23:w->package_fab13485:e - - - - - - - + + + + +SCHCRWLR_FAB0C026_7886C8C4 - + domain_78873d23:w->spec_27641a:e - - - - - - - + + + + +SCHCRWLR_0026EFBB_7886C8C4 endpoint_966d81f4 - - -ENDPOINT - -[table] -ENDPOINT_ID - -INTEGER - -auto-incremented -SESSION_REF - -INTEGER -ENDPOINT_TYPE_REF - -INTEGER -PROFILE - -INTEGER -ENDPOINT_IDENTIFIER - -INTEGER -NETWORK_IDENTIFIER - -INTEGER -DEVICE_IDENTIFIER - -INTEGER -DEVICE_VERSION - -INTEGER - + +ENDPOINT + +[table] +ENDPOINT_ID + +INTEGER + +auto-incremented +SESSION_REF + +INTEGER +ENDPOINT_TYPE_REF + +INTEGER +PROFILE + +INTEGER +ENDPOINT_IDENTIFIER + +INTEGER +NETWORK_IDENTIFIER + +INTEGER + endpoint_966d81f4:w->endpoint_type_9857dc03:e - - - - - - - + + + + +SCHCRWLR_985767A4_966D0D95 + + + +session_a11c82d5 + +SESSION + +[table] +SESSION_ID + +INTEGER + +auto-incremented +USER_REF + +INTEGER +SESSION_KEY + +TEXT +CREATION_TIME + +INTEGER +DIRTY + +INTEGER + - + endpoint_966d81f4:w->session_a11c82d5:e - - - - - - - + + + + +SCHCRWLR_A11C0E76_966D0D95 + + + +endpoint_type_9857dc03:w->session_a11c82d5:e + + + + +SCHCRWLR_A11C0E76_985767A4 - + endpoint_type_event_e67d6e7e - - -ENDPOINT_TYPE_EVENT - -[table] -ENDPOINT_TYPE_EVENT_ID - -INTEGER - -auto-incremented -ENDPOINT_TYPE_REF - -INTEGER -ENDPOINT_TYPE_CLUSTER_REF - -INTEGER -EVENT_REF - -INTEGER -INCLUDED - -INTEGER - + +ENDPOINT_TYPE_EVENT + +[table] +ENDPOINT_TYPE_EVENT_ID + +INTEGER + +auto-incremented +ENDPOINT_TYPE_REF + +INTEGER +ENDPOINT_TYPE_CLUSTER_REF + +INTEGER +EVENT_REF + +INTEGER +INCLUDED + +INTEGER + - + endpoint_type_event_e67d6e7e:w->endpoint_type_cluster_c12e3c9e:e - - - - - - - + + + + +SCHCRWLR_C12DC83F_E67CFA1F endpoint_type_event_e67d6e7e:w->event_3f4eed9:e - - - - - - - + + + + +SCHCRWLR_03F47A7A_E67CFA1F - + endpoint_type_event_e67d6e7e:w->endpoint_type_9857dc03:e - - - - - - - + + + + +SCHCRWLR_985767A4_E67CFA1F - + enum_item_b6420bf0 - - -ENUM_ITEM - -[table] -ENUM_ITEM_ID - -INTEGER NOT NULL - -auto-incremented -ENUM_REF - -INTEGER -NAME - -TEXT -DESCRIPTION - -TEXT -FIELD_IDENTIFIER - -INTEGER -"VALUE" - -INTEGER - + +ENUM_ITEM + +[table] +ENUM_ITEM_ID + +INTEGER NOT NULL + +auto-incremented +ENUM_REF + +INTEGER +NAME + +TEXT +DESCRIPTION + +TEXT +FIELD_IDENTIFIER + +INTEGER +"VALUE" + +INTEGER + - + enum_item_b6420bf0:w->enum_210160:e - - - - - - - + + + + +SCHCRWLR_00208D01_B6419791 - + event_field_d102b734 - - -EVENT_FIELD - -[table] -EVENT_REF - -INTEGER -FIELD_IDENTIFIER - -INTEGER -NAME - -TEXT -TYPE - -TEXT -IS_ARRAY - -INTEGER -IS_NULLABLE - -INTEGER -IS_OPTIONAL - -INTEGER -INTRODUCED_IN_REF - -INTEGER -REMOVED_IN_REF - -INTEGER - + +EVENT_FIELD + +[table] +EVENT_REF + +INTEGER +FIELD_IDENTIFIER + +INTEGER +NAME + +TEXT +TYPE + +TEXT +IS_ARRAY + +INTEGER +IS_NULLABLE + +INTEGER +IS_OPTIONAL + +INTEGER +INTRODUCED_IN_REF + +INTEGER +REMOVED_IN_REF + +INTEGER + - + event_field_d102b734:w->event_3f4eed9:e - - - - - - - + + + + +SCHCRWLR_03F47A7A_D10242D5 - + event_field_d102b734:w->spec_27641a:e - - - - - - - + + + + +SCHCRWLR_0026EFBB_D10242D5 - + event_field_d102b734:w->spec_27641a:e - - - - - - - + + + + +SCHCRWLR_0026EFBB_D10242D5 - + global_attribute_bit_e934f16d - - -GLOBAL_ATTRIBUTE_BIT - -[table] -GLOBAL_ATTRIBUTE_DEFAULT_REF - -INTEGER NOT NULL -BIT - -INTEGER NOT NULL -"VALUE" - -INTEGER -TAG_REF - -INTEGER NOT NULL - + +GLOBAL_ATTRIBUTE_BIT + +[table] +GLOBAL_ATTRIBUTE_DEFAULT_REF + +INTEGER NOT NULL +BIT + +INTEGER NOT NULL +"VALUE" + +INTEGER +TAG_REF + +INTEGER NOT NULL + - + global_attribute_bit_e934f16d:w->global_attribute_default_73c65a21:e - - - - - - - + + + + +SCHCRWLR_73C5E5C2_E9347D0E - + global_attribute_bit_e934f16d:w->tag_1b7d9:e - - - - - - - + + + + +SCHCRWLR_0001437A_E9347D0E - + operation_93359a6:w->package_fab13485:e - - - - - - - + + + + +SCHCRWLR_FAB0C026_0932E547 - + package_fab13485:w->package_fab13485:e - - - - - - - + + + + +SCHCRWLR_FAB0C026_FAB0C026 - + package_extension_2789e3a5 - - -PACKAGE_EXTENSION - -[table] -PACKAGE_EXTENSION_ID - -INTEGER - -auto-incremented -PACKAGE_REF - -INTEGER -ENTITY - -TEXT -PROPERTY - -TEXT -TYPE - -TEXT -CONFIGURABILITY - -TEXT -LABEL - -TEXT -GLOBAL_DEFAULT - -TEXT - + +PACKAGE_EXTENSION + +[table] +PACKAGE_EXTENSION_ID + +INTEGER + +auto-incremented +PACKAGE_REF + +INTEGER +ENTITY + +TEXT +PROPERTY + +TEXT +TYPE + +TEXT +CONFIGURABILITY + +TEXT +LABEL + +TEXT +GLOBAL_DEFAULT + +TEXT + - + package_extension_2789e3a5:w->package_fab13485:e - - - - - - - + + + + +SCHCRWLR_FAB0C026_27896F46 - + package_option_1931d70d - - -PACKAGE_OPTION - -[table] -OPTION_ID - -INTEGER - -auto-incremented -PACKAGE_REF - -INTEGER -OPTION_CATEGORY - -TEXT -OPTION_CODE - -TEXT -OPTION_LABEL - -TEXT - + +PACKAGE_OPTION + +[table] +OPTION_ID + +INTEGER + +auto-incremented +PACKAGE_REF + +INTEGER +OPTION_CATEGORY + +TEXT +OPTION_CODE + +TEXT +OPTION_LABEL + +TEXT + - + package_option_1931d70d:w->package_fab13485:e - - - - - - - - - - -role_26ecd5:w->package_fab13485:e - - - - - - - - - - -spec_27641a:w->package_fab13485:e - - - - - - - + + + + +SCHCRWLR_FAB0C026_193162AE - + package_option_default_64a251ef - - -PACKAGE_OPTION_DEFAULT - -[table] -OPTION_DEFAULT_ID - -INTEGER - -auto-incremented -PACKAGE_REF - -INTEGER -OPTION_CATEGORY - -TEXT -OPTION_REF - -INTEGER - + +PACKAGE_OPTION_DEFAULT + +[table] +OPTION_DEFAULT_ID + +INTEGER + +auto-incremented +PACKAGE_REF + +INTEGER +OPTION_CATEGORY + +TEXT +OPTION_REF + +INTEGER + - + package_option_default_64a251ef:w->package_fab13485:e - - - - - - - + + + + +SCHCRWLR_FAB0C026_64A1DD90 - + package_option_default_64a251ef:w->package_option_1931d70d:e - - - - - - - + + + + +SCHCRWLR_193162AE_64A1DD90 + + + +role_26ecd5:w->package_fab13485:e + + + + +SCHCRWLR_FAB0C026_00267876 session_package_61fa13bc - - -SESSION_PACKAGE - -[table] -SESSION_REF - -INTEGER -PACKAGE_REF - -INTEGER -REQUIRED - -INTEGER -ENABLED - -INTEGER - + +SESSION_PACKAGE + +[table] +SESSION_REF + +INTEGER +PACKAGE_REF + +INTEGER +REQUIRED + +INTEGER +ENABLED + +INTEGER + - + session_package_61fa13bc:w->package_fab13485:e - - - - - - - + + + + +SCHCRWLR_FAB0C026_61F99F5D - + session_package_61fa13bc:w->session_a11c82d5:e - - - - - - - + + + + +SCHCRWLR_A11C0E76_61F99F5D + + + +spec_27641a:w->package_fab13485:e + + + + +SCHCRWLR_FAB0C026_0026EFBB - + package_extension_default_d8d04687 - - -PACKAGE_EXTENSION_DEFAULT - -[table] -PACKAGE_EXTENSION_REF - -INTEGER -ENTITY_CODE - -INTEGER -ENTITY_QUALIFIER - -TEXT -PARENT_CODE - -INTEGER -MANUFACTURER_CODE - -INTEGER -"VALUE" - -TEXT - + +PACKAGE_EXTENSION_DEFAULT + +[table] +PACKAGE_EXTENSION_REF + +INTEGER +ENTITY_CODE + +INTEGER +ENTITY_QUALIFIER + +TEXT +PARENT_CODE + +INTEGER +MANUFACTURER_CODE + +INTEGER +"VALUE" + +TEXT + - + package_extension_default_d8d04687:w->package_extension_2789e3a5:e - - - - - - - + + + + +SCHCRWLR_27896F46_D8CFD228 - + package_extension_value_8e65d377 - - -PACKAGE_EXTENSION_VALUE - -[table] -PACKAGE_EXTENSION_VALUE_ID - -INTEGER - -auto-incremented -PACKAGE_EXTENSION_REF - -INTEGER -SESSION_REF - -INTEGER -ENTITY_CODE - -INTEGER -PARENT_CODE - -INTEGER -"VALUE" - -TEXT - + +PACKAGE_EXTENSION_VALUE + +[table] +PACKAGE_EXTENSION_VALUE_ID + +INTEGER + +auto-incremented +PACKAGE_EXTENSION_REF + +INTEGER +SESSION_REF + +INTEGER +ENTITY_CODE + +INTEGER +PARENT_CODE + +INTEGER +"VALUE" + +TEXT + - + package_extension_value_8e65d377:w->package_extension_2789e3a5:e - - - - - - - + + + + +SCHCRWLR_27896F46_8E655F18 - + package_extension_value_8e65d377:w->session_a11c82d5:e - - - - - - - + + + + +SCHCRWLR_A11C0E76_8E655F18 - + user_28582a - - -"USER" - -[table] -USER_ID - -INTEGER - -auto-incremented -USER_KEY - -TEXT -CREATION_TIME - -INTEGER - + +"USER" + +[table] +USER_ID + +INTEGER + +auto-incremented +USER_KEY + +TEXT +CREATION_TIME + +INTEGER + - + session_a11c82d5:w->user_28582a:e - - - - - - - + + + + +SCHCRWLR_3ED95AD5_A11C0E76 - + session_key_value_334d9527 - - -SESSION_KEY_VALUE - -[table] -SESSION_REF - -INTEGER -KEY - -TEXT -"VALUE" - -TEXT - + +SESSION_KEY_VALUE + +[table] +SESSION_REF + +INTEGER +KEY + +TEXT +"VALUE" + +TEXT + - + session_key_value_334d9527:w->session_a11c82d5:e - - - - - - - + + + + +SCHCRWLR_A11C0E76_334D20C8 - + session_log_7f10ae3a - - -SESSION_LOG - -[table] -SESSION_REF - -INTEGER -"TIMESTAMP" - -TEXT -LOG - -TEXT - + +SESSION_LOG + +[table] +SESSION_REF + +INTEGER +"TIMESTAMP" + +TEXT +LOG + +TEXT + - + session_log_7f10ae3a:w->session_a11c82d5:e - - - - - - - + + + + +SCHCRWLR_A11C0E76_7F1039DB + + + +session_notice_84addd20 + +SESSION_NOTICE + +[table] +SESSION_REF + +INTEGER +NOTICE_TYPE + +TEXT +NOTICE_MESSAGE + +TEXT +NOTICE_SEVERITY + +INTEGER +NOTICE_ORDER + +INTEGER + +auto-incremented +DISPLAY + +INTEGER + + + + +session_notice_84addd20:w->session_a11c82d5:e + + + + +SCHCRWLR_A11C0E76_84AD68C1 - + setting_a12b0e8f - - -SETTING - -[table] -CATEGORY - -TEXT -KEY - -TEXT -"VALUE" - -TEXT - + +SETTING + +[table] +CATEGORY + +TEXT +KEY + +TEXT +"VALUE" + +TEXT + diff --git a/src-electron/db/query-config.js b/src-electron/db/query-config.js index 835e31338a..51651d5288 100644 --- a/src-electron/db/query-config.js +++ b/src-electron/db/query-config.js @@ -525,11 +525,19 @@ async function insertEndpointType( sessionId, name, deviceTypeRef, + deviceTypeIdentifier, + deviceTypeVersion, doTransaction = true ) { let deviceTypeRefs = Array.isArray(deviceTypeRef) ? deviceTypeRef : [deviceTypeRef] + let deviceTypeIdentifiers = Array.isArray(deviceTypeIdentifier) + ? deviceTypeIdentifier + : [deviceTypeIdentifier] + let deviceTypeVersions = Array.isArray(deviceTypeVersion) + ? deviceTypeVersion + : [deviceTypeVersion] // Insert endpoint type let newEndpointTypeId = await dbApi.dbInsert( db, @@ -540,14 +548,20 @@ async function insertEndpointType( // Creating endpoint type and device type ref combinations along with order of insertion let newEndpointTypeIdDeviceCombination = [] for (let i = 0; i < deviceTypeRefs.length; i++) { - let endpointTypeDevice = [newEndpointTypeId, deviceTypeRefs[i], i] + let endpointTypeDevice = [ + newEndpointTypeId, + deviceTypeRefs[i], + deviceTypeIdentifiers[i], + deviceTypeVersions[i], + i, + ] newEndpointTypeIdDeviceCombination.push(endpointTypeDevice) } // Insert into endpoint_type_device await dbApi.dbMultiInsert( db, - 'INSERT INTO ENDPOINT_TYPE_DEVICE (ENDPOINT_TYPE_REF, DEVICE_TYPE_REF, DEVICE_TYPE_ORDER) VALUES (?, ?, ?)', + 'INSERT INTO ENDPOINT_TYPE_DEVICE (ENDPOINT_TYPE_REF, DEVICE_TYPE_REF, DEVICE_IDENTIFIER, DEVICE_VERSION, DEVICE_TYPE_ORDER) VALUES (?, ?, ?, ?, ?)', newEndpointTypeIdDeviceCombination ) @@ -578,7 +592,11 @@ async function duplicateEndpointType(db, endpointTypeId) { db, ` SELECT - ENDPOINT_TYPE.SESSION_REF, ENDPOINT_TYPE.NAME, ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF + ENDPOINT_TYPE.SESSION_REF, + ENDPOINT_TYPE.NAME, + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF, + ENDPOINT_TYPE_DEVICE.DEVICE_IDENTIFIER, + ENDPOINT_TYPE_DEVICE.DEVICE_VERSION FROM ENDPOINT_TYPE INNER JOIN @@ -607,6 +625,8 @@ async function duplicateEndpointType(db, endpointTypeId) { endpointTypeDeviceInfoValues.push([ newEndpointTypeId, dt.DEVICE_TYPE_REF, + dt.DEVICE_IDENTIFIER, + dt.DEVICE_VERSION, index, ]) ) @@ -614,9 +634,9 @@ async function duplicateEndpointType(db, endpointTypeId) { db, ` INSERT INTO - ENDPOINT_TYPE_DEVICE (ENDPOINT_TYPE_REF, DEVICE_TYPE_REF, DEVICE_TYPE_ORDER) + ENDPOINT_TYPE_DEVICE (ENDPOINT_TYPE_REF, DEVICE_TYPE_REF, DEVICE_IDENTIFIER, DEVICE_VERSION, DEVICE_TYPE_ORDER) VALUES - (?, ?, ?)`, + (?, ?, ?, ?, ?)`, endpointTypeDeviceInfoValues ) } diff --git a/src-electron/db/query-endpoint-type.js b/src-electron/db/query-endpoint-type.js index db67700021..76f76850a0 100644 --- a/src-electron/db/query-endpoint-type.js +++ b/src-electron/db/query-endpoint-type.js @@ -366,7 +366,7 @@ SELECT * FROM ( 0 END ) OVER (PARTITION BY ENDPOINT.ENDPOINT_IDENTIFIER) ATTRIBUTES_SIZE, - ENDPOINT_TYPE.ENDPOINT_TYPE_ID AS ENDPOINT_TYPE_ID, + ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF AS ENDPOINT_TYPE_ID, ENDPOINT.ENDPOINT_IDENTIFIER AS ENDPOINT_IDENTIFIER, SUM(CASE WHEN @@ -400,8 +400,8 @@ SELECT * FROM ( END ) OVER () ALL_ATTRIBUTES_SIZE_ACROSS_ENDPOINTS, ENDPOINT.PROFILE AS PROFILE_ID, - ENDPOINT.DEVICE_IDENTIFIER AS DEVICE_ID, - ENDPOINT.DEVICE_VERSION AS DEVICE_VERSION, + ENDPOINT_TYPE_DEVICE.DEVICE_IDENTIFIER AS DEVICE_ID, + ENDPOINT_TYPE_DEVICE.DEVICE_VERSION AS DEVICE_VERSION, ENDPOINT.NETWORK_IDENTIFIER AS NETWORK_ID FROM ATTRIBUTE INNER JOIN ENDPOINT_TYPE_ATTRIBUTE @@ -412,12 +412,12 @@ SELECT * FROM ( ON ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID INNER JOIN ATOMIC ON ATOMIC.NAME = ATTRIBUTE.TYPE - INNER JOIN ENDPOINT_TYPE - ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_REF + INNER JOIN ENDPOINT_TYPE_DEVICE + ON ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_REF INNER JOIN ENDPOINT - ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT.ENDPOINT_TYPE_REF + ON ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF = ENDPOINT.ENDPOINT_TYPE_REF WHERE ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF IN (${endpointClusterIds}) AND ENDPOINT_TYPE_CLUSTER.ENABLED=1 - AND ENDPOINT_TYPE_ATTRIBUTE.INCLUDED = 1 AND ENDPOINT_TYPE_CLUSTER.SIDE=ATTRIBUTE.SIDE + AND ENDPOINT_TYPE_ATTRIBUTE.INCLUDED = 1 AND ENDPOINT_TYPE_CLUSTER.SIDE=ATTRIBUTE.SIDE AND ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_ORDER = 0 GROUP BY ENDPOINT.ENDPOINT_IDENTIFIER, CLUSTER.MANUFACTURER_CODE, CLUSTER.NAME, ENDPOINT_TYPE_CLUSTER.SIDE, ATTRIBUTE.NAME) WHERE ENDPOINT_INDEX=1 ORDER BY ENDPOINT_IDENTIFIER ` ) diff --git a/src-electron/db/query-endpoint.js b/src-electron/db/query-endpoint.js index 3b95e00047..19440a622f 100644 --- a/src-electron/db/query-endpoint.js +++ b/src-electron/db/query-endpoint.js @@ -36,16 +36,21 @@ async function selectAllEndpoints(db, sessionId) { db, ` SELECT - ENDPOINT_ID, - SESSION_REF, - ENDPOINT_TYPE_REF, - PROFILE, - ENDPOINT_IDENTIFIER, - NETWORK_IDENTIFIER, - DEVICE_VERSION, - DEVICE_IDENTIFIER -FROM ENDPOINT -WHERE SESSION_REF = ? + ENDPOINT.ENDPOINT_ID, + ENDPOINT.SESSION_REF, + ENDPOINT.ENDPOINT_TYPE_REF, + ENDPOINT.PROFILE, + ENDPOINT.ENDPOINT_IDENTIFIER, + ENDPOINT.NETWORK_IDENTIFIER, + ENDPOINT_TYPE_DEVICE.DEVICE_VERSION, + ENDPOINT_TYPE_DEVICE.DEVICE_IDENTIFIER +FROM + ENDPOINT +LEFT JOIN + ENDPOINT_TYPE_DEVICE +ON + ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF = ENDPOINT.ENDPOINT_TYPE_REF +WHERE ENDPOINT.SESSION_REF = ? ORDER BY ENDPOINT_IDENTIFIER `, [sessionId] @@ -335,7 +340,6 @@ async function insertEndpoint( endpointTypeRef, networkIdentifier, profileIdentifier, - endpointVersion, deviceIdentifier ) { let primaryDeviceIdentifierForEndpoint = Array.isArray(deviceIdentifier) @@ -350,17 +354,13 @@ INTO ENDPOINT ( ENDPOINT_IDENTIFIER, ENDPOINT_TYPE_REF, NETWORK_IDENTIFIER, - DEVICE_VERSION, - DEVICE_IDENTIFIER, PROFILE -) VALUES ( ?, ?, ?, ?, ?, ?, ?)`, +) VALUES ( ?, ?, ?, ?, ?)`, [ sessionId, endpointIdentifier, endpointTypeRef, networkIdentifier, - endpointVersion, - primaryDeviceIdentifierForEndpoint, profileIdentifier, ] ) @@ -377,10 +377,24 @@ async function duplicateEndpoint(db, id, endpointIdentifier, endpointTypeId) { return dbApi.dbInsert( db, ` - insert into ENDPOINT (SESSION_REF,ENDPOINT_IDENTIFIER,ENDPOINT_TYPE_REF,NETWORK_IDENTIFIER,DEVICE_VERSION,DEVICE_IDENTIFIER,PROFILE) - select SESSION_REF, ? , ? ,NETWORK_IDENTIFIER,DEVICE_VERSION,DEVICE_IDENTIFIER,PROFILE - from ENDPOINT - where ENDPOINT_ID = ?`, + INSERT INTO + ENDPOINT ( + SESSION_REF, + ENDPOINT_IDENTIFIER, + ENDPOINT_TYPE_REF, + NETWORK_IDENTIFIER, + PROFILE + ) + SELECT + SESSION_REF, + ?, + ?, + NETWORK_IDENTIFIER, + PROFILE + FROM + ENDPOINT + WHERE + ENDPOINT_ID = ?`, [endpointIdentifier, endpointTypeId, id] ) } @@ -399,16 +413,20 @@ async function selectEndpoint(db, endpointId) { db, ` SELECT - ENDPOINT_ID, - SESSION_REF, - ENDPOINT_IDENTIFIER, - ENDPOINT_TYPE_REF, - PROFILE, - NETWORK_IDENTIFIER, - DEVICE_VERSION, - DEVICE_IDENTIFIER + ENDPOINT.ENDPOINT_ID, + ENDPOINT.SESSION_REF, + ENDPOINT.ENDPOINT_IDENTIFIER, + ENDPOINT.ENDPOINT_TYPE_REF, + ENDPOINT.PROFILE, + ENDPOINT.NETWORK_IDENTIFIER, + ENDPOINT_TYPE_DEVICE.DEVICE_VERSION, + ENDPOINT_TYPE_DEVICE.DEVICE_IDENTIFIER FROM ENDPOINT +LEFT JOIN + ENDPOINT_TYPE_DEVICE +ON + ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF = ENDPOINT.ENDPOINT_TYPE_REF WHERE ENDPOINT_ID = ?`, [endpointId] diff --git a/src-electron/db/zap-schema.sql b/src-electron/db/zap-schema.sql index ed47185de0..79b92e3f0c 100644 --- a/src-electron/db/zap-schema.sql +++ b/src-electron/db/zap-schema.sql @@ -728,6 +728,8 @@ CREATE TABLE IF NOT EXISTS "ENDPOINT_TYPE_DEVICE" ( "DEVICE_TYPE_REF" INTEGER, "ENDPOINT_TYPE_REF" INTEGER, "DEVICE_TYPE_ORDER" INTEGER, + "DEVICE_IDENTIFIER" INTEGER, + "DEVICE_VERSION" INTEGER, foreign key(DEVICE_TYPE_REF) references DEVICE_TYPE(DEVICE_TYPE_ID) on delete cascade, foreign key (ENDPOINT_TYPE_REF) references ENDPOINT_TYPE(ENDPOINT_TYPE_ID) on delete set NULL, @@ -745,8 +747,6 @@ CREATE TABLE IF NOT EXISTS "ENDPOINT" ( "PROFILE" integer, "ENDPOINT_IDENTIFIER" integer, "NETWORK_IDENTIFIER" integer, - "DEVICE_IDENTIFIER" integer, - "DEVICE_VERSION" integer, foreign key (SESSION_REF) references SESSION(SESSION_ID) on delete cascade, foreign key (ENDPOINT_TYPE_REF) references ENDPOINT_TYPE(ENDPOINT_TYPE_ID) on delete set NULL diff --git a/src-electron/rest/endpoint.js b/src-electron/rest/endpoint.js index 8445e0c10f..16b3bbbee8 100644 --- a/src-electron/rest/endpoint.js +++ b/src-electron/rest/endpoint.js @@ -70,14 +70,8 @@ function httpDeleteEndpointType(db) { */ function httpPostEndpoint(db) { return async (request, response) => { - let { - endpointId, - networkId, - profileId, - endpointType, - endpointVersion, - deviceIdentifier, - } = request.body + let { endpointId, networkId, profileId, endpointType, deviceIdentifier } = + request.body let sessionId = request.zapSessionId let newId = await queryEndpoint.insertEndpoint( db, @@ -86,7 +80,6 @@ function httpPostEndpoint(db) { endpointType, networkId, profileId, - endpointVersion, deviceIdentifier ) try { @@ -99,7 +92,6 @@ function httpPostEndpoint(db) { networkId: networkId, deviceId: deviceIdentifier, profileId: profileId, - endpointVersion: endpointVersion, validationIssues: validationData, }) } catch (err) { @@ -144,20 +136,24 @@ function httpPatchEndpoint(db) { */ function httpPostEndpointType(db) { return async (request, response) => { - let { name, deviceTypeRef } = request.body + let { name, deviceTypeRef, deviceIdentifier, deviceVersion } = request.body let sessionId = request.zapSessionId try { let newId = await queryConfig.insertEndpointType( db, sessionId, name, - deviceTypeRef + deviceTypeRef, + deviceIdentifier, + deviceVersion ) response.status(StatusCodes.OK).json({ id: newId, name: name, deviceTypeRef: deviceTypeRef, + deviceTypeIdentifier: deviceVersion, + deviceTypeVersion: deviceVersion, }) } catch (err) { response.status(StatusCodes.INTERNAL_SERVER_ERROR).json(err) diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index 056056a41c..5cf7aa1e03 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -399,13 +399,19 @@ export default { }, newEpt() { const deviceTypeRef = [] + const deviceIdentifier = [] + const deviceVersion = [] this.deviceTypeTmp.forEach((dt) => { deviceTypeRef.push(dt.deviceTypeRef) + deviceIdentifier.push(dt.deviceIdentifier) + deviceVersion.push(dt.deviceVersion) }) this.$store .dispatch(`zap/addEndpointType`, { name: 'Anonymous Endpoint Type', deviceTypeRef, + deviceIdentifier, + deviceVersion, }) .then((response) => { const deviceIdentifier = [] diff --git a/src/store/zap/actions.js b/src/store/zap/actions.js index dc05e654aa..1d9552eca6 100644 --- a/src/store/zap/actions.js +++ b/src/store/zap/actions.js @@ -322,7 +322,6 @@ export function addEndpoint(context, newEndpointContext) { networkId: arg.networkId, profileId: arg.profileId, deviceIdentifier: arg.deviceId, // TODO this should be array too - endpointVersion: arg.endpointVersion, endpointIdValidationIssues: arg.validationIssues.endpointId, networkIdValidationIssues: arg.validationIssues.networkId, }) @@ -339,6 +338,8 @@ export function addEndpointType(context, endpointTypeData) { id: res.data.id, name: res.data.name, deviceTypeRef: res.data.deviceTypeRef, + deviceIdentifier: res.data.deviceIdentifier, + deviceVersion: res.data.deviceVersion, }) return res.data }) diff --git a/src/store/zap/mutations.js b/src/store/zap/mutations.js index 68e57a7983..b72cc62a00 100644 --- a/src/store/zap/mutations.js +++ b/src/store/zap/mutations.js @@ -223,7 +223,9 @@ export function addEndpointType(state, endpointType) { vue3Set( state.endpointTypeView.deviceTypeRef, endpointType.id, - endpointType.deviceTypeRef + endpointType.deviceTypeRef, + endpointType.deviceIdentifier, + endpointType.deviceVersion ) } diff --git a/src/tutorials/ZclTour.vue b/src/tutorials/ZclTour.vue index 28ebd28702..0aaf66e901 100644 --- a/src/tutorials/ZclTour.vue +++ b/src/tutorials/ZclTour.vue @@ -72,7 +72,11 @@ export default { return dt[a].description.localeCompare(dt[b].description) }) return keys.map((item) => { - return { deviceTypeRef: item, deviceIdentifier: dt[item].code } + return { + deviceTypeRef: item, + deviceIdentifier: dt[item].code, + deviceVersion: dt[item].version, + } }) }, }, @@ -88,6 +92,8 @@ export default { .dispatch(`zap/addEndpointType`, { name: 'Anonymous Endpoint Type', deviceTypeRef: this.zclDeviceTypeOptions[0].deviceTypeRef, + deviceIdentifier: this.zclDeviceTypeOptions[0].deviceIdentifier, + deviceVersion: this.zclDeviceTypeOptions[0].deviceVersion, }) .then((response) => { let profileId = this.asHex( From f72c4afbf3e844ae0959b79629453ac81cb35378 Mon Sep 17 00:00:00 2001 From: Gergely Kiss Date: Wed, 14 Jun 2023 18:15:35 +0200 Subject: [PATCH 32/40] Add multi version option to endpoint card --- src/components/ZclCreateModifyEndpoint.vue | 74 +++++++++++++++++++--- src/components/ZclEndpointCard.vue | 6 +- 2 files changed, 68 insertions(+), 12 deletions(-) diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index 5cf7aa1e03..6c20b68af6 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -15,9 +15,9 @@ limitations under the License. -->
    - + -
    +
    {{ this.endpointReference ? 'Edit Endpoint' : 'Create New Endpoint' }}
    @@ -26,7 +26,7 @@ limitations under the License. type="number" v-model="shownEndpoint.endpointIdentifier" ref="endpoint" - filled + outlined class="col v-step-1" :rules="[reqInteger, reqPosInt, reqUniqueEndpoint]" min="0" @@ -37,7 +37,6 @@ limitations under the License. v-model="computedProfileId" ref="profile" outlined - filled class="col" :rules="[reqInteger, reqPosInt]" @update:model-value="setProfileId" @@ -45,7 +44,7 @@ limitations under the License. + + + + + Device + Version + + + + + + + + + +
    - !(v >= 0))) && profile ) { this.$emit('saveOrCreateValidated') @@ -389,6 +438,11 @@ export default { reqPosInt(value) { return parseInt(value) >= 0 || '* Positive integer required' }, + nonnegativeIntegersOnlyInput(e) { + if (e.data != null && !(parseInt(e.data) >= 0)) { + e.preventDefault() + } + }, reqUniqueEndpoint(value) { return ( _.isNil(_.findKey(this.endpointId, (a) => a == value)) || diff --git a/src/components/ZclEndpointCard.vue b/src/components/ZclEndpointCard.vue index 7ece313de9..1f41934bf4 100644 --- a/src/components/ZclEndpointCard.vue +++ b/src/components/ZclEndpointCard.vue @@ -96,7 +96,9 @@ limitations under the License. style="list-style-type: none" > {{ - `${dev.description} (${asHex(dev.code, 4)})` + `${dev.description} (${asHex(dev.code, 4)}) v${ + endpointVersion[endpointReference] + }` }}
    @@ -143,7 +145,7 @@ limitations under the License. {{ asHex(profileId[endpointReference], 4) }}
    - +
    Version
    From 93a06035128dea10c81d3cf0a3ef7b7eaba81059 Mon Sep 17 00:00:00 2001 From: Gergely Kiss Date: Wed, 14 Jun 2023 18:15:35 +0200 Subject: [PATCH 33/40] Add multi version option to endpoint card --- src/components/ZclCreateModifyEndpoint.vue | 74 ++++++++++++-- src/components/ZclEndpointCard.vue | 107 ++++++++++++--------- 2 files changed, 124 insertions(+), 57 deletions(-) diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index 5cf7aa1e03..6c20b68af6 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -15,9 +15,9 @@ limitations under the License. -->