From 203522dd0e66bc460b5996a77b70adf523f38d3f Mon Sep 17 00:00:00 2001 From: Bharat Raju Date: Thu, 11 Apr 2024 09:18:55 -0400 Subject: [PATCH] Revert "Revert a reverted multi-protocol commit 61d328ca3af094cefe71a61248b60be1bede651a" (#1299) This reverts commit 61d328ca3af094cefe71a61248b60be1bede651a. Fixing Custom XML issues: - Cleaning up the custom xml UI update as well as the custom xml package uploading such that there are no duplicates - Fixing the custom xml UI for attributes, commands and events when cluster extensions are added through custom xml. Needed the custom xml package ids to be included - Fixing the duplicate attributes and commands which show up in the attribute and command UI when a custom cluster with custom attributes and commands is added. This is solved by using a set in : reduceAndConcatenateZclEntity(db, id, [...new Set([...standAlonePackageIds, clusterInfo.packageRef])], - Adding unique constraint to Attribute table and adding insert or replace to attribute insert query such that custom cluster extensions are not reloaded into the db. - Making sure the global attributes are part of the custom clusters in static-zcl.js while calling reduceAndConcatenateZclEntity - Making sure that session partition numbering is correct for the partitionNumber column - For loading custom cluster extensions such as attributes and commands. Making sure they are loaded into the database based on the top level zcl package loaded. This is needed for sdk upgrades or custom xml in multi-protocol. See changes to zcl-loader-silabs and zcl-loader - When adding custom xml, there are instances where multiple zcl packages are loaded for the same xml file. This was an issue with the mutation observer. Getting the load new package call out of the observer to fix this. Reproducer: Open zap, add custom xml from extensions, close extensions pane, add another xml from extensions and you will see two instances of the xml added. If you add another xml then you see 3 instances. This is fixed in ZclCustomZclView.vue - Making sure that the delete button appears across custom xml for removal and doing some minor UI cleanup - Add more unit tests for custom xml - Cleaning up zap toolbar UI for logos - JIRA: ZAPP-1351 --- apack.json | 2 +- docs/zap-schema.svg | 4162 +++++++------ package.json | 2 + src-electron/db/db-mapping.js | 48 + src-electron/db/query-attribute.js | 6 +- src-electron/db/query-cluster.js | 6 +- src-electron/db/query-config.js | 76 +- src-electron/db/query-device-type.js | 6 +- src-electron/db/query-endpoint-type.js | 45 +- src-electron/db/query-endpoint.js | 73 +- src-electron/db/query-impexp.js | 32 +- src-electron/db/query-loader.js | 5 +- src-electron/db/query-package-notification.js | 11 +- src-electron/db/query-package.js | 127 +- src-electron/db/query-session-zcl.js | 33 +- src-electron/db/query-session.js | 276 +- src-electron/db/query-zcl.js | 6 +- src-electron/db/zap-schema.sql | 170 +- src-electron/generator/generation-engine.js | 8 +- .../generator/helper-endpointconfig.js | 20 +- src-electron/generator/template-util.js | 132 +- src-electron/importexport/import-isc.js | 9 +- src-electron/importexport/import-json.js | 152 +- src-electron/main-process/startup.js | 33 +- src-electron/rest/endpoint.js | 10 +- src-electron/rest/initialize.js | 22 +- src-electron/rest/static-zcl.js | 71 +- src-electron/rest/user-data.js | 39 +- src-electron/util/env.js | 6 + src-electron/util/util.js | 370 +- src-electron/zcl/zcl-loader-silabs.js | 51 +- src-electron/zcl/zcl-loader.js | 12 +- src/App.vue | 8 +- src/components/ZCLToolbar.vue | 56 +- src/components/ZclClusterManager.vue | 24 +- src/components/ZclCreateModifyEndpoint.vue | 5 +- src/components/ZclCustomZclView.vue | 30 +- src/layouts/ZclConfiguratorLayout.vue | 20 +- src/pages/EndpointManager.vue | 8 +- src/pages/ZapConfig.vue | 165 +- src/store/zap/actions.js | 9 +- src/store/zap/mutations.js | 45 +- src/tutorials/ZclTour.vue | 1 + src/util/common-mixin.js | 1 + src/util/ui-options.js | 23 +- test/custom-cluster.test.js | 28 +- test/endpoint-config.test.js | 15 +- test/gen-dotdot.test.js | 9 +- test/gen-matter-4.test.js | 12 +- test/gen-test.test.js | 13 +- test/gen-zigbee-2.test.js | 21 +- test/gen-zigbee-8.test.js | 42 +- test/multi-protocol.test.js | 165 + test/notification.test.js | 23 +- test/parent-endpoint.test.js | 18 +- test/query.test.js | 63 +- test/resource/multi-protocol.zap | 5160 +++++++++++++++++ .../spec-check-all-clusters-app-matter.zap | 2 +- test/server-bare.test.js | 27 +- test/test-query.js | 12 +- test/test-util.js | 1 + test/validation.test.js | 13 +- .../matter/zcl-with-test-extensions.json | 3 +- 63 files changed, 9391 insertions(+), 2652 deletions(-) create mode 100644 test/multi-protocol.test.js create mode 100644 test/resource/multi-protocol.zap diff --git a/apack.json b/apack.json index ffe29d365a..ec97804203 100644 --- a/apack.json +++ b/apack.json @@ -4,7 +4,7 @@ "description": "Graphical configuration tool for application and libraries based on Zigbee Cluster Library.", "path": [".", "node_modules/.bin/", "ZAP.app/Contents/MacOS"], "requiredFeatureLevel": "apack.core:9", - "featureLevel": 100, + "featureLevel": 101, "uc.triggerExtension": "zap", "executable": { "zap:win32.x86_64": { diff --git a/docs/zap-schema.svg b/docs/zap-schema.svg index 2c2f454f41..095ca42336 100644 --- a/docs/zap-schema.svg +++ b/docs/zap-schema.svg @@ -1,2799 +1,2575 @@ - - - + + SchemaCrawler_Diagram - -generated by -SchemaCrawler 16.20.4 -ZAP schema, Copyright (c) 2020 Silicon Labs, released under Apache 2.0 license. - + +generated by +SchemaCrawler 16.20.6 +generated on +2024-02-06 12:14: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 -API_MATURITY - -TEXT - + +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 +API_MATURITY + +TEXT + 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 -API_MATURITY - -TEXT - + +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 +API_MATURITY + +TEXT + 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 - - - - - - - + + + + +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 - + +ENDPOINT_TYPE + +[table] +ENDPOINT_TYPE_ID + +INTEGER + +auto-incremented +SESSION_PARTITION_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 + +[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 -TYPE - -TEXT(100) - + +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 -CLASS - -TEXT -"SCOPE" - -TEXT -SUPERSET - -TEXT - + +DEVICE_TYPE + +[table] +DEVICE_TYPE_ID + +INTEGER + +auto-incremented +PACKAGE_REF + +INTEGER +DOMAIN + +TEXT +CODE + +INTEGER +PROFILE_ID + +INTEGER +NAME + +TEXT +DESCRIPTION + +TEXT +CLASS + +TEXT +"SCOPE" + +TEXT +SUPERSET + +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 - - - - - - - + + + + +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 - - - - - - - + + + + +SCHCRWLR_0026EFBB_03F47A7A tag_1b7d9 - - -TAG - -[table] -TAG_ID - -INTEGER - -auto-incremented -PACKAGE_REF - -INTEGER -CLUSTER_REF - -INTEGER -NAME - -TEXT -DESCRIPTION - -TEXT - + +TAG + +[table] +TAG_ID + +INTEGER + +auto-incremented +PACKAGE_REF + +INTEGER +CLUSTER_REF + +INTEGER +NAME + +TEXT +DESCRIPTION + +TEXT + tag_1b7d9:w->cluster_5ec71239:e - - - - - - - + + + + +SCHCRWLR_5EC69DDA_0001437A 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 + +[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 -IS_INCOMING - -INTEGER -IS_ENABLED - -INTEGER - + +ENDPOINT_TYPE_COMMAND + +[table] +ENDPOINT_TYPE_COMMAND_ID + +INTEGER + +auto-incremented +ENDPOINT_TYPE_REF + +INTEGER +ENDPOINT_TYPE_CLUSTER_REF + +INTEGER +COMMAND_REF + +INTEGER +IS_INCOMING + +INTEGER +IS_ENABLED + +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 - - - - - - - + + + + +SCHCRWLR_FAB0C026_26203383 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 + +[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 - + +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 - + +SESSION + +[table] +SESSION_ID + +INTEGER + +auto-incremented +USER_REF + +INTEGER +SESSION_KEY + +TEXT +CREATION_TIME + +INTEGER +DIRTY + +INTEGER +NEW_NOTIFICATION + +INTEGER + endpoint_966d81f4:w->session_a11c82d5:e - - - - - - - - - - -endpoint_type_9857dc03:w->session_a11c82d5:e - - - - - - - + + + + +SCHCRWLR_A11C0E76_966D0D95 + + + +session_partition_f35f84a0 + +SESSION_PARTITION + +[table] +SESSION_PARTITION_ID + +INTEGER + +auto-incremented +SESSION_PARTITION_NUMBER + +INTEGER +SESSION_REF + +INTEGER + + + + +endpoint_type_9857dc03:w->session_partition_f35f84a0:e + + + + +SCHCRWLR_F35F1041_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_notice_176ee570 - - -PACKAGE_NOTICE - -[table] -PACKAGE_REF - -INTEGER -NOTICE_TYPE - -TEXT -NOTICE_MESSAGE - -TEXT -NOTICE_SEVERITY - -INTEGER -NOTICE_ID - -INTEGER - -auto-incremented - + +PACKAGE_NOTICE + +[table] +PACKAGE_REF + +INTEGER +NOTICE_TYPE + +TEXT +NOTICE_MESSAGE + +TEXT +NOTICE_SEVERITY + +INTEGER +NOTICE_ID + +INTEGER + +auto-incremented + package_notice_176ee570:w->package_fab13485:e - - - - - - - + + + + +SCHCRWLR_FAB0C026_176E7111 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 - - - - - - - + + + + +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_PARTITION_REF + +INTEGER +PACKAGE_REF + +INTEGER +REQUIRED + +INTEGER +ENABLED + +INTEGER + session_package_61fa13bc:w->package_fab13485:e - - - - - - - - - - -session_package_61fa13bc:w->session_a11c82d5:e - - - - - - - + + + + +SCHCRWLR_FAB0C026_61F99F5D + + + +session_package_61fa13bc:w->session_partition_f35f84a0:e + + + + +SCHCRWLR_F35F1041_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_ID - -INTEGER - -auto-incremented -DISPLAY - -INTEGER -SEEN - -INTEGER - + +SESSION_NOTICE + +[table] +SESSION_REF + +INTEGER +NOTICE_TYPE + +TEXT +NOTICE_MESSAGE + +TEXT +NOTICE_SEVERITY + +INTEGER +NOTICE_ID + +INTEGER + +auto-incremented +DISPLAY + +INTEGER +SEEN + +INTEGER + - + session_notice_84addd20:w->session_a11c82d5:e - - - - - - - + + + + +SCHCRWLR_A11C0E76_84AD68C1 + + + +session_partition_f35f84a0:w->session_a11c82d5:e + + + + +SCHCRWLR_A11C0E76_F35F1041 - + setting_a12b0e8f - - -SETTING - -[table] -CATEGORY - -TEXT -KEY - -TEXT -"VALUE" - -TEXT - + +SETTING + +[table] +CATEGORY + +TEXT +KEY + +TEXT +"VALUE" + +TEXT + diff --git a/package.json b/package.json index 7865fd6806..852ecb2f0c 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "package-metadata": "node src-script/zap-package-metadata.js", "zap": "node src-script/zap-start.js --logToStdout --gen ./test/gen-template/zigbee/gen-templates.json", "zapall": "node src-script/zap-start.js --logToStdout --zcl ./test/resource/meta/zcl.json --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 --gen ./test/resource/meta/gen-test.json", + "zapmultiprotocol": "node src-script/zap-start.js --logToStdout --zcl ./zcl-builtin/silabs/zcl.json --zcl ./zcl-builtin/matter/zcl-with-test-extensions.json --gen ./test/gen-template/zigbee/gen-templates.json --gen ./test/gen-template/matter/gen-test.json", "zapzigbee": "node src-script/zap-start.js --logToStdout --zcl ./zcl-builtin/silabs/zcl.json --gen ./test/gen-template/zigbee/gen-templates.json", "zapmatter": "node src-script/zap-start.js --logToStdoutc --zcl ./zcl-builtin/matter/zcl.json --gen ./test/gen-template/matter/gen-test.json", "zapmeta": "node src-script/zap-start.js --logToStdout --zcl ./test/resource/meta/zcl.json --gen ./test/resource/meta/gen-test.json --in ./test/resource/test-meta.zap", @@ -66,6 +67,7 @@ "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", + "zapall-devserver": "node src-script/zap-start.js server --stateDirectory --zcl ./zcl-builtin/silabs/zcl.json --zcl ./zcl-builtin/matter/zcl.json --allowCors --logToStdout --gen ./test/gen-template/zigbee/gen-templates.json --gen ./test/gen-template/matter/gen-test.json --gen --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-electron/db/db-mapping.js b/src-electron/db/db-mapping.js index cf8afd228f..964c132736 100644 --- a/src-electron/db/db-mapping.js +++ b/src-electron/db/db-mapping.js @@ -384,6 +384,23 @@ exports.map = { name: x.NAME, caption: x.DESCRIPTION, class: x.CLASS, + packageRef: x.PACKAGE_REF, + } + }, + + deviceTypeExtended: (x) => { + if (x == null) return undefined + return { + id: x.DEVICE_TYPE_ID, + code: x.CODE, + profileId: x.PROFILE_ID, + domain: x.DOMAIN, + label: x.NAME, + name: x.NAME, + caption: x.DESCRIPTION, + class: x.CLASS, + packageRef: x.PACKAGE_REF, + category: x.CATEGORY, } }, @@ -452,6 +469,25 @@ exports.map = { parentEndpointIdentifier: x.PARENT_ENDPOINT_IDENTIFIER, } }, + endpointExtended: (x) => { + if (x == null) return undefined + return { + id: x.ENDPOINT_ID, + endpointRef: x.ENDPOINT_ID, + sessionRef: x.SESSION_REF, + endpointIdentifier: x.ENDPOINT_IDENTIFIER, + endpointId: x.ENDPOINT_IDENTIFIER, + endpointTypeRef: x.ENDPOINT_TYPE_REF, + profileId: x.PROFILE, + networkId: x.NETWORK_IDENTIFIER, + endpointVersion: x.DEVICE_VERSION, // Left for backwards compatibility + deviceVersion: x.DEVICE_VERSION, + deviceIdentifier: x.DEVICE_IDENTIFIER, + parentRef: x.PARENT_ENDPOINT_REF, + parentEndpointIdentifier: x.PARENT_ENDPOINT_IDENTIFIER, + category: x.CATEGORY, // Category of the device type coming from the zcl package it belongs to. + } + }, endpointType: (x) => { if (x == null) return undefined return { @@ -643,6 +679,8 @@ exports.map = { sessionRef: x.SESSION_REF, required: x.REQUIRED, type: x.TYPE, + sessionPartitionId: x.SESSION_PARTITION_ID, + category: x.CATEGORY, } }, sessionLog: (x) => { @@ -664,6 +702,16 @@ exports.map = { newNotification: x.NEW_NOTIFICATION == 1, } }, + + sessionPartition: (x) => { + if (x == null) return undefined + return { + sessionPartitionId: x.SESSION_PARTITION_ID, + sessionRef: x.SESSION_REF, + sessionPartitionNumber: x.SESSION_PARTITION_NUMBER, + } + }, + user: (x) => { if (x == null) return undefined return { diff --git a/src-electron/db/query-attribute.js b/src-electron/db/query-attribute.js index 79b6d39d74..eaf7fd4bb8 100644 --- a/src-electron/db/query-attribute.js +++ b/src-electron/db/query-attribute.js @@ -1102,8 +1102,12 @@ INNER JOIN CLUSTER ON ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID +INNER JOIN + SESSION_PARTITION +ON +ENDPOINT_TYPE.SESSION_PARTITION_REF = SESSION_PARTITION.SESSION_PARTITION_ID WHERE - ENDPOINT_TYPE.SESSION_REF = ${sessionId} + SESSION_PARTITION.SESSION_REF = ${sessionId} AND ENDPOINT_TYPE_CLUSTER.ENABLED=1 AND diff --git a/src-electron/db/query-cluster.js b/src-electron/db/query-cluster.js index a5a22e118e..994ea1d040 100644 --- a/src-electron/db/query-cluster.js +++ b/src-electron/db/query-cluster.js @@ -218,8 +218,12 @@ async function selectAllUserClustersWithTokenAttributes( CLUSTER ON ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID + INNER JOIN + SESSION_PARTITION + ON + ENDPOINT_TYPE.SESSION_PARTITION_REF = SESSION_PARTITION.SESSION_PARTITION_ID WHERE - ENDPOINT_TYPE.SESSION_REF = ? + SESSION_PARTITION.SESSION_REF = ? AND ENDPOINT_TYPE_CLUSTER.ENABLED=1 AND diff --git a/src-electron/db/query-config.js b/src-electron/db/query-config.js index a9942aff0b..736873ef9b 100644 --- a/src-electron/db/query-config.js +++ b/src-electron/db/query-config.js @@ -27,6 +27,7 @@ const dbEnum = require('../../src-shared/db-enum.js') const queryZcl = require('./query-zcl.js') const queryUpgrade = require('../sdk/matter.js') const queryDeviceType = require('./query-device-type') +const querySession = require('./query-session') const queryCommand = require('./query-command.js') const restApi = require('../../src-shared/rest-api.js') const _ = require('lodash') @@ -576,16 +577,18 @@ async function selectCountOfEndpointsWithGivenEndpointIdentifier( /** * Promises to add an endpoint type. * - * @export * @param {*} db - * @param {*} sessionId + * @param {*} sessionPartitionInfo * @param {*} name * @param {*} deviceTypeRef + * @param {*} deviceTypeIdentifier + * @param {*} deviceTypeVersion + * @param {*} doTransaction * @returns Promise to update endpoints. */ async function insertEndpointType( db, - sessionId, + sessionPartitionInfo, name, deviceTypeRef, deviceTypeIdentifier, @@ -604,8 +607,8 @@ async function insertEndpointType( // Insert endpoint type let newEndpointTypeId = await dbApi.dbInsert( db, - 'INSERT OR REPLACE INTO ENDPOINT_TYPE ( SESSION_REF, NAME ) VALUES ( ?, ?)', - [sessionId, name] + 'INSERT OR REPLACE INTO ENDPOINT_TYPE ( SESSION_PARTITION_REF, NAME ) VALUES ( ?, ?)', + [sessionPartitionInfo.sessionPartitionId, name] ) // Creating endpoint type and device type ref combinations along with order of insertion @@ -635,7 +638,7 @@ async function insertEndpointType( db, 'ERROR', isErrorStringPresent ? err.split('Error:')[1] : err, - sessionId, + sessionPartitionInfo.sessionRef, 1, 1 ) @@ -656,7 +659,7 @@ async function insertEndpointType( for (const dtRef of deviceTypeRefs) { await setEndpointDefaults( db, - sessionId, + sessionPartitionInfo.sessionRef, newEndpointTypeId, dtRef, doTransaction @@ -679,7 +682,8 @@ async function duplicateEndpointType(db, endpointTypeId) { db, ` SELECT - ENDPOINT_TYPE.SESSION_REF, + SESSION_PARTITION.SESSION_REF, + SESSION_PARTITION.SESSION_PARTITION_ID, ENDPOINT_TYPE.NAME, ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF, ENDPOINT_TYPE_DEVICE.DEVICE_IDENTIFIER, @@ -690,6 +694,10 @@ async function duplicateEndpointType(db, endpointTypeId) { ENDPOINT_TYPE_DEVICE ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF + INNER JOIN + SESSION_PARTITION + ON + ENDPOINT_TYPE.SESSION_PARTITION_REF = SESSION_PARTITION.SESSION_PARTITION_ID WHERE ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF = ?`, [endpointTypeId] @@ -699,9 +707,12 @@ async function duplicateEndpointType(db, endpointTypeId) { // Enter into the endpoint_type table newEndpointTypeId = await dbApi.dbInsert( db, - `INSERT INTO ENDPOINT_TYPE (SESSION_REF, NAME) + `INSERT INTO ENDPOINT_TYPE (SESSION_PARTITION_REF, NAME) VALUES (?, ?)`, - [endpointTypeDeviceInfo[0].SESSION_REF, endpointTypeDeviceInfo[0].NAME] + [ + endpointTypeDeviceInfo[0].SESSION_PARTITION_ID, + endpointTypeDeviceInfo[0].NAME, + ] ) // Enter into the endpoint_type_device table to establish the endpoint_type @@ -758,8 +769,12 @@ async function updateEndpointType(db, sessionId, endpointTypeId, changesArray) { INNER JOIN ENDPOINT_TYPE_DEVICE ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF + INNER JOIN + SESSION_PARTITION + ON + ENDPOINT_TYPE.SESSION_PARTITION_REF = SESSION_PARTITION.SESSION_PARTITION_ID WHERE - ENDPOINT_TYPE_ID = ? AND SESSION_REF = ? + ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ? AND SESSION_PARTITION.SESSION_REF = ? ORDER BY ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_ORDER`, [endpointTypeId, sessionId] @@ -873,7 +888,10 @@ async function updateEndpointType(db, sessionId, endpointTypeId, changesArray) { /** * Promise to set the default attributes and clusters for a endpoint type. * @param {*} db + * @param {*} sessionId * @param {*} endpointTypeId + * @param {*} deviceTypeRef + * @param {*} doTransaction */ async function setEndpointDefaults( db, @@ -893,7 +911,20 @@ async function setEndpointDefaults( if (pkgs == null || pkgs.length < 1) throw new Error('Could not locate package id for a given session.') + let deviceTypeInfo = + await querySession.selectDeviceTypePackageInfoFromDeviceTypeId( + db, + deviceTypeRef + ) + let endpointTypeCategory = + deviceTypeInfo.length > 0 ? deviceTypeInfo[0].category : null let packageId = pkgs[0].id + for (let i = 0; i < pkgs.length; i++) { + if (pkgs[i].category == endpointTypeCategory) { + packageId = pkgs[i].id + break + } + } let clusters = await queryDeviceType.selectDeviceTypeClustersByDeviceTypeRef( db, deviceTypeRef @@ -1216,7 +1247,16 @@ async function resolveNonOptionalAndReportableAttributes( async function selectEndpointTypeCount(db, sessionId) { let x = await dbApi.dbGet( db, - 'SELECT COUNT(ENDPOINT_TYPE_ID) AS CNT FROM ENDPOINT_TYPE WHERE SESSION_REF = ?', + `SELECT + COUNT(ENDPOINT_TYPE_ID) AS CNT + FROM + ENDPOINT_TYPE + INNER JOIN + SESSION_PARTITION + ON + SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF + WHERE + SESSION_PARTITION.SESSION_REF = ?`, [sessionId] ) return x['CNT'] @@ -1243,7 +1283,11 @@ SELECT COUNT(ENDPOINT_TYPE_ID) FROM ENDPOINT_TYPE -WHERE SESSION_REF = ? +INNER JOIN + SESSION_PARTITION +ON + SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF +WHERE SESSION_PARTITION.SESSION_REF = ? AND ENDPOINT_TYPE_ID IN (SELECT ENDPOINT_TYPE_REF FROM ENDPOINT_TYPE_CLUSTER @@ -1404,8 +1448,12 @@ JOIN ATTRIBUTE AS A ON ETA.ATTRIBUTE_REF = A.ATTRIBUTE_ID JOIN ENDPOINT_TYPE AS ET ON ETA.ENDPOINT_TYPE_REF = ET.ENDPOINT_TYPE_ID +INNER JOIN + SESSION_PARTITION +ON + ET.SESSION_PARTITION_REF = SESSION_PARTITION.SESSION_PARTITION_ID WHERE - ET.SESSION_REF = ? AND ETA.INCLUDED = 1 + SESSION_PARTITION.SESSION_REF = ? AND ETA.INCLUDED = 1 ORDER BY CLUSTER_CODE, ATTRIBUTE_CODE `, diff --git a/src-electron/db/query-device-type.js b/src-electron/db/query-device-type.js index 13c37d6ab0..4fb96a4ade 100644 --- a/src-electron/db/query-device-type.js +++ b/src-electron/db/query-device-type.js @@ -26,15 +26,15 @@ const dbMapping = require('./db-mapping') /** * Retrieves all the device types in the database. * - * @export * @param {*} db + * @param {*} packageId * @returns Promise that resolves with the rows of device types. */ async function selectAllDeviceTypes(db, packageId) { return dbApi .dbAll( db, - 'SELECT DEVICE_TYPE_ID, DOMAIN, CODE, PROFILE_ID, NAME, DESCRIPTION, CLASS FROM DEVICE_TYPE WHERE PACKAGE_REF = ? ORDER BY DOMAIN, CODE', + 'SELECT DEVICE_TYPE_ID, DOMAIN, CODE, PROFILE_ID, NAME, DESCRIPTION, CLASS, PACKAGE_REF FROM DEVICE_TYPE WHERE PACKAGE_REF = ? ORDER BY DOMAIN, CODE', [packageId] ) .then((rows) => rows.map(dbMapping.map.deviceType)) @@ -51,7 +51,7 @@ async function selectDeviceTypeById(db, id) { return dbApi .dbGet( db, - 'SELECT DEVICE_TYPE_ID, DOMAIN, CODE, PROFILE_ID, NAME, DESCRIPTION, CLASS FROM DEVICE_TYPE WHERE DEVICE_TYPE_ID = ?', + 'SELECT DEVICE_TYPE_ID, DOMAIN, CODE, PROFILE_ID, NAME, DESCRIPTION, CLASS, PACKAGE_REF FROM DEVICE_TYPE WHERE DEVICE_TYPE_ID = ?', [id] ) .then(dbMapping.map.deviceType) diff --git a/src-electron/db/query-endpoint-type.js b/src-electron/db/query-endpoint-type.js index 79ce37267a..48fd15b192 100644 --- a/src-electron/db/query-endpoint-type.js +++ b/src-electron/db/query-endpoint-type.js @@ -51,13 +51,17 @@ async function selectAllEndpointTypes(db, sessionId) { .dbAll( db, ` -SELECT - ENDPOINT_TYPE.ENDPOINT_TYPE_ID, - ENDPOINT_TYPE.NAME, - ENDPOINT_TYPE.SESSION_REF -FROM - ENDPOINT_TYPE -WHERE SESSION_REF = ? ORDER BY NAME`, + SELECT + ENDPOINT_TYPE.ENDPOINT_TYPE_ID, + ENDPOINT_TYPE.NAME, + ENDPOINT_TYPE.SESSION_PARTITION_REF + FROM + ENDPOINT_TYPE + INNER JOIN + SESSION_PARTITION + ON + ENDPOINT_TYPE.SESSION_PARTITION_REF = SESSION_PARTITION.SESSION_PARTITION_ID +WHERE SESSION_PARTITION.SESSION_REF = ? ORDER BY NAME`, [sessionId] ) .then((rows) => rows.map(dbMapping.map.endpointType)) @@ -83,8 +87,12 @@ WHERE SESSION_REF = ? ORDER BY NAME`, ENDPOINT_TYPE ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF + INNER JOIN + SESSION_PARTITION + ON + ENDPOINT_TYPE.SESSION_PARTITION_REF = SESSION_PARTITION.SESSION_PARTITION_ID WHERE - ENDPOINT_TYPE.SESSION_REF = ? + SESSION_PARTITION.SESSION_REF = ? AND ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF = ? ORDER BY DEVICE_TYPE.NAME, @@ -122,8 +130,12 @@ SELECT ENDPOINT_TYPE.ENDPOINT_TYPE_ID FROM ENDPOINT_TYPE +INNER JOIN + SESSION_PARTITION +ON + ENDPOINT_TYPE.SESSION_PARTITION_REF = SESSION_PARTITION.SESSION_PARTITION_ID WHERE - ENDPOINT_TYPE.SESSION_REF = ? + SESSION_PARTITION.SESSION_REF = ? ORDER BY ENDPOINT_TYPE.NAME`, [sessionId] ) @@ -158,8 +170,12 @@ INNER JOIN ENDPOINT ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT.ENDPOINT_TYPE_REF +INNER JOIN + SESSION_PARTITION +ON + ENDPOINT_TYPE.SESSION_PARTITION_REF = SESSION_PARTITION.SESSION_PARTITION_ID WHERE - ENDPOINT_TYPE.SESSION_REF = ? + SESSION_PARTITION.SESSION_REF = ? ORDER BY ENDPOINT_TYPE.NAME`, [sessionId] ) @@ -167,7 +183,7 @@ ORDER BY ENDPOINT_TYPE.NAME`, } /** - * Returns promise of a details of an endpoint type. + * Returns promise on the details of an endpoint type based on endpoint type id. * * @param {*} db * @param {*} id @@ -180,10 +196,14 @@ async function selectEndpointType(db, id) { ` SELECT ENDPOINT_TYPE.ENDPOINT_TYPE_ID, - ENDPOINT_TYPE.SESSION_REF, + SESSION_PARTITION.SESSION_REF, ENDPOINT_TYPE.NAME FROM ENDPOINT_TYPE + INNER JOIN + SESSION_PARTITION + ON + ENDPOINT_TYPE.SESSION_PARTITION_REF = SESSION_PARTITION.SESSION_PARTITION_ID WHERE ENDPOINT_TYPE_ID = ?`, [id] @@ -212,7 +232,6 @@ async function selectEndpointType(db, id) { DEVICE_TYPE.PROFILE_ID`, [id] ) - endpointType.deviceTypes = rows.map((row) => row.DEVICE_TYPE_ID) endpointType.deviceVersions = rows.map((row) => row.DEVICE_VERSION) endpointType.deviceIdentifiers = rows.map((row) => row.DEVICE_IDENTIFIER) diff --git a/src-electron/db/query-endpoint.js b/src-electron/db/query-endpoint.js index 234ca970be..c175b542e8 100644 --- a/src-electron/db/query-endpoint.js +++ b/src-electron/db/query-endpoint.js @@ -58,6 +58,75 @@ ORDER BY E1.ENDPOINT_IDENTIFIER return rows.map(dbMapping.map.endpoint) } +/** + * Returns a promise resolving into all endpoints based on the template + * category(eg zigbee/matter). + * + * @param {*} db + * @param {*} sessionId + * @param {*} templateCategory + * @returns Promise that resolves to endpoints. + */ +async function selectAllEndpointsBasedOnTemplateCategory( + db, + sessionId, + templateCategory +) { + let rows = await dbApi.dbAll( + db, + ` +SELECT + E1.ENDPOINT_ID, + E1.SESSION_REF, + E1.ENDPOINT_TYPE_REF, + E1.PROFILE, + E1.ENDPOINT_IDENTIFIER, + E1.NETWORK_IDENTIFIER, + PACKAGE.CATEGORY, + E2.ENDPOINT_ID AS PARENT_ENDPOINT_REF, + E2.ENDPOINT_IDENTIFIER AS PARENT_ENDPOINT_IDENTIFIER +FROM + ENDPOINT AS E1 +LEFT JOIN + ENDPOINT AS E2 +ON + E2.ENDPOINT_ID = E1.PARENT_ENDPOINT_REF +INNER JOIN + ENDPOINT_TYPE +ON + E1.ENDPOINT_TYPE_REF = ENDPOINT_TYPE.ENDPOINT_TYPE_ID +INNER JOIN + ENDPOINT_TYPE_DEVICE +ON + ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF = ENDPOINT_TYPE.ENDPOINT_TYPE_ID +INNER JOIN + DEVICE_TYPE +ON + ENDPOINT_TYPE_DEVICE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID +INNER JOIN + PACKAGE +ON + PACKAGE.PACKAGE_ID = DEVICE_TYPE.PACKAGE_REF +WHERE + E1.SESSION_REF = ? +AND + PACKAGE.CATEGORY = ? +GROUP BY + E1.ENDPOINT_IDENTIFIER +ORDER BY E1.ENDPOINT_IDENTIFIER + `, + [sessionId, templateCategory] + ) + + // if now rows are found then return all endpoints in the session. This can + // happen if an endpoint has an undefined endponit type device + if (rows.length == 0) { + return selectAllEndpoints(db, sessionId) + } else { + return rows.map(dbMapping.map.endpointExtended) + } +} + /** * Retrieves clusters on an endpoint. * @@ -90,7 +159,6 @@ ORDER BY C.CODE `, [endpointTypeId] ) - return rows.map((row) => { return { clusterId: row['CLUSTER_ID'], @@ -394,6 +462,7 @@ async function getParentEndpointIdentifier(db, parentRef, sessionId) { * @param {*} endpointTypeRef * @param {*} networkIdentifier * @param {*} profileIdentifier + * @param {*} parentRef * @returns Promise to update endpoints. */ async function insertEndpoint( @@ -513,3 +582,5 @@ exports.duplicateEndpoint = duplicateEndpoint exports.selectAllEndpoints = selectAllEndpoints exports.getParentEndpointRef = getParentEndpointRef exports.getParentEndpointIdentifier = getParentEndpointIdentifier +exports.selectAllEndpointsBasedOnTemplateCategory = + selectAllEndpointsBasedOnTemplateCategory diff --git a/src-electron/db/query-impexp.js b/src-electron/db/query-impexp.js index 8797e24e71..925f625f76 100644 --- a/src-electron/db/query-impexp.js +++ b/src-electron/db/query-impexp.js @@ -155,12 +155,16 @@ SELECT ROW_NUMBER() OVER(ORDER BY ENDPOINT.ENDPOINT_IDENTIFIER) AS ENDPOINT_TYPE_INDEX FROM ENDPOINT_TYPE +INNER JOIN + SESSION_PARTITION +ON + ENDPOINT_TYPE.SESSION_PARTITION_REF = SESSION_PARTITION.SESSION_PARTITION_ID LEFT JOIN ENDPOINT ON ENDPOINT.ENDPOINT_TYPE_REF = ENDPOINT_TYPE.ENDPOINT_TYPE_ID WHERE - ENDPOINT_TYPE.SESSION_REF = ? + SESSION_PARTITION.SESSION_REF = ? ORDER BY ENDPOINT.ENDPOINT_IDENTIFIER, ENDPOINT_TYPE.NAME`, @@ -189,8 +193,12 @@ ORDER BY ENDPOINT_TYPE ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF + INNER JOIN + SESSION_PARTITION + ON + ENDPOINT_TYPE.SESSION_PARTITION_REF = SESSION_PARTITION.SESSION_PARTITION_ID WHERE - ENDPOINT_TYPE.SESSION_REF = ? + SESSION_PARTITION.SESSION_REF = ? AND ENDPOINT_TYPE_DEVICE.ENDPOINT_TYPE_REF = ? ORDER BY DEVICE_TYPE.NAME, @@ -223,22 +231,27 @@ ORDER BY * Imports an endpoint type, resolving other data along the way. * * @param {*} db - * @param {*} sessionId + * @param {*} sessionPartitionId * @param {*} packageId * @param {*} endpointType * @returns Promise of endpoint insertion. */ -async function importEndpointType(db, sessionId, packageIds, endpointType) { +async function importEndpointType( + db, + sessionPartitionId, + packageIds, + endpointType +) { // Insert endpoint type let endpointTypeId = await dbApi.dbInsert( db, ` INSERT INTO ENDPOINT_TYPE ( - SESSION_REF, + SESSION_PARTITION_REF, NAME ) VALUES (?, ?)`, - [sessionId, endpointType.name] + [sessionPartitionId, endpointType.name] ) // Process device types @@ -347,7 +360,11 @@ SELECT FROM PACKAGE INNER JOIN SESSION_PACKAGE ON PACKAGE.PACKAGE_ID = SESSION_PACKAGE.PACKAGE_REF -WHERE SESSION_PACKAGE.SESSION_REF = ? AND SESSION_PACKAGE.ENABLED = 1`, +INNER JOIN + SESSION_PARTITION +ON + SESSION_PACKAGE.SESSION_PARTITION_REF= SESSION_PARTITION.SESSION_PARTITION_ID +WHERE SESSION_PARTITION.SESSION_REF = ? AND SESSION_PACKAGE.ENABLED = 1`, [sessionId] ) .then((rows) => rows.map(mapFunction)) @@ -430,7 +447,6 @@ async function importClusterForEndpointType( cluster.mfgCode == null ? [cluster.code] : [cluster.code, cluster.mfgCode] ) .then((matchedPackageIds) => matchedPackageIds.shift()?.PACKAGE_REF) - return dbApi.dbInsert( db, ` diff --git a/src-electron/db/query-loader.js b/src-electron/db/query-loader.js index cfc1f23043..26b637f4d6 100644 --- a/src-electron/db/query-loader.js +++ b/src-electron/db/query-loader.js @@ -131,8 +131,11 @@ INSERT INTO COMMAND_ARG ( (SELECT SPEC_ID FROM SPEC WHERE CODE = ? AND PACKAGE_REF = ?) )` +// Replace here is used to prevent custom cluster extensions from being re-loaded again. +// Attribute table needs to be unique based on: +// UNIQUE("CLUSTER_REF", "PACKAGE_REF", "CODE", "MANUFACTURER_CODE") const INSERT_ATTRIBUTE_QUERY = ` -INSERT INTO ATTRIBUTE ( +INSERT OR REPLACE INTO ATTRIBUTE ( CLUSTER_REF, PACKAGE_REF, CODE, diff --git a/src-electron/db/query-package-notification.js b/src-electron/db/query-package-notification.js index b1e4638725..f982cbb182 100644 --- a/src-electron/db/query-package-notification.js +++ b/src-electron/db/query-package-notification.js @@ -67,7 +67,16 @@ async function getNotificationBySessionId(db, sessionId) { rows = await dbApi.dbAll( db, 'SELECT * FROM PACKAGE_NOTICE WHERE PACKAGE_REF IN' + - '( SELECT PACKAGE_REF FROM SESSION_PACKAGE WHERE SESSION_REF = ( ? ) )', + `( SELECT + SESSION_PACKAGE.PACKAGE_REF + FROM + SESSION_PACKAGE + INNER JOIN + SESSION_PARTITION + ON + SESSION_PACKAGE.SESSION_PARTITION_REF= SESSION_PARTITION.SESSION_PARTITION_ID + WHERE + SESSION_PARTITION.SESSION_REF = ( ? ) )`, [sessionId] ) return rows.map(dbMapping.map.packageNotification) diff --git a/src-electron/db/query-package.js b/src-electron/db/query-package.js index a4f7e7bcd7..a83b2bd99c 100644 --- a/src-electron/db/query-package.js +++ b/src-electron/db/query-package.js @@ -148,10 +148,11 @@ async function getPackagesByType(db, type) { */ async function getPackagesByCategoryAndType(db, type, category = '') { return dbApi - .dbAll(db, `${querySelectFromPackage} WHERE TYPE = ? AND CATEGORY = ?`, [ - type, - category, - ]) + .dbAll( + db, + `${querySelectFromPackage} WHERE TYPE = ? AND (CATEGORY IN (${category}) OR CATEGORY IS NULL)`, + [type] + ) .then((rows) => rows.map(dbMapping.map.package)) } @@ -173,12 +174,12 @@ async function getPackagesByParentAndType(db, parentId, type) { } /** - * Checks if the package with a given path exists and executes appropriate action. - * Returns the promise that resolves the the package or null if nothing was found. + * Checks if the package with a given package id exists and executes appropriate action. + * Returns the promise that resolves the package or null if nothing was found. * * @export * @param {*} db - * @param {*} path Path of a file to check. + * @param {*} packageId */ async function getPackageByPackageId(db, packageId) { return dbApi @@ -186,6 +187,25 @@ async function getPackageByPackageId(db, packageId) { .then(dbMapping.map.package) } +/** + * Checks if packages with given package ids exist and executes appropriate action. + * Returns the promise that resolves the packages or null if nothing was found. + * + * @export + * @param {*} db + * @param {*} packageIds + */ +async function getPackagesByPackageIds(db, packageIds) { + return dbApi + .dbAll( + db, + `${querySelectFromPackage} WHERE PACKAGE_ID IN (${dbApi.toInClause( + packageIds + )})` + ) + .then((rows) => rows.map(dbMapping.map.package)) +} + /** * Returns a package ref from the attribute ID * @@ -327,48 +347,56 @@ async function updatePathCrc(db, path, crc, parentId) { * Inserts a mapping between session and package. * * @param {*} db - * @param {*} sessionId + * @param {*} sessionPartitionId * @param {*} packageId + * @param {*} required * @returns Promise of an insert. */ async function insertSessionPackage( db, - sessionId, + sessionPartitionId, packageId, required = false ) { return dbApi.dbInsert( db, - 'INSERT OR REPLACE INTO SESSION_PACKAGE (SESSION_REF, PACKAGE_REF, REQUIRED, ENABLED) VALUES (?,?,?,1)', - [sessionId, packageId, required] + 'INSERT OR REPLACE INTO SESSION_PACKAGE (SESSION_PARTITION_REF, PACKAGE_REF, REQUIRED, ENABLED) VALUES (?,?,?,1)', + [sessionPartitionId, packageId, required] ) } /** * @param {*} db - * @param {*} sessionId + * @param {*} sessionPartitionId * @param {*} packageType */ -async function deleteSessionPackage(db, sessionId, packageId) { +async function deleteSessionPackage(db, sessionPartitionId, packageId) { return dbApi.dbRemove( db, - `UPDATE SESSION_PACKAGE SET ENABLED = 0 WHERE SESSION_REF = ? AND PACKAGE_REF = ?`, - [sessionId, packageId] + `UPDATE SESSION_PACKAGE SET ENABLED = 0 WHERE SESSION_PARTITION_REF = ? AND PACKAGE_REF = ?`, + [sessionPartitionId, packageId] ) } /** - * Deletes all session packages. + * Deletes all session packages based on sessionPartitionIds. * * @param {*} db - * @param {*} sessionId + * @param {*} sessionPartitionIds * @returns promise */ -async function deleteAllSessionPackages(db, sessionId) { +async function deleteAllSessionPackages(db, sessionPartitionIds) { + await dbApi.dbRemove( + db, + `DELETE FROM SESSION_PACKAGE WHERE SESSION_PARTITION_REF IN (${dbApi.toInClause( + sessionPartitionIds + )})` + ) return dbApi.dbRemove( db, - `DELETE FROM SESSION_PACKAGE WHERE SESSION_REF = ?`, - [sessionId] + `DELETE FROM SESSION_PARTITION WHERE SESSION_PARTITION_ID IN (${dbApi.toInClause( + sessionPartitionIds + )})` ) } @@ -396,7 +424,11 @@ SELECT FROM PACKAGE INNER JOIN SESSION_PACKAGE ON PACKAGE.PACKAGE_ID = SESSION_PACKAGE.PACKAGE_REF -WHERE SESSION_PACKAGE.SESSION_REF = ? +INNER JOIN + SESSION_PARTITION +ON + SESSION_PACKAGE.SESSION_PARTITION_REF= SESSION_PARTITION.SESSION_PARTITION_ID +WHERE SESSION_PARTITION.SESSION_REF = ? AND PACKAGE.TYPE = ? AND SESSION_PACKAGE.ENABLED = 1`, [sessionId, packageType] @@ -433,7 +465,11 @@ async function getSessionGenTemplates(db, sessionId) { FROM PACKAGE INNER JOIN SESSION_PACKAGE ON PACKAGE.PACKAGE_ID = SESSION_PACKAGE.PACKAGE_REF - WHERE SESSION_PACKAGE.SESSION_REF = ? + INNER JOIN + SESSION_PARTITION + ON + SESSION_PACKAGE.SESSION_PARTITION_REF= SESSION_PARTITION.SESSION_PARTITION_ID + WHERE SESSION_PARTITION.SESSION_REF = ? AND PACKAGE.TYPE = ? AND SESSION_PACKAGE.ENABLED = 1) ORDER BY PACKAGE.PATH ASC`, @@ -459,16 +495,22 @@ async function getSessionZclPackages(db, sessionId) { ` SELECT SP.PACKAGE_REF, - SP.SESSION_REF, - SP.REQUIRED -FROM + SESSION_PARTITION.SESSION_REF, + SESSION_PARTITION.SESSION_PARTITION_ID, + SP.REQUIRED, + P.CATEGORY +FROM + SESSION_PARTITION +INNER JOIN SESSION_PACKAGE AS SP +ON + SP.SESSION_PARTITION_REF= SESSION_PARTITION.SESSION_PARTITION_ID INNER JOIN PACKAGE AS P ON SP.PACKAGE_REF = P.PACKAGE_ID WHERE - SP.SESSION_REF = ? AND SP.ENABLED = 1 AND P.TYPE IN ${inList} + SESSION_PARTITION.SESSION_REF = ? AND SP.ENABLED = 1 AND P.TYPE IN ${inList} `, [sessionId] ) @@ -496,7 +538,19 @@ async function getSessionPackages(db, sessionId) { return dbApi .dbAll( db, - 'SELECT PACKAGE_REF, SESSION_REF, REQUIRED FROM SESSION_PACKAGE WHERE SESSION_REF = ? AND ENABLED = 1', + ` + SELECT + SESSION_PACKAGE.PACKAGE_REF, + SESSION_PARTITION.SESSION_REF, + SESSION_PACKAGE.REQUIRED + FROM + SESSION_PACKAGE + INNER JOIN + SESSION_PARTITION + ON + SESSION_PACKAGE.SESSION_PARTITION_REF= SESSION_PARTITION.SESSION_PARTITION_ID + WHERE + SESSION_PARTITION.SESSION_REF = ? AND SESSION_PACKAGE.ENABLED = 1`, [sessionId] ) .then((rows) => rows.map(dbMapping.map.sessionPackage)) @@ -515,17 +569,21 @@ async function getSessionPackagesWithTypes(db, sessionId) { ` SELECT SP.PACKAGE_REF, - SP.SESSION_REF, + SESSION_PARTITION.SESSION_REF, SP.REQUIRED, P.TYPE FROM + SESSION_PARTITION +INNER JOIN SESSION_PACKAGE AS SP +ON + SP.SESSION_PARTITION_REF= SESSION_PARTITION.SESSION_PARTITION_ID INNER JOIN PACKAGE AS P ON SP.PACKAGE_REF = P.PACKAGE_ID WHERE - SP.SESSION_REF = ? AND SP.ENABLED = 1`, + SESSION_PARTITION.SESSION_REF = ? AND SP.ENABLED = 1`, [sessionId] ) .then((rows) => rows.map(dbMapping.map.sessionPackage)) @@ -550,7 +608,7 @@ SELECT P.DESCRIPTION, P.PARENT_PACKAGE_REF, SP.PACKAGE_REF, - SP.SESSION_REF, + SESSION_PARTITION.SESSION_REF, SP.REQUIRED FROM PACKAGE AS P @@ -558,8 +616,12 @@ INNER JOIN SESSION_PACKAGE AS SP ON P.PACKAGE_ID = SP.PACKAGE_REF +INNER JOIN + SESSION_PARTITION +ON + SP.SESSION_PARTITION_REF= SESSION_PARTITION.SESSION_PARTITION_ID WHERE - SP.SESSION_REF = ? + SESSION_PARTITION.SESSION_REF = ? AND SP.ENABLED = 1`, [sessionId] ) @@ -1022,7 +1084,6 @@ exports.getPackageIdByPathAndTypeAndVersion = getPackageIdByPathAndTypeAndVersion exports.getPackageSessionPackagePairBySessionId = getPackageSessionPackagePairBySessionId - exports.getPathCrc = getPathCrc exports.getZclPropertiesPackage = getZclPropertiesPackage exports.insertPathCrc = insertPathCrc @@ -1045,7 +1106,6 @@ exports.getSessionZclPackages = getSessionZclPackages exports.getSessionZclPackageIds = getSessionZclPackageIds exports.getAllPackages = getAllPackages exports.deleteAllSessionPackages = deleteAllSessionPackages - exports.insertPackageExtension = insertPackageExtension exports.selectPackageExtension = selectPackageExtension exports.selectPackageExtensionByPropertyAndEntity = @@ -1055,3 +1115,4 @@ exports.selectAllUiOptions = selectAllUiOptions exports.insertSessionKeyValuesFromPackageDefaults = insertSessionKeyValuesFromPackageDefaults exports.getPackagesByCategoryAndType = getPackagesByCategoryAndType +exports.getPackagesByPackageIds = getPackagesByPackageIds diff --git a/src-electron/db/query-session-zcl.js b/src-electron/db/query-session-zcl.js index 3e324fbdb1..5d3a954932 100644 --- a/src-electron/db/query-session-zcl.js +++ b/src-electron/db/query-session-zcl.js @@ -31,6 +31,8 @@ const dbEnum = require('../../src-shared/db-enum.js') * * @param {*} db * @param {*} sessionId + * @param {*} code + * @param {*} mfgCode * @returns all the cluster objects for a given session. */ async function selectSessionClusterByCode(db, sessionId, code, mfgCode) { @@ -58,8 +60,12 @@ INNER JOIN SESSION_PACKAGE AS SP ON C.PACKAGE_REF = SP.PACKAGE_REF +INNER JOIN + SESSION_PARTITION +ON + SESSION_PARTITION.SESSION_PARTITION_ID = SP.SESSION_PARTITION_REF WHERE - SP.SESSION_REF = ? AND C.CODE = ? AND ${ + SESSION_PARTITION.SESSION_REF = ? AND C.CODE = ? AND ${ mfgCode == 0 || mfgCode == null ? 'C.MANUFACTURER_CODE IS NULL' : 'C.MANUFACTURER_CODE = ?' @@ -99,8 +105,12 @@ INNER JOIN SESSION_PACKAGE AS SP ON C.PACKAGE_REF = SP.PACKAGE_REF +INNER JOIN + SESSION_PARTITION +ON + SESSION_PARTITION.SESSION_PARTITION_ID = SP.SESSION_PARTITION_REF WHERE - SP.SESSION_REF = ? + SESSION_PARTITION.SESSION_REF = ? `, [sessionId] ) @@ -112,6 +122,10 @@ WHERE * * @param {*} db * @param {*} sessionId + * @param {*} clusterCode + * @param {*} side + * @param {*} attributeCode + * @param {*} mfgCode * @returns the session attribute */ async function selectSessionAttributeByCode( @@ -151,8 +165,12 @@ SELECT ATTRIBUTE.MUST_USE_TIMED_WRITE FROM ATTRIBUTE, CLUSTER, SESSION_PACKAGE +INNER JOIN + SESSION_PARTITION +ON + SESSION_PACKAGE.SESSION_PARTITION_REF= SESSION_PARTITION.SESSION_PARTITION_ID WHERE - SESSION_PACKAGE.SESSION_REF = ? AND + SESSION_PARTITION.SESSION_REF = ? AND ATTRIBUTE.PACKAGE_REF = SESSION_PACKAGE.PACKAGE_REF AND ATTRIBUTE.CODE = ? AND ((ATTRIBUTE.CLUSTER_REF = CLUSTER.CLUSTER_ID AND CLUSTER.CODE = ?) OR (ATTRIBUTE.CLUSTER_REF IS NULL)) AND ATTRIBUTE.SIDE = ? @@ -167,6 +185,9 @@ WHERE * * @param {*} db * @param {*} sessionId + * @param {*} clusterCode + * @param {*} commandCode + * @param {*} source * @returns the session attribute */ async function selectSessionCommandByCode( @@ -203,8 +224,12 @@ INNER JOIN SESSION_PACKAGE AS SP ON C.PACKAGE_REF = SP.PACKAGE_REF +INNER JOIN + SESSION_PARTITION +ON + SESSION_PARTITION.SESSION_PARTITION_ID = SP.SESSION_PARTITION_REF WHERE - SP.SESSION_REF = ? AND C.CODE = ? AND CMD.CODE = ? AND CMD.SOURCE = ? + SESSION_PARTITION.SESSION_REF = ? AND C.CODE = ? AND CMD.CODE = ? AND CMD.SOURCE = ? `, [sessionId, clusterCode, commandCode, source] ) diff --git a/src-electron/db/query-session.js b/src-electron/db/query-session.js index 91d22204ba..a595a61c99 100644 --- a/src-electron/db/query-session.js +++ b/src-electron/db/query-session.js @@ -59,7 +59,8 @@ async function reloadSession(db, sessionId, userRef, sessionKey) { } /** - * Returns a promise that resolves into an array of objects containing 'sessionId', 'sessionKey' and 'creationTime' and assigned packages. + * Returns a promise that resolves into an array of objects containing + * 'sessionId', 'sessionKey' and 'creationTime' and assigned packages. * Dirty Sessions are the sessions which are created in the past and not saved * * @export @@ -75,11 +76,16 @@ SELECT SESSION.SESSION_KEY, SESSION.CREATION_TIME, SESSION.DIRTY, - SESSION_PACKAGE.SESSION_REF, + SESSION_PARTITION.SESSION_REF, SESSION_PACKAGE.PACKAGE_REF FROM SESSION - INNER JOIN SESSION_PACKAGE - ON SESSION.SESSION_ID = SESSION_PACKAGE.SESSION_REF + INNER JOIN + SESSION_PARTITION + ON SESSION.SESSION_ID = SESSION_PARTITION.SESSION_REF + INNER JOIN + SESSION_PACKAGE + ON + SESSION_PACKAGE.SESSION_PARTITION_REF= SESSION_PARTITION.SESSION_PARTITION_ID WHERE SESSION.DIRTY = 1`, [] ) @@ -254,6 +260,7 @@ async function ensureZapUserAndSession( options = { sessionId: null, userId: null, + partitions: null, } ) { if (options.sessionId != null && options.userId != null) { @@ -262,6 +269,7 @@ async function ensureZapUserAndSession( sessionId: options.sessionId, userId: options.userId, newSession: false, + partitions: options.partitions, } } else if (options.sessionId != null) { // we have a session, but not the user, so we create @@ -272,40 +280,281 @@ async function ensureZapUserAndSession( sessionId: options.sessionId, userId: user.userId, newSession: false, + partitions: options.partitions, } } else if (options.userId != null) { // we have the user, but not the session, so we create the session, // and link it to the user. - let sessionId = await ensureBlankSession(db, sessionUuid) + let sessionId = await ensureBlankSession( + db, + sessionUuid, + options.partitions + ) await linkSessionToUser(db, sessionId, options.userId) return { sessionId: sessionId, userId: options.userId, newSession: true, + partitions: options.partitions, } } else { // we have nothing, create both the user and the session. let user = await ensureUser(db, userKey) - let sessionId = await ensureBlankSession(db, sessionUuid) + let sessionId = await ensureBlankSession( + db, + sessionUuid, + options.partitions + ) await linkSessionToUser(db, sessionId, user.userId) return { sessionId: sessionId, userId: user.userId, newSession: true, + partitions: options.partitions, } } } -async function ensureBlankSession(db, uuid) { - await dbApi.dbInsert( +/** + * Create a blank session with a new session id and its session partitions. + * + * @param {*} db + * @param {*} uuid + * @param {*} partitions + * @returns session Id + */ +async function ensureBlankSession(db, uuid, partitions) { + let sessionId = await dbApi.dbInsert( db, 'INSERT OR IGNORE INTO SESSION (SESSION_KEY, CREATION_TIME, DIRTY) VALUES (?,?,?)', [uuid, Date.now(), 0] ) + // An ignore in the above insert command can lead to false session Ids. Hence the additional check. + let sessionIdInserted = await dbApi.dbGet( + db, + `SELECT SESSION_ID FROM SESSION WHERE SESSION_ID = ?`, + [sessionId] + ) + if (sessionIdInserted) { + let sessionPartitionPromises = [] + for (let i = 0; i < partitions; i++) { + sessionPartitionPromises.push( + dbApi.dbInsert( + db, + 'INSERT OR IGNORE INTO SESSION_PARTITION (SESSION_REF, SESSION_PARTITION_NUMBER) VALUES (?,?)', + [sessionId, i + 1] + ) + ) + } + await Promise.all(sessionPartitionPromises) + } + const session = await getSessionInfoFromSessionKey(db, uuid) return session.sessionId } +/** + * Populate the session partition table based on session partitions + * @param {*} db + * @param {*} sessionId + * @param {*} partitions + * @returns sessionPartition Ids + */ +async function insertSessionPartitions(db, sessionId, partitions) { + let sessionPartitionPromises = [] + for (let i = 0; i < partitions; i++) { + sessionPartitionPromises.push( + dbApi.dbInsert( + db, + 'INSERT OR IGNORE INTO SESSION_PARTITION (SESSION_REF, SESSION_PARTITION_NUMBER) VALUES (?,?)', + [sessionId, i + 1] + ) + ) + } + let sessionPartitions = await Promise.all(sessionPartitionPromises) + return sessionPartitions +} + +/** + * + * @param {*} db + * @param {*} sessionId + * @param {*} partitionNumber + * @returns inserted sessionPartitionId + */ +async function insertSessionPartition(db, sessionId, partitionNumber) { + let sessionPartition = await dbApi.dbInsert( + db, + 'INSERT OR IGNORE INTO SESSION_PARTITION (SESSION_REF, SESSION_PARTITION_NUMBER) VALUES (?,?)', + [sessionId, partitionNumber] + ) + return sessionPartition +} + +/** + * Retrieve session partition info from sessionId and partition number. + * + * @param {*} db + * @param {*} sessionId + * @param {*} partitionNumber + * @returns session partition info + */ +async function getSessionPartitionInfo(db, sessionId, partitionNumber) { + let rows = await dbApi.dbAll( + db, + ` + SELECT + SESSION_PARTITION_ID, + SESSION_PARTITION_NUMBER, + SESSION_REF + FROM + SESSION_PARTITION + WHERE + SESSION_REF = ? + AND + SESSION_PARTITION_NUMBER <= ?`, + [sessionId, partitionNumber] + ) + return rows.map(dbMapping.map.sessionPartition) +} + +/** + * Retrieve session partition info for a given session. + * + * @param {*} db + * @param {*} sessionId + * @returns session partition info for a session + */ +async function getAllSessionPartitionInfoForSession(db, sessionId) { + let rows = await dbApi.dbAll( + db, + ` + SELECT + SESSION_PARTITION_ID, + SESSION_PARTITION_NUMBER, + SESSION_REF + FROM + SESSION_PARTITION + WHERE + SESSION_REF = ?`, + [sessionId] + ) + return rows.map(dbMapping.map.sessionPartition) +} + +/** + * Retrieve session partition info from session id and device type id + * @param {*} db + * @param {*} sessionId + * @param {*} deviceTypeIds + * @returns session partition info + */ +async function selectSessionPartitionInfoFromDeviceType( + db, + sessionId, + deviceTypeIds +) { + let rows = await dbApi.dbAll( + db, + ` + SELECT + SESSION_PARTITION.SESSION_PARTITION_ID, + SESSION_PARTITION.SESSION_PARTITION_NUMBER, + SESSION_PARTITION.SESSION_REF + FROM + DEVICE_TYPE + INNER JOIN + SESSION_PACKAGE + ON + DEVICE_TYPE.PACKAGE_REF = SESSION_PACKAGE.PACKAGE_REF + INNER JOIN + SESSION_PARTITION + ON + SESSION_PARTITION.SESSION_PARTITION_ID = SESSION_PACKAGE.SESSION_PARTITION_REF + INNER JOIN + SESSION + ON + SESSION.SESSION_ID = SESSION_PARTITION.SESSION_REF + WHERE + SESSION.SESSION_ID = ? + AND + DEVICE_TYPE.DEVICE_TYPE_ID IN (${dbApi.toInClause(deviceTypeIds)}) + AND + SESSION_PACKAGE.ENABLED=1`, + [sessionId] + ) + return rows.map(dbMapping.map.sessionPartition) +} + +/** + * Retrieve session partition infor from session id and package id. + * @param {*} db + * @param {*} sessionId + * @param {*} packageIds + * @returns session partition info + */ +async function selectSessionPartitionInfoFromPackageId( + db, + sessionId, + packageIds +) { + let rows = await dbApi.dbAll( + db, + ` + SELECT + SESSION_PARTITION.SESSION_PARTITION_ID, + SESSION_PARTITION.SESSION_PARTITION_NUMBER, + SESSION_PARTITION.SESSION_REF + FROM + SESSION_PACKAGE + INNER JOIN + SESSION_PARTITION + ON + SESSION_PACKAGE.SESSION_PARTITION_REF = SESSION_PARTITION.SESSION_PARTITION_ID + INNER JOIN + SESSION + ON + SESSION_PARTITION.SESSION_REF = SESSION.SESSION_ID + WHERE + SESSION_PARTITION.SESSION_REF = ? + AND + SESSION_PACKAGE.PACKAGE_REF IN (${packageIds}) + AND + SESSION_PACKAGE.ENABLED=1`, + [sessionId] + ) + return rows.map(dbMapping.map.sessionPartition) +} + +/** + * Retrieve session partition infor from deviceTypeId. + * @param {*} db + * @param {*} deviceTypeId + * @returns session partition info + */ +async function selectDeviceTypePackageInfoFromDeviceTypeId(db, deviceTypeIds) { + let rows = await dbApi.dbAll( + db, + ` + SELECT + DEVICE_TYPE.DEVICE_TYPE_ID, + DEVICE_TYPE.CODE, + DEVICE_TYPE.NAME, + DEVICE_TYPE.NAME, + DEVICE_TYPE.PACKAGE_REF, + PACKAGE.CATEGORY + FROM + DEVICE_TYPE + INNER JOIN + PACKAGE + ON + PACKAGE.PACKAGE_ID = DEVICE_TYPE.PACKAGE_REF + WHERE + DEVICE_TYPE.DEVICE_TYPE_ID IN (${dbApi.toInClause(deviceTypeIds)})` + ) + return rows.map(dbMapping.map.deviceTypeExtended) +} + /** * When loading in a file, we start with a blank session. * @@ -591,3 +840,14 @@ exports.getUserSessionsById = getUserSessionsById exports.getUsers = getUsers exports.getUsersSessions = getUsersSessions exports.setSessionNewNotificationClean = setSessionNewNotificationClean +exports.getSessionPartitionInfo = getSessionPartitionInfo +exports.selectSessionPartitionInfoFromDeviceType = + selectSessionPartitionInfoFromDeviceType +exports.insertSessionPartitions = insertSessionPartitions +exports.selectSessionPartitionInfoFromPackageId = + selectSessionPartitionInfoFromPackageId +exports.insertSessionPartition = insertSessionPartition +exports.getAllSessionPartitionInfoForSession = + getAllSessionPartitionInfoForSession +exports.selectDeviceTypePackageInfoFromDeviceTypeId = + selectDeviceTypePackageInfoFromDeviceTypeId diff --git a/src-electron/db/query-zcl.js b/src-electron/db/query-zcl.js index e2d8fabb22..e02a226cfd 100644 --- a/src-electron/db/query-zcl.js +++ b/src-electron/db/query-zcl.js @@ -540,7 +540,8 @@ SELECT DOMAIN_NAME, IS_SINGLETON, REVISION, - API_MATURITY + API_MATURITY, + PACKAGE_REF FROM CLUSTER WHERE PACKAGE_REF = ? @@ -672,7 +673,8 @@ SELECT IS_SCENE_REQUIRED, ARRAY_TYPE, MUST_USE_TIMED_WRITE, - API_MATURITY + API_MATURITY, + PACKAGE_REF FROM ATTRIBUTE WHERE (CLUSTER_REF = ? OR CLUSTER_REF IS NULL) AND PACKAGE_REF IN (${dbApi.toInClause(packageIds)}) diff --git a/src-electron/db/zap-schema.sql b/src-electron/db/zap-schema.sql index e9d37319f7..e41814ce62 100644 --- a/src-electron/db/zap-schema.sql +++ b/src-electron/db/zap-schema.sql @@ -284,6 +284,7 @@ CREATE TABLE IF NOT EXISTS "ATTRIBUTE" ( foreign key (REMOVED_IN_REF) references SPEC(SPEC_ID), foreign key (CLUSTER_REF) references CLUSTER(CLUSTER_ID), foreign key (PACKAGE_REF) references PACKAGE(PACKAGE_ID) on delete cascade + UNIQUE("CLUSTER_REF", "PACKAGE_REF", "CODE", "MANUFACTURER_CODE") ); /* GLOBAL_ATTRIBUTE_DEFAULT table contains default values of attributes per cluster. @@ -699,19 +700,28 @@ CREATE TABLE IF NOT EXISTS "SESSION_LOG" ( "LOG" text, foreign key (SESSION_REF) references SESSION(SESSION_ID) on delete cascade ); + +DROP TABLE IF EXISTS "SESSION_PARTITION"; +CREATE TABLE IF NOT EXISTS "SESSION_PARTITION" ( + "SESSION_PARTITION_ID" integer primary key autoincrement, + "SESSION_PARTITION_NUMBER" integer, + "SESSION_REF" integer, + foreign key (SESSION_REF) references SESSION(SESSION_ID) on delete cascade +); + /* SESSION_PACKAGE table is a junction table, listing which packages are used for a given session. */ DROP TABLE IF EXISTS "SESSION_PACKAGE"; CREATE TABLE IF NOT EXISTS "SESSION_PACKAGE" ( - "SESSION_REF" integer, + "SESSION_PARTITION_REF" integer, "PACKAGE_REF" integer, "REQUIRED" integer default false, "ENABLED" integer default true, - foreign key (SESSION_REF) references SESSION(SESSION_ID) on delete cascade, + foreign key (SESSION_PARTITION_REF) references SESSION_PARTITION(SESSION_PARTITION_ID) on delete cascade, foreign key (PACKAGE_REF) references PACKAGE(PACKAGE_ID) on delete cascade, - UNIQUE(SESSION_REF, PACKAGE_REF) + UNIQUE(SESSION_PARTITION_REF, PACKAGE_REF) ); /* ENDPOINT_TYPE contains the bulk of the configuration: clusters, attributes, etc. @@ -719,9 +729,9 @@ CREATE TABLE IF NOT EXISTS "SESSION_PACKAGE" ( DROP TABLE IF EXISTS "ENDPOINT_TYPE"; CREATE TABLE IF NOT EXISTS "ENDPOINT_TYPE" ( "ENDPOINT_TYPE_ID" integer primary key autoincrement, - "SESSION_REF" integer, + "SESSION_PARTITION_REF" integer, "NAME" text, - foreign key (SESSION_REF) references SESSION(SESSION_ID) on delete cascade + foreign key (SESSION_PARTITION_REF) references SESSION_PARTITION(SESSION_PARTITION_ID) on delete cascade ); /* ENDPOINT_TYPE_DEVICE: many-to-many relationship between endpoint type and @@ -877,13 +887,17 @@ BEGIN ( ( SELECT - SESSION_REF + SESSION_PARTITION.SESSION_REF FROM - ENDPOINT_TYPE - INNER JOIN ENDPOINT_TYPE_CLUSTER + INNER JOIN + ENDPOINT_TYPE ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_REF + INNER JOIN + SESSION_PARTITION + ON + SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF WHERE ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = new.ENDPOINT_TYPE_CLUSTER_ID ), @@ -1205,13 +1219,17 @@ BEGIN ( ( SELECT - SESSION_REF + SESSION_PARTITION.SESSION_REF FROM - ENDPOINT_TYPE - INNER JOIN ENDPOINT_TYPE_ATTRIBUTE + INNER JOIN + ENDPOINT_TYPE ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_REF + INNER JOIN + SESSION_PARTITION + ON + SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF WHERE ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_ATTRIBUTE_ID = new.ENDPOINT_TYPE_ATTRIBUTE_ID ), @@ -1309,13 +1327,17 @@ BEGIN ( ( SELECT - SESSION_REF + SESSION_PARTITION.SESSION_REF FROM - ENDPOINT_TYPE - INNER JOIN ENDPOINT_TYPE_ATTRIBUTE + INNER JOIN + ENDPOINT_TYPE ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_REF + INNER JOIN + SESSION_PARTITION + ON + SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF WHERE ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_ATTRIBUTE_ID = new.ENDPOINT_TYPE_ATTRIBUTE_ID ), @@ -1860,7 +1882,11 @@ WHEN SELECT COUNT() FROM + ENDPOINT_TYPE_CLUSTER + INNER JOIN ENDPOINT_TYPE_COMMAND + ON + ENDPOINT_TYPE_COMMAND.ENDPOINT_TYPE_CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID INNER JOIN DEVICE_TYPE_COMMAND ON @@ -1884,7 +1910,9 @@ WHEN AND ENDPOINT_TYPE_COMMAND.IS_INCOMING = new.IS_INCOMING AND - ENDPOINT_TYPE_COMMAND.IS_ENABLED = 0) > 0 + ENDPOINT_TYPE_COMMAND.IS_ENABLED = 0 + AND + ENDPOINT_TYPE_CLUSTER.ENABLED = 1) > 0 BEGIN INSERT INTO SESSION_NOTICE(SESSION_REF, NOTICE_TYPE, NOTICE_MESSAGE, NOTICE_SEVERITY, DISPLAY, SEEN) @@ -1892,13 +1920,17 @@ BEGIN ( ( SELECT - SESSION_REF + SESSION_PARTITION.SESSION_REF FROM - ENDPOINT_TYPE - INNER JOIN ENDPOINT_TYPE_COMMAND + INNER JOIN + ENDPOINT_TYPE ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_COMMAND.ENDPOINT_TYPE_REF + INNER JOIN + SESSION_PARTITION + ON + SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF WHERE ENDPOINT_TYPE_COMMAND.ENDPOINT_TYPE_COMMAND_ID = new.ENDPOINT_TYPE_COMMAND_ID ), @@ -1971,7 +2003,7 @@ END; /* SQL Trigger for Cluster's command Compliance. -This trigger is used to add a warning to the notification table when an +This trigger is used to add a warning to the notification table when a command is not enabled as per the cluster specification. */ CREATE TRIGGER @@ -1989,8 +2021,14 @@ WHEN ENDPOINT_TYPE_COMMAND ON ENDPOINT_TYPE_COMMAND.COMMAND_REF = COMMAND.COMMAND_ID + INNER JOIN + ENDPOINT_TYPE_CLUSTER + ON + ENDPOINT_TYPE_COMMAND.ENDPOINT_TYPE_CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID WHERE - ENDPOINT_TYPE_COMMAND.ENDPOINT_TYPE_COMMAND_ID = new.ENDPOINT_TYPE_COMMAND_ID) == 0 + ENDPOINT_TYPE_COMMAND.ENDPOINT_TYPE_COMMAND_ID = new.ENDPOINT_TYPE_COMMAND_ID + AND + ENDPOINT_TYPE_CLUSTER.ENABLED=1) == 0 AND new.IS_ENABLED = 0 ) @@ -2001,13 +2039,17 @@ BEGIN ( ( SELECT - SESSION_REF + SESSION_PARTITION.SESSION_REF FROM - ENDPOINT_TYPE - INNER JOIN ENDPOINT_TYPE_COMMAND + INNER JOIN + ENDPOINT_TYPE ON ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT_TYPE_COMMAND.ENDPOINT_TYPE_REF + INNER JOIN + SESSION_PARTITION + ON + SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF WHERE ENDPOINT_TYPE_COMMAND.ENDPOINT_TYPE_COMMAND_ID = new.ENDPOINT_TYPE_COMMAND_ID ), @@ -2617,7 +2659,7 @@ AFTER INSERT ON "SESSION_PACKAGE" BEGIN UPDATE SESSION SET DIRTY = 1 -WHERE SESSION_ID = NEW.SESSION_REF; +WHERE SESSION_ID = (SELECT SESSION_REF FROM SESSION_PARTITION WHERE SESSION_PARTITION.SESSION_PARTITION_ID = NEW.SESSION_PARTITION_REF); END; CREATE TRIGGER IF NOT EXISTS "UPDATE_TRIGGER_SESSION_KEY_VALUE" AFTER @@ -2631,7 +2673,7 @@ AFTER UPDATE ON "SESSION_PACKAGE" BEGIN UPDATE SESSION SET DIRTY = 1 -WHERE SESSION_ID = NEW.SESSION_REF; +WHERE SESSION_ID = (SELECT SESSION_REF FROM SESSION_PARTITION WHERE SESSION_PARTITION.SESSION_PARTITION_ID = NEW.SESSION_PARTITION_REF); END; CREATE TRIGGER IF NOT EXISTS "DELETE_TRIGGER_SESSION_KEY_VALUE" AFTER DELETE ON "SESSION_KEY_VALUE" BEGIN @@ -2664,20 +2706,20 @@ AFTER INSERT ON "ENDPOINT_TYPE" BEGIN UPDATE SESSION SET DIRTY = 1 -WHERE SESSION_ID = NEW.SESSION_REF; +WHERE SESSION_ID = (SELECT SESSION_REF FROM SESSION_PARTITION WHERE SESSION_PARTITION.SESSION_PARTITION_ID = NEW.SESSION_PARTITION_REF); END; CREATE TRIGGER IF NOT EXISTS "UPDATE_TRIGGER_ENDPOINT_TYPE" AFTER UPDATE ON "ENDPOINT_TYPE" BEGIN UPDATE SESSION SET DIRTY = 1 -WHERE SESSION_ID = NEW.SESSION_REF; +WHERE SESSION_ID = (SELECT SESSION_REF FROM SESSION_PARTITION WHERE SESSION_PARTITION.SESSION_PARTITION_ID = NEW.SESSION_PARTITION_REF); END; CREATE TRIGGER IF NOT EXISTS "DELETE_TRIGGER_ENDPOINT_TYPE" AFTER DELETE ON "ENDPOINT_TYPE" BEGIN UPDATE SESSION SET DIRTY = 1 -WHERE SESSION_ID = OLD.SESSION_REF; +WHERE SESSION_ID = (SELECT SESSION_REF FROM SESSION_PARTITION WHERE SESSION_PARTITION.SESSION_PARTITION_ID = OLD.SESSION_PARTITION_REF); END; CREATE TRIGGER IF NOT EXISTS "INSERT_TRIGGER_ENDPOINT" AFTER @@ -2705,9 +2747,11 @@ INSERT ON "ENDPOINT_TYPE_CLUSTER" BEGIN UPDATE SESSION SET DIRTY = 1 WHERE SESSION_ID = ( - SELECT SESSION_REF + SELECT SESSION_PARTITION.SESSION_REF FROM ENDPOINT_TYPE - WHERE ENDPOINT_TYPE_ID = NEW.ENDPOINT_TYPE_REF + INNER JOIN SESSION_PARTITION + ON SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF + WHERE ENDPOINT_TYPE.ENDPOINT_TYPE_ID = NEW.ENDPOINT_TYPE_REF ); END; CREATE TRIGGER IF NOT EXISTS "UPDATE_TRIGGER_ENDPOINT_TYPE_CLUSTER" @@ -2716,9 +2760,11 @@ UPDATE ON "ENDPOINT_TYPE_CLUSTER" BEGIN UPDATE SESSION SET DIRTY = 1 WHERE SESSION_ID = ( - SELECT SESSION_REF + SELECT SESSION_PARTITION.SESSION_REF FROM ENDPOINT_TYPE - WHERE ENDPOINT_TYPE_ID = NEW.ENDPOINT_TYPE_REF + INNER JOIN SESSION_PARTITION + ON SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF + WHERE ENDPOINT_TYPE.ENDPOINT_TYPE_ID = NEW.ENDPOINT_TYPE_REF ); END; CREATE TRIGGER IF NOT EXISTS "DELETE_TRIGGER_ENDPOINT_TYPE_CLUSTER" @@ -2726,9 +2772,11 @@ AFTER DELETE ON "ENDPOINT_TYPE_CLUSTER" BEGIN UPDATE SESSION SET DIRTY = 1 WHERE SESSION_ID = ( - SELECT SESSION_REF + SELECT SESSION_PARTITION.SESSION_REF FROM ENDPOINT_TYPE - WHERE ENDPOINT_TYPE_ID = OLD.ENDPOINT_TYPE_REF + INNER JOIN SESSION_PARTITION + ON SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF + WHERE ENDPOINT_TYPE.ENDPOINT_TYPE_ID = OLD.ENDPOINT_TYPE_REF ); END; CREATE TRIGGER IF NOT EXISTS "INSERT_TRIGGER_ENDPOINT_TYPE_ATTRIBUTE" @@ -2737,9 +2785,11 @@ INSERT ON "ENDPOINT_TYPE_ATTRIBUTE" BEGIN UPDATE SESSION SET DIRTY = 1 WHERE SESSION_ID = ( - SELECT SESSION_REF + SELECT SESSION_PARTITION.SESSION_REF FROM ENDPOINT_TYPE - WHERE ENDPOINT_TYPE_ID = NEW.ENDPOINT_TYPE_REF + INNER JOIN SESSION_PARTITION + ON SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF + WHERE ENDPOINT_TYPE.ENDPOINT_TYPE_ID = NEW.ENDPOINT_TYPE_REF ); END; CREATE TRIGGER IF NOT EXISTS "UPDATE_TRIGGER_ENDPOINT_TYPE_ATTRIBUTE" @@ -2748,9 +2798,11 @@ UPDATE ON "ENDPOINT_TYPE_ATTRIBUTE" BEGIN UPDATE SESSION SET DIRTY = 1 WHERE SESSION_ID = ( - SELECT SESSION_REF + SELECT SESSION_PARTITION.SESSION_REF FROM ENDPOINT_TYPE - WHERE ENDPOINT_TYPE_ID = NEW.ENDPOINT_TYPE_REF + INNER JOIN SESSION_PARTITION + ON SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF + WHERE ENDPOINT_TYPE.ENDPOINT_TYPE_ID = NEW.ENDPOINT_TYPE_REF ); END; CREATE TRIGGER IF NOT EXISTS "DELETE_TRIGGER_ENDPOINT_TYPE_ATTRIBUTE" @@ -2758,9 +2810,11 @@ AFTER DELETE ON "ENDPOINT_TYPE_ATTRIBUTE" BEGIN UPDATE SESSION SET DIRTY = 1 WHERE SESSION_ID = ( - SELECT SESSION_REF + SELECT SESSION_PARTITION.SESSION_REF FROM ENDPOINT_TYPE - WHERE ENDPOINT_TYPE_ID = OLD.ENDPOINT_TYPE_REF + INNER JOIN SESSION_PARTITION + ON SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF + WHERE ENDPOINT_TYPE.ENDPOINT_TYPE_ID = OLD.ENDPOINT_TYPE_REF ); END; CREATE TRIGGER IF NOT EXISTS "INSERT_TRIGGER_ENDPOINT_TYPE_COMMAND" @@ -2769,9 +2823,11 @@ INSERT ON "ENDPOINT_TYPE_COMMAND" BEGIN UPDATE SESSION SET DIRTY = 1 WHERE SESSION_ID = ( - SELECT SESSION_REF + SELECT SESSION_PARTITION.SESSION_REF FROM ENDPOINT_TYPE - WHERE ENDPOINT_TYPE_ID = NEW.ENDPOINT_TYPE_REF + INNER JOIN SESSION_PARTITION + ON SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF + WHERE ENDPOINT_TYPE.ENDPOINT_TYPE_ID = NEW.ENDPOINT_TYPE_REF ); END; CREATE TRIGGER IF NOT EXISTS "UPDATE_TRIGGER_ENDPOINT_TYPE_COMMAND" @@ -2780,9 +2836,11 @@ UPDATE ON "ENDPOINT_TYPE_COMMAND" BEGIN UPDATE SESSION SET DIRTY = 1 WHERE SESSION_ID = ( - SELECT SESSION_REF + SELECT SESSION_PARTITION.SESSION_REF FROM ENDPOINT_TYPE - WHERE ENDPOINT_TYPE_ID = NEW.ENDPOINT_TYPE_REF + INNER JOIN SESSION_PARTITION + ON SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF + WHERE ENDPOINT_TYPE.ENDPOINT_TYPE_ID = NEW.ENDPOINT_TYPE_REF ); END; CREATE TRIGGER IF NOT EXISTS "DELETE_TRIGGER_ENDPOINT_TYPE_COMMAND" @@ -2790,9 +2848,11 @@ AFTER DELETE ON "ENDPOINT_TYPE_COMMAND" BEGIN UPDATE SESSION SET DIRTY = 1 WHERE SESSION_ID = ( - SELECT SESSION_REF + SELECT SESSION_PARTITION.SESSION_REF FROM ENDPOINT_TYPE - WHERE ENDPOINT_TYPE_ID = OLD.ENDPOINT_TYPE_REF + INNER JOIN SESSION_PARTITION + ON SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF + WHERE ENDPOINT_TYPE.ENDPOINT_TYPE_ID = OLD.ENDPOINT_TYPE_REF ); END; CREATE TRIGGER IF NOT EXISTS "INSERT_TRIGGER_ENDPOINT_TYPE_EVENT" @@ -2801,9 +2861,11 @@ INSERT ON "ENDPOINT_TYPE_EVENT" BEGIN UPDATE SESSION SET DIRTY = 1 WHERE SESSION_ID = ( - SELECT SESSION_REF + SELECT SESSION_PARTITION.SESSION_REF FROM ENDPOINT_TYPE - WHERE ENDPOINT_TYPE_ID = NEW.ENDPOINT_TYPE_REF + INNER JOIN SESSION_PARTITION + ON SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF + WHERE ENDPOINT_TYPE.ENDPOINT_TYPE_ID = NEW.ENDPOINT_TYPE_REF ); END; CREATE TRIGGER IF NOT EXISTS "UPDATE_TRIGGER_ENDPOINT_TYPE_EVENT" @@ -2812,9 +2874,11 @@ UPDATE ON "ENDPOINT_TYPE_EVENT" BEGIN UPDATE SESSION SET DIRTY = 1 WHERE SESSION_ID = ( - SELECT SESSION_REF + SELECT SESSION_PARTITION.SESSION_REF FROM ENDPOINT_TYPE - WHERE ENDPOINT_TYPE_ID = NEW.ENDPOINT_TYPE_REF + INNER JOIN SESSION_PARTITION + ON SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF + WHERE ENDPOINT_TYPE.ENDPOINT_TYPE_ID = NEW.ENDPOINT_TYPE_REF ); END; CREATE TRIGGER IF NOT EXISTS "DELETE_TRIGGER_ENDPOINT_TYPE_EVENT" @@ -2822,9 +2886,11 @@ AFTER DELETE ON "ENDPOINT_TYPE_EVENT" BEGIN UPDATE SESSION SET DIRTY = 1 WHERE SESSION_ID = ( - SELECT SESSION_REF + SELECT SESSION_PARTITION.SESSION_REF FROM ENDPOINT_TYPE - WHERE ENDPOINT_TYPE_ID = OLD.ENDPOINT_TYPE_REF + INNER JOIN SESSION_PARTITION + ON SESSION_PARTITION.SESSION_PARTITION_ID = ENDPOINT_TYPE.SESSION_PARTITION_REF + WHERE ENDPOINT_TYPE.ENDPOINT_TYPE_ID = OLD.ENDPOINT_TYPE_REF ); END; CREATE TRIGGER IF NOT EXISTS "INSERT_TRIGGER_PACKAGE_EXTENSION_VALUE" diff --git a/src-electron/generator/generation-engine.js b/src-electron/generator/generation-engine.js index d8ee594043..4f7bb23bfb 100644 --- a/src-electron/generator/generation-engine.js +++ b/src-electron/generator/generation-engine.js @@ -516,6 +516,7 @@ async function loadTemplates( let globalCtx = { packageIds: [], packageId: null, + templateData: [], } if (genTemplatesJsonArray != null && genTemplatesJsonArray.length > 0) { for (let jsonFile of genTemplatesJsonArray) { @@ -527,6 +528,7 @@ async function loadTemplates( if (globalCtx.packageId == null) { globalCtx.packageId = ctx.packageId } + globalCtx.templateData.push(ctx.templateData) globalCtx.packageIds.push(ctx.packageId) } } @@ -782,7 +784,11 @@ async function generateSingleTemplate( * Main API async function to generate stuff. * * @param {*} db Database - * @param {*} packageId packageId Template package id. It can be either single template or gen template json. + * @param {*} sessionId + * @param {*} templatePackageId packageId Template package id. It can be either single template or gen template json. + * @returns Promise that resolves into a generation result. + * @param {*} templateGeneratorOptions + * @param {*} options * @returns Promise that resolves into a generation result. */ async function generate( diff --git a/src-electron/generator/helper-endpointconfig.js b/src-electron/generator/helper-endpointconfig.js index 4f2e6e2b0a..08175c9bc1 100644 --- a/src-electron/generator/helper-endpointconfig.js +++ b/src-electron/generator/helper-endpointconfig.js @@ -19,6 +19,7 @@ const cHelper = require('./helper-c.js') const templateUtil = require('./template-util') const queryEndpoint = require('../db/query-endpoint.js') const queryEndpointType = require('../db/query-endpoint-type.js') +const queryPackage = require('../db/query-package.js') const bin = require('../util/bin') const types = require('../util/types.js') const zclUtil = require('../util/zcl-util.js') @@ -1162,7 +1163,21 @@ function endpoint_config(options) { } let promise = templateUtil .ensureZclPackageIds(newContext) - .then(() => queryEndpoint.selectAllEndpoints(db, sessionId)) + .then(() => + queryPackage.getPackageByPackageId( + newContext.global.db, + newContext.global.genTemplatePackageId + ) + ) + .then((templatePackage) => + templatePackage && templatePackage.category + ? queryEndpoint.selectAllEndpointsBasedOnTemplateCategory( + db, + sessionId, + templatePackage.category + ) + : queryEndpoint.selectAllEndpoints(db, sessionId) + ) .then((endpoints) => { newContext.endpoints = endpoints let endpointTypeIds = [] @@ -1260,6 +1275,9 @@ function endpoint_config(options) { Object.assign(newContext, collection) }) .then(() => options.fn(newContext)) + .catch((err) => + console.log('Error in endpoint_config helper: ' + err.message) + ) return templateUtil.templatePromise(this.global, promise) } diff --git a/src-electron/generator/template-util.js b/src-electron/generator/template-util.js index bd7b93413e..e6ddf0336f 100644 --- a/src-electron/generator/template-util.js +++ b/src-electron/generator/template-util.js @@ -17,6 +17,7 @@ const queryPackage = require('../db/query-package.js') const queryEndpointType = require('../db/query-endpoint-type.js') +const queryDeviceType = require('../db/query-device-type.js') const dbEnum = require('../../src-shared/db-enum.js') const env = require('../util/env') const _ = require('lodash') @@ -141,16 +142,58 @@ async function ensureZclPackageId(context) { * @returns promise that resolves with a list of package id. */ async function ensureZclPackageIds(context) { + // Get category of templates.json + let pkg = await queryPackage.getPackageByPackageId( + context.global.db, + context.global.genTemplatePackageId + ) + let packageCategory = pkg ? pkg.category : null + let resPkgIds = [] if ('zclPackageIds' in context.global) { - return context.global.zclPackageIds + let pkgIds = context.global.zclPackageIds + if (!packageCategory) { + return pkgIds + } else { + for (let i = 0; i < pkgIds.length; i++) { + let zclPkg = await queryPackage.getPackageByPackageId( + context.global.db, + pkgIds[i] + ) + // Checking for category match or custom xml + if ( + zclPkg.category == packageCategory || + zclPkg.type == dbEnum.packageType.zclXmlStandalone + ) { + resPkgIds.push(pkgIds[i]) + } + } + return resPkgIds + } } else { let pkgs = await queryPackage.getSessionZclPackageIds( context.global.db, context.global.sessionId ) - context.global.zclPackageIds = pkgs - - return pkgs + if (!packageCategory) { + context.global.zclPackageIds = pkgs + return pkgs + } else { + for (let i = 0; i < pkgs.length; i++) { + let zclPkg = await queryPackage.getPackageByPackageId( + context.global.db, + pkgs[i] + ) + // Checking for category match or custom xml + if ( + zclPkg.category == packageCategory || + zclPkg.type == dbEnum.packageType.zclXmlStandalone + ) { + resPkgIds.push(pkgs[i]) + } + } + context.global.zclPackageIds = pkgs + return resPkgIds + } } } @@ -184,15 +227,88 @@ async function ensureTemplatePackageId(context) { * @returns endpoint type ids */ async function ensureEndpointTypeIds(context) { + let pkg = await queryPackage.getPackageByPackageId( + context.global.db, + context.global.genTemplatePackageId + ) + let packageCategory = pkg.category + let resEptIds = [] + if ('endpointTypeIds' in context.global) { - return context.global.endpointTypeIds + let eptIds = context.global.endpointTypeIds + if (!packageCategory) { + return eptIds + } else { + for (let i = 0; i < eptIds.length; i++) { + // Get endpoint type device info + let deviceTypes = + await queryDeviceType.selectDeviceTypesByEndpointTypeId( + context.global.db, + eptIds[i].endpointTypeId + ) + // Sometimes a device type cannot be found for an endpoint type(undefined) + if (deviceTypes.length == 0) { + return context.global.endpointTypeIds + } + for (let j = 0; j < deviceTypes.length; j++) { + // Get device info + let deviceType = await queryDeviceType.selectDeviceTypeById( + context.global.db, + deviceTypes[j].deviceTypeRef + ) + // Get package information to see the category of the device type + let packageInfo = await queryPackage.getPackageByPackageId( + context.global.db, + deviceType.packageRef + ) + // Check for package category match based on gen template category and add it to relevant endpoint types + if (packageInfo.category == packageCategory || !packageCategory) { + resEptIds.push(eptIds[i]) + break + } + } + } + return resEptIds + } } else { - let epts = await queryEndpointType.selectEndpointTypeIds( + let eptIds = await queryEndpointType.selectEndpointTypeIds( context.global.db, context.global.sessionId ) - context.global.endpointTypeIds = epts - return epts + if (!packageCategory) { + context.global.endpointTypeIds = eptIds + return eptIds + } else { + for (let i = 0; i < eptIds.length; i++) { + let deviceTypes = + await queryDeviceType.selectDeviceTypesByEndpointTypeId( + context.global.db, + eptIds[i].endpointTypeId + ) + // Sometimes a device type cannot be found for an endpoint type(undefined) + if (deviceTypes.length == 0) { + context.global.endpointTypeIds = eptIds + return eptIds + } + for (let j = 0; j < deviceTypes.length; j++) { + let deviceType = await queryDeviceType.selectDeviceTypeById( + context.global.db, + deviceTypes[j].deviceTypeRef + ) + let packageInfo = await queryPackage.getPackageByPackageId( + context.global.db, + deviceType.packageRef + ) + if (packageInfo.category == packageCategory) { + resEptIds.push(eptIds[i]) + break + } + } + } + + context.global.endpointTypeIds = eptIds + return resEptIds + } } } diff --git a/src-electron/importexport/import-isc.js b/src-electron/importexport/import-isc.js index f2fe5b311f..10b444146f 100644 --- a/src-electron/importexport/import-isc.js +++ b/src-electron/importexport/import-isc.js @@ -368,9 +368,16 @@ async function loadEndpointType(db, sessionId, packageId, endpointType) { if (dev == null) throw new Error(`Unknown device type: ${deviceName} / ${deviceCode}`) + // Get session partition given the device type reference + let sessionPartitionInfo = + await querySession.selectSessionPartitionInfoFromDeviceType( + db, + sessionId, + dev.id + ) return queryConfig.insertEndpointType( db, - sessionId, + sessionPartitionInfo[0], endpointType.typeName, dev.id, dev.code, diff --git a/src-electron/importexport/import-json.js b/src-electron/importexport/import-json.js index 1d372b8c5a..05ee033fe5 100644 --- a/src-electron/importexport/import-json.js +++ b/src-electron/importexport/import-json.js @@ -318,14 +318,14 @@ async function importSinglePackage( */ function convertPackageResult(data) { let ret = { - zclPackageId: null, + zclPackageIds: [], templateIds: [], optionalIds: [], } data.forEach((obj) => { if (obj == null) return null if (obj.packageType == dbEnum.packageType.zclProperties) { - ret.zclPackageId = obj.packageId + ret.zclPackageIds.push(obj.packageId) } else if (obj.packageType == dbEnum.packageType.genTemplatesJson) { ret.templateIds.push(obj.packageId) } else { @@ -399,18 +399,31 @@ function sortEndpoints(endpoints) { * @param {*} clusters */ async function importClusters(db, allZclPackageIds, endpointTypeId, clusters) { + let relevantZclPackageIds = allZclPackageIds + let endpointTypeDeviceTypesInfo = + await queryDeviceType.selectDeviceTypesByEndpointTypeId(db, endpointTypeId) + let deviceTypeRefs = endpointTypeDeviceTypesInfo.map( + (etd) => etd.deviceTypeRef + ) + if (deviceTypeRefs.length > 0) { + let deviceTypeInfo = await queryDeviceType.selectDeviceTypeById( + db, + deviceTypeRefs[0] + ) + relevantZclPackageIds = deviceTypeInfo.packageRef + } if (clusters) { for (let k = 0; k < clusters.length; k++) { const endpointClusterId = await queryImpexp.importClusterForEndpointType( db, - allZclPackageIds, + relevantZclPackageIds, endpointTypeId, clusters[k] ) await importCommands( db, - allZclPackageIds, + relevantZclPackageIds, endpointTypeId, endpointClusterId, clusters[k].commands @@ -418,7 +431,7 @@ async function importClusters(db, allZclPackageIds, endpointTypeId, clusters) { await importAttributes( db, - allZclPackageIds, + relevantZclPackageIds, endpointTypeId, endpointClusterId, clusters[k].attributes, @@ -427,7 +440,7 @@ async function importClusters(db, allZclPackageIds, endpointTypeId, clusters) { await importEvents( db, - allZclPackageIds, + relevantZclPackageIds, endpointTypeId, endpointClusterId, clusters[k].events @@ -1164,10 +1177,16 @@ async function importEndpointTypes( 'Application is failing the Device Type Specification as follows: \n' const clusterSpecCheckComplianceFailureTitle = '\n\nApplication is failing the Cluster Specification as follows: \n' + let sessionPartitionInfo = + await querySession.selectSessionPartitionInfoFromPackageId( + db, + sessionId, + allZclPackageIds + ) for (let i = 0; i < endpointTypes.length; i++) { let endpointTypeId = await queryImpexp.importEndpointType( db, - sessionId, + sessionPartitionInfo[0].sessionPartitionId, allZclPackageIds, endpointTypes[i] ) @@ -1392,6 +1411,18 @@ async function jsonDataLoader( defaultTemplateFile ) { // Initially clean up all the packages from the session. + let sessionPartitions = + await querySession.getAllSessionPartitionInfoForSession(db, sessionId) + let sessionPartitionIds = sessionPartitions.map((sp) => sp.sessionPartitionId) + await queryPackage.deleteAllSessionPackages(db, sessionPartitionIds) + let sessionPartitionIndex = 0 + + let allPartitionPackages = state.package.filter( + (pkg) => + pkg.type == dbEnum.packageType.zclProperties || + pkg.type == dbEnum.packageType.genTemplatesJson || + pkg.type == dbEnum.packageType.zclXmlStandalone + ) // Loading all packages before custom xml to make sure clusterExtensions are // handled properly @@ -1408,31 +1439,56 @@ async function jsonDataLoader( defaultZclMetafile, defaultTemplateFile ) + + await querySession.insertSessionPartitions( + db, + sessionId, + allPartitionPackages.length + ) + let sessionPartitionInfo = await querySession.getSessionPartitionInfo( + db, + sessionId, + allPartitionPackages.length + ) + mainPackageData.sessionId = sessionId let mainPackagePromise = [] - mainPackagePromise.push( - queryPackage.insertSessionPackage( - db, - sessionId, - mainPackageData.zclPackageId + for (let i = 0; i < mainPackageData.zclPackageIds.length; i++) { + mainPackagePromise.push( + queryPackage.insertSessionPackage( + db, + sessionPartitionInfo[sessionPartitionIndex].sessionPartitionId, + mainPackageData.zclPackageIds[i] + ) ) - ) + sessionPartitionIndex++ + } if (mainPackageData.templateIds.length > 0) { mainPackageData.templateIds.forEach((templateId) => { mainPackagePromise.push( - queryPackage.insertSessionPackage(db, sessionId, templateId) + queryPackage.insertSessionPackage( + db, + sessionPartitionInfo[sessionPartitionIndex].sessionPartitionId, + templateId + ) ) + sessionPartitionIndex++ }) } if (mainPackageData.optionalIds.length > 0) { - mainPackageData.optionalIds.forEach((optionalId) => + mainPackageData.optionalIds.forEach((optionalId) => { mainPackagePromise.push( - queryPackage.insertSessionPackage(db, sessionId, optionalId) + queryPackage.insertSessionPackage( + db, + sessionPartitionInfo[sessionPartitionIndex].sessionPartitionId, + optionalId + ) ) - ) + sessionPartitionIndex++ + }) } await Promise.all(mainPackagePromise) @@ -1505,12 +1561,30 @@ async function jsonDataLoader( // packageData: { sessionId, packageId, otherIds, optionalIds} let optionalPackagePromises = [] - if (standAlonePackageData.optionalIds.length > 0) { - standAlonePackageData.optionalIds.forEach((optionalId) => - optionalPackagePromises.push( - queryPackage.insertSessionPackage(db, sessionId, optionalId) - ) - ) + if ( + standAlonePackageData.optionalIds && + standAlonePackageData.optionalIds.length > 0 + ) { + let optionalIds = standAlonePackageData.optionalIds + for (let i = 0; i < optionalIds.length; i++) { + let sessionPartitionInfoForNewPackage = + await querySession.selectSessionPartitionInfoFromPackageId( + db, + sessionId, + optionalIds[i] + ) + // Loading only those packages which have not been loaded + if (sessionPartitionInfoForNewPackage.length == 0) { + optionalPackagePromises.push( + queryPackage.insertSessionPackage( + db, + sessionPartitionInfo[sessionPartitionIndex].sessionPartitionId, + optionalIds[i] + ) + ) + sessionPartitionIndex++ + } + } } await Promise.all(optionalPackagePromises) @@ -1525,7 +1599,7 @@ async function jsonDataLoader( if ('endpointTypes' in state) { const allZclPackageIds = [] - allZclPackageIds.push(mainPackageData.zclPackageId) + allZclPackageIds.push(mainPackageData.zclPackageIds) allZclPackageIds.push(...existingCustomXmlPackageIds) allZclPackageIds.push(...newlyLoadedCustomPackageIds) promisesStage1.push( @@ -1564,24 +1638,34 @@ async function jsonDataLoader( pkg.version ) - if (validSessionPkgId != null && invalidSessionPkgs.length) { - await Promise.all( - invalidSessionPkgs.map((y) => { - env.logDebug( - `Disabling/removing invalid session package. sessionId(${sessionId}), packageId(${y.id}), path(${y.path})` + if (validSessionPkgId != null && invalidSessionPkgs.length > 0) { + for (let i = 0; i < invalidSessionPkgs.length; i++) { + let sessionPartitionInfoCurrent = + await querySession.selectSessionPartitionInfoFromPackageId( + db, + sessionId, + invalidSessionPkgs[i].id ) - return queryPackage.deleteSessionPackage(db, sessionId, y.id) - }) - ) + env.logDebug( + `Disabling/removing invalid session package. sessionId(${sessionId}), packageId(${invalidSessionPkgs[i].id}), path(${invalidSessionPkgs[i].path})` + ) + await queryPackage.deleteSessionPackage( + db, + sessionPartitionInfoCurrent[0].sessionPartitionId, + invalidSessionPkgs[i].id + ) + sessionPartitionIndex-- + } env.logDebug( `Enabling session package. sessionId(${sessionId}), packageId(${validSessionPkgId})` ) await queryPackage.insertSessionPackage( db, - sessionId, + sessionPartitionInfo[sessionPartitionIndex].sessionPartitionId, validSessionPkgId ) + sessionPartitionIndex++ } }) ) @@ -1589,7 +1673,7 @@ async function jsonDataLoader( return { sessionId: mainPackageData.sessionId, - zclPackageId: mainPackageData.zclPackageId, + zclPackageId: mainPackageData.zclPackageIds, templateIds: mainPackageData.templateIds, errors: [], warnings: [], diff --git a/src-electron/main-process/startup.js b/src-electron/main-process/startup.js index 809c13e009..d0ada6862d 100644 --- a/src-electron/main-process/startup.js +++ b/src-electron/main-process/startup.js @@ -572,10 +572,10 @@ async function generateSingleFile( sessionId, options ) - let usedTemplatePackageId = templatePackageId + let usedTemplatePackageIds = [] for (let pkg of sessPkg) { if (pkg.type === dbEnum.packageType.genTemplatesJson) { - usedTemplatePackageId = pkg.packageRef + usedTemplatePackageIds.push(pkg.packageRef) } } @@ -584,20 +584,27 @@ async function generateSingleFile( options.fileLoadTime = nsDuration - let genResult = await generatorEngine.generateAndWriteFiles( - db, - sessionId, - usedTemplatePackageId, - output, - options - ) + if (usedTemplatePackageIds.length === 0) { + usedTemplatePackageIds = [templatePackageId] + } + let genResults = [] + for (let i = 0; i < usedTemplatePackageIds.length; i++) { + let genResult = await generatorEngine.generateAndWriteFiles( + db, + sessionId, + usedTemplatePackageIds[i], + output, + options + ) - if (genResult.hasErrors) { - console.log(JSON.stringify(genResult.errors)) - throw new Error(`Generation failed: ${zapFile}`) + if (genResult.hasErrors) { + console.log(JSON.stringify(genResult.errors)) + throw new Error(`Generation failed: ${zapFile}`) + } + genResults.push(genResult) } - return genResult + return genResults } /** diff --git a/src-electron/rest/endpoint.js b/src-electron/rest/endpoint.js index 973e1a51f1..c6b9f80e4a 100644 --- a/src-electron/rest/endpoint.js +++ b/src-electron/rest/endpoint.js @@ -23,6 +23,7 @@ const queryEndpointType = require('../db/query-endpoint-type.js') const queryEndpoint = require('../db/query-endpoint.js') const queryConfig = require('../db/query-config.js') +const querySession = require('../db/query-session.js') const validation = require('../validation/validation.js') const restApi = require('../../src-shared/rest-api.js') const notification = require('../db/query-session-notification.js') @@ -169,10 +170,17 @@ function httpPostEndpointType(db) { return async (request, response) => { let { name, deviceTypeRef, deviceIdentifier, deviceVersion } = request.body let sessionId = request.zapSessionId + // Get session partition given the device type reference + let sessionPartitionInfo = + await querySession.selectSessionPartitionInfoFromDeviceType( + db, + sessionId, + deviceTypeRef + ) try { let newId = await queryConfig.insertEndpointType( db, - sessionId, + sessionPartitionInfo[0], name, deviceTypeRef, deviceIdentifier, diff --git a/src-electron/rest/initialize.js b/src-electron/rest/initialize.js index b25734da8d..f2c9b5f5d8 100644 --- a/src-electron/rest/initialize.js +++ b/src-electron/rest/initialize.js @@ -44,8 +44,15 @@ function sessionAttempt(db) { if (filePath.includes('.zap')) { let data = await fsp.readFile(filePath) let obj = JSON.parse(data) - let category = obj.package[0].category - if (category) { + let category = [] + let zapFilePackages = obj.package + zapFilePackages.forEach((pkg) => { + let pkgCategory = "'" + pkg.category + "'" + if (!category.includes(pkgCategory)) { + category.push(pkgCategory) + } + }) + if (category.length > 0) { let open = true const zclProperties = await queryPackage.getPackagesByCategoryAndType( db, @@ -64,6 +71,7 @@ function sessionAttempt(db) { zclProperties, sessions, filePath, + zapFilePackages, open, }) } else { @@ -147,23 +155,27 @@ function sessionCreate(db) { } else { pkgArray = [] } - - querySession + let partitionsLength = + (zclProperties && zclProperties.length ? zclProperties.length : 0) + + (genTemplate && genTemplate.length ? genTemplate.length : 0) + await querySession .ensureZapUserAndSession(db, userKey, sessionUuid, { sessionId: zapSessionId, userId: zapUserId, + partitions: partitionsLength, }) .then((result) => { req.session.zapUserId = result.userId req.session.zapSessionId[sessionUuid] = result.sessionId req.zapSessionId = result.sessionId + req.zapSessionPartitions = result.partitions return result }) .then((result) => { return util.ensurePackagesAndPopulateSessionOptions( db, result.sessionId, - null, + { partitions: result.partitions }, pkgArray, genTemplate ) diff --git a/src-electron/rest/static-zcl.js b/src-electron/rest/static-zcl.js index 4c3aeffadf..be2011c066 100644 --- a/src-electron/rest/static-zcl.js +++ b/src-electron/rest/static-zcl.js @@ -107,7 +107,17 @@ function reduceAndConcatenateZclEntity( ) } -function parseForZclData(db, entity, id, packageIdArray) { +async function parseForZclData(db, entity, id, packageIdArray) { + // Retrieve all the standalone custom xml packages + let packageData = await queryPackage.getPackagesByPackageIds( + db, + packageIdArray + ) + let standalonePackages = packageData.filter( + (pd) => pd.type === dbEnum.packageType.zclXmlStandalone + ) + let standAlonePackageIds = standalonePackages.map((sp) => sp.id) + switch (entity) { case 'atomics': return reduceAndConcatenateZclEntity( @@ -117,21 +127,50 @@ function parseForZclData(db, entity, id, packageIdArray) { zclEntityQuery(queryZcl.selectAllAtomics, queryZcl.selectAtomicById) ) case 'cluster': - return reduceAndConcatenateZclEntity( - db, - id, - packageIdArray, - returnZclEntitiesForClusterId, - mergeZclClusterAttributeCommandEventData, - { clusterData: [], attributeData: [], commandData: [], eventData: [] } - ).then((data) => { - return { - clusterData: data.clusterData, - attributeData: data.attributeData, - commandData: data.commandData, - eventData: data.eventData, - } - }) + // Making sure that global attributes are being collected from packages + // related to the cluster package when querying by clusterId. + // eg: do not need matter global attributes for a zigbee cluster + return queryZcl + .selectClusterById(db, id) + .then((clusterInfo) => + id == 'all' + ? reduceAndConcatenateZclEntity( + db, + id, + packageIdArray, + returnZclEntitiesForClusterId, + mergeZclClusterAttributeCommandEventData, + { + clusterData: [], + attributeData: [], + commandData: [], + eventData: [], + } + ) + : reduceAndConcatenateZclEntity( + db, + id, + standAlonePackageIds.includes(clusterInfo.packageRef) // Use packageId array if cluster belongs to standalone xml(custom cluster) else use just the package from the cluster. + ? packageIdArray + : [...standAlonePackageIds, clusterInfo.packageRef], // Taking cluster package and custom xml into account. Using a set since a cluster may sometimes be a custom one as well thus duplicating this array. + returnZclEntitiesForClusterId, + mergeZclClusterAttributeCommandEventData, + { + clusterData: [], + attributeData: [], + commandData: [], + eventData: [], + } + ) + ) + .then((data) => { + return { + clusterData: data.clusterData, + attributeData: data.attributeData, + commandData: data.commandData, + eventData: data.eventData, + } + }) case 'domain': return reduceAndConcatenateZclEntity( db, diff --git a/src-electron/rest/user-data.js b/src-electron/rest/user-data.js index 645f88df8e..a17a78fe4b 100644 --- a/src-electron/rest/user-data.js +++ b/src-electron/rest/user-data.js @@ -543,12 +543,31 @@ function httpPostAddNewPackage(db) { err: data.err.message, } } else { - await queryPackage.insertSessionPackage( - db, - sessionId, - data.packageId, - false - ) + // Check if session partition for package exists. If not then add it. + let sessionPartitionInfoForNewPackage = + await querySession.selectSessionPartitionInfoFromPackageId( + db, + sessionId, + data.packageId + ) + if (sessionPartitionInfoForNewPackage.length == 0) { + let sessionPartitionInfo = + await querySession.getAllSessionPartitionInfoForSession( + db, + sessionId + ) + let sessionPartitionId = await querySession.insertSessionPartition( + db, + sessionId, + sessionPartitionInfo.length + 1 + ) + await queryPackage.insertSessionPackage( + db, + sessionPartitionId, + data.packageId, + true + ) + } status = { isValid: true, sessionId: sessionId, @@ -840,9 +859,15 @@ function attributeEquals(a, b) { function httpDeleteSessionPackage(db) { return async (request, response) => { let { sessionRef, packageRef } = request.query + let sessionPartitionInfo = + await querySession.selectSessionPartitionInfoFromPackageId( + db, + sessionRef, + packageRef + ) let removed = await queryPackage.deleteSessionPackage( db, - sessionRef, + sessionPartitionInfo[0].sessionPartitionId, packageRef ) diff --git a/src-electron/util/env.js b/src-electron/util/env.js index 2f0ab3c759..5284ee7c9e 100644 --- a/src-electron/util/env.js +++ b/src-electron/util/env.js @@ -47,6 +47,12 @@ export function builtinDotdotZclMetafile() { return locateProjectResource('./zcl-builtin/dotdot/library.xml') } +export function builtinMatterZclMetafile2() { + return locateProjectResource( + './zcl-builtin/matter/zcl-with-test-extensions.json' + ) +} + export function builtinTemplateMetafile() { return null // No default. } diff --git a/src-electron/util/util.js b/src-electron/util/util.js index 86900ec730..4bf859e0be 100644 --- a/src-electron/util/util.js +++ b/src-electron/util/util.js @@ -75,6 +75,8 @@ async function ensurePackagesAndPopulateSessionOptions( zclFile = options.zcl } else { zclFile = selectedZclPropertyPackage.path + ? selectedZclPropertyPackage.path + : selectedZclPropertyPackage[0].path } // 0. Read current packages. let currentPackages = @@ -91,155 +93,271 @@ async function ensurePackagesAndPopulateSessionOptions( }) // 1. Associate a zclProperties file. + let sessionPartitionIndex = 0 + let sessionPartitionInfo = + await querySession.getAllSessionPartitionInfoForSession(db, sessionId) if (!hasZclPackage) { - let zclPropertiesPromise = queryPackage - .getPackagesByType(db, dbEnum.packageType.zclProperties) - .then((rows) => { - let packageId - if (selectedZclPropertyPackage) { - packageId = selectedZclPropertyPackage.id - } else if (rows.length == 1) { - packageId = rows[0].id - env.logDebug( - `Single zcl.properties found, using it for the session: ${packageId}` - ) - } else if (rows.length == 0) { - env.logError(`No zcl.properties found for session.`) - queryNotification.setNotification( - db, - 'WARNING', - `No zcl.properties found for session.`, - sessionId, - 2, - 0 - ) - packageId = null - } else { - rows.forEach((p) => { - if (path.resolve(zclFile) === p.path) { - packageId = p.id - } - }) - env.logWarning( - `${sessionId}, ${zclFile}: Multiple toplevel zcl.properties found. Using the first one from args: ${packageId}` - ) - queryNotification.setNotification( - db, - 'WARNING', - `${sessionId}, ${zclFile}: Multiple toplevel zcl.properties found. Using the first one from args: ${packageId}`, - sessionId, - 2, - 0 - ) - } - if (packageId != null) { - return queryPackage.insertSessionPackage( + if (selectedZclPropertyPackage && selectedZclPropertyPackage.length > 1) { + console.log( + `Multiple zcl.properties selected, using them for a multiprotocol configuration: ` + + JSON.stringify(selectedZclPropertyPackage) + ) + for (let i = 0; i < selectedZclPropertyPackage.length; i++) { + promises.push( + queryPackage.insertSessionPackage( db, - sessionId, - packageId, + sessionPartitionInfo[sessionPartitionIndex].sessionPartitionId, + selectedZclPropertyPackage[i].id, true ) - } - }) - promises.push(zclPropertiesPromise) + ) + sessionPartitionIndex++ + } + } else { + let zclPropertiesPromise = queryPackage + .getPackagesByType(db, dbEnum.packageType.zclProperties) + .then((rows) => { + let packageId + if ( + selectedZclPropertyPackage && + selectedZclPropertyPackage.length > 0 + ) { + packageId = selectedZclPropertyPackage[0].id + } else if (rows.length == 1) { + packageId = rows[0].id + env.logDebug( + `Single zcl.properties found, using it for the session: ${packageId}` + ) + } else if (rows.length == 0) { + env.logError(`No zcl.properties found for session.`) + queryNotification.setNotification( + db, + 'WARNING', + `No zcl.properties found for session.`, + sessionId, + 2, + 0 + ) + packageId = null + } else { + rows.forEach((p) => { + // If no zcl file is selected then pick the first one available + if (!zclFile) { + zclFile = p.path + } + if (path.resolve(zclFile) === p.path) { + packageId = p.id + } + }) + env.logWarning( + `${sessionId}, ${zclFile}: Multiple toplevel zcl.properties found. Using the first one from args: ${packageId}` + ) + queryNotification.setNotification( + db, + 'WARNING', + `${sessionId}, ${zclFile}: Multiple toplevel zcl.properties found. Using the first one from args: ${packageId}`, + sessionId, + 2, + 0 + ) + } + if (packageId != null) { + if (sessionPartitionInfo.length == 0) { + sessionPartitionIndex++ + return querySession + .insertSessionPartition(db, sessionId, sessionPartitionIndex) + .then((sessionPartitionId) => + queryPackage.insertSessionPackage( + db, + sessionPartitionId, + packageId, + true + ) + ) + } else { + sessionPartitionIndex++ + return querySession + .getAllSessionPartitionInfoForSession(db, sessionId) + .then((sessionPartitionInfo) => + queryPackage.insertSessionPackage( + db, + sessionPartitionInfo[sessionPartitionIndex - 1] + .sessionPartitionId, + packageId, + true + ) + ) + } + } + }) + promises.push(zclPropertiesPromise) + } } // 2. Associate gen template files if (!hasGenTemplate) { - let genTemplateJsonPromise = queryPackage - .getPackagesByType(db, dbEnum.packageType.genTemplatesJson) - .then((rows) => { - let packageId - if (selectedGenTemplatePackages?.length > 0) { - selectedGenTemplatePackages.forEach((gen) => { - if (gen) { - packageId = gen - } else if (rows.length == 1) { - packageId = rows[0].id - env.logDebug( - `Single generation template metafile found, using it for the session: ${packageId}` - ) - } else if (rows.length == 0) { - env.logInfo(`No generation template metafile found for session.`) - packageId = null - } else { - rows.forEach((p) => { - if ( - selectedGenTemplatePackages != null && - path.resolve(selectedGenTemplatePackages) === p.path - ) { - packageId = p.id - } - }) - if (packageId != null) { - env.logWarning( - `Multiple toplevel generation template metafiles found. Using the one from args: ${packageId}` - ) - queryNotification.setNotification( - db, - 'WARNING', - `Multiple toplevel generation template metafiles found. Using the one from args: ${packageId}`, - sessionId, - 2, - 0 - ) - } else { + if (selectedGenTemplatePackages && selectedGenTemplatePackages.length > 1) { + console.log( + `Multiple generation templates selected, using them for a multiprotocol configuration: ` + + JSON.stringify(selectedGenTemplatePackages) + ) + for (let i = 0; i < selectedGenTemplatePackages.length; i++) { + promises.push( + queryPackage.insertSessionPackage( + db, + sessionPartitionInfo[sessionPartitionIndex].sessionPartitionId, + selectedGenTemplatePackages[i], + true + ) + ) + sessionPartitionIndex++ + } + } else { + let genTemplateJsonPromise = queryPackage + .getPackagesByType(db, dbEnum.packageType.genTemplatesJson) + .then((rows) => { + let packageId + if ( + selectedGenTemplatePackages && + selectedGenTemplatePackages.length > 0 + ) { + selectedGenTemplatePackages.forEach((gen) => { + if (gen) { + packageId = gen + } else if (rows.length == 1) { packageId = rows[0].id - env.logWarning( - `Multiple toplevel generation template metafiles found. Using the first one.` + env.logDebug( + `Single generation template metafile found, using it for the session: ${packageId}` ) - queryNotification.setNotification( - db, - 'WARNING', - `Multiple toplevel generation template metafiles found. Using the first one.`, - sessionId, - 2, - 0 + } else if (rows.length == 0) { + env.logInfo( + `No generation template metafile found for session.` ) + packageId = null + } else { + rows.forEach((p) => { + if ( + selectedGenTemplatePackages != null && + path.resolve(selectedGenTemplatePackages) === p.path + ) { + packageId = p.id + } + }) + if (packageId != null) { + env.logWarning( + `Multiple toplevel generation template metafiles found. Using the one from args: ${packageId}` + ) + queryNotification.setNotification( + db, + 'WARNING', + `Multiple toplevel generation template metafiles found. Using the one from args: ${packageId}`, + sessionId, + 2, + 0 + ) + } else { + packageId = rows[0].id + env.logWarning( + `Multiple toplevel generation template metafiles found. Using the first one.` + ) + queryNotification.setNotification( + db, + 'WARNING', + `Multiple toplevel generation template metafiles found. Using the first one.`, + sessionId, + 2, + 0 + ) + } } - } - if (packageId != null) { - return queryPackage.insertSessionPackage( - db, - sessionId, - packageId, - true + if (packageId != null) { + if (sessionPartitionInfo.length == 0) { + sessionPartitionIndex++ + return querySession + .insertSessionPartition( + db, + sessionId, + sessionPartitionIndex + ) + .then((sessionPartitionId) => + queryPackage.insertSessionPackage( + db, + sessionPartitionId, + packageId, + true + ) + ) + } else { + sessionPartitionIndex++ + return querySession + .getAllSessionPartitionInfoForSession(db, sessionId) + .then((sessionPartitionInfo) => + queryPackage.insertSessionPackage( + db, + sessionPartitionInfo[sessionPartitionIndex - 1] + .sessionPartitionId, + packageId, + true + ) + ) + } + } + }) + } + if (packageId == null && rows.length > 0) { + // If package id is not resolved and there are gen-template packages available, + // find one with matching category. if nothing is found, blindly pick the first one available + + let packageId + if ( + selectedZclPropertyPackage && + selectedZclPropertyPackage.length > 0 + ) { + const matchBySelectedCategory = rows.find( + (r) => r?.category === selectedZclPropertyPackage[0].category ) + packageId = matchBySelectedCategory?.id || rows[0].id + } else { + packageId = rows[0].id } - }) - } - if (packageId == null && rows.length > 0) { - // If package id is not resolved and there are gen-template packages available, - // find one with matching category. if nothing is found, blindly pick the first one available - let packageId - if (selectedZclPropertyPackage) { - const matchBySelectedCategory = rows.find( - (r) => r?.category === selectedZclPropertyPackage.category - ) - packageId = matchBySelectedCategory?.id || rows[0].id - } else { - packageId = rows[0].id + if (sessionPartitionInfo.length == 0) { + sessionPartitionIndex++ + return querySession + .insertSessionPartition(db, sessionId, sessionPartitionIndex) + .then((sessionPartitionId) => + queryPackage.insertSessionPackage( + db, + sessionPartitionId, + packageId, + true + ) + ) + } else { + sessionPartitionIndex++ + return querySession + .getAllSessionPartitionInfoForSession(db, sessionId) + .then((sessionPartitionInfo) => + queryPackage.insertSessionPackage( + db, + sessionPartitionInfo[sessionPartitionIndex - 1] + .sessionPartitionId, + packageId, + true + ) + ) + } } - - return queryPackage.insertSessionPackage( - db, - sessionId, - packageId, - true - ) - } - }) - promises.push(genTemplateJsonPromise) + }) + promises.push(genTemplateJsonPromise) + } } if (promises.length > 0) await Promise.all(promises) - // We read all the packages. let packages = await queryPackage.getSessionPackagesWithTypes(db, sessionId) // Now we create promises with the queries that populate the // session key/value pairs from package options. - await populateSessionPackageOptions(db, sessionId, packages) return packages } diff --git a/src-electron/zcl/zcl-loader-silabs.js b/src-electron/zcl/zcl-loader-silabs.js index 035f7e4951..f04b61dab0 100644 --- a/src-electron/zcl/zcl-loader-silabs.js +++ b/src-electron/zcl/zcl-loader-silabs.js @@ -21,6 +21,7 @@ const path = require('path') const properties = require('properties') const dbApi = require('../db/db-api') const queryPackage = require('../db/query-package') +const querySession = require('../db/query-session') const queryDeviceType = require('../db/query-device-type') const queryLoader = require('../db/query-loader') const queryZcl = require('../db/query-zcl') @@ -2155,7 +2156,10 @@ async function parseTextDefaults(db, pkgRef, textDefaults) { }) .then((specificValue) => { if (specificValue == null) { - throw `Default value for: ${optionCategory}/${txt} does not match an option.` + env.logWarning( + 'Default value for: ${optionCategory}/${txt} does not match an option for packageId: ' + + pkgRef + ) } else { return queryPackage.insertDefaultOptionValue( db, @@ -2226,6 +2230,28 @@ async function loadIndividualSilabsFile(db, filePath, sessionId) { if (result.data) { result.result = await util.parseXml(result.data) delete result.data + // Just adding the cluster attribute and command extensions for a cluster + // because they can be related to any top level package in the .zap config + if ( + result.customXmlReload && + result.result.configurator && + result.result.configurator.clusterExtension + ) { + result.result = { + configurator: { + clusterExtension: result.result.configurator.clusterExtension, + }, + } + } else if ( + result.customXmlReload && + result.result.configurator && + !result.result.configurator.clusterExtension + ) { + env.logDebug( + `CRC match for file ${result.filePath} (${result.crc}), skipping parsing.` + ) + delete result.result + } } let sessionPackages = await queryPackage.getSessionZclPackages( db, @@ -2242,6 +2268,28 @@ async function loadIndividualSilabsFile(db, filePath, sessionId) { if (promise != null && promise != undefined) return promise() }) ) + // Check if session partition for package exists. If not then add it. + let sessionPartitionInfoForNewPackage = + await querySession.selectSessionPartitionInfoFromPackageId( + db, + sessionId, + pkgId + ) + if (sessionPartitionInfoForNewPackage.length == 0) { + let sessionPartitionInfo = + await querySession.getAllSessionPartitionInfoForSession(db, sessionId) + let sessionPartitionId = await querySession.insertSessionPartition( + db, + sessionId, + sessionPartitionInfo.length + 1 + ) + await queryPackage.insertSessionPackage( + db, + sessionPartitionId, + pkgId, + true + ) + } await zclLoader.processZclPostLoading(db, pkgId) return { succeeded: true, packageId: pkgId } } catch (err) { @@ -2371,7 +2419,6 @@ async function loadZclJsonOrProperties(db, metafile, isJson = false) { `\n\nUnknown cluster "${clusterName}" in attributeAccessInterfaceAttributes\n\n` ) } - let known_cluster_attributes = await queryZcl.selectAttributesByClusterIdIncludingGlobal( db, diff --git a/src-electron/zcl/zcl-loader.js b/src-electron/zcl/zcl-loader.js index 2f8016d864..b096a0b09a 100644 --- a/src-electron/zcl/zcl-loader.js +++ b/src-electron/zcl/zcl-loader.js @@ -186,6 +186,16 @@ async function qualifyZclFile( } else { // This is executed if CRC is found in the database. if (pkg.crc == actualCrc) { + // Sending data back when it is a custom xml + if (parentPackageId == null) { + return { + filePath: filePath, + data: data, + packageId: pkg.id, + customXmlReload: true, + crc: actualCrc, + } + } env.logDebug( `CRC match for file ${pkg.path} (${pkg.crc}), skipping parsing.` ) @@ -201,7 +211,7 @@ async function qualifyZclFile( return { filePath: filePath, data: data, - packageId: parentPackageId == null ? packageId : parentPackageId, + packageId: parentPackageId == null ? pkg.id : parentPackageId, // Changing from package to pkg.id since package is not defined } } } diff --git a/src/App.vue b/src/App.vue index a7c3f3c9b1..aa9e1a6f89 100644 --- a/src/App.vue +++ b/src/App.vue @@ -137,7 +137,13 @@ export default defineComponent({ }, uiThemeCategory: { get() { - return this.$store.state.zap.selectedZapConfig?.zclProperties.category + let zclProps = this.$store.state.zap.selectedZapConfig?.zclProperties + // Picking the first category in the case of multi-protocol(zigbee/matter) + if (Array.isArray(zclProps) && zclProps.length > 0) { + return zclProps[0].category + } else { + return this.$store.state.zap.selectedZapConfig?.zclProperties.category + } }, }, }, diff --git a/src/components/ZCLToolbar.vue b/src/components/ZCLToolbar.vue index a340438464..36090a3e14 100644 --- a/src/components/ZCLToolbar.vue +++ b/src/components/ZCLToolbar.vue @@ -9,7 +9,12 @@ >
- +
0 @@ -220,19 +228,41 @@ export default { return this.$store.state.zap.debugNavBar }, }, - getLogo: { + getLogos: { get() { - if (this.$store.state.zap.selectedZapConfig?.zclProperties.category) { - return ( - '/' + - this.$store.state.zap.selectedZapConfig?.zclProperties.category + - '_logo' + - (this.$q.dark.isActive ? '_white' : '') + - '.svg' - ) + let zclProperties = this.$store.state.zap.selectedZapConfig + ? this.$store.state.zap.selectedZapConfig.zclProperties + : null + let logos = [] + if (Array.isArray(zclProperties)) { + for (let i = 0; i < zclProperties.length; i++) { + if (zclProperties[i].category) { + logos.push( + '/' + + zclProperties[i].category + + '_logo' + + (this.$q.dark.isActive ? '_white' : '') + + '.svg' + ) + } else { + logos.push('/zap_logo.png') + } + } } else { - return '/zap_logo.png' + if (zclProperties && zclProperties.category) { + logos.push( + '/' + + this.$store.state.zap.selectedZapConfig?.zclProperties[0] + .category + + '_logo' + + (this.$q.dark.isActive ? '_white' : '') + + '.svg' + ) + } else { + logos.push('/zap_logo.png') + } } + return logos }, }, }, @@ -371,4 +401,8 @@ export default { .window-button-padding-right { padding-right: calc(100vw - env(titlebar-area-width, 100vw) + 2px); } + +.image-space { + margin-right: 15px; +} diff --git a/src/components/ZclClusterManager.vue b/src/components/ZclClusterManager.vue index 21be16d0d7..4653acc0e1 100644 --- a/src/components/ZclClusterManager.vue +++ b/src/components/ZclClusterManager.vue @@ -185,13 +185,23 @@ export default { }, relevantClusters: { get() { - return this.clusters.filter((cluster) => - this.filterString == '' - ? true - : cluster.label - .toLowerCase() - .includes(this.filterString.toLowerCase()) - ) + if (this.clusters.clusterData) { + return this.clusters.clusterData.filter((cluster) => + this.filterString == '' + ? true + : cluster.label + .toLowerCase() + .includes(this.filterString.toLowerCase()) + ) + } else { + return this.clusters.filter((cluster) => + this.filterString == '' + ? true + : cluster.label + .toLowerCase() + .includes(this.filterString.toLowerCase()) + ) + } }, }, enabledClusters: { diff --git a/src/components/ZclCreateModifyEndpoint.vue b/src/components/ZclCreateModifyEndpoint.vue index 83f1c1049f..4948c81aad 100644 --- a/src/components/ZclCreateModifyEndpoint.vue +++ b/src/components/ZclCreateModifyEndpoint.vue @@ -28,7 +28,7 @@ limitations under the License. ref="endpoint" outlined class="col v-step-1" - :rules="[reqInteger, reqPosInt, reqUniqueEndpoint]" + :rules="[reqInteger, reqPosInt]" min="0" /> console.log('Error in newEpt: ' + err.message)) }, editEpt(shownEndpoint, endpointReference) { let endpointTypeReference = this.endpointType[this.endpointReference] @@ -662,6 +664,7 @@ export default { deviceTypeRef: deviceTypeRef, }) this.$store.dispatch('zap/updateSelectedEndpoint', this.endpointReference) + this.$store.dispatch('zap/updateClusters') }, getDeviceOptionLabel(item) { if (item == null || item.deviceTypeRef == null) return '' diff --git a/src/components/ZclCustomZclView.vue b/src/components/ZclCustomZclView.vue index 4d1f09845b..b4118723b4 100644 --- a/src/components/ZclCustomZclView.vue +++ b/src/components/ZclCustomZclView.vue @@ -30,6 +30,14 @@ limitations under the License. You can use this functionality to add custom ZCL clusters or commands to the Zigbee Clusters Configurator +

+ Warning: Custom xml is currently not supported for multi-protocol + configurations. +

{ + this.$store.dispatch('zap/updateZclDeviceTypes') + }) + }, }, methods: { getFileName(path) { @@ -290,6 +306,15 @@ export default { let key = type == 'ERROR' ? 'errors' : 'warnings' return this.notisData[packageId][key] }, + // Custom xml currently not supported for multi-protocol + enableExtensionsWarning() { + let categories = + this.$store.state.zap.selectedZapConfig?.zclProperties.map( + (zclProp) => zclProp.category + ) + // Showing extensions when the zcl packages have less than 1 category + return categories.length > 1 + }, }, mounted() { if (this.$serverGet != null) { @@ -299,9 +324,6 @@ export default { (value) => { if (value.context == 'customXml') { this.packageToLoad = value.filePaths[0] - this.loadNewPackage().then(() => { - this.$store.dispatch('zap/updateZclDeviceTypes') - }) } } ) diff --git a/src/layouts/ZclConfiguratorLayout.vue b/src/layouts/ZclConfiguratorLayout.vue index cd1ea03c78..b6aa63c5cf 100644 --- a/src/layouts/ZclConfiguratorLayout.vue +++ b/src/layouts/ZclConfiguratorLayout.vue @@ -223,13 +223,27 @@ export default { }, uiThemeCategory: { get() { - return this.$store.state.zap.selectedZapConfig?.zclProperties.category + let zclProps = this.$store.state.zap.selectedZapConfig?.zclProperties + // Picking the first category in the case of multi-protocol(zigbee/matter) + if (Array.isArray(zclProps) && zclProps.length > 0) { + return zclProps[0].category + } else { + return this.$store.state.zap.selectedZapConfig?.zclProperties.category + } }, }, description: { get() { - return this.$store.state.zap.selectedZapConfig?.zclProperties - .description + // Picking the first description in the case of multi-protocol(zigbee/matter) + if ( + Array.isArray(this.$store.state.zap.selectedZapConfig?.zclProperties) + ) { + return this.$store.state.zap.selectedZapConfig?.zclProperties[0] + .description + } else { + return this.$store.state.zap.selectedZapConfig?.zclProperties + .description + } }, }, miniState: { diff --git a/src/pages/EndpointManager.vue b/src/pages/EndpointManager.vue index a4a87e84e4..d6105b84c9 100644 --- a/src/pages/EndpointManager.vue +++ b/src/pages/EndpointManager.vue @@ -103,7 +103,13 @@ export default { }, uiThemeCategory: { get() { - return this.$store.state.zap.selectedZapConfig?.zclProperties.category + let zclProps = this.$store.state.zap.selectedZapConfig?.zclProperties + // Picking the first category in the case of multi-protocol(zigbee/matter) + if (Array.isArray(zclProps) && zclProps.length > 0) { + return zclProps[0].category + } else { + return this.$store.state.zap.selectedZapConfig?.zclProperties.category + } }, }, miniState: { diff --git a/src/pages/ZapConfig.vue b/src/pages/ZapConfig.vue index 766c478c95..1a66a86091 100644 --- a/src/pages/ZapConfig.vue +++ b/src/pages/ZapConfig.vue @@ -33,12 +33,37 @@ label="Restore Unsaved Session" /> +

+ Warning: Please select atleast one package each from ZCL metadata + and Templates. If a package is not selected then internal packages + used for testing will be loaded automatically. +

+

+ Warning: More than one ZCL packages with different categories have + been selected. You are initiating a ZAP configuration for + multi-protocol. +

+

+ Warning: Corresponding ZCL and Template packages are not enabled + based on the same category. +

There are multiple packages of ZCL metadata loaded. Please select - the one you wish to use with this configuration. + the one you wish to use with this configuration. Packages within + an existing .zap file will come pre-selected when available. + However please update the packages in case of a SDK upgrade such + that you are using the latest version of the packages.

These are sessions found in the database that were not saved into @@ -71,11 +96,9 @@