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 @@