From 0ed880587c518ab3d895ac158f25b7ae9bf98465 Mon Sep 17 00:00:00 2001 From: Philippe Coval Date: Tue, 28 Oct 2025 17:28:01 +0100 Subject: [PATCH 01/10] fix(ci): Release on tag push For some reason the step was skip, I believe a gh update caused that regression Signed-off-by: Philippe Coval --- .github/workflows/build-rootfs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-rootfs.yml b/.github/workflows/build-rootfs.yml index a48806909..49a8f0c2e 100644 --- a/.github/workflows/build-rootfs.yml +++ b/.github/workflows/build-rootfs.yml @@ -52,7 +52,7 @@ jobs: env: token-defined: ${{ secrets.GH_UNIFY_ACCESS_TOKEN != '' }} # yamllint disable-line rule:line-length - if: ${{ env.token-defined == true && startsWith(github.ref, 'refs/tags/') }} + if: github.ref_type == 'tag' && env.token-defined # yamllint disable-line rule:line-length uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 with: From 5d6e3e0c8fb9fdf0ae422295c27f726dd18f7318 Mon Sep 17 00:00:00 2001 From: Philippe Coval Date: Mon, 29 Sep 2025 14:26:27 +0200 Subject: [PATCH 02/10] Revert "NOJIRA: Rename color switch cc to cpp for clang support (#24)" This reverts commit 8d284db03c2490ec2af913f8c76e45f17d5eb3d3. Origin: https://github.com/SiliconLabsSoftware/z-wave-protocol-controller/pull/146 Signed-off-by: Philippe Coval --- .../zpc/components/zwave_command_classes/CMakeLists.txt | 2 +- ...lass_switch_color.cpp => zwave_command_class_switch_color.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename applications/zpc/components/zwave_command_classes/src/{zwave_command_class_switch_color.cpp => zwave_command_class_switch_color.c} (100%) diff --git a/applications/zpc/components/zwave_command_classes/CMakeLists.txt b/applications/zpc/components/zwave_command_classes/CMakeLists.txt index 2d4e7fe81..63a2b2e8c 100644 --- a/applications/zpc/components/zwave_command_classes/CMakeLists.txt +++ b/applications/zpc/components/zwave_command_classes/CMakeLists.txt @@ -46,7 +46,7 @@ add_library( src/zwave_command_class_supervision.c src/zwave_command_class_supervision_process.cpp src/zwave_command_class_sound_switch.c - src/zwave_command_class_switch_color.cpp + src/zwave_command_class_switch_color.c src/zwave_command_class_switch_multilevel.c src/zwave_command_class_thermostat_mode.c src/zwave_command_class_thermostat_fan_mode.c diff --git a/applications/zpc/components/zwave_command_classes/src/zwave_command_class_switch_color.cpp b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_switch_color.c similarity index 100% rename from applications/zpc/components/zwave_command_classes/src/zwave_command_class_switch_color.cpp rename to applications/zpc/components/zwave_command_classes/src/zwave_command_class_switch_color.c From 11ed4a5c95a3ca5c7b27a64d9fa2c9c9363d486f Mon Sep 17 00:00:00 2001 From: Philippe Coval Date: Mon, 29 Sep 2025 10:59:17 +0200 Subject: [PATCH 03/10] UIC-3272: Import Unify patches for ColorSwitch Origin: https://github.com/SiliconLabsSoftware/z-wave-protocol-controller/pull/146 Signed-off-by: Philippe Coval --- ...272-Generated-files-for-Switch-Color.patch | 7384 +++++++++++++++++ ...UIC-3272-Custom-Switch-Color-cluster.patch | 81 + .../0017-UIC-3272-Regen-zap-files.patch | 1073 +++ 3 files changed, 8538 insertions(+) create mode 100644 patches/UnifySDK/0015-UIC-3272-Generated-files-for-Switch-Color.patch create mode 100644 patches/UnifySDK/0016-UIC-3272-Custom-Switch-Color-cluster.patch create mode 100644 patches/UnifySDK/0017-UIC-3272-Regen-zap-files.patch diff --git a/patches/UnifySDK/0015-UIC-3272-Generated-files-for-Switch-Color.patch b/patches/UnifySDK/0015-UIC-3272-Generated-files-for-Switch-Color.patch new file mode 100644 index 000000000..1847144f1 --- /dev/null +++ b/patches/UnifySDK/0015-UIC-3272-Generated-files-for-Switch-Color.patch @@ -0,0 +1,7384 @@ +From 44fedc439961733d8ba06700d15975a0e4d45c41 Mon Sep 17 00:00:00 2001 +From: Viet +Date: Wed, 11 Sep 2024 18:06:50 +0700 +Subject: [PATCH] UIC-3272: Generated files for Switch Color + +--- + .../zap-generated/include/dotdot_mqtt.h | 511 ++++++ + .../include/dotdot_mqtt_attributes.h | 113 ++ + .../include/dotdot_mqtt_generated_commands.h | 64 + + .../include/dotdot_mqtt_group_commands.h | 49 + + .../include/dotdot_mqtt_send_commands.h | 78 + + ...dotdot_mqtt_supported_generated_commands.h | 30 + + .../zap-generated/src/dotdot_mqtt.cpp | 1462 +++++++++++++++++ + .../zap-generated/src/dotdot_mqtt.hpp | 66 + + .../src/dotdot_mqtt_attributes.cpp | 707 ++++++++ + .../src/dotdot_mqtt_command_helpers.cpp | 176 ++ + .../src/dotdot_mqtt_command_helpers.hpp | 82 + + .../src/dotdot_mqtt_generated_commands.cpp | 112 ++ + .../src/dotdot_mqtt_group_commands.cpp | 335 ++++ + .../zap-generated/src/dotdot_mqtt_helpers.cpp | 102 ++ + .../src/dotdot_mqtt_send_commands.cpp | 148 ++ + ...tdot_mqtt_supported_generated_commands.cpp | 49 + + .../test/dotdot_mqtt_test.include | 49 + + .../include/dotdot_attributes.uam | 10 + + .../include/dotdot_attributes_camel_case.uam | 10 + + .../unify_dotdot_attribute_store_helpers.h | 876 ++++++++++ + .../unify_dotdot_defined_attribute_types.h | 9 + + ...ot_attribute_store_attribute_publisher.cpp | 481 ++++++ + ..._force_read_attributes_command_callbacks.c | 67 + + .../unify_dotdot_attribute_store_helpers.cpp | 931 +++++++++++ + ...fy_dotdot_attribute_store_registration.cpp | 192 +++ + ...store_write_attributes_command_callbacks.c | 33 + + .../test/unify_dotdot_attribute_store_test.c | 158 ++ + .../test/unify_dotdot_attribute_store_test.h | 10 + + 28 files changed, 6910 insertions(+) + +diff --git a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt.h b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt.h +index 7106f0f0fc..650ce8ed54 100644 +--- a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt.h ++++ b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt.h +@@ -42337,6 +42337,517 @@ void uic_mqtt_dotdot_unify_humidity_control_publish_supported_commands( + void uic_mqtt_dotdot_unify_humidity_control_publish_empty_supported_commands( + const dotdot_unid_t unid + ,dotdot_endpoint_id_t endpoint); ++// Callback types used by the unify_switch_color cluster ++typedef sl_status_t (*uic_mqtt_dotdot_unify_switch_color_set_color_callback_t)( ++ dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint, ++ uic_mqtt_dotdot_callback_call_type_t call_type, ++ uint8_t color_component_id, ++ ++ uint8_t value, ++ ++ uint32_t duration ++ ++); ++typedef sl_status_t (*uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_t)( ++ dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint, ++ uic_mqtt_dotdot_callback_call_type_t call_type, ++ bool start_stop, ++ ++ bool up_down, ++ ++ bool ignor_start_level, ++ ++ uint8_t color_component_id, ++ ++ uint8_t start_level, ++ ++ uint32_t duration ++ ++); ++ ++typedef struct { ++ uint8_t warm_white; ++ uint8_t cold_white; ++ uint8_t red; ++ uint8_t green; ++ uint8_t blue; ++ uint8_t amber; ++ uint8_t cyan; ++ uint8_t purple; ++} uic_mqtt_dotdot_unify_switch_color_state_t; ++ ++typedef struct { ++ bool warm_white; ++ bool cold_white; ++ bool red; ++ bool green; ++ bool blue; ++ bool amber; ++ bool cyan; ++ bool purple; ++} uic_mqtt_dotdot_unify_switch_color_updated_state_t; ++ ++typedef sl_status_t (*uic_mqtt_dotdot_unify_switch_color_write_attributes_callback_t)( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint, ++ uic_mqtt_dotdot_callback_call_type_t call_type, ++ uic_mqtt_dotdot_unify_switch_color_state_t, ++ uic_mqtt_dotdot_unify_switch_color_updated_state_t ++); ++ ++typedef sl_status_t (*uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback_t)( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint, ++ uic_mqtt_dotdot_callback_call_type_t call_type, ++ uic_mqtt_dotdot_unify_switch_color_updated_state_t ++); ++ ++ ++/** ++ * @brief Command fields for UnifySwitchColor/SetColor ++ */ ++typedef struct { ++ uint8_t color_component_id; ++ ++ uint8_t value; ++ ++ uint32_t duration; ++} uic_mqtt_dotdot_unify_switch_color_command_set_color_fields_t; ++ ++/** ++ * @brief Command fields for UnifySwitchColor/StartStopChange ++ */ ++typedef struct { ++ bool start_stop; ++ ++ bool up_down; ++ ++ bool ignor_start_level; ++ ++ uint8_t color_component_id; ++ ++ uint8_t start_level; ++ ++ uint32_t duration; ++} uic_mqtt_dotdot_unify_switch_color_command_start_stop_change_fields_t; ++ ++ ++/** ++ * @brief Setup callback to be called when a ++ * UnifySwitchColor/Commands/set_color is received. ++ * ++ * Setting this callback will not overwrite the previous set callback ++ * @param callback Function to be called on command reception ++ */ ++void uic_mqtt_dotdot_unify_switch_color_set_color_callback_set(const uic_mqtt_dotdot_unify_switch_color_set_color_callback_t callback); ++/** ++ * @brief Unsets callback to be called when a ++ * UnifySwitchColor/Commands/set_color is received. ++ * ++ * @param callback Function to be no longer called on command reception ++ */ ++void uic_mqtt_dotdot_unify_switch_color_set_color_callback_unset(const uic_mqtt_dotdot_unify_switch_color_set_color_callback_t callback); ++/** ++ * @brief Clears all callbacks registered for when ++ * UnifySwitchColor/Commands/set_color is received. ++ */ ++void uic_mqtt_dotdot_unify_switch_color_set_color_callback_clear(); ++ ++/** ++ * @brief Setup callback to be called when a ++ * +/UnifySwitchColor/GeneratedCommands/set_color is received. ++ * ++ * Setting this callback will not overwrite the previous set callback ++ * @param callback Function to be called on command reception ++ */ ++void uic_mqtt_dotdot_unify_switch_color_generated_set_color_callback_set(const uic_mqtt_dotdot_unify_switch_color_set_color_callback_t callback); ++/** ++ * @brief Unsets callback to be called when a ++ * +/UnifySwitchColor/GeneratedCommands/set_color is received. ++ * @param callback Function to be no longer called on command reception ++ */ ++void uic_mqtt_dotdot_unify_switch_color_generated_set_color_callback_unset(const uic_mqtt_dotdot_unify_switch_color_set_color_callback_t callback); ++/** ++ * @brief Clears all callbacks registered for when ++ * +/UnifySwitchColor/GeneratedCommands/set_color is received. ++ */ ++void uic_mqtt_dotdot_unify_switch_color_generated_set_color_callback_clear(); ++/** ++ * @brief Setup callback to be called when a ++ * UnifySwitchColor/Commands/start_stop_change is received. ++ * ++ * Setting this callback will not overwrite the previous set callback ++ * @param callback Function to be called on command reception ++ */ ++void uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_set(const uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_t callback); ++/** ++ * @brief Unsets callback to be called when a ++ * UnifySwitchColor/Commands/start_stop_change is received. ++ * ++ * @param callback Function to be no longer called on command reception ++ */ ++void uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_unset(const uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_t callback); ++/** ++ * @brief Clears all callbacks registered for when ++ * UnifySwitchColor/Commands/start_stop_change is received. ++ */ ++void uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_clear(); ++ ++/** ++ * @brief Setup callback to be called when a ++ * +/UnifySwitchColor/GeneratedCommands/start_stop_change is received. ++ * ++ * Setting this callback will not overwrite the previous set callback ++ * @param callback Function to be called on command reception ++ */ ++void uic_mqtt_dotdot_unify_switch_color_generated_start_stop_change_callback_set(const uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_t callback); ++/** ++ * @brief Unsets callback to be called when a ++ * +/UnifySwitchColor/GeneratedCommands/start_stop_change is received. ++ * @param callback Function to be no longer called on command reception ++ */ ++void uic_mqtt_dotdot_unify_switch_color_generated_start_stop_change_callback_unset(const uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_t callback); ++/** ++ * @brief Clears all callbacks registered for when ++ * +/UnifySwitchColor/GeneratedCommands/start_stop_change is received. ++ */ ++void uic_mqtt_dotdot_unify_switch_color_generated_start_stop_change_callback_clear(); ++ ++/** ++ * @brief Setup a callback for WriteAttribute to be called when a ++ * +/unify_switch_color/Commands/WriteAttributes is received. ++ * ++ * Setting this callback will not overwrite the previous set callback ++ * @param callback Function to be called on command reception ++ */ ++void uic_mqtt_dotdot_set_unify_switch_color_write_attributes_callback( ++ const uic_mqtt_dotdot_unify_switch_color_write_attributes_callback_t callback ++); ++/** ++ * @brief Unsets a callback for WriteAttribute to be called when a ++ * +/unify_switch_color/Commands/WriteAttributes is received. ++ * @param callback Function to be no longer called on command reception ++ */ ++void uic_mqtt_dotdot_unset_unify_switch_color_write_attributes_callback( ++ const uic_mqtt_dotdot_unify_switch_color_write_attributes_callback_t callback ++); ++/** ++ * @brief Clears all callbacks registered for when ++ * +/unify_switch_color/Commands/WriteAttributes is received. ++ */ ++void uic_mqtt_dotdot_clear_unify_switch_color_write_attributes_callbacks(); ++ ++/** ++ * @brief Setup a callback for ForceReadAttributes to be called when a ++ * +/unify_switch_color/Commands/ForceReadAttributes is received. ++ * ++ * Setting this callback will not overwrite the previous set callback ++ * @param callback Function to be called on command reception ++ */ ++void uic_mqtt_dotdot_set_unify_switch_color_force_read_attributes_callback( ++ const uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback_t callback ++); ++/** ++ * @brief Unsets a callback for ForceReadAttributes to be called when a ++ * +/unify_switch_color/Commands/ForceReadAttributes is received. ++ * ++ * @param callback Function to be no longer called on command reception ++ */ ++void uic_mqtt_dotdot_unset_unify_switch_color_force_read_attributes_callback( ++ const uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback_t callback ++); ++/** ++ * @brief Clears all callbacks registered for when ++ * +/unify_switch_color/Commands/ForceReadAttributes is received. ++ */ ++void uic_mqtt_dotdot_clear_unify_switch_color_force_read_attributes_callbacks(); ++ ++/** ++ * @brief Publish the attribute; UnifySwitchColor/Attributes/WarmWhite ++ * ++ * @param base_topic topic prefix to publish, /warm_white ++ * will be appended ++ * @param value Value to publish ++ * @param publish_type Whether to publish as Desired, Reported, or Both. ++ * ++ * @returns SL_STATUS_OK on success ++ */ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_warm_white_publish( ++ const char *base_topic, ++ uint8_t value, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++); ++ ++/** ++ * @brief Unretains a published attribute; UnifySwitchColor/Attributes/WarmWhite ++ * ++ * @param base_topic topic prefix to publish, /warm_white ++ * will be appended ++ * @param publish_type Whether to publish as Desired, Reported, or Both. ++ * ++ * @returns SL_STATUS_OK on success ++ */ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_warm_white_unretain( ++ const char *base_topic, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++); ++ ++/** ++ * @brief Publish the attribute; UnifySwitchColor/Attributes/ColdWhite ++ * ++ * @param base_topic topic prefix to publish, /cold_white ++ * will be appended ++ * @param value Value to publish ++ * @param publish_type Whether to publish as Desired, Reported, or Both. ++ * ++ * @returns SL_STATUS_OK on success ++ */ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_cold_white_publish( ++ const char *base_topic, ++ uint8_t value, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++); ++ ++/** ++ * @brief Unretains a published attribute; UnifySwitchColor/Attributes/ColdWhite ++ * ++ * @param base_topic topic prefix to publish, /cold_white ++ * will be appended ++ * @param publish_type Whether to publish as Desired, Reported, or Both. ++ * ++ * @returns SL_STATUS_OK on success ++ */ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_cold_white_unretain( ++ const char *base_topic, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++); ++ ++/** ++ * @brief Publish the attribute; UnifySwitchColor/Attributes/Red ++ * ++ * @param base_topic topic prefix to publish, /red ++ * will be appended ++ * @param value Value to publish ++ * @param publish_type Whether to publish as Desired, Reported, or Both. ++ * ++ * @returns SL_STATUS_OK on success ++ */ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_red_publish( ++ const char *base_topic, ++ uint8_t value, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++); ++ ++/** ++ * @brief Unretains a published attribute; UnifySwitchColor/Attributes/Red ++ * ++ * @param base_topic topic prefix to publish, /red ++ * will be appended ++ * @param publish_type Whether to publish as Desired, Reported, or Both. ++ * ++ * @returns SL_STATUS_OK on success ++ */ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_red_unretain( ++ const char *base_topic, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++); ++ ++/** ++ * @brief Publish the attribute; UnifySwitchColor/Attributes/Green ++ * ++ * @param base_topic topic prefix to publish, /green ++ * will be appended ++ * @param value Value to publish ++ * @param publish_type Whether to publish as Desired, Reported, or Both. ++ * ++ * @returns SL_STATUS_OK on success ++ */ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_green_publish( ++ const char *base_topic, ++ uint8_t value, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++); ++ ++/** ++ * @brief Unretains a published attribute; UnifySwitchColor/Attributes/Green ++ * ++ * @param base_topic topic prefix to publish, /green ++ * will be appended ++ * @param publish_type Whether to publish as Desired, Reported, or Both. ++ * ++ * @returns SL_STATUS_OK on success ++ */ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_green_unretain( ++ const char *base_topic, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++); ++ ++/** ++ * @brief Publish the attribute; UnifySwitchColor/Attributes/Blue ++ * ++ * @param base_topic topic prefix to publish, /blue ++ * will be appended ++ * @param value Value to publish ++ * @param publish_type Whether to publish as Desired, Reported, or Both. ++ * ++ * @returns SL_STATUS_OK on success ++ */ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_blue_publish( ++ const char *base_topic, ++ uint8_t value, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++); ++ ++/** ++ * @brief Unretains a published attribute; UnifySwitchColor/Attributes/Blue ++ * ++ * @param base_topic topic prefix to publish, /blue ++ * will be appended ++ * @param publish_type Whether to publish as Desired, Reported, or Both. ++ * ++ * @returns SL_STATUS_OK on success ++ */ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_blue_unretain( ++ const char *base_topic, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++); ++ ++/** ++ * @brief Publish the attribute; UnifySwitchColor/Attributes/Amber ++ * ++ * @param base_topic topic prefix to publish, /amber ++ * will be appended ++ * @param value Value to publish ++ * @param publish_type Whether to publish as Desired, Reported, or Both. ++ * ++ * @returns SL_STATUS_OK on success ++ */ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_amber_publish( ++ const char *base_topic, ++ uint8_t value, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++); ++ ++/** ++ * @brief Unretains a published attribute; UnifySwitchColor/Attributes/Amber ++ * ++ * @param base_topic topic prefix to publish, /amber ++ * will be appended ++ * @param publish_type Whether to publish as Desired, Reported, or Both. ++ * ++ * @returns SL_STATUS_OK on success ++ */ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_amber_unretain( ++ const char *base_topic, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++); ++ ++/** ++ * @brief Publish the attribute; UnifySwitchColor/Attributes/Cyan ++ * ++ * @param base_topic topic prefix to publish, /cyan ++ * will be appended ++ * @param value Value to publish ++ * @param publish_type Whether to publish as Desired, Reported, or Both. ++ * ++ * @returns SL_STATUS_OK on success ++ */ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_cyan_publish( ++ const char *base_topic, ++ uint8_t value, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++); ++ ++/** ++ * @brief Unretains a published attribute; UnifySwitchColor/Attributes/Cyan ++ * ++ * @param base_topic topic prefix to publish, /cyan ++ * will be appended ++ * @param publish_type Whether to publish as Desired, Reported, or Both. ++ * ++ * @returns SL_STATUS_OK on success ++ */ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_cyan_unretain( ++ const char *base_topic, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++); ++ ++/** ++ * @brief Publish the attribute; UnifySwitchColor/Attributes/Purple ++ * ++ * @param base_topic topic prefix to publish, /purple ++ * will be appended ++ * @param value Value to publish ++ * @param publish_type Whether to publish as Desired, Reported, or Both. ++ * ++ * @returns SL_STATUS_OK on success ++ */ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_purple_publish( ++ const char *base_topic, ++ uint8_t value, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++); ++ ++/** ++ * @brief Unretains a published attribute; UnifySwitchColor/Attributes/Purple ++ * ++ * @param base_topic topic prefix to publish, /purple ++ * will be appended ++ * @param publish_type Whether to publish as Desired, Reported, or Both. ++ * ++ * @returns SL_STATUS_OK on success ++ */ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_purple_unretain( ++ const char *base_topic, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++); ++ ++ ++/** ++ * @brief Publish the UnifySwitchColor/ClusterRevision attribute ++ * ++ * @param base_topic topic prefix to publish, /UnifySwitchColor/Attributes/ClusterRevision ++ * will be appended. ++ * @param value Value to publish. ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_cluster_revision(const char* base_topic, uint16_t value); ++ ++/** ++ * @brief Unretain a publication to UnifySwitchColor/ClusterRevision attribute ++ * ++ * @param base_topic topic prefix to publish, /UnifySwitchColor/Attributes/ClusterRevision ++ * will be appended. ++ */ ++void uic_mqtt_dotdot_unify_switch_color_unretain_cluster_revision(const char* base_topic); ++ ++/** ++ * @brief Publish the SupportedCommands for UNID/EndPoint for the UnifySwitchColor Cluster ++ * ++ * This function will iterate over all Commands in the UnifySwitchColor Cluster and ++ * call all registered callback functions with UNID/endpoint, and ++ * callback_type = UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK. ++ * All Cluster Command callback functions that return SL_STATUS_OK ++ * will be added to the list of supported commands and published. ++ * ++ * @param unid ++ * @param endpoint ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_supported_commands( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint); ++ ++/** ++ * @brief Publish an empty array of SupportedCommands for UNID/EndPoint for ++ * the UnifySwitchColor Cluster ++ * ++ * @param unid ++ * @param endpoint ) ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_empty_supported_commands( ++ const dotdot_unid_t unid ++ ,dotdot_endpoint_id_t endpoint); + + /** + * @brief Publish the SupportedCommands for UNID/EndPoint +diff --git a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_attributes.h b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_attributes.h +index 9f094654e3..8cba2ecb59 100644 +--- a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_attributes.h ++++ b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_attributes.h +@@ -5230,6 +5230,63 @@ typedef sl_status_t (*uic_mqtt_dotdot_unify_humidity_control_attribute_auto_setp + uic_mqtt_dotdot_attribute_update_type_t update_type, + uint8_t auto_setpoint_precision + ); ++// Callback types used by the unify_switch_color cluster ++typedef sl_status_t (*uic_mqtt_dotdot_unify_switch_color_attribute_warm_white_callback_t)( ++ dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint, ++ bool unretained, ++ uic_mqtt_dotdot_attribute_update_type_t update_type, ++ uint8_t warm_white ++); ++typedef sl_status_t (*uic_mqtt_dotdot_unify_switch_color_attribute_cold_white_callback_t)( ++ dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint, ++ bool unretained, ++ uic_mqtt_dotdot_attribute_update_type_t update_type, ++ uint8_t cold_white ++); ++typedef sl_status_t (*uic_mqtt_dotdot_unify_switch_color_attribute_red_callback_t)( ++ dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint, ++ bool unretained, ++ uic_mqtt_dotdot_attribute_update_type_t update_type, ++ uint8_t red ++); ++typedef sl_status_t (*uic_mqtt_dotdot_unify_switch_color_attribute_green_callback_t)( ++ dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint, ++ bool unretained, ++ uic_mqtt_dotdot_attribute_update_type_t update_type, ++ uint8_t green ++); ++typedef sl_status_t (*uic_mqtt_dotdot_unify_switch_color_attribute_blue_callback_t)( ++ dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint, ++ bool unretained, ++ uic_mqtt_dotdot_attribute_update_type_t update_type, ++ uint8_t blue ++); ++typedef sl_status_t (*uic_mqtt_dotdot_unify_switch_color_attribute_amber_callback_t)( ++ dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint, ++ bool unretained, ++ uic_mqtt_dotdot_attribute_update_type_t update_type, ++ uint8_t amber ++); ++typedef sl_status_t (*uic_mqtt_dotdot_unify_switch_color_attribute_cyan_callback_t)( ++ dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint, ++ bool unretained, ++ uic_mqtt_dotdot_attribute_update_type_t update_type, ++ uint8_t cyan ++); ++typedef sl_status_t (*uic_mqtt_dotdot_unify_switch_color_attribute_purple_callback_t)( ++ dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint, ++ bool unretained, ++ uic_mqtt_dotdot_attribute_update_type_t update_type, ++ uint8_t purple ++); + + #ifdef __cplusplus + extern "C" { +@@ -10054,6 +10111,62 @@ void uic_mqtt_dotdot_unify_humidity_control_attribute_auto_setpoint_scale_callba + void uic_mqtt_dotdot_unify_humidity_control_attribute_auto_setpoint_precision_callback_set(const uic_mqtt_dotdot_unify_humidity_control_attribute_auto_setpoint_precision_callback_t callback); + + ++/** ++ * Initializes the attributes features for the UnifySwitchColor cluster, ++ * allowing to receive attribute updates from other UNIDs. ++ */ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_attributes_init(); ++ ++/** ++ * Setup callback to be called when a ++ * UnifySwitchColor/Attributes/warm_white/# is received. Setting ++ * this callback will overwrite the previous set callback ++ */ ++void uic_mqtt_dotdot_unify_switch_color_attribute_warm_white_callback_set(const uic_mqtt_dotdot_unify_switch_color_attribute_warm_white_callback_t callback); ++/** ++ * Setup callback to be called when a ++ * UnifySwitchColor/Attributes/cold_white/# is received. Setting ++ * this callback will overwrite the previous set callback ++ */ ++void uic_mqtt_dotdot_unify_switch_color_attribute_cold_white_callback_set(const uic_mqtt_dotdot_unify_switch_color_attribute_cold_white_callback_t callback); ++/** ++ * Setup callback to be called when a ++ * UnifySwitchColor/Attributes/red/# is received. Setting ++ * this callback will overwrite the previous set callback ++ */ ++void uic_mqtt_dotdot_unify_switch_color_attribute_red_callback_set(const uic_mqtt_dotdot_unify_switch_color_attribute_red_callback_t callback); ++/** ++ * Setup callback to be called when a ++ * UnifySwitchColor/Attributes/green/# is received. Setting ++ * this callback will overwrite the previous set callback ++ */ ++void uic_mqtt_dotdot_unify_switch_color_attribute_green_callback_set(const uic_mqtt_dotdot_unify_switch_color_attribute_green_callback_t callback); ++/** ++ * Setup callback to be called when a ++ * UnifySwitchColor/Attributes/blue/# is received. Setting ++ * this callback will overwrite the previous set callback ++ */ ++void uic_mqtt_dotdot_unify_switch_color_attribute_blue_callback_set(const uic_mqtt_dotdot_unify_switch_color_attribute_blue_callback_t callback); ++/** ++ * Setup callback to be called when a ++ * UnifySwitchColor/Attributes/amber/# is received. Setting ++ * this callback will overwrite the previous set callback ++ */ ++void uic_mqtt_dotdot_unify_switch_color_attribute_amber_callback_set(const uic_mqtt_dotdot_unify_switch_color_attribute_amber_callback_t callback); ++/** ++ * Setup callback to be called when a ++ * UnifySwitchColor/Attributes/cyan/# is received. Setting ++ * this callback will overwrite the previous set callback ++ */ ++void uic_mqtt_dotdot_unify_switch_color_attribute_cyan_callback_set(const uic_mqtt_dotdot_unify_switch_color_attribute_cyan_callback_t callback); ++/** ++ * Setup callback to be called when a ++ * UnifySwitchColor/Attributes/purple/# is received. Setting ++ * this callback will overwrite the previous set callback ++ */ ++void uic_mqtt_dotdot_unify_switch_color_attribute_purple_callback_set(const uic_mqtt_dotdot_unify_switch_color_attribute_purple_callback_t callback); ++ ++ + #ifdef __cplusplus + } + #endif // __cplusplus +diff --git a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_generated_commands.h b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_generated_commands.h +index 96e33e47d2..e1f17dad77 100644 +--- a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_generated_commands.h ++++ b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_generated_commands.h +@@ -5461,6 +5461,70 @@ void uic_mqtt_dotdot_unify_humidity_control_publish_generated_write_attributes_c + uic_mqtt_dotdot_unify_humidity_control_updated_state_t attribute_list + ); + ++/** ++ * @brief Publishes an incoming/generated SetColor command for ++ * the UnifySwitchColor cluster. ++ * ++ * Publication will be made at the following topic ++ * ucl/by-unid/UNID/epID/UnifySwitchColor/GeneratedCommands/SetColor ++ * ++ * @param unid The UNID of the node that sent us the command. ++ * ++ * @param endpoint The Endpoint ID of the node that sent us the command. ++ * ++ * ++ * @param fields Struct pointer with the fields value of the command ++ * ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_generated_set_color_command( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint, ++ const uic_mqtt_dotdot_unify_switch_color_command_set_color_fields_t *fields ++ ++); ++/** ++ * @brief Publishes an incoming/generated StartStopChange command for ++ * the UnifySwitchColor cluster. ++ * ++ * Publication will be made at the following topic ++ * ucl/by-unid/UNID/epID/UnifySwitchColor/GeneratedCommands/StartStopChange ++ * ++ * @param unid The UNID of the node that sent us the command. ++ * ++ * @param endpoint The Endpoint ID of the node that sent us the command. ++ * ++ * ++ * @param fields Struct pointer with the fields value of the command ++ * ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_generated_start_stop_change_command( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint, ++ const uic_mqtt_dotdot_unify_switch_color_command_start_stop_change_fields_t *fields ++ ++); ++ ++/** ++ * @brief Publishes an incoming/generated WriteAttributes command for ++ * the UnifySwitchColor cluster. ++ * ++ * Publication will be made at the following topic ++ * ucl/by-unid/UNID/epID/UnifySwitchColor/GeneratedCommands/WriteAttributes ++ * ++ * @param unid The UNID of the node that sent us the command. ++ * ++ * @param endpoint The Endpoint ID of the node that sent us the command. ++ * ++ * @param attribute_values Values to assign to the attributes ++ * @param attribute_list List of attributes that are written ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_generated_write_attributes_command( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint, ++ uic_mqtt_dotdot_unify_switch_color_state_t attribute_values, ++ uic_mqtt_dotdot_unify_switch_color_updated_state_t attribute_list ++); ++ + + #ifdef __cplusplus + } +diff --git a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_group_commands.h b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_group_commands.h +index e052483320..6bf8346dae 100644 +--- a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_group_commands.h ++++ b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_group_commands.h +@@ -4073,6 +4073,55 @@ void uic_mqtt_dotdot_by_group_unify_humidity_control_write_attributes_callback_s + + + ++/** ++ * @brief Callback signature for by-group UnifySwitchColor::SetColor command. ++ */ ++typedef void (*uic_mqtt_dotdot_by_group_unify_switch_color_set_color_callback_t)( ++ const dotdot_group_id_t group_id, ++ const uic_mqtt_dotdot_unify_switch_color_command_set_color_fields_t *fields ++); ++ ++/** ++ * Setup handler to be called when a ++ * ucl/by-group/+/UnifySwitchColor/set_color is received. ++ * Setting this callback will overwrite the previous set callback. ++ * ++ */ ++void uic_mqtt_dotdot_by_group_unify_switch_color_set_color_callback_set(const uic_mqtt_dotdot_by_group_unify_switch_color_set_color_callback_t callback); ++ ++/** ++ * @brief Callback signature for by-group UnifySwitchColor::StartStopChange command. ++ */ ++typedef void (*uic_mqtt_dotdot_by_group_unify_switch_color_start_stop_change_callback_t)( ++ const dotdot_group_id_t group_id, ++ const uic_mqtt_dotdot_unify_switch_color_command_start_stop_change_fields_t *fields ++); ++ ++/** ++ * Setup handler to be called when a ++ * ucl/by-group/+/UnifySwitchColor/start_stop_change is received. ++ * Setting this callback will overwrite the previous set callback. ++ * ++ */ ++void uic_mqtt_dotdot_by_group_unify_switch_color_start_stop_change_callback_set(const uic_mqtt_dotdot_by_group_unify_switch_color_start_stop_change_callback_t callback); ++ ++typedef void (*uic_mqtt_dotdot_by_group_unify_switch_color_write_attributes_callback_t)( ++ const dotdot_group_id_t group_id, ++ uic_mqtt_dotdot_unify_switch_color_state_t, ++ uic_mqtt_dotdot_unify_switch_color_updated_state_t ++); ++ ++/** ++ * Setup a callback for WriteAttribute to be called when a ++ * ucl/by-group/+/unify_switch_color/Commands/WriteAttributes is received. ++ * Setting this callback will overwrite any previously set callback. ++ */ ++void uic_mqtt_dotdot_by_group_unify_switch_color_write_attributes_callback_set( ++ const uic_mqtt_dotdot_by_group_unify_switch_color_write_attributes_callback_t callback ++); ++ ++ ++ + #ifdef __cplusplus + } + #endif // __cplusplus +diff --git a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_send_commands.h b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_send_commands.h +index 3d8d69ac9e..fdbeda4042 100644 +--- a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_send_commands.h ++++ b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_send_commands.h +@@ -7926,6 +7926,84 @@ void uic_mqtt_dotdot_unify_humidity_control_publish_setpoint_set_command_to_grou + const uic_mqtt_dotdot_unify_humidity_control_command_setpoint_set_fields_t *fields + + ); ++/** ++ * @brief Sends/Publishes a SetColor command for ++ * the UnifySwitchColor cluster to a destination. ++ * ++ * Publication will be made at the following topic ++ * ucl/by-unid/UNID/epID/UnifySwitchColor/Commands/SetColor ++ * ++ * @param destination_unid The UNID of the node that should receive the command. ++ * ++ * @param destination_endpoint The Endpoint ID of the node that should receive the command. ++ * ++ * ++ * @param fields Struct pointer with the fields value of the command ++ * ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_set_color_command( ++ const dotdot_unid_t destination_unid, ++ const dotdot_endpoint_id_t destination_endpoint, ++ const uic_mqtt_dotdot_unify_switch_color_command_set_color_fields_t *fields ++ ++); ++ ++/** ++ * @brief Sends/Publishes a SetColor command for ++ * the UnifySwitchColor cluster to a group. ++ * ++ * Publication will be made at the following topic ++ * ucl/by-group/GroupID/UnifySwitchColor/Commands/SetColor ++ * ++ * @param destination_group_id The GroupID that should receive the command. ++ * ++ * @param fields Struct pointer with the fields value of the command ++ * ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_set_color_command_to_group( ++ uint16_t destination_group_id, ++ const uic_mqtt_dotdot_unify_switch_color_command_set_color_fields_t *fields ++ ++); ++/** ++ * @brief Sends/Publishes a StartStopChange command for ++ * the UnifySwitchColor cluster to a destination. ++ * ++ * Publication will be made at the following topic ++ * ucl/by-unid/UNID/epID/UnifySwitchColor/Commands/StartStopChange ++ * ++ * @param destination_unid The UNID of the node that should receive the command. ++ * ++ * @param destination_endpoint The Endpoint ID of the node that should receive the command. ++ * ++ * ++ * @param fields Struct pointer with the fields value of the command ++ * ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_start_stop_change_command( ++ const dotdot_unid_t destination_unid, ++ const dotdot_endpoint_id_t destination_endpoint, ++ const uic_mqtt_dotdot_unify_switch_color_command_start_stop_change_fields_t *fields ++ ++); ++ ++/** ++ * @brief Sends/Publishes a StartStopChange command for ++ * the UnifySwitchColor cluster to a group. ++ * ++ * Publication will be made at the following topic ++ * ucl/by-group/GroupID/UnifySwitchColor/Commands/StartStopChange ++ * ++ * @param destination_group_id The GroupID that should receive the command. ++ * ++ * @param fields Struct pointer with the fields value of the command ++ * ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_start_stop_change_command_to_group( ++ uint16_t destination_group_id, ++ const uic_mqtt_dotdot_unify_switch_color_command_start_stop_change_fields_t *fields ++ ++); + + + #ifdef __cplusplus +diff --git a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_supported_generated_commands.h b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_supported_generated_commands.h +index 4c1c15b4eb..7872bdcec3 100644 +--- a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_supported_generated_commands.h ++++ b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_supported_generated_commands.h +@@ -1742,6 +1742,36 @@ void uic_mqtt_dotdot_unify_humidity_control_publish_supported_generated_commands + ); + + ++/** ++ * @brief Struct containing the list of commands for UnifySwitchColor ++ */ ++typedef struct _uic_mqtt_dotdot_unify_switch_color_supported_commands_ { ++ bool set_color; ++ bool start_stop_change; ++ bool write_attributes; ++} uic_mqtt_dotdot_unify_switch_color_supported_commands_t; ++ ++/** ++ * @brief Sends/Publishes a the SupportedGenerated commands for ++ * the UnifySwitchColor cluster for a UNID/Endpoint ++ * ++ * Publication will be made at the following topic ++ * ucl/by-unid/UNID/epID/UnifySwitchColor/SupportedGeneratedCommands ++ * ++ * @param unid The UNID of the node on behalf of which the advertisment is made ++ * ++ * @param endpoint The Endpoint ID of the node on behalf of which the advertisment is made ++ * ++ * @param command_list Struct pointer with the fields value indicating if ++ * individual commands can be generated. ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_supported_generated_commands( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint, ++ const uic_mqtt_dotdot_unify_switch_color_supported_commands_t *command_list ++); ++ ++ + + #ifdef __cplusplus + } +diff --git a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.cpp b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.cpp +index 2ad8e173db..0a2f0bbdb7 100644 +--- a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.cpp ++++ b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.cpp +@@ -99777,6 +99777,1164 @@ sl_status_t uic_mqtt_dotdot_unify_humidity_control_init() + return SL_STATUS_OK; + } + ++// Callbacks pointers ++static std::set uic_mqtt_dotdot_unify_switch_color_set_color_callback; ++static std::set uic_mqtt_dotdot_unify_switch_color_generated_set_color_callback; ++static std::set uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback; ++static std::set uic_mqtt_dotdot_unify_switch_color_generated_start_stop_change_callback; ++static std::set uic_mqtt_dotdot_unify_switch_color_write_attributes_callback; ++static std::set uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback; ++ ++// Callbacks setters ++void uic_mqtt_dotdot_unify_switch_color_set_color_callback_set(const uic_mqtt_dotdot_unify_switch_color_set_color_callback_t callback) ++{ ++ if (callback != nullptr) { ++ uic_mqtt_dotdot_unify_switch_color_set_color_callback.insert(callback); ++ } ++} ++void uic_mqtt_dotdot_unify_switch_color_set_color_callback_unset(const uic_mqtt_dotdot_unify_switch_color_set_color_callback_t callback) ++{ ++ uic_mqtt_dotdot_unify_switch_color_set_color_callback.erase(callback); ++} ++void uic_mqtt_dotdot_unify_switch_color_set_color_callback_clear() ++{ ++ uic_mqtt_dotdot_unify_switch_color_set_color_callback.clear(); ++} ++std::set& get_uic_mqtt_dotdot_unify_switch_color_set_color_callback() ++{ ++ return uic_mqtt_dotdot_unify_switch_color_set_color_callback; ++} ++ ++void uic_mqtt_dotdot_unify_switch_color_generated_set_color_callback_set(const uic_mqtt_dotdot_unify_switch_color_set_color_callback_t callback) ++{ ++ if (callback != nullptr) { ++ uic_mqtt_dotdot_unify_switch_color_generated_set_color_callback.insert(callback); ++ } ++} ++void uic_mqtt_dotdot_unify_switch_color_generated_set_color_callback_unset(const uic_mqtt_dotdot_unify_switch_color_set_color_callback_t callback) ++{ ++ uic_mqtt_dotdot_unify_switch_color_generated_set_color_callback.erase(callback); ++} ++void uic_mqtt_dotdot_unify_switch_color_generated_set_color_callback_clear() ++{ ++ uic_mqtt_dotdot_unify_switch_color_generated_set_color_callback.clear(); ++} ++void uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_set(const uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_t callback) ++{ ++ if (callback != nullptr) { ++ uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback.insert(callback); ++ } ++} ++void uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_unset(const uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_t callback) ++{ ++ uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback.erase(callback); ++} ++void uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_clear() ++{ ++ uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback.clear(); ++} ++std::set& get_uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback() ++{ ++ return uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback; ++} ++ ++void uic_mqtt_dotdot_unify_switch_color_generated_start_stop_change_callback_set(const uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_t callback) ++{ ++ if (callback != nullptr) { ++ uic_mqtt_dotdot_unify_switch_color_generated_start_stop_change_callback.insert(callback); ++ } ++} ++void uic_mqtt_dotdot_unify_switch_color_generated_start_stop_change_callback_unset(const uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_t callback) ++{ ++ uic_mqtt_dotdot_unify_switch_color_generated_start_stop_change_callback.erase(callback); ++} ++void uic_mqtt_dotdot_unify_switch_color_generated_start_stop_change_callback_clear() ++{ ++ uic_mqtt_dotdot_unify_switch_color_generated_start_stop_change_callback.clear(); ++} ++ ++void uic_mqtt_dotdot_set_unify_switch_color_write_attributes_callback( ++ const uic_mqtt_dotdot_unify_switch_color_write_attributes_callback_t callback) ++{ ++ if (callback != nullptr) { ++ uic_mqtt_dotdot_unify_switch_color_write_attributes_callback.insert(callback); ++ } ++} ++void uic_mqtt_dotdot_unset_unify_switch_color_write_attributes_callback( ++ const uic_mqtt_dotdot_unify_switch_color_write_attributes_callback_t callback) ++{ ++ uic_mqtt_dotdot_unify_switch_color_write_attributes_callback.erase(callback); ++} ++void uic_mqtt_dotdot_clear_unify_switch_color_write_attributes_callbacks() ++{ ++ uic_mqtt_dotdot_unify_switch_color_write_attributes_callback.clear(); ++} ++std::set& get_uic_mqtt_dotdot_unify_switch_color_write_attributes_callback() ++{ ++ return uic_mqtt_dotdot_unify_switch_color_write_attributes_callback; ++} ++ ++void uic_mqtt_dotdot_set_unify_switch_color_force_read_attributes_callback( ++ const uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback_t callback) ++{ ++ if (callback != nullptr) { ++ uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback.insert(callback); ++ } ++} ++void uic_mqtt_dotdot_unset_unify_switch_color_force_read_attributes_callback( ++ const uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback_t callback) ++{ ++ uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback.erase(callback); ++} ++void uic_mqtt_dotdot_clear_unify_switch_color_force_read_attributes_callbacks() ++{ ++ uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback.clear(); ++} ++ ++ ++// Callback function for incoming publications on ucl/by-unid/+/+/UnifySwitchColor/Commands/SetColor ++void uic_mqtt_dotdot_on_unify_switch_color_set_color( ++ const char *topic, ++ const char *message, ++ const size_t message_length) ++{ ++ if (message_length == 0 || (uic_mqtt_dotdot_unify_switch_color_set_color_callback.empty())) { ++ return; ++ } ++ ++ std::string unid; ++ uint8_t endpoint = 0; // Default value for endpoint-less topics. ++ if(! uic_dotdot_mqtt::parse_topic(topic,unid,endpoint)) { ++ sl_log_debug(LOG_TAG, ++ "Error parsing UNID / Endpoint ID from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ uint8_t color_component_id = {}; ++ uint8_t value = {}; ++ uint32_t duration = {}; ++ ++ ++ nlohmann::json jsn; ++ try { ++ jsn = nlohmann::json::parse(std::string(message)); ++ ++ ++ uic_mqtt_dotdot_parse_unify_switch_color_set_color( ++ jsn, ++ color_component_id, ++ ++ value, ++ ++ duration ++ ); ++ ++ } catch (const nlohmann::json::parse_error& e) { ++ // Catch JSON object field parsing errors ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_PARSE_FAIL, "UnifySwitchColor", "SetColor"); ++ return; ++ } catch (const nlohmann::json::exception& e) { ++ // Catch JSON object field parsing errors ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor", "SetColor", e.what()); ++ return; ++ } catch (const std::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor", "SetColor", ""); ++ return; ++ } ++ ++ ++ ++ for (const auto& callback: uic_mqtt_dotdot_unify_switch_color_set_color_callback){ ++ callback( ++ static_cast(unid.c_str()), ++ endpoint, ++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL, ++ color_component_id, ++ ++ value, ++ ++ duration ++ ++ ); ++ } ++ ++} ++ ++// Callback function for incoming publications on ucl/by-unid/+/+/UnifySwitchColor/GeneratedCommands/SetColor ++static void uic_mqtt_dotdot_on_generated_unify_switch_color_set_color( ++ const char *topic, ++ const char *message, ++ const size_t message_length) ++{ ++ if (message_length == 0 || (uic_mqtt_dotdot_unify_switch_color_generated_set_color_callback.empty())) { ++ return; ++ } ++ ++ std::string unid; ++ uint8_t endpoint = 0; // Default value for endpoint-less topics. ++ if(! uic_dotdot_mqtt::parse_topic(topic,unid,endpoint)) { ++ sl_log_debug(LOG_TAG, ++ "Error parsing UNID / Endpoint ID from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ uint8_t color_component_id = {}; ++ uint8_t value = {}; ++ uint32_t duration = {}; ++ ++ ++ nlohmann::json jsn; ++ try { ++ jsn = nlohmann::json::parse(std::string(message)); ++ ++ ++ uic_mqtt_dotdot_parse_unify_switch_color_set_color( ++ jsn, ++ color_component_id, ++ ++ value, ++ ++ duration ++ ); ++ ++ } catch (const nlohmann::json::parse_error& e) { ++ // Catch JSON object field parsing errors ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_PARSE_FAIL, "UnifySwitchColor", "SetColor"); ++ return; ++ } catch (const nlohmann::json::exception& e) { ++ // Catch JSON object field parsing errors ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor", "SetColor", e.what()); ++ return; ++ } catch (const std::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor", "SetColor", ""); ++ return; ++ } ++ ++ ++ ++ ++ for (const auto& callback: uic_mqtt_dotdot_unify_switch_color_generated_set_color_callback){ ++ callback( ++ static_cast(unid.c_str()), ++ endpoint, ++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL, ++ color_component_id, ++ ++ value, ++ ++ duration ++ ++ ); ++ } ++} ++ ++ ++// Callback function for incoming publications on ucl/by-unid/+/+/UnifySwitchColor/Commands/StartStopChange ++void uic_mqtt_dotdot_on_unify_switch_color_start_stop_change( ++ const char *topic, ++ const char *message, ++ const size_t message_length) ++{ ++ if (message_length == 0 || (uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback.empty())) { ++ return; ++ } ++ ++ std::string unid; ++ uint8_t endpoint = 0; // Default value for endpoint-less topics. ++ if(! uic_dotdot_mqtt::parse_topic(topic,unid,endpoint)) { ++ sl_log_debug(LOG_TAG, ++ "Error parsing UNID / Endpoint ID from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ bool start_stop = {}; ++ bool up_down = {}; ++ bool ignor_start_level = {}; ++ uint8_t color_component_id = {}; ++ uint8_t start_level = {}; ++ uint32_t duration = {}; ++ ++ ++ nlohmann::json jsn; ++ try { ++ jsn = nlohmann::json::parse(std::string(message)); ++ ++ ++ uic_mqtt_dotdot_parse_unify_switch_color_start_stop_change( ++ jsn, ++ start_stop, ++ ++ up_down, ++ ++ ignor_start_level, ++ ++ color_component_id, ++ ++ start_level, ++ ++ duration ++ ); ++ ++ } catch (const nlohmann::json::parse_error& e) { ++ // Catch JSON object field parsing errors ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_PARSE_FAIL, "UnifySwitchColor", "StartStopChange"); ++ return; ++ } catch (const nlohmann::json::exception& e) { ++ // Catch JSON object field parsing errors ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor", "StartStopChange", e.what()); ++ return; ++ } catch (const std::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor", "StartStopChange", ""); ++ return; ++ } ++ ++ ++ ++ for (const auto& callback: uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback){ ++ callback( ++ static_cast(unid.c_str()), ++ endpoint, ++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL, ++ start_stop, ++ ++ up_down, ++ ++ ignor_start_level, ++ ++ color_component_id, ++ ++ start_level, ++ ++ duration ++ ++ ); ++ } ++ ++} ++ ++// Callback function for incoming publications on ucl/by-unid/+/+/UnifySwitchColor/GeneratedCommands/StartStopChange ++static void uic_mqtt_dotdot_on_generated_unify_switch_color_start_stop_change( ++ const char *topic, ++ const char *message, ++ const size_t message_length) ++{ ++ if (message_length == 0 || (uic_mqtt_dotdot_unify_switch_color_generated_start_stop_change_callback.empty())) { ++ return; ++ } ++ ++ std::string unid; ++ uint8_t endpoint = 0; // Default value for endpoint-less topics. ++ if(! uic_dotdot_mqtt::parse_topic(topic,unid,endpoint)) { ++ sl_log_debug(LOG_TAG, ++ "Error parsing UNID / Endpoint ID from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ bool start_stop = {}; ++ bool up_down = {}; ++ bool ignor_start_level = {}; ++ uint8_t color_component_id = {}; ++ uint8_t start_level = {}; ++ uint32_t duration = {}; ++ ++ ++ nlohmann::json jsn; ++ try { ++ jsn = nlohmann::json::parse(std::string(message)); ++ ++ ++ uic_mqtt_dotdot_parse_unify_switch_color_start_stop_change( ++ jsn, ++ start_stop, ++ ++ up_down, ++ ++ ignor_start_level, ++ ++ color_component_id, ++ ++ start_level, ++ ++ duration ++ ); ++ ++ } catch (const nlohmann::json::parse_error& e) { ++ // Catch JSON object field parsing errors ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_PARSE_FAIL, "UnifySwitchColor", "StartStopChange"); ++ return; ++ } catch (const nlohmann::json::exception& e) { ++ // Catch JSON object field parsing errors ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor", "StartStopChange", e.what()); ++ return; ++ } catch (const std::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor", "StartStopChange", ""); ++ return; ++ } ++ ++ ++ ++ ++ for (const auto& callback: uic_mqtt_dotdot_unify_switch_color_generated_start_stop_change_callback){ ++ callback( ++ static_cast(unid.c_str()), ++ endpoint, ++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL, ++ start_stop, ++ ++ up_down, ++ ++ ignor_start_level, ++ ++ color_component_id, ++ ++ start_level, ++ ++ duration ++ ++ ); ++ } ++} ++ ++ ++// Callback function for incoming publications on ucl/by-unid/+/+/UnifySwitchColor/Commands/WriteAttributes ++void uic_mqtt_dotdot_on_unify_switch_color_WriteAttributes( ++ const char *topic, ++ const char *message, ++ const size_t message_length) ++{ ++ if (uic_mqtt_dotdot_unify_switch_color_write_attributes_callback.empty()) { ++ return; ++ } ++ ++ if (message_length == 0) { ++ return; ++ } ++ ++ std::string unid; ++ uint8_t endpoint = 0; // Default value for endpoint-less topics. ++ if(! uic_dotdot_mqtt::parse_topic(topic,unid,endpoint)) { ++ sl_log_debug(LOG_TAG, ++ "Error parsing UNID / Endpoint ID from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ uic_mqtt_dotdot_unify_switch_color_state_t new_state = {}; ++ uic_mqtt_dotdot_unify_switch_color_updated_state_t new_updated_state = {}; ++ ++ ++ nlohmann::json jsn; ++ try { ++ jsn = nlohmann::json::parse(std::string(message)); ++ ++ uic_mqtt_dotdot_parse_unify_switch_color_write_attributes( ++ jsn, ++ new_state, ++ new_updated_state ++ ); ++ } catch (const nlohmann::json::parse_error& e) { ++ // Catch JSON object field parsing errors ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_PARSE_FAIL, "UnifySwitchColor", "WriteAttributes"); ++ return; ++ } catch (const nlohmann::json::exception& e) { ++ // Catch JSON object field parsing errors ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor", "WriteAttributes", e.what()); ++ return; ++ } catch (const std::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor", "WriteAttributes", ""); ++ return; ++ } ++ ++ for (const auto& callback: uic_mqtt_dotdot_unify_switch_color_write_attributes_callback){ ++ callback( ++ static_cast(unid.c_str()), ++ endpoint, ++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL, ++ new_state, ++ new_updated_state ++ ); ++ } ++ ++} ++ ++static void uic_mqtt_dotdot_on_unify_switch_color_force_read_attributes( ++ const char *topic, ++ const char *message, ++ const size_t message_length) ++{ ++ uint8_t endpoint = 0; ++ std::string unid; ++ ++ if ((message_length == 0) || (uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback.empty())) { ++ return; ++ } ++ ++ if(! uic_dotdot_mqtt::parse_topic(topic, unid, endpoint)) { ++ sl_log_debug(LOG_TAG, ++ "Error parsing UNID / Endpoint ID from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ try { ++ uic_mqtt_dotdot_unify_switch_color_updated_state_t force_update = {0}; ++ bool trigger_handler = false; ++ ++ nlohmann::json jsn = nlohmann::json::parse(std::string(message)); ++ std::vector attributes = jsn["value"].get>(); ++ ++ // Assume all attributes to be read on empty array received ++ if (attributes.size() == 0) { ++ force_update.warm_white = true; ++ force_update.cold_white = true; ++ force_update.red = true; ++ force_update.green = true; ++ force_update.blue = true; ++ force_update.amber = true; ++ force_update.cyan = true; ++ force_update.purple = true; ++ trigger_handler = true; ++ } else { ++ std::unordered_map supported_attrs = { ++ {"WarmWhite", &force_update.warm_white }, ++ {"ColdWhite", &force_update.cold_white }, ++ {"Red", &force_update.red }, ++ {"Green", &force_update.green }, ++ {"Blue", &force_update.blue }, ++ {"Amber", &force_update.amber }, ++ {"Cyan", &force_update.cyan }, ++ {"Purple", &force_update.purple }, ++ }; ++ ++ for (auto& attribute : attributes) { ++ auto found_attr = supported_attrs.find(attribute); ++ if (found_attr != supported_attrs.end()) { ++ *(found_attr->second) = true; ++ trigger_handler = true; ++ } ++ } ++ } ++ ++ if (trigger_handler == true) { ++ for (const auto& callback: uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback) { ++ callback( ++ static_cast(unid.c_str()), ++ endpoint, ++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL, ++ force_update ++ ); ++ } ++ } ++ } catch (...) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor/Commands/ForceReadAttributes: Unable to parse JSON payload"); ++ return; ++ } ++} ++ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_warm_white_publish( ++ const char *base_topic, ++ uint8_t value, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++) ++{ ++ nlohmann::json jsn; ++ ++ // This is a single value ++ ++ if (true == uic_dotdot_has_attribute_value_a_name(65441,0,value)) { ++ jsn["value"] = uic_dotdot_get_attribute_value_name(65441,0,value); ++ }else{ ++ jsn["value"] = value; ++ } ++ ++ ++ std::string payload_str; ++ try { ++ // Payload contains data from end nodes, which we cannot control, thus we handle if there are non-utf8 characters ++ payload_str = jsn.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace); ++ } catch (const nlohmann::json::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor/Attributes/WarmWhite", e.what()); ++ return SL_STATUS_OK; ++ } ++ ++ ++ std::string topic = std::string(base_topic) + "/UnifySwitchColor/Attributes/WarmWhite"; ++ if (publish_type & UCL_MQTT_PUBLISH_TYPE_DESIRED) ++ { ++ std::string topic_desired = topic + "/Desired"; ++ uic_mqtt_publish(topic_desired.c_str(), ++ payload_str.c_str(), ++ payload_str.length(), ++ true); ++ } ++ if (publish_type & UCL_MQTT_PUBLISH_TYPE_REPORTED) ++ { ++ std::string topic_reported = topic + "/Reported"; ++ uic_mqtt_publish(topic_reported.c_str(), ++ payload_str.c_str(), ++ payload_str.length(), ++ true); ++ } ++ return SL_STATUS_OK; ++} ++ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_warm_white_unretain( ++ const char *base_topic, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type) ++{ ++ // clang-format on ++ std::string topic ++ = std::string(base_topic) ++ + "/UnifySwitchColor/Attributes/WarmWhite"; ++ ++ if ((publish_type == UCL_MQTT_PUBLISH_TYPE_DESIRED) ++ || (publish_type == UCL_MQTT_PUBLISH_TYPE_ALL)) { ++ std::string topic_desired = topic + "/Desired"; ++ uic_mqtt_publish(topic_desired.c_str(), NULL, 0, true); ++ } ++ if ((publish_type == UCL_MQTT_PUBLISH_TYPE_REPORTED) ++ || (publish_type == UCL_MQTT_PUBLISH_TYPE_ALL)) { ++ std::string topic_reported = topic + "/Reported"; ++ uic_mqtt_publish(topic_reported.c_str(), NULL, 0, true); ++ } ++ return SL_STATUS_OK; ++} ++// clang-format off ++ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_cold_white_publish( ++ const char *base_topic, ++ uint8_t value, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++) ++{ ++ nlohmann::json jsn; ++ ++ // This is a single value ++ ++ if (true == uic_dotdot_has_attribute_value_a_name(65441,1,value)) { ++ jsn["value"] = uic_dotdot_get_attribute_value_name(65441,1,value); ++ }else{ ++ jsn["value"] = value; ++ } ++ ++ ++ std::string payload_str; ++ try { ++ // Payload contains data from end nodes, which we cannot control, thus we handle if there are non-utf8 characters ++ payload_str = jsn.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace); ++ } catch (const nlohmann::json::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor/Attributes/ColdWhite", e.what()); ++ return SL_STATUS_OK; ++ } ++ ++ ++ std::string topic = std::string(base_topic) + "/UnifySwitchColor/Attributes/ColdWhite"; ++ if (publish_type & UCL_MQTT_PUBLISH_TYPE_DESIRED) ++ { ++ std::string topic_desired = topic + "/Desired"; ++ uic_mqtt_publish(topic_desired.c_str(), ++ payload_str.c_str(), ++ payload_str.length(), ++ true); ++ } ++ if (publish_type & UCL_MQTT_PUBLISH_TYPE_REPORTED) ++ { ++ std::string topic_reported = topic + "/Reported"; ++ uic_mqtt_publish(topic_reported.c_str(), ++ payload_str.c_str(), ++ payload_str.length(), ++ true); ++ } ++ return SL_STATUS_OK; ++} ++ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_cold_white_unretain( ++ const char *base_topic, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type) ++{ ++ // clang-format on ++ std::string topic ++ = std::string(base_topic) ++ + "/UnifySwitchColor/Attributes/ColdWhite"; ++ ++ if ((publish_type == UCL_MQTT_PUBLISH_TYPE_DESIRED) ++ || (publish_type == UCL_MQTT_PUBLISH_TYPE_ALL)) { ++ std::string topic_desired = topic + "/Desired"; ++ uic_mqtt_publish(topic_desired.c_str(), NULL, 0, true); ++ } ++ if ((publish_type == UCL_MQTT_PUBLISH_TYPE_REPORTED) ++ || (publish_type == UCL_MQTT_PUBLISH_TYPE_ALL)) { ++ std::string topic_reported = topic + "/Reported"; ++ uic_mqtt_publish(topic_reported.c_str(), NULL, 0, true); ++ } ++ return SL_STATUS_OK; ++} ++// clang-format off ++ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_red_publish( ++ const char *base_topic, ++ uint8_t value, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++) ++{ ++ nlohmann::json jsn; ++ ++ // This is a single value ++ ++ if (true == uic_dotdot_has_attribute_value_a_name(65441,2,value)) { ++ jsn["value"] = uic_dotdot_get_attribute_value_name(65441,2,value); ++ }else{ ++ jsn["value"] = value; ++ } ++ ++ ++ std::string payload_str; ++ try { ++ // Payload contains data from end nodes, which we cannot control, thus we handle if there are non-utf8 characters ++ payload_str = jsn.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace); ++ } catch (const nlohmann::json::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor/Attributes/Red", e.what()); ++ return SL_STATUS_OK; ++ } ++ ++ ++ std::string topic = std::string(base_topic) + "/UnifySwitchColor/Attributes/Red"; ++ if (publish_type & UCL_MQTT_PUBLISH_TYPE_DESIRED) ++ { ++ std::string topic_desired = topic + "/Desired"; ++ uic_mqtt_publish(topic_desired.c_str(), ++ payload_str.c_str(), ++ payload_str.length(), ++ true); ++ } ++ if (publish_type & UCL_MQTT_PUBLISH_TYPE_REPORTED) ++ { ++ std::string topic_reported = topic + "/Reported"; ++ uic_mqtt_publish(topic_reported.c_str(), ++ payload_str.c_str(), ++ payload_str.length(), ++ true); ++ } ++ return SL_STATUS_OK; ++} ++ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_red_unretain( ++ const char *base_topic, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type) ++{ ++ // clang-format on ++ std::string topic ++ = std::string(base_topic) ++ + "/UnifySwitchColor/Attributes/Red"; ++ ++ if ((publish_type == UCL_MQTT_PUBLISH_TYPE_DESIRED) ++ || (publish_type == UCL_MQTT_PUBLISH_TYPE_ALL)) { ++ std::string topic_desired = topic + "/Desired"; ++ uic_mqtt_publish(topic_desired.c_str(), NULL, 0, true); ++ } ++ if ((publish_type == UCL_MQTT_PUBLISH_TYPE_REPORTED) ++ || (publish_type == UCL_MQTT_PUBLISH_TYPE_ALL)) { ++ std::string topic_reported = topic + "/Reported"; ++ uic_mqtt_publish(topic_reported.c_str(), NULL, 0, true); ++ } ++ return SL_STATUS_OK; ++} ++// clang-format off ++ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_green_publish( ++ const char *base_topic, ++ uint8_t value, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++) ++{ ++ nlohmann::json jsn; ++ ++ // This is a single value ++ ++ if (true == uic_dotdot_has_attribute_value_a_name(65441,3,value)) { ++ jsn["value"] = uic_dotdot_get_attribute_value_name(65441,3,value); ++ }else{ ++ jsn["value"] = value; ++ } ++ ++ ++ std::string payload_str; ++ try { ++ // Payload contains data from end nodes, which we cannot control, thus we handle if there are non-utf8 characters ++ payload_str = jsn.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace); ++ } catch (const nlohmann::json::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor/Attributes/Green", e.what()); ++ return SL_STATUS_OK; ++ } ++ ++ ++ std::string topic = std::string(base_topic) + "/UnifySwitchColor/Attributes/Green"; ++ if (publish_type & UCL_MQTT_PUBLISH_TYPE_DESIRED) ++ { ++ std::string topic_desired = topic + "/Desired"; ++ uic_mqtt_publish(topic_desired.c_str(), ++ payload_str.c_str(), ++ payload_str.length(), ++ true); ++ } ++ if (publish_type & UCL_MQTT_PUBLISH_TYPE_REPORTED) ++ { ++ std::string topic_reported = topic + "/Reported"; ++ uic_mqtt_publish(topic_reported.c_str(), ++ payload_str.c_str(), ++ payload_str.length(), ++ true); ++ } ++ return SL_STATUS_OK; ++} ++ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_green_unretain( ++ const char *base_topic, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type) ++{ ++ // clang-format on ++ std::string topic ++ = std::string(base_topic) ++ + "/UnifySwitchColor/Attributes/Green"; ++ ++ if ((publish_type == UCL_MQTT_PUBLISH_TYPE_DESIRED) ++ || (publish_type == UCL_MQTT_PUBLISH_TYPE_ALL)) { ++ std::string topic_desired = topic + "/Desired"; ++ uic_mqtt_publish(topic_desired.c_str(), NULL, 0, true); ++ } ++ if ((publish_type == UCL_MQTT_PUBLISH_TYPE_REPORTED) ++ || (publish_type == UCL_MQTT_PUBLISH_TYPE_ALL)) { ++ std::string topic_reported = topic + "/Reported"; ++ uic_mqtt_publish(topic_reported.c_str(), NULL, 0, true); ++ } ++ return SL_STATUS_OK; ++} ++// clang-format off ++ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_blue_publish( ++ const char *base_topic, ++ uint8_t value, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++) ++{ ++ nlohmann::json jsn; ++ ++ // This is a single value ++ ++ if (true == uic_dotdot_has_attribute_value_a_name(65441,4,value)) { ++ jsn["value"] = uic_dotdot_get_attribute_value_name(65441,4,value); ++ }else{ ++ jsn["value"] = value; ++ } ++ ++ ++ std::string payload_str; ++ try { ++ // Payload contains data from end nodes, which we cannot control, thus we handle if there are non-utf8 characters ++ payload_str = jsn.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace); ++ } catch (const nlohmann::json::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor/Attributes/Blue", e.what()); ++ return SL_STATUS_OK; ++ } ++ ++ ++ std::string topic = std::string(base_topic) + "/UnifySwitchColor/Attributes/Blue"; ++ if (publish_type & UCL_MQTT_PUBLISH_TYPE_DESIRED) ++ { ++ std::string topic_desired = topic + "/Desired"; ++ uic_mqtt_publish(topic_desired.c_str(), ++ payload_str.c_str(), ++ payload_str.length(), ++ true); ++ } ++ if (publish_type & UCL_MQTT_PUBLISH_TYPE_REPORTED) ++ { ++ std::string topic_reported = topic + "/Reported"; ++ uic_mqtt_publish(topic_reported.c_str(), ++ payload_str.c_str(), ++ payload_str.length(), ++ true); ++ } ++ return SL_STATUS_OK; ++} ++ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_blue_unretain( ++ const char *base_topic, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type) ++{ ++ // clang-format on ++ std::string topic ++ = std::string(base_topic) ++ + "/UnifySwitchColor/Attributes/Blue"; ++ ++ if ((publish_type == UCL_MQTT_PUBLISH_TYPE_DESIRED) ++ || (publish_type == UCL_MQTT_PUBLISH_TYPE_ALL)) { ++ std::string topic_desired = topic + "/Desired"; ++ uic_mqtt_publish(topic_desired.c_str(), NULL, 0, true); ++ } ++ if ((publish_type == UCL_MQTT_PUBLISH_TYPE_REPORTED) ++ || (publish_type == UCL_MQTT_PUBLISH_TYPE_ALL)) { ++ std::string topic_reported = topic + "/Reported"; ++ uic_mqtt_publish(topic_reported.c_str(), NULL, 0, true); ++ } ++ return SL_STATUS_OK; ++} ++// clang-format off ++ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_amber_publish( ++ const char *base_topic, ++ uint8_t value, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++) ++{ ++ nlohmann::json jsn; ++ ++ // This is a single value ++ ++ if (true == uic_dotdot_has_attribute_value_a_name(65441,5,value)) { ++ jsn["value"] = uic_dotdot_get_attribute_value_name(65441,5,value); ++ }else{ ++ jsn["value"] = value; ++ } ++ ++ ++ std::string payload_str; ++ try { ++ // Payload contains data from end nodes, which we cannot control, thus we handle if there are non-utf8 characters ++ payload_str = jsn.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace); ++ } catch (const nlohmann::json::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor/Attributes/Amber", e.what()); ++ return SL_STATUS_OK; ++ } ++ ++ ++ std::string topic = std::string(base_topic) + "/UnifySwitchColor/Attributes/Amber"; ++ if (publish_type & UCL_MQTT_PUBLISH_TYPE_DESIRED) ++ { ++ std::string topic_desired = topic + "/Desired"; ++ uic_mqtt_publish(topic_desired.c_str(), ++ payload_str.c_str(), ++ payload_str.length(), ++ true); ++ } ++ if (publish_type & UCL_MQTT_PUBLISH_TYPE_REPORTED) ++ { ++ std::string topic_reported = topic + "/Reported"; ++ uic_mqtt_publish(topic_reported.c_str(), ++ payload_str.c_str(), ++ payload_str.length(), ++ true); ++ } ++ return SL_STATUS_OK; ++} ++ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_amber_unretain( ++ const char *base_topic, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type) ++{ ++ // clang-format on ++ std::string topic ++ = std::string(base_topic) ++ + "/UnifySwitchColor/Attributes/Amber"; ++ ++ if ((publish_type == UCL_MQTT_PUBLISH_TYPE_DESIRED) ++ || (publish_type == UCL_MQTT_PUBLISH_TYPE_ALL)) { ++ std::string topic_desired = topic + "/Desired"; ++ uic_mqtt_publish(topic_desired.c_str(), NULL, 0, true); ++ } ++ if ((publish_type == UCL_MQTT_PUBLISH_TYPE_REPORTED) ++ || (publish_type == UCL_MQTT_PUBLISH_TYPE_ALL)) { ++ std::string topic_reported = topic + "/Reported"; ++ uic_mqtt_publish(topic_reported.c_str(), NULL, 0, true); ++ } ++ return SL_STATUS_OK; ++} ++// clang-format off ++ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_cyan_publish( ++ const char *base_topic, ++ uint8_t value, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++) ++{ ++ nlohmann::json jsn; ++ ++ // This is a single value ++ ++ if (true == uic_dotdot_has_attribute_value_a_name(65441,6,value)) { ++ jsn["value"] = uic_dotdot_get_attribute_value_name(65441,6,value); ++ }else{ ++ jsn["value"] = value; ++ } ++ ++ ++ std::string payload_str; ++ try { ++ // Payload contains data from end nodes, which we cannot control, thus we handle if there are non-utf8 characters ++ payload_str = jsn.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace); ++ } catch (const nlohmann::json::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor/Attributes/Cyan", e.what()); ++ return SL_STATUS_OK; ++ } ++ ++ ++ std::string topic = std::string(base_topic) + "/UnifySwitchColor/Attributes/Cyan"; ++ if (publish_type & UCL_MQTT_PUBLISH_TYPE_DESIRED) ++ { ++ std::string topic_desired = topic + "/Desired"; ++ uic_mqtt_publish(topic_desired.c_str(), ++ payload_str.c_str(), ++ payload_str.length(), ++ true); ++ } ++ if (publish_type & UCL_MQTT_PUBLISH_TYPE_REPORTED) ++ { ++ std::string topic_reported = topic + "/Reported"; ++ uic_mqtt_publish(topic_reported.c_str(), ++ payload_str.c_str(), ++ payload_str.length(), ++ true); ++ } ++ return SL_STATUS_OK; ++} ++ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_cyan_unretain( ++ const char *base_topic, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type) ++{ ++ // clang-format on ++ std::string topic ++ = std::string(base_topic) ++ + "/UnifySwitchColor/Attributes/Cyan"; ++ ++ if ((publish_type == UCL_MQTT_PUBLISH_TYPE_DESIRED) ++ || (publish_type == UCL_MQTT_PUBLISH_TYPE_ALL)) { ++ std::string topic_desired = topic + "/Desired"; ++ uic_mqtt_publish(topic_desired.c_str(), NULL, 0, true); ++ } ++ if ((publish_type == UCL_MQTT_PUBLISH_TYPE_REPORTED) ++ || (publish_type == UCL_MQTT_PUBLISH_TYPE_ALL)) { ++ std::string topic_reported = topic + "/Reported"; ++ uic_mqtt_publish(topic_reported.c_str(), NULL, 0, true); ++ } ++ return SL_STATUS_OK; ++} ++// clang-format off ++ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_purple_publish( ++ const char *base_topic, ++ uint8_t value, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type ++) ++{ ++ nlohmann::json jsn; ++ ++ // This is a single value ++ ++ if (true == uic_dotdot_has_attribute_value_a_name(65441,7,value)) { ++ jsn["value"] = uic_dotdot_get_attribute_value_name(65441,7,value); ++ }else{ ++ jsn["value"] = value; ++ } ++ ++ ++ std::string payload_str; ++ try { ++ // Payload contains data from end nodes, which we cannot control, thus we handle if there are non-utf8 characters ++ payload_str = jsn.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace); ++ } catch (const nlohmann::json::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor/Attributes/Purple", e.what()); ++ return SL_STATUS_OK; ++ } ++ ++ ++ std::string topic = std::string(base_topic) + "/UnifySwitchColor/Attributes/Purple"; ++ if (publish_type & UCL_MQTT_PUBLISH_TYPE_DESIRED) ++ { ++ std::string topic_desired = topic + "/Desired"; ++ uic_mqtt_publish(topic_desired.c_str(), ++ payload_str.c_str(), ++ payload_str.length(), ++ true); ++ } ++ if (publish_type & UCL_MQTT_PUBLISH_TYPE_REPORTED) ++ { ++ std::string topic_reported = topic + "/Reported"; ++ uic_mqtt_publish(topic_reported.c_str(), ++ payload_str.c_str(), ++ payload_str.length(), ++ true); ++ } ++ return SL_STATUS_OK; ++} ++ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_purple_unretain( ++ const char *base_topic, ++ uic_mqtt_dotdot_attribute_publish_type_t publish_type) ++{ ++ // clang-format on ++ std::string topic ++ = std::string(base_topic) ++ + "/UnifySwitchColor/Attributes/Purple"; ++ ++ if ((publish_type == UCL_MQTT_PUBLISH_TYPE_DESIRED) ++ || (publish_type == UCL_MQTT_PUBLISH_TYPE_ALL)) { ++ std::string topic_desired = topic + "/Desired"; ++ uic_mqtt_publish(topic_desired.c_str(), NULL, 0, true); ++ } ++ if ((publish_type == UCL_MQTT_PUBLISH_TYPE_REPORTED) ++ || (publish_type == UCL_MQTT_PUBLISH_TYPE_ALL)) { ++ std::string topic_reported = topic + "/Reported"; ++ uic_mqtt_publish(topic_reported.c_str(), NULL, 0, true); ++ } ++ return SL_STATUS_OK; ++} ++// clang-format off ++ ++ ++sl_status_t uic_mqtt_dotdot_unify_switch_color_init() ++{ ++ std::string base_topic = "ucl/by-unid/+/+/"; ++ ++ std::string subscription_topic; ++ if(!uic_mqtt_dotdot_unify_switch_color_write_attributes_callback.empty()) { ++ subscription_topic = base_topic + "UnifySwitchColor/Commands/WriteAttributes"; ++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_unify_switch_color_WriteAttributes); ++ } ++ ++ if(!uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback.empty()) { ++ subscription_topic = base_topic + "UnifySwitchColor/Commands/ForceReadAttributes"; ++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_unify_switch_color_force_read_attributes); ++ } ++ if (!uic_mqtt_dotdot_unify_switch_color_set_color_callback.empty()) { ++ subscription_topic = base_topic + "UnifySwitchColor/Commands/SetColor"; ++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_unify_switch_color_set_color); ++ } ++ if (!uic_mqtt_dotdot_unify_switch_color_generated_set_color_callback.empty()) { ++ subscription_topic = base_topic + "UnifySwitchColor/GeneratedCommands/SetColor"; ++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_generated_unify_switch_color_set_color); ++ } ++ if (!uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback.empty()) { ++ subscription_topic = base_topic + "UnifySwitchColor/Commands/StartStopChange"; ++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_unify_switch_color_start_stop_change); ++ } ++ if (!uic_mqtt_dotdot_unify_switch_color_generated_start_stop_change_callback.empty()) { ++ subscription_topic = base_topic + "UnifySwitchColor/GeneratedCommands/StartStopChange"; ++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_generated_unify_switch_color_start_stop_change); ++ } ++ ++ // Init the attributes for that cluster ++ uic_mqtt_dotdot_unify_switch_color_attributes_init(); ++ ++ uic_mqtt_dotdot_by_group_unify_switch_color_init(); ++ ++ return SL_STATUS_OK; ++} ++ + + sl_status_t uic_mqtt_dotdot_init() { + +@@ -99998,6 +101156,10 @@ sl_status_t uic_mqtt_dotdot_init() { + status_flag = uic_mqtt_dotdot_unify_humidity_control_init(); + } + ++ if (status_flag == SL_STATUS_OK) { ++ status_flag = uic_mqtt_dotdot_unify_switch_color_init(); ++ } ++ + + return status_flag; + } +@@ -100061,6 +101223,7 @@ void uic_mqtt_dotdot_publish_supported_commands( + uic_mqtt_dotdot_unify_fan_control_publish_supported_commands(unid, endpoint_id); + uic_mqtt_dotdot_unify_thermostat_publish_supported_commands(unid, endpoint_id); + uic_mqtt_dotdot_unify_humidity_control_publish_supported_commands(unid, endpoint_id); ++ uic_mqtt_dotdot_unify_switch_color_publish_supported_commands(unid, endpoint_id); + } + + void uic_mqtt_dotdot_publish_empty_supported_commands( +@@ -100121,6 +101284,7 @@ void uic_mqtt_dotdot_publish_empty_supported_commands( + uic_mqtt_dotdot_unify_fan_control_publish_empty_supported_commands(unid, endpoint_id); + uic_mqtt_dotdot_unify_thermostat_publish_empty_supported_commands(unid, endpoint_id); + uic_mqtt_dotdot_unify_humidity_control_publish_empty_supported_commands(unid, endpoint_id); ++ uic_mqtt_dotdot_unify_switch_color_publish_empty_supported_commands(unid, endpoint_id); + } + + // Publishing Cluster Revision for Basic Cluster +@@ -114499,6 +115663,232 @@ void uic_mqtt_dotdot_unify_humidity_control_publish_empty_supported_commands( + } + } + ++// Publishing Cluster Revision for UnifySwitchColor Cluster ++void uic_mqtt_dotdot_unify_switch_color_publish_cluster_revision(const char* base_topic, uint16_t value) ++{ ++ std::string cluster_topic = std::string(base_topic) + "/UnifySwitchColor/Attributes/ClusterRevision"; ++ // Publish Desired ++ std::string pub_topic_des = cluster_topic + "/Desired"; ++ std::string payload = std::string(R"({"value": )") ++ + std::to_string(value) + std::string("}"); ++ uic_mqtt_publish(pub_topic_des.c_str(), ++ payload.c_str(), ++ payload.size(), ++ true); ++ // Publish Reported ++ std::string pub_topic_rep = cluster_topic + "/Reported"; ++ uic_mqtt_publish(pub_topic_rep.c_str(), ++ payload.c_str(), ++ payload.size(), ++ true); ++} ++ ++// Unretain Cluster Revision for UnifySwitchColor Cluster ++void uic_mqtt_dotdot_unify_switch_color_unretain_cluster_revision(const char* base_topic) ++{ ++ // clang-format on ++ std::string cluster_topic ++ = std::string(base_topic) ++ + "/UnifySwitchColor/Attributes/ClusterRevision"; ++ // Publish Desired ++ std::string desired_topic = cluster_topic + "/Desired"; ++ uic_mqtt_publish(desired_topic.c_str(), NULL, 0, true); ++ // Publish Reported ++ std::string reported_topic = cluster_topic + "/Reported"; ++ uic_mqtt_publish(reported_topic.c_str(), NULL, 0, true); ++ // clang-format off ++} ++ ++static inline bool uic_mqtt_dotdot_unify_switch_color_set_color_is_supported( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id) ++{ ++ uint8_t color_component_id_value; ++ memset(&color_component_id_value, 0x00, sizeof(color_component_id_value)); ++ uint8_t value_value; ++ memset(&value_value, 0x00, sizeof(value_value)); ++ uint32_t duration_value; ++ memset(&duration_value, 0x00, sizeof(duration_value)); ++ for (const auto& callback: uic_mqtt_dotdot_unify_switch_color_set_color_callback) { ++ if (callback( unid, endpoint_id, UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK ++ , ++ color_component_id_value, ++ ++ value_value, ++ ++ duration_value ++ ++ ) == SL_STATUS_OK) { ++ return true; ++ } ++ } ++ ++ return false; ++} ++static inline bool uic_mqtt_dotdot_unify_switch_color_start_stop_change_is_supported( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id) ++{ ++ bool start_stop_value; ++ memset(&start_stop_value, 0x00, sizeof(start_stop_value)); ++ bool up_down_value; ++ memset(&up_down_value, 0x00, sizeof(up_down_value)); ++ bool ignor_start_level_value; ++ memset(&ignor_start_level_value, 0x00, sizeof(ignor_start_level_value)); ++ uint8_t color_component_id_value; ++ memset(&color_component_id_value, 0x00, sizeof(color_component_id_value)); ++ uint8_t start_level_value; ++ memset(&start_level_value, 0x00, sizeof(start_level_value)); ++ uint32_t duration_value; ++ memset(&duration_value, 0x00, sizeof(duration_value)); ++ for (const auto& callback: uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback) { ++ if (callback( unid, endpoint_id, UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK ++ , ++ start_stop_value, ++ ++ up_down_value, ++ ++ ignor_start_level_value, ++ ++ color_component_id_value, ++ ++ start_level_value, ++ ++ duration_value ++ ++ ) == SL_STATUS_OK) { ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++static inline bool uic_mqtt_dotdot_unify_switch_color_write_attributes_is_supported( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id) ++{ ++ for (const auto& callback: uic_mqtt_dotdot_unify_switch_color_write_attributes_callback) { ++ uic_mqtt_dotdot_unify_switch_color_state_t unify_switch_color_new_state = {}; ++ uic_mqtt_dotdot_unify_switch_color_updated_state_t unify_switch_color_new_updated_state = {}; ++ ++ if (callback( ++ unid, ++ endpoint_id, ++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK, ++ unify_switch_color_new_state, ++ unify_switch_color_new_updated_state ++ ) == SL_STATUS_OK) { ++ return true; ++ } ++ } ++ return false; ++} ++ ++static inline bool uic_mqtt_dotdot_unify_switch_color_force_read_attributes_is_supported( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id) ++{ ++ for (const auto& callback: uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback) { ++ uic_mqtt_dotdot_unify_switch_color_updated_state_t unify_switch_color_force_update = {0}; ++ if (callback( ++ unid, ++ endpoint_id, ++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK, ++ unify_switch_color_force_update ++ ) == SL_STATUS_OK) { ++ return true; ++ } ++ } ++ return false; ++} ++ ++// Publishing Supported Commands for UnifySwitchColor Cluster ++void uic_mqtt_dotdot_unify_switch_color_publish_supported_commands( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id) ++{ ++ std::stringstream ss; ++ bool first_command = true; ++ ss.str(""); ++ ++ // check if there is callback for each command ++ if (uic_mqtt_dotdot_unify_switch_color_set_color_is_supported(unid, endpoint_id)) { ++ if (first_command == false) { ++ ss << ", "; ++ } ++ first_command = false; ++ ss << R"("SetColor")"; ++ } ++ if (uic_mqtt_dotdot_unify_switch_color_start_stop_change_is_supported(unid, endpoint_id)) { ++ if (first_command == false) { ++ ss << ", "; ++ } ++ first_command = false; ++ ss << R"("StartStopChange")"; ++ } ++ ++ // Check for a WriteAttributes Callback ++ if(uic_mqtt_dotdot_unify_switch_color_write_attributes_is_supported(unid, endpoint_id)) { ++ if (first_command == false) { ++ ss << ", "; ++ } ++ first_command = false; ++ ss << R"("WriteAttributes")"; ++ } ++ ++ // Check for a ForceReadAttributes Callback ++ if (uic_mqtt_dotdot_unify_switch_color_force_read_attributes_is_supported(unid, endpoint_id)) { ++ if (first_command == false) { ++ ss << ", "; ++ } ++ first_command = false; ++ ss << R"("ForceReadAttributes")"; ++ } ++ ++ // Publish supported commands ++ std::string topic = "ucl/by-unid/" + std::string(unid); ++ topic += "/ep"+ std::to_string(endpoint_id); ++ topic += "/UnifySwitchColor/SupportedCommands"; ++ std::string payload_str("{\"value\": [" + ss.str() + "]" + "}"); ++ if (first_command == false) { ++ uic_mqtt_publish(topic.c_str(), ++ payload_str.c_str(), ++ payload_str.length(), ++ true); ++ } else if (uic_mqtt_count_topics(topic.c_str()) == 0) { ++ // There are no supported commands, but make sure we publish some ++ // SupportedCommands = [] if any attribute has been published for a cluster. ++ std::string attributes_topic = "ucl/by-unid/" + std::string(unid); ++ attributes_topic += "/ep"+ std::to_string(endpoint_id); ++ attributes_topic += "/UnifySwitchColor/Attributes"; ++ ++ if (uic_mqtt_count_topics(attributes_topic.c_str()) > 0) { ++ uic_mqtt_publish(topic.c_str(), ++ EMPTY_VALUE_ARRAY, ++ strlen(EMPTY_VALUE_ARRAY), ++ true); ++ } ++ } ++} ++ ++// Publishing empty/no Supported Commands for UnifySwitchColor Cluster ++void uic_mqtt_dotdot_unify_switch_color_publish_empty_supported_commands( ++ const dotdot_unid_t unid ++ , dotdot_endpoint_id_t endpoint_id) ++{ ++ std::string topic = "ucl/by-unid/" + std::string(unid); ++ topic += "/ep"+ std::to_string(endpoint_id); ++ topic += "/UnifySwitchColor/SupportedCommands"; ++ ++ if (uic_mqtt_count_topics(topic.c_str()) > 0) { ++ uic_mqtt_publish(topic.c_str(), ++ EMPTY_VALUE_ARRAY, ++ strlen(EMPTY_VALUE_ARRAY), ++ true); ++ } ++} ++ + + //////////////////////////////////////////////////////////////////////////////// + // Generated Commands publications functions +@@ -121907,3 +123297,75 @@ void uic_mqtt_dotdot_unify_humidity_control_publish_generated_setpoint_set_comma + payload.size(), + false); + } ++/** ++ * @brief Publishes an incoming/generated SetColor command for ++ * the UnifySwitchColor cluster. ++ * ++ * Publication will be made at the following topic ++ * ucl/by-unid/UNID/epID/UnifySwitchColor/GeneratedCommands/SetColor ++ * ++ * @param unid The UNID of the node that sent us the command. ++ * ++ * @param endpoint The Endpoint ID of the node that sent us the command. ++ * ++ * ++ * @param fields Struct pointer with the fields value of the command ++ * ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_generated_set_color_command( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint, ++ const uic_mqtt_dotdot_unify_switch_color_command_set_color_fields_t *fields ++ ++) { ++ // Create the topic ++ std::string topic = "ucl/by-unid/"+ std::string(unid) + "/ep" + ++ std::to_string(endpoint) + "/"; ++ topic += "UnifySwitchColor/GeneratedCommands/SetColor"; ++ ++ std::string payload = ++ get_json_payload_for_unify_switch_color_set_color_command( ++ fields); ++ ++ // Publish our command ++ uic_mqtt_publish(topic.c_str(), ++ payload.c_str(), ++ payload.size(), ++ false); ++} ++/** ++ * @brief Publishes an incoming/generated StartStopChange command for ++ * the UnifySwitchColor cluster. ++ * ++ * Publication will be made at the following topic ++ * ucl/by-unid/UNID/epID/UnifySwitchColor/GeneratedCommands/StartStopChange ++ * ++ * @param unid The UNID of the node that sent us the command. ++ * ++ * @param endpoint The Endpoint ID of the node that sent us the command. ++ * ++ * ++ * @param fields Struct pointer with the fields value of the command ++ * ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_generated_start_stop_change_command( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint, ++ const uic_mqtt_dotdot_unify_switch_color_command_start_stop_change_fields_t *fields ++ ++) { ++ // Create the topic ++ std::string topic = "ucl/by-unid/"+ std::string(unid) + "/ep" + ++ std::to_string(endpoint) + "/"; ++ topic += "UnifySwitchColor/GeneratedCommands/StartStopChange"; ++ ++ std::string payload = ++ get_json_payload_for_unify_switch_color_start_stop_change_command( ++ fields); ++ ++ // Publish our command ++ uic_mqtt_publish(topic.c_str(), ++ payload.c_str(), ++ payload.size(), ++ false); ++} +diff --git a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.hpp b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.hpp +index cef2277e5a..626983fca7 100644 +--- a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.hpp ++++ b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.hpp +@@ -378,6 +378,13 @@ sl_status_t uic_mqtt_dotdot_by_group_unify_thermostat_init(); + */ + sl_status_t uic_mqtt_dotdot_by_group_unify_humidity_control_init(); + ++/** ++ * @brief Initialize UnifySwitchColor dotdot bygroup command handlers ++ * ++ * @returns SL_STATUS_OK on success, error otherwise. ++ */ ++sl_status_t uic_mqtt_dotdot_by_group_unify_switch_color_init(); ++ + + + // clang-format on +@@ -5523,6 +5530,65 @@ void uic_mqtt_dotdot_on_unify_humidity_control_WriteAttributes( + const size_t message_length); + + ++// clang-format on ++ ++/** ++ * @brief Retrieves the container with callbacks pointer for ++ * by-unid UnifySwitchColor/Commands/SetColor messages ++ * ++ * @returns std::set of callbacks. ++ */ ++std::set &get_uic_mqtt_dotdot_unify_switch_color_set_color_callback(); ++ ++/** ++ * @brief MQTT Subscribe handler for incoming publications on: ++ * ucl/by-unid/+/+/UnifySwitchColor/Commands/SetColor ++ */ ++// clang-format off ++void uic_mqtt_dotdot_on_unify_switch_color_set_color( ++ const char *topic, ++ const char *message, ++ const size_t message_length); ++// clang-format on ++ ++/** ++ * @brief Retrieves the container with callbacks pointer for ++ * by-unid UnifySwitchColor/Commands/StartStopChange messages ++ * ++ * @returns std::set of callbacks. ++ */ ++std::set &get_uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback(); ++ ++/** ++ * @brief MQTT Subscribe handler for incoming publications on: ++ * ucl/by-unid/+/+/UnifySwitchColor/Commands/StartStopChange ++ */ ++// clang-format off ++void uic_mqtt_dotdot_on_unify_switch_color_start_stop_change( ++ const char *topic, ++ const char *message, ++ const size_t message_length); ++// clang-format on ++ ++/** ++ * @brief Retrieves the container with callback pointers for by-unid ++ * /Commands/WriteAttributes messages ++ * ++ * @returns std::set of callbacks. ++ */ ++std::set & get_uic_mqtt_dotdot_unify_switch_color_write_attributes_callback(); ++ ++/** ++ * @brief MQTT Subscribe handler for incoming publications on: ++ * ucl/by-unid/+/+/UnifySwitchColor/Commands/WriteAttributes ++ */ ++// clang-format off ++void uic_mqtt_dotdot_on_unify_switch_color_WriteAttributes( ++ const char *topic, ++ const char *message, ++ const size_t message_length); ++ ++ + + + // All bitmaps are defined as the cluster label for the bitmap plus the command/attribute name +diff --git a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_attributes.cpp b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_attributes.cpp +index 87fddb1ebf..d652e2f9eb 100644 +--- a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_attributes.cpp ++++ b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_attributes.cpp +@@ -64347,3 +64347,710 @@ void uic_mqtt_dotdot_unify_humidity_control_attribute_auto_setpoint_precision_ca + + // End of supported cluster. + ++/////////////////////////////////////////////////////////////////////////////// ++// Callback pointers for UnifySwitchColor ++/////////////////////////////////////////////////////////////////////////////// ++static uic_mqtt_dotdot_unify_switch_color_attribute_warm_white_callback_t uic_mqtt_dotdot_unify_switch_color_attribute_warm_white_callback = nullptr; ++static uic_mqtt_dotdot_unify_switch_color_attribute_cold_white_callback_t uic_mqtt_dotdot_unify_switch_color_attribute_cold_white_callback = nullptr; ++static uic_mqtt_dotdot_unify_switch_color_attribute_red_callback_t uic_mqtt_dotdot_unify_switch_color_attribute_red_callback = nullptr; ++static uic_mqtt_dotdot_unify_switch_color_attribute_green_callback_t uic_mqtt_dotdot_unify_switch_color_attribute_green_callback = nullptr; ++static uic_mqtt_dotdot_unify_switch_color_attribute_blue_callback_t uic_mqtt_dotdot_unify_switch_color_attribute_blue_callback = nullptr; ++static uic_mqtt_dotdot_unify_switch_color_attribute_amber_callback_t uic_mqtt_dotdot_unify_switch_color_attribute_amber_callback = nullptr; ++static uic_mqtt_dotdot_unify_switch_color_attribute_cyan_callback_t uic_mqtt_dotdot_unify_switch_color_attribute_cyan_callback = nullptr; ++static uic_mqtt_dotdot_unify_switch_color_attribute_purple_callback_t uic_mqtt_dotdot_unify_switch_color_attribute_purple_callback = nullptr; ++ ++/////////////////////////////////////////////////////////////////////////////// ++// Attribute update handlers for UnifySwitchColor ++/////////////////////////////////////////////////////////////////////////////// ++static void uic_mqtt_dotdot_on_unify_switch_color_warm_white_attribute_update( ++ const char *topic, ++ const char *message, ++ const size_t message_length) { ++ if (uic_mqtt_dotdot_unify_switch_color_attribute_warm_white_callback == nullptr) { ++ return; ++ } ++ ++ std::string unid; ++ uint8_t endpoint = 0; // Default value for endpoint-less topics. ++ if(! uic_dotdot_mqtt::parse_topic(topic,unid,endpoint)) { ++ sl_log_debug(LOG_TAG, ++ "Error parsing UNID / Endpoint ID from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ std::string last_item; ++ if (SL_STATUS_OK != uic_dotdot_mqtt::get_topic_last_item(topic,last_item)){ ++ sl_log_debug(LOG_TAG, ++ "Error parsing last item from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ uic_mqtt_dotdot_attribute_update_type_t update_type; ++ if (last_item == "Reported") { ++ update_type = UCL_REPORTED_UPDATED; ++ } else if (last_item == "Desired") { ++ update_type = UCL_DESIRED_UPDATED; ++ } else { ++ sl_log_debug(LOG_TAG, ++ "Unknown value type (neither Desired/Reported) for topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ // Empty message means unretained value. ++ bool unretained = false; ++ if (message_length == 0) { ++ unretained = true; ++ } ++ ++ ++ uint8_t warm_white = {}; ++ ++ nlohmann::json json_payload; ++ try { ++ ++ if (unretained == false) { ++ json_payload = nlohmann::json::parse(std::string(message)); ++ ++ if (json_payload.find("value") == json_payload.end()) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor::WarmWhite: Missing attribute element: 'value'\n"); ++ return; ++ } ++// Start parsing value ++ warm_white = json_payload.at("value").get(); ++ ++ // End parsing value ++ } ++ ++ } catch (const std::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "value", message); ++ return; ++ } ++ ++ uic_mqtt_dotdot_unify_switch_color_attribute_warm_white_callback( ++ static_cast(unid.c_str()), ++ endpoint, ++ unretained, ++ update_type, ++ warm_white ++ ); ++ ++} ++static void uic_mqtt_dotdot_on_unify_switch_color_cold_white_attribute_update( ++ const char *topic, ++ const char *message, ++ const size_t message_length) { ++ if (uic_mqtt_dotdot_unify_switch_color_attribute_cold_white_callback == nullptr) { ++ return; ++ } ++ ++ std::string unid; ++ uint8_t endpoint = 0; // Default value for endpoint-less topics. ++ if(! uic_dotdot_mqtt::parse_topic(topic,unid,endpoint)) { ++ sl_log_debug(LOG_TAG, ++ "Error parsing UNID / Endpoint ID from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ std::string last_item; ++ if (SL_STATUS_OK != uic_dotdot_mqtt::get_topic_last_item(topic,last_item)){ ++ sl_log_debug(LOG_TAG, ++ "Error parsing last item from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ uic_mqtt_dotdot_attribute_update_type_t update_type; ++ if (last_item == "Reported") { ++ update_type = UCL_REPORTED_UPDATED; ++ } else if (last_item == "Desired") { ++ update_type = UCL_DESIRED_UPDATED; ++ } else { ++ sl_log_debug(LOG_TAG, ++ "Unknown value type (neither Desired/Reported) for topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ // Empty message means unretained value. ++ bool unretained = false; ++ if (message_length == 0) { ++ unretained = true; ++ } ++ ++ ++ uint8_t cold_white = {}; ++ ++ nlohmann::json json_payload; ++ try { ++ ++ if (unretained == false) { ++ json_payload = nlohmann::json::parse(std::string(message)); ++ ++ if (json_payload.find("value") == json_payload.end()) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor::ColdWhite: Missing attribute element: 'value'\n"); ++ return; ++ } ++// Start parsing value ++ cold_white = json_payload.at("value").get(); ++ ++ // End parsing value ++ } ++ ++ } catch (const std::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "value", message); ++ return; ++ } ++ ++ uic_mqtt_dotdot_unify_switch_color_attribute_cold_white_callback( ++ static_cast(unid.c_str()), ++ endpoint, ++ unretained, ++ update_type, ++ cold_white ++ ); ++ ++} ++static void uic_mqtt_dotdot_on_unify_switch_color_red_attribute_update( ++ const char *topic, ++ const char *message, ++ const size_t message_length) { ++ if (uic_mqtt_dotdot_unify_switch_color_attribute_red_callback == nullptr) { ++ return; ++ } ++ ++ std::string unid; ++ uint8_t endpoint = 0; // Default value for endpoint-less topics. ++ if(! uic_dotdot_mqtt::parse_topic(topic,unid,endpoint)) { ++ sl_log_debug(LOG_TAG, ++ "Error parsing UNID / Endpoint ID from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ std::string last_item; ++ if (SL_STATUS_OK != uic_dotdot_mqtt::get_topic_last_item(topic,last_item)){ ++ sl_log_debug(LOG_TAG, ++ "Error parsing last item from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ uic_mqtt_dotdot_attribute_update_type_t update_type; ++ if (last_item == "Reported") { ++ update_type = UCL_REPORTED_UPDATED; ++ } else if (last_item == "Desired") { ++ update_type = UCL_DESIRED_UPDATED; ++ } else { ++ sl_log_debug(LOG_TAG, ++ "Unknown value type (neither Desired/Reported) for topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ // Empty message means unretained value. ++ bool unretained = false; ++ if (message_length == 0) { ++ unretained = true; ++ } ++ ++ ++ uint8_t red = {}; ++ ++ nlohmann::json json_payload; ++ try { ++ ++ if (unretained == false) { ++ json_payload = nlohmann::json::parse(std::string(message)); ++ ++ if (json_payload.find("value") == json_payload.end()) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor::Red: Missing attribute element: 'value'\n"); ++ return; ++ } ++// Start parsing value ++ red = json_payload.at("value").get(); ++ ++ // End parsing value ++ } ++ ++ } catch (const std::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "value", message); ++ return; ++ } ++ ++ uic_mqtt_dotdot_unify_switch_color_attribute_red_callback( ++ static_cast(unid.c_str()), ++ endpoint, ++ unretained, ++ update_type, ++ red ++ ); ++ ++} ++static void uic_mqtt_dotdot_on_unify_switch_color_green_attribute_update( ++ const char *topic, ++ const char *message, ++ const size_t message_length) { ++ if (uic_mqtt_dotdot_unify_switch_color_attribute_green_callback == nullptr) { ++ return; ++ } ++ ++ std::string unid; ++ uint8_t endpoint = 0; // Default value for endpoint-less topics. ++ if(! uic_dotdot_mqtt::parse_topic(topic,unid,endpoint)) { ++ sl_log_debug(LOG_TAG, ++ "Error parsing UNID / Endpoint ID from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ std::string last_item; ++ if (SL_STATUS_OK != uic_dotdot_mqtt::get_topic_last_item(topic,last_item)){ ++ sl_log_debug(LOG_TAG, ++ "Error parsing last item from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ uic_mqtt_dotdot_attribute_update_type_t update_type; ++ if (last_item == "Reported") { ++ update_type = UCL_REPORTED_UPDATED; ++ } else if (last_item == "Desired") { ++ update_type = UCL_DESIRED_UPDATED; ++ } else { ++ sl_log_debug(LOG_TAG, ++ "Unknown value type (neither Desired/Reported) for topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ // Empty message means unretained value. ++ bool unretained = false; ++ if (message_length == 0) { ++ unretained = true; ++ } ++ ++ ++ uint8_t green = {}; ++ ++ nlohmann::json json_payload; ++ try { ++ ++ if (unretained == false) { ++ json_payload = nlohmann::json::parse(std::string(message)); ++ ++ if (json_payload.find("value") == json_payload.end()) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor::Green: Missing attribute element: 'value'\n"); ++ return; ++ } ++// Start parsing value ++ green = json_payload.at("value").get(); ++ ++ // End parsing value ++ } ++ ++ } catch (const std::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "value", message); ++ return; ++ } ++ ++ uic_mqtt_dotdot_unify_switch_color_attribute_green_callback( ++ static_cast(unid.c_str()), ++ endpoint, ++ unretained, ++ update_type, ++ green ++ ); ++ ++} ++static void uic_mqtt_dotdot_on_unify_switch_color_blue_attribute_update( ++ const char *topic, ++ const char *message, ++ const size_t message_length) { ++ if (uic_mqtt_dotdot_unify_switch_color_attribute_blue_callback == nullptr) { ++ return; ++ } ++ ++ std::string unid; ++ uint8_t endpoint = 0; // Default value for endpoint-less topics. ++ if(! uic_dotdot_mqtt::parse_topic(topic,unid,endpoint)) { ++ sl_log_debug(LOG_TAG, ++ "Error parsing UNID / Endpoint ID from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ std::string last_item; ++ if (SL_STATUS_OK != uic_dotdot_mqtt::get_topic_last_item(topic,last_item)){ ++ sl_log_debug(LOG_TAG, ++ "Error parsing last item from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ uic_mqtt_dotdot_attribute_update_type_t update_type; ++ if (last_item == "Reported") { ++ update_type = UCL_REPORTED_UPDATED; ++ } else if (last_item == "Desired") { ++ update_type = UCL_DESIRED_UPDATED; ++ } else { ++ sl_log_debug(LOG_TAG, ++ "Unknown value type (neither Desired/Reported) for topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ // Empty message means unretained value. ++ bool unretained = false; ++ if (message_length == 0) { ++ unretained = true; ++ } ++ ++ ++ uint8_t blue = {}; ++ ++ nlohmann::json json_payload; ++ try { ++ ++ if (unretained == false) { ++ json_payload = nlohmann::json::parse(std::string(message)); ++ ++ if (json_payload.find("value") == json_payload.end()) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor::Blue: Missing attribute element: 'value'\n"); ++ return; ++ } ++// Start parsing value ++ blue = json_payload.at("value").get(); ++ ++ // End parsing value ++ } ++ ++ } catch (const std::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "value", message); ++ return; ++ } ++ ++ uic_mqtt_dotdot_unify_switch_color_attribute_blue_callback( ++ static_cast(unid.c_str()), ++ endpoint, ++ unretained, ++ update_type, ++ blue ++ ); ++ ++} ++static void uic_mqtt_dotdot_on_unify_switch_color_amber_attribute_update( ++ const char *topic, ++ const char *message, ++ const size_t message_length) { ++ if (uic_mqtt_dotdot_unify_switch_color_attribute_amber_callback == nullptr) { ++ return; ++ } ++ ++ std::string unid; ++ uint8_t endpoint = 0; // Default value for endpoint-less topics. ++ if(! uic_dotdot_mqtt::parse_topic(topic,unid,endpoint)) { ++ sl_log_debug(LOG_TAG, ++ "Error parsing UNID / Endpoint ID from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ std::string last_item; ++ if (SL_STATUS_OK != uic_dotdot_mqtt::get_topic_last_item(topic,last_item)){ ++ sl_log_debug(LOG_TAG, ++ "Error parsing last item from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ uic_mqtt_dotdot_attribute_update_type_t update_type; ++ if (last_item == "Reported") { ++ update_type = UCL_REPORTED_UPDATED; ++ } else if (last_item == "Desired") { ++ update_type = UCL_DESIRED_UPDATED; ++ } else { ++ sl_log_debug(LOG_TAG, ++ "Unknown value type (neither Desired/Reported) for topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ // Empty message means unretained value. ++ bool unretained = false; ++ if (message_length == 0) { ++ unretained = true; ++ } ++ ++ ++ uint8_t amber = {}; ++ ++ nlohmann::json json_payload; ++ try { ++ ++ if (unretained == false) { ++ json_payload = nlohmann::json::parse(std::string(message)); ++ ++ if (json_payload.find("value") == json_payload.end()) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor::Amber: Missing attribute element: 'value'\n"); ++ return; ++ } ++// Start parsing value ++ amber = json_payload.at("value").get(); ++ ++ // End parsing value ++ } ++ ++ } catch (const std::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "value", message); ++ return; ++ } ++ ++ uic_mqtt_dotdot_unify_switch_color_attribute_amber_callback( ++ static_cast(unid.c_str()), ++ endpoint, ++ unretained, ++ update_type, ++ amber ++ ); ++ ++} ++static void uic_mqtt_dotdot_on_unify_switch_color_cyan_attribute_update( ++ const char *topic, ++ const char *message, ++ const size_t message_length) { ++ if (uic_mqtt_dotdot_unify_switch_color_attribute_cyan_callback == nullptr) { ++ return; ++ } ++ ++ std::string unid; ++ uint8_t endpoint = 0; // Default value for endpoint-less topics. ++ if(! uic_dotdot_mqtt::parse_topic(topic,unid,endpoint)) { ++ sl_log_debug(LOG_TAG, ++ "Error parsing UNID / Endpoint ID from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ std::string last_item; ++ if (SL_STATUS_OK != uic_dotdot_mqtt::get_topic_last_item(topic,last_item)){ ++ sl_log_debug(LOG_TAG, ++ "Error parsing last item from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ uic_mqtt_dotdot_attribute_update_type_t update_type; ++ if (last_item == "Reported") { ++ update_type = UCL_REPORTED_UPDATED; ++ } else if (last_item == "Desired") { ++ update_type = UCL_DESIRED_UPDATED; ++ } else { ++ sl_log_debug(LOG_TAG, ++ "Unknown value type (neither Desired/Reported) for topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ // Empty message means unretained value. ++ bool unretained = false; ++ if (message_length == 0) { ++ unretained = true; ++ } ++ ++ ++ uint8_t cyan = {}; ++ ++ nlohmann::json json_payload; ++ try { ++ ++ if (unretained == false) { ++ json_payload = nlohmann::json::parse(std::string(message)); ++ ++ if (json_payload.find("value") == json_payload.end()) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor::Cyan: Missing attribute element: 'value'\n"); ++ return; ++ } ++// Start parsing value ++ cyan = json_payload.at("value").get(); ++ ++ // End parsing value ++ } ++ ++ } catch (const std::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "value", message); ++ return; ++ } ++ ++ uic_mqtt_dotdot_unify_switch_color_attribute_cyan_callback( ++ static_cast(unid.c_str()), ++ endpoint, ++ unretained, ++ update_type, ++ cyan ++ ); ++ ++} ++static void uic_mqtt_dotdot_on_unify_switch_color_purple_attribute_update( ++ const char *topic, ++ const char *message, ++ const size_t message_length) { ++ if (uic_mqtt_dotdot_unify_switch_color_attribute_purple_callback == nullptr) { ++ return; ++ } ++ ++ std::string unid; ++ uint8_t endpoint = 0; // Default value for endpoint-less topics. ++ if(! uic_dotdot_mqtt::parse_topic(topic,unid,endpoint)) { ++ sl_log_debug(LOG_TAG, ++ "Error parsing UNID / Endpoint ID from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ std::string last_item; ++ if (SL_STATUS_OK != uic_dotdot_mqtt::get_topic_last_item(topic,last_item)){ ++ sl_log_debug(LOG_TAG, ++ "Error parsing last item from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ uic_mqtt_dotdot_attribute_update_type_t update_type; ++ if (last_item == "Reported") { ++ update_type = UCL_REPORTED_UPDATED; ++ } else if (last_item == "Desired") { ++ update_type = UCL_DESIRED_UPDATED; ++ } else { ++ sl_log_debug(LOG_TAG, ++ "Unknown value type (neither Desired/Reported) for topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ // Empty message means unretained value. ++ bool unretained = false; ++ if (message_length == 0) { ++ unretained = true; ++ } ++ ++ ++ uint8_t purple = {}; ++ ++ nlohmann::json json_payload; ++ try { ++ ++ if (unretained == false) { ++ json_payload = nlohmann::json::parse(std::string(message)); ++ ++ if (json_payload.find("value") == json_payload.end()) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor::Purple: Missing attribute element: 'value'\n"); ++ return; ++ } ++// Start parsing value ++ purple = json_payload.at("value").get(); ++ ++ // End parsing value ++ } ++ ++ } catch (const std::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "value", message); ++ return; ++ } ++ ++ uic_mqtt_dotdot_unify_switch_color_attribute_purple_callback( ++ static_cast(unid.c_str()), ++ endpoint, ++ unretained, ++ update_type, ++ purple ++ ); ++ ++} ++ ++/////////////////////////////////////////////////////////////////////////////// ++// Attribute init functions for UnifySwitchColor ++/////////////////////////////////////////////////////////////////////////////// ++sl_status_t uic_mqtt_dotdot_unify_switch_color_attributes_init() ++{ ++ std::string base_topic = "ucl/by-unid/+/+/"; ++ ++ std::string subscription_topic; ++ if(uic_mqtt_dotdot_unify_switch_color_attribute_warm_white_callback) { ++ subscription_topic = base_topic + "UnifySwitchColor/Attributes/WarmWhite/#"; ++ uic_mqtt_subscribe(subscription_topic.c_str(), &uic_mqtt_dotdot_on_unify_switch_color_warm_white_attribute_update); ++ } ++ if(uic_mqtt_dotdot_unify_switch_color_attribute_cold_white_callback) { ++ subscription_topic = base_topic + "UnifySwitchColor/Attributes/ColdWhite/#"; ++ uic_mqtt_subscribe(subscription_topic.c_str(), &uic_mqtt_dotdot_on_unify_switch_color_cold_white_attribute_update); ++ } ++ if(uic_mqtt_dotdot_unify_switch_color_attribute_red_callback) { ++ subscription_topic = base_topic + "UnifySwitchColor/Attributes/Red/#"; ++ uic_mqtt_subscribe(subscription_topic.c_str(), &uic_mqtt_dotdot_on_unify_switch_color_red_attribute_update); ++ } ++ if(uic_mqtt_dotdot_unify_switch_color_attribute_green_callback) { ++ subscription_topic = base_topic + "UnifySwitchColor/Attributes/Green/#"; ++ uic_mqtt_subscribe(subscription_topic.c_str(), &uic_mqtt_dotdot_on_unify_switch_color_green_attribute_update); ++ } ++ if(uic_mqtt_dotdot_unify_switch_color_attribute_blue_callback) { ++ subscription_topic = base_topic + "UnifySwitchColor/Attributes/Blue/#"; ++ uic_mqtt_subscribe(subscription_topic.c_str(), &uic_mqtt_dotdot_on_unify_switch_color_blue_attribute_update); ++ } ++ if(uic_mqtt_dotdot_unify_switch_color_attribute_amber_callback) { ++ subscription_topic = base_topic + "UnifySwitchColor/Attributes/Amber/#"; ++ uic_mqtt_subscribe(subscription_topic.c_str(), &uic_mqtt_dotdot_on_unify_switch_color_amber_attribute_update); ++ } ++ if(uic_mqtt_dotdot_unify_switch_color_attribute_cyan_callback) { ++ subscription_topic = base_topic + "UnifySwitchColor/Attributes/Cyan/#"; ++ uic_mqtt_subscribe(subscription_topic.c_str(), &uic_mqtt_dotdot_on_unify_switch_color_cyan_attribute_update); ++ } ++ if(uic_mqtt_dotdot_unify_switch_color_attribute_purple_callback) { ++ subscription_topic = base_topic + "UnifySwitchColor/Attributes/Purple/#"; ++ uic_mqtt_subscribe(subscription_topic.c_str(), &uic_mqtt_dotdot_on_unify_switch_color_purple_attribute_update); ++ } ++ ++ return SL_STATUS_OK; ++} ++ ++ ++/////////////////////////////////////////////////////////////////////////////// ++// Callback setters and getters for UnifySwitchColor ++/////////////////////////////////////////////////////////////////////////////// ++void uic_mqtt_dotdot_unify_switch_color_attribute_warm_white_callback_set(const uic_mqtt_dotdot_unify_switch_color_attribute_warm_white_callback_t callback) ++{ ++ uic_mqtt_dotdot_unify_switch_color_attribute_warm_white_callback = callback; ++} ++void uic_mqtt_dotdot_unify_switch_color_attribute_cold_white_callback_set(const uic_mqtt_dotdot_unify_switch_color_attribute_cold_white_callback_t callback) ++{ ++ uic_mqtt_dotdot_unify_switch_color_attribute_cold_white_callback = callback; ++} ++void uic_mqtt_dotdot_unify_switch_color_attribute_red_callback_set(const uic_mqtt_dotdot_unify_switch_color_attribute_red_callback_t callback) ++{ ++ uic_mqtt_dotdot_unify_switch_color_attribute_red_callback = callback; ++} ++void uic_mqtt_dotdot_unify_switch_color_attribute_green_callback_set(const uic_mqtt_dotdot_unify_switch_color_attribute_green_callback_t callback) ++{ ++ uic_mqtt_dotdot_unify_switch_color_attribute_green_callback = callback; ++} ++void uic_mqtt_dotdot_unify_switch_color_attribute_blue_callback_set(const uic_mqtt_dotdot_unify_switch_color_attribute_blue_callback_t callback) ++{ ++ uic_mqtt_dotdot_unify_switch_color_attribute_blue_callback = callback; ++} ++void uic_mqtt_dotdot_unify_switch_color_attribute_amber_callback_set(const uic_mqtt_dotdot_unify_switch_color_attribute_amber_callback_t callback) ++{ ++ uic_mqtt_dotdot_unify_switch_color_attribute_amber_callback = callback; ++} ++void uic_mqtt_dotdot_unify_switch_color_attribute_cyan_callback_set(const uic_mqtt_dotdot_unify_switch_color_attribute_cyan_callback_t callback) ++{ ++ uic_mqtt_dotdot_unify_switch_color_attribute_cyan_callback = callback; ++} ++void uic_mqtt_dotdot_unify_switch_color_attribute_purple_callback_set(const uic_mqtt_dotdot_unify_switch_color_attribute_purple_callback_t callback) ++{ ++ uic_mqtt_dotdot_unify_switch_color_attribute_purple_callback = callback; ++} ++ ++// End of supported cluster. ++ +diff --git a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_command_helpers.cpp b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_command_helpers.cpp +index 9dcceb98fc..9c5fea5705 100644 +--- a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_command_helpers.cpp ++++ b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_command_helpers.cpp +@@ -15957,5 +15957,181 @@ void uic_mqtt_dotdot_parse_unify_humidity_control_write_attributes( + + + ++} ++ ++ ++std::string get_json_payload_for_unify_switch_color_set_color_command( ++ ++ const uic_mqtt_dotdot_unify_switch_color_command_set_color_fields_t *fields ++ ++){ ++ bool command_with_no_fields = true; ++ ++ // Create a JSON payload from all the parameters ++ nlohmann::json json_payload; ++ command_with_no_fields = false; ++ // Single Value ++ // Non-enum and non-bitmask (struct, string or scalar) ++ json_payload["ColorComponentId"] = nlohmann::json(fields->color_component_id); ++ command_with_no_fields = false; ++ // Single Value ++ // Non-enum and non-bitmask (struct, string or scalar) ++ json_payload["Value"] = nlohmann::json(fields->value); ++ command_with_no_fields = false; ++ // Single Value ++ // Non-enum and non-bitmask (struct, string or scalar) ++ json_payload["Duration"] = nlohmann::json(fields->duration); ++ ++ // Get the string ++ if (command_with_no_fields == true) { ++ return std::string("{}"); ++ } ++ // Payload may contain data from end nodes, which we cannot control, thus we handle if there are non-utf8 characters ++ return json_payload.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace); ++} ++ ++ ++void uic_mqtt_dotdot_parse_unify_switch_color_set_color( ++ nlohmann::json &jsn, ++ uint8_t &color_component_id, ++ ++ uint8_t &value, ++ ++ uint32_t &duration ++ ++) { ++ ++ if (jsn.at("ColorComponentId").is_null()) { ++ sl_log_debug(LOG_TAG, "Ignoring JSON Null object"); ++ return; ++ } ++ ++ color_component_id = jsn.at("ColorComponentId").get< uint8_t >(); ++ if (jsn.at("Value").is_null()) { ++ sl_log_debug(LOG_TAG, "Ignoring JSON Null object"); ++ return; ++ } ++ ++ value = jsn.at("Value").get< uint8_t >(); ++ if (jsn.at("Duration").is_null()) { ++ sl_log_debug(LOG_TAG, "Ignoring JSON Null object"); ++ return; ++ } ++ ++ duration = jsn.at("Duration").get< uint32_t >(); ++ } ++ ++ ++std::string get_json_payload_for_unify_switch_color_start_stop_change_command( ++ ++ const uic_mqtt_dotdot_unify_switch_color_command_start_stop_change_fields_t *fields ++ ++){ ++ bool command_with_no_fields = true; ++ ++ // Create a JSON payload from all the parameters ++ nlohmann::json json_payload; ++ command_with_no_fields = false; ++ // Single Value ++ // Non-enum and non-bitmask (struct, string or scalar) ++ json_payload["StartStop"] = nlohmann::json(fields->start_stop); ++ command_with_no_fields = false; ++ // Single Value ++ // Non-enum and non-bitmask (struct, string or scalar) ++ json_payload["UpDown"] = nlohmann::json(fields->up_down); ++ command_with_no_fields = false; ++ // Single Value ++ // Non-enum and non-bitmask (struct, string or scalar) ++ json_payload["IgnorStartLevel"] = nlohmann::json(fields->ignor_start_level); ++ command_with_no_fields = false; ++ // Single Value ++ // Non-enum and non-bitmask (struct, string or scalar) ++ json_payload["ColorComponentId"] = nlohmann::json(fields->color_component_id); ++ command_with_no_fields = false; ++ // Single Value ++ // Non-enum and non-bitmask (struct, string or scalar) ++ json_payload["StartLevel"] = nlohmann::json(fields->start_level); ++ command_with_no_fields = false; ++ // Single Value ++ // Non-enum and non-bitmask (struct, string or scalar) ++ json_payload["Duration"] = nlohmann::json(fields->duration); ++ ++ // Get the string ++ if (command_with_no_fields == true) { ++ return std::string("{}"); ++ } ++ // Payload may contain data from end nodes, which we cannot control, thus we handle if there are non-utf8 characters ++ return json_payload.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace); ++} ++ ++ ++void uic_mqtt_dotdot_parse_unify_switch_color_start_stop_change( ++ nlohmann::json &jsn, ++ bool &start_stop, ++ ++ bool &up_down, ++ ++ bool &ignor_start_level, ++ ++ uint8_t &color_component_id, ++ ++ uint8_t &start_level, ++ ++ uint32_t &duration ++ ++) { ++ ++ if (jsn.at("StartStop").is_null()) { ++ sl_log_debug(LOG_TAG, "Ignoring JSON Null object"); ++ return; ++ } ++ ++ start_stop = jsn.at("StartStop").get< bool >(); ++ if (jsn.at("UpDown").is_null()) { ++ sl_log_debug(LOG_TAG, "Ignoring JSON Null object"); ++ return; ++ } ++ ++ up_down = jsn.at("UpDown").get< bool >(); ++ if (jsn.at("IgnorStartLevel").is_null()) { ++ sl_log_debug(LOG_TAG, "Ignoring JSON Null object"); ++ return; ++ } ++ ++ ignor_start_level = jsn.at("IgnorStartLevel").get< bool >(); ++ if (jsn.at("ColorComponentId").is_null()) { ++ sl_log_debug(LOG_TAG, "Ignoring JSON Null object"); ++ return; ++ } ++ ++ color_component_id = jsn.at("ColorComponentId").get< uint8_t >(); ++ if (jsn.at("StartLevel").is_null()) { ++ sl_log_debug(LOG_TAG, "Ignoring JSON Null object"); ++ return; ++ } ++ ++ start_level = jsn.at("StartLevel").get< uint8_t >(); ++ if (jsn.at("Duration").is_null()) { ++ sl_log_debug(LOG_TAG, "Ignoring JSON Null object"); ++ return; ++ } ++ ++ duration = jsn.at("Duration").get< uint32_t >(); ++ } ++ ++ ++/** ++ * @brief JSON parser for ::WriteAttributes command arguments. ++ * ++ * Parse incoming JSON object to populate command arguments passed in by reference. ++ */ ++void uic_mqtt_dotdot_parse_unify_switch_color_write_attributes( ++ nlohmann::json &jsn, ++ uic_mqtt_dotdot_unify_switch_color_state_t &new_state, ++ uic_mqtt_dotdot_unify_switch_color_updated_state_t &new_updated_state ++) { ++ ++ ++ + } + +diff --git a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_command_helpers.hpp b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_command_helpers.hpp +index ede2d6189e..5ecd3fe972 100644 +--- a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_command_helpers.hpp ++++ b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_command_helpers.hpp +@@ -6650,6 +6650,88 @@ void uic_mqtt_dotdot_parse_unify_humidity_control_write_attributes( + ); + + ++/** ++ * @brief Private helper function that will create a JSON string based on the ++ * fields of a UnifySwitchColor SetColor command ++ * ++ * @param fields Struct pointer with the list of fields for the command ++ * ++ * @returns std::string that contains JSON payload ++ */ ++std::string get_json_payload_for_unify_switch_color_set_color_command( ++ ++ const uic_mqtt_dotdot_unify_switch_color_command_set_color_fields_t *fields ++ ++); ++ ++ ++/** ++ * @brief JSON parser for UnifySwitchColor SetColor command arguments. ++ * ++ * Parse incoming JSON object to populate command arguments passed in by reference. ++ */ ++void uic_mqtt_dotdot_parse_unify_switch_color_set_color( ++ nlohmann::json &jsn, ++ uint8_t &color_component_id, ++ ++ uint8_t &value, ++ ++ uint32_t &duration ++ ++); ++ ++ ++ ++/** ++ * @brief Private helper function that will create a JSON string based on the ++ * fields of a UnifySwitchColor StartStopChange command ++ * ++ * @param fields Struct pointer with the list of fields for the command ++ * ++ * @returns std::string that contains JSON payload ++ */ ++std::string get_json_payload_for_unify_switch_color_start_stop_change_command( ++ ++ const uic_mqtt_dotdot_unify_switch_color_command_start_stop_change_fields_t *fields ++ ++); ++ ++ ++/** ++ * @brief JSON parser for UnifySwitchColor StartStopChange command arguments. ++ * ++ * Parse incoming JSON object to populate command arguments passed in by reference. ++ */ ++void uic_mqtt_dotdot_parse_unify_switch_color_start_stop_change( ++ nlohmann::json &jsn, ++ bool &start_stop, ++ ++ bool &up_down, ++ ++ bool &ignor_start_level, ++ ++ uint8_t &color_component_id, ++ ++ uint8_t &start_level, ++ ++ uint32_t &duration ++ ++); ++ ++ ++ ++/** ++ * @brief JSON parser for UnifySwitchColor WriteAttributes command arguments. ++ * ++ * Parse incoming JSON object to populate command arguments passed in by reference. ++ */ ++void uic_mqtt_dotdot_parse_unify_switch_color_write_attributes( ++ nlohmann::json &jsn, ++ uic_mqtt_dotdot_unify_switch_color_state_t &new_state, ++ uic_mqtt_dotdot_unify_switch_color_updated_state_t &new_updated_state ++); ++ ++ + + #endif //DOTDOT_MQTT_COMMAND_HELPERS_HPP + /** @} end dotdot_mqtt_command_helpers */ +diff --git a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_generated_commands.cpp b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_generated_commands.cpp +index 523ffd0855..e2e522b193 100644 +--- a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_generated_commands.cpp ++++ b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_generated_commands.cpp +@@ -12047,3 +12047,115 @@ void uic_mqtt_dotdot_unify_humidity_control_publish_generated_write_attributes_c + false); + } + ++/** ++ * @brief Publishes an incoming/generated SetColor command for ++ * the UnifySwitchColor cluster. ++ * ++ * Publication will be made at the following topic ++ * ucl/by-unid/UNID/epID/UnifySwitchColor/GeneratedCommands/SetColor ++ * ++ * @param unid The UNID of the node that sent us the command. ++ * ++ * @param endpoint The Endpoint ID of the node that sent us the command. ++ * ++ * ++ * @param fields Struct pointer with the fields value of the command ++ * ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_generated_set_color_command( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint, ++ const uic_mqtt_dotdot_unify_switch_color_command_set_color_fields_t *fields ++ ++) { ++ // Create the topic ++ std::string topic = "ucl/by-unid/"+ std::string(unid) + "/ep" + ++ std::to_string(endpoint) + "/"; ++ topic += "UnifySwitchColor/GeneratedCommands/SetColor"; ++ ++ std::string payload = ++ get_json_payload_for_unify_switch_color_set_color_command( ++ fields); ++ ++ // Publish our command ++ uic_mqtt_publish(topic.c_str(), ++ payload.c_str(), ++ payload.size(), ++ false); ++} ++/** ++ * @brief Publishes an incoming/generated StartStopChange command for ++ * the UnifySwitchColor cluster. ++ * ++ * Publication will be made at the following topic ++ * ucl/by-unid/UNID/epID/UnifySwitchColor/GeneratedCommands/StartStopChange ++ * ++ * @param unid The UNID of the node that sent us the command. ++ * ++ * @param endpoint The Endpoint ID of the node that sent us the command. ++ * ++ * ++ * @param fields Struct pointer with the fields value of the command ++ * ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_generated_start_stop_change_command( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint, ++ const uic_mqtt_dotdot_unify_switch_color_command_start_stop_change_fields_t *fields ++ ++) { ++ // Create the topic ++ std::string topic = "ucl/by-unid/"+ std::string(unid) + "/ep" + ++ std::to_string(endpoint) + "/"; ++ topic += "UnifySwitchColor/GeneratedCommands/StartStopChange"; ++ ++ std::string payload = ++ get_json_payload_for_unify_switch_color_start_stop_change_command( ++ fields); ++ ++ // Publish our command ++ uic_mqtt_publish(topic.c_str(), ++ payload.c_str(), ++ payload.size(), ++ false); ++} ++ ++ ++/** ++ * @brief Publishes an incoming/generated WriteAttributes command for ++ * the UnifySwitchColor cluster. ++ * ++ * Publication will be made at the following topic ++ * ucl/by-unid/UNID/epID/UnifySwitchColor/GeneratedCommands/WriteAttributes ++ * ++ * @param unid The UNID of the node that sent us the command. ++ * ++ * @param endpoint The Endpoint ID of the node that sent us the command. ++ * ++ * @param attribute_values Values to assign to the attributes ++ * @param attribute_list List of attributes that are written ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_generated_write_attributes_command( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint, ++ uic_mqtt_dotdot_unify_switch_color_state_t attribute_values, ++ uic_mqtt_dotdot_unify_switch_color_updated_state_t attribute_list ++){ ++ // Create the topic ++ std::string topic = "ucl/by-unid/"+ std::string(unid) + "/ep" + ++ std::to_string(endpoint) + "/"; ++ topic += "UnifySwitchColor/GeneratedCommands/WriteAttributes"; ++ ++ nlohmann::json json_object = nlohmann::json::object(); ++ ++ ++ // Payload contains data from end nodes, which we cannot control, thus we handle if there are non-utf8 characters ++ std::string payload = json_object.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace); ++ ++ // Publish our command ++ uic_mqtt_publish(topic.c_str(), ++ payload.c_str(), ++ payload.size(), ++ false); ++} ++ +diff --git a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_group_commands.cpp b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_group_commands.cpp +index 295e2af47e..15eb05a694 100644 +--- a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_group_commands.cpp ++++ b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_group_commands.cpp +@@ -393,6 +393,11 @@ static uic_mqtt_dotdot_by_group_unify_humidity_control_setpoint_set_callback_t u + static uic_mqtt_dotdot_by_group_unify_humidity_control_write_attributes_callback_t uic_mqtt_dotdot_by_group_unify_humidity_control_write_attributes_callback = nullptr; + + ++static uic_mqtt_dotdot_by_group_unify_switch_color_set_color_callback_t uic_mqtt_dotdot_by_group_unify_switch_color_set_color_callback = nullptr; ++static uic_mqtt_dotdot_by_group_unify_switch_color_start_stop_change_callback_t uic_mqtt_dotdot_by_group_unify_switch_color_start_stop_change_callback = nullptr; ++static uic_mqtt_dotdot_by_group_unify_switch_color_write_attributes_callback_t uic_mqtt_dotdot_by_group_unify_switch_color_write_attributes_callback = nullptr; ++ ++ + + // Callbacks setters + +@@ -2047,6 +2052,27 @@ void uic_mqtt_dotdot_by_group_unify_humidity_control_write_attributes_callback_s + + + ++// Callbacks setters ++ ++void uic_mqtt_dotdot_by_group_unify_switch_color_set_color_callback_set(const uic_mqtt_dotdot_by_group_unify_switch_color_set_color_callback_t callback) ++{ ++ uic_mqtt_dotdot_by_group_unify_switch_color_set_color_callback = callback; ++} ++ ++ ++void uic_mqtt_dotdot_by_group_unify_switch_color_start_stop_change_callback_set(const uic_mqtt_dotdot_by_group_unify_switch_color_start_stop_change_callback_t callback) ++{ ++ uic_mqtt_dotdot_by_group_unify_switch_color_start_stop_change_callback = callback; ++} ++ ++void uic_mqtt_dotdot_by_group_unify_switch_color_write_attributes_callback_set( ++ const uic_mqtt_dotdot_by_group_unify_switch_color_write_attributes_callback_t callback) ++{ ++ uic_mqtt_dotdot_by_group_unify_switch_color_write_attributes_callback = callback; ++} ++ ++ ++ + + // Callback function for incoming publications on ucl/by-group/+/Basic/Commands/ResetToFactoryDefaults + static void uic_mqtt_dotdot_on_by_group_basic_reset_to_factory_defaults( +@@ -25768,6 +25794,311 @@ sl_status_t uic_mqtt_dotdot_by_group_unify_humidity_control_init() + + + ++ ++// Callback function for incoming publications on ucl/by-group/+/UnifySwitchColor/Commands/SetColor ++static void uic_mqtt_dotdot_on_by_group_unify_switch_color_set_color( ++ const char *topic, ++ const char *message, ++ const size_t message_length) ++{ ++ if ((group_dispatch_callback == nullptr) && (uic_mqtt_dotdot_by_group_unify_switch_color_set_color_callback == nullptr)) { ++ return; ++ } ++ if (message_length == 0) { ++ return; ++ } ++ ++ dotdot_group_id_t group_id = 0U; ++ if(!uic_dotdot_mqtt::parse_topic_group_id(topic,group_id)) { ++ sl_log_debug(LOG_TAG, ++ "Failed to parse GroupId from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ // Pass to command-specific callback if set. Otherwise, pass to ++ // group-dispatch callback ++ if (uic_mqtt_dotdot_by_group_unify_switch_color_set_color_callback != nullptr) { ++ ++ ++ uic_mqtt_dotdot_unify_switch_color_command_set_color_fields_t fields; ++ ++ ++ nlohmann::json jsn; ++ try { ++ jsn = nlohmann::json::parse(std::string(message)); ++ ++ ++ uic_mqtt_dotdot_parse_unify_switch_color_set_color( ++ jsn, ++ fields.color_component_id, ++ ++ fields.value, ++ ++ fields.duration ++ ); ++ ++ // Populate list fields from vector or string types ++ ++ ++ } catch (const nlohmann::json::parse_error& e) { ++ // Catch JSON object field parsing errors ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_PARSE_FAIL, "UnifySwitchColor", "SetColor"); ++ return; ++ } catch (const nlohmann::json::exception& e) { ++ // Catch JSON object field parsing errors ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor", "SetColor", e.what()); ++ return; ++ } catch (const std::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor", "SetColor", ""); ++ return; ++ } ++ ++ uic_mqtt_dotdot_by_group_unify_switch_color_set_color_callback( ++ group_id, ++ &fields ++ ); ++ } else if ((group_dispatch_callback != nullptr) && (!get_uic_mqtt_dotdot_unify_switch_color_set_color_callback().empty())) { ++ // group-dispatch callback only called if the command-specific by-unid ++ // callback is set ++ try { ++ nlohmann::json jsn = nlohmann::json::parse(std::string(message)); ++ if (jsn.find("ColorComponentId") == jsn.end()) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor::SetColor: Missing command-argument: ColorComponentId\n"); ++ return; ++ } ++ if (jsn.find("Value") == jsn.end()) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor::SetColor: Missing command-argument: Value\n"); ++ return; ++ } ++ if (jsn.find("Duration") == jsn.end()) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor::SetColor: Missing command-argument: Duration\n"); ++ return; ++ } ++ ++ group_dispatch_callback( ++ group_id, ++ "UnifySwitchColor", ++ "SetColor", ++ message, ++ message_length, ++ uic_mqtt_dotdot_on_unify_switch_color_set_color); ++ ++ } catch (...) { ++ sl_log_debug(LOG_TAG, "SetColor: Unable to parse JSON payload.\n"); ++ return; ++ } ++ } ++ ++} ++ ++// Callback function for incoming publications on ucl/by-group/+/UnifySwitchColor/Commands/StartStopChange ++static void uic_mqtt_dotdot_on_by_group_unify_switch_color_start_stop_change( ++ const char *topic, ++ const char *message, ++ const size_t message_length) ++{ ++ if ((group_dispatch_callback == nullptr) && (uic_mqtt_dotdot_by_group_unify_switch_color_start_stop_change_callback == nullptr)) { ++ return; ++ } ++ if (message_length == 0) { ++ return; ++ } ++ ++ dotdot_group_id_t group_id = 0U; ++ if(!uic_dotdot_mqtt::parse_topic_group_id(topic,group_id)) { ++ sl_log_debug(LOG_TAG, ++ "Failed to parse GroupId from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ // Pass to command-specific callback if set. Otherwise, pass to ++ // group-dispatch callback ++ if (uic_mqtt_dotdot_by_group_unify_switch_color_start_stop_change_callback != nullptr) { ++ ++ ++ uic_mqtt_dotdot_unify_switch_color_command_start_stop_change_fields_t fields; ++ ++ ++ nlohmann::json jsn; ++ try { ++ jsn = nlohmann::json::parse(std::string(message)); ++ ++ ++ uic_mqtt_dotdot_parse_unify_switch_color_start_stop_change( ++ jsn, ++ fields.start_stop, ++ ++ fields.up_down, ++ ++ fields.ignor_start_level, ++ ++ fields.color_component_id, ++ ++ fields.start_level, ++ ++ fields.duration ++ ); ++ ++ // Populate list fields from vector or string types ++ ++ ++ } catch (const nlohmann::json::parse_error& e) { ++ // Catch JSON object field parsing errors ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_PARSE_FAIL, "UnifySwitchColor", "StartStopChange"); ++ return; ++ } catch (const nlohmann::json::exception& e) { ++ // Catch JSON object field parsing errors ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor", "StartStopChange", e.what()); ++ return; ++ } catch (const std::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor", "StartStopChange", ""); ++ return; ++ } ++ ++ uic_mqtt_dotdot_by_group_unify_switch_color_start_stop_change_callback( ++ group_id, ++ &fields ++ ); ++ } else if ((group_dispatch_callback != nullptr) && (!get_uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback().empty())) { ++ // group-dispatch callback only called if the command-specific by-unid ++ // callback is set ++ try { ++ nlohmann::json jsn = nlohmann::json::parse(std::string(message)); ++ if (jsn.find("StartStop") == jsn.end()) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor::StartStopChange: Missing command-argument: StartStop\n"); ++ return; ++ } ++ if (jsn.find("UpDown") == jsn.end()) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor::StartStopChange: Missing command-argument: UpDown\n"); ++ return; ++ } ++ if (jsn.find("IgnorStartLevel") == jsn.end()) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor::StartStopChange: Missing command-argument: IgnorStartLevel\n"); ++ return; ++ } ++ if (jsn.find("ColorComponentId") == jsn.end()) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor::StartStopChange: Missing command-argument: ColorComponentId\n"); ++ return; ++ } ++ if (jsn.find("StartLevel") == jsn.end()) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor::StartStopChange: Missing command-argument: StartLevel\n"); ++ return; ++ } ++ if (jsn.find("Duration") == jsn.end()) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor::StartStopChange: Missing command-argument: Duration\n"); ++ return; ++ } ++ ++ group_dispatch_callback( ++ group_id, ++ "UnifySwitchColor", ++ "StartStopChange", ++ message, ++ message_length, ++ uic_mqtt_dotdot_on_unify_switch_color_start_stop_change); ++ ++ } catch (...) { ++ sl_log_debug(LOG_TAG, "StartStopChange: Unable to parse JSON payload.\n"); ++ return; ++ } ++ } ++ ++} ++ ++static void uic_mqtt_dotdot_on_by_group_unify_switch_color_WriteAttributes( ++ const char *topic, ++ const char *message, ++ const size_t message_length) ++{ ++ ++ if ((group_dispatch_callback == nullptr) && (uic_mqtt_dotdot_by_group_unify_switch_color_write_attributes_callback == nullptr)) { ++ return; ++ } ++ if (message_length == 0) { ++ return; ++ } ++ ++ dotdot_group_id_t group_id = 0U; ++ if(!uic_dotdot_mqtt::parse_topic_group_id(topic,group_id)) { ++ sl_log_debug(LOG_TAG, ++ "Failed to parse GroupId from topic %s. Ignoring", ++ topic); ++ return; ++ } ++ ++ if ((group_dispatch_callback != nullptr) && (!get_uic_mqtt_dotdot_unify_switch_color_write_attributes_callback().empty())) { ++ try { ++ group_dispatch_callback(group_id, ++ "UnifySwitchColor", ++ "WriteAttributes", ++ message, ++ message_length, ++ uic_mqtt_dotdot_on_unify_switch_color_WriteAttributes); ++ ++ } catch (...) { ++ sl_log_debug(LOG_TAG, "UnifySwitchColor: Unable to parse JSON payload.\n"); ++ return; ++ } ++ } else if (uic_mqtt_dotdot_by_group_unify_switch_color_write_attributes_callback != nullptr) { ++ ++ uic_mqtt_dotdot_unify_switch_color_state_t new_state = {}; ++ uic_mqtt_dotdot_unify_switch_color_updated_state_t new_updated_state = {}; ++ ++ ++ nlohmann::json jsn; ++ try { ++ jsn = nlohmann::json::parse(std::string(message)); ++ ++ uic_mqtt_dotdot_parse_unify_switch_color_write_attributes( ++ jsn, ++ new_state, ++ new_updated_state ++ ); ++ } catch (const nlohmann::json::parse_error& e) { ++ // Catch JSON object field parsing errors ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_PARSE_FAIL, "UnifySwitchColor", "WriteAttributes"); ++ return; ++ } catch (const nlohmann::json::exception& e) { ++ // Catch JSON object field parsing errors ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor", "WriteAttributes", e.what()); ++ return; ++ } catch (const std::exception& e) { ++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifySwitchColor", "WriteAttributes", ""); ++ return; ++ } ++ ++ uic_mqtt_dotdot_by_group_unify_switch_color_write_attributes_callback( ++ group_id, ++ new_state, ++ new_updated_state ++ ); ++ } ++} ++ ++sl_status_t uic_mqtt_dotdot_by_group_unify_switch_color_init() ++{ ++ std::string subscription_topic; ++ const std::string topic_bygroup = TOPIC_BY_GROUP_PREFIX; ++ if(uic_mqtt_dotdot_by_group_unify_switch_color_write_attributes_callback) { ++ subscription_topic = topic_bygroup + "UnifySwitchColor/Commands/WriteAttributes"; ++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_by_group_unify_switch_color_WriteAttributes); ++ } ++ if (uic_mqtt_dotdot_by_group_unify_switch_color_set_color_callback) { ++ subscription_topic = topic_bygroup + "UnifySwitchColor/Commands/SetColor"; ++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_by_group_unify_switch_color_set_color); ++ } ++ if (uic_mqtt_dotdot_by_group_unify_switch_color_start_stop_change_callback) { ++ subscription_topic = topic_bygroup + "UnifySwitchColor/Commands/StartStopChange"; ++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_by_group_unify_switch_color_start_stop_change); ++ } ++ ++ return SL_STATUS_OK; ++} ++ ++ ++ + void uic_mqtt_dotdot_set_group_dispatch_callback(group_dispatch_t callback) + { + // Check for uninitialized value in order to subscribe with on_group handlers +@@ -26074,6 +26405,10 @@ void uic_mqtt_dotdot_set_group_dispatch_callback(group_dispatch_t callback) + uic_mqtt_subscribe("ucl/by-group/+/UnifyHumidityControl/Commands/ModeSet", uic_mqtt_dotdot_on_by_group_unify_humidity_control_mode_set); + uic_mqtt_subscribe("ucl/by-group/+/UnifyHumidityControl/Commands/SetpointSet", uic_mqtt_dotdot_on_by_group_unify_humidity_control_setpoint_set); + ++ uic_mqtt_subscribe("ucl/by-group/+/UnifySwitchColor/Commands/WriteAttributes", uic_mqtt_dotdot_on_by_group_unify_switch_color_WriteAttributes); ++ uic_mqtt_subscribe("ucl/by-group/+/UnifySwitchColor/Commands/SetColor", uic_mqtt_dotdot_on_by_group_unify_switch_color_set_color); ++ uic_mqtt_subscribe("ucl/by-group/+/UnifySwitchColor/Commands/StartStopChange", uic_mqtt_dotdot_on_by_group_unify_switch_color_start_stop_change); ++ + } + + group_dispatch_callback = callback; +diff --git a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_helpers.cpp b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_helpers.cpp +index 620772af1c..082fdb9bdf 100644 +--- a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_helpers.cpp ++++ b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_helpers.cpp +@@ -10644,6 +10644,57 @@ std::string get_enum_value_name( + #endif + } + ++ if (65441 == cluster_id) { ++ #ifdef UNIFY_SWITCH_COLOR_WARM_WHITE_ENUM_NAME_AVAILABLE ++ if (0 == attribute_id) { ++ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_switch_colorwarm_white instead of this: unify_switch_color_warm_white ++ return unify_switch_color_warm_white_get_enum_value_name(value); ++ } ++ #endif ++ #ifdef UNIFY_SWITCH_COLOR_COLD_WHITE_ENUM_NAME_AVAILABLE ++ if (1 == attribute_id) { ++ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_switch_colorcold_white instead of this: unify_switch_color_cold_white ++ return unify_switch_color_cold_white_get_enum_value_name(value); ++ } ++ #endif ++ #ifdef UNIFY_SWITCH_COLOR_RED_ENUM_NAME_AVAILABLE ++ if (2 == attribute_id) { ++ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_switch_colorred instead of this: unify_switch_color_red ++ return unify_switch_color_red_get_enum_value_name(value); ++ } ++ #endif ++ #ifdef UNIFY_SWITCH_COLOR_GREEN_ENUM_NAME_AVAILABLE ++ if (3 == attribute_id) { ++ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_switch_colorgreen instead of this: unify_switch_color_green ++ return unify_switch_color_green_get_enum_value_name(value); ++ } ++ #endif ++ #ifdef UNIFY_SWITCH_COLOR_BLUE_ENUM_NAME_AVAILABLE ++ if (4 == attribute_id) { ++ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_switch_colorblue instead of this: unify_switch_color_blue ++ return unify_switch_color_blue_get_enum_value_name(value); ++ } ++ #endif ++ #ifdef UNIFY_SWITCH_COLOR_AMBER_ENUM_NAME_AVAILABLE ++ if (5 == attribute_id) { ++ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_switch_coloramber instead of this: unify_switch_color_amber ++ return unify_switch_color_amber_get_enum_value_name(value); ++ } ++ #endif ++ #ifdef UNIFY_SWITCH_COLOR_CYAN_ENUM_NAME_AVAILABLE ++ if (6 == attribute_id) { ++ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_switch_colorcyan instead of this: unify_switch_color_cyan ++ return unify_switch_color_cyan_get_enum_value_name(value); ++ } ++ #endif ++ #ifdef UNIFY_SWITCH_COLOR_PURPLE_ENUM_NAME_AVAILABLE ++ if (7 == attribute_id) { ++ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_switch_colorpurple instead of this: unify_switch_color_purple ++ return unify_switch_color_purple_get_enum_value_name(value); ++ } ++ #endif ++ } ++ + + std::string value_name; + return value_name; +@@ -15202,6 +15253,57 @@ uint32_t get_enum_name_value( + #endif + } + ++ if (65441 == cluster_id) { ++ #ifdef UNIFY_SWITCH_COLOR_WARM_WHITE_ENUM_NAME_AVAILABLE ++ if (0 == attribute_id) { ++ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_switch_colorwarm_white instead of this: unify_switch_color_warm_white ++ return unify_switch_color_warm_white_get_enum_value_number(name); ++ } ++ #endif ++ #ifdef UNIFY_SWITCH_COLOR_COLD_WHITE_ENUM_NAME_AVAILABLE ++ if (1 == attribute_id) { ++ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_switch_colorcold_white instead of this: unify_switch_color_cold_white ++ return unify_switch_color_cold_white_get_enum_value_number(name); ++ } ++ #endif ++ #ifdef UNIFY_SWITCH_COLOR_RED_ENUM_NAME_AVAILABLE ++ if (2 == attribute_id) { ++ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_switch_colorred instead of this: unify_switch_color_red ++ return unify_switch_color_red_get_enum_value_number(name); ++ } ++ #endif ++ #ifdef UNIFY_SWITCH_COLOR_GREEN_ENUM_NAME_AVAILABLE ++ if (3 == attribute_id) { ++ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_switch_colorgreen instead of this: unify_switch_color_green ++ return unify_switch_color_green_get_enum_value_number(name); ++ } ++ #endif ++ #ifdef UNIFY_SWITCH_COLOR_BLUE_ENUM_NAME_AVAILABLE ++ if (4 == attribute_id) { ++ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_switch_colorblue instead of this: unify_switch_color_blue ++ return unify_switch_color_blue_get_enum_value_number(name); ++ } ++ #endif ++ #ifdef UNIFY_SWITCH_COLOR_AMBER_ENUM_NAME_AVAILABLE ++ if (5 == attribute_id) { ++ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_switch_coloramber instead of this: unify_switch_color_amber ++ return unify_switch_color_amber_get_enum_value_number(name); ++ } ++ #endif ++ #ifdef UNIFY_SWITCH_COLOR_CYAN_ENUM_NAME_AVAILABLE ++ if (6 == attribute_id) { ++ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_switch_colorcyan instead of this: unify_switch_color_cyan ++ return unify_switch_color_cyan_get_enum_value_number(name); ++ } ++ #endif ++ #ifdef UNIFY_SWITCH_COLOR_PURPLE_ENUM_NAME_AVAILABLE ++ if (7 == attribute_id) { ++ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_switch_colorpurple instead of this: unify_switch_color_purple ++ return unify_switch_color_purple_get_enum_value_number(name); ++ } ++ #endif ++ } ++ + + // No known numeric value is set for this string. + // Return UINT32_MAX to indicate an error. +diff --git a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_send_commands.cpp b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_send_commands.cpp +index cbee8704d9..d142a852d8 100644 +--- a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_send_commands.cpp ++++ b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_send_commands.cpp +@@ -15295,3 +15295,151 @@ void uic_mqtt_dotdot_unify_humidity_control_publish_setpoint_set_command_to_grou + payload.size(), + false); + } ++ ++/** ++ * @brief Sends/Publishes a SetColor command for ++ * the UnifySwitchColor cluster to a destination. ++ * ++ * Publication will be made at the following topic ++ * ucl/by-unid/UNID/epID/UnifySwitchColor/Commands/SetColor ++ * ++ * @param destination_unid The UNID of the node that should receive the command. ++ * ++ * @param destination_endpoint The Endpoint ID of the node that should receive the command. ++ * ++ * ++ * @param fields Struct pointer with the fields value of the command ++ * ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_set_color_command( ++ const dotdot_unid_t destination_unid, ++ const dotdot_endpoint_id_t destination_endpoint, ++ const uic_mqtt_dotdot_unify_switch_color_command_set_color_fields_t *fields ++ ++) { ++ // Create the topic ++ std::string topic = "ucl/by-unid/"+ std::string(destination_unid) + "/ep" + ++ std::to_string(destination_endpoint) + "/"; ++ topic += "UnifySwitchColor/Commands/SetColor"; ++ ++ ++ std::string payload = ++ get_json_payload_for_unify_switch_color_set_color_command( ++ fields); ++ ++ sl_log_debug(LOG_TAG, "Sending command to %s with payload %s ---", topic.c_str() , payload.c_str()); ++ ++ // Publish our command, not retained ++ uic_mqtt_publish(topic.c_str(), ++ payload.c_str(), ++ payload.size(), ++ false); ++} ++ ++/** ++ * @brief Sends/Publishes a SetColor command for ++ * the UnifySwitchColor cluster to a group. ++ * ++ * Publication will be made at the following topic ++ * ucl/by-group/GroupID/UnifySwitchColor/Commands/SetColor ++ * ++ * @param destination_group_id The GroupID that should receive the command. ++ * ++ * @param fields Struct pointer with the fields value of the command ++ * ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_set_color_command_to_group( ++ uint16_t destination_group_id, ++ const uic_mqtt_dotdot_unify_switch_color_command_set_color_fields_t *fields ++ ++){ ++ // Create the topic ++ std::string topic = "ucl/by-group/"+ std::to_string(destination_group_id) + ++ "/UnifySwitchColor/Commands/SetColor"; ++ ++ std::string payload = ++ get_json_payload_for_unify_switch_color_set_color_command( ++ fields); ++ ++ sl_log_info(LOG_TAG, "Sending group command to %s with payload %s ---", topic.c_str() , payload.c_str()); ++ ++ // Publish our command, not retained ++ uic_mqtt_publish(topic.c_str(), ++ payload.c_str(), ++ payload.size(), ++ false); ++} ++ ++/** ++ * @brief Sends/Publishes a StartStopChange command for ++ * the UnifySwitchColor cluster to a destination. ++ * ++ * Publication will be made at the following topic ++ * ucl/by-unid/UNID/epID/UnifySwitchColor/Commands/StartStopChange ++ * ++ * @param destination_unid The UNID of the node that should receive the command. ++ * ++ * @param destination_endpoint The Endpoint ID of the node that should receive the command. ++ * ++ * ++ * @param fields Struct pointer with the fields value of the command ++ * ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_start_stop_change_command( ++ const dotdot_unid_t destination_unid, ++ const dotdot_endpoint_id_t destination_endpoint, ++ const uic_mqtt_dotdot_unify_switch_color_command_start_stop_change_fields_t *fields ++ ++) { ++ // Create the topic ++ std::string topic = "ucl/by-unid/"+ std::string(destination_unid) + "/ep" + ++ std::to_string(destination_endpoint) + "/"; ++ topic += "UnifySwitchColor/Commands/StartStopChange"; ++ ++ ++ std::string payload = ++ get_json_payload_for_unify_switch_color_start_stop_change_command( ++ fields); ++ ++ sl_log_debug(LOG_TAG, "Sending command to %s with payload %s ---", topic.c_str() , payload.c_str()); ++ ++ // Publish our command, not retained ++ uic_mqtt_publish(topic.c_str(), ++ payload.c_str(), ++ payload.size(), ++ false); ++} ++ ++/** ++ * @brief Sends/Publishes a StartStopChange command for ++ * the UnifySwitchColor cluster to a group. ++ * ++ * Publication will be made at the following topic ++ * ucl/by-group/GroupID/UnifySwitchColor/Commands/StartStopChange ++ * ++ * @param destination_group_id The GroupID that should receive the command. ++ * ++ * @param fields Struct pointer with the fields value of the command ++ * ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_start_stop_change_command_to_group( ++ uint16_t destination_group_id, ++ const uic_mqtt_dotdot_unify_switch_color_command_start_stop_change_fields_t *fields ++ ++){ ++ // Create the topic ++ std::string topic = "ucl/by-group/"+ std::to_string(destination_group_id) + ++ "/UnifySwitchColor/Commands/StartStopChange"; ++ ++ std::string payload = ++ get_json_payload_for_unify_switch_color_start_stop_change_command( ++ fields); ++ ++ sl_log_info(LOG_TAG, "Sending group command to %s with payload %s ---", topic.c_str() , payload.c_str()); ++ ++ // Publish our command, not retained ++ uic_mqtt_publish(topic.c_str(), ++ payload.c_str(), ++ payload.size(), ++ false); ++} +diff --git a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_supported_generated_commands.cpp b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_supported_generated_commands.cpp +index a615166fa3..0229839e9f 100644 +--- a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_supported_generated_commands.cpp ++++ b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_supported_generated_commands.cpp +@@ -2964,3 +2964,52 @@ void uic_mqtt_dotdot_unify_humidity_control_publish_supported_generated_commands + + } + ++ ++/** ++ * @brief Sends/Publishes a the SupportedGenerated commands for ++ * the UnifySwitchColor cluster for a UNID/Endpoint ++ * ++ * Publication will be made at the following topic ++ * ucl/by-unid/UNID/epID/UnifySwitchColor/SupportedGeneratedCommands ++ * ++ * @param unid The UNID of the node on behalf of which the advertisment is made ++ * ++ * @param endpoint The Endpoint ID of the node on behalf of which the advertisment is made ++ * ++ * @param command_list Struct pointer with the fields value indicating if ++ * individual commands can be generated. ++ */ ++void uic_mqtt_dotdot_unify_switch_color_publish_supported_generated_commands( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint, ++ const uic_mqtt_dotdot_unify_switch_color_supported_commands_t *command_list) ++{ ++ std::string topic = "ucl/by-unid/" + std::string(unid); ++ topic += "/ep"+ std::to_string(endpoint); ++ topic += "/UnifySwitchColor/SupportedGeneratedCommands"; ++ ++ // Assemble of vector of strings for the Supported Commands: ++ std::vector command_vector; ++ if (command_list->set_color == true) { ++ command_vector.emplace_back("SetColor"); ++ } ++ if (command_list->start_stop_change == true) { ++ command_vector.emplace_back("StartStopChange"); ++ } ++ if (command_list->write_attributes == true) { ++ command_vector.emplace_back("WriteAttributes"); ++ } ++ ++ // JSONify, then Stringify ++ nlohmann::json json_payload; ++ json_payload["value"] = command_vector; ++ std::string string_payload = json_payload.dump(); ++ ++ // Publish to MQTT ++ uic_mqtt_publish(topic.c_str(), ++ string_payload.c_str(), ++ string_payload.length(), ++ true); ++ ++} ++ +diff --git a/components/uic_dotdot_mqtt/zap-generated/test/dotdot_mqtt_test.include b/components/uic_dotdot_mqtt/zap-generated/test/dotdot_mqtt_test.include +index 89a5002b0f..0ce338a51e 100644 +--- a/components/uic_dotdot_mqtt/zap-generated/test/dotdot_mqtt_test.include ++++ b/components/uic_dotdot_mqtt/zap-generated/test/dotdot_mqtt_test.include +@@ -3339,6 +3339,46 @@ static sl_status_t uic_mqtt_dotdot_unify_humidity_control_setpoint_set_callback_ + return SL_STATUS_OK; + } + ++static unsigned int uic_mqtt_dotdot_unify_switch_color_set_color_callback_count; ++static sl_status_t uic_mqtt_dotdot_unify_switch_color_set_color_callback_func( ++ dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint, ++ uic_mqtt_dotdot_callback_call_type_t callback_type, ++ uint8_t color_component_id, ++ ++ uint8_t value, ++ ++ uint32_t duration ++ ++) { ++ uic_mqtt_dotdot_unify_switch_color_set_color_callback_count++; ++ num_command_callbacks++; ++ return SL_STATUS_OK; ++} ++ ++static unsigned int uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_count; ++static sl_status_t uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_func( ++ dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint, ++ uic_mqtt_dotdot_callback_call_type_t callback_type, ++ bool start_stop, ++ ++ bool up_down, ++ ++ bool ignor_start_level, ++ ++ uint8_t color_component_id, ++ ++ uint8_t start_level, ++ ++ uint32_t duration ++ ++) { ++ uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_count++; ++ num_command_callbacks++; ++ return SL_STATUS_OK; ++} ++ + static unsigned int set_all_callbacks() + { + unsigned int num_callbacks = 0; +@@ -3765,6 +3805,10 @@ static unsigned int set_all_callbacks() + num_callbacks++; + uic_mqtt_dotdot_unify_humidity_control_setpoint_set_callback_set(&uic_mqtt_dotdot_unify_humidity_control_setpoint_set_callback_func); + num_callbacks++; ++ uic_mqtt_dotdot_unify_switch_color_set_color_callback_set(&uic_mqtt_dotdot_unify_switch_color_set_color_callback_func); ++ num_callbacks++; ++ uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_set(&uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_func); ++ num_callbacks++; + return num_callbacks; + } + +@@ -4036,6 +4080,9 @@ static void unset_all_callbacks() + uic_mqtt_dotdot_unify_humidity_control_mode_set_callback_clear(); + uic_mqtt_dotdot_unify_humidity_control_setpoint_set_callback_clear(); + uic_mqtt_dotdot_clear_unify_humidity_control_write_attributes_callbacks(); ++ uic_mqtt_dotdot_unify_switch_color_set_color_callback_clear(); ++ uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_clear(); ++ uic_mqtt_dotdot_clear_unify_switch_color_write_attributes_callbacks(); + } + + static void reset_callback_counters() +@@ -4252,4 +4299,6 @@ static void reset_callback_counters() + uic_mqtt_dotdot_unify_fan_control_turn_off_callback_count = 0; + uic_mqtt_dotdot_unify_humidity_control_mode_set_callback_count = 0; + uic_mqtt_dotdot_unify_humidity_control_setpoint_set_callback_count = 0; ++ uic_mqtt_dotdot_unify_switch_color_set_color_callback_count = 0; ++ uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_count = 0; + } +diff --git a/components/unify_dotdot_attribute_store/zap-generated/include/dotdot_attributes.uam b/components/unify_dotdot_attribute_store/zap-generated/include/dotdot_attributes.uam +index 68ed25df42..b3cb71a58e 100644 +--- a/components/unify_dotdot_attribute_store/zap-generated/include/dotdot_attributes.uam ++++ b/components/unify_dotdot_attribute_store/zap-generated/include/dotdot_attributes.uam +@@ -904,3 +904,13 @@ def DOTDOT_ATTRIBUTE_ID_UNIFY_HUMIDITY_CONTROL_AUTO_SETPOINT 0xfda00011 + def DOTDOT_ATTRIBUTE_ID_UNIFY_HUMIDITY_CONTROL_AUTO_SETPOINT_SCALE 0xfda00012 + def DOTDOT_ATTRIBUTE_ID_UNIFY_HUMIDITY_CONTROL_AUTO_SETPOINT_PRECISION 0xfda00013 + ++// This represents the attributes in the DotDot UnifySwitchColor cluster ++def DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE 0xffa10000 ++def DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE 0xffa10001 ++def DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED 0xffa10002 ++def DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN 0xffa10003 ++def DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE 0xffa10004 ++def DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER 0xffa10005 ++def DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN 0xffa10006 ++def DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE 0xffa10007 ++ +diff --git a/components/unify_dotdot_attribute_store/zap-generated/include/dotdot_attributes_camel_case.uam b/components/unify_dotdot_attribute_store/zap-generated/include/dotdot_attributes_camel_case.uam +index 440dddc2ea..ede33f9966 100644 +--- a/components/unify_dotdot_attribute_store/zap-generated/include/dotdot_attributes_camel_case.uam ++++ b/components/unify_dotdot_attribute_store/zap-generated/include/dotdot_attributes_camel_case.uam +@@ -904,3 +904,13 @@ def zb_AutoSetpoint 0xfda00011 + def zb_AutoSetpointScale 0xfda00012 + def zb_AutoSetpointPrecision 0xfda00013 + ++// This represents short CamelCase labels the attributes in the DotDot UnifySwitchColor cluster ++def zb_WarmWhite 0xffa10000 ++def zb_ColdWhite 0xffa10001 ++def zb_Red 0xffa10002 ++def zb_Green 0xffa10003 ++def zb_Blue 0xffa10004 ++def zb_Amber 0xffa10005 ++def zb_Cyan 0xffa10006 ++def zb_Purple 0xffa10007 ++ +diff --git a/components/unify_dotdot_attribute_store/zap-generated/include/unify_dotdot_attribute_store_helpers.h b/components/unify_dotdot_attribute_store/zap-generated/include/unify_dotdot_attribute_store_helpers.h +index 8027848315..9ebb9bc489 100644 +--- a/components/unify_dotdot_attribute_store/zap-generated/include/unify_dotdot_attribute_store_helpers.h ++++ b/components/unify_dotdot_attribute_store/zap-generated/include/unify_dotdot_attribute_store_helpers.h +@@ -79177,6 +79177,882 @@ bool dotdot_is_any_unify_humidity_control_writable_attribute_supported( + const dotdot_unid_t unid, + const dotdot_endpoint_id_t endpoint_id); + ++//////////////////////////////////////////////////////////////////////////////// ++// Start of cluster UnifySwitchColor ++//////////////////////////////////////////////////////////////////////////////// ++// UnifySwitchColor WarmWhite ++/** ++ * @brief Verifies if the DotDot UnifySwitchColor - WarmWhite is supported ++ * under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * ++ * @returns true if WarmWhite is supported ++ * @returns false if WarmWhite is not supported ++ */ ++bool dotdot_is_supported_unify_switch_color_warm_white ( ++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Gets the DotDot UnifySwitchColor - WarmWhite attribute value under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @param value_state value state to get, ++ * see \ref attribute_store_get_node_attribute_value ++ * ++ * ++ * @returns WarmWhite attribute ++ */ ++uint8_t dotdot_get_unify_switch_color_warm_white( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state); ++ ++/** ++ * @brief Set the DotDot UnifySwitchColor - WarmWhite attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @param value_state value state to write for the node, ++ * see \ref attribute_store_set_node_attribute_value ++ * ++ * @param new_warm_white new value to set ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_set_unify_switch_color_warm_white( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state, ++ uint8_t new_warm_white ++ ); ++ ++/** ++ * @brief Undefines the Reported value of the the DotDot UnifySwitchColor - WarmWhite ++ * attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_unify_switch_color_warm_white_undefine_reported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Undefines the Desired value of the DotDot ++ * UnifySwitchColor - WarmWhite attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_unify_switch_color_warm_white_undefine_desired( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if the reported value is defined for the DotDot ++ * UnifySwitchColor - WarmWhite attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if defined, false is undefined or non-existent ++ */ ++bool dotdot_unify_switch_color_warm_white_is_reported_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if the desired value is defined for the DotDot ++ * UnifySwitchColor - WarmWhite attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if defined, false is undefined or non-existent ++ */ ++bool dotdot_unify_switch_color_warm_white_is_desired_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Creates a DotDot UnifySwitchColor - WarmWhite attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_create_unify_switch_color_warm_white( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++// UnifySwitchColor ColdWhite ++/** ++ * @brief Verifies if the DotDot UnifySwitchColor - ColdWhite is supported ++ * under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * ++ * @returns true if ColdWhite is supported ++ * @returns false if ColdWhite is not supported ++ */ ++bool dotdot_is_supported_unify_switch_color_cold_white ( ++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Gets the DotDot UnifySwitchColor - ColdWhite attribute value under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @param value_state value state to get, ++ * see \ref attribute_store_get_node_attribute_value ++ * ++ * ++ * @returns ColdWhite attribute ++ */ ++uint8_t dotdot_get_unify_switch_color_cold_white( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state); ++ ++/** ++ * @brief Set the DotDot UnifySwitchColor - ColdWhite attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @param value_state value state to write for the node, ++ * see \ref attribute_store_set_node_attribute_value ++ * ++ * @param new_cold_white new value to set ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_set_unify_switch_color_cold_white( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state, ++ uint8_t new_cold_white ++ ); ++ ++/** ++ * @brief Undefines the Reported value of the the DotDot UnifySwitchColor - ColdWhite ++ * attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_unify_switch_color_cold_white_undefine_reported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Undefines the Desired value of the DotDot ++ * UnifySwitchColor - ColdWhite attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_unify_switch_color_cold_white_undefine_desired( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if the reported value is defined for the DotDot ++ * UnifySwitchColor - ColdWhite attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if defined, false is undefined or non-existent ++ */ ++bool dotdot_unify_switch_color_cold_white_is_reported_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if the desired value is defined for the DotDot ++ * UnifySwitchColor - ColdWhite attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if defined, false is undefined or non-existent ++ */ ++bool dotdot_unify_switch_color_cold_white_is_desired_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Creates a DotDot UnifySwitchColor - ColdWhite attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_create_unify_switch_color_cold_white( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++// UnifySwitchColor Red ++/** ++ * @brief Verifies if the DotDot UnifySwitchColor - Red is supported ++ * under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * ++ * @returns true if Red is supported ++ * @returns false if Red is not supported ++ */ ++bool dotdot_is_supported_unify_switch_color_red ( ++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Gets the DotDot UnifySwitchColor - Red attribute value under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @param value_state value state to get, ++ * see \ref attribute_store_get_node_attribute_value ++ * ++ * ++ * @returns Red attribute ++ */ ++uint8_t dotdot_get_unify_switch_color_red( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state); ++ ++/** ++ * @brief Set the DotDot UnifySwitchColor - Red attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @param value_state value state to write for the node, ++ * see \ref attribute_store_set_node_attribute_value ++ * ++ * @param new_red new value to set ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_set_unify_switch_color_red( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state, ++ uint8_t new_red ++ ); ++ ++/** ++ * @brief Undefines the Reported value of the the DotDot UnifySwitchColor - Red ++ * attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_unify_switch_color_red_undefine_reported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Undefines the Desired value of the DotDot ++ * UnifySwitchColor - Red attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_unify_switch_color_red_undefine_desired( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if the reported value is defined for the DotDot ++ * UnifySwitchColor - Red attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if defined, false is undefined or non-existent ++ */ ++bool dotdot_unify_switch_color_red_is_reported_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if the desired value is defined for the DotDot ++ * UnifySwitchColor - Red attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if defined, false is undefined or non-existent ++ */ ++bool dotdot_unify_switch_color_red_is_desired_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Creates a DotDot UnifySwitchColor - Red attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_create_unify_switch_color_red( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++// UnifySwitchColor Green ++/** ++ * @brief Verifies if the DotDot UnifySwitchColor - Green is supported ++ * under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * ++ * @returns true if Green is supported ++ * @returns false if Green is not supported ++ */ ++bool dotdot_is_supported_unify_switch_color_green ( ++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Gets the DotDot UnifySwitchColor - Green attribute value under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @param value_state value state to get, ++ * see \ref attribute_store_get_node_attribute_value ++ * ++ * ++ * @returns Green attribute ++ */ ++uint8_t dotdot_get_unify_switch_color_green( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state); ++ ++/** ++ * @brief Set the DotDot UnifySwitchColor - Green attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @param value_state value state to write for the node, ++ * see \ref attribute_store_set_node_attribute_value ++ * ++ * @param new_green new value to set ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_set_unify_switch_color_green( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state, ++ uint8_t new_green ++ ); ++ ++/** ++ * @brief Undefines the Reported value of the the DotDot UnifySwitchColor - Green ++ * attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_unify_switch_color_green_undefine_reported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Undefines the Desired value of the DotDot ++ * UnifySwitchColor - Green attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_unify_switch_color_green_undefine_desired( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if the reported value is defined for the DotDot ++ * UnifySwitchColor - Green attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if defined, false is undefined or non-existent ++ */ ++bool dotdot_unify_switch_color_green_is_reported_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if the desired value is defined for the DotDot ++ * UnifySwitchColor - Green attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if defined, false is undefined or non-existent ++ */ ++bool dotdot_unify_switch_color_green_is_desired_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Creates a DotDot UnifySwitchColor - Green attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_create_unify_switch_color_green( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++// UnifySwitchColor Blue ++/** ++ * @brief Verifies if the DotDot UnifySwitchColor - Blue is supported ++ * under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * ++ * @returns true if Blue is supported ++ * @returns false if Blue is not supported ++ */ ++bool dotdot_is_supported_unify_switch_color_blue ( ++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Gets the DotDot UnifySwitchColor - Blue attribute value under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @param value_state value state to get, ++ * see \ref attribute_store_get_node_attribute_value ++ * ++ * ++ * @returns Blue attribute ++ */ ++uint8_t dotdot_get_unify_switch_color_blue( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state); ++ ++/** ++ * @brief Set the DotDot UnifySwitchColor - Blue attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @param value_state value state to write for the node, ++ * see \ref attribute_store_set_node_attribute_value ++ * ++ * @param new_blue new value to set ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_set_unify_switch_color_blue( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state, ++ uint8_t new_blue ++ ); ++ ++/** ++ * @brief Undefines the Reported value of the the DotDot UnifySwitchColor - Blue ++ * attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_unify_switch_color_blue_undefine_reported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Undefines the Desired value of the DotDot ++ * UnifySwitchColor - Blue attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_unify_switch_color_blue_undefine_desired( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if the reported value is defined for the DotDot ++ * UnifySwitchColor - Blue attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if defined, false is undefined or non-existent ++ */ ++bool dotdot_unify_switch_color_blue_is_reported_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if the desired value is defined for the DotDot ++ * UnifySwitchColor - Blue attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if defined, false is undefined or non-existent ++ */ ++bool dotdot_unify_switch_color_blue_is_desired_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Creates a DotDot UnifySwitchColor - Blue attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_create_unify_switch_color_blue( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++// UnifySwitchColor Amber ++/** ++ * @brief Verifies if the DotDot UnifySwitchColor - Amber is supported ++ * under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * ++ * @returns true if Amber is supported ++ * @returns false if Amber is not supported ++ */ ++bool dotdot_is_supported_unify_switch_color_amber ( ++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Gets the DotDot UnifySwitchColor - Amber attribute value under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @param value_state value state to get, ++ * see \ref attribute_store_get_node_attribute_value ++ * ++ * ++ * @returns Amber attribute ++ */ ++uint8_t dotdot_get_unify_switch_color_amber( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state); ++ ++/** ++ * @brief Set the DotDot UnifySwitchColor - Amber attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @param value_state value state to write for the node, ++ * see \ref attribute_store_set_node_attribute_value ++ * ++ * @param new_amber new value to set ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_set_unify_switch_color_amber( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state, ++ uint8_t new_amber ++ ); ++ ++/** ++ * @brief Undefines the Reported value of the the DotDot UnifySwitchColor - Amber ++ * attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_unify_switch_color_amber_undefine_reported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Undefines the Desired value of the DotDot ++ * UnifySwitchColor - Amber attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_unify_switch_color_amber_undefine_desired( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if the reported value is defined for the DotDot ++ * UnifySwitchColor - Amber attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if defined, false is undefined or non-existent ++ */ ++bool dotdot_unify_switch_color_amber_is_reported_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if the desired value is defined for the DotDot ++ * UnifySwitchColor - Amber attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if defined, false is undefined or non-existent ++ */ ++bool dotdot_unify_switch_color_amber_is_desired_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Creates a DotDot UnifySwitchColor - Amber attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_create_unify_switch_color_amber( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++// UnifySwitchColor Cyan ++/** ++ * @brief Verifies if the DotDot UnifySwitchColor - Cyan is supported ++ * under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * ++ * @returns true if Cyan is supported ++ * @returns false if Cyan is not supported ++ */ ++bool dotdot_is_supported_unify_switch_color_cyan ( ++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Gets the DotDot UnifySwitchColor - Cyan attribute value under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @param value_state value state to get, ++ * see \ref attribute_store_get_node_attribute_value ++ * ++ * ++ * @returns Cyan attribute ++ */ ++uint8_t dotdot_get_unify_switch_color_cyan( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state); ++ ++/** ++ * @brief Set the DotDot UnifySwitchColor - Cyan attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @param value_state value state to write for the node, ++ * see \ref attribute_store_set_node_attribute_value ++ * ++ * @param new_cyan new value to set ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_set_unify_switch_color_cyan( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state, ++ uint8_t new_cyan ++ ); ++ ++/** ++ * @brief Undefines the Reported value of the the DotDot UnifySwitchColor - Cyan ++ * attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_unify_switch_color_cyan_undefine_reported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Undefines the Desired value of the DotDot ++ * UnifySwitchColor - Cyan attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_unify_switch_color_cyan_undefine_desired( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if the reported value is defined for the DotDot ++ * UnifySwitchColor - Cyan attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if defined, false is undefined or non-existent ++ */ ++bool dotdot_unify_switch_color_cyan_is_reported_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if the desired value is defined for the DotDot ++ * UnifySwitchColor - Cyan attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if defined, false is undefined or non-existent ++ */ ++bool dotdot_unify_switch_color_cyan_is_desired_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Creates a DotDot UnifySwitchColor - Cyan attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_create_unify_switch_color_cyan( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++// UnifySwitchColor Purple ++/** ++ * @brief Verifies if the DotDot UnifySwitchColor - Purple is supported ++ * under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * ++ * @returns true if Purple is supported ++ * @returns false if Purple is not supported ++ */ ++bool dotdot_is_supported_unify_switch_color_purple ( ++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Gets the DotDot UnifySwitchColor - Purple attribute value under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @param value_state value state to get, ++ * see \ref attribute_store_get_node_attribute_value ++ * ++ * ++ * @returns Purple attribute ++ */ ++uint8_t dotdot_get_unify_switch_color_purple( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state); ++ ++/** ++ * @brief Set the DotDot UnifySwitchColor - Purple attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @param value_state value state to write for the node, ++ * see \ref attribute_store_set_node_attribute_value ++ * ++ * @param new_purple new value to set ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_set_unify_switch_color_purple( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state, ++ uint8_t new_purple ++ ); ++ ++/** ++ * @brief Undefines the Reported value of the the DotDot UnifySwitchColor - Purple ++ * attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_unify_switch_color_purple_undefine_reported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Undefines the Desired value of the DotDot ++ * UnifySwitchColor - Purple attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_unify_switch_color_purple_undefine_desired( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if the reported value is defined for the DotDot ++ * UnifySwitchColor - Purple attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if defined, false is undefined or non-existent ++ */ ++bool dotdot_unify_switch_color_purple_is_reported_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if the desired value is defined for the DotDot ++ * UnifySwitchColor - Purple attribute under a UNID/EndpointID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if defined, false is undefined or non-existent ++ */ ++bool dotdot_unify_switch_color_purple_is_desired_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Creates a DotDot UnifySwitchColor - Purple attribute under a UNID/EndpoinID ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns sl_status_t SL_STATUS_OK on success ++ */ ++sl_status_t dotdot_create_unify_switch_color_purple( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if a UNID/Endpoint supports any attribute for the UnifySwitchColor ++ * Cluster ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if at least 1 attribute in the Attribute Store, false otherwise ++ */ ++bool dotdot_is_any_unify_switch_color_attribute_supported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ ++/** ++ * @brief Checks if a UNID/Endpoint supports any writable attribute for the ++ * UnifySwitchColor Cluster ++ * ++ * @param unid Node's UNID ++ * @param endpoint_id Endpoint ID ++ * @returns true if at least 1 writable attribute in the Attribute Store, false otherwise ++ */ ++bool dotdot_is_any_unify_switch_color_writable_attribute_supported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id); ++ + #ifdef __cplusplus + } + #endif // __cplusplus +diff --git a/components/unify_dotdot_attribute_store/zap-generated/include/unify_dotdot_defined_attribute_types.h b/components/unify_dotdot_attribute_store/zap-generated/include/unify_dotdot_defined_attribute_types.h +index 6f3c5b0f35..6ca13e5787 100644 +--- a/components/unify_dotdot_attribute_store/zap-generated/include/unify_dotdot_defined_attribute_types.h ++++ b/components/unify_dotdot_attribute_store/zap-generated/include/unify_dotdot_defined_attribute_types.h +@@ -810,6 +810,15 @@ DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_UNIFY_HUMIDITY_CONTROL_AUTO_SETPOINT_MAX , + DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_UNIFY_HUMIDITY_CONTROL_AUTO_SETPOINT , 0xfda00011) + DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_UNIFY_HUMIDITY_CONTROL_AUTO_SETPOINT_SCALE , 0xfda00012) + DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_UNIFY_HUMIDITY_CONTROL_AUTO_SETPOINT_PRECISION , 0xfda00013) ++// Attribute Defines for UnifySwitchColor ++DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE , 0xffa10000) ++DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE , 0xffa10001) ++DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED , 0xffa10002) ++DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN , 0xffa10003) ++DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE , 0xffa10004) ++DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER , 0xffa10005) ++DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN , 0xffa10006) ++DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE , 0xffa10007) + + // Additional manually defined types: + +diff --git a/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_attribute_publisher.cpp b/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_attribute_publisher.cpp +index 75631aebad..559bcfb380 100644 +--- a/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_attribute_publisher.cpp ++++ b/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_attribute_publisher.cpp +@@ -26377,6 +26377,375 @@ static void unify_humidity_control_cluster_cluster_revision_callback( + } + + ++/** ++ * @brief Publishes the desired value of an updated attribute store node for ++ * the UnifySwitchColor cluster. ++ * @param updated_node Updated attribute store node ++ * @param change Type of change applied ++ */ ++static void unify_switch_color_cluster_publish_desired_value_callback( ++ attribute_store_node_t updated_node, attribute_store_change_t change) ++{ ++ // clang-format on ++ if (false == is_publish_desired_attribute_values_to_mqtt_enabled()) { ++ return; ++ } ++ if (change == ATTRIBUTE_DELETED || change == ATTRIBUTE_CREATED) { ++ return; ++ } ++ // Scene exception: check that the attribute is not under the Scene Table extension, which is a config and not the node's state. ++ if (ATTRIBUTE_STORE_INVALID_NODE ++ != attribute_store_get_first_parent_with_type( ++ updated_node, ++ DOTDOT_ATTRIBUTE_ID_SCENES_SCENE_TABLE)) { ++ return; ++ } ++ ++ // Get the UNID and EndPoint, and prepare the basic topic ++ char unid[MAXIMUM_UNID_SIZE] = {}; ++ // clang-format off ++ // clang-format on ++ dotdot_endpoint_id_t endpoint_id = 0; ++ if (SL_STATUS_OK ++ != unify_dotdot_attributes_get_unid_endpoint()(updated_node, ++ unid, ++ &endpoint_id)) { ++ return; ++ } ++ // clang-format off ++ // clang-format on ++ ++ std::string base_topic = "ucl/by-unid/" + std::string(unid); ++ // clang-format off ++ base_topic += "/ep" + std::to_string(endpoint_id); ++ // clang-format on ++ ++ attribute_store_type_t type = attribute_store_get_node_type(updated_node); ++ if (type == ATTRIBUTE_STORE_INVALID_ATTRIBUTE_TYPE) { ++ sl_log_debug(LOG_TAG, ++ "Warning: Invalid type for Attribute ID %d, " ++ "this should not happen.", ++ updated_node); ++ return; ++ } ++ ++ // If the value got updated but both Reported and Desired undefined, we skip publication ++ if (false == attribute_store_is_reported_defined(updated_node) ++ && false == attribute_store_is_desired_defined(updated_node)) { ++ sl_log_debug(LOG_TAG, ++ "Reported/Desired values are undefined. " ++ "Skipping publication"); ++ return; ++ } ++ ++ // clang-format off ++ try { ++ attribute_store::attribute attr(updated_node); ++ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE) { ++ uic_mqtt_dotdot_unify_switch_color_warm_white_publish( ++ base_topic.c_str(), ++ static_cast(attr.desired_or_reported()), ++ UCL_MQTT_PUBLISH_TYPE_DESIRED); ++ return; ++ } ++ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE) { ++ uic_mqtt_dotdot_unify_switch_color_cold_white_publish( ++ base_topic.c_str(), ++ static_cast(attr.desired_or_reported()), ++ UCL_MQTT_PUBLISH_TYPE_DESIRED); ++ return; ++ } ++ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED) { ++ uic_mqtt_dotdot_unify_switch_color_red_publish( ++ base_topic.c_str(), ++ static_cast(attr.desired_or_reported()), ++ UCL_MQTT_PUBLISH_TYPE_DESIRED); ++ return; ++ } ++ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN) { ++ uic_mqtt_dotdot_unify_switch_color_green_publish( ++ base_topic.c_str(), ++ static_cast(attr.desired_or_reported()), ++ UCL_MQTT_PUBLISH_TYPE_DESIRED); ++ return; ++ } ++ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE) { ++ uic_mqtt_dotdot_unify_switch_color_blue_publish( ++ base_topic.c_str(), ++ static_cast(attr.desired_or_reported()), ++ UCL_MQTT_PUBLISH_TYPE_DESIRED); ++ return; ++ } ++ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER) { ++ uic_mqtt_dotdot_unify_switch_color_amber_publish( ++ base_topic.c_str(), ++ static_cast(attr.desired_or_reported()), ++ UCL_MQTT_PUBLISH_TYPE_DESIRED); ++ return; ++ } ++ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN) { ++ uic_mqtt_dotdot_unify_switch_color_cyan_publish( ++ base_topic.c_str(), ++ static_cast(attr.desired_or_reported()), ++ UCL_MQTT_PUBLISH_TYPE_DESIRED); ++ return; ++ } ++ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE) { ++ uic_mqtt_dotdot_unify_switch_color_purple_publish( ++ base_topic.c_str(), ++ static_cast(attr.desired_or_reported()), ++ UCL_MQTT_PUBLISH_TYPE_DESIRED); ++ return; ++ } ++ } catch (std::exception &ex) { ++ sl_log_warning(LOG_TAG, "Failed to publish the Desired attribute value: %s", ex.what()); ++ } ++} ++ ++/** ++ * @brief Publishes the reported value of an updated attribute store node for ++ * the UnifySwitchColor cluster. ++ * @param updated_node Updated attribute store node ++ * @param change Type of change applied ++ */ ++static void unify_switch_color_cluster_publish_reported_value_callback( ++ attribute_store_node_t updated_node, attribute_store_change_t change) ++{ ++ // clang-format on ++ if (false == is_publish_reported_attribute_values_to_mqtt_enabled()) { ++ return; ++ } ++ if (change == ATTRIBUTE_CREATED) { ++ return; ++ } ++ // Scene exception: check that the attribute is not under the Scene Table extension, which is a config and not the node's state. ++ if (ATTRIBUTE_STORE_INVALID_NODE ++ != attribute_store_get_first_parent_with_type( ++ updated_node, ++ DOTDOT_ATTRIBUTE_ID_SCENES_SCENE_TABLE)) { ++ return; ++ } ++ ++ // Get the UNID and EndPoint, and prepare the basic topic ++ char unid[MAXIMUM_UNID_SIZE] = {}; ++ // clang-format off ++ // clang-format on ++ dotdot_endpoint_id_t endpoint_id = 0; ++ if (SL_STATUS_OK ++ != unify_dotdot_attributes_get_unid_endpoint()(updated_node, ++ unid, ++ &endpoint_id)) { ++ return; ++ } ++ // clang-format off ++ // clang-format on ++ ++ std::string base_topic = "ucl/by-unid/" + std::string(unid); ++ // clang-format off ++ base_topic += "/ep" + std::to_string(endpoint_id); ++ // clang-format on ++ ++ attribute_store_type_t type = attribute_store_get_node_type(updated_node); ++ if (type == ATTRIBUTE_STORE_INVALID_ATTRIBUTE_TYPE) { ++ sl_log_debug(LOG_TAG, ++ "Warning: Invalid type for Attribute ID %d, " ++ "this should not happen.", ++ updated_node); ++ return; ++ } ++ ++ // Deletion case: ++ if (change == ATTRIBUTE_DELETED) { ++ // clang-format off ++ switch(type) { ++ case DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE: ++ // clang-format on ++ sl_log_debug(LOG_TAG, ++ "Unretaining UnifySwitchColor::WarmWhite under topic %s", ++ base_topic.c_str()); ++ // clang-format off ++ uic_mqtt_dotdot_unify_switch_color_warm_white_unretain(base_topic.c_str(), UCL_MQTT_PUBLISH_TYPE_ALL); ++ break; ++ case DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE: ++ // clang-format on ++ sl_log_debug(LOG_TAG, ++ "Unretaining UnifySwitchColor::ColdWhite under topic %s", ++ base_topic.c_str()); ++ // clang-format off ++ uic_mqtt_dotdot_unify_switch_color_cold_white_unretain(base_topic.c_str(), UCL_MQTT_PUBLISH_TYPE_ALL); ++ break; ++ case DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED: ++ // clang-format on ++ sl_log_debug(LOG_TAG, ++ "Unretaining UnifySwitchColor::Red under topic %s", ++ base_topic.c_str()); ++ // clang-format off ++ uic_mqtt_dotdot_unify_switch_color_red_unretain(base_topic.c_str(), UCL_MQTT_PUBLISH_TYPE_ALL); ++ break; ++ case DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN: ++ // clang-format on ++ sl_log_debug(LOG_TAG, ++ "Unretaining UnifySwitchColor::Green under topic %s", ++ base_topic.c_str()); ++ // clang-format off ++ uic_mqtt_dotdot_unify_switch_color_green_unretain(base_topic.c_str(), UCL_MQTT_PUBLISH_TYPE_ALL); ++ break; ++ case DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE: ++ // clang-format on ++ sl_log_debug(LOG_TAG, ++ "Unretaining UnifySwitchColor::Blue under topic %s", ++ base_topic.c_str()); ++ // clang-format off ++ uic_mqtt_dotdot_unify_switch_color_blue_unretain(base_topic.c_str(), UCL_MQTT_PUBLISH_TYPE_ALL); ++ break; ++ case DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER: ++ // clang-format on ++ sl_log_debug(LOG_TAG, ++ "Unretaining UnifySwitchColor::Amber under topic %s", ++ base_topic.c_str()); ++ // clang-format off ++ uic_mqtt_dotdot_unify_switch_color_amber_unretain(base_topic.c_str(), UCL_MQTT_PUBLISH_TYPE_ALL); ++ break; ++ case DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN: ++ // clang-format on ++ sl_log_debug(LOG_TAG, ++ "Unretaining UnifySwitchColor::Cyan under topic %s", ++ base_topic.c_str()); ++ // clang-format off ++ uic_mqtt_dotdot_unify_switch_color_cyan_unretain(base_topic.c_str(), UCL_MQTT_PUBLISH_TYPE_ALL); ++ break; ++ case DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE: ++ // clang-format on ++ sl_log_debug(LOG_TAG, ++ "Unretaining UnifySwitchColor::Purple under topic %s", ++ base_topic.c_str()); ++ // clang-format off ++ uic_mqtt_dotdot_unify_switch_color_purple_unretain(base_topic.c_str(), UCL_MQTT_PUBLISH_TYPE_ALL); ++ break; ++ default: ++ break; ++ } ++ // clang-format on ++ return; ++ } ++ ++ // If the value got updated but undefined, we skip publication ++ if (false == attribute_store_is_reported_defined(updated_node)) { ++ sl_log_debug(LOG_TAG, "Reported value is undefined. Skipping publication"); ++ return; ++ } ++ ++ // Else we assume update case: ++ // clang-format off ++ try { ++ attribute_store::attribute attr(updated_node); ++ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE) { ++ uic_mqtt_dotdot_unify_switch_color_warm_white_publish( ++ base_topic.c_str(), ++ static_cast(attr.reported()), ++ (attr.desired_exists() && !attribute_store_is_value_matched(updated_node)) ? UCL_MQTT_PUBLISH_TYPE_REPORTED : UCL_MQTT_PUBLISH_TYPE_ALL); ++ return; ++ } ++ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE) { ++ uic_mqtt_dotdot_unify_switch_color_cold_white_publish( ++ base_topic.c_str(), ++ static_cast(attr.reported()), ++ (attr.desired_exists() && !attribute_store_is_value_matched(updated_node)) ? UCL_MQTT_PUBLISH_TYPE_REPORTED : UCL_MQTT_PUBLISH_TYPE_ALL); ++ return; ++ } ++ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED) { ++ uic_mqtt_dotdot_unify_switch_color_red_publish( ++ base_topic.c_str(), ++ static_cast(attr.reported()), ++ (attr.desired_exists() && !attribute_store_is_value_matched(updated_node)) ? UCL_MQTT_PUBLISH_TYPE_REPORTED : UCL_MQTT_PUBLISH_TYPE_ALL); ++ return; ++ } ++ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN) { ++ uic_mqtt_dotdot_unify_switch_color_green_publish( ++ base_topic.c_str(), ++ static_cast(attr.reported()), ++ (attr.desired_exists() && !attribute_store_is_value_matched(updated_node)) ? UCL_MQTT_PUBLISH_TYPE_REPORTED : UCL_MQTT_PUBLISH_TYPE_ALL); ++ return; ++ } ++ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE) { ++ uic_mqtt_dotdot_unify_switch_color_blue_publish( ++ base_topic.c_str(), ++ static_cast(attr.reported()), ++ (attr.desired_exists() && !attribute_store_is_value_matched(updated_node)) ? UCL_MQTT_PUBLISH_TYPE_REPORTED : UCL_MQTT_PUBLISH_TYPE_ALL); ++ return; ++ } ++ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER) { ++ uic_mqtt_dotdot_unify_switch_color_amber_publish( ++ base_topic.c_str(), ++ static_cast(attr.reported()), ++ (attr.desired_exists() && !attribute_store_is_value_matched(updated_node)) ? UCL_MQTT_PUBLISH_TYPE_REPORTED : UCL_MQTT_PUBLISH_TYPE_ALL); ++ return; ++ } ++ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN) { ++ uic_mqtt_dotdot_unify_switch_color_cyan_publish( ++ base_topic.c_str(), ++ static_cast(attr.reported()), ++ (attr.desired_exists() && !attribute_store_is_value_matched(updated_node)) ? UCL_MQTT_PUBLISH_TYPE_REPORTED : UCL_MQTT_PUBLISH_TYPE_ALL); ++ return; ++ } ++ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE) { ++ uic_mqtt_dotdot_unify_switch_color_purple_publish( ++ base_topic.c_str(), ++ static_cast(attr.reported()), ++ (attr.desired_exists() && !attribute_store_is_value_matched(updated_node)) ? UCL_MQTT_PUBLISH_TYPE_REPORTED : UCL_MQTT_PUBLISH_TYPE_ALL); ++ return; ++ } ++ } catch (std::exception &ex) { ++ sl_log_warning(LOG_TAG, "Failed to publish the Reported attribute value: %s", ex.what()); ++ } ++} ++ ++static void unify_switch_color_cluster_cluster_revision_callback( ++ attribute_store_node_t updated_node, attribute_store_change_t change) ++{ ++ // clang-format on ++ if (false == is_publish_reported_attribute_values_to_mqtt_enabled()) { ++ return; ++ } ++ ++ // Get the UNID and EndPoint, and prepare the basic topic ++ char unid[MAXIMUM_UNID_SIZE] = {}; ++ dotdot_endpoint_id_t endpoint_id = 0; ++ // clang-format off ++ // clang-format on ++ if (SL_STATUS_OK ++ != unify_dotdot_attributes_get_unid_endpoint()(updated_node, ++ unid, ++ &endpoint_id)) { ++ return; ++ } ++ // clang-format off ++ // clang-format on ++ ++ std::string base_topic = "ucl/by-unid/" + std::string(unid); ++ // clang-format off ++ base_topic += "/ep" + std::to_string(endpoint_id); ++ ++ if ((change == ATTRIBUTE_CREATED) || (change == ATTRIBUTE_UPDATED)) { ++ // On attribute creation, make sure to publish the attribute revision for the first time ++ std::string cluster_revision_topic = base_topic + "/UnifySwitchColor/Attributes/ClusterRevision"; ++ if (uic_mqtt_count_topics(cluster_revision_topic.c_str()) == 0) { ++ uic_mqtt_dotdot_unify_switch_color_publish_cluster_revision(base_topic.c_str(), 1); ++ } ++ } ++ ++ if (change == ATTRIBUTE_DELETED) { ++ // Check if we just erased the last attribute under a cluster, if yes, unretain ++ // the Cluster revision too. ++ if (false == dotdot_is_any_unify_switch_color_attribute_supported(unid, endpoint_id)) { ++ base_topic += "/UnifySwitchColor"; ++ sl_log_debug(LOG_TAG, "No more attributes supported for UnifySwitchColor cluster for UNID %s Endpoint %d. Unretaining leftover topics at %s",unid, endpoint_id, base_topic.c_str()); ++ uic_mqtt_unretain(base_topic.c_str()); ++ } ++ } ++} ++ ++ + + // Initialization of the component. + sl_status_t unify_dotdot_attribute_store_attribute_publisher_init() +@@ -36615,6 +36984,118 @@ sl_status_t unify_dotdot_attribute_store_attribute_publisher_init() + attribute_store_register_callback_by_type( + unify_humidity_control_cluster_cluster_revision_callback, + DOTDOT_ATTRIBUTE_ID_UNIFY_HUMIDITY_CONTROL_AUTO_SETPOINT_PRECISION); ++ //Desired attribute state ++ attribute_store_register_callback_by_type_and_state( ++ unify_switch_color_cluster_publish_desired_value_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE, ++ DESIRED_ATTRIBUTE); ++ //Reported attribute state ++ attribute_store_register_callback_by_type_and_state( ++ unify_switch_color_cluster_publish_reported_value_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE, ++ REPORTED_ATTRIBUTE); ++ //registering a callback when an attribute is created for publishing cluster revision ++ attribute_store_register_callback_by_type( ++ unify_switch_color_cluster_cluster_revision_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE); ++ //Desired attribute state ++ attribute_store_register_callback_by_type_and_state( ++ unify_switch_color_cluster_publish_desired_value_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE, ++ DESIRED_ATTRIBUTE); ++ //Reported attribute state ++ attribute_store_register_callback_by_type_and_state( ++ unify_switch_color_cluster_publish_reported_value_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE, ++ REPORTED_ATTRIBUTE); ++ //registering a callback when an attribute is created for publishing cluster revision ++ attribute_store_register_callback_by_type( ++ unify_switch_color_cluster_cluster_revision_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE); ++ //Desired attribute state ++ attribute_store_register_callback_by_type_and_state( ++ unify_switch_color_cluster_publish_desired_value_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED, ++ DESIRED_ATTRIBUTE); ++ //Reported attribute state ++ attribute_store_register_callback_by_type_and_state( ++ unify_switch_color_cluster_publish_reported_value_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED, ++ REPORTED_ATTRIBUTE); ++ //registering a callback when an attribute is created for publishing cluster revision ++ attribute_store_register_callback_by_type( ++ unify_switch_color_cluster_cluster_revision_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED); ++ //Desired attribute state ++ attribute_store_register_callback_by_type_and_state( ++ unify_switch_color_cluster_publish_desired_value_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN, ++ DESIRED_ATTRIBUTE); ++ //Reported attribute state ++ attribute_store_register_callback_by_type_and_state( ++ unify_switch_color_cluster_publish_reported_value_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN, ++ REPORTED_ATTRIBUTE); ++ //registering a callback when an attribute is created for publishing cluster revision ++ attribute_store_register_callback_by_type( ++ unify_switch_color_cluster_cluster_revision_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN); ++ //Desired attribute state ++ attribute_store_register_callback_by_type_and_state( ++ unify_switch_color_cluster_publish_desired_value_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE, ++ DESIRED_ATTRIBUTE); ++ //Reported attribute state ++ attribute_store_register_callback_by_type_and_state( ++ unify_switch_color_cluster_publish_reported_value_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE, ++ REPORTED_ATTRIBUTE); ++ //registering a callback when an attribute is created for publishing cluster revision ++ attribute_store_register_callback_by_type( ++ unify_switch_color_cluster_cluster_revision_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE); ++ //Desired attribute state ++ attribute_store_register_callback_by_type_and_state( ++ unify_switch_color_cluster_publish_desired_value_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER, ++ DESIRED_ATTRIBUTE); ++ //Reported attribute state ++ attribute_store_register_callback_by_type_and_state( ++ unify_switch_color_cluster_publish_reported_value_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER, ++ REPORTED_ATTRIBUTE); ++ //registering a callback when an attribute is created for publishing cluster revision ++ attribute_store_register_callback_by_type( ++ unify_switch_color_cluster_cluster_revision_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER); ++ //Desired attribute state ++ attribute_store_register_callback_by_type_and_state( ++ unify_switch_color_cluster_publish_desired_value_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN, ++ DESIRED_ATTRIBUTE); ++ //Reported attribute state ++ attribute_store_register_callback_by_type_and_state( ++ unify_switch_color_cluster_publish_reported_value_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN, ++ REPORTED_ATTRIBUTE); ++ //registering a callback when an attribute is created for publishing cluster revision ++ attribute_store_register_callback_by_type( ++ unify_switch_color_cluster_cluster_revision_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN); ++ //Desired attribute state ++ attribute_store_register_callback_by_type_and_state( ++ unify_switch_color_cluster_publish_desired_value_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE, ++ DESIRED_ATTRIBUTE); ++ //Reported attribute state ++ attribute_store_register_callback_by_type_and_state( ++ unify_switch_color_cluster_publish_reported_value_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE, ++ REPORTED_ATTRIBUTE); ++ //registering a callback when an attribute is created for publishing cluster revision ++ attribute_store_register_callback_by_type( ++ unify_switch_color_cluster_cluster_revision_callback, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE); + + return SL_STATUS_OK; + } +diff --git a/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_force_read_attributes_command_callbacks.c b/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_force_read_attributes_command_callbacks.c +index fe3a605125..17cb0e11f5 100644 +--- a/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_force_read_attributes_command_callbacks.c ++++ b/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_force_read_attributes_command_callbacks.c +@@ -4619,6 +4619,71 @@ static sl_status_t uic_mqtt_dotdot_unify_humidity_control_force_read_attributes_ + } + return SL_STATUS_OK; + } ++//////////////////////////////////////////////////////////////////////////////// ++// Start of cluster UnifySwitchColor ++//////////////////////////////////////////////////////////////////////////////// ++static sl_status_t uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback ( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ uic_mqtt_dotdot_callback_call_type_t call_type, ++ uic_mqtt_dotdot_unify_switch_color_updated_state_t attribute_list) { ++ ++ if (false == is_force_read_attributes_enabled()){ ++ return SL_STATUS_FAIL; ++ } ++ ++ if (call_type == UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK) { ++ if (is_automatic_deduction_of_supported_commands_enabled()) { ++ return dotdot_is_any_unify_switch_color_attribute_supported(unid, endpoint_id) ? ++ SL_STATUS_OK : SL_STATUS_FAIL; ++ } else { ++ return SL_STATUS_FAIL; ++ } ++ } ++ ++ // Go and undefine everything that needs to be read again: ++ if (true == attribute_list.warm_white) { ++ if (SL_STATUS_OK == dotdot_unify_switch_color_warm_white_undefine_reported(unid, endpoint_id)) { ++ sl_log_debug(LOG_TAG, "Undefined Reported value of UnifySwitchColor::WarmWhite under %s - Endpoint %d", unid, endpoint_id); ++ } ++ } ++ if (true == attribute_list.cold_white) { ++ if (SL_STATUS_OK == dotdot_unify_switch_color_cold_white_undefine_reported(unid, endpoint_id)) { ++ sl_log_debug(LOG_TAG, "Undefined Reported value of UnifySwitchColor::ColdWhite under %s - Endpoint %d", unid, endpoint_id); ++ } ++ } ++ if (true == attribute_list.red) { ++ if (SL_STATUS_OK == dotdot_unify_switch_color_red_undefine_reported(unid, endpoint_id)) { ++ sl_log_debug(LOG_TAG, "Undefined Reported value of UnifySwitchColor::Red under %s - Endpoint %d", unid, endpoint_id); ++ } ++ } ++ if (true == attribute_list.green) { ++ if (SL_STATUS_OK == dotdot_unify_switch_color_green_undefine_reported(unid, endpoint_id)) { ++ sl_log_debug(LOG_TAG, "Undefined Reported value of UnifySwitchColor::Green under %s - Endpoint %d", unid, endpoint_id); ++ } ++ } ++ if (true == attribute_list.blue) { ++ if (SL_STATUS_OK == dotdot_unify_switch_color_blue_undefine_reported(unid, endpoint_id)) { ++ sl_log_debug(LOG_TAG, "Undefined Reported value of UnifySwitchColor::Blue under %s - Endpoint %d", unid, endpoint_id); ++ } ++ } ++ if (true == attribute_list.amber) { ++ if (SL_STATUS_OK == dotdot_unify_switch_color_amber_undefine_reported(unid, endpoint_id)) { ++ sl_log_debug(LOG_TAG, "Undefined Reported value of UnifySwitchColor::Amber under %s - Endpoint %d", unid, endpoint_id); ++ } ++ } ++ if (true == attribute_list.cyan) { ++ if (SL_STATUS_OK == dotdot_unify_switch_color_cyan_undefine_reported(unid, endpoint_id)) { ++ sl_log_debug(LOG_TAG, "Undefined Reported value of UnifySwitchColor::Cyan under %s - Endpoint %d", unid, endpoint_id); ++ } ++ } ++ if (true == attribute_list.purple) { ++ if (SL_STATUS_OK == dotdot_unify_switch_color_purple_undefine_reported(unid, endpoint_id)) { ++ sl_log_debug(LOG_TAG, "Undefined Reported value of UnifySwitchColor::Purple under %s - Endpoint %d", unid, endpoint_id); ++ } ++ } ++ return SL_STATUS_OK; ++} + // clang-format on + + //////////////////////////////////////////////////////////////////////////////// +@@ -4733,6 +4798,8 @@ sl_status_t + + uic_mqtt_dotdot_set_unify_humidity_control_force_read_attributes_callback(&uic_mqtt_dotdot_unify_humidity_control_force_read_attributes_callback); + ++ uic_mqtt_dotdot_set_unify_switch_color_force_read_attributes_callback(&uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback); ++ + // clang-format on + + return SL_STATUS_OK; +diff --git a/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_helpers.cpp b/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_helpers.cpp +index ba326df8ab..2d6b9ffc81 100644 +--- a/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_helpers.cpp ++++ b/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_helpers.cpp +@@ -85167,5 +85167,936 @@ bool dotdot_is_any_unify_humidity_control_writable_attribute_supported( + const dotdot_endpoint_id_t endpoint_id) { + + ++ return false; ++} ++//////////////////////////////////////////////////////////////////////////////// ++// Start of cluster UnifySwitchColor ++//////////////////////////////////////////////////////////////////////////////// ++bool dotdot_is_supported_unify_switch_color_warm_white( ++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE); ++ return attribute_store_node_exists(node); ++} ++ ++uint8_t dotdot_get_unify_switch_color_warm_white( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE); ++ ++ uint8_t result = {}; ++ attribute_store_read_value(node, ++ value_state, ++ (uint8_t *)&result, ++ sizeof(result)); ++ return result; ++} ++ ++sl_status_t dotdot_set_unify_switch_color_warm_white( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state, ++ uint8_t new_warm_white ++ ) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE); ++ ++ return attribute_store_set_node_attribute_value(node, ++ value_state, ++ (uint8_t *)&new_warm_white, ++ sizeof(uint8_t)); ++ } ++ ++sl_status_t dotdot_unify_switch_color_warm_white_undefine_reported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE); ++ attribute_store_undefine_reported(node); ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++ ++sl_status_t dotdot_unify_switch_color_warm_white_undefine_desired( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE); ++ attribute_store_undefine_desired(node); ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++ ++ ++bool dotdot_unify_switch_color_warm_white_is_reported_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE); ++ return attribute_store_is_reported_defined(node); ++} ++ ++bool dotdot_unify_switch_color_warm_white_is_desired_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE); ++ return attribute_store_is_desired_defined(node); ++} ++ ++sl_status_t dotdot_create_unify_switch_color_warm_white( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node = ++ attribute_store_create_child_if_missing(endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE); ++ ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++bool dotdot_is_supported_unify_switch_color_cold_white( ++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE); ++ return attribute_store_node_exists(node); ++} ++ ++uint8_t dotdot_get_unify_switch_color_cold_white( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE); ++ ++ uint8_t result = {}; ++ attribute_store_read_value(node, ++ value_state, ++ (uint8_t *)&result, ++ sizeof(result)); ++ return result; ++} ++ ++sl_status_t dotdot_set_unify_switch_color_cold_white( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state, ++ uint8_t new_cold_white ++ ) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE); ++ ++ return attribute_store_set_node_attribute_value(node, ++ value_state, ++ (uint8_t *)&new_cold_white, ++ sizeof(uint8_t)); ++ } ++ ++sl_status_t dotdot_unify_switch_color_cold_white_undefine_reported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE); ++ attribute_store_undefine_reported(node); ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++ ++sl_status_t dotdot_unify_switch_color_cold_white_undefine_desired( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE); ++ attribute_store_undefine_desired(node); ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++ ++ ++bool dotdot_unify_switch_color_cold_white_is_reported_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE); ++ return attribute_store_is_reported_defined(node); ++} ++ ++bool dotdot_unify_switch_color_cold_white_is_desired_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE); ++ return attribute_store_is_desired_defined(node); ++} ++ ++sl_status_t dotdot_create_unify_switch_color_cold_white( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node = ++ attribute_store_create_child_if_missing(endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE); ++ ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++bool dotdot_is_supported_unify_switch_color_red( ++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED); ++ return attribute_store_node_exists(node); ++} ++ ++uint8_t dotdot_get_unify_switch_color_red( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED); ++ ++ uint8_t result = {}; ++ attribute_store_read_value(node, ++ value_state, ++ (uint8_t *)&result, ++ sizeof(result)); ++ return result; ++} ++ ++sl_status_t dotdot_set_unify_switch_color_red( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state, ++ uint8_t new_red ++ ) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED); ++ ++ return attribute_store_set_node_attribute_value(node, ++ value_state, ++ (uint8_t *)&new_red, ++ sizeof(uint8_t)); ++ } ++ ++sl_status_t dotdot_unify_switch_color_red_undefine_reported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED); ++ attribute_store_undefine_reported(node); ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++ ++sl_status_t dotdot_unify_switch_color_red_undefine_desired( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED); ++ attribute_store_undefine_desired(node); ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++ ++ ++bool dotdot_unify_switch_color_red_is_reported_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED); ++ return attribute_store_is_reported_defined(node); ++} ++ ++bool dotdot_unify_switch_color_red_is_desired_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED); ++ return attribute_store_is_desired_defined(node); ++} ++ ++sl_status_t dotdot_create_unify_switch_color_red( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node = ++ attribute_store_create_child_if_missing(endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED); ++ ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++bool dotdot_is_supported_unify_switch_color_green( ++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN); ++ return attribute_store_node_exists(node); ++} ++ ++uint8_t dotdot_get_unify_switch_color_green( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN); ++ ++ uint8_t result = {}; ++ attribute_store_read_value(node, ++ value_state, ++ (uint8_t *)&result, ++ sizeof(result)); ++ return result; ++} ++ ++sl_status_t dotdot_set_unify_switch_color_green( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state, ++ uint8_t new_green ++ ) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN); ++ ++ return attribute_store_set_node_attribute_value(node, ++ value_state, ++ (uint8_t *)&new_green, ++ sizeof(uint8_t)); ++ } ++ ++sl_status_t dotdot_unify_switch_color_green_undefine_reported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN); ++ attribute_store_undefine_reported(node); ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++ ++sl_status_t dotdot_unify_switch_color_green_undefine_desired( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN); ++ attribute_store_undefine_desired(node); ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++ ++ ++bool dotdot_unify_switch_color_green_is_reported_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN); ++ return attribute_store_is_reported_defined(node); ++} ++ ++bool dotdot_unify_switch_color_green_is_desired_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN); ++ return attribute_store_is_desired_defined(node); ++} ++ ++sl_status_t dotdot_create_unify_switch_color_green( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node = ++ attribute_store_create_child_if_missing(endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN); ++ ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++bool dotdot_is_supported_unify_switch_color_blue( ++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE); ++ return attribute_store_node_exists(node); ++} ++ ++uint8_t dotdot_get_unify_switch_color_blue( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE); ++ ++ uint8_t result = {}; ++ attribute_store_read_value(node, ++ value_state, ++ (uint8_t *)&result, ++ sizeof(result)); ++ return result; ++} ++ ++sl_status_t dotdot_set_unify_switch_color_blue( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state, ++ uint8_t new_blue ++ ) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE); ++ ++ return attribute_store_set_node_attribute_value(node, ++ value_state, ++ (uint8_t *)&new_blue, ++ sizeof(uint8_t)); ++ } ++ ++sl_status_t dotdot_unify_switch_color_blue_undefine_reported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE); ++ attribute_store_undefine_reported(node); ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++ ++sl_status_t dotdot_unify_switch_color_blue_undefine_desired( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE); ++ attribute_store_undefine_desired(node); ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++ ++ ++bool dotdot_unify_switch_color_blue_is_reported_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE); ++ return attribute_store_is_reported_defined(node); ++} ++ ++bool dotdot_unify_switch_color_blue_is_desired_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE); ++ return attribute_store_is_desired_defined(node); ++} ++ ++sl_status_t dotdot_create_unify_switch_color_blue( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node = ++ attribute_store_create_child_if_missing(endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE); ++ ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++bool dotdot_is_supported_unify_switch_color_amber( ++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER); ++ return attribute_store_node_exists(node); ++} ++ ++uint8_t dotdot_get_unify_switch_color_amber( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER); ++ ++ uint8_t result = {}; ++ attribute_store_read_value(node, ++ value_state, ++ (uint8_t *)&result, ++ sizeof(result)); ++ return result; ++} ++ ++sl_status_t dotdot_set_unify_switch_color_amber( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state, ++ uint8_t new_amber ++ ) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER); ++ ++ return attribute_store_set_node_attribute_value(node, ++ value_state, ++ (uint8_t *)&new_amber, ++ sizeof(uint8_t)); ++ } ++ ++sl_status_t dotdot_unify_switch_color_amber_undefine_reported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER); ++ attribute_store_undefine_reported(node); ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++ ++sl_status_t dotdot_unify_switch_color_amber_undefine_desired( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER); ++ attribute_store_undefine_desired(node); ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++ ++ ++bool dotdot_unify_switch_color_amber_is_reported_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER); ++ return attribute_store_is_reported_defined(node); ++} ++ ++bool dotdot_unify_switch_color_amber_is_desired_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER); ++ return attribute_store_is_desired_defined(node); ++} ++ ++sl_status_t dotdot_create_unify_switch_color_amber( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node = ++ attribute_store_create_child_if_missing(endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER); ++ ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++bool dotdot_is_supported_unify_switch_color_cyan( ++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN); ++ return attribute_store_node_exists(node); ++} ++ ++uint8_t dotdot_get_unify_switch_color_cyan( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN); ++ ++ uint8_t result = {}; ++ attribute_store_read_value(node, ++ value_state, ++ (uint8_t *)&result, ++ sizeof(result)); ++ return result; ++} ++ ++sl_status_t dotdot_set_unify_switch_color_cyan( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state, ++ uint8_t new_cyan ++ ) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN); ++ ++ return attribute_store_set_node_attribute_value(node, ++ value_state, ++ (uint8_t *)&new_cyan, ++ sizeof(uint8_t)); ++ } ++ ++sl_status_t dotdot_unify_switch_color_cyan_undefine_reported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN); ++ attribute_store_undefine_reported(node); ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++ ++sl_status_t dotdot_unify_switch_color_cyan_undefine_desired( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN); ++ attribute_store_undefine_desired(node); ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++ ++ ++bool dotdot_unify_switch_color_cyan_is_reported_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN); ++ return attribute_store_is_reported_defined(node); ++} ++ ++bool dotdot_unify_switch_color_cyan_is_desired_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN); ++ return attribute_store_is_desired_defined(node); ++} ++ ++sl_status_t dotdot_create_unify_switch_color_cyan( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node = ++ attribute_store_create_child_if_missing(endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN); ++ ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++bool dotdot_is_supported_unify_switch_color_purple( ++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE); ++ return attribute_store_node_exists(node); ++} ++ ++uint8_t dotdot_get_unify_switch_color_purple( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE); ++ ++ uint8_t result = {}; ++ attribute_store_read_value(node, ++ value_state, ++ (uint8_t *)&result, ++ sizeof(result)); ++ return result; ++} ++ ++sl_status_t dotdot_set_unify_switch_color_purple( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ attribute_store_node_value_state_t value_state, ++ uint8_t new_purple ++ ) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE); ++ ++ return attribute_store_set_node_attribute_value(node, ++ value_state, ++ (uint8_t *)&new_purple, ++ sizeof(uint8_t)); ++ } ++ ++sl_status_t dotdot_unify_switch_color_purple_undefine_reported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE); ++ attribute_store_undefine_reported(node); ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++ ++sl_status_t dotdot_unify_switch_color_purple_undefine_desired( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE); ++ attribute_store_undefine_desired(node); ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++ ++ ++bool dotdot_unify_switch_color_purple_is_reported_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE); ++ return attribute_store_is_reported_defined(node); ++} ++ ++bool dotdot_unify_switch_color_purple_is_desired_defined( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) ++{ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node ++ = attribute_store_get_first_child_by_type( ++ endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE); ++ return attribute_store_is_desired_defined(node); ++} ++ ++sl_status_t dotdot_create_unify_switch_color_purple( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id); ++ attribute_store_node_t node = ++ attribute_store_create_child_if_missing(endpoint_node, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE); ++ ++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL; ++} ++ ++bool dotdot_is_any_unify_switch_color_attribute_supported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ if (true == dotdot_is_supported_unify_switch_color_warm_white(unid, endpoint_id)) { ++ return true; ++ } ++ if (true == dotdot_is_supported_unify_switch_color_cold_white(unid, endpoint_id)) { ++ return true; ++ } ++ if (true == dotdot_is_supported_unify_switch_color_red(unid, endpoint_id)) { ++ return true; ++ } ++ if (true == dotdot_is_supported_unify_switch_color_green(unid, endpoint_id)) { ++ return true; ++ } ++ if (true == dotdot_is_supported_unify_switch_color_blue(unid, endpoint_id)) { ++ return true; ++ } ++ if (true == dotdot_is_supported_unify_switch_color_amber(unid, endpoint_id)) { ++ return true; ++ } ++ if (true == dotdot_is_supported_unify_switch_color_cyan(unid, endpoint_id)) { ++ return true; ++ } ++ if (true == dotdot_is_supported_unify_switch_color_purple(unid, endpoint_id)) { ++ return true; ++ } ++ ++ return false; ++} ++ ++bool dotdot_is_any_unify_switch_color_writable_attribute_supported( ++ const dotdot_unid_t unid, ++ const dotdot_endpoint_id_t endpoint_id) { ++ ++ + return false; + } +diff --git a/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_registration.cpp b/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_registration.cpp +index 329813ba1c..15a883ab8a 100644 +--- a/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_registration.cpp ++++ b/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_registration.cpp +@@ -17647,6 +17647,198 @@ sl_status_t unify_dotdot_attribute_store_registration_init() + // clang-format off + // clang-format on + ++ { ++ // uint8 // uint8 // uint8_t ++ std::string attribute_type_string = "uint8_t"; ++ attribute_store_storage_type_t storage_type = UNKNOWN_STORAGE_TYPE; ++ ++ // clang-format off ++ storage_type = attribute_storage_type_conversion(attribute_type_string); ++ ++ if (storage_type == UNKNOWN_STORAGE_TYPE) { ++ sl_log_warning(LOG_TAG, ++ "Unkown storage type for ZCL UnifySwitchColor WarmWhite, " ++ "type: uint8 // uint8_t"); ++ } ++ ++ status |= attribute_store_register_type( ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE, ++ "ZCL UnifySwitchColor WarmWhite", ++ ATTRIBUTE_STORE_INVALID_ATTRIBUTE_TYPE, ++ storage_type); ++ } ++ ++ // clang-format off ++ // clang-format on ++ ++ { ++ // uint8 // uint8 // uint8_t ++ std::string attribute_type_string = "uint8_t"; ++ attribute_store_storage_type_t storage_type = UNKNOWN_STORAGE_TYPE; ++ ++ // clang-format off ++ storage_type = attribute_storage_type_conversion(attribute_type_string); ++ ++ if (storage_type == UNKNOWN_STORAGE_TYPE) { ++ sl_log_warning(LOG_TAG, ++ "Unkown storage type for ZCL UnifySwitchColor ColdWhite, " ++ "type: uint8 // uint8_t"); ++ } ++ ++ status |= attribute_store_register_type( ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE, ++ "ZCL UnifySwitchColor ColdWhite", ++ ATTRIBUTE_STORE_INVALID_ATTRIBUTE_TYPE, ++ storage_type); ++ } ++ ++ // clang-format off ++ // clang-format on ++ ++ { ++ // uint8 // uint8 // uint8_t ++ std::string attribute_type_string = "uint8_t"; ++ attribute_store_storage_type_t storage_type = UNKNOWN_STORAGE_TYPE; ++ ++ // clang-format off ++ storage_type = attribute_storage_type_conversion(attribute_type_string); ++ ++ if (storage_type == UNKNOWN_STORAGE_TYPE) { ++ sl_log_warning(LOG_TAG, ++ "Unkown storage type for ZCL UnifySwitchColor Red, " ++ "type: uint8 // uint8_t"); ++ } ++ ++ status |= attribute_store_register_type( ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED, ++ "ZCL UnifySwitchColor Red", ++ ATTRIBUTE_STORE_INVALID_ATTRIBUTE_TYPE, ++ storage_type); ++ } ++ ++ // clang-format off ++ // clang-format on ++ ++ { ++ // uint8 // uint8 // uint8_t ++ std::string attribute_type_string = "uint8_t"; ++ attribute_store_storage_type_t storage_type = UNKNOWN_STORAGE_TYPE; ++ ++ // clang-format off ++ storage_type = attribute_storage_type_conversion(attribute_type_string); ++ ++ if (storage_type == UNKNOWN_STORAGE_TYPE) { ++ sl_log_warning(LOG_TAG, ++ "Unkown storage type for ZCL UnifySwitchColor Green, " ++ "type: uint8 // uint8_t"); ++ } ++ ++ status |= attribute_store_register_type( ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN, ++ "ZCL UnifySwitchColor Green", ++ ATTRIBUTE_STORE_INVALID_ATTRIBUTE_TYPE, ++ storage_type); ++ } ++ ++ // clang-format off ++ // clang-format on ++ ++ { ++ // uint8 // uint8 // uint8_t ++ std::string attribute_type_string = "uint8_t"; ++ attribute_store_storage_type_t storage_type = UNKNOWN_STORAGE_TYPE; ++ ++ // clang-format off ++ storage_type = attribute_storage_type_conversion(attribute_type_string); ++ ++ if (storage_type == UNKNOWN_STORAGE_TYPE) { ++ sl_log_warning(LOG_TAG, ++ "Unkown storage type for ZCL UnifySwitchColor Blue, " ++ "type: uint8 // uint8_t"); ++ } ++ ++ status |= attribute_store_register_type( ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE, ++ "ZCL UnifySwitchColor Blue", ++ ATTRIBUTE_STORE_INVALID_ATTRIBUTE_TYPE, ++ storage_type); ++ } ++ ++ // clang-format off ++ // clang-format on ++ ++ { ++ // uint8 // uint8 // uint8_t ++ std::string attribute_type_string = "uint8_t"; ++ attribute_store_storage_type_t storage_type = UNKNOWN_STORAGE_TYPE; ++ ++ // clang-format off ++ storage_type = attribute_storage_type_conversion(attribute_type_string); ++ ++ if (storage_type == UNKNOWN_STORAGE_TYPE) { ++ sl_log_warning(LOG_TAG, ++ "Unkown storage type for ZCL UnifySwitchColor Amber, " ++ "type: uint8 // uint8_t"); ++ } ++ ++ status |= attribute_store_register_type( ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER, ++ "ZCL UnifySwitchColor Amber", ++ ATTRIBUTE_STORE_INVALID_ATTRIBUTE_TYPE, ++ storage_type); ++ } ++ ++ // clang-format off ++ // clang-format on ++ ++ { ++ // uint8 // uint8 // uint8_t ++ std::string attribute_type_string = "uint8_t"; ++ attribute_store_storage_type_t storage_type = UNKNOWN_STORAGE_TYPE; ++ ++ // clang-format off ++ storage_type = attribute_storage_type_conversion(attribute_type_string); ++ ++ if (storage_type == UNKNOWN_STORAGE_TYPE) { ++ sl_log_warning(LOG_TAG, ++ "Unkown storage type for ZCL UnifySwitchColor Cyan, " ++ "type: uint8 // uint8_t"); ++ } ++ ++ status |= attribute_store_register_type( ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN, ++ "ZCL UnifySwitchColor Cyan", ++ ATTRIBUTE_STORE_INVALID_ATTRIBUTE_TYPE, ++ storage_type); ++ } ++ ++ // clang-format off ++ // clang-format on ++ ++ { ++ // uint8 // uint8 // uint8_t ++ std::string attribute_type_string = "uint8_t"; ++ attribute_store_storage_type_t storage_type = UNKNOWN_STORAGE_TYPE; ++ ++ // clang-format off ++ storage_type = attribute_storage_type_conversion(attribute_type_string); ++ ++ if (storage_type == UNKNOWN_STORAGE_TYPE) { ++ sl_log_warning(LOG_TAG, ++ "Unkown storage type for ZCL UnifySwitchColor Purple, " ++ "type: uint8 // uint8_t"); ++ } ++ ++ status |= attribute_store_register_type( ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE, ++ "ZCL UnifySwitchColor Purple", ++ ATTRIBUTE_STORE_INVALID_ATTRIBUTE_TYPE, ++ storage_type); ++ } ++ ++ // clang-format off ++ // clang-format on ++ + // Additional attributes: + for (auto const &a: zcl_additional_attribute_schema) { + status |= attribute_store_register_type(a.type, +diff --git a/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_write_attributes_command_callbacks.c b/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_write_attributes_command_callbacks.c +index 7443995a7b..8e992503d3 100644 +--- a/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_write_attributes_command_callbacks.c ++++ b/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_write_attributes_command_callbacks.c +@@ -2585,6 +2585,36 @@ static sl_status_t unify_humidity_control_cluster_write_attributes_callback( + endpoint_id); + return SL_STATUS_OK; + } ++//////////////////////////////////////////////////////////////////////////////// ++// Start of cluster UnifySwitchColor ++//////////////////////////////////////////////////////////////////////////////// ++// WriteAttribute Callbacks unify_switch_color ++static sl_status_t unify_switch_color_cluster_write_attributes_callback( ++ const dotdot_unid_t unid, ++ dotdot_endpoint_id_t endpoint_id, ++ uic_mqtt_dotdot_callback_call_type_t call_type, ++ uic_mqtt_dotdot_unify_switch_color_state_t attributes, ++ uic_mqtt_dotdot_unify_switch_color_updated_state_t updated_attributes) ++{ ++ if (false == is_write_attributes_enabled()) { ++ return SL_STATUS_FAIL; ++ } ++ ++ if (call_type == UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK) { ++ if (is_automatic_deduction_of_supported_commands_enabled()) { ++ return dotdot_is_any_unify_switch_color_writable_attribute_supported(unid, endpoint_id) ? ++ SL_STATUS_OK : SL_STATUS_FAIL; ++ } else { ++ return SL_STATUS_FAIL; ++ } ++ } ++ ++ sl_log_debug(LOG_TAG, ++ "unify_switch_color: Incoming WriteAttributes command for %s, endpoint %d.\n", ++ unid, ++ endpoint_id); ++ return SL_STATUS_OK; ++} + // clang-format on + + //////////////////////////////////////////////////////////////////////////////// +@@ -2758,6 +2788,9 @@ sl_status_t + uic_mqtt_dotdot_set_unify_humidity_control_write_attributes_callback( + &unify_humidity_control_cluster_write_attributes_callback); + ++ uic_mqtt_dotdot_set_unify_switch_color_write_attributes_callback( ++ &unify_switch_color_cluster_write_attributes_callback); ++ + // clang-format on + + return SL_STATUS_OK; +diff --git a/components/unify_dotdot_attribute_store/zap-generated/test/unify_dotdot_attribute_store_test.c b/components/unify_dotdot_attribute_store/zap-generated/test/unify_dotdot_attribute_store_test.c +index 12f32c1833..40b1d826a4 100644 +--- a/components/unify_dotdot_attribute_store/zap-generated/test/unify_dotdot_attribute_store_test.c ++++ b/components/unify_dotdot_attribute_store/zap-generated/test/unify_dotdot_attribute_store_test.c +@@ -1420,6 +1420,24 @@ static uic_mqtt_dotdot_unify_humidity_control_setpoint_set_callback_t test_uic_m + uic_mqtt_dotdot_unify_humidity_control_setpoint_set_callback_t get_uic_mqtt_dotdot_unify_humidity_control_setpoint_set_callback(){ + return test_uic_mqtt_dotdot_unify_humidity_control_setpoint_set_callback; + } ++static uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback_t test_uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback = NULL; ++static uic_mqtt_dotdot_unify_switch_color_write_attributes_callback_t test_uic_mqtt_dotdot_unify_switch_color_write_attributes_callback = NULL; ++ ++uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback_t get_uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback(){ ++ return test_uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback; ++} ++uic_mqtt_dotdot_unify_switch_color_write_attributes_callback_t get_uic_mqtt_dotdot_unify_switch_color_write_attributes_callback(){ ++ return test_uic_mqtt_dotdot_unify_switch_color_write_attributes_callback; ++} ++ ++static uic_mqtt_dotdot_unify_switch_color_set_color_callback_t test_uic_mqtt_dotdot_unify_switch_color_set_color_callback = NULL; ++uic_mqtt_dotdot_unify_switch_color_set_color_callback_t get_uic_mqtt_dotdot_unify_switch_color_set_color_callback(){ ++ return test_uic_mqtt_dotdot_unify_switch_color_set_color_callback; ++} ++static uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_t test_uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback = NULL; ++uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_t get_uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback(){ ++ return test_uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback; ++} + // clang-format on + + #define TEST_UNID "test-unid-123" +@@ -3131,6 +3149,26 @@ void uic_mqtt_dotdot_unify_humidity_control_setpoint_set_callback_set_stub( + { + test_uic_mqtt_dotdot_unify_humidity_control_setpoint_set_callback = callback; + } ++void set_uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback_stub( ++ const uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback_t callback, int cmock_num_calls) ++{ ++ test_uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback = callback; ++} ++void set_uic_mqtt_dotdot_unify_switch_color_write_attributes_callback_stub( ++ const uic_mqtt_dotdot_unify_switch_color_write_attributes_callback_t callback, int cmock_num_calls) ++{ ++ test_uic_mqtt_dotdot_unify_switch_color_write_attributes_callback = callback; ++} ++void uic_mqtt_dotdot_unify_switch_color_set_color_callback_set_stub( ++ const uic_mqtt_dotdot_unify_switch_color_set_color_callback_t callback, int cmock_num_calls) ++{ ++ test_uic_mqtt_dotdot_unify_switch_color_set_color_callback = callback; ++} ++void uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_set_stub( ++ const uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_t callback, int cmock_num_calls) ++{ ++ test_uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback = callback; ++} + // clang-format on + + // Test functions +@@ -4129,6 +4167,18 @@ void setUp() + test_uic_mqtt_dotdot_unify_humidity_control_setpoint_set_callback = NULL; + uic_mqtt_dotdot_unify_humidity_control_setpoint_set_callback_set_Stub( + &uic_mqtt_dotdot_unify_humidity_control_setpoint_set_callback_set_stub); ++ test_uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback = NULL; ++ uic_mqtt_dotdot_set_unify_switch_color_force_read_attributes_callback_Stub( ++ &set_uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback_stub); ++ test_uic_mqtt_dotdot_unify_switch_color_write_attributes_callback = NULL; ++ uic_mqtt_dotdot_set_unify_switch_color_write_attributes_callback_Stub( ++ &set_uic_mqtt_dotdot_unify_switch_color_write_attributes_callback_stub); ++ test_uic_mqtt_dotdot_unify_switch_color_set_color_callback = NULL; ++ uic_mqtt_dotdot_unify_switch_color_set_color_callback_set_Stub( ++ &uic_mqtt_dotdot_unify_switch_color_set_color_callback_set_stub); ++ test_uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback = NULL; ++ uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_set_Stub( ++ &uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_set_stub); + // clang-format on + + group_command_dispatch = NULL; +@@ -4905,6 +4955,14 @@ void test_automatic_deduction_of_supported_commands() + TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_unify_humidity_control_auto_setpoint(expected_unid,expected_endpoint_id) ); + TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_unify_humidity_control_auto_setpoint_scale(expected_unid,expected_endpoint_id) ); + TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_unify_humidity_control_auto_setpoint_precision(expected_unid,expected_endpoint_id) ); ++ TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_unify_switch_color_warm_white(expected_unid,expected_endpoint_id) ); ++ TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_unify_switch_color_cold_white(expected_unid,expected_endpoint_id) ); ++ TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_unify_switch_color_red(expected_unid,expected_endpoint_id) ); ++ TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_unify_switch_color_green(expected_unid,expected_endpoint_id) ); ++ TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_unify_switch_color_blue(expected_unid,expected_endpoint_id) ); ++ TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_unify_switch_color_amber(expected_unid,expected_endpoint_id) ); ++ TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_unify_switch_color_cyan(expected_unid,expected_endpoint_id) ); ++ TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_unify_switch_color_purple(expected_unid,expected_endpoint_id) ); + + // clang-format on + // ColorControl checks the value in the bitmask: +@@ -8352,6 +8410,56 @@ void test_automatic_deduction_of_supported_commands() + + )); + } ++ if (NULL != test_uic_mqtt_dotdot_unify_switch_color_set_color_callback) { ++ // Dummy command parameters ++ uint8_t color_component_id_value; ++ memset(&color_component_id_value, 0x00, sizeof(color_component_id_value)); ++ uint8_t value_value; ++ memset(&value_value, 0x00, sizeof(value_value)); ++ uint32_t duration_value; ++ memset(&duration_value, 0x00, sizeof(duration_value)); ++ // Invoke with support check ++ TEST_ASSERT_EQUAL(SL_STATUS_FAIL, test_uic_mqtt_dotdot_unify_switch_color_set_color_callback(expected_unid,expected_endpoint_id,UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK ++ , ++ color_component_id_value, ++ ++ value_value, ++ ++ duration_value ++ ++ )); ++ } ++ if (NULL != test_uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback) { ++ // Dummy command parameters ++ bool start_stop_value; ++ memset(&start_stop_value, 0x00, sizeof(start_stop_value)); ++ bool up_down_value; ++ memset(&up_down_value, 0x00, sizeof(up_down_value)); ++ bool ignor_start_level_value; ++ memset(&ignor_start_level_value, 0x00, sizeof(ignor_start_level_value)); ++ uint8_t color_component_id_value; ++ memset(&color_component_id_value, 0x00, sizeof(color_component_id_value)); ++ uint8_t start_level_value; ++ memset(&start_level_value, 0x00, sizeof(start_level_value)); ++ uint32_t duration_value; ++ memset(&duration_value, 0x00, sizeof(duration_value)); ++ // Invoke with support check ++ TEST_ASSERT_EQUAL(SL_STATUS_FAIL, test_uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback(expected_unid,expected_endpoint_id,UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK ++ , ++ start_stop_value, ++ ++ up_down_value, ++ ++ ignor_start_level_value, ++ ++ color_component_id_value, ++ ++ start_level_value, ++ ++ duration_value ++ ++ )); ++ } + + // Invoke all commands with support check, they should return SL_STATUS_OK + // because all ZCL attributes are supported +@@ -11791,5 +11899,55 @@ void test_automatic_deduction_of_supported_commands() + + )); + } ++ if (NULL != test_uic_mqtt_dotdot_unify_switch_color_set_color_callback) { ++ // Dummy command parameters ++ uint8_t color_component_id_value; ++ memset(&color_component_id_value, 0x00, sizeof(color_component_id_value)); ++ uint8_t value_value; ++ memset(&value_value, 0x00, sizeof(value_value)); ++ uint32_t duration_value; ++ memset(&duration_value, 0x00, sizeof(duration_value)); ++ // Invoke with support check ++ TEST_ASSERT_EQUAL(SL_STATUS_OK, test_uic_mqtt_dotdot_unify_switch_color_set_color_callback(expected_unid,expected_endpoint_id,UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK ++ , ++ color_component_id_value, ++ ++ value_value, ++ ++ duration_value ++ ++ )); ++ } ++ if (NULL != test_uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback) { ++ // Dummy command parameters ++ bool start_stop_value; ++ memset(&start_stop_value, 0x00, sizeof(start_stop_value)); ++ bool up_down_value; ++ memset(&up_down_value, 0x00, sizeof(up_down_value)); ++ bool ignor_start_level_value; ++ memset(&ignor_start_level_value, 0x00, sizeof(ignor_start_level_value)); ++ uint8_t color_component_id_value; ++ memset(&color_component_id_value, 0x00, sizeof(color_component_id_value)); ++ uint8_t start_level_value; ++ memset(&start_level_value, 0x00, sizeof(start_level_value)); ++ uint32_t duration_value; ++ memset(&duration_value, 0x00, sizeof(duration_value)); ++ // Invoke with support check ++ TEST_ASSERT_EQUAL(SL_STATUS_OK, test_uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback(expected_unid,expected_endpoint_id,UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK ++ , ++ start_stop_value, ++ ++ up_down_value, ++ ++ ignor_start_level_value, ++ ++ color_component_id_value, ++ ++ start_level_value, ++ ++ duration_value ++ ++ )); ++ } + + } +diff --git a/components/unify_dotdot_attribute_store/zap-generated/test/unify_dotdot_attribute_store_test.h b/components/unify_dotdot_attribute_store/zap-generated/test/unify_dotdot_attribute_store_test.h +index d5c2ed0913..7e291a589c 100644 +--- a/components/unify_dotdot_attribute_store/zap-generated/test/unify_dotdot_attribute_store_test.h ++++ b/components/unify_dotdot_attribute_store/zap-generated/test/unify_dotdot_attribute_store_test.h +@@ -867,4 +867,14 @@ + + uic_mqtt_dotdot_unify_humidity_control_setpoint_set_callback_t get_uic_mqtt_dotdot_unify_humidity_control_setpoint_set_callback(); + ++ ++ uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback_t get_uic_mqtt_dotdot_unify_switch_color_force_read_attributes_callback(); ++ uic_mqtt_dotdot_unify_switch_color_write_attributes_callback_t get_uic_mqtt_dotdot_unify_switch_color_write_attributes_callback(); ++ ++ ++ uic_mqtt_dotdot_unify_switch_color_set_color_callback_t get_uic_mqtt_dotdot_unify_switch_color_set_color_callback(); ++ ++ ++ uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_t get_uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback(); ++ + #endif // UNIFY_DOTDOT_ATTRIBUTE_STORE_TEST_H +\ No newline at end of file +-- +2.39.5 + diff --git a/patches/UnifySDK/0016-UIC-3272-Custom-Switch-Color-cluster.patch b/patches/UnifySDK/0016-UIC-3272-Custom-Switch-Color-cluster.patch new file mode 100644 index 000000000..d7fcd5ab4 --- /dev/null +++ b/patches/UnifySDK/0016-UIC-3272-Custom-Switch-Color-cluster.patch @@ -0,0 +1,81 @@ +From d6dafa94d28e5abfacdab6ea03062f9ed01cfded Mon Sep 17 00:00:00 2001 +From: Viet +Date: Wed, 11 Sep 2024 18:17:01 +0700 +Subject: [PATCH] UIC-3272: Custom Switch Color cluster + +--- + .../dotdot-xml/Unify_SwitchColor.xml | 48 +++++++++++++++++++ + components/uic_dotdot/dotdot-xml/library.xml | 4 +- + 2 files changed, 50 insertions(+), 2 deletions(-) + create mode 100644 components/uic_dotdot/dotdot-xml/Unify_SwitchColor.xml + +diff --git a/components/uic_dotdot/dotdot-xml/Unify_SwitchColor.xml b/components/uic_dotdot/dotdot-xml/Unify_SwitchColor.xml +new file mode 100644 +index 0000000000..e4a5d1d6d9 +--- /dev/null ++++ b/components/uic_dotdot/dotdot-xml/Unify_SwitchColor.xml +@@ -0,0 +1,48 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/components/uic_dotdot/dotdot-xml/library.xml b/components/uic_dotdot/dotdot-xml/library.xml +index 79e165dbc6..892551c6b0 100644 +--- a/components/uic_dotdot/dotdot-xml/library.xml ++++ b/components/uic_dotdot/dotdot-xml/library.xml +@@ -502,5 +502,5 @@ applicable to this document can be found in the LICENSE.md file. + + + +- +- +\ No newline at end of file ++ ++ +-- +2.39.5 + diff --git a/patches/UnifySDK/0017-UIC-3272-Regen-zap-files.patch b/patches/UnifySDK/0017-UIC-3272-Regen-zap-files.patch new file mode 100644 index 000000000..1c2507b27 --- /dev/null +++ b/patches/UnifySDK/0017-UIC-3272-Regen-zap-files.patch @@ -0,0 +1,1073 @@ +From f91e80abb94fea222cdf8499b64ddcbec992cd16 Mon Sep 17 00:00:00 2001 +From: Philippe Coval +Date: Mon, 29 Sep 2025 10:46:44 +0200 +Subject: [PATCH] UIC-3272: Regen zap files + +Signed-off-by: Philippe Coval +--- + .../src/eed_attribute_store_clusters.c | 32 + + .../src/eed_dotdot_create_clusters.cpp | 87 +++ + .../include/dotdot_attribute_id_definitions.h | 9 + + .../dotdot_cluster_command_id_definitions.h | 4 + + .../include/dotdot_cluster_id_definitions.h | 4 + + .../readme_ucl_mqtt_reference.md | 697 ++++++++++++++++++ + .../src/dotdot_attribute_id_definitions.c | 79 ++ + .../src/dotdot_cluster_id_definitions.c | 5 + + 8 files changed, 917 insertions(+) + +diff --git a/applications/examples/applications/emulated_end_device/components/eed_attribute_store/zap-generated/src/eed_attribute_store_clusters.c b/applications/examples/applications/emulated_end_device/components/eed_attribute_store/zap-generated/src/eed_attribute_store_clusters.c +index 05c5b08f6f..b0d111a7fa 100644 +--- a/applications/examples/applications/emulated_end_device/components/eed_attribute_store/zap-generated/src/eed_attribute_store_clusters.c ++++ b/applications/examples/applications/emulated_end_device/components/eed_attribute_store/zap-generated/src/eed_attribute_store_clusters.c +@@ -2823,6 +2823,38 @@ sl_status_t eed_attribute_store_clusters_init() + &on_zcl_desired_value_update, + DOTDOT_ATTRIBUTE_ID_UNIFY_HUMIDITY_CONTROL_AUTO_SETPOINT_PRECISION, + DESIRED_ATTRIBUTE); ++ attribute_store_register_callback_by_type_and_state( ++ &on_zcl_desired_value_update, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE, ++ DESIRED_ATTRIBUTE); ++ attribute_store_register_callback_by_type_and_state( ++ &on_zcl_desired_value_update, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE, ++ DESIRED_ATTRIBUTE); ++ attribute_store_register_callback_by_type_and_state( ++ &on_zcl_desired_value_update, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED, ++ DESIRED_ATTRIBUTE); ++ attribute_store_register_callback_by_type_and_state( ++ &on_zcl_desired_value_update, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN, ++ DESIRED_ATTRIBUTE); ++ attribute_store_register_callback_by_type_and_state( ++ &on_zcl_desired_value_update, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE, ++ DESIRED_ATTRIBUTE); ++ attribute_store_register_callback_by_type_and_state( ++ &on_zcl_desired_value_update, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER, ++ DESIRED_ATTRIBUTE); ++ attribute_store_register_callback_by_type_and_state( ++ &on_zcl_desired_value_update, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN, ++ DESIRED_ATTRIBUTE); ++ attribute_store_register_callback_by_type_and_state( ++ &on_zcl_desired_value_update, ++ DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE, ++ DESIRED_ATTRIBUTE); + // clang-format on + return SL_STATUS_OK; + } +\ No newline at end of file +diff --git a/applications/examples/applications/emulated_end_device/components/eed_attribute_store/zap-generated/src/eed_dotdot_create_clusters.cpp b/applications/examples/applications/emulated_end_device/components/eed_attribute_store/zap-generated/src/eed_dotdot_create_clusters.cpp +index e3ce84ccee..5619115b87 100644 +--- a/applications/examples/applications/emulated_end_device/components/eed_attribute_store/zap-generated/src/eed_dotdot_create_clusters.cpp ++++ b/applications/examples/applications/emulated_end_device/components/eed_attribute_store/zap-generated/src/eed_dotdot_create_clusters.cpp +@@ -4208,6 +4208,57 @@ void dotdot_create_unify_humidity_control_wrapper(const dotdot_unid_t unid, cons + + } + ++void dotdot_create_unify_switch_color_wrapper(const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id){ ++ // Create and set a default value if undefined. ++ dotdot_create_unify_switch_color_warm_white(unid,endpoint_id); ++ if (false == dotdot_unify_switch_color_warm_white_is_reported_defined(unid,endpoint_id)){ ++ dotdot_set_unify_switch_color_warm_white(unid,endpoint_id,REPORTED_ATTRIBUTE, static_cast(0)); ++ } ++ ++ // Create and set a default value if undefined. ++ dotdot_create_unify_switch_color_cold_white(unid,endpoint_id); ++ if (false == dotdot_unify_switch_color_cold_white_is_reported_defined(unid,endpoint_id)){ ++ dotdot_set_unify_switch_color_cold_white(unid,endpoint_id,REPORTED_ATTRIBUTE, static_cast(0)); ++ } ++ ++ // Create and set a default value if undefined. ++ dotdot_create_unify_switch_color_red(unid,endpoint_id); ++ if (false == dotdot_unify_switch_color_red_is_reported_defined(unid,endpoint_id)){ ++ dotdot_set_unify_switch_color_red(unid,endpoint_id,REPORTED_ATTRIBUTE, static_cast(0)); ++ } ++ ++ // Create and set a default value if undefined. ++ dotdot_create_unify_switch_color_green(unid,endpoint_id); ++ if (false == dotdot_unify_switch_color_green_is_reported_defined(unid,endpoint_id)){ ++ dotdot_set_unify_switch_color_green(unid,endpoint_id,REPORTED_ATTRIBUTE, static_cast(0)); ++ } ++ ++ // Create and set a default value if undefined. ++ dotdot_create_unify_switch_color_blue(unid,endpoint_id); ++ if (false == dotdot_unify_switch_color_blue_is_reported_defined(unid,endpoint_id)){ ++ dotdot_set_unify_switch_color_blue(unid,endpoint_id,REPORTED_ATTRIBUTE, static_cast(0)); ++ } ++ ++ // Create and set a default value if undefined. ++ dotdot_create_unify_switch_color_amber(unid,endpoint_id); ++ if (false == dotdot_unify_switch_color_amber_is_reported_defined(unid,endpoint_id)){ ++ dotdot_set_unify_switch_color_amber(unid,endpoint_id,REPORTED_ATTRIBUTE, static_cast(0)); ++ } ++ ++ // Create and set a default value if undefined. ++ dotdot_create_unify_switch_color_cyan(unid,endpoint_id); ++ if (false == dotdot_unify_switch_color_cyan_is_reported_defined(unid,endpoint_id)){ ++ dotdot_set_unify_switch_color_cyan(unid,endpoint_id,REPORTED_ATTRIBUTE, static_cast(0)); ++ } ++ ++ // Create and set a default value if undefined. ++ dotdot_create_unify_switch_color_purple(unid,endpoint_id); ++ if (false == dotdot_unify_switch_color_purple_is_reported_defined(unid,endpoint_id)){ ++ dotdot_set_unify_switch_color_purple(unid,endpoint_id,REPORTED_ATTRIBUTE, static_cast(0)); ++ } ++ ++} ++ + + void dotdot_unretain_basic_wrapper(const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id){ + char base_topic[256]; +@@ -6718,6 +6769,40 @@ void dotdot_unretain_unify_humidity_control_wrapper(const dotdot_unid_t unid, co + uic_mqtt_dotdot_unify_humidity_control_publish_empty_supported_commands(unid, endpoint_id); + } + ++void dotdot_unretain_unify_switch_color_wrapper(const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id){ ++ char base_topic[256]; ++ snprintf(base_topic, sizeof(base_topic), "ucl/by-unid/%s/ep%d", unid, endpoint_id); ++ attribute_store::attribute ep_node = eed_attribute_store_get_endpoint_node(unid, endpoint_id); ++ ++ uic_mqtt_dotdot_unify_switch_color_warm_white_unretain(base_topic,UCL_MQTT_PUBLISH_TYPE_ALL); ++ ep_node.child_by_type(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_WARM_WHITE).delete_node(); ++ ++ uic_mqtt_dotdot_unify_switch_color_cold_white_unretain(base_topic,UCL_MQTT_PUBLISH_TYPE_ALL); ++ ep_node.child_by_type(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_COLD_WHITE).delete_node(); ++ ++ uic_mqtt_dotdot_unify_switch_color_red_unretain(base_topic,UCL_MQTT_PUBLISH_TYPE_ALL); ++ ep_node.child_by_type(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_RED).delete_node(); ++ ++ uic_mqtt_dotdot_unify_switch_color_green_unretain(base_topic,UCL_MQTT_PUBLISH_TYPE_ALL); ++ ep_node.child_by_type(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN).delete_node(); ++ ++ uic_mqtt_dotdot_unify_switch_color_blue_unretain(base_topic,UCL_MQTT_PUBLISH_TYPE_ALL); ++ ep_node.child_by_type(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_BLUE).delete_node(); ++ ++ uic_mqtt_dotdot_unify_switch_color_amber_unretain(base_topic,UCL_MQTT_PUBLISH_TYPE_ALL); ++ ep_node.child_by_type(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_AMBER).delete_node(); ++ ++ uic_mqtt_dotdot_unify_switch_color_cyan_unretain(base_topic,UCL_MQTT_PUBLISH_TYPE_ALL); ++ ep_node.child_by_type(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_CYAN).delete_node(); ++ ++ uic_mqtt_dotdot_unify_switch_color_purple_unretain(base_topic,UCL_MQTT_PUBLISH_TYPE_ALL); ++ ep_node.child_by_type(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_PURPLE).delete_node(); ++ ++ ++ uic_mqtt_dotdot_unify_switch_color_unretain_cluster_revision(base_topic); ++ uic_mqtt_dotdot_unify_switch_color_publish_empty_supported_commands(unid, endpoint_id); ++} ++ + + void eed_dotdot_create_clusters(const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id) { + for (auto& pair : CreateClusterMap) { +@@ -6797,6 +6882,7 @@ std::map CreateClusterMap = { + { "UnifyFanControl", dotdot_create_unify_fan_control_wrapper }, + { "UnifyThermostat", dotdot_create_unify_thermostat_wrapper }, + { "UnifyHumidityControl", dotdot_create_unify_humidity_control_wrapper }, ++{ "UnifySwitchColor", dotdot_create_unify_switch_color_wrapper }, + }; + + std::map CreateUnretainMap = { +@@ -6849,4 +6935,5 @@ std::map CreateUnretainMap = { + { "UnifyFanControl", dotdot_unretain_unify_fan_control_wrapper }, + { "UnifyThermostat", dotdot_unretain_unify_thermostat_wrapper }, + { "UnifyHumidityControl", dotdot_unretain_unify_humidity_control_wrapper }, ++{ "UnifySwitchColor", dotdot_unretain_unify_switch_color_wrapper }, + }; +\ No newline at end of file +diff --git a/components/uic_dotdot/zap-generated/include/dotdot_attribute_id_definitions.h b/components/uic_dotdot/zap-generated/include/dotdot_attribute_id_definitions.h +index b1512d6a82..643ace7524 100644 +--- a/components/uic_dotdot/zap-generated/include/dotdot_attribute_id_definitions.h ++++ b/components/uic_dotdot/zap-generated/include/dotdot_attribute_id_definitions.h +@@ -893,6 +893,15 @@ typedef enum { + #define DOTDOT_UNIFY_HUMIDITY_CONTROL_AUTO_SETPOINT_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x11) + #define DOTDOT_UNIFY_HUMIDITY_CONTROL_AUTO_SETPOINT_SCALE_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x12) + #define DOTDOT_UNIFY_HUMIDITY_CONTROL_AUTO_SETPOINT_PRECISION_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x13) ++// Definitions for cluster: UnifySwitchColor ++#define DOTDOT_UNIFY_SWITCH_COLOR_WARM_WHITE_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x0) ++#define DOTDOT_UNIFY_SWITCH_COLOR_COLD_WHITE_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x1) ++#define DOTDOT_UNIFY_SWITCH_COLOR_RED_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x2) ++#define DOTDOT_UNIFY_SWITCH_COLOR_GREEN_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x3) ++#define DOTDOT_UNIFY_SWITCH_COLOR_BLUE_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x4) ++#define DOTDOT_UNIFY_SWITCH_COLOR_AMBER_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x5) ++#define DOTDOT_UNIFY_SWITCH_COLOR_CYAN_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x6) ++#define DOTDOT_UNIFY_SWITCH_COLOR_PURPLE_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x7) + + // clang-format on + +diff --git a/components/uic_dotdot/zap-generated/include/dotdot_cluster_command_id_definitions.h b/components/uic_dotdot/zap-generated/include/dotdot_cluster_command_id_definitions.h +index 958a1064f5..6067e3ce74 100644 +--- a/components/uic_dotdot/zap-generated/include/dotdot_cluster_command_id_definitions.h ++++ b/components/uic_dotdot/zap-generated/include/dotdot_cluster_command_id_definitions.h +@@ -397,6 +397,10 @@ + #define DOTDOT_UNIFY_HUMIDITY_CONTROL_MODE_SET_COMMAND_ID (0x1) + #define DOTDOT_UNIFY_HUMIDITY_CONTROL_SETPOINT_SET_COMMAND_ID (0x2) + ++// Commands for cluster: UnifySwitchColor ++#define DOTDOT_UNIFY_SWITCH_COLOR_SET_COLOR_COMMAND_ID (0x0) ++#define DOTDOT_UNIFY_SWITCH_COLOR_START_STOP_CHANGE_COMMAND_ID (0x1) ++ + #ifdef __cplusplus + extern "C" { + #endif +diff --git a/components/uic_dotdot/zap-generated/include/dotdot_cluster_id_definitions.h b/components/uic_dotdot/zap-generated/include/dotdot_cluster_id_definitions.h +index ee7d429b0f..78c2cd96b4 100644 +--- a/components/uic_dotdot/zap-generated/include/dotdot_cluster_id_definitions.h ++++ b/components/uic_dotdot/zap-generated/include/dotdot_cluster_id_definitions.h +@@ -270,6 +270,10 @@ + #define DOTDOT_UNIFY_HUMIDITY_CONTROL_CLUSTER_ID ((dotdot_cluster_id_t)0xFDA0) + + ++// Definitions for cluster: UnifySwitchColor ++#define DOTDOT_UNIFY_SWITCH_COLOR_CLUSTER_ID ((dotdot_cluster_id_t)0xFFA1) ++ ++ + #ifdef __cplusplus + extern "C" { + #endif +diff --git a/components/uic_dotdot/zap-generated/readme_ucl_mqtt_reference.md b/components/uic_dotdot/zap-generated/readme_ucl_mqtt_reference.md +index 18ad4f947e..e1d6b1ddca 100644 +--- a/components/uic_dotdot/zap-generated/readme_ucl_mqtt_reference.md ++++ b/components/uic_dotdot/zap-generated/readme_ucl_mqtt_reference.md +@@ -55997,6 +55997,703 @@ mosquitto_pub -t 'ucl/by-unid///UnifyHumidityControl/Commands/ForceRea + + + ++


++ ++ ++ ++ ++ ++ ++ ++\page unify_switch_color UnifySwitchColor Cluster ++The following commands and attributes are accepted as JSON payloads for the ++UnifySwitchColor cluster. ++ ++

++ ++ ++ ++ ++\section unify_switch_color_attrs UnifySwitchColor Attributes ++The following attribute topics are used to retrieve the UnifySwitchColor cluster state. ++ ++
++ ++\subsection unify_switch_color_attr_warm_white UnifySwitchColor/WarmWhite Attribute ++ ++**MQTT Topic Pattern:** ++ ++``` ++[PREFIX]/UnifySwitchColor/Attributes/WarmWhite/Reported ++[PREFIX]/UnifySwitchColor/Attributes/WarmWhite/Desired ++``` ++ ++**MQTT Payload JSON Schema:** ++ ++```json ++{ ++ "$schema": "http://json-schema.org/draft-07/schema#", ++ "title": "UnifySwitchColor Cluster WarmWhite Attribute Properties", ++ "type": "object", ++ "properties": { ++ "value": { ++ "type": "integer" ++ } ++ }, ++ "required": [ ++ "value" ++ ] ++} ++``` ++ ++ ++**Example Mosquitto CLI Tool Usage** ++ ++To see desired/reported value for WarmWhite attribute under the by-unid topic space: ++ ++```console ++mosquitto_sub -t 'ucl/by-unid/+/+/UnifySwitchColor/Attributes/WarmWhite/+' ++ ++# Example output ++ ++ucl/by-unid//ep0/UnifySwitchColor/Attributes/WarmWhite/Desired { "value": } ++ucl/by-unid//ep0/UnifySwitchColor/Attributes/WarmWhite/Reported { "value": } ++ ++``` ++ ++

++ ++\subsection unify_switch_color_attr_cold_white UnifySwitchColor/ColdWhite Attribute ++ ++**MQTT Topic Pattern:** ++ ++``` ++[PREFIX]/UnifySwitchColor/Attributes/ColdWhite/Reported ++[PREFIX]/UnifySwitchColor/Attributes/ColdWhite/Desired ++``` ++ ++**MQTT Payload JSON Schema:** ++ ++```json ++{ ++ "$schema": "http://json-schema.org/draft-07/schema#", ++ "title": "UnifySwitchColor Cluster ColdWhite Attribute Properties", ++ "type": "object", ++ "properties": { ++ "value": { ++ "type": "integer" ++ } ++ }, ++ "required": [ ++ "value" ++ ] ++} ++``` ++ ++ ++**Example Mosquitto CLI Tool Usage** ++ ++To see desired/reported value for ColdWhite attribute under the by-unid topic space: ++ ++```console ++mosquitto_sub -t 'ucl/by-unid/+/+/UnifySwitchColor/Attributes/ColdWhite/+' ++ ++# Example output ++ ++ucl/by-unid//ep0/UnifySwitchColor/Attributes/ColdWhite/Desired { "value": } ++ucl/by-unid//ep0/UnifySwitchColor/Attributes/ColdWhite/Reported { "value": } ++ ++``` ++ ++

++ ++\subsection unify_switch_color_attr_red UnifySwitchColor/Red Attribute ++ ++**MQTT Topic Pattern:** ++ ++``` ++[PREFIX]/UnifySwitchColor/Attributes/Red/Reported ++[PREFIX]/UnifySwitchColor/Attributes/Red/Desired ++``` ++ ++**MQTT Payload JSON Schema:** ++ ++```json ++{ ++ "$schema": "http://json-schema.org/draft-07/schema#", ++ "title": "UnifySwitchColor Cluster Red Attribute Properties", ++ "type": "object", ++ "properties": { ++ "value": { ++ "type": "integer" ++ } ++ }, ++ "required": [ ++ "value" ++ ] ++} ++``` ++ ++ ++**Example Mosquitto CLI Tool Usage** ++ ++To see desired/reported value for Red attribute under the by-unid topic space: ++ ++```console ++mosquitto_sub -t 'ucl/by-unid/+/+/UnifySwitchColor/Attributes/Red/+' ++ ++# Example output ++ ++ucl/by-unid//ep0/UnifySwitchColor/Attributes/Red/Desired { "value": } ++ucl/by-unid//ep0/UnifySwitchColor/Attributes/Red/Reported { "value": } ++ ++``` ++ ++

++ ++\subsection unify_switch_color_attr_green UnifySwitchColor/Green Attribute ++ ++**MQTT Topic Pattern:** ++ ++``` ++[PREFIX]/UnifySwitchColor/Attributes/Green/Reported ++[PREFIX]/UnifySwitchColor/Attributes/Green/Desired ++``` ++ ++**MQTT Payload JSON Schema:** ++ ++```json ++{ ++ "$schema": "http://json-schema.org/draft-07/schema#", ++ "title": "UnifySwitchColor Cluster Green Attribute Properties", ++ "type": "object", ++ "properties": { ++ "value": { ++ "type": "integer" ++ } ++ }, ++ "required": [ ++ "value" ++ ] ++} ++``` ++ ++ ++**Example Mosquitto CLI Tool Usage** ++ ++To see desired/reported value for Green attribute under the by-unid topic space: ++ ++```console ++mosquitto_sub -t 'ucl/by-unid/+/+/UnifySwitchColor/Attributes/Green/+' ++ ++# Example output ++ ++ucl/by-unid//ep0/UnifySwitchColor/Attributes/Green/Desired { "value": } ++ucl/by-unid//ep0/UnifySwitchColor/Attributes/Green/Reported { "value": } ++ ++``` ++ ++

++ ++\subsection unify_switch_color_attr_blue UnifySwitchColor/Blue Attribute ++ ++**MQTT Topic Pattern:** ++ ++``` ++[PREFIX]/UnifySwitchColor/Attributes/Blue/Reported ++[PREFIX]/UnifySwitchColor/Attributes/Blue/Desired ++``` ++ ++**MQTT Payload JSON Schema:** ++ ++```json ++{ ++ "$schema": "http://json-schema.org/draft-07/schema#", ++ "title": "UnifySwitchColor Cluster Blue Attribute Properties", ++ "type": "object", ++ "properties": { ++ "value": { ++ "type": "integer" ++ } ++ }, ++ "required": [ ++ "value" ++ ] ++} ++``` ++ ++ ++**Example Mosquitto CLI Tool Usage** ++ ++To see desired/reported value for Blue attribute under the by-unid topic space: ++ ++```console ++mosquitto_sub -t 'ucl/by-unid/+/+/UnifySwitchColor/Attributes/Blue/+' ++ ++# Example output ++ ++ucl/by-unid//ep0/UnifySwitchColor/Attributes/Blue/Desired { "value": } ++ucl/by-unid//ep0/UnifySwitchColor/Attributes/Blue/Reported { "value": } ++ ++``` ++ ++

++ ++\subsection unify_switch_color_attr_amber UnifySwitchColor/Amber Attribute ++ ++**MQTT Topic Pattern:** ++ ++``` ++[PREFIX]/UnifySwitchColor/Attributes/Amber/Reported ++[PREFIX]/UnifySwitchColor/Attributes/Amber/Desired ++``` ++ ++**MQTT Payload JSON Schema:** ++ ++```json ++{ ++ "$schema": "http://json-schema.org/draft-07/schema#", ++ "title": "UnifySwitchColor Cluster Amber Attribute Properties", ++ "type": "object", ++ "properties": { ++ "value": { ++ "type": "integer" ++ } ++ }, ++ "required": [ ++ "value" ++ ] ++} ++``` ++ ++ ++**Example Mosquitto CLI Tool Usage** ++ ++To see desired/reported value for Amber attribute under the by-unid topic space: ++ ++```console ++mosquitto_sub -t 'ucl/by-unid/+/+/UnifySwitchColor/Attributes/Amber/+' ++ ++# Example output ++ ++ucl/by-unid//ep0/UnifySwitchColor/Attributes/Amber/Desired { "value": } ++ucl/by-unid//ep0/UnifySwitchColor/Attributes/Amber/Reported { "value": } ++ ++``` ++ ++

++ ++\subsection unify_switch_color_attr_cyan UnifySwitchColor/Cyan Attribute ++ ++**MQTT Topic Pattern:** ++ ++``` ++[PREFIX]/UnifySwitchColor/Attributes/Cyan/Reported ++[PREFIX]/UnifySwitchColor/Attributes/Cyan/Desired ++``` ++ ++**MQTT Payload JSON Schema:** ++ ++```json ++{ ++ "$schema": "http://json-schema.org/draft-07/schema#", ++ "title": "UnifySwitchColor Cluster Cyan Attribute Properties", ++ "type": "object", ++ "properties": { ++ "value": { ++ "type": "integer" ++ } ++ }, ++ "required": [ ++ "value" ++ ] ++} ++``` ++ ++ ++**Example Mosquitto CLI Tool Usage** ++ ++To see desired/reported value for Cyan attribute under the by-unid topic space: ++ ++```console ++mosquitto_sub -t 'ucl/by-unid/+/+/UnifySwitchColor/Attributes/Cyan/+' ++ ++# Example output ++ ++ucl/by-unid//ep0/UnifySwitchColor/Attributes/Cyan/Desired { "value": } ++ucl/by-unid//ep0/UnifySwitchColor/Attributes/Cyan/Reported { "value": } ++ ++``` ++ ++

++ ++\subsection unify_switch_color_attr_purple UnifySwitchColor/Purple Attribute ++ ++**MQTT Topic Pattern:** ++ ++``` ++[PREFIX]/UnifySwitchColor/Attributes/Purple/Reported ++[PREFIX]/UnifySwitchColor/Attributes/Purple/Desired ++``` ++ ++**MQTT Payload JSON Schema:** ++ ++```json ++{ ++ "$schema": "http://json-schema.org/draft-07/schema#", ++ "title": "UnifySwitchColor Cluster Purple Attribute Properties", ++ "type": "object", ++ "properties": { ++ "value": { ++ "type": "integer" ++ } ++ }, ++ "required": [ ++ "value" ++ ] ++} ++``` ++ ++ ++**Example Mosquitto CLI Tool Usage** ++ ++To see desired/reported value for Purple attribute under the by-unid topic space: ++ ++```console ++mosquitto_sub -t 'ucl/by-unid/+/+/UnifySwitchColor/Attributes/Purple/+' ++ ++# Example output ++ ++ucl/by-unid//ep0/UnifySwitchColor/Attributes/Purple/Desired { "value": } ++ucl/by-unid//ep0/UnifySwitchColor/Attributes/Purple/Reported { "value": } ++ ++``` ++ ++

++ ++ ++\subsection unify_switch_color_attr_cluster_revision UnifySwitchColor/ClusterRevision Attribute ++ ++**MQTT Topic Pattern:** ++ ++``` ++[PREFIX]/UnifySwitchColor/Attributes/ClusterRevision/Reported ++[PREFIX]/UnifySwitchColor/Attributes/ClusterRevision/Desired ++``` ++ ++**MQTT Payload JSON Schema:** ++ ++```json ++{ ++ "$schema": "http://json-schema.org/draft-07/schema#", ++ "title": "UnifySwitchColor Cluster ClusterRevision Attribute Properties", ++ "type": "object", ++ "properties": { ++ "value": { ++ "type": "integer" ++ } ++ }, ++ "required": [ ++ "value" ++ ] ++} ++``` ++ ++**Example Mosquitto CLI Tool Usage** ++ ++To see desired/reported value for ClusterRevision attribute under the by-unid topic space: ++ ++```console ++mosquitto_sub -t 'ucl/by-unid///UnifySwitchColor/Attributes/ClusterRevision/+' ++# Example output ++ucl/by-unid///UnifySwitchColor/Attributes/ClusterRevision/Desired { "value": } ++ucl/by-unid///UnifySwitchColor/Attributes/ClusterRevision/Reported { "value": } ++``` ++ ++ ++ ++ ++ ++

++ ++ ++ ++ ++\section unify_switch_color_recv_cmd_support UnifySwitchColor Command Support ++ ++**MQTT Topic Pattern:** ++ ++``` ++[PREFIX]/UnifySwitchColor/SupportedCommands ++[PREFIX]/UnifySwitchColor/SupportedGeneratedCommands ++``` ++ ++**MQTT Payload JSON Schema:** ++ ++```json ++{ ++ "$schema": "http://json-schema.org/draft-07/schema#", ++ "title": "UnifySwitchColor Command Support Properties", ++ "type": "object", ++ "properties": { ++ "value": { ++ "type": "array", ++ "items" : { ++ "type": "string", ++ "enum": [ ++ "SetColor", ++ "StartStopChange", ++ "WriteAttributes", ++ "ForceReadAttributes" ++ ] ++ } ++ } ++ } ++ }, ++ "required": [ ++ "value" ++ ] ++} ++``` ++ ++**Example Mosquitto CLI Tool Usage** ++ ++To see supported commands for UnifySwitchColor cluster under the by-unid topic space: ++ ++```console ++mosquitto_sub -t 'ucl/by-unid///UnifySwitchColor/SupportedCommands' ++# Example output ++ucl/by-unid///UnifySwitchColor/SupportedCommands { "value": ["SetColor","StartStopChange","WriteAttributes", "ForceReadAttributes"] } ++``` ++ ++To see supported generated commands for UnifySwitchColor cluster under the by-unid topic space: ++ ++```console ++mosquitto_sub -t 'ucl/by-unid///UnifySwitchColor/SupportedGeneratedCommands' ++# Example output ++ucl/by-unid///UnifySwitchColor/SupportedGeneratedCommands { "value": [] } ++``` ++ ++ ++ ++ ++ ++

++ ++ ++ ++ ++\section unify_switch_color_cmds UnifySwitchColor Commands ++ ++

++ ++\subsection unify_switch_color_set_color_cmd UnifySwitchColor/SetColor Command ++ ++**MQTT Topic Pattern:** ++ ++``` ++[PREFIX]/UnifySwitchColor/Commands/SetColor ++[PREFIX]/UnifySwitchColor/GeneratedCommands/SetColor ++``` ++ ++**MQTT Payload JSON Schema:** ++ ++```json ++{ ++ "$schema": "http://json-schema.org/draft-07/schema#", ++ "title": "UnifySwitchColor Cluster SetColor Command Properties", ++ "type": "object", ++ "properties": { ++ "ColorComponentId": { ++ "type": "integer" ++ }, ++ "Value": { ++ "type": "integer" ++ }, ++ "Duration": { ++ "type": "integer" ++ } ++ }, ++ "required": [ ++ "ColorComponentId", ++ "Value", ++ "Duration" ++ ] ++} ++``` ++ ++**Example Mosquitto CLI Tool Usage** ++ ++To send a UnifySwitchColor/SetColor command under the by-unid topic space: ++ ++```console ++mosquitto_pub -t 'ucl/by-unid///UnifySwitchColor/Commands/SetColor' -m '{ "ColorComponentId": ,"Value": ,"Duration": }' ++``` ++ ++To receive a UnifySwitchColor/SetColor generated command from a UNID/endpoint: ++ ++```console ++mosquitto_sub -t 'ucl/by-unid///UnifySwitchColor/GeneratedCommands/SetColor' ++``` ++ ++

++ ++\subsection unify_switch_color_start_stop_change_cmd UnifySwitchColor/StartStopChange Command ++ ++**MQTT Topic Pattern:** ++ ++``` ++[PREFIX]/UnifySwitchColor/Commands/StartStopChange ++[PREFIX]/UnifySwitchColor/GeneratedCommands/StartStopChange ++``` ++ ++**MQTT Payload JSON Schema:** ++ ++```json ++{ ++ "$schema": "http://json-schema.org/draft-07/schema#", ++ "title": "UnifySwitchColor Cluster StartStopChange Command Properties", ++ "type": "object", ++ "properties": { ++ "StartStop": { ++ "type": "boolean" ++ }, ++ "UpDown": { ++ "type": "boolean" ++ }, ++ "IgnorStartLevel": { ++ "type": "boolean" ++ }, ++ "ColorComponentId": { ++ "type": "integer" ++ }, ++ "StartLevel": { ++ "type": "integer" ++ }, ++ "Duration": { ++ "type": "integer" ++ } ++ }, ++ "required": [ ++ "StartStop", ++ "UpDown", ++ "IgnorStartLevel", ++ "ColorComponentId", ++ "StartLevel", ++ "Duration" ++ ] ++} ++``` ++ ++**Example Mosquitto CLI Tool Usage** ++ ++To send a UnifySwitchColor/StartStopChange command under the by-unid topic space: ++ ++```console ++mosquitto_pub -t 'ucl/by-unid///UnifySwitchColor/Commands/StartStopChange' -m '{ "StartStop": ,"UpDown": ,"IgnorStartLevel": ,"ColorComponentId": ,"StartLevel": ,"Duration": }' ++``` ++ ++To receive a UnifySwitchColor/StartStopChange generated command from a UNID/endpoint: ++ ++```console ++mosquitto_sub -t 'ucl/by-unid///UnifySwitchColor/GeneratedCommands/StartStopChange' ++``` ++ ++

++ ++\subsection unify_switch_color_write_attr_cmd UnifySwitchColor/WriteAttributes Command ++ ++**MQTT Topic Pattern:** ++ ++``` ++[PREFIX]/UnifySwitchColor/Commands/WriteAttributes ++``` ++ ++**MQTT Payload JSON Schema:** ++ ++```json ++{ ++ "$schema": "http://json-schema.org/draft-07/schema#", ++ "title": "UnifySwitchColor Cluster WriteAttributes Command Properties", ++ "type": "object", ++ "properties": { ++ }, ++ "required": [ ++ "value" ++ ] ++} ++``` ++ ++**Example Mosquitto CLI Tool Usage** ++ ++To update all UnifySwitchColor attributes under the by-unid topic space: ++ ++```console ++mosquitto_pub -t 'ucl/by-unid///UnifySwitchColor/Commands/WriteAttributes' -m '{ }' ++``` ++ ++> NOTE: Specify only the list of attributes to write in this command. ++> Unspecified attributes will not be updated. ++ ++

++ ++\subsection unify_switch_color_force_read_attr_cmd UnifySwitchColor/ForceReadAttributes Command ++ ++**MQTT Topic Pattern:** ++ ++``` ++[PREFIX]/UnifySwitchColor/Commands/ForceReadAttributes ++``` ++ ++**MQTT Payload JSON Schema:** ++ ++```json ++{ ++ "$schema": "http://json-schema.org/draft-07/schema#", ++ "title": "UnifySwitchColor Cluster ForceReadAttributes Command Properties", ++ "type": "object", ++ "properties": { ++ "value": { ++ "type": "array" ++ "items": { ++ "type": "string", ++ "enum": [ ++ "WarmWhite", ++ "ColdWhite", ++ "Red", ++ "Green", ++ "Blue", ++ "Amber", ++ "Cyan", ++ "Purple" ++ ] ++ } ++ } ++ }, ++ "required": [ ++ "value" ++ ] ++} ++``` ++ ++**Example Mosquitto CLI Tool Usage** ++ ++To force read all UnifySwitchColor attributes under the by-unid topic space (by sending an empty array): ++ ++```console ++mosquitto_pub -t 'ucl/by-unid///UnifySwitchColor/Commands/ForceReadAttributes' -m '{ "value": [] }' ++``` ++ ++To force read one of the UnifySwitchColor attributes under the by-unid topic space: ++ ++```console ++mosquitto_pub -t 'ucl/by-unid///UnifySwitchColor/Commands/ForceReadAttributes' -m '{ "value": ["WarmWhite"] }' ++``` ++ ++ ++ ++ ++ + +


+ +diff --git a/components/uic_dotdot/zap-generated/src/dotdot_attribute_id_definitions.c b/components/uic_dotdot/zap-generated/src/dotdot_attribute_id_definitions.c +index 372b67422a..500dd55f11 100644 +--- a/components/uic_dotdot/zap-generated/src/dotdot_attribute_id_definitions.c ++++ b/components/uic_dotdot/zap-generated/src/dotdot_attribute_id_definitions.c +@@ -2127,6 +2127,31 @@ const char *uic_dotdot_get_attribute_name(dotdot_cluster_id_t cluster_id, + return "Unknown"; + } + // clang-format off ++ case DOTDOT_UNIFY_SWITCH_COLOR_CLUSTER_ID: ++ // clang-format on ++ switch (attribute_id) { ++ // clang-format off ++ case DOTDOT_UNIFY_SWITCH_COLOR_WARM_WHITE_ATTRIBUTE_ID: ++ return "WarmWhite"; ++ case DOTDOT_UNIFY_SWITCH_COLOR_COLD_WHITE_ATTRIBUTE_ID: ++ return "ColdWhite"; ++ case DOTDOT_UNIFY_SWITCH_COLOR_RED_ATTRIBUTE_ID: ++ return "Red"; ++ case DOTDOT_UNIFY_SWITCH_COLOR_GREEN_ATTRIBUTE_ID: ++ return "Green"; ++ case DOTDOT_UNIFY_SWITCH_COLOR_BLUE_ATTRIBUTE_ID: ++ return "Blue"; ++ case DOTDOT_UNIFY_SWITCH_COLOR_AMBER_ATTRIBUTE_ID: ++ return "Amber"; ++ case DOTDOT_UNIFY_SWITCH_COLOR_CYAN_ATTRIBUTE_ID: ++ return "Cyan"; ++ case DOTDOT_UNIFY_SWITCH_COLOR_PURPLE_ATTRIBUTE_ID: ++ return "Purple"; ++ // clang-format on ++ default: ++ return "Unknown"; ++ } ++ // clang-format off + // clang-format on + default: + return "Unknown"; +@@ -4618,6 +4643,32 @@ dotdot_attribute_id_t + return DOTDOT_UNIFY_HUMIDITY_CONTROL_AUTO_SETPOINT_PRECISION_ATTRIBUTE_ID; + } + break; ++ case DOTDOT_UNIFY_SWITCH_COLOR_CLUSTER_ID: ++ if (strcmp ("WarmWhite", attribute_name) == 0) { ++ return DOTDOT_UNIFY_SWITCH_COLOR_WARM_WHITE_ATTRIBUTE_ID; ++ } ++ if (strcmp ("ColdWhite", attribute_name) == 0) { ++ return DOTDOT_UNIFY_SWITCH_COLOR_COLD_WHITE_ATTRIBUTE_ID; ++ } ++ if (strcmp ("Red", attribute_name) == 0) { ++ return DOTDOT_UNIFY_SWITCH_COLOR_RED_ATTRIBUTE_ID; ++ } ++ if (strcmp ("Green", attribute_name) == 0) { ++ return DOTDOT_UNIFY_SWITCH_COLOR_GREEN_ATTRIBUTE_ID; ++ } ++ if (strcmp ("Blue", attribute_name) == 0) { ++ return DOTDOT_UNIFY_SWITCH_COLOR_BLUE_ATTRIBUTE_ID; ++ } ++ if (strcmp ("Amber", attribute_name) == 0) { ++ return DOTDOT_UNIFY_SWITCH_COLOR_AMBER_ATTRIBUTE_ID; ++ } ++ if (strcmp ("Cyan", attribute_name) == 0) { ++ return DOTDOT_UNIFY_SWITCH_COLOR_CYAN_ATTRIBUTE_ID; ++ } ++ if (strcmp ("Purple", attribute_name) == 0) { ++ return DOTDOT_UNIFY_SWITCH_COLOR_PURPLE_ATTRIBUTE_ID; ++ } ++ break; + default: + return DOTDOT_INVALID_ATTRIBUTE_ID; + } +@@ -6737,6 +6788,31 @@ dotdot_attribute_json_type_t + return JSON_TYPE_UNKNOWN; + } + // clang-format off ++ case DOTDOT_UNIFY_SWITCH_COLOR_CLUSTER_ID: ++ // clang-format on ++ switch (attribute_id) { ++ // clang-format off ++ case DOTDOT_UNIFY_SWITCH_COLOR_WARM_WHITE_ATTRIBUTE_ID: ++ return JSON_TYPE_NUMBER; ++ case DOTDOT_UNIFY_SWITCH_COLOR_COLD_WHITE_ATTRIBUTE_ID: ++ return JSON_TYPE_NUMBER; ++ case DOTDOT_UNIFY_SWITCH_COLOR_RED_ATTRIBUTE_ID: ++ return JSON_TYPE_NUMBER; ++ case DOTDOT_UNIFY_SWITCH_COLOR_GREEN_ATTRIBUTE_ID: ++ return JSON_TYPE_NUMBER; ++ case DOTDOT_UNIFY_SWITCH_COLOR_BLUE_ATTRIBUTE_ID: ++ return JSON_TYPE_NUMBER; ++ case DOTDOT_UNIFY_SWITCH_COLOR_AMBER_ATTRIBUTE_ID: ++ return JSON_TYPE_NUMBER; ++ case DOTDOT_UNIFY_SWITCH_COLOR_CYAN_ATTRIBUTE_ID: ++ return JSON_TYPE_NUMBER; ++ case DOTDOT_UNIFY_SWITCH_COLOR_PURPLE_ATTRIBUTE_ID: ++ return JSON_TYPE_NUMBER; ++ // clang-format on ++ default: ++ return JSON_TYPE_UNKNOWN; ++ } ++ // clang-format off + // clang-format on + default: + return JSON_TYPE_UNKNOWN; +@@ -7103,5 +7179,8 @@ bool uic_dotdot_attribute_is_enum(dotdot_cluster_id_t cluster_id, + } + } + ++ if (65441 == cluster_id) { ++ } ++ + return false; + } +diff --git a/components/uic_dotdot/zap-generated/src/dotdot_cluster_id_definitions.c b/components/uic_dotdot/zap-generated/src/dotdot_cluster_id_definitions.c +index a5c8e4d09b..48d521edc8 100644 +--- a/components/uic_dotdot/zap-generated/src/dotdot_cluster_id_definitions.c ++++ b/components/uic_dotdot/zap-generated/src/dotdot_cluster_id_definitions.c +@@ -136,6 +136,8 @@ const char* uic_dotdot_get_cluster_name(dotdot_cluster_id_t cluster_id) { + return "UnifyThermostat"; + case DOTDOT_UNIFY_HUMIDITY_CONTROL_CLUSTER_ID: + return "UnifyHumidityControl"; ++ case DOTDOT_UNIFY_SWITCH_COLOR_CLUSTER_ID: ++ return "UnifySwitchColor"; + default: + return "Unknown"; + } +@@ -319,6 +321,9 @@ dotdot_cluster_id_t uic_dotdot_get_cluster_id(const char* cluster_name) { + if (strcmp ("UnifyHumidityControl", cluster_name) == 0) { + return DOTDOT_UNIFY_HUMIDITY_CONTROL_CLUSTER_ID; + } ++ if (strcmp ("UnifySwitchColor", cluster_name) == 0) { ++ return DOTDOT_UNIFY_SWITCH_COLOR_CLUSTER_ID; ++ } + + // Return an invalid ID if we did not get any match. + return DOTDOT_INVALID_CLUSTER_ID; +-- +2.39.5 + From e11122db127a434530308594056653fab4e5f6b6 Mon Sep 17 00:00:00 2001 From: Viet Date: Wed, 4 Sep 2024 16:01:55 +0700 Subject: [PATCH 04/10] UIC-3272: Switch Color Command Class Cpp UIC-3272: Fix mismatch attribute size Due to legacy reason some attributes are stored as uint32_t while being single byte (uint8_t). This cause issue with the C++ API and those attribute needs to manually set a raw bytes. UIC-3272: fixed issue with types value Origin: https://github.com/SiliconLabsSoftware/z-wave-protocol-controller/pull/146 Signed-off-by: Philippe Coval --- .../attribute_store_defined_attribute_types.h | 25 + .../zwave_command_class_color_switch_types.h | 12 + .../zpc_attribute_store_type_registration.cpp | 5 + .../zwave_command_classes/CMakeLists.txt | 2 +- .../src/zwave_command_class_switch_color.c | 269 ------- .../src/zwave_command_class_switch_color.cpp | 690 ++++++++++++++++ .../src/zwave_command_class_switch_color.h | 69 +- .../zwave_command_classes/test/CMakeLists.txt | 7 +- .../zwave_command_class_switch_color_test.c | 262 ------ .../zwave_command_class_switch_color_test.cpp | 743 ++++++++++++++++++ 10 files changed, 1542 insertions(+), 542 deletions(-) delete mode 100644 applications/zpc/components/zwave_command_classes/src/zwave_command_class_switch_color.c create mode 100644 applications/zpc/components/zwave_command_classes/src/zwave_command_class_switch_color.cpp delete mode 100644 applications/zpc/components/zwave_command_classes/test/zwave_command_class_switch_color_test.c create mode 100644 applications/zpc/components/zwave_command_classes/test/zwave_command_class_switch_color_test.cpp diff --git a/applications/zpc/components/zpc_attribute_store/include/attribute_store_defined_attribute_types.h b/applications/zpc/components/zpc_attribute_store/include/attribute_store_defined_attribute_types.h index 3b084d146..28107fbd2 100644 --- a/applications/zpc/components/zpc_attribute_store/include/attribute_store_defined_attribute_types.h +++ b/applications/zpc/components/zpc_attribute_store/include/attribute_store_defined_attribute_types.h @@ -416,6 +416,31 @@ DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_DURATION, ((COMMAND_CLASS_SWITCH_COLOR << 8) | 0x6)) +///< This represents a Up/Down value in Color Switch Start Level Change Command +/// Located under ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STATE +DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_UP_DOWN, + ((COMMAND_CLASS_SWITCH_COLOR << 8) | 0x7)) + +///< This represents a Ignore Start Level in Color Switch Start Level Change Command +/// Located under ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STATE +DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_IGNORE_START_LEVEL, + ((COMMAND_CLASS_SWITCH_COLOR << 8) | 0x8)) + +///< This represents a Start Level in Color Switch Start Level Change Command +/// Located under ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STATE +DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_START_LEVEL, + ((COMMAND_CLASS_SWITCH_COLOR << 8) | 0x9)) + +///< This represents a Color Switch Start Level Change +/// Located under ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STATE +DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_START_CHANGE, + ((COMMAND_CLASS_SWITCH_COLOR << 8) | 0x0A)) + +///< This represents a Color Switch Stop Level Change +/// Located under ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STATE +DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STOP_CHANGE, + ((COMMAND_CLASS_SWITCH_COLOR << 8) | 0x0B)) + /////////////////////////////////// // Multilevel Sensor Command Class DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SENSOR_MULTILEVEL_VERSION, diff --git a/applications/zpc/components/zpc_attribute_store/include/command_class_types/zwave_command_class_color_switch_types.h b/applications/zpc/components/zpc_attribute_store/include/command_class_types/zwave_command_class_color_switch_types.h index fc85882ae..cdc4294a9 100644 --- a/applications/zpc/components/zpc_attribute_store/include/command_class_types/zwave_command_class_color_switch_types.h +++ b/applications/zpc/components/zpc_attribute_store/include/command_class_types/zwave_command_class_color_switch_types.h @@ -89,5 +89,17 @@ typedef uint8_t color_component_id_t; typedef uint32_t color_component_id_value_t; typedef uint32_t color_component_id_duration_t; +///> Color Component ID +typedef enum { + WARM_WHITE = 0, + COLD_WHITE = 1, + RED = 2, + GREEN = 3, + BLUE = 4, + AMBER = 5, + CYAN = 6, + PURPLE = 7 +} color_component_id_enum; + #endif //ZWAVE_COMMAND_CLASS_COLOR_SWITCH_TYPES_H /** @} end zwave_command_class_color_switch_types */ diff --git a/applications/zpc/components/zpc_attribute_store/src/zpc_attribute_store_type_registration.cpp b/applications/zpc/components/zpc_attribute_store/src/zpc_attribute_store_type_registration.cpp index 44bcf8f6f..ee8c49700 100644 --- a/applications/zpc/components/zpc_attribute_store/src/zpc_attribute_store_type_registration.cpp +++ b/applications/zpc/components/zpc_attribute_store/src/zpc_attribute_store_type_registration.cpp @@ -167,7 +167,12 @@ static const std::vector attribute_schema = { {ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STATE, "Color Switch State", ATTRIBUTE_ENDPOINT_ID, ENUM_STORAGE_TYPE}, {ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_COLOR_COMPONENT_ID, "Component ID", ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STATE, U8_STORAGE_TYPE}, {ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, "Value", ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_COLOR_COMPONENT_ID, U32_STORAGE_TYPE}, + {ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_START_CHANGE, "Color Start Level Change", ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_COLOR_COMPONENT_ID, U8_STORAGE_TYPE}, + {ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STOP_CHANGE, "Color Stop Level Change", ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_COLOR_COMPONENT_ID, U8_STORAGE_TYPE}, {ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_DURATION, "Duration", ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STATE, U32_STORAGE_TYPE}, + {ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_UP_DOWN, "Up Down", ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STATE, U8_STORAGE_TYPE}, + {ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_IGNORE_START_LEVEL, "Ignore Start Level", ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STATE, U8_STORAGE_TYPE}, + {ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_START_LEVEL, "Start Level", ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STATE, U8_STORAGE_TYPE}, ///////////////////////////////////////////////////////////////////// // Configuration Command Class attributes ///////////////////////////////////////////////////////////////////// diff --git a/applications/zpc/components/zwave_command_classes/CMakeLists.txt b/applications/zpc/components/zwave_command_classes/CMakeLists.txt index 63a2b2e8c..2d4e7fe81 100644 --- a/applications/zpc/components/zwave_command_classes/CMakeLists.txt +++ b/applications/zpc/components/zwave_command_classes/CMakeLists.txt @@ -46,7 +46,7 @@ add_library( src/zwave_command_class_supervision.c src/zwave_command_class_supervision_process.cpp src/zwave_command_class_sound_switch.c - src/zwave_command_class_switch_color.c + src/zwave_command_class_switch_color.cpp src/zwave_command_class_switch_multilevel.c src/zwave_command_class_thermostat_mode.c src/zwave_command_class_thermostat_fan_mode.c diff --git a/applications/zpc/components/zwave_command_classes/src/zwave_command_class_switch_color.c b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_switch_color.c deleted file mode 100644 index 649307245..000000000 --- a/applications/zpc/components/zwave_command_classes/src/zwave_command_class_switch_color.c +++ /dev/null @@ -1,269 +0,0 @@ -/****************************************************************************** - * # License - * Copyright 2022 Silicon Laboratories Inc. www.silabs.com - ****************************************************************************** - * The licensor of this software is Silicon Laboratories Inc. Your use of this - * software is governed by the terms of Silicon Labs Master Software License - * Agreement (MSLA) available at - * www.silabs.com/about-us/legal/master-software-license-agreement. This - * software is distributed to you in Source Code format and is governed by the - * sections of the MSLA applicable to Source Code. - * - *****************************************************************************/ -#include "zwave_command_class_switch_color.h" - -// Interfaces -#include "zwave_command_class_color_switch_types.h" -#include "zwave_command_class_generic_types.h" - -// Includes from other ZPC Components -#include "zwave_command_class_indices.h" -#include "zwave_unid.h" -#include "zwave_command_handler.h" -#include "zpc_attribute_store_network_helper.h" -#include "attribute_store_defined_attribute_types.h" -#include "ZW_classcmd.h" -#include "zpc_attribute_resolver.h" -#include "zwave_command_classes_utils.h" - -// Includes from other Unify Components -#include "dotdot_mqtt.h" -#include "dotdot_mqtt_generated_commands.h" -#include "attribute_store_helper.h" -#include "attribute_resolver.h" -#include "attribute_transitions.h" -#include "attribute_timeouts.h" -#include "sl_log.h" - -#define LOG_TAG "zwave_command_class_switch_color" - -static void set_duration(attribute_store_node_t state_node, - attribute_store_node_value_state_t state, - uint32_t duration) -{ - attribute_store_node_t duration_node - = attribute_store_get_first_child_by_type( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_DURATION); - - attribute_store_set_node_attribute_value(duration_node, - state, - (uint8_t *)&duration, - sizeof(duration)); -} - -[[maybe_unused]] -static void - set_all_color_switch_durations(attribute_store_node_t state_node, - attribute_store_node_value_state_t value_state, - color_component_id_duration_t duration) -{ - uint32_t index = 0; - attribute_store_node_t component_node - = attribute_store_get_first_child_by_type( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_COLOR_COMPONENT_ID); - while (component_node != ATTRIBUTE_STORE_INVALID_NODE) { - index += 1; - - set_duration(component_node, value_state, duration); - - component_node = attribute_store_get_node_child_by_type( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_COLOR_COMPONENT_ID, - index); - } -} - -static void switch_color_undefine_reported(attribute_store_node_t state_node) -{ - zwave_command_class_switch_color_invoke_on_all_attributes_with_return_value( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, - attribute_stop_transition); - - attribute_store_node_t duration_node - = attribute_store_get_first_child_by_type( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_DURATION); - color_component_id_duration_t duration = 0; - attribute_store_undefine_desired(duration_node); - attribute_store_set_reported(duration_node, - &duration, - sizeof(duration)); - - sl_log_debug(LOG_TAG, "Transition time expired, probe color"); - zwave_command_class_switch_color_invoke_on_all_attributes( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, - attribute_store_undefine_desired); - zwave_command_class_switch_color_invoke_on_all_attributes( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, - attribute_store_undefine_reported); -} - -// FIXME: UIC-1901 This function belongs to zwave_command_class_switch_color.rs, but this -// component really cannot interact with the attribute resolver. -static void - on_color_switch_state_send_data_complete(attribute_store_node_t state_node, - resolver_rule_type_t rule_type, - zpc_resolver_event_t event) -{ - if (rule_type == RESOLVER_GET_RULE) { - sl_log_error("zwave_command_class_switch_color_control", - "Received a Get Rule type callback for State node %d " - "whereas no Get rule is registered. Something is broken."); - return; - } - - attribute_store_node_t duration_node - = attribute_store_get_first_child_by_type( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_DURATION); - - color_component_id_duration_t duration = 0; - attribute_store_get_desired(duration_node, - &duration, - sizeof(duration)); - - clock_time_t zwave_desired_duration - = zwave_duration_to_time((uint8_t)duration); - - switch (event) { - case FRAME_SENT_EVENT_OK_SUPERVISION_WORKING: - attribute_store_set_reported_as_desired(duration_node); - break; - - case FRAME_SENT_EVENT_OK_SUPERVISION_SUCCESS: - zwave_command_class_switch_color_invoke_on_all_attributes_with_return_value( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, - &attribute_store_set_reported_as_desired); - zwave_command_class_switch_color_invoke_on_all_attributes( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, - &attribute_store_undefine_desired); - set_duration(state_node, REPORTED_ATTRIBUTE, 0); - attribute_store_undefine_desired(duration_node); - break; - - case FRAME_SENT_EVENT_OK_NO_SUPERVISION: - zwave_command_class_switch_color_invoke_on_all_attributes_with_return_value( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, - attribute_stop_transition); - if(zwave_desired_duration > 0) { - // Should we estimate reported color values during transition - // and publish them as reported, like we did for level cluster? - - zwave_command_class_switch_color_invoke_on_all_attributes( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, - attribute_store_undefine_desired); - - attribute_store_set_reported_as_desired(duration_node); - attribute_store_undefine_desired(duration_node); - - // Probe again after this duration - attribute_timeout_set_callback(state_node, - zwave_desired_duration + PROBE_BACK_OFF, - &switch_color_undefine_reported); - } else { - zwave_command_class_switch_color_invoke_on_all_attributes( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, - attribute_store_undefine_desired); - zwave_command_class_switch_color_invoke_on_all_attributes( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, - attribute_store_undefine_reported); - attribute_store_undefine_desired(duration_node); - } - break; - - // FRAME_SENT_EVENT_OK_SUPERVISION_NO_SUPPORT: - // FRAME_SENT_EVENT_OK_SUPERVISION_FAIL: - default: - zwave_command_class_switch_color_invoke_on_all_attributes_with_return_value( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, - &attribute_stop_transition); - zwave_command_class_switch_color_invoke_on_all_attributes( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, - &attribute_store_undefine_desired); - zwave_command_class_switch_color_invoke_on_all_attributes( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, - &attribute_store_undefine_reported); - attribute_store_undefine_desired(duration_node); - attribute_store_undefine_reported(duration_node); - break; - } - - command_status_values_t state = FINAL_STATE; - attribute_store_set_reported(state_node, &state, sizeof(state)); - attribute_store_set_desired(state_node, &state, sizeof(state)); -} - -/////////////////////////////////////////////////////////////////////////////// -// Public interface functions -/////////////////////////////////////////////////////////////////////////////// -sl_status_t zwave_command_class_switch_color_init() -{ - // FIXME: UIC-1901 - register_send_event_handler(ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STATE, - &on_color_switch_state_send_data_complete); - - // zwave_command_handler_t is registered using rust, see zwave_command_class_switch_color.rs - return SL_STATUS_OK; -} - -void zwave_command_class_switch_color_invoke_on_all_attributes( - attribute_store_node_t state_node, - attribute_store_type_t child_node_type, - void (*function)(attribute_store_node_t)) -{ - uint32_t index = 0; - attribute_store_node_t component_node - = attribute_store_get_first_child_by_type( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_COLOR_COMPONENT_ID); - while (component_node != ATTRIBUTE_STORE_INVALID_NODE) { - index += 1; - attribute_store_node_t child_node - = attribute_store_get_first_child_by_type(component_node, - child_node_type); - - function(child_node); - component_node = attribute_store_get_node_child_by_type( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_COLOR_COMPONENT_ID, - index); - } -} - -void zwave_command_class_switch_color_invoke_on_all_attributes_with_return_value( - attribute_store_node_t state_node, - attribute_store_type_t child_node_type, - sl_status_t (*function)(attribute_store_node_t)) -{ - uint32_t index = 0; - attribute_store_node_t component_node - = attribute_store_get_first_child_by_type( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_COLOR_COMPONENT_ID); - while (component_node != ATTRIBUTE_STORE_INVALID_NODE) { - index += 1; - attribute_store_node_t child_node - = attribute_store_get_first_child_by_type(component_node, - child_node_type); - - function(child_node); - component_node = attribute_store_get_node_child_by_type( - state_node, - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_COLOR_COMPONENT_ID, - index); - } -} diff --git a/applications/zpc/components/zwave_command_classes/src/zwave_command_class_switch_color.cpp b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_switch_color.cpp new file mode 100644 index 000000000..3c8df24d4 --- /dev/null +++ b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_switch_color.cpp @@ -0,0 +1,690 @@ +/****************************************************************************** + * # License + * Copyright 2024 Silicon Laboratories Inc. www.silabs.com + ****************************************************************************** + * The licensor of this software is Silicon Laboratories Inc. Your use of this + * software is governed by the terms of Silicon Labs Master Software License + * Agreement (MSLA) available at + * www.silabs.com/about-us/legal/master-software-license-agreement. This + * software is distributed to you in Source Code format and is governed by the + * sections of the MSLA applicable to Source Code. + * + *****************************************************************************/ +// Includes from this component +#include "zwave_command_class_switch_color.h" +#include "zwave_command_classes_utils.h" + +// Generic includes +#include +#include + +// Includes from other ZPC Components +#include "zwave_command_class_indices.h" +#include "zwave_command_handler.h" +#include "zpc_attribute_store_network_helper.h" +#include "attribute_store_defined_attribute_types.h" +#include "ZW_classcmd.h" +#include "zpc_attribute_resolver.h" + +// Includes from other Unify Components +#include "dotdot_mqtt.h" +#include "dotdot_mqtt_generated_commands.h" +#include "attribute_store_helper.h" +#include "attribute_resolver.h" +#include "attribute_timeouts.h" +#include "sl_log.h" + +// Cpp include +#include "attribute.hpp" +#include "zwave_frame_generator.hpp" +#include "zwave_frame_parser.hpp" + +// Interfaces +#include "zwave_command_class_color_switch_types.h" + +// Attribute macro, shortening those long defines for attribute types: +#define ATTRIBUTE(type) ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_##type + +// Max component ID color supported +constexpr uint8_t MAX_SUPPORTED_COLOR_COMPONENT = 9; + +// Index of obsoleted component ID +constexpr uint8_t COMPONENT_ID_INDEXED_COLOR = 8; + +// Define initial state of attribute +constexpr uint8_t INITIAL_STATE = 0; + +// Log tag +constexpr char LOG_TAG[] = "zwave_command_class_switch_color"; + +namespace +{ +zwave_frame_generator frame_generator(COMMAND_CLASS_SWITCH_COLOR); +} + +/////////////////////////////////////////////////////////////////////////////// +// Helper functions +/////////////////////////////////////////////////////////////////////////////// +zwave_cc_version_t get_current_switch_color_version(attribute_store_node_t node) +{ + zwave_cc_version_t version + = zwave_command_class_get_version_from_node(node, + COMMAND_CLASS_SWITCH_COLOR); + + if (version == 0) { + sl_log_error(LOG_TAG, "Switch_color Command Class Version not found"); + } + + return version; +} + +/////////////////////////////////////////////////////////////////////////////// +// Validation function +/////////////////////////////////////////////////////////////////////////////// +bool zwave_command_class_switch_color_validate_value(uint8_t value) +{ + return (value >= 0x00 && value <= 0xFF); +} + +/////////////////////////////////////////////////////////////////////////////// +// Resolution functions +/////////////////////////////////////////////////////////////////////////////// +static sl_status_t zwave_command_class_switch_color_supported_get( + attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length) +{ + return frame_generator.generate_no_args_frame(SWITCH_COLOR_SUPPORTED_GET, + frame, + frame_length); +} + +static sl_status_t zwave_command_class_switch_color_get( + attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length) +{ + sl_log_debug(LOG_TAG, "Switch Color Get"); + try { + attribute_store::attribute value_node(node); + assert(value_node.is_valid() && value_node.type() == ATTRIBUTE(VALUE)); + + // Compute expected size for set frame + const uint8_t expected_frame_size = sizeof(ZW_SWITCH_COLOR_GET_FRAME); + + // Creating the frame + frame_generator.initialize_frame(SWITCH_COLOR_GET, + frame, + expected_frame_size); + + auto component_id_node + = value_node.first_parent(ATTRIBUTE(COLOR_COMPONENT_ID)); + // Add Color Component ID field to the frame + frame_generator.add_value(component_id_node, DESIRED_OR_REPORTED_ATTRIBUTE); + + frame_generator.validate_frame(frame_length); + } catch (const std::exception &e) { + sl_log_error(LOG_TAG, + "Error while generating Switch Color get frame : %s", + e.what()); + return SL_STATUS_FAIL; + } + + return SL_STATUS_OK; +} + +static sl_status_t zwave_command_class_switch_color_set( + attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length) +{ + sl_log_debug(LOG_TAG, "Switch Color Set"); + try { + attribute_store::attribute value_node(node); + assert(value_node.is_valid() && value_node.type() == ATTRIBUTE(VALUE)); + + auto current_version = get_current_switch_color_version(node); + + constexpr uint8_t ZWAVE_CC_HEADER_SIZE = 2; + + attribute_store::attribute state_node + = value_node.first_parent(ATTRIBUTE(STATE)); + //Get number of COLOR_COMPONENT_ID + auto supported_color_component_count + = state_node.children(ATTRIBUTE(COLOR_COMPONENT_ID)).size(); + + // Compute expected size for set frame + auto expected_frame_size + = ZWAVE_CC_HEADER_SIZE + supported_color_component_count * 2; + if (current_version >= 2) { + // V2 have color component count + duration size + expected_frame_size += 2; + } + + // Creating the frame + frame_generator.initialize_frame(SWITCH_COLOR_SET, + frame, + expected_frame_size); + + if (current_version >= 2) { + //Set Color Component Count in frame + frame_generator.add_raw_byte(supported_color_component_count); + } + + // Iterate on all color count + for (auto color_component_id_node: + state_node.children(ATTRIBUTE(COLOR_COMPONENT_ID))) { + // Set Color Component ID in frame + frame_generator.add_value(color_component_id_node, + DESIRED_OR_REPORTED_ATTRIBUTE); + // Set Value in frame + auto value_node = color_component_id_node.child_by_type(ATTRIBUTE(VALUE)); + // Can't set value directly since attribute store uses uint32_t and we only want to set 1 byte (uint8_t) + auto value = value_node.desired_or_reported(); + frame_generator.add_raw_byte(static_cast(value)); + } + + if (current_version >= 2) { + auto duration_node = state_node.child_by_type(ATTRIBUTE(DURATION)); + // Can't set value directly since attribute store uses uint32_t and we only want to set 1 byte (uint8_t) + auto duration = duration_node.desired_or_reported(); + frame_generator.add_raw_byte(static_cast(duration)); + } + + frame_generator.validate_frame(frame_length); + } catch (const std::exception &e) { + sl_log_error(LOG_TAG, + "Error while generating Switch Color Set frame : %s", + e.what()); + return SL_STATUS_FAIL; + } + + return SL_STATUS_OK; +} + +static sl_status_t zwave_command_class_switch_color_start_level_change( + attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length) +{ + sl_log_debug(LOG_TAG, "Switch Color Start Level Change"); + try { + attribute_store::attribute start_change_node(node); + assert(start_change_node.is_valid() + && start_change_node.type() == ATTRIBUTE(START_CHANGE)); + + uint8_t start_change = start_change_node.desired_or_reported(); + sl_log_debug(LOG_TAG, "start_change: %d", start_change); + + //Set start change = 0 to be able to handle the next command + start_change_node.set_desired(INITIAL_STATE); + + //We only handle if Start Change is 1 + if (start_change != 1) { + sl_log_error(LOG_TAG, + "Start Change have invalid value: %d", + start_change); + return SL_STATUS_FAIL; + } + + auto current_version = get_current_switch_color_version(node); + + // Compute expected size for set frame + const uint8_t expected_frame_size + = current_version >= 3 + ? sizeof(ZW_SWITCH_COLOR_START_LEVEL_CHANGE_V3_FRAME) + : sizeof(ZW_SWITCH_COLOR_START_LEVEL_CHANGE_FRAME); + + // Creating the frame + frame_generator.initialize_frame(SWITCH_COLOR_START_LEVEL_CHANGE, + frame, + expected_frame_size); + + //Get color component id node + auto color_component_id_node = start_change_node.parent(); + + //Get state node + attribute_store::attribute state_node + = start_change_node.first_parent(ATTRIBUTE(STATE)); + + //Get start level node + attribute_store::attribute start_level_node( + state_node.child_by_type(ATTRIBUTE(START_LEVEL))); + uint8_t start_level = start_level_node.desired_or_reported(); + if (!zwave_command_class_switch_color_validate_value(start_level)) { + sl_log_error( + LOG_TAG, + "Start Level have invalid value: %d, it should in range <0 - 255>", + start_level); + return SL_STATUS_FAIL; + } + + //Get up down node and value + attribute_store::attribute up_down_node( + state_node.child_by_type(ATTRIBUTE(UP_DOWN))); + uint8_t up_down = up_down_node.desired_or_reported(); + if ((up_down != 0) && (up_down != 1)) { + sl_log_error(LOG_TAG, + "Up/Down have invalid value: %d, it should be 0 or 1", + up_down); + return SL_STATUS_FAIL; + } + + //Get ignore start level node and value + attribute_store::attribute ignore_start_level_node( + state_node.child_by_type(ATTRIBUTE(IGNORE_START_LEVEL))); + uint8_t ignore_start_level + = ignore_start_level_node.desired_or_reported(); + if ((ignore_start_level != 0) && (ignore_start_level != 1)) { + sl_log_error( + LOG_TAG, + "Ignore Start Level have invalid value: %d, it should be 0 or 1", + ignore_start_level); + return SL_STATUS_FAIL; + } + + uint8_t properties1 = ((up_down << 6) | (ignore_start_level << 5)); + + //Add data to frame + frame_generator.add_raw_byte(properties1); + frame_generator.add_value(color_component_id_node, + DESIRED_OR_REPORTED_ATTRIBUTE); + frame_generator.add_raw_byte(start_level); + + if (current_version >= 3) { + auto duration_node = state_node.child_by_type(ATTRIBUTE(DURATION)); + auto duration = duration_node.desired_or_reported(); + frame_generator.add_raw_byte(static_cast(duration)); + } + + frame_generator.validate_frame(frame_length); + } catch (const std::exception &e) { + sl_log_error( + LOG_TAG, + "Error while generating Switch Color Start Level Change frame : %s", + e.what()); + return SL_STATUS_FAIL; + } + + return SL_STATUS_OK; +} + +static sl_status_t zwave_command_class_switch_color_stop_level_change( + attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length) +{ + sl_log_debug(LOG_TAG, "Switch Color Stop Level Change"); + try { + attribute_store::attribute stop_change_node(node); + assert(stop_change_node.is_valid() + && stop_change_node.type() == ATTRIBUTE(STOP_CHANGE)); + + uint8_t stop_change = stop_change_node.desired_or_reported(); + sl_log_debug(LOG_TAG, "stop_change: %d", stop_change); + + //Set start change = 0 to be able to handle the next command + stop_change_node.set_desired(INITIAL_STATE); + + //We only handle if Stop Change is 1 + if (stop_change != 1) { + sl_log_error(LOG_TAG, "Start Change have invalid value: %d", stop_change); + return SL_STATUS_FAIL; + } + + // Compute expected size for set frame + const uint8_t expected_frame_size + = sizeof(ZW_SWITCH_COLOR_STOP_LEVEL_CHANGE_V3_FRAME); + + // Creating the frame + frame_generator.initialize_frame(SWITCH_COLOR_STOP_LEVEL_CHANGE, + frame, + expected_frame_size); + + //Get color component id node + auto color_component_id_node = stop_change_node.parent(); + + //Add data to frame + frame_generator.add_value(color_component_id_node, + DESIRED_OR_REPORTED_ATTRIBUTE); + + frame_generator.validate_frame(frame_length); + } catch (const std::exception &e) { + sl_log_error( + LOG_TAG, + "Error while generating Switch Color Stop Level Change frame : %s", + e.what()); + return SL_STATUS_FAIL; + } + + return SL_STATUS_OK; +} + +/////////////////////////////////////////////////////////////////////////////// +// Frame parsing functions +/////////////////////////////////////////////////////////////////////////////// +static sl_status_t zwave_command_class_switch_color_handle_supported_report( + const zwave_controller_connection_info_t *connection_info, + const uint8_t *frame_data, + uint16_t frame_length) +{ + // Setup + attribute_store::attribute endpoint_node( + zwave_command_class_get_endpoint_node(connection_info)); + + sl_log_debug(LOG_TAG, "Switch_color Supported Report frame received"); + + // Compute expected size for report frame + const uint8_t expected_size = sizeof(ZW_SWITCH_COLOR_SUPPORTED_REPORT_FRAME); + + // Parse the frame + try { + zwave_frame_parser parser(frame_data, frame_length); + + if (!parser.is_frame_size_valid(expected_size)) { + sl_log_error(LOG_TAG, "Invalid frame size for Switch_color Report frame"); + return SL_STATUS_FAIL; + } + + const uint8_t bitmask_1 = parser.read_byte(); + const uint8_t bitmask_2 = parser.read_byte(); + color_component_bitmask_t bitmask = (bitmask_2 << 8) | bitmask_1; + sl_log_debug(LOG_TAG, + "Switch Color Report Color Component Mask : %d", + bitmask); + + //Get mask node + attribute_store::attribute mask_node + = endpoint_node.child_by_type(ATTRIBUTE(SUPPORTED_COLOR_COMPONENT_MASK)); + //Set reported mask node + mask_node.set_reported(bitmask); + + //Get state node + attribute_store::attribute state_node( + endpoint_node.child_by_type(ATTRIBUTE(STATE))); + + // Create the color component ID attributes + color_component_bitmask_t current_bit; + for (uint8_t i = 0; i < MAX_SUPPORTED_COLOR_COMPONENT; i++) { + current_bit = 1 << i; + current_bit &= bitmask; + + // Marked as not supported, we check the next one + if (current_bit == 0) { + continue; + } + + // Ignore special case + if (i == COMPONENT_ID_INDEXED_COLOR) { + sl_log_warning(LOG_TAG, + "Component ID 8 is obsoleted, not creating attribute\n"); + continue; + } + + // Create component ID + color_component_id_t component_id = i; + auto color_component_node + = state_node.emplace_node(ATTRIBUTE(COLOR_COMPONENT_ID), component_id); + + // New we associate a value to it so the controller can get it's values + color_component_node.emplace_node(ATTRIBUTE(VALUE)); + + // Create Start and Stop Level change + auto start_node + = color_component_node.emplace_node(ATTRIBUTE(START_CHANGE)); + start_node.set_reported(INITIAL_STATE); + + auto stop_node + = color_component_node.emplace_node(ATTRIBUTE(STOP_CHANGE)); + stop_node.set_reported(INITIAL_STATE); + } + + } catch (const std::exception &e) { + sl_log_error(LOG_TAG, + "Error while parsing Switch_color Supported Report frame : %s", + e.what()); + return SL_STATUS_FAIL; + } + return SL_STATUS_OK; +} + +static sl_status_t zwave_command_class_switch_color_handle_report( + const zwave_controller_connection_info_t *connection_info, + const uint8_t *frame_data, + uint16_t frame_length) +{ + // Setup + attribute_store::attribute endpoint_node( + zwave_command_class_get_endpoint_node(connection_info)); + auto current_version = get_current_switch_color_version(endpoint_node); + + sl_log_debug(LOG_TAG, "Switch_color Report frame received"); + + // Compute expected size for report frame + const uint8_t expected_size = (current_version >= 3) + ? sizeof(ZW_SWITCH_COLOR_REPORT_V3_FRAME) + : sizeof(ZW_SWITCH_COLOR_REPORT_FRAME); + + attribute_store::attribute state_node + = endpoint_node.child_by_type(ATTRIBUTE(STATE)); + + if (!state_node.is_valid()) { + sl_log_error( + LOG_TAG, + "Can't find state node when parsing Switch Color Report frame"); + return SL_STATUS_FAIL; + } + + // Parse the frame + try { + zwave_frame_parser parser(frame_data, frame_length); + + if (!parser.is_frame_size_valid(expected_size)) { + sl_log_error(LOG_TAG, "Invalid frame size for Switch_color Report frame"); + return SL_STATUS_FAIL; + } + + //Get Color Component ID + uint8_t component_id = parser.read_byte(); + + //Get Color Current Value + uint32_t current_value = parser.read_byte(); + + attribute_store::attribute component_id_node + = state_node.child_by_type_and_value(ATTRIBUTE(COLOR_COMPONENT_ID), + component_id); + + attribute_store::attribute value_node + = component_id_node.child_by_type(ATTRIBUTE(VALUE)); + + value_node.set_reported(current_value); + + if (current_version >= 3) { + //Get Target Value + + uint32_t target_value = parser.read_byte(); + sl_log_debug(LOG_TAG, + "Switch Color Report Target Value : %d", + target_value); + + //Get Duration from frame and Set value + auto duration_node = state_node.child_by_type(ATTRIBUTE(DURATION)); + auto duration_value = parser.read_byte(); + duration_node.set_reported(duration_value); + } + + } catch (const std::exception &e) { + sl_log_error(LOG_TAG, + "Error while parsing Switch_color Report frame : %s", + e.what()); + return SL_STATUS_FAIL; + } + return SL_STATUS_OK; +} + +/////////////////////////////////////////////////////////////////////////////// +// Incoming commands handler +/////////////////////////////////////////////////////////////////////////////// +sl_status_t zwave_command_class_switch_color_control_handler( + const zwave_controller_connection_info_t *connection_info, + const uint8_t *frame_data, + uint16_t frame_length) +{ + // Frame too short, it should have not come here. + if (frame_length <= COMMAND_INDEX) { + return SL_STATUS_NOT_SUPPORTED; + } + + switch (frame_data[COMMAND_INDEX]) { + case SWITCH_COLOR_SUPPORTED_REPORT: + return zwave_command_class_switch_color_handle_supported_report( + connection_info, + frame_data, + frame_length); + case SWITCH_COLOR_REPORT: + return zwave_command_class_switch_color_handle_report(connection_info, + frame_data, + frame_length); + default: + return SL_STATUS_NOT_SUPPORTED; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Attribute Store callback functions +/////////////////////////////////////////////////////////////////////////////// +static void zwave_command_class_switch_color_on_version_attribute_update( + attribute_store_node_t updated_node, attribute_store_change_t change) +{ + if (change == ATTRIBUTE_DELETED) { + return; + } + + // Confirm that we have a version attribute update + assert(ATTRIBUTE(VERSION) == attribute_store_get_node_type(updated_node)); + + attribute_store::attribute version_node(updated_node); + // Do not create the attributes until we are sure of the version + zwave_cc_version_t supporting_node_version = 0; + + // Wait for the version + if (!version_node.reported_exists()) { + return; + } + + sl_log_debug(LOG_TAG, "Switch Color version attribute update received"); + + supporting_node_version = version_node.reported(); + + // Now we know we have a switch_color supporting endpoint. + attribute_store::attribute endpoint_node + = version_node.first_parent(ATTRIBUTE_ENDPOINT_ID); + + // Emplace supported color mask + endpoint_node.emplace_node(ATTRIBUTE(SUPPORTED_COLOR_COMPONENT_MASK)); + // Emplace state + auto state_node = endpoint_node.emplace_node(ATTRIBUTE(STATE)); + + // Set Reported state + state_node.set_reported(FINAL_STATE); + + // Emplace color start level change + std::vector switch_color_start_change_attributes; + switch_color_start_change_attributes.push_back(ATTRIBUTE(UP_DOWN)); + switch_color_start_change_attributes.push_back(ATTRIBUTE(IGNORE_START_LEVEL)); + switch_color_start_change_attributes.push_back(ATTRIBUTE(START_LEVEL)); + + for (auto attribute: switch_color_start_change_attributes) { + state_node.emplace_node(attribute); + } + + // Emplace duration + if (supporting_node_version >= 2) { + state_node.emplace_node(ATTRIBUTE(DURATION)); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Public interface functions +/////////////////////////////////////////////////////////////////////////////// +sl_status_t zwave_command_class_switch_color_init() +{ + // Attribute store callbacks + attribute_store_register_callback_by_type( + zwave_command_class_switch_color_on_version_attribute_update, + ATTRIBUTE(VERSION)); + + // Attribute resolver rules + attribute_resolver_register_rule( + ATTRIBUTE(SUPPORTED_COLOR_COMPONENT_MASK), + NULL, + &zwave_command_class_switch_color_supported_get); + + attribute_resolver_register_rule( + ATTRIBUTE(START_CHANGE), + &zwave_command_class_switch_color_start_level_change, + NULL); + + attribute_resolver_register_rule( + ATTRIBUTE(STOP_CHANGE), + &zwave_command_class_switch_color_stop_level_change, + NULL); + + attribute_resolver_register_rule(ATTRIBUTE(VALUE), + &zwave_command_class_switch_color_set, + &zwave_command_class_switch_color_get); + + // The support side of things: Register our handler to the Z-Wave CC framework: + zwave_command_handler_t handler = {}; + handler.support_handler = NULL; + handler.control_handler = &zwave_command_class_switch_color_control_handler; + // Not supported, so this does not really matter + handler.minimal_scheme = ZWAVE_CONTROLLER_ENCAPSULATION_NETWORK_SCHEME; + handler.manual_security_validation = false; + handler.command_class = COMMAND_CLASS_SWITCH_COLOR; + handler.version = SWITCH_COLOR_VERSION_V3; + handler.command_class_name = "Switch_color"; + handler.comments = ""; + + zwave_command_handler_register_handler(handler); + + return SL_STATUS_OK; +} + +void zwave_command_class_switch_color_invoke_on_all_attributes( + attribute_store_node_t state_node, + attribute_store_type_t child_node_type, + void (*function)(attribute_store_node_t)) +{ + uint32_t index = 0; + attribute_store_node_t component_node + = attribute_store_get_first_child_by_type( + state_node, + ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_COLOR_COMPONENT_ID); + while (component_node != ATTRIBUTE_STORE_INVALID_NODE) { + index += 1; + attribute_store_node_t child_node + = attribute_store_get_first_child_by_type(component_node, + child_node_type); + + function(child_node); + component_node = attribute_store_get_node_child_by_type( + state_node, + ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_COLOR_COMPONENT_ID, + index); + } +} + +void zwave_command_class_switch_color_invoke_on_all_attributes_with_return_value( + attribute_store_node_t state_node, + attribute_store_type_t child_node_type, + sl_status_t (*function)(attribute_store_node_t)) +{ + uint32_t index = 0; + attribute_store_node_t component_node + = attribute_store_get_first_child_by_type( + state_node, + ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_COLOR_COMPONENT_ID); + while (component_node != ATTRIBUTE_STORE_INVALID_NODE) { + index += 1; + attribute_store_node_t child_node + = attribute_store_get_first_child_by_type(component_node, + child_node_type); + + function(child_node); + component_node = attribute_store_get_node_child_by_type( + state_node, + ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_COLOR_COMPONENT_ID, + index); + } +} \ No newline at end of file diff --git a/applications/zpc/components/zwave_command_classes/src/zwave_command_class_switch_color.h b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_switch_color.h index 2bb0720e6..d42c7311f 100644 --- a/applications/zpc/components/zwave_command_classes/src/zwave_command_class_switch_color.h +++ b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_switch_color.h @@ -1,6 +1,6 @@ /****************************************************************************** * # License - * Copyright 2022 Silicon Laboratories Inc. www.silabs.com + * Copyright 2021 Silicon Laboratories Inc. www.silabs.com ****************************************************************************** * The licensor of this software is Silicon Laboratories Inc. Your use of this * software is governed by the terms of Silicon Labs Master Software License @@ -12,15 +12,70 @@ *****************************************************************************/ /** - * @defgroup zwave_command_class_switch_color Switch Color Command Class + * @defgroup switch_color_command_class Switch Color Command Class * @ingroup command_classes * @brief Switch Color Command Class handlers and control functions * - * This module implement some of the functions to control the Color Switch - * Command Class + * This module implement functions for generating and parsing the Z-Wave frames + * for controlling the Switch Color Command Class. + * + * The data model used for this command class is tailored to be mapped to the + * ZCL Level cluster. + * + * The State attribute is a hook for the Set / Get rule registrations. The + * actual values being set and resolved are the duration and the value. + * If the duration and/or the value needs a resolution, the Command Class + * handler adjusts the state in order to trigger the resolver: + * + * - state = reported [] for a get resolution + * - state = desired [1] reported [0] for a set resolution + * - state = desired [0] reported [0] for a no resolution + * +@startuml{attribute_store_switch_color_command_class.png} "Switch Color data model" width=10cm +title Switch Color data model +allow_mixing +skinparam objectBorderColor black + +legend top +ATTRIBUTE(type) : ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_type +endlegend + +package "Attribute Store" <> { + object "NodeID" as node #f2ffe6 + node : Attribute Type = ATTRIBUTE_NODE_ID + node : value = Desired: [], Reported: [03] + + object "Endpoint Attribute" as endpoint #e6fff7 + endpoint : Attribute Type = ATTRIBUTE_ENDPOINT_ID + endpoint : value = Desired: [] - Reported: [04] + + object "Version" as version #FEFEFE + version : Attribute Type = ATTRIBUTE(VERSION) + version : value = Desired: [] - Reported: [2] + + object "State" as state #FFFFFF + state : Attribute Type = ATTRIBUTE(STATE) + state : value = Desired: [1] - Reported: [0] + + object "Value" as value #FFFFFF + value : Attribute Type = ATTRIBUTE(VALUE) + value : value = Desired: [0x00], Reported: [0xFF] + + object "Duration" as duration #FFFFFF + duration : Attribute Type = ATTRIBUTE(DURATION) + duration : value = Desired: [10], Reported: [10] +} + +node *-- endpoint +endpoint *-- version +endpoint *-- state +state *-- value +state *-- duration + +@enduml * * @{ - */ +*/ #ifndef ZWAVE_COMMAND_CLASS_SWITCH_COLOR_H #define ZWAVE_COMMAND_CLASS_SWITCH_COLOR_H @@ -59,7 +114,7 @@ void zwave_command_class_switch_color_invoke_on_all_attributes_with_return_value sl_status_t (*function)(attribute_store_node_t)); /** - * @brief This function initialize the Color Switch Command Class handler + * @brief This function initialize the Switch Color Command Class handler * * @return SL_STATUS_OK on success, any other error code for an error. */ @@ -70,4 +125,4 @@ sl_status_t zwave_command_class_switch_color_init(); #endif #endif //ZWAVE_COMMAND_CLASS_SWITCH_COLOR_H -/** @} end zwave_command_class_switch_color */ +/** @} end switch_color_command_class */ diff --git a/applications/zpc/components/zwave_command_classes/test/CMakeLists.txt b/applications/zpc/components/zwave_command_classes/test/CMakeLists.txt index e79a13e0d..8ec25f7ce 100644 --- a/applications/zpc/components/zwave_command_classes/test/CMakeLists.txt +++ b/applications/zpc/components/zwave_command_classes/test/CMakeLists.txt @@ -451,17 +451,18 @@ target_add_unittest( NAME zwave_command_class_switch_color_test SOURCES - zwave_command_class_switch_color_test.c + zwave_command_class_switch_color_test.cpp DEPENDS + zwave_command_class_test_helpers zpc_attribute_store_test_helper - uic_attribute_utils_mock zwave_command_handler_mock zwave_controller_mock uic_attribute_resolver_mock zpc_attribute_resolver_mock zpc_config_mock zwave_tx_scheme_selector_mock - zwave_tx_mock) + zwave_tx_mock + uic_dotdot_mqtt_mock) # Z-Wave Binary Switch Command Class test target_add_unittest( diff --git a/applications/zpc/components/zwave_command_classes/test/zwave_command_class_switch_color_test.c b/applications/zpc/components/zwave_command_classes/test/zwave_command_class_switch_color_test.c deleted file mode 100644 index 5a69252ac..000000000 --- a/applications/zpc/components/zwave_command_classes/test/zwave_command_class_switch_color_test.c +++ /dev/null @@ -1,262 +0,0 @@ -/****************************************************************************** - * # License - * Copyright 2021 Silicon Laboratories Inc. www.silabs.com - ****************************************************************************** - * The licensor of this software is Silicon Laboratories Inc. Your use of this - * software is governed by the terms of Silicon Labs Master Software License - * Agreement (MSLA) available at - * www.silabs.com/about-us/legal/master-software-license-agreement. This - * software is distributed to you in Source Code format and is governed by the - * sections of the MSLA applicable to Source Code. - * - *****************************************************************************/ -#include "zwave_command_class_switch_color.h" -#include "zwave_command_classes_utils.h" -#include "unity.h" - -// Generic includes -#include - -// Includes from other components -#include "datastore.h" -#include "attribute_store.h" -#include "attribute_store_helper.h" -#include "attribute_store_fixt.h" -#include "zwave_unid.h" -#include "zpc_attribute_store_type_registration.h" - -// Interface includes -#include "attribute_store_defined_attribute_types.h" -#include "zwave_command_class_color_switch_types.h" //FIXME: UIC-1901 remove this -#include "ZW_classcmd.h" -#include "zwave_utils.h" -#include "zwave_controller_types.h" -#include "zwave_command_class_color_switch_types.h" - -// Test helpers -#include "zpc_attribute_store_test_helper.h" - -// Mock includes -#include "attribute_resolver_mock.h" -#include "zpc_attribute_resolver_mock.h" -#include "zwave_command_handler_mock.h" -#include "attribute_transitions_mock.h" -#include "attribute_timeouts_mock.h" - -// Attribute macro, shortening those long defines for attribute types: -#define ATTRIBUTE(type) ATTRIBUTE_COMMAND_CLASS_MULTILEVEL_SWITCH_##type - -// Static variables -static zpc_resolver_event_notification_function_t on_send_complete = NULL; -static attribute_timeout_callback_t switch_color_undefine_reported = NULL; - -// Stub functions -static sl_status_t register_send_event_handler_stub( - attribute_store_type_t type, - zpc_resolver_event_notification_function_t function, - int cmock_num_calls) -{ - if (ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STATE == type) { - on_send_complete = function; - } - TEST_ASSERT_NOT_NULL(on_send_complete); - TEST_ASSERT_EQUAL(ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STATE, type); - return SL_STATUS_OK; -} - -static sl_status_t attribute_timeout_set_callback_stub( - attribute_store_node_t node, - clock_time_t duration, - attribute_timeout_callback_t callback_function, - int cmock_num_calls) -{ - TEST_ASSERT_EQUAL(ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STATE, attribute_store_get_node_type(node)); - switch_color_undefine_reported = callback_function; - return SL_STATUS_OK; -} - - -/// Setup the test suite (called once before all test_xxx functions are called) -void suiteSetUp() -{ - on_send_complete = NULL; - switch_color_undefine_reported = NULL; - - datastore_init(":memory:"); - attribute_store_init(); - zpc_attribute_store_register_known_attribute_types(); - zpc_attribute_store_test_helper_create_network(); - zwave_unid_set_home_id(home_id); -} - -/// Teardown the test suite (called once after all test_xxx functions are called) -int suiteTearDown(int num_failures) -{ - attribute_store_teardown(); - datastore_teardown(); - return num_failures; -} - -/// Called before each and every test -void setUp() -{ - is_attribute_transition_ongoing_IgnoreAndReturn(false); -} - -void test_zwave_command_class_switch_color_init() -{ - // On send complete handler - register_send_event_handler_Stub(®ister_send_event_handler_stub); - - // Call init - TEST_ASSERT_EQUAL(SL_STATUS_OK, zwave_command_class_switch_color_init()); -} - -void test_zwave_command_class_on_send_complete() -{ - attribute_stop_transition_IgnoreAndReturn(SL_STATUS_OK); - - // First check the frame creation. - TEST_ASSERT_NOT_NULL(on_send_complete); - - // Create a small network with color switch values - attribute_store_node_t state_node - = attribute_store_add_node(ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_STATE, - endpoint_id_node); - - color_component_id_t id = 1; - attribute_store_node_t component_1_node = attribute_store_add_node( - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_COLOR_COMPONENT_ID, - state_node); - attribute_store_set_reported(component_1_node, &id, sizeof(id)); - attribute_store_node_t value_1_node - = attribute_store_add_node(ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, - component_1_node); - color_component_id_value_t value = 1; - attribute_store_set_reported(value_1_node, &value, sizeof(value)); - value = 2; - attribute_store_set_desired(value_1_node, &value, sizeof(value)); - - attribute_store_node_t component_2_node = attribute_store_add_node( - ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_COLOR_COMPONENT_ID, - state_node); - id = 2; - attribute_store_set_reported(component_1_node, &id, sizeof(id)); - attribute_store_node_t value_2_node - = attribute_store_add_node(ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, - component_2_node); - value = 2; - attribute_store_set_reported(value_2_node, &value, sizeof(value)); - value = 3; - attribute_store_set_desired(value_2_node, &value, sizeof(value)); - - on_send_complete(state_node, - RESOLVER_GET_RULE, - FRAME_SENT_EVENT_OK_SUPERVISION_WORKING); - - TEST_ASSERT_FALSE(attribute_store_is_value_matched(value_1_node)); - - on_send_complete(state_node, - RESOLVER_SET_RULE, - FRAME_SENT_EVENT_OK_SUPERVISION_WORKING); - - TEST_ASSERT_FALSE(attribute_store_is_value_matched(value_1_node)); - - on_send_complete(state_node, - RESOLVER_SET_RULE, - FRAME_SENT_EVENT_OK_SUPERVISION_SUCCESS); - - TEST_ASSERT_FALSE(attribute_store_is_value_matched(value_1_node)); - TEST_ASSERT_TRUE( - attribute_store_is_value_defined(value_1_node, REPORTED_ATTRIBUTE)); - - // Test without duration - on_send_complete(state_node, - RESOLVER_SET_RULE, - FRAME_SENT_EVENT_OK_NO_SUPERVISION); - - TEST_ASSERT_FALSE( - attribute_store_is_value_defined(value_2_node, REPORTED_ATTRIBUTE)); - TEST_ASSERT_FALSE( - attribute_store_is_value_defined(value_2_node, DESIRED_ATTRIBUTE)); - TEST_ASSERT_FALSE( - attribute_store_is_value_defined(value_1_node, REPORTED_ATTRIBUTE)); - TEST_ASSERT_FALSE( - attribute_store_is_value_defined(value_1_node, DESIRED_ATTRIBUTE)); - - // Test with duration - value = 0; - attribute_store_set_reported(value_1_node, &value, sizeof(value)); - value = 1; - attribute_store_set_desired(value_1_node, &value, sizeof(value)); - value = 2; - attribute_store_set_reported(value_2_node, &value, sizeof(value)); - value = 3; - attribute_store_set_desired(value_2_node, &value, sizeof(value)); - - color_component_id_duration_t duration_value = 20; - attribute_store_node_t duration_node - = attribute_store_add_node(ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_DURATION, - state_node); - attribute_store_set_desired(duration_node, &duration_value, sizeof(duration_value)); - - attribute_timeout_set_callback_ExpectAndReturn( - state_node, - zwave_duration_to_time(duration_value) + PROBE_BACK_OFF, - NULL, - SL_STATUS_OK); - attribute_timeout_set_callback_IgnoreArg_callback_function(); - attribute_timeout_set_callback_Stub(&attribute_timeout_set_callback_stub); - - on_send_complete(state_node, - RESOLVER_SET_RULE, - FRAME_SENT_EVENT_OK_NO_SUPERVISION); - TEST_ASSERT_FALSE( - attribute_store_is_value_defined(value_2_node, DESIRED_ATTRIBUTE)); - TEST_ASSERT_FALSE( - attribute_store_is_value_defined(value_1_node, DESIRED_ATTRIBUTE)); - TEST_ASSERT_FALSE( - attribute_store_is_value_defined(duration_node, DESIRED_ATTRIBUTE)); - TEST_ASSERT_TRUE( - attribute_store_is_value_defined(duration_node, REPORTED_ATTRIBUTE)); - TEST_ASSERT_TRUE( - attribute_store_is_value_defined(value_1_node, REPORTED_ATTRIBUTE)); - TEST_ASSERT_TRUE( - attribute_store_is_value_defined(value_2_node, REPORTED_ATTRIBUTE)); - - on_send_complete(state_node, - RESOLVER_SET_RULE, - FRAME_SENT_EVENT_OK_SUPERVISION_NO_SUPPORT); - - TEST_ASSERT_FALSE( - attribute_store_is_value_defined(value_1_node, REPORTED_ATTRIBUTE)); -} - -void test_switch_color_undefine_reported_happy_case() -{ - // - TEST_ASSERT_NOT_NULL(switch_color_undefine_reported); - - const int COLOR_VALUE_COUNT = 3; - - for (int i = 0; i < COLOR_VALUE_COUNT; i++) { - attribute_store_node_t color_value_node - = attribute_store_add_node(ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, - endpoint_id_node); - - attribute_store_set_reported(color_value_node, &i, sizeof(i)); - } - - switch_color_undefine_reported(endpoint_id_node); - - for (int i = 0; i < COLOR_VALUE_COUNT; i++) { - int j; - attribute_store_node_t color_value_node - = attribute_store_add_node(ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_VALUE, - endpoint_id_node); - - TEST_ASSERT_EQUAL( - SL_STATUS_FAIL, - attribute_store_get_reported(color_value_node, &j, sizeof(j))); - } -} \ No newline at end of file diff --git a/applications/zpc/components/zwave_command_classes/test/zwave_command_class_switch_color_test.cpp b/applications/zpc/components/zwave_command_classes/test/zwave_command_class_switch_color_test.cpp new file mode 100644 index 000000000..6596c4e47 --- /dev/null +++ b/applications/zpc/components/zwave_command_classes/test/zwave_command_class_switch_color_test.cpp @@ -0,0 +1,743 @@ +/****************************************************************************** + * # License + * Copyright 2024 Silicon Laboratories Inc. www.silabs.com + ****************************************************************************** + * The licensor of this software is Silicon Laboratories Inc. Your use of this + * software is governed by the terms of Silicon Labs Master Software License + * Agreement (MSLA) available at + * www.silabs.com/about-us/legal/master-software-license-agreement. This + * software is distributed to you in Source Code format and is governed by the + * sections of the MSLA applicable to Source Code. + * + *****************************************************************************/ +// Base class +#include "zwave_command_class_switch_color.h" +#include "zwave_command_class_color_switch_types.h" +#include "zwave_command_class_generic_types.h" +#include "zwave_command_classes_utils.h" +#include "unity.h" + +// Generic includes +#include + +// Unify +#include "datastore.h" +#include "attribute_store.h" +#include "attribute_store_fixt.h" + +// Interface includes +#include "ZW_classcmd.h" +#include "sl_log.h" + +// ZPC includes +#include "attribute_store_defined_attribute_types.h" +#include "zpc_attribute_store_type_registration.h" + +// Test helpers +#include "zwave_command_class_test_helper.hpp" + +// Attribute macro, shortening those long defines for attribute types: +#define ATTRIBUTE(type) ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_##type + +// Max component ID color supported +#define MAX_SUPPORTED_COLOR_COMPONENT 9 +// Index of obsoleted component ID +#define COMPONENT_ID_INDEXED_COLOR 8 + +// Log tag +constexpr char LOG_TAG[] = "zwave_command_class_switch_color_test"; + +using namespace zwave_command_class_test_helper; + +extern "C" { + +/// Setup the test suite (called once before all test_xxx functions are called) +void suiteSetUp() +{ + datastore_init(":memory:"); + attribute_store_init(); + zpc_attribute_store_register_known_attribute_types(); +} + +/// Teardown the test suite (called once after all test_xxx functions are called) +int suiteTearDown(int num_failures) +{ + attribute_store_teardown(); + datastore_teardown(); + return num_failures; +} + +// Tested command class handler +const zwave_struct_handler_args command_class_handler + = {.command_class_id = COMMAND_CLASS_SWITCH_COLOR, + .supported_version = 3, + .scheme = ZWAVE_CONTROLLER_ENCAPSULATION_NETWORK_SCHEME}; +// Get Set function map +const resolver_function_map attribute_bindings = { + {ATTRIBUTE(VALUE), {SWITCH_COLOR_GET, SWITCH_COLOR_SET}}, + {ATTRIBUTE(STOP_CHANGE), {0, SWITCH_COLOR_STOP_LEVEL_CHANGE}}, + {ATTRIBUTE(START_CHANGE), {0, SWITCH_COLOR_START_LEVEL_CHANGE}}, + {ATTRIBUTE(SUPPORTED_COLOR_COMPONENT_MASK), {SWITCH_COLOR_SUPPORTED_GET, 0}}, +}; + +/// Called before each and every test +void setUp() +{ + zwave_setUp(command_class_handler, + &zwave_command_class_switch_color_init, + attribute_bindings); +} + +/////////////////////////////////////////////////////////////////////////////// +// Internal helpers +/////////////////////////////////////////////////////////////////////////////// +attribute_store::attribute helper_get_component_maks_node() +{ + return helper_test_and_get_node(ATTRIBUTE(SUPPORTED_COLOR_COMPONENT_MASK)); +} + +attribute_store::attribute helper_get_state_node() +{ + return helper_test_and_get_node(ATTRIBUTE(STATE)); +} + +attribute_store::attribute helper_get_component_id_node() +{ + auto state_node = helper_test_and_get_node(ATTRIBUTE(STATE)); + + return helper_test_and_get_node(ATTRIBUTE(COLOR_COMPONENT_ID), state_node); +} + +attribute_store::attribute helper_get_duration_node() +{ + auto state_node = helper_test_and_get_node(ATTRIBUTE(STATE)); + + return helper_test_and_get_node(ATTRIBUTE(DURATION), state_node); +} + +attribute_store::attribute helper_get_up_down_node() +{ + auto state_node = helper_test_and_get_node(ATTRIBUTE(STATE)); + + return helper_test_and_get_node(ATTRIBUTE(UP_DOWN), state_node); +} + +attribute_store::attribute helper_get_ignore_start_level_node() +{ + auto state_node = helper_test_and_get_node(ATTRIBUTE(STATE)); + + return helper_test_and_get_node(ATTRIBUTE(IGNORE_START_LEVEL), state_node); +} + +attribute_store::attribute helper_get_start_level_node() +{ + auto state_node = helper_test_and_get_node(ATTRIBUTE(STATE)); + + return helper_test_and_get_node(ATTRIBUTE(START_LEVEL), state_node); +} + +attribute_store::attribute helper_get_value_node_from_color_component_id_node(attribute_store_node_t color_component_id_node) +{ + return helper_test_and_get_node(ATTRIBUTE(VALUE), color_component_id_node); +} + +attribute_store::attribute helper_get_start_change_node_from_color_component_id_node(attribute_store_node_t color_component_id_node) +{ + return helper_test_and_get_node(ATTRIBUTE(START_CHANGE), color_component_id_node); +} + +attribute_store::attribute helper_get_stop_change_node_from_color_component_id_node(attribute_store_node_t color_component_id_node) +{ + return helper_test_and_get_node(ATTRIBUTE(STOP_CHANGE), color_component_id_node); +} + +std::vector get_supported_color_component_id_node(uint16_t bitmask_tested) +{ + std::vector supported_colors_node; + uint8_t current_bit; + + //Get state node form endpoint node + auto vector_state_node = cpp_endpoint_id_node.children(ATTRIBUTE(STATE)); + attribute_store::attribute state_node(vector_state_node.front()); + + for (uint8_t i = 0; i < MAX_SUPPORTED_COLOR_COMPONENT; i++) { + current_bit = 1 << i; + current_bit &= bitmask_tested; + + // Marked as not supported, we check the next one + if (current_bit == 0) { + continue; + } + + // Ignore special case + if (i == COMPONENT_ID_INDEXED_COLOR) { + sl_log_warning(LOG_TAG, + "Component ID 8 is obsoleted, not creating attribute\n"); + continue; + } + + // Get color component id node + color_component_id_t component_id = i; + supported_colors_node.push_back(state_node.child_by_type_and_value(ATTRIBUTE(COLOR_COMPONENT_ID), component_id)); + } + + return supported_colors_node; +} + +/////////////////////////////////////////////////////////////////////////////// +// Test cases +/////////////////////////////////////////////////////////////////////////////// + +void test_switch_color_interview_v1_happy_case() +{ + helper_set_version(1); + + helper_test_and_get_node(ATTRIBUTE(SUPPORTED_COLOR_COMPONENT_MASK)); + auto state_node = helper_test_and_get_node(ATTRIBUTE(STATE)); + + // Verify that we have the correct node(s) + helper_test_node_exists(ATTRIBUTE(UP_DOWN), state_node); + helper_test_node_exists(ATTRIBUTE(IGNORE_START_LEVEL), state_node); + helper_test_node_exists(ATTRIBUTE(START_LEVEL), state_node); + + helper_test_node_does_not_exists(ATTRIBUTE(DURATION), state_node); +} + +void test_switch_color_interview_v2_happy_case() +{ + helper_set_version(2); + + helper_test_and_get_node(ATTRIBUTE(SUPPORTED_COLOR_COMPONENT_MASK)); + auto state_node = helper_test_and_get_node(ATTRIBUTE(STATE)); + + // Verify that we have the correct node(s) + helper_test_node_exists(ATTRIBUTE(UP_DOWN), state_node); + helper_test_node_exists(ATTRIBUTE(IGNORE_START_LEVEL), state_node); + helper_test_node_exists(ATTRIBUTE(START_LEVEL), state_node); + helper_test_node_exists(ATTRIBUTE(DURATION), state_node); +} + +void test_switch_color_supported_get_happy_case() +{ + helper_test_get_set_frame_happy_case(SWITCH_COLOR_SUPPORTED_GET); +} + +void test_switch_color_supported_report_happy_case() +{ + + helper_set_version(1); + + uint8_t mask_1 = 0x1C; + uint8_t mask_2 = 0x00; + uint16_t bitmask_tested = (mask_2 << 8) | mask_1; // 0000 0000 0001 1100 + + auto component_mask_node = helper_get_component_maks_node(); + helper_test_report_frame(SWITCH_COLOR_SUPPORTED_REPORT, {mask_1, mask_2}); + + // Verify that the value of color component mask is updated + TEST_ASSERT_EQUAL_MESSAGE(bitmask_tested, + component_mask_node.reported(), + "Value of color component mask isn't updated after report"); + + //Get state node form endpoint node + auto vector_state_node = cpp_endpoint_id_node.children(ATTRIBUTE(STATE)); + attribute_store::attribute state_node(vector_state_node.front()); + + + auto vector_supported_node_id = get_supported_color_component_id_node(bitmask_tested); + + + for (auto color_component_id_node : vector_supported_node_id) { + // Verify that color component id node exist + uint8_t component_id_not_expect_tested = ATTRIBUTE_STORE_INVALID_NODE; + TEST_ASSERT_NOT_EQUAL_MESSAGE(component_id_not_expect_tested, + color_component_id_node, + "Can not find attribute"); + + // Verify that we value note exist + helper_get_value_node_from_color_component_id_node(color_component_id_node); + + // Verify that we start change note exist and have correct value + auto start_change_node = helper_get_start_change_node_from_color_component_id_node(color_component_id_node); + uint8_t start_change_value_tested = 0; + TEST_ASSERT_EQUAL_MESSAGE(start_change_value_tested, + start_change_node.reported(), + "Start change node isn't have correct value"); + + // Verify that we stop change note exist and have correct value + auto stop_change_node = helper_get_stop_change_node_from_color_component_id_node(color_component_id_node); + uint8_t stop_change_value_tested = 0; + TEST_ASSERT_EQUAL_MESSAGE(stop_change_value_tested, + stop_change_node.reported(), + "Stop change node isn't have correct value"); + } + + // Test number of Color Component ID + auto supported_color_component_count = attribute_store_get_node_child_count_by_type(state_node, + ATTRIBUTE(COLOR_COMPONENT_ID)); + + TEST_ASSERT_EQUAL_MESSAGE(vector_supported_node_id.size(), + supported_color_component_count, + "Number of Color Component ID attribute is not correct"); +} + +void test_switch_color_get_happy_case() +{ + helper_set_version(1); + + uint8_t mask_1 = 0x1C; + uint8_t mask_2 = 0x00; + uint16_t bitmask_tested = (mask_2 << 8) | mask_1; // 0000 0000 0001 1100 + + //Send Color Switch Supported Report frame to create necessary attributes. + helper_test_report_frame(SWITCH_COLOR_SUPPORTED_REPORT, {mask_1, mask_2}); + + // attribute_store_log(); + + auto vector_supported_node_id = get_supported_color_component_id_node(bitmask_tested); + + for (auto element : vector_supported_node_id) { + //Get value node + attribute_store::attribute color_component_id_node(element); + auto value_node = color_component_id_node.child_by_type(ATTRIBUTE(VALUE)); + //Test switch color get frame + helper_test_get_set_frame_happy_case(SWITCH_COLOR_GET, value_node, {color_component_id_node.reported()}); + } +} + +void test_switch_color_report_v1_happy_case() +{ + helper_set_version(1); + + uint8_t mask_1 = 0x1C; + uint8_t mask_2 = 0x00; + uint16_t bitmask_tested = (mask_2 << 8) | mask_1; // 0000 0000 0001 1100 + uint8_t value_tested = 0xAB; + + auto component_mask_node = helper_get_component_maks_node(); + helper_test_report_frame(SWITCH_COLOR_SUPPORTED_REPORT, {mask_1, mask_2}); + + // Verify that the value of color component mask is updated + TEST_ASSERT_EQUAL_MESSAGE(bitmask_tested, + component_mask_node.reported(), + "Value of color component mask isn't updated after report"); + + auto vector_supported_node_id = get_supported_color_component_id_node(bitmask_tested); + + for (auto color_component_id_node : vector_supported_node_id) { + + // Verify that we value note exist + auto value_node = helper_get_value_node_from_color_component_id_node(color_component_id_node); + + helper_test_report_frame(SWITCH_COLOR_REPORT, {color_component_id_node.reported(), value_tested}); + // attribute_store_log(); + // Verify that the value is updated correct + TEST_ASSERT_EQUAL_MESSAGE(value_tested, + value_node.reported(), + "Value of isn't updated correct after swich color report"); + } +} + +void test_switch_color_report_v3_happy_case() +{ + helper_set_version(3); + + uint8_t mask_1 = 0x1C; + uint8_t mask_2 = 0x00; + uint16_t bitmask_tested = (mask_2 << 8) | mask_1; // 0000 0000 0001 1100 + uint8_t current_value_tested = 0xAB; + uint8_t target_value_tested = 0xAB; + uint8_t duration_tested = 10; + + auto component_mask_node = helper_get_component_maks_node(); + helper_test_report_frame(SWITCH_COLOR_SUPPORTED_REPORT, {mask_1, mask_2}); + + // Verify that the value of color component mask is updated + TEST_ASSERT_EQUAL_MESSAGE(bitmask_tested, + component_mask_node.reported(), + "Value of color component mask isn't updated after report"); + + auto vector_supported_node_id = get_supported_color_component_id_node(bitmask_tested); + + for (auto color_component_id_node : vector_supported_node_id) { + // Verify that we value note exist + auto value_node = helper_get_value_node_from_color_component_id_node(color_component_id_node); + + //Verify that we duration note exist + auto duration_node = helper_get_duration_node(); + + helper_test_report_frame(SWITCH_COLOR_REPORT, {color_component_id_node.reported(), current_value_tested, target_value_tested, duration_tested}); + + // attribute_store_log(); + + // Verify that the value is updated correct + TEST_ASSERT_EQUAL_MESSAGE(current_value_tested, + value_node.reported(), + "Value of value node isn't updated correct after swich color report"); + + // Verify that the duration is updated correct + TEST_ASSERT_EQUAL_MESSAGE(duration_tested, + duration_node.reported(), + "Value of duration node isn't updated correct after swich color report"); + } +} + +void test_switch_color_report_v1_invalid_color_component_id() +{ + helper_set_version(1); + + uint8_t mask_1 = 0x1C; + uint8_t mask_2 = 0x00; + uint16_t bitmask_tested = (mask_2 << 8) | mask_1; // 0000 0000 0001 1100 + uint8_t value_tested = 0xAB; + uint8_t color_component_id_invalid_tested = 5; + + auto component_mask_node = helper_get_component_maks_node(); + helper_test_report_frame(SWITCH_COLOR_SUPPORTED_REPORT, {mask_1, mask_2}); + + // Verify that the value of color component mask is updated + TEST_ASSERT_EQUAL_MESSAGE(bitmask_tested, + component_mask_node.reported(), + "Value of color component mask isn't updated after report"); + + auto vector_supported_node_id = get_supported_color_component_id_node(bitmask_tested); + + for (auto color_component_id_node : vector_supported_node_id) { + // Verify that we value note exist + helper_get_value_node_from_color_component_id_node(color_component_id_node); + + helper_test_report_frame(SWITCH_COLOR_REPORT, {color_component_id_invalid_tested, value_tested}, SL_STATUS_FAIL); + } +} + +void test_switch_color_start_level_change_v1_happy_case() +{ + helper_set_version(1); + + uint8_t mask_1 = 0x1C; + uint8_t mask_2 = 0x00; + uint16_t bitmask_tested = (mask_2 << 8) | mask_1; // 0000 0000 0001 1100 + uint8_t start_change_node_tested = 1; + uint8_t start_change_node_finnal_state = FINAL_STATE; + uint8_t up_down_tested = 1; + uint8_t ignore_start_level_tested = 1; + uint8_t start_level_tested = 0xAB; + uint8_t start_level_change_properties1_tested = ((up_down_tested << 6) | (ignore_start_level_tested << 5)); + + auto component_mask_node = helper_get_component_maks_node(); + helper_test_report_frame(SWITCH_COLOR_SUPPORTED_REPORT, {mask_1, mask_2}); + + // Verify that the value of color component mask is updated + TEST_ASSERT_EQUAL_MESSAGE(bitmask_tested, + component_mask_node.reported(), + "Value of color component mask isn't updated after report"); + + auto vector_supported_node_id = get_supported_color_component_id_node(bitmask_tested); + + for (auto color_component_id_node : vector_supported_node_id) { + // Get color start change node and set desired value + auto start_change_node = helper_get_start_change_node_from_color_component_id_node(color_component_id_node); + start_change_node.set_desired(start_change_node_tested); + + // Get color start change node and set desired value + auto up_down_node = helper_get_up_down_node(); + up_down_node.set_desired(up_down_tested); + + // Get color start change node and set desired value + auto ignore_start_level_node = helper_get_ignore_start_level_node(); + ignore_start_level_node.set_desired(ignore_start_level_tested); + + // Get color start change node and set desired value + auto start_level_node = helper_get_start_level_node(); + start_level_node.set_desired(start_level_tested); + + // attribute_store_log(); + helper_test_get_set_frame_happy_case(SWITCH_COLOR_START_LEVEL_CHANGE, + start_change_node, + {start_level_change_properties1_tested, color_component_id_node.reported(), start_level_tested}); + + //Verify start leve change = 0 after send frame + TEST_ASSERT_EQUAL_MESSAGE(start_change_node_finnal_state, + start_change_node.reported(), + "Value of start change isn't updated correct after send frame"); + } +} + +void test_switch_color_start_level_change_v3_happy_case() +{ + helper_set_version(3); + + uint8_t mask_1 = 0x1C; + uint8_t mask_2 = 0x00; + uint16_t bitmask_tested = (mask_2 << 8) | mask_1; // 0000 0000 0001 1100 + uint8_t start_change_node_tested = 1; + uint8_t start_change_node_finnal_state = FINAL_STATE; + uint8_t up_down_tested = 1; + uint8_t ignore_start_level_tested = 1; + uint8_t start_level_tested = 0xAB; + uint8_t duration_tested = 10; + uint8_t start_level_change_properties1_tested = ((up_down_tested << 6) | (ignore_start_level_tested << 5)); + + auto component_mask_node = helper_get_component_maks_node(); + helper_test_report_frame(SWITCH_COLOR_SUPPORTED_REPORT, {mask_1, mask_2}); + + // Verify that the value of color component mask is updated + TEST_ASSERT_EQUAL_MESSAGE(bitmask_tested, + component_mask_node.reported(), + "Value of color component mask isn't updated after report"); + + auto vector_supported_node_id = get_supported_color_component_id_node(bitmask_tested); + + for (auto color_component_id_node : vector_supported_node_id) { + // Get color start change node and set desired value + auto start_change_node = helper_get_start_change_node_from_color_component_id_node(color_component_id_node); + start_change_node.set_desired(start_change_node_tested); + + // Get up down node and set desired value + auto up_down_node = helper_get_up_down_node(); + up_down_node.set_desired(up_down_tested); + + // Get ignore start level node and set desired value + auto ignore_start_level_node = helper_get_ignore_start_level_node(); + ignore_start_level_node.set_desired(ignore_start_level_tested); + + // Get start level node and set desired value + auto start_level_node = helper_get_start_level_node(); + start_level_node.set_desired(start_level_tested); + + // Get duration node and set desired value + auto duration_node = helper_get_duration_node(); + duration_node.set_desired(duration_tested); + + // attribute_store_log(); + helper_test_get_set_frame_happy_case(SWITCH_COLOR_START_LEVEL_CHANGE_V3, + start_change_node, + {start_level_change_properties1_tested, color_component_id_node.reported(), start_level_tested, duration_tested}); + + //Verify start leve change = 0 after send frame + TEST_ASSERT_EQUAL_MESSAGE(start_change_node_finnal_state, + start_change_node.reported(), + "Value of start change isn't updated correct after send frame"); + } +} + +void test_switch_color_start_level_change_invalid_start_change_value() +{ + helper_set_version(1); + + uint8_t mask_1 = 0x1C; + uint8_t mask_2 = 0x00; + uint16_t bitmask_tested = (mask_2 << 8) | mask_1; // 0000 0000 0001 1100 + uint8_t start_change_node_tested = 2; + uint8_t start_change_node_finnal_state = FINAL_STATE; + + auto component_mask_node = helper_get_component_maks_node(); + helper_test_report_frame(SWITCH_COLOR_SUPPORTED_REPORT, {mask_1, mask_2}); + + // Verify that the value of color component mask is updated + TEST_ASSERT_EQUAL_MESSAGE(bitmask_tested, + component_mask_node.reported(), + "Value of color component mask isn't updated after report"); + + auto vector_supported_node_id = get_supported_color_component_id_node(bitmask_tested); + + for (auto color_component_id_node : vector_supported_node_id) { + // Get color start change node and set desired value + auto start_change_node = helper_get_start_change_node_from_color_component_id_node(color_component_id_node); + start_change_node.set_desired(start_change_node_tested); + + // attribute_store_log(); + + helper_test_get_set_fail_case(SWITCH_COLOR_START_LEVEL_CHANGE, + SL_STATUS_FAIL, + start_change_node); + + //Verify start leve change = 0 after send frame + TEST_ASSERT_EQUAL_MESSAGE(start_change_node_finnal_state, + start_change_node.reported(), + "Value of start change isn't updated correct after send frame"); + } +} + +void test_switch_color_stop_level_change_happy_case() +{ + helper_set_version(3); + + uint8_t mask_1 = 0x1C; + uint8_t mask_2 = 0x00; + uint16_t bitmask_tested = (mask_2 << 8) | mask_1; // 0000 0000 0001 1100 + uint8_t stop_change_node_tested = 1; + uint8_t stop_change_node_finnal_state = FINAL_STATE; + + auto component_mask_node = helper_get_component_maks_node(); + helper_test_report_frame(SWITCH_COLOR_SUPPORTED_REPORT, {mask_1, mask_2}); + + // Verify that the value of color component mask is updated + TEST_ASSERT_EQUAL_MESSAGE(bitmask_tested, + component_mask_node.reported(), + "Value of color component mask isn't updated after report"); + + auto vector_supported_node_id = get_supported_color_component_id_node(bitmask_tested); + + for (auto color_component_id_node : vector_supported_node_id) { + + // Get color start change node and set desired value + auto stop_change_node = helper_get_stop_change_node_from_color_component_id_node(color_component_id_node); + stop_change_node.set_desired(stop_change_node_tested); + + // attribute_store_log(); + helper_test_get_set_frame_happy_case(SWITCH_COLOR_STOP_LEVEL_CHANGE, + stop_change_node, + {color_component_id_node.reported()}); + + //Verify start leve change = 0 after send frame + TEST_ASSERT_EQUAL_MESSAGE(stop_change_node_finnal_state, + stop_change_node.reported(), + "Value of stop change isn't updated correct after send frame"); + } +} + +void test_switch_color_stop_level_change_invalid_stop_change_value() +{ + helper_set_version(3); + + uint8_t mask_1 = 0x1C; + uint8_t mask_2 = 0x00; + uint16_t bitmask_tested = (mask_2 << 8) | mask_1; // 0000 0000 0001 1100 + uint8_t stop_change_node_tested = 2; + uint8_t stop_change_node_finnal_state = FINAL_STATE; + + auto component_mask_node = helper_get_component_maks_node(); + helper_test_report_frame(SWITCH_COLOR_SUPPORTED_REPORT, {mask_1, mask_2}); + + // Verify that the value of color component mask is updated + TEST_ASSERT_EQUAL_MESSAGE(bitmask_tested, + component_mask_node.reported(), + "Value of color component mask isn't updated after report"); + + auto vector_supported_node_id = get_supported_color_component_id_node(bitmask_tested); + + for (auto color_component_id_node : vector_supported_node_id) { + + // Get color start change node and set desired value + auto stop_change_node = helper_get_stop_change_node_from_color_component_id_node(color_component_id_node); + stop_change_node.set_desired(stop_change_node_tested); + + // attribute_store_log(); + + helper_test_get_set_fail_case(SWITCH_COLOR_STOP_LEVEL_CHANGE, + SL_STATUS_FAIL, + stop_change_node); + + //Verify start leve change = 0 after send frame + TEST_ASSERT_EQUAL_MESSAGE(stop_change_node_finnal_state, + stop_change_node.reported(), + "Value of stop change isn't updated correct after send frame"); + } +} + +void test_switch_color_set_v1_happy_case() +{ + helper_set_version(1); + + uint8_t mask_1 = 0x1C; + uint8_t mask_2 = 0x00; + uint16_t bitmask_tested = (mask_2 << 8) | mask_1; // 0000 0000 0001 1100 + uint8_t value_reported_tested = 0xAB; + uint8_t value_desired_tested = 0xCD; + attribute_store::attribute value_node_tested; + + std::vector arg_tested_frame; + + auto component_mask_node = helper_get_component_maks_node(); + helper_test_report_frame(SWITCH_COLOR_SUPPORTED_REPORT, {mask_1, mask_2}); + + // Verify that the value of color component mask is updated + TEST_ASSERT_EQUAL_MESSAGE(bitmask_tested, + component_mask_node.reported(), + "Value of color component mask isn't updated after report"); + + auto vector_supported_node_id = get_supported_color_component_id_node(bitmask_tested); + + for (auto color_component_id_node : vector_supported_node_id) { + + //Send report frame to initialize the value + helper_test_report_frame(SWITCH_COLOR_REPORT, {color_component_id_node.reported(), value_reported_tested}); + + attribute_store::attribute value_node = helper_get_value_node_from_color_component_id_node(color_component_id_node); + value_node.set_desired(value_desired_tested); + + arg_tested_frame.push_back(color_component_id_node.reported()); + arg_tested_frame.push_back(value_desired_tested); + + value_node_tested = value_node; + } + + // attribute_store_log(); + + helper_test_get_set_frame_happy_case(SWITCH_COLOR_SET, + value_node_tested, + arg_tested_frame); +} + + + +void test_switch_color_set_v2_happy_case() +{ + helper_set_version(2); + + uint8_t mask_1 = 0x1C; + uint8_t mask_2 = 0x00; + uint16_t bitmask_tested = (mask_2 << 8) | mask_1; // 0000 0000 0001 1100 + uint8_t value_reported_tested = 0xAB; + uint8_t value_desired_tested = 0xCD; + uint8_t value_duration_tested = 100; + attribute_store::attribute value_node_tested; + + std::vector arg_tested_frame; + + auto component_mask_node = helper_get_component_maks_node(); + helper_test_report_frame(SWITCH_COLOR_SUPPORTED_REPORT, {mask_1, mask_2}); + + // Verify that the value of color component mask is updated + TEST_ASSERT_EQUAL_MESSAGE(bitmask_tested, + component_mask_node.reported(), + "Value of color component mask isn't updated after report"); + + //Get state node form endpoint node + auto vector_state_node = cpp_endpoint_id_node.children(ATTRIBUTE(STATE)); + attribute_store::attribute state_node(vector_state_node.front()); + + auto vector_supported_node_id = get_supported_color_component_id_node(bitmask_tested); + + for (auto color_component_id_node : vector_supported_node_id) { + + //Send report frame to initialize the value + helper_test_report_frame(SWITCH_COLOR_REPORT, {color_component_id_node.reported(), value_reported_tested}); + + attribute_store::attribute value_node = helper_get_value_node_from_color_component_id_node(color_component_id_node); + value_node.set_desired(value_desired_tested); + + arg_tested_frame.push_back(color_component_id_node.reported()); + arg_tested_frame.push_back(value_desired_tested); + + value_node_tested = value_node; + } + + // attribute_store_log(); + + attribute_store::attribute duration_node = helper_get_duration_node(); + duration_node.set_desired(value_duration_tested); + + arg_tested_frame.push_back(value_duration_tested); + + auto supported_color_component_count = attribute_store_get_node_child_count_by_type(state_node, + ATTRIBUTE(COLOR_COMPONENT_ID)); + arg_tested_frame.insert(arg_tested_frame.begin(), (uint8_t)supported_color_component_count); + + helper_test_get_set_frame_happy_case(SWITCH_COLOR_SET_V2, + value_node_tested, + arg_tested_frame); +} + +} \ No newline at end of file From 0a9da54882f61b7a4983610c083d7cba702ac0a4 Mon Sep 17 00:00:00 2001 From: Viet Date: Wed, 11 Sep 2024 18:17:01 +0700 Subject: [PATCH 05/10] UIC-3272: Custom Switch Color cluster Origin: https://github.com/SiliconLabsSoftware/z-wave-protocol-controller/pull/146 Signed-off-by: Philippe Coval --- .../zcl_cluster_servers/CMakeLists.txt | 1 + .../src/switch_color_cluster_server.cpp | 322 ++++++++++++ .../src/switch_color_cluster_server.h | 46 ++ .../src/zcl_cluster_servers.cpp | 2 + .../zcl_cluster_servers/test/CMakeLists.txt | 17 +- .../test/switch_color_cluster_server_test.c | 470 ++++++++++++++++++ 6 files changed, 857 insertions(+), 1 deletion(-) create mode 100644 applications/zpc/components/zcl_cluster_servers/src/switch_color_cluster_server.cpp create mode 100644 applications/zpc/components/zcl_cluster_servers/src/switch_color_cluster_server.h create mode 100644 applications/zpc/components/zcl_cluster_servers/test/switch_color_cluster_server_test.c diff --git a/applications/zpc/components/zcl_cluster_servers/CMakeLists.txt b/applications/zpc/components/zcl_cluster_servers/CMakeLists.txt index bef0569bc..2e4215344 100644 --- a/applications/zpc/components/zcl_cluster_servers/CMakeLists.txt +++ b/applications/zpc/components/zcl_cluster_servers/CMakeLists.txt @@ -18,6 +18,7 @@ add_library( src/zcl_OTA_cluster_server.cpp src/zcl_rf_telemetry_cluster_server.c src/zcl_scenes_cluster_server.cpp + src/switch_color_cluster_server.cpp ) target_include_directories( diff --git a/applications/zpc/components/zcl_cluster_servers/src/switch_color_cluster_server.cpp b/applications/zpc/components/zcl_cluster_servers/src/switch_color_cluster_server.cpp new file mode 100644 index 000000000..78c39b3c8 --- /dev/null +++ b/applications/zpc/components/zcl_cluster_servers/src/switch_color_cluster_server.cpp @@ -0,0 +1,322 @@ + +/****************************************************************************** + * # License + * Copyright 2021 Silicon Laboratories Inc. www.silabs.com + ****************************************************************************** + * The licensor of this software is Silicon Laboratories Inc. Your use of this + * software is governed by the terms of Silicon Labs Master Software License + * Agreement (MSLA) available at + * www.silabs.com/about-us/legal/master-software-license-agreement. This + * software is distributed to you in Source Code format and is governed by the + * sections of the MSLA applicable to Source Code. + * + *****************************************************************************/ +// Includes from this component +#include "switch_color_cluster_server.h" + +// Includes from Unify +#include "sl_log.h" +#include "sl_status.h" +#include "attribute_store_helper.h" +#include "attribute_store.h" +#include "zpc_attribute_store_network_helper.h" +#include "zwave_command_class_color_switch_types.h" + +#include "attribute_store_defined_attribute_types.h" +#include "unify_dotdot_defined_attribute_types.h" +#include "unify_dotdot_attribute_store.h" +#include "unify_dotdot_attribute_store_node_state.h" +#include "unify_dotdot_attribute_store_helpers.h" + +// Includes from auto-generated files +#include "dotdot_mqtt.h" + +// Cpp include +#include "attribute.hpp" + +// Setup Log ID +#define LOG_TAG "switch_color_cluster_server" + +// Attribute macro, shortening those long defines for attribute types: +#define ATTRIBUTE(type) ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_##type + +//////////////////////////////////////////////////////////////////////////////// +// Private helper functions +//////////////////////////////////////////////////////////////////////////////// +attribute_store_node_t + get_state_node_by_unid_endpoint(dotdot_unid_t unid, + attribute_store_node_t endpoint) +{ + attribute_store::attribute endpoint_node + = attribute_store_network_helper_get_endpoint_node(unid, endpoint); + return endpoint_node.child_by_type(ATTRIBUTE(STATE)); +} + +attribute_store_node_t + get_duration_node_by_unid_endpoint(dotdot_unid_t unid, + attribute_store_node_t endpoint) +{ + attribute_store::attribute state_node + = get_state_node_by_unid_endpoint(unid, endpoint); + attribute_store::attribute duration_node + = state_node.child_by_type(ATTRIBUTE(DURATION)); + + return duration_node; +} + +attribute_store_node_t + get_up_down_node_by_unid_endpoint(dotdot_unid_t unid, + attribute_store_node_t endpoint) +{ + attribute_store::attribute state_node + = get_state_node_by_unid_endpoint(unid, endpoint); + attribute_store::attribute up_down + = state_node.child_by_type(ATTRIBUTE(UP_DOWN)); + + return up_down; +} + +attribute_store_node_t + get_ignore_start_level_node_by_unid_endpoint(dotdot_unid_t unid, + attribute_store_node_t endpoint) +{ + attribute_store::attribute state_node + = get_state_node_by_unid_endpoint(unid, endpoint); + attribute_store::attribute ignore_start_level_node + = state_node.child_by_type(ATTRIBUTE(IGNORE_START_LEVEL)); + + return ignore_start_level_node; +} + +attribute_store_node_t + get_start_level_node_by_unid_endpoint(dotdot_unid_t unid, + attribute_store_node_t endpoint) +{ + attribute_store::attribute state_node + = get_state_node_by_unid_endpoint(unid, endpoint); + attribute_store::attribute start_level_node + = state_node.child_by_type(ATTRIBUTE(START_LEVEL)); + + return start_level_node; +} + +attribute_store_node_t + get_start_change_node_by_unid_endpoint_color_component_id( + dotdot_unid_t unid, + attribute_store_node_t endpoint, + uint8_t color_component_id) +{ + attribute_store::attribute state_node + = get_state_node_by_unid_endpoint(unid, endpoint); + attribute_store::attribute color_component_id_node + = state_node.child_by_type_and_value(ATTRIBUTE(COLOR_COMPONENT_ID), + color_component_id); + + attribute_store::attribute start_change_node + = color_component_id_node.child_by_type(ATTRIBUTE(START_CHANGE)); + + return start_change_node; +} + +attribute_store_node_t get_stop_change_node_by_unid_endpoint_color_component_id( + dotdot_unid_t unid, + attribute_store_node_t endpoint, + uint8_t color_component_id) +{ + attribute_store::attribute state_node + = get_state_node_by_unid_endpoint(unid, endpoint); + attribute_store::attribute color_component_id_node + = state_node.child_by_type_and_value(ATTRIBUTE(COLOR_COMPONENT_ID), + color_component_id); + + attribute_store::attribute stop_change_node + = color_component_id_node.child_by_type(ATTRIBUTE(STOP_CHANGE)); + + return stop_change_node; +} + +sl_status_t unify_switch_color_cluster_set_color_command( + const dotdot_unid_t unid, + const dotdot_endpoint_id_t endpoint, + uic_mqtt_dotdot_callback_call_type_t callback_type, + uint8_t color_component_id, + uint8_t value, + uint32_t duration) +{ + try { + if (callback_type == UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK) { + return dotdot_is_any_unify_switch_color_attribute_supported(unid, + endpoint) + ? SL_STATUS_OK + : SL_STATUS_FAIL; + } + + sl_log_debug(LOG_TAG, + "Updating ZCL desired values after Unify_SwitchColor::Set " + "command. color_component_id: %d, value :%d, duration : %d", + color_component_id, + value, + duration); + + sl_status_t result = SL_STATUS_FAIL; + + //Set value for attribute by color component id + switch (color_component_id) { + case WARM_WHITE: + result = dotdot_set_unify_switch_color_warm_white(unid, + endpoint, + DESIRED_ATTRIBUTE, + value); + break; + case COLD_WHITE: + result = dotdot_set_unify_switch_color_cold_white(unid, + endpoint, + DESIRED_ATTRIBUTE, + value); + break; + case RED: + result = dotdot_set_unify_switch_color_red(unid, + endpoint, + DESIRED_ATTRIBUTE, + value); + break; + case GREEN: + result = dotdot_set_unify_switch_color_green(unid, + endpoint, + DESIRED_ATTRIBUTE, + value); + break; + case BLUE: + result = dotdot_set_unify_switch_color_blue(unid, + endpoint, + DESIRED_ATTRIBUTE, + value); + break; + case AMBER: + result = dotdot_set_unify_switch_color_amber(unid, + endpoint, + DESIRED_ATTRIBUTE, + value); + break; + case CYAN: + result = dotdot_set_unify_switch_color_cyan(unid, + endpoint, + DESIRED_ATTRIBUTE, + value); + break; + case PURPLE: + result = dotdot_set_unify_switch_color_purple(unid, + endpoint, + DESIRED_ATTRIBUTE, + value); + break; + default: + sl_log_debug( + LOG_TAG, + "Invalid Colol Component ID Unify_SwitchColor::Set command"); + break; + } + + if (result != SL_STATUS_OK) { + sl_log_warning(LOG_TAG, "Can't set value for Unify Switch Color cluster"); + return SL_STATUS_FAIL; + } + // Find duration node and set desired value + attribute_store::attribute duration_node + = get_duration_node_by_unid_endpoint(unid, endpoint); + if (duration_node.is_valid()) { + duration_node.set_desired(duration); + } + } catch (const std::exception &e) { + sl_log_error( + LOG_TAG, + "Error while handle unify_switch_color_cluster_set_color_command : %s", + e.what()); + return SL_STATUS_FAIL; + } + return SL_STATUS_OK; +} + +sl_status_t unify_switch_color_cluster_start_stop_change_command( + const dotdot_unid_t unid, + const dotdot_endpoint_id_t endpoint, + uic_mqtt_dotdot_callback_call_type_t callback_type, + bool start_stop, + bool up_down, + bool ignor_start_level, + uint8_t color_component_id, + uint8_t start_level, + uint32_t duration) +{ + try { + if (callback_type == UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK) { + return dotdot_is_any_unify_switch_color_attribute_supported(unid, + endpoint) + ? SL_STATUS_OK + : SL_STATUS_FAIL; + } + + sl_log_debug(LOG_TAG, + "Updating ZCL desired values after Unify_SwitchColor::Start " + "Stop Change command"); + + // Find duration node and set desired value + attribute_store::attribute duration_node + = get_duration_node_by_unid_endpoint(unid, endpoint); + if (duration_node.is_valid()) { + duration_node.set_desired(duration); + } + + // Find up down node and set desired value + attribute_store::attribute up_down_node + = get_up_down_node_by_unid_endpoint(unid, endpoint); + up_down_node.set_desired(up_down); + + // Find irnore start level node and set desired value + attribute_store::attribute ignore_start_level_node + = get_ignore_start_level_node_by_unid_endpoint(unid, endpoint); + ignore_start_level_node.set_desired(ignor_start_level); + + // Find start level node and set desired value + attribute_store::attribute start_level_node + = get_start_level_node_by_unid_endpoint(unid, endpoint); + start_level_node.set_desired(start_level); + + if (start_stop) { + attribute_store::attribute start_change_node + = get_start_change_node_by_unid_endpoint_color_component_id( + unid, + endpoint, + color_component_id); + start_change_node.set_desired(start_stop); + } else { + attribute_store::attribute stop_change_node + = get_stop_change_node_by_unid_endpoint_color_component_id( + unid, + endpoint, + color_component_id); + stop_change_node.set_desired(!start_stop); + } + } catch (const std::exception &e) { + sl_log_error(LOG_TAG, + "Error while handle " + "unify_switch_color_cluster_start_stop_change_command : %s", + e.what()); + return SL_STATUS_FAIL; + } + return SL_STATUS_OK; +} + +/////////////////////////////////////////////////////////////////////////////// +// Init and teardown functions +/////////////////////////////////////////////////////////////////////////////// +sl_status_t switch_color_cluster_server_init() +{ + sl_log_debug(LOG_TAG, "SwitchColor cluster (ZWave) server initialization"); + + uic_mqtt_dotdot_unify_switch_color_set_color_callback_set( + &unify_switch_color_cluster_set_color_command); + uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_set( + &unify_switch_color_cluster_start_stop_change_command); + return SL_STATUS_OK; +} diff --git a/applications/zpc/components/zcl_cluster_servers/src/switch_color_cluster_server.h b/applications/zpc/components/zcl_cluster_servers/src/switch_color_cluster_server.h new file mode 100644 index 000000000..11e5cbe80 --- /dev/null +++ b/applications/zpc/components/zcl_cluster_servers/src/switch_color_cluster_server.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * # License + * Copyright 2024 Silicon Laboratories Inc. www.silabs.com + ****************************************************************************** + * The licensor of this software is Silicon Laboratories Inc. Your use of this + * software is governed by the terms of Silicon Labs Master Software License + * Agreement (MSLA) available at + * www.silabs.com/about-us/legal/master-software-license-agreement. This + * software is distributed to you in Source Code format and is governed by the + * sections of the MSLA applicable to Source Code. + * + *****************************************************************************/ + +/** + * @defgroup zpc_on_off_cluster_mapper ZPC Fan Control + * @ingroup dotdot_mapper + * @brief Maps OnOff Cluster incoming Commands to attribute modifications. + * + * @{ + */ + +#ifndef SWITCH_COLOR_CLUSTER_SERVER_H +#define SWITCH_COLOR_CLUSTER_SERVER_H + +// Generic includes +#include "sl_status.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize the FanControl cluster server + * + * @returns true on success + * @returns false on failure + * + */ +sl_status_t switch_color_cluster_server_init(void); + +#ifdef __cplusplus +} +#endif + +#endif //SWITCH_COLOR_CLUSTER_SERVER_H +/** @} end switch_color_cluster_server */ diff --git a/applications/zpc/components/zcl_cluster_servers/src/zcl_cluster_servers.cpp b/applications/zpc/components/zcl_cluster_servers/src/zcl_cluster_servers.cpp index 43bc4c385..52cfd1d80 100644 --- a/applications/zpc/components/zcl_cluster_servers/src/zcl_cluster_servers.cpp +++ b/applications/zpc/components/zcl_cluster_servers/src/zcl_cluster_servers.cpp @@ -20,6 +20,7 @@ #include "user_code_cluster_server.h" #include "fan_control_cluster_server.h" #include "user_credential_cluster_server.h" +#include "switch_color_cluster_server.cpp" //Includes from other components #include "attribute_store.h" @@ -44,6 +45,7 @@ sl_status_t zcl_cluster_servers_init() init_status |= user_code_cluster_server_init(); init_status |= fan_control_cluster_server_init(); init_status |= user_credential_cluster_server_init(); + init_status |= switch_color_cluster_server_init(); return init_status; } diff --git a/applications/zpc/components/zcl_cluster_servers/test/CMakeLists.txt b/applications/zpc/components/zcl_cluster_servers/test/CMakeLists.txt index 6112d25e8..da646b28b 100644 --- a/applications/zpc/components/zcl_cluster_servers/test/CMakeLists.txt +++ b/applications/zpc/components/zcl_cluster_servers/test/CMakeLists.txt @@ -142,4 +142,19 @@ target_add_unittest( uic_mqtt_stub uic_attribute_store unify) -target_include_directories(user_credential_cluster_server_test PRIVATE ../src) \ No newline at end of file +target_include_directories(user_credential_cluster_server_test PRIVATE ../src) + + # Switch Color Server test +target_add_unittest( + zcl_cluster_servers + NAME + switch_color_cluster_server_test + SOURCES + switch_color_cluster_server_test.c + DEPENDS + zpc_attribute_store_test_helper + uic_dotdot_mqtt_mock + uic_mqtt_stub + uic_contiki_stub + unify) + diff --git a/applications/zpc/components/zcl_cluster_servers/test/switch_color_cluster_server_test.c b/applications/zpc/components/zcl_cluster_servers/test/switch_color_cluster_server_test.c new file mode 100644 index 000000000..88a6a3c00 --- /dev/null +++ b/applications/zpc/components/zcl_cluster_servers/test/switch_color_cluster_server_test.c @@ -0,0 +1,470 @@ +/****************************************************************************** + * # License + * Copyright 2022 Silicon Laboratories Inc. www.silabs.com + ****************************************************************************** + * The licensor of this software is Silicon Laboratories Inc. Your use of this + * software is governed by the terms of Silicon Labs Master Software License + * Agreement (MSLA) available at + * www.silabs.com/about-us/legal/master-software-license-agreement. This + * software is distributed to you in Source Code format and is governed by the + * sections of the MSLA applicable to Source Code. + * + *****************************************************************************/ +#include "switch_color_cluster_server.h" +#include "unify_dotdot_attribute_store.h" +#include "unity.h" + +// Unify components +#include "datastore.h" +#include "attribute_store_fixt.h" +#include "attribute_store_helper.h" +#include "unify_dotdot_defined_attribute_types.h" +#include "dotdot_mqtt_mock.h" + +// ZPC Components +#include "zwave_unid.h" +#include "zwave_command_class_thermostat_fan_types.h" + +// Test helpers +#include "zpc_attribute_store_test_helper.h" +#include "attribute_store_defined_attribute_types.h" + +#define ATTRIBUTE(type) ATTRIBUTE_COMMAND_CLASS_SWITCH_COLOR_##type + +static uic_mqtt_dotdot_unify_switch_color_set_color_callback_t set_color_command = NULL; +static uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_t start_stop_change_command = NULL; + +void uic_mqtt_dotdot_unify_switch_color_set_color_callback_set_stub( + const uic_mqtt_dotdot_unify_switch_color_set_color_callback_t callback, + int cmock_num_calls) +{ + set_color_command = callback; +} + +void uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_set_stub( + const uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_t callback, + int cmock_num_calls) +{ + start_stop_change_command = callback; +} + +/// Setup the test suite (called once before all test_xxx functions are called) +void suiteSetUp() +{ + datastore_init(":memory:"); + attribute_store_init(); +} + +/// Teardown the test suite (called once after all test_xxx functions are called) +int suiteTearDown(int num_failures) +{ + attribute_store_teardown(); + datastore_teardown(); + return num_failures; +} + +/// Called before each and every test +void setUp() +{ + zpc_attribute_store_test_helper_create_network(); + + set_color_command = NULL; + start_stop_change_command = NULL; + + uic_mqtt_dotdot_unify_switch_color_set_color_callback_set_Stub(&uic_mqtt_dotdot_unify_switch_color_set_color_callback_set_stub); + uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_set_Stub(&uic_mqtt_dotdot_unify_switch_color_start_stop_change_callback_set_stub); + + // Call init + TEST_ASSERT_EQUAL(SL_STATUS_OK, switch_color_cluster_server_init()); +} + +/// Called after each and every test +void tearDown() +{ + attribute_store_delete_node(attribute_store_get_root()); +} + +void test_color_set_command_v1_happy_case() +{ + TEST_ASSERT_NOT_NULL(set_color_command); + + const uint8_t color_component_id_tested = 3; //Green Color + const uint8_t value_tested = 0xAB; + const uint16_t duration_tested = 100; + + // It should not work since we don't have the attribute yet + TEST_ASSERT_EQUAL(SL_STATUS_FAIL, + set_color_command(supporting_node_unid, + endpoint_id, + UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK, + color_component_id_tested, + value_tested, + duration_tested)); + + // Simulate that the nodes is created by an another function + attribute_store_node_t green_node = attribute_store_add_node(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN, + endpoint_id_node); + + // Test support + TEST_ASSERT_EQUAL(SL_STATUS_OK, + set_color_command(supporting_node_unid, + endpoint_id, + UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK, + color_component_id_tested, + value_tested, + duration_tested)); + + // Test callback + TEST_ASSERT_EQUAL(SL_STATUS_OK, + set_color_command(supporting_node_unid, + endpoint_id, + UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL, + color_component_id_tested, + value_tested, + duration_tested)); + + uint8_t color_value = 0; + + TEST_ASSERT_EQUAL_MESSAGE( + SL_STATUS_OK, + attribute_store_get_desired(green_node, &color_value, sizeof(color_value)), + "Can't get color value"); + + // Test value + TEST_ASSERT_EQUAL(value_tested, color_value); +} + +void test_color_set_command_v2_happy_case() +{ + TEST_ASSERT_NOT_NULL(set_color_command); + + const uint8_t color_component_id_tested = 3; //Green Color + const uint8_t value_tested = 0xAB; + const uint16_t duration_tested = 100; + + // It should not work since we don't have the attribute yet + TEST_ASSERT_EQUAL(SL_STATUS_FAIL, + set_color_command(supporting_node_unid, + endpoint_id, + UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK, + color_component_id_tested, + value_tested, + duration_tested)); + + // Simulate that the nodes is created by an another function + attribute_store_node_t green_node = attribute_store_add_node(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN, + endpoint_id_node); + + attribute_store_node_t state_node = attribute_store_add_node(ATTRIBUTE(STATE), + endpoint_id_node); + + attribute_store_node_t duration_node = attribute_store_add_node(ATTRIBUTE(DURATION), + state_node); + + // Test support + TEST_ASSERT_EQUAL(SL_STATUS_OK, + set_color_command(supporting_node_unid, + endpoint_id, + UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK, + color_component_id_tested, + value_tested, + duration_tested)); + + // Test callback + TEST_ASSERT_EQUAL(SL_STATUS_OK, + set_color_command(supporting_node_unid, + endpoint_id, + UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL, + color_component_id_tested, + value_tested, + duration_tested)); + + uint8_t color_value = 0; + uint32_t duration_value = 0; + + TEST_ASSERT_EQUAL_MESSAGE( + SL_STATUS_OK, + attribute_store_get_desired(green_node, &color_value, sizeof(color_value)), + "Can't get color value"); + + TEST_ASSERT_EQUAL_MESSAGE( + SL_STATUS_OK, + attribute_store_get_desired(duration_node, &duration_value, sizeof(duration_value)), + "Can't get duration value"); + + // Test value + TEST_ASSERT_EQUAL(value_tested, color_value); + TEST_ASSERT_EQUAL(duration_tested, duration_value); +} + +void test_color_set_command_v1_invalid_color_component_id() +{ + TEST_ASSERT_NOT_NULL(set_color_command); + + const uint8_t color_component_id_tested = 10; //Green Color + const uint8_t value_tested = 0xAB; + const uint16_t duration_tested = 100; + + // It should not work since we don't have the attribute yet + TEST_ASSERT_EQUAL(SL_STATUS_FAIL, + set_color_command(supporting_node_unid, + endpoint_id, + UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK, + color_component_id_tested, + value_tested, + duration_tested)); + + // Simulate that the nodes is created by an another function + attribute_store_add_node(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN, + endpoint_id_node); + + // Test support + TEST_ASSERT_EQUAL(SL_STATUS_OK, + set_color_command(supporting_node_unid, + endpoint_id, + UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK, + color_component_id_tested, + value_tested, + duration_tested)); + + // Test callback + TEST_ASSERT_EQUAL(SL_STATUS_FAIL, + set_color_command(supporting_node_unid, + endpoint_id, + UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL, + color_component_id_tested, + value_tested, + duration_tested)); +} + +void test_start_stop_change_command_start_change_happy_case() +{ + TEST_ASSERT_NOT_NULL(set_color_command); + + const bool start_stop_tested = 1; //Start change + const uint8_t start_change_value_tested = 1; + const bool up_down_tested = 1; + const bool ignor_start_level_tested = 1; + const uint8_t color_component_id_tested = 3; //Green Color; + const uint8_t start_level_tested = 0xAB; + const uint32_t duration_tested = 100; + + // It should not work since we don't have the attribute yet + TEST_ASSERT_EQUAL(SL_STATUS_FAIL, + start_stop_change_command(supporting_node_unid, + endpoint_id, + UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK, + start_stop_tested, + up_down_tested, + ignor_start_level_tested, + color_component_id_tested, + start_level_tested, + duration_tested)); + + // Simulate that the nodes is created by an another function + attribute_store_add_node(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN, + endpoint_id_node); + + attribute_store_node_t state_node = attribute_store_add_node(ATTRIBUTE(STATE), + endpoint_id_node); + attribute_store_node_t color_component_id_node = attribute_store_add_node(ATTRIBUTE(COLOR_COMPONENT_ID), + state_node); + + attribute_store_set_node_attribute_value(color_component_id_node, + REPORTED_ATTRIBUTE, + (uint8_t*)&color_component_id_tested, + sizeof(color_component_id_tested)); + + attribute_store_node_t start_change_node = attribute_store_add_node(ATTRIBUTE(START_CHANGE), + color_component_id_node); + + attribute_store_node_t duration_node = attribute_store_add_node(ATTRIBUTE(DURATION), + state_node); + + attribute_store_node_t up_down_node = attribute_store_add_node(ATTRIBUTE(UP_DOWN), + state_node); + + attribute_store_node_t ignore_start_level_node = attribute_store_add_node(ATTRIBUTE(IGNORE_START_LEVEL), + state_node); + + attribute_store_node_t start_level_node = attribute_store_add_node(ATTRIBUTE(START_LEVEL), + state_node); + + // Test support + TEST_ASSERT_EQUAL(SL_STATUS_OK, + start_stop_change_command(supporting_node_unid, + endpoint_id, + UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK, + start_stop_tested, + up_down_tested, + ignor_start_level_tested, + color_component_id_tested, + start_level_tested, + duration_tested)); + + // Test callback + TEST_ASSERT_EQUAL(SL_STATUS_OK, + start_stop_change_command(supporting_node_unid, + endpoint_id, + UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL, + start_stop_tested, + up_down_tested, + ignor_start_level_tested, + color_component_id_tested, + start_level_tested, + duration_tested)); + + uint8_t start_change_value = 0; + uint8_t up_down_value = 0; + uint8_t ignor_start_level_value = 0; + uint8_t start_level_value = 0; + uint32_t duration_value = 0; + + TEST_ASSERT_EQUAL_MESSAGE( + SL_STATUS_OK, + attribute_store_get_desired(start_change_node, &start_change_value, sizeof(start_change_value)), + "Can't get start change value"); + + TEST_ASSERT_EQUAL_MESSAGE( + SL_STATUS_OK, + attribute_store_get_desired(up_down_node, &up_down_value, sizeof(up_down_value)), + "Can't get up down value"); + + TEST_ASSERT_EQUAL_MESSAGE( + SL_STATUS_OK, + attribute_store_get_desired(ignore_start_level_node, &ignor_start_level_value, sizeof(ignor_start_level_value)), + "Can't get ignore start level value"); + + TEST_ASSERT_EQUAL_MESSAGE( + SL_STATUS_OK, + attribute_store_get_desired(start_level_node, &start_level_value, sizeof(start_level_value)), + "Can't get tart level value"); + + TEST_ASSERT_EQUAL_MESSAGE( + SL_STATUS_OK, + attribute_store_get_desired(duration_node, &duration_value, sizeof(duration_value)), + "Can't get duration value"); + + // Test value + TEST_ASSERT_EQUAL(start_change_value_tested, start_change_value); + TEST_ASSERT_EQUAL(up_down_tested, up_down_value); + TEST_ASSERT_EQUAL(ignor_start_level_tested, ignor_start_level_value); + TEST_ASSERT_EQUAL(start_level_tested, start_level_value); + TEST_ASSERT_EQUAL(duration_tested, duration_value); +} + +void test_start_stop_change_command_stop_change_happy_case() +{ + TEST_ASSERT_NOT_NULL(set_color_command); + + const bool start_stop_tested = 0; //Stop change + const uint8_t stop_change_value_tested = 1; + const bool up_down_tested = 1; + const bool ignor_start_level_tested = 1; + const uint8_t color_component_id_tested = 3; //Green Color; + const uint8_t start_level_tested = 0xAB; + const uint32_t duration_tested = 100; + + // It should not work since we don't have the attribute yet + TEST_ASSERT_EQUAL(SL_STATUS_FAIL, + start_stop_change_command(supporting_node_unid, + endpoint_id, + UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK, + start_stop_tested, + up_down_tested, + ignor_start_level_tested, + color_component_id_tested, + start_level_tested, + duration_tested)); + + // Simulate that the nodes is created by an another function + attribute_store_add_node(DOTDOT_ATTRIBUTE_ID_UNIFY_SWITCH_COLOR_GREEN, + endpoint_id_node); + + attribute_store_node_t state_node = attribute_store_add_node(ATTRIBUTE(STATE), + endpoint_id_node); + attribute_store_node_t color_component_id_node = attribute_store_add_node(ATTRIBUTE(COLOR_COMPONENT_ID), + state_node); + + attribute_store_set_node_attribute_value(color_component_id_node, + REPORTED_ATTRIBUTE, + (uint8_t*)&color_component_id_tested, + sizeof(color_component_id_tested)); + + attribute_store_node_t stop_change_node = attribute_store_add_node(ATTRIBUTE(STOP_CHANGE), + color_component_id_node); + + attribute_store_node_t duration_node = attribute_store_add_node(ATTRIBUTE(DURATION), + state_node); + + attribute_store_node_t up_down_node = attribute_store_add_node(ATTRIBUTE(UP_DOWN), + state_node); + + attribute_store_node_t ignore_start_level_node = attribute_store_add_node(ATTRIBUTE(IGNORE_START_LEVEL), + state_node); + + attribute_store_node_t start_level_node = attribute_store_add_node(ATTRIBUTE(START_LEVEL), + state_node); + + // Test support + TEST_ASSERT_EQUAL(SL_STATUS_OK, + start_stop_change_command(supporting_node_unid, + endpoint_id, + UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK, + start_stop_tested, + up_down_tested, + ignor_start_level_tested, + color_component_id_tested, + start_level_tested, + duration_tested)); + + // Test callback + TEST_ASSERT_EQUAL(SL_STATUS_OK, + start_stop_change_command(supporting_node_unid, + endpoint_id, + UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL, + start_stop_tested, + up_down_tested, + ignor_start_level_tested, + color_component_id_tested, + start_level_tested, + duration_tested)); + + uint8_t stop_change_value = 0; + uint8_t up_down_value = 0; + uint8_t ignor_start_level_value = 0; + uint8_t start_level_value = 0; + uint32_t duration_value = 0; + + TEST_ASSERT_EQUAL_MESSAGE( + SL_STATUS_OK, + attribute_store_get_desired(stop_change_node, &stop_change_value, sizeof(stop_change_value)), + "Can't get stop change value"); + + TEST_ASSERT_EQUAL_MESSAGE( + SL_STATUS_OK, + attribute_store_get_desired(up_down_node, &up_down_value, sizeof(up_down_value)), + "Can't get up down value"); + + TEST_ASSERT_EQUAL_MESSAGE( + SL_STATUS_OK, + attribute_store_get_desired(ignore_start_level_node, &ignor_start_level_value, sizeof(ignor_start_level_value)), + "Can't get ignore start level value"); + + TEST_ASSERT_EQUAL_MESSAGE( + SL_STATUS_OK, + attribute_store_get_desired(start_level_node, &start_level_value, sizeof(start_level_value)), + "Can't get tart level value"); + + TEST_ASSERT_EQUAL_MESSAGE( + SL_STATUS_OK, + attribute_store_get_desired(duration_node, &duration_value, sizeof(duration_value)), + "Can't get duration value"); + + // Test value + TEST_ASSERT_EQUAL(stop_change_value_tested, stop_change_value); + TEST_ASSERT_EQUAL(up_down_tested, up_down_value); + TEST_ASSERT_EQUAL(ignor_start_level_tested, ignor_start_level_value); + TEST_ASSERT_EQUAL(start_level_tested, start_level_value); + TEST_ASSERT_EQUAL(duration_tested, duration_value); +} \ No newline at end of file From 69dbf76419b27fb734ff1e1f89db79a90e394178 Mon Sep 17 00:00:00 2001 From: Viet Date: Thu, 12 Sep 2024 16:50:45 +0700 Subject: [PATCH 06/10] UIC-3272: Switch Color uam file Origin: https://github.com/SiliconLabsSoftware/z-wave-protocol-controller/pull/146 Signed-off-by: Philippe Coval --- .../dotdot_mapper/rules/SwitchColor.uam | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 applications/zpc/components/dotdot_mapper/rules/SwitchColor.uam diff --git a/applications/zpc/components/dotdot_mapper/rules/SwitchColor.uam b/applications/zpc/components/dotdot_mapper/rules/SwitchColor.uam new file mode 100644 index 000000000..4da4c0a5f --- /dev/null +++ b/applications/zpc/components/dotdot_mapper/rules/SwitchColor.uam @@ -0,0 +1,130 @@ + +// Swtich Color Command Class +def zwSTATE 0x3303 +def zwCOLOR_COMPONENT_ID 0x3304 +def zwVALUE 0x3305 + +// We have 7 Color Component ID. +def ZW_COLOR_ID_WARM_WHITE 0x00 +def ZW_COLOR_ID_COLD_WHITE 0x01 +def ZW_COLOR_ID_RED 0x02 +def ZW_COLOR_ID_GREEN 0x03 +def ZW_COLOR_ID_BLUE 0x04 +def ZW_COLOR_ID_AMBER 0x05 +def ZW_COLOR_ID_CYAN 0x06 +def ZW_COLOR_ID_PURPLE 0x07 + +// ZCL Swich Color cluster attributes +def zb_SWITCH_COLOR_WARM_WHITE 0xffa10000 +def zb_SWITCH_COLOR_COLD_WHITE 0xffa10001 +def zb_SWITCH_COLOR_RED 0xffa10002 +def zb_SWITCH_COLOR_GREEN 0xffa10003 +def zb_SWITCH_COLOR_BLUE 0xffa10004 +def zb_SWITCH_COLOR_AMBER 0xffa10005 +def zb_SWITCH_COLOR_CYAN 0xffa10006 +def zb_SWITCH_COLOR_PURPLE 0xffa10007 + + +scope 25 chain_reaction(0) { + + d'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_WARM_WHITE].zwVALUE = + if(e'zb_SWITCH_COLOR_WARM_WHITE) d'zb_SWITCH_COLOR_WARM_WHITE + undefined + d'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_COLD_WHITE].zwVALUE = + if(e'zb_SWITCH_COLOR_COLD_WHITE) d'zb_SWITCH_COLOR_COLD_WHITE + undefined + d'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_RED].zwVALUE = + if(e'zb_SWITCH_COLOR_RED) d'zb_SWITCH_COLOR_RED + undefined + d'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_GREEN].zwVALUE = + if(e'zb_SWITCH_COLOR_GREEN) d'zb_SWITCH_COLOR_GREEN + undefined + d'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_BLUE].zwVALUE = + if(e'zb_SWITCH_COLOR_BLUE) d'zb_SWITCH_COLOR_BLUE + undefined + d'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_AMBER].zwVALUE = + if(e'zb_SWITCH_COLOR_AMBER) d'zb_SWITCH_COLOR_AMBER + undefined + d'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_CYAN].zwVALUE = + if(e'zb_SWITCH_COLOR_CYAN) d'zb_SWITCH_COLOR_CYAN + undefined + d'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_PURPLE].zwVALUE = + if(e'zb_SWITCH_COLOR_PURPLE) d'zb_SWITCH_COLOR_PURPLE + undefined + + r'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_WARM_WHITE].zwVALUE = + if(e'zb_SWITCH_COLOR_WARM_WHITE) r'zb_SWITCH_COLOR_WARM_WHITE + undefined + r'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_COLD_WHITE].zwVALUE = + if(e'zb_SWITCH_COLOR_COLD_WHITE) r'zb_SWITCH_COLOR_COLD_WHITE + undefined + r'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_RED].zwVALUE = + if(e'zb_SWITCH_COLOR_RED) r'zb_SWITCH_COLOR_RED + undefined + r'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_GREEN].zwVALUE = + if(e'zb_SWITCH_COLOR_GREEN) r'zb_SWITCH_COLOR_GREEN + undefined + r'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_BLUE].zwVALUE = + if(e'zb_SWITCH_COLOR_BLUE) r'zb_SWITCH_COLOR_BLUE + undefined + r'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_AMBER].zwVALUE = + if(e'zb_SWITCH_COLOR_AMBER) r'zb_SWITCH_COLOR_AMBER + undefined + r'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_CYAN].zwVALUE = + if(e'zb_SWITCH_COLOR_CYAN) r'zb_SWITCH_COLOR_CYAN + undefined + r'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_PURPLE].zwVALUE = + if(e'zb_SWITCH_COLOR_PURPLE) r'zb_SWITCH_COLOR_PURPLE + undefined + + r'zb_SWITCH_COLOR_WARM_WHITE = + if(e'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_WARM_WHITE].zwVALUE) (r'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_WARM_WHITE].zwVALUE) + undefined + r'zb_SWITCH_COLOR_COLD_WHITE = + if(e'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_COLD_WHITE].zwVALUE) (r'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_COLD_WHITE].zwVALUE) + undefined + r'zb_SWITCH_COLOR_RED = + if(e'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_RED].zwVALUE) (r'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_RED].zwVALUE) + undefined + r'zb_SWITCH_COLOR_GREEN = + if(e'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_GREEN].zwVALUE) (r'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_GREEN].zwVALUE) + undefined + r'zb_SWITCH_COLOR_BLUE = + if(e'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_BLUE].zwVALUE) (r'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_BLUE].zwVALUE) + undefined + r'zb_SWITCH_COLOR_AMBER = + if(e'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_AMBER].zwVALUE) (r'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_AMBER].zwVALUE) + undefined + r'zb_SWITCH_COLOR_CYAN = + if(e'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_CYAN].zwVALUE) (r'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_CYAN].zwVALUE) + undefined + r'zb_SWITCH_COLOR_PURPLE = + if(e'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_PURPLE].zwVALUE) (r'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_PURPLE].zwVALUE) + undefined + + d'zb_SWITCH_COLOR_WARM_WHITE = + if(e'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_WARM_WHITE].zwVALUE) (d'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_WARM_WHITE].zwVALUE) + undefined + d'zb_SWITCH_COLOR_COLD_WHITE = + if(e'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_COLD_WHITE].zwVALUE) (d'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_COLD_WHITE].zwVALUE) + undefined + d'zb_SWITCH_COLOR_RED = + if(e'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_RED].zwVALUE) (d'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_RED].zwVALUE) + undefined + d'zb_SWITCH_COLOR_GREEN = + if(e'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_GREEN].zwVALUE) (d'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_GREEN].zwVALUE) + undefined + d'zb_SWITCH_COLOR_BLUE = + if(e'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_BLUE].zwVALUE) (d'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_BLUE].zwVALUE) + undefined + d'zb_SWITCH_COLOR_AMBER = + if(e'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_AMBER].zwVALUE) (d'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_AMBER].zwVALUE) + undefined + d'zb_SWITCH_COLOR_CYAN = + if(e'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_CYAN].zwVALUE) (d'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_CYAN].zwVALUE) + undefined + d'zb_SWITCH_COLOR_PURPLE = + if(e'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_PURPLE].zwVALUE) (d'zwSTATE.zwCOLOR_COMPONENT_ID[ZW_COLOR_ID_PURPLE].zwVALUE) + undefined +} + From 6005b6fe3406f06ea0bdcb8e8028d140fa49669f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Boris=20Labb=C3=A9?= Date: Mon, 24 Jun 2024 11:40:45 +0200 Subject: [PATCH 07/10] UIC-3272: Remove Switch Color rust implementation This one of the two classes still handled by rust. Since rust is only partially supported, we won't maintain this. Origin: https://github.com/SiliconLabsSoftware/z-wave-protocol-controller/pull/146 Signed-off-by: Philippe Coval --- .../zwave_command_classes/mod.rs | 2 - .../zwave_command_class_switch_color.rs | 530 ------------------ 2 files changed, 532 deletions(-) delete mode 100644 applications/zpc/components/zpc_rust/src/rust_command_handlers/zwave_command_classes/zwave_command_class_switch_color.rs diff --git a/applications/zpc/components/zpc_rust/src/rust_command_handlers/zwave_command_classes/mod.rs b/applications/zpc/components/zpc_rust/src/rust_command_handlers/zwave_command_classes/mod.rs index d7adceb9d..34673eb48 100644 --- a/applications/zpc/components/zpc_rust/src/rust_command_handlers/zwave_command_classes/mod.rs +++ b/applications/zpc/components/zpc_rust/src/rust_command_handlers/zwave_command_classes/mod.rs @@ -12,7 +12,5 @@ /////////////////////////////////////////////////////////////////////////////// pub mod zwave_command_class_firmware_update; -mod zwave_command_class_switch_color; pub use zwave_command_class_firmware_update::*; -pub use zwave_command_class_switch_color::*; diff --git a/applications/zpc/components/zpc_rust/src/rust_command_handlers/zwave_command_classes/zwave_command_class_switch_color.rs b/applications/zpc/components/zpc_rust/src/rust_command_handlers/zwave_command_classes/zwave_command_class_switch_color.rs deleted file mode 100644 index 278455d53..000000000 --- a/applications/zpc/components/zpc_rust/src/rust_command_handlers/zwave_command_classes/zwave_command_class_switch_color.rs +++ /dev/null @@ -1,530 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// # License -// Copyright 2021 Silicon Laboratories Inc. www.silabs.com -/////////////////////////////////////////////////////////////////////////////// -// The licensor of this software is Silicon Laboratories Inc. Your use of this -// software is governed by the terms of Silicon Labs Master Software License -// Agreement (MSLA) available at -// www.silabs.com/about-us/legal/master-software-license-agreement. This -// software is distributed to you in Source Code format and is governed by the -// sections of the MSLA applicable to Source Code. -// -/////////////////////////////////////////////////////////////////////////////// -#![allow( - missing_docs, - dead_code, - non_snake_case, - non_camel_case_types, - non_upper_case_globals -)] -use crate::rust_command_handlers::{ - zwave_command_class_definitions::{ConnectionInfoTrait, ZwaveControllerEncapsulationScheme}, - zwave_command_class_interface::{ - CommandClassConfigurationTrait, FrameControlSupportTrait, ZwaveVersionChangedTrait, - }, -}; -use crate::zwave_command_classes_sys::{ - is_zwave_command_class_filtered_for_root_device, sl_status_t, -}; -use rust_command_class_frame_types::command_class_switch_color::*; -use unify_attribute_resolver_sys::{ - attribute_resolver_register_rule, attribute_resolver_restart_set_resolution, - is_node_pending_set_resolution, -}; -use unify_log_sys::*; -use unify_middleware::{ - attribute_callback_by_type_and_state, attribute_store_or_return_with, Attribute, - AttributeEvent, AttributeEventType, AttributeStoreError, AttributeTrait, AttributeValueState, -}; -use unify_proc_macro::{as_extern_c, generate_resolver_callback}; -use unify_sl_status_sys::{map_to_sl_status_fail, SL_STATUS_FAIL, SL_STATUS_OK}; -use zwave_rust_proc_macros::zwave_command_class; - -/// Attribute definitions -const ATTRIBUTE_ENDPOINT_ID: u32 = 0x4; -const ATTRIBUTE_VERSION: u32 = 0x3301; -const ATTRIBUTE_SUPPORTED_COLOR_COMPONENT_MASK: u32 = 0x3302; -const ATTRIBUTE_STATE: u32 = 0x3303; -const ATTRIBUTE_COLOR_COMPONENT_ID: u32 = 0x3304; -const ATTRIBUTE_COLOR_VALUE: u32 = 0x3305; -const ATTRIBUTE_COLOR_DURATION: u32 = 0x3306; - -// Attribute types, copy from zwave_command_class_color_switch_types.h -type color_component_bitmask_t = u16; -type color_component_id_t = u8; -type color_component_id_value_t = u32; -type color_component_id_duration_t = u32; - -type command_status_values_t = u32; -const FINAL_STATE: command_status_values_t = 0; -const NEEDS_ONE_COMMAND: command_status_values_t = 1; -const NEEDS_MULTIPLE_COMMANDS: command_status_values_t = 2; - -declare_app_name!("zwave_command_class_switch_color_control"); - -fn on_value_update(event: &AttributeEvent) { - if event.event_type != AttributeEventType::ATTRIBUTE_UPDATED { - return; - } - // Verify if any of the values has a desired/reported mismatch under the state. - let mut command_needed = false; - - let state_node = match event.attribute.get_first_parent_with_type(ATTRIBUTE_STATE) { - Some(state) => state, - None => { - log_warning!("Cannot find state parent attribute for {}", event.attribute); - return; - } - }; - - let component_nodes = state_node.get_children_by_type(ATTRIBUTE_COLOR_COMPONENT_ID); - - // Verify if we have any mismatch - for component_node in &component_nodes { - let value_node = component_node.get_child_by_type(ATTRIBUTE_COLOR_VALUE); - if true == value_node.is_desired_set() && false == value_node.is_value_matched() { - command_needed = true; - break; - } - } - - if command_needed == true { - let _ = state_node - .set_reported(Some(FINAL_STATE)) - .and(state_node.set_desired(Some(NEEDS_ONE_COMMAND))); - if is_node_pending_set_resolution(state_node.handle) { - attribute_resolver_restart_set_resolution(state_node.handle); - } - } else { - let _ = state_node - .set_reported(Some(FINAL_STATE)) - .and(state_node.set_desired(Some(FINAL_STATE))); - } -} - -///////////////////////// Command class registration //////////////////// -#[zwave_command_class] -impl CommandClassConfigurationTrait for CommandClassSwitchColorFrame { - const COMMAND_CLASS_NAME: &'static str = "Color Switch"; - const MINIMAL_SCHEME: ZwaveControllerEncapsulationScheme = - ZwaveControllerEncapsulationScheme::ZwaveControllerEncapsulationNetworkScheme; - const COMMENTS: &'static str = "Partial Control:
1. Durations are ignored
2. No support for Start/Stop Level Change
3. No support for other Color Component IDs than 0,1,2,3,4"; - const MANUAL_SECURITY_VALIDATION: bool = false; - const INCLUDE_SUPPORT: bool = false; - const INCLUDE_CONTROL: bool = true; - - fn on_init() -> sl_status_t { - attribute_resolver_register_rule( - ATTRIBUTE_SUPPORTED_COLOR_COMPONENT_MASK, - None, - as_extern_c!(switch_color_supported_get), - ); - - attribute_resolver_register_rule(ATTRIBUTE_STATE, as_extern_c!(switch_color_set), None); - - attribute_resolver_register_rule( - ATTRIBUTE_COLOR_VALUE, - None, - as_extern_c!(switch_color_get), - ); - - attribute_callback_by_type_and_state( - ATTRIBUTE_COLOR_VALUE, - AttributeValueState::DESIRED_ATTRIBUTE, - on_value_update, - ); - attribute_callback_by_type_and_state( - ATTRIBUTE_COLOR_DURATION, - AttributeValueState::DESIRED_ATTRIBUTE, - on_value_update, - ); - - SL_STATUS_OK - } -} - -///////////////////////////// Version Update /////////////////////////////// -#[zwave_command_class] -impl ZwaveVersionChangedTrait for CommandClassSwitchColorFrame { - const ATTRIBUTE_STORE_TYPE: u32 = ATTRIBUTE_VERSION; - - fn on_attribute_version(ep: Attribute, version: u8) { - if unsafe { - is_zwave_command_class_filtered_for_root_device(COMMAND_CLASS_SWITCH_COLOR, ep.handle) - } == true - { - return; - } - - // Use any color component id at token for starting the supported get - if version > 0 { - if !ep - .get_child_by_type(ATTRIBUTE_SUPPORTED_COLOR_COMPONENT_MASK) - .valid() - { - let _ = ep.add::( - ATTRIBUTE_SUPPORTED_COLOR_COMPONENT_MASK, - None, - None, - ); - } - } - } -} - -/////////////////////////// Command Handlers /////////////////////////// -impl FrameControlSupportTrait for SwitchColorSupportedReportFrame { - fn on_control(&self, info: &dyn ConnectionInfoTrait) -> Result<(), sl_status_t> { - let ep = info.get_endpoint(); - - // Save the bitmask of supported component IDs in the attribute store - if let Err(e) = ep - .get_child_by_type(ATTRIBUTE_SUPPORTED_COLOR_COMPONENT_MASK) - .set_reported::(Some(self.color_component_mask)) - { - log_warning!("could not set bitmask for color component {}", e); - } - - let mut state_node = ep.get_child_by_type(ATTRIBUTE_STATE); - if !state_node.valid() { - state_node = ep - .add::(ATTRIBUTE_STATE, None, None) - .map_err(map_to_sl_status_fail)?; - } - - // Create the duration under the State node, if does not exist - if !state_node - .get_child_by_type(ATTRIBUTE_COLOR_DURATION) - .valid() - { - state_node - .add::(ATTRIBUTE_COLOR_DURATION, None, None) - .map_err(map_to_sl_status_fail)?; - } - - // The bits bitmask is byte reversed order with LSB bits in the first byte - let mask = (self.color_component_mask >> 8) | (self.color_component_mask & 0xff); - for i in 0..15 { - if (mask & (1 << i)) != 0 { - // Create all the attributes under the state (component IDs and their value/duration) - let component = state_node - .emplace::(ATTRIBUTE_COLOR_COMPONENT_ID, Some(i), None) - .map_err(map_to_sl_status_fail)?; - - // Create the value under the component, if does not exist - if !component.get_child_by_type(ATTRIBUTE_COLOR_VALUE).valid() { - component - .add::(ATTRIBUTE_COLOR_VALUE, None, None) - .map_err(map_to_sl_status_fail)?; - } - } - } - Ok(()) - } -} - -impl FrameControlSupportTrait for SwitchColorReportFrame { - fn on_control(&self, info: &dyn ConnectionInfoTrait) -> Result<(), sl_status_t> { - let ep = info.get_endpoint(); - - let state_node = ep.get_child_by_type(ATTRIBUTE_STATE); - let component_node = state_node.get_child_by_type_and_value( - ATTRIBUTE_COLOR_COMPONENT_ID, - &Some(self.color_component_id), - ); - let value_node = component_node.get_child_by_type(ATTRIBUTE_COLOR_VALUE); - let duration_node = state_node.get_child_by_type(ATTRIBUTE_COLOR_DURATION); - - if !value_node.valid() || !duration_node.valid() { - return Err(SL_STATUS_FAIL); - } - - value_node.stop_transition(); - - // UIC-1927 : change value_node.set_desired(current_value) to - // .set_desired::(Some(self.target_value.into())) - // This will trigger the Rust callbacks to invoke on_value_update() later on. - // which provokes that we try to set this desired value again. - - // Set all the values in the attribute store - value_node - .set_desired::(Some(self.current_value.into())) - .and( - value_node - .set_reported::(Some(self.current_value.into())), - ) - .and(duration_node.set_desired::(None)) - .and(duration_node.set_reported(Some(self.duration as color_component_id_duration_t))) - .map_err(map_to_sl_status_fail)?; - - // FIXME: UIC-1926 Here when we get the real duration, we want to - // do like in Multilevel switch: - // clock_time_t duration_time = zwave_duration_to_time(self.duration); - // value_node.start_transition(duration_time); - - // FIXME: UIC-1927 See above. this is normally how we prevent to resolve - // after updating the desired value ourselves. - // Make sure not to resolve Color Switch values if the node tells us its desired state - let _ = state_node - .set_reported(Some(FINAL_STATE)) - .and(state_node.set_desired(Some(FINAL_STATE))); - - log_debug!( - "NodeID {}:{} reported Color ID {} set to {}", - unsafe { info.get_remote().__bindgen_anon_1.node_id }, - info.get_remote().endpoint_id, - self.color_component_id, - self.current_value - ); - - Ok(()) - } -} - -/////////////////////// Command Generators ////////////////////////// - -#[generate_resolver_callback] -fn switch_color_get(value_node: Attribute) -> Result<(sl_status_t, Vec), AttributeStoreError> { - let component_node = value_node - .get_first_parent_with_type(ATTRIBUTE_COLOR_COMPONENT_ID) - .ok_or(AttributeStoreError::InvalidType)?; - let get_frame = SwitchColorGetFrame { - color_component_id: component_node.get_reported::()?, - }; - Ok((SL_STATUS_OK, get_frame.into())) -} - -#[generate_resolver_callback] -fn switch_color_set(state_node: Attribute) -> Result<(sl_status_t, Vec), AttributeStoreError> { - let mut colors = Vec::new(); - // FIXME: UIC-1926 Default should be 0xFF if we have no desired value in the - // attribute store. I really can't use SwitchColorSetDurationEnum::Default, which is 0 - // the "real" default value is 0xFF - let mut _duration: color_component_id_duration_t = 0xFF as color_component_id_duration_t; - // Check if this component has a desired duration - match state_node - .get_child_by_type(ATTRIBUTE_COLOR_DURATION) - .get_desired::() - { - Ok(desired_duration) => _duration = desired_duration, - Err(_) => (), - } - // Gather data tor all color components - for component in state_node.get_children_by_type(ATTRIBUTE_COLOR_COMPONENT_ID) { - let value_attribute = component.get_child_by_type(ATTRIBUTE_COLOR_VALUE); - let value: u32 = value_attribute.get_desired_or_reported::()?; - let color_value = SwitchColorSetVg1Vg { - color_component_id: component.get_reported::()?, - value: value as u8, - }; - colors.push(color_value); - } - - let set_frame = SwitchColorSetFrame { - properties1: SwitchColorSetProperties1Bits { - color_component_count: 0, //The component count is updated by the frame generator - reserved: 0, - }, - vg1: colors, - duration: _duration as u8, - }; - - Ok((SL_STATUS_OK, set_frame.into())) -} - -#[generate_resolver_callback] -fn switch_color_supported_get(_: Attribute) -> Result<(sl_status_t, Vec), AttributeStoreError> { - Ok((SL_STATUS_OK, (SwitchColorSupportedGetFrame {}).into())) -} - -//////////////////////////////////////// Tests /////////////////////////////////// -#[cfg(test)] -mod test { - use super::*; - use crate::zwave_command_class_definitions::MockConnectionInfoTrait; - use crate::zwave_controller_sys::zwave_controller_endpoint_t; - use serial_test::serial; - use std::ffi::CString; - use std::sync::Once; - use unify_middleware::AttributeStore; - use unify_middleware::AttributeStoreTrait; - - extern "C" { - pub fn datastore_init(database: *const std::os::raw::c_char) -> u32; - pub fn zpc_attribute_store_test_helper_create_network(); - pub fn attribute_store_log(); - } - - static INIT: Once = Once::new(); - pub fn initialize() { - INIT.call_once(|| unsafe { - let database_name = CString::new(":memory:").unwrap(); - assert_eq!(0, datastore_init(database_name.as_ptr())); - }); - AttributeStore::new().unwrap().root().delete().unwrap(); - } - - #[test] - #[serial] - fn test_on_interview() { - use std::convert::TryInto; - - initialize(); - let ep = AttributeStore::new().unwrap().root(); - - //Check that we create the first color component id - CommandClassSwitchColorFrame::on_attribute_version(ep, 2); - - // Check that we can handle a SUPPORTED report - let z = [0x33u8, 0x02u8, 0x03u8, 0x00u8]; - let f: CommandClassSwitchColorFrame = (z[..]).try_into().unwrap(); - - let mut mock_connection_info = MockConnectionInfoTrait::new(); - mock_connection_info - .expect_get_endpoint() - .times(1) - .return_const(ep); - - let status = f.on_control(&mock_connection_info); - assert_eq!(Ok(()), status); - - //Expect that we get two color components, 0 and 1 - let state = ep.get_child_by_type(ATTRIBUTE_STATE); - let components = state.get_children_by_type(ATTRIBUTE_COLOR_COMPONENT_ID); - - assert_eq!(2, components.len()); - assert_eq!( - 0, - components[0] - .get_reported::() - .unwrap() - ); - assert_eq!( - 1, - components[1] - .get_reported::() - .unwrap() - ); - - //Check that we can do a get - let value0 = components[0].get_child_by_type(ATTRIBUTE_COLOR_VALUE); - let duration = state.get_child_by_type(ATTRIBUTE_COLOR_DURATION); - let value1 = components[1].get_child_by_type(ATTRIBUTE_COLOR_VALUE); - - let mut frame_result = switch_color_get_rust(value0).unwrap(); - assert_eq!((SL_STATUS_OK, vec![0x33u8, 0x03u8, 0x00u8]), frame_result); - - frame_result = switch_color_get_rust(value1).unwrap(); - assert_eq!((SL_STATUS_OK, vec![0x33u8, 0x03u8, 0x01u8]), frame_result); - - // Check that we can handle a V3 report - // FIXME: UIC-1926 Frame parsing dies if duration is not one of these - // 3 values : SwitchColorReportDurationEnum - // We should be very tolerant in frame parsing and accept quirky values (event when they are out of spec) - // so stopping the frame parsing when a value is wrong is a bit strong here. - let z = [ - 0x33u8, 0x04u8, 0x01u8, 0x42u8, 0xaau8, 0xFEu8, 0x00u8, 0x00u8, 0x00u8, - ]; - let f: CommandClassSwitchColorFrame = (z[..]).try_into().unwrap(); - - mock_connection_info - .expect_get_endpoint() - .times(1) - .return_const(ep); - let mock_controller_endpoint_info: zwave_controller_endpoint_t = Default::default(); - mock_connection_info - .expect_get_remote() - .times(2) - .return_const(mock_controller_endpoint_info); - - let status = f.on_control(&mock_connection_info); - assert_eq!(Ok(()), status); - - // Verify that the attribute store was updated - assert_eq!( - 0x42, - value1.get_reported::().unwrap() - ); - // UIC-1927 : Reactivate this test - //assert_eq!( - // 0xaa, - // value1.get_desired::().unwrap() - //); - // FIXME: UIC-1926 Frame parser fail. Here we receive 0xFE in the report and saves value 0x01 - // SwitchColorReportDurationEnum::UnknownDuration in the attribute store - /* - assert_eq!( - 0xFEu32, - duration - .get_reported::() - .unwrap() - ); - */ - - //Check that we can handle a V1 report - let z = [0x33u8, 0x04u8, 0x01u8, 0x52u8]; - let f: CommandClassSwitchColorFrame = (z[..]).try_into().unwrap(); - // ZwaveCommandClassSwitchColor::handle_control(ep, f.unwrap()).unwrap(); - - mock_connection_info - .expect_get_endpoint() - .times(1) - .return_const(ep); - mock_connection_info - .expect_get_remote() - .times(2) - .return_const(mock_controller_endpoint_info); - - let status = f.on_control(&mock_connection_info); - assert_eq!(Ok(()), status); - assert_eq!( - 0x52, - value1.get_reported::().unwrap() - ); - // UIC-1927 : Reactivate this test - //assert_eq!( - // 0x00, - // value1.get_desired::().unwrap() - //); - - let test_event = AttributeEvent { - attribute: value0, - event_type: AttributeEventType::ATTRIBUTE_UPDATED, - value_state: AttributeValueState::DESIRED_ATTRIBUTE, - }; - - //Can we generate a set? - value0 - .set_desired(Some(0xaa as color_component_id_value_t)) - .unwrap(); - value1 - .set_desired(Some(0xbb as color_component_id_value_t)) - .unwrap(); - duration - .set_desired(Some(0x12 as color_component_id_value_t)) - .unwrap(); - - // Trigger the attribute store callback, now the state node should - // indicate that we need a set command - assert_eq!(true, state.is_value_matched()); - on_value_update(&test_event); - assert_eq!(false, state.is_value_matched()); - - frame_result = switch_color_set_rust(state).unwrap(); - assert_eq!( - ( - SL_STATUS_OK, - vec![0x33u8, 0x05u8, 0x02u8, 0x00u8, 0xaau8, 0x01u8, 0xbbu8, 0x00u8] - ), - frame_result - ); - - // Align all the values - assert_eq!(true, value0.set_desired_as_reported()); - assert_eq!(true, value1.set_desired_as_reported()); - // State attribute gets updated accordingly: - assert_eq!(false, state.is_value_matched()); - on_value_update(&test_event); - assert_eq!(true, state.is_value_matched()); - } -} From cea8980a1fc30275a2cafff9acc99b86a47bf509 Mon Sep 17 00:00:00 2001 From: Viet Date: Wed, 25 Sep 2024 21:57:16 +0700 Subject: [PATCH 08/10] UIC-3272: Add Python Script for CTT test Switch Color Command Class Origin: https://github.com/SiliconLabsSoftware/z-wave-protocol-controller/pull/146 Signed-off-by: Philippe Coval --- .../clusters/unify_switch_color.py | 17 +++++++ .../command_classes/color_switch.py | 46 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 applications/zpc/scripts/certification/command_classes/clusters/unify_switch_color.py create mode 100644 applications/zpc/scripts/certification/command_classes/color_switch.py diff --git a/applications/zpc/scripts/certification/command_classes/clusters/unify_switch_color.py b/applications/zpc/scripts/certification/command_classes/clusters/unify_switch_color.py new file mode 100644 index 000000000..46c478728 --- /dev/null +++ b/applications/zpc/scripts/certification/command_classes/clusters/unify_switch_color.py @@ -0,0 +1,17 @@ +import mqtt.mqtt_manager as mqtt_manager +import utils.utils as utils + +CLUSTER_NAME = "UnifySwitchColor" + +def command_set_color(color_component_id, value, duration = 0): + mqtt_manager.send_unify_cluster_command(CLUSTER_NAME, "SetColor", + '{"ColorComponentId" : %d, "Value" : %d, "Duration" : %d}' + % (color_component_id, value, duration) + ) + + +def command_start_stop_level_change(start_stop, up_down, ignor_start_level, color_component_id, start_level, duration = 1): + mqtt_manager.send_unify_cluster_command(CLUSTER_NAME, "StartStopChange", + '{"StartStop" : %s, "UpDown" : %s, "IgnorStartLevel" : %s, "ColorComponentId" : %d, "StartLevel" : %d, "Duration" : %d}' + % (utils.bool_to_str(start_stop), utils.bool_to_str(up_down), utils.bool_to_str(ignor_start_level), color_component_id, start_level, duration) + ) \ No newline at end of file diff --git a/applications/zpc/scripts/certification/command_classes/color_switch.py b/applications/zpc/scripts/certification/command_classes/color_switch.py new file mode 100644 index 000000000..8e5ab756a --- /dev/null +++ b/applications/zpc/scripts/certification/command_classes/color_switch.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 + +import mqtt.mqtt_manager as mqtt_manager +import utils.pretty_print as display + +from clusters import on_off, level, unify_switch_color + +def color_set(color_id, color_value): + display.action_description(f"Color ID {color_id} Set to {color_value}") + unify_switch_color.command_set_color(color_id, color_value, 0) + +def color_start_change_up(color_id): + display.action_description(f"Color ID {color_id} Start Level Change Up") + unify_switch_color.command_start_stop_level_change(True, False, True, color_id, 50, 1) + +def color_stop_change(color_id): + display.action_description(f"Color ID {color_id} Stop Level Change") + unify_switch_color.command_start_stop_level_change(False, False, True, color_id, 50, 1) + +def switch_multilevel_set(level_value): + display.action_description(f"Switch Multilevel Set to {level_value}") + level.command_move_level(level_value, True, True) + +def switch_binary_set_on(): + display.action_description(f"Switch Binary Set On") + on_off.command_on() + +def switch_binary_set_off(): + display.action_description(f"Switch Binary Set Off") + on_off.command_off() + +if __name__ == '__main__': + mqtt_manager.add_node() + + # set color component 'Green' (ID = 0x03) with value= 255 + color_set(3, 255) + # start level change for color component 'Red' (ID = 0x02) increasing its brightness + color_start_change_up(2) + # stop level change for color component 'Red' (ID = 0x02) + color_stop_change(2) + # binary switch set + switch_binary_set_on() + # multilevel switch set + switch_multilevel_set(50) + + mqtt_manager.remove_node() From 0fbe892017f68d62dc32c22d055e6ea3c9d2a22f Mon Sep 17 00:00:00 2001 From: ptphan Date: Mon, 4 Nov 2024 15:19:25 +0700 Subject: [PATCH 09/10] UIC-3272: Documentation for the Color Switch command class. Origin: https://github.com/SiliconLabsSoftware/z-wave-protocol-controller/pull/146 Signed-off-by: Philippe Coval --- .../zpc/doc/command_classes/color_switch.rst | 227 ++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 applications/zpc/doc/command_classes/color_switch.rst diff --git a/applications/zpc/doc/command_classes/color_switch.rst b/applications/zpc/doc/command_classes/color_switch.rst new file mode 100644 index 000000000..dc7db7518 --- /dev/null +++ b/applications/zpc/doc/command_classes/color_switch.rst @@ -0,0 +1,227 @@ +Color Switch +============= + +Version supported : 3 + +.. contents:: + :depth: 2 + :local: + :backlinks: none + + +Interview process +***************** + +#. :ref:`Color Switch Supported Get ` +#. For each supported Color Component: :ref:`Color Switch Get ` + +Command Class Commands +********************** + +.. _color-switch-supported-get-command: + +Color Switch Supported Get +--------------------------- + +Trigger on undefined **reported** value of ``SUPPORTED_COLOR_COMPONENT_MASK`` + +Color Switch Supported Report +------------------------------ + +Mapping between Report command and attribute store : + +.. list-table:: + :header-rows: 1 + + * - Z-Wave Command Attribute + - Z-Wave Attribute Store + * - ``Color Component mask 1 | ((Color Component mask 2) << 8)`` + - ``SUPPORTED_COLOR_COMPONENT_MASK`` + +.. note:: + ``Color Component mask 1``, ``Color Component mask 2`` used for calculating supported ``COLOR_COMPONENT_ID`` + + +Color Switch Set +------------------------------- + +Trigger on new **desired** value of ``VALUE``: + +Mapping between attribute store and Set command: + +.. list-table:: + :header-rows: 1 + + * - Z-wave Attribute Store + - Attribute State + - Z-wave Set Field + * - ``VALUE`` + - Desired or Reported + - ``Value`` + * - ``DURATION`` + - Desired or Reported + - ``Duration`` + * - ``COLOR_COMPONENT_ID`` + - Desired or Reported + - ``Color Component ID`` + +.. _color-switch-get-command: + +Color Switch Get +------------------------------- + +Trigger on undefined **reported** value of ``VALUE``: + + +Color Switch Report +---------------------------------- + +Mapping between Report command and attribute store : + +.. list-table:: + :header-rows: 1 + + * - Report Field Command + - Z-Wave Attribute Store + * - ``Color Component ID`` + - ``COLOR_COMPONENT_ID`` + * - ``Current Value`` + - ``VALUE`` + * - ``Duration`` + - ``DURATION`` + +Color Switch Start Level Change +-------------------------- + +Trigger on new **desired** value of ``START_CHANGE``: + +Mapping between attribute store and command: + +.. list-table:: + :header-rows: 1 + + * - Z-wave Attribute Store + - Attribute State + - Z-wave Set Field + * - ``START_LEVEL`` + - Desired or Reported + - ``Start Level`` + * - ``UP_DOWN`` + - Desired or Reported + - ``Up/Down`` + * - ``IGNORE_START_LEVEL`` + - Desired or Reported + - ``Ignore Start State`` + * - ``COLOR_COMPONENT_ID`` + - Desired or Reported + - ``Color Component ID`` + * - ``START_LEVEL`` + - Desired or Reported + - ``Start Level`` + * - ``DURATION`` + - Desired or Reported + - ``Duration`` + + + +Color Switch Stop Level Change +-------------------------- + +Trigger on new **desired** value of ``STOP_CHANGE``: + +Mapping between attribute store and command: + +.. list-table:: + :header-rows: 1 + + * - Z-wave Attribute Store + - Attribute State + - Z-wave Set Field + * - ``COLOR_COMPONENT_ID`` + - Desired or Reported + - ``Color Component ID`` + +.. note:: + The structure of the attribute store is : + + .. code:: text + + |__ SUPPORTED_COLOR_COMPONENT_MASK + |__ STATE + |__ COLOR_COMPONENT_ID + | |__ VALUE + | |__ START_CHANGE + | |__ STOP_CHANGE + |__ DURATION + |__ UP_DOWN + |__ IGNORE_START_LEVEL + |__ START_LEVEL + + +Unify Clusters +************** + +UAM files +--------- + +.. list-table:: + :header-rows: 1 + + * - UAM File + - Cluster + - Comments + * - ``SwitchColor.uam`` + - ``Unify_SwitchColor.xml`` + - Mapping between Color Switch command class and Color Switch cluster + +Bindings +-------- + +.. list-table:: + :header-rows: 1 + + * - Z-Wave Attribute Store + - Cluster attribute + - Comments + * - ``VALUE`` + - UnifySwitchColor WarmWhite + - Z-Wave <-> Cluster (If ``COMPONENT_ID`` = 0x00) + * - ``VALUE`` + - UnifySwitchColor ColdWhite + - Z-Wave <-> Cluster (If ``COMPONENT_ID`` = 0x01) + * - ``VALUE`` + - UnifySwitchColor Red + - Z-Wave <-> Cluster (If ``COMPONENT_ID`` = 0x02) + * - ``VALUE`` + - UnifySwitchColor Green + - Z-Wave <-> Cluster (If ``COMPONENT_ID`` = 0x03) + * - ``VALUE`` + - UnifySwitchColor Blue + - Z-Wave <-> Cluster (If ``COMPONENT_ID`` = 0x04) + * - ``VALUE`` + - UnifySwitchColor Amber + - Z-Wave <-> Cluster (If ``COMPONENT_ID`` = 0x05) + * - ``VALUE`` + - UnifySwitchColor Cyan + - Z-Wave <-> Cluster (If ``COMPONENT_ID`` = 0x06) + * - ``VALUE`` + - UnifySwitchColor Purple + - Z-Wave <-> Cluster (If ``COMPONENT_ID`` = 0x07) + + +Command actions +--------------- + +.. list-table:: + :widths: 20 50 30 + :header-rows: 1 + + * - Action + - MQTT Topic + - Comments + * - End user performs set the color + - ``ucl/by-unid///UnifySwitchColor/Commands/SetColor {"ColorComponentId" : 4, "Value" : 100, "Duration" : 0}`` + - See ``ColorComponentId`` values in Bindings table + * - End user performs start/stop enhancing a color component + - ``ucl/by-unid///UnifySwitchColor/Commands/StartStopChange {"StartStop" : true, "UpDown" : false, "IgnorStartLevel" : true, "ColorComponentId" : 2, "StartLevel" : 50, "Duration" : 10}`` + - ``StartStop`` = ``true`` for Start level change, = ``false`` for Stop level change; ``UpDown`` = ``true`` for decreasing, = ``false`` for increasing \ No newline at end of file From c7730cfadc2979ea698cbcc9c22c4fdc011bfcf3 Mon Sep 17 00:00:00 2001 From: ptphan Date: Mon, 4 Nov 2024 15:19:25 +0700 Subject: [PATCH 10/10] UIC-3272: Documentation for the Color Switch command class. Origin: https://github.com/SiliconLabsSoftware/z-wave-protocol-controller/pull/146 Signed-off-by: Philippe Coval --- applications/zpc/doc/command_classes/color_switch.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/applications/zpc/doc/command_classes/color_switch.rst b/applications/zpc/doc/command_classes/color_switch.rst index dc7db7518..fe8d7b008 100644 --- a/applications/zpc/doc/command_classes/color_switch.rst +++ b/applications/zpc/doc/command_classes/color_switch.rst @@ -23,7 +23,7 @@ Command Class Commands Color Switch Supported Get --------------------------- -Trigger on undefined **reported** value of ``SUPPORTED_COLOR_COMPONENT_MASK`` +Trigger on undefined **reported** value of ``SUPPORTED_COLOR_COMPONENT_MASK``. Color Switch Supported Report ------------------------------ @@ -45,7 +45,7 @@ Mapping between Report command and attribute store : Color Switch Set ------------------------------- -Trigger on new **desired** value of ``VALUE``: +Trigger on new **desired** value of ``VALUE``. Mapping between attribute store and Set command: @@ -70,7 +70,7 @@ Mapping between attribute store and Set command: Color Switch Get ------------------------------- -Trigger on undefined **reported** value of ``VALUE``: +Trigger on undefined **reported** value of ``VALUE``. Color Switch Report @@ -93,7 +93,7 @@ Mapping between Report command and attribute store : Color Switch Start Level Change -------------------------- -Trigger on new **desired** value of ``START_CHANGE``: +Trigger on new **desired** value of ``START_CHANGE``. Mapping between attribute store and command: @@ -127,7 +127,7 @@ Mapping between attribute store and command: Color Switch Stop Level Change -------------------------- -Trigger on new **desired** value of ``STOP_CHANGE``: +Trigger on new **desired** value of ``STOP_CHANGE``. Mapping between attribute store and command: