diff --git a/applications/zpc/components/dotdot_mapper/rules/Unifyschedulelockentry_to_schedulelockentry.uam b/applications/zpc/components/dotdot_mapper/rules/Unifyschedulelockentry_to_schedulelockentry.uam
new file mode 100644
index 000000000..22932a0a5
--- /dev/null
+++ b/applications/zpc/components/dotdot_mapper/rules/Unifyschedulelockentry_to_schedulelockentry.uam
@@ -0,0 +1,125 @@
+// Schedule Entry Lock All Command Class
+def zwSLOTS_WEEK_DAY 0x4E05
+def zwSLOTS_YEAR_DAY 0x4E06
+def zwSIGN_TZO 0x4E1B
+def zwHOUR_TZO 0x4E1C
+def zwMINUTE_TZO 0x4E1D
+def zwDST_OFFSET_SIGN 0x4E1E
+def zwDST_OFFSET_MINUTE 0x4E1F
+def zwNUMBER_OF_SLOTS_DAILY_REPEATING 0x4E20
+
+// Unify Schedule Entry Lock Cluster
+def zbSLOTS_WEEK_DAY 0xFD210001
+def zbSLOTS_YEAR_DAY 0xFD210002
+def zbSIGN_TZO 0xFD210003
+def zbHOUR_TZO 0xFD210004
+def zbMINUTE_TZO 0xFD210005
+def zbDST_OFFSET_SIGN 0xFD210006
+def zbDST_OFFSET_MINUTE 0xFD210007
+def zbNUMBER_OF_SLOTS_DAILY_REPEATING 0xFD210008
+
+def zwave_no_schedule_entry_lock (e'zwSLOTS_WEEK_DAY == 0)
+def zwave_no_schedule_entry_lock_v2 (e'zwHOUR_TZO == 0)
+
+scope 0 {
+
+ // Linking attributes zwave -> zigbee
+ r'zwSLOTS_WEEK_DAY =
+ if (zwave_no_schedule_entry_lock) undefined
+ r'zbSLOTS_WEEK_DAY
+ d'zwSLOTS_WEEK_DAY =
+ if (zwave_no_schedule_entry_lock) undefined
+ d'zbSLOTS_WEEK_DAY
+ r'zwSLOTS_YEAR_DAY =
+ if (zwave_no_schedule_entry_lock) undefined
+ r'zbSLOTS_YEAR_DAY
+ d'zwSLOTS_YEAR_DAY =
+ if (zwave_no_schedule_entry_lock) undefined
+ d'zbSLOTS_YEAR_DAY
+ r'zwSIGN_TZO =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ r'zbSIGN_TZO
+ d'zwSIGN_TZO =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ d'zbSIGN_TZO
+ r'zwHOUR_TZO =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ r'zbHOUR_TZO
+ d'zwHOUR_TZO =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ d'zbHOUR_TZO
+ r'zwMINUTE_TZO =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ r'zbMINUTE_TZO
+ d'zwMINUTE_TZO =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ d'zbMINUTE_TZO
+ r'zwDST_OFFSET_SIGN =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ r'zbDST_OFFSET_SIGN
+ d'zwDST_OFFSET_SIGN =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ d'zbDST_OFFSET_SIGN
+ r'zwDST_OFFSET_MINUTE =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ r'zbDST_OFFSET_MINUTE
+ d'zwDST_OFFSET_MINUTE =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ d'zbDST_OFFSET_MINUTE
+ r'zwNUMBER_OF_SLOTS_DAILY_REPEATING =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ r'zbNUMBER_OF_SLOTS_DAILY_REPEATING
+ d'zwNUMBER_OF_SLOTS_DAILY_REPEATING =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ d'zbNUMBER_OF_SLOTS_DAILY_REPEATING
+
+ // Linking attributes zigbee -> zwave
+ r'zbSLOTS_WEEK_DAY =
+ if (zwave_no_schedule_entry_lock) undefined
+ r'zwSLOTS_WEEK_DAY
+ d'zbSLOTS_WEEK_DAY =
+ if (zwave_no_schedule_entry_lock) undefined
+ d'zwSLOTS_WEEK_DAY
+ r'zbSLOTS_YEAR_DAY =
+ if (zwave_no_schedule_entry_lock) undefined
+ r'zwSLOTS_YEAR_DAY
+ d'zbSLOTS_YEAR_DAY =
+ if (zwave_no_schedule_entry_lock) undefined
+ d'zwSLOTS_YEAR_DAY
+ r'zbSIGN_TZO =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ r'zwSIGN_TZO
+ d'zbSIGN_TZO =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ d'zwSIGN_TZO
+ r'zbHOUR_TZO =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ r'zwHOUR_TZO
+ d'zbHOUR_TZO =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ d'zwHOUR_TZO
+ r'zbMINUTE_TZO =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ r'zwMINUTE_TZO
+ d'zbMINUTE_TZO =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ d'zwMINUTE_TZO
+ r'zbDST_OFFSET_SIGN =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ r'zwDST_OFFSET_SIGN
+ d'zbDST_OFFSET_SIGN =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ d'zwDST_OFFSET_SIGN
+ r'zbDST_OFFSET_MINUTE =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ r'zwDST_OFFSET_MINUTE
+ d'zbDST_OFFSET_MINUTE =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ d'zwDST_OFFSET_MINUTE
+ r'zbNUMBER_OF_SLOTS_DAILY_REPEATING =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ r'zwNUMBER_OF_SLOTS_DAILY_REPEATING
+ d'zbNUMBER_OF_SLOTS_DAILY_REPEATING =
+ if (zwave_no_schedule_entry_lock_v2) undefined
+ d'zwNUMBER_OF_SLOTS_DAILY_REPEATING
+}
diff --git a/applications/zpc/components/zcl_cluster_servers/CMakeLists.txt b/applications/zpc/components/zcl_cluster_servers/CMakeLists.txt
index 8827e1f08..3ae54aba8 100644
--- a/applications/zpc/components/zcl_cluster_servers/CMakeLists.txt
+++ b/applications/zpc/components/zcl_cluster_servers/CMakeLists.txt
@@ -11,12 +11,14 @@ add_library(
src/humidity_control_cluster_server.c
src/user_code_cluster_server.cpp
src/fan_control_cluster_server.c
+ src/schedule_entry_lock_server.cpp
src/zcl_binding_cluster_server.cpp
src/zcl_cluster_servers.cpp
src/zcl_cluster_servers_helpers.cpp
src/zcl_OTA_cluster_server.cpp
src/zcl_rf_telemetry_cluster_server.c
src/zcl_scenes_cluster_server.cpp
+ src/multilevel_sensor_cluster_server.cpp
)
target_include_directories(
diff --git a/applications/zpc/components/zcl_cluster_servers/include/schedule_entry_lock_server.h b/applications/zpc/components/zcl_cluster_servers/include/schedule_entry_lock_server.h
new file mode 100644
index 000000000..acb4f0b51
--- /dev/null
+++ b/applications/zpc/components/zcl_cluster_servers/include/schedule_entry_lock_server.h
@@ -0,0 +1,70 @@
+/******************************************************************************
+ * # 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.
+ *
+ *****************************************************************************/
+
+#ifndef SCHEDULE_ENTRY_LOCK_SERVER_H
+#define SCHEDULE_ENTRY_LOCK_SERVER_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 "zwave_frame_generator.hpp"
+#include "zwave_frame_parser.hpp"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Initialize the schedule entry lock cluster server
+ *
+ * @returns true on success
+ * @returns false on failure
+ *
+ */
+sl_status_t schedule_entry_lock_cluster_server_init(void);
+
+sl_status_t zwave_command_class_publish_generated_week_day_report_command(
+ dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint,
+ attribute_store_node_t endpoint_node);
+
+sl_status_t zwave_command_class_publish_generated_year_day_report_command(
+ dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint,
+ attribute_store_node_t endpoint_node);
+
+sl_status_t
+ zwave_command_class_publish_generated_daily_repeating_report_command(
+ dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint,
+ attribute_store_node_t endpoint_node);
+
+sl_status_t zwave_command_class_schedule_entry_lock_write_attributes_callback(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint,
+ uic_mqtt_dotdot_callback_call_type_t call_type,
+ uic_mqtt_dotdot_unify_schedule_entry_lock_state_t lock_state,
+ uic_mqtt_dotdot_unify_schedule_entry_lock_updated_state_t updated_lock_state);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //SCHEDULE_ENTRY_LOCK_SERVER_H
+/** @} end schedule_entry_lock_server */
diff --git a/applications/zpc/components/zcl_cluster_servers/src/multilevel_sensor_cluster_server.cpp b/applications/zpc/components/zcl_cluster_servers/src/multilevel_sensor_cluster_server.cpp
new file mode 100644
index 000000000..0645623b8
--- /dev/null
+++ b/applications/zpc/components/zcl_cluster_servers/src/multilevel_sensor_cluster_server.cpp
@@ -0,0 +1,181 @@
+/******************************************************************************
+ * # 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 "multilevel_sensor_cluster_server.h"
+#include "zcl_cluster_servers_helpers.hpp"
+
+// Interfaces
+#include "zwave_command_class_version_types.h"
+#include "zwave_command_class_configuration_types.h"
+
+// ZPC includes
+#include "zpc_attribute_store.h"
+#include "zpc_attribute_store_network_helper.h"
+#include "zwave_command_class_generic_types.h"
+#include "attribute_store_defined_attribute_types.h"
+
+// Includes from Unify shared components
+#include "attribute.hpp"
+#include "attribute_store_helper.h"
+#include "sl_log.h"
+
+// Includes from auto-generated files
+#include "dotdot_mqtt.h"
+#include "zap-types.h"
+#include "dotdot_mqtt_helpers.hpp"
+
+// Generic includes
+#include
+#include
+#include
+
+using namespace attribute_store;
+
+// Setup Log ID
+constexpr char LOG_TAG[] = "multilevel_sensor_cluster_server";
+
+// Attribute macro, shortening those long defines for attribute types:
+#define ATTRIBUTE(type) ATTRIBUTE_COMMAND_CLASS_SENSOR_MULTILEVEL_##type
+
+// List of attributes of SensorValues
+namespace
+{
+const std::vector sensor_values_attributes
+ = {ATTRIBUTE(SENSOR_VALUE), ATTRIBUTE(SCALE)};
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Attribute publication functions
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @brief Publishes the Multilevel Sensor Cluster Server attributes
+ *
+ * @param unid unid for which we want to publish the
+ * SensorValues attributes.
+ * @param endpoint_id Endpoint ID for which we want to publish the
+ * SensorValues attributes.
+ * @param sensor_type Sensor Type node ID for which we want to publish the
+ * SensorValues attributes.
+ */
+static sl_status_t publish_multilevel_sensor_cluster_attributes(
+ const std::string &unid,
+ attribute_store::attribute sensor_type_node,
+ zwave_endpoint_id_t endpoint_id)
+{
+ // Do not publish any state supported commands for ourselves.
+ if (is_zpc_unid(unid.c_str())) {
+ return SL_STATUS_FAIL;
+ }
+
+ // Build the base topic and pass it on to DotDot MQTT.
+ try {
+ // Get reported sensor type ID
+ uint8_t sensor_type = sensor_type_node.reported();
+
+ // Get SensorType name
+ const std::string sensor_type_str
+ = multilevel_sensor_sensor_type_get_enum_value_name(sensor_type);
+
+ // Added sensor type name to base topic
+ const std::string base_topic = "ucl/by-unid/" + std::string(unid) + "/ep"
+ + std::to_string(endpoint_id) + "/"
+ + std::string(sensor_type_str);
+
+ SensorValue value = {0, 0};
+ // Get report sensor value
+ attribute_store::attribute sensor_value_node
+ = sensor_type_node.child_by_type(ATTRIBUTE(SENSOR_VALUE));
+ if (sensor_value_node.reported_exists()) {
+ value.Value = sensor_value_node.reported();
+ }
+ // Get report sensor scale
+ attribute_store::attribute sensor_scale_node
+ = sensor_type_node.child_by_type(ATTRIBUTE(SCALE));
+ if (sensor_scale_node.reported_exists()) {
+ value.Scale = static_cast(sensor_scale_node.reported());
+ }
+
+ // Pulish the sensor value attribute
+ if (SL_STATUS_OK
+ != uic_mqtt_dotdot_multilevel_sensor_sensor_values_publish(
+ base_topic.c_str(),
+ value,
+ UCL_MQTT_PUBLISH_TYPE_REPORTED)) {
+ return SL_STATUS_FAIL;
+ }
+ } catch (const std::exception &e) {
+ sl_log_error(LOG_TAG,
+ "Error while get base topic and sensor data : %s",
+ e.what());
+
+ return SL_STATUS_FAIL;
+ }
+ return SL_STATUS_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Attribute store callback functions
+//////////////////////////////////////////////////////////////////////////////
+/**
+ * @brief Listens to updates to the SensorValues then publishes the attributes.
+ *
+ * @param updated_node Attribute Store node that was modified.
+ * @param change Type of change applied to the node.
+ */
+void on_sensor_values_update(attribute_store_node_t updated_node,
+ attribute_store_change_t change)
+{
+ if (change == ATTRIBUTE_CREATED || change == ATTRIBUTE_DELETED) {
+ return;
+ }
+
+ // Go up and find the UNID/Endpoint and its network status.
+ unid_t unid;
+ zwave_endpoint_id_t endpoint_id = 0;
+ if (SL_STATUS_OK
+ != attribute_store_network_helper_get_unid_endpoint_from_node(
+ updated_node,
+ unid,
+ &endpoint_id)) {
+ return;
+ }
+
+ attribute_store::attribute sensor_type_node
+ = attribute_store_get_first_parent_with_type(updated_node,
+ ATTRIBUTE(SENSOR_TYPE));
+
+ // Publish the multilevel sensor values:
+ if (SL_STATUS_OK
+ != publish_multilevel_sensor_cluster_attributes(std::string(unid),
+ sensor_type_node,
+ endpoint_id)) {
+ return;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Init and teardown functions.
+//////////////////////////////////////////////////////////////////////////////
+sl_status_t multilevel_sensor_cluster_server_init(void)
+{
+ sl_log_debug(LOG_TAG, "Multilevel sensor server initialization");
+
+ // Register attribute updates
+
+ attribute_store_register_callback_by_type_to_array(
+ &on_sensor_values_update,
+ sensor_values_attributes.data(),
+ static_cast(sensor_values_attributes.size()));
+
+ return SL_STATUS_OK;
+}
diff --git a/applications/zpc/components/zcl_cluster_servers/src/multilevel_sensor_cluster_server.h b/applications/zpc/components/zcl_cluster_servers/src/multilevel_sensor_cluster_server.h
new file mode 100644
index 000000000..7abce7475
--- /dev/null
+++ b/applications/zpc/components/zcl_cluster_servers/src/multilevel_sensor_cluster_server.h
@@ -0,0 +1,44 @@
+/******************************************************************************
+ * # 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.
+ *
+ *****************************************************************************/
+
+/**
+ * @defgroup multilevel_sensor_cluster_server ZCL Multilevel Sensor cluster
+ * @ingroup zcl_cluster_servers
+ * @brief The module handlers the Multilevel Sensor Cluster attribute and
+ * publish directly the attribute via MQTT.
+ *
+ * @{
+ */
+
+#ifndef MULTILEVEL_SENSOR_CLUSTER_SERVER_H
+#define MULTILEVEL_SENSOR_CLUSTER_SERVER_H
+
+#include "sl_status.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Initialize the Multilevel Sensor Cluster Commands handler.
+ *
+ * @returns SL_STATUS_OK on success, any other code on failure
+ */
+sl_status_t multilevel_sensor_cluster_server_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //MULTILEVEL_SENSOR_CLUSTER_SERVER_H
+/** @} end configuration_cluster_mapper */
diff --git a/applications/zpc/components/zcl_cluster_servers/src/schedule_entry_lock_server.cpp b/applications/zpc/components/zcl_cluster_servers/src/schedule_entry_lock_server.cpp
new file mode 100644
index 000000000..9b706861e
--- /dev/null
+++ b/applications/zpc/components/zcl_cluster_servers/src/schedule_entry_lock_server.cpp
@@ -0,0 +1,628 @@
+/******************************************************************************
+ * # 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_schedule_entry_lock.h"
+#include "zwave_command_classes_utils.h"
+#include "schedule_entry_lock_server.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 "attribute.hpp"
+
+// Attribute macro, shortening those long defines for attribute types:
+#define ATTRIBUTE(type) ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_##type
+
+// Log tag
+constexpr char LOG_TAG[] = "zwave_command_class_schedule_entry_lock";
+
+///////////////////////////////////////////////////////////////////////////////
+// helper functions
+//////////////////////////////////////////////////////////////////////////////
+attribute_store::attribute get_user_id_node(const dotdot_unid_t &unid,
+ dotdot_endpoint_id_t endpoint,
+ uint8_t user_identifier)
+{
+ attribute_store::attribute base_id_node
+ = attribute_store_network_helper_get_node_id_node(unid);
+ attribute_store::attribute endpoint_node
+ = base_id_node.child_by_type_and_value(ATTRIBUTE_ENDPOINT_ID, endpoint);
+ auto user_id_node
+ = endpoint_node.child_by_type_and_value(ATTRIBUTE(USER_IDENTIFIER),
+ user_identifier);
+
+ return user_id_node;
+}
+
+sl_status_t
+ zwave_command_class_check_ep_support(const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint)
+{
+ attribute_store::attribute base_id_node
+ = attribute_store_network_helper_get_node_id_node(unid);
+ attribute_store::attribute endpoint_node
+ = base_id_node.child_by_type_and_value<>(ATTRIBUTE_ENDPOINT_ID, endpoint);
+
+ // If both attribute are not defined, we definitely doesn't support this Command Class
+ if (!endpoint_node.child_by_type(ATTRIBUTE(SLOTS_WEEK_DAY)).is_valid()
+ && !endpoint_node.child_by_type(ATTRIBUTE(HOUR_TZO)).is_valid()) {
+ return SL_STATUS_FAIL;
+ }
+
+ return SL_STATUS_OK;
+}
+
+// Helper function to set the desired values based on the attribute map.
+static sl_status_t helper_set_desired_values(
+ attribute_store::attribute base_node,
+ const std::map &attribute_map)
+{
+ try {
+ for (const auto &[attribute, value]: attribute_map) {
+ auto child_node = base_node.emplace_node(attribute);
+ child_node.set_desired(value);
+ }
+ } catch (const std::exception &e) {
+ sl_log_error(LOG_TAG, "Error while setting desired values : %s", e.what());
+ return SL_STATUS_FAIL;
+ }
+ return SL_STATUS_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// commands handling callbacks
+//////////////////////////////////////////////////////////////////////////////
+
+static sl_status_t zwave_command_class_schedule_entry_lock_enable_set_callback(
+ dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint,
+ uic_mqtt_dotdot_callback_call_type_t call_type,
+ uint8_t user_identifier,
+ uint8_t enabled)
+{
+ if (call_type == UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK) {
+ return zwave_command_class_check_ep_support(unid, endpoint);
+ }
+ try {
+ auto user_id_node = get_user_id_node(unid, endpoint, user_identifier);
+ user_id_node.child_by_type(ATTRIBUTE(ENABLED)).set_desired(enabled);
+ } catch (const std::exception &e) {
+ sl_log_error(LOG_TAG,
+ "Error while generating schedule_entry_lock enable Set : %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+ return SL_STATUS_OK;
+}
+
+static sl_status_t
+ zwave_command_class_schedule_entry_lock_enable_all_set_callback(
+ dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint,
+ uic_mqtt_dotdot_callback_call_type_t call_type,
+ uint8_t enabled)
+{
+ if (call_type == UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK) {
+ return zwave_command_class_check_ep_support(unid, endpoint);
+ }
+ try {
+ attribute_store::attribute base_id_node
+ = attribute_store_network_helper_get_node_id_node(unid);
+ attribute_store::attribute endpoint_node
+ = base_id_node.child_by_type_and_value(ATTRIBUTE_ENDPOINT_ID, endpoint);
+ endpoint_node.child_by_type(ATTRIBUTE(ENABLE_ALL)).set_desired<>(enabled);
+ } catch (const std::exception &e) {
+ sl_log_error(
+ LOG_TAG,
+ "Error while generating schedule_entry_lock enable all Set : %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+ return SL_STATUS_OK;
+}
+
+static sl_status_t
+ zwave_command_class_schedule_entry_lock_week_day_set_callback(
+ dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint,
+ uic_mqtt_dotdot_callback_call_type_t call_type,
+ uint8_t set_action,
+ uint8_t user_identifier,
+ uint8_t schedule_slotid,
+ uint8_t day_of_week,
+ uint8_t start_hour,
+ uint8_t start_minute,
+ uint8_t stop_hour,
+ uint8_t stop_minute)
+{
+ if (call_type == UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK) {
+ return zwave_command_class_check_ep_support(unid, endpoint);
+ }
+ try {
+ auto user_id_node = get_user_id_node(unid, endpoint, user_identifier);
+ auto slot_id_node = user_id_node.child_by_type_and_value(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_SLOT_ID),
+ schedule_slotid);
+
+ const std::map attribute_map
+ = {{ATTRIBUTE(WEEK_DAY_SCHEDULE_SET_ACTION), set_action},
+ {ATTRIBUTE(WEEK_DAY_SCHEDULE_DAY_OF_WEEK), day_of_week},
+ {ATTRIBUTE(WEEK_DAY_SCHEDULE_START_HOUR), start_hour},
+ {ATTRIBUTE(WEEK_DAY_SCHEDULE_START_MINUTE), start_minute},
+ {ATTRIBUTE(WEEK_DAY_SCHEDULE_STOP_HOUR), stop_hour},
+ {ATTRIBUTE(WEEK_DAY_SCHEDULE_STOP_MINUTE), stop_minute}};
+ return helper_set_desired_values(slot_id_node, attribute_map);
+
+ } catch (const std::exception &e) {
+ sl_log_error(LOG_TAG,
+ "Error while generating schedule_entry_lock week day Set : %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+}
+
+static sl_status_t
+ zwave_command_class_schedule_entry_lock_week_day_get_callback(
+ dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint,
+ uic_mqtt_dotdot_callback_call_type_t call_type,
+ uint8_t user_identifier,
+ uint8_t schedule_slotid)
+{
+ if (call_type == UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK) {
+ return zwave_command_class_check_ep_support(unid, endpoint);
+ }
+
+ try {
+ auto user_id_node = get_user_id_node(unid, endpoint, user_identifier);
+ auto slot_id_node = user_id_node.child_by_type_and_value(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_SLOT_ID),
+ schedule_slotid);
+ auto set_action_node
+ = slot_id_node.child_by_type(ATTRIBUTE(WEEK_DAY_SCHEDULE_SET_ACTION));
+ set_action_node.clear_reported();
+
+ } catch (const std::exception &e) {
+ sl_log_error(LOG_TAG,
+ "Error while retrieving schedule_entry_lock weekday get: %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+ return SL_STATUS_OK;
+}
+
+static sl_status_t
+ zwave_command_class_schedule_entry_lock_year_day_set_callback(
+ dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint,
+ uic_mqtt_dotdot_callback_call_type_t call_type,
+ uint8_t set_action,
+ uint8_t user_identifier,
+ uint8_t schedule_slotid,
+ uint8_t start_year,
+ uint8_t start_month,
+ uint8_t start_day,
+ uint8_t start_hour,
+ uint8_t start_minute,
+ uint8_t stop_year,
+ uint8_t stop_month,
+ uint8_t stop_day,
+ uint8_t stop_hour,
+ uint8_t stop_minute)
+{
+ if (call_type == UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK) {
+ return zwave_command_class_check_ep_support(unid, endpoint);
+ }
+
+ try {
+ auto user_id_node = get_user_id_node(unid, endpoint, user_identifier);
+ auto slot_id_node = user_id_node.child_by_type_and_value(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_SLOT_ID),
+ schedule_slotid);
+
+ const std::map attribute_map
+ = {{ATTRIBUTE(YEAR_DAY_SCHEDULE_SET_ACTION), set_action},
+ {ATTRIBUTE(YEAR_DAY_SCHEDULE_START_YEAR), start_year},
+ {ATTRIBUTE(YEAR_DAY_SCHEDULE_START_MONTH), start_month},
+ {ATTRIBUTE(YEAR_DAY_SCHEDULE_START_DAY), start_day},
+ {ATTRIBUTE(YEAR_DAY_SCHEDULE_START_HOUR), start_hour},
+ {ATTRIBUTE(YEAR_DAY_SCHEDULE_START_MINUTE), start_minute},
+ {ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_YEAR), stop_year},
+ {ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_MONTH), stop_month},
+ {ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_DAY), stop_day},
+ {ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_HOUR), stop_hour},
+ {ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_MINUTE), stop_minute}};
+
+ return helper_set_desired_values(slot_id_node, attribute_map);
+ } catch (const std::exception &e) {
+ sl_log_error(LOG_TAG,
+ "Error while generating schedule_entry_lock yearday set: %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+}
+
+static sl_status_t
+ zwave_command_class_schedule_entry_lock_year_day_get_callback(
+ dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint,
+ uic_mqtt_dotdot_callback_call_type_t call_type,
+ uint8_t user_identifier,
+ uint8_t schedule_slotid)
+{
+ if (call_type == UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK) {
+ return zwave_command_class_check_ep_support(unid, endpoint);
+ }
+ try {
+ auto user_id_node = get_user_id_node(unid, endpoint, user_identifier);
+ auto slot_id_node = user_id_node.child_by_type_and_value(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_SLOT_ID),
+ schedule_slotid);
+ auto set_action_node
+ = slot_id_node.child_by_type(ATTRIBUTE(YEAR_DAY_SCHEDULE_SET_ACTION));
+ set_action_node.clear_reported();
+ } catch (const std::exception &e) {
+ sl_log_error(LOG_TAG,
+ "Error while generating schedule_entry_lock yearday get : %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+ return SL_STATUS_OK;
+}
+
+static sl_status_t
+ zwave_command_class_schedule_entry_lock_daily_repeating_set_callback(
+ dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint,
+ uic_mqtt_dotdot_callback_call_type_t call_type,
+ uint8_t set_action,
+ uint8_t user_identifier,
+ uint8_t schedule_slotid,
+ uint8_t week_day_bitmask,
+ uint8_t start_hour,
+ uint8_t start_minute,
+ uint8_t duration_hour,
+ uint8_t duration_minute)
+{
+ if (call_type == UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK) {
+ return zwave_command_class_check_ep_support(unid, endpoint);
+ }
+ try {
+ auto user_id_node = get_user_id_node(unid, endpoint, user_identifier);
+ auto slot_id_node = user_id_node.child_by_type_and_value(
+ ATTRIBUTE(DAILY_REPEATING_SCHEDULE_SLOT_ID),
+ schedule_slotid);
+
+ const std::map attribute_map
+ = {{ATTRIBUTE(DAILY_REPEATING_SET_ACTION), set_action},
+ {ATTRIBUTE(DAILY_REPEATING_WEEK_DAY), week_day_bitmask},
+ {ATTRIBUTE(DAILY_REPEATING_START_HOUR), start_hour},
+ {ATTRIBUTE(DAILY_REPEATING_START_MINUTE), start_minute},
+ {ATTRIBUTE(DAILY_REPEATING_DURATION_HOUR), duration_hour},
+ {ATTRIBUTE(DAILY_REPEATING_DURATION_MINUTE), duration_minute}};
+
+ return helper_set_desired_values(slot_id_node, attribute_map);
+ } catch (const std::exception &e) {
+ sl_log_error(
+ LOG_TAG,
+ "Error while generating schedule_entry_lock daily repeating Set: %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+}
+
+static sl_status_t
+ zwave_command_class_schedule_entry_lock_daily_repeating_get_callback(
+ dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint,
+ uic_mqtt_dotdot_callback_call_type_t call_type,
+ uint8_t user_identifier,
+ uint8_t schedule_slotid)
+{
+ if (call_type == UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK) {
+ return zwave_command_class_check_ep_support(unid, endpoint);
+ }
+
+ try {
+ attribute_store::attribute base_id_node
+ = attribute_store_network_helper_get_node_id_node(unid);
+ attribute_store::attribute endpoint_node
+ = base_id_node.child_by_type_and_value(ATTRIBUTE_ENDPOINT_ID, endpoint);
+ auto user_id_node
+ = endpoint_node.child_by_type_and_value(ATTRIBUTE(USER_IDENTIFIER),
+ user_identifier);
+ auto slot_id_node = user_id_node.child_by_type_and_value(
+ ATTRIBUTE(DAILY_REPEATING_SCHEDULE_SLOT_ID),
+ schedule_slotid);
+ auto set_action_node
+ = slot_id_node.child_by_type(ATTRIBUTE(DAILY_REPEATING_SET_ACTION));
+ set_action_node.clear_reported();
+ } catch (const std::exception &e) {
+ sl_log_error(
+ LOG_TAG,
+ "Error while generating schedule_entry_lock daily repeating Set : %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+ return SL_STATUS_OK;
+}
+
+sl_status_t zwave_command_class_schedule_entry_lock_write_attributes_callback(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint,
+ uic_mqtt_dotdot_callback_call_type_t call_type,
+ uic_mqtt_dotdot_unify_schedule_entry_lock_state_t lock_state,
+ uic_mqtt_dotdot_unify_schedule_entry_lock_updated_state_t updated_lock_state)
+{
+ if (call_type == UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK) {
+ return zwave_command_class_check_ep_support(unid, endpoint);
+ }
+
+ std::map attributes_to_update;
+
+ if (updated_lock_state.slots_week_day) {
+ attributes_to_update
+ [DOTDOT_ATTRIBUTE_ID_UNIFY_SCHEDULE_ENTRY_LOCK_SLOTS_WEEK_DAY]
+ = lock_state.slots_week_day;
+ }
+
+ if (updated_lock_state.slots_year_day) {
+ attributes_to_update
+ [DOTDOT_ATTRIBUTE_ID_UNIFY_SCHEDULE_ENTRY_LOCK_SLOTS_YEAR_DAY]
+ = lock_state.slots_year_day;
+ }
+
+ if (updated_lock_state.signtzo) {
+ attributes_to_update[DOTDOT_ATTRIBUTE_ID_UNIFY_SCHEDULE_ENTRY_LOCK_SIGNTZO]
+ = lock_state.signtzo;
+ }
+
+ if (updated_lock_state.hourtzo) {
+ attributes_to_update[DOTDOT_ATTRIBUTE_ID_UNIFY_SCHEDULE_ENTRY_LOCK_HOURTZO]
+ = lock_state.hourtzo;
+ }
+
+ if (updated_lock_state.minutetzo) {
+ attributes_to_update
+ [DOTDOT_ATTRIBUTE_ID_UNIFY_SCHEDULE_ENTRY_LOCK_MINUTETZO]
+ = lock_state.minutetzo;
+ }
+
+ if (updated_lock_state.dst_offset_sign) {
+ attributes_to_update
+ [DOTDOT_ATTRIBUTE_ID_UNIFY_SCHEDULE_ENTRY_LOCK_DST_OFFSET_SIGN]
+ = lock_state.dst_offset_sign;
+ }
+
+ if (updated_lock_state.dst_offset_minute) {
+ attributes_to_update
+ [DOTDOT_ATTRIBUTE_ID_UNIFY_SCHEDULE_ENTRY_LOCK_DST_OFFSET_MINUTE]
+ = lock_state.dst_offset_minute;
+ }
+
+ if (updated_lock_state.number_of_slots_daily_repeating) {
+ attributes_to_update
+ [DOTDOT_ATTRIBUTE_ID_UNIFY_SCHEDULE_ENTRY_LOCK_NUMBER_OF_SLOTS_DAILY_REPEATING]
+ = lock_state.number_of_slots_daily_repeating;
+ }
+
+ attribute_store::attribute base_id_node
+ = attribute_store_network_helper_get_node_id_node(unid);
+ attribute_store::attribute endpoint_node
+ = base_id_node.child_by_type_and_value(ATTRIBUTE_ENDPOINT_ID, endpoint);
+
+ for (const auto &[attribute_id, value]: attributes_to_update) {
+ attribute_store::attribute attribute_node
+ = endpoint_node.emplace_node(attribute_id);
+ attribute_node.set_desired<>(value);
+ sl_log_debug(LOG_TAG,
+ "write callback set desired attribute %u %u",
+ attribute_id,
+ attribute_node);
+ }
+
+ return SL_STATUS_OK;
+}
+
+sl_status_t zwave_command_class_publish_generated_week_day_report_command(
+ dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint,
+ attribute_store_node_t ep_node)
+{
+ attribute_store::attribute endpoint_node(ep_node);
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_command_week_day_report_fields_t
+ fields;
+ attribute_store::attribute user_id_node
+ = endpoint_node.child_by_type(ATTRIBUTE(USER_IDENTIFIER));
+ attribute_store::attribute week_day_slot_id_node
+ = user_id_node.child_by_type(ATTRIBUTE(WEEK_DAY_SCHEDULE_SLOT_ID));
+ attribute_store::attribute day_of_week_node
+ = week_day_slot_id_node.child_by_type(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_DAY_OF_WEEK));
+ attribute_store::attribute start_hour_node
+ = week_day_slot_id_node.child_by_type(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_START_HOUR));
+ attribute_store::attribute start_minute_node
+ = week_day_slot_id_node.child_by_type(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_START_MINUTE));
+ attribute_store::attribute stop_hour_node
+ = week_day_slot_id_node.child_by_type(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_STOP_HOUR));
+ attribute_store::attribute stop_minute_node
+ = week_day_slot_id_node.child_by_type(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_STOP_MINUTE));
+ fields.user_identifier = user_id_node.reported();
+ fields.schedule_slotid = week_day_slot_id_node.reported();
+ fields.day_of_week = day_of_week_node.reported();
+ fields.start_hour = start_hour_node.reported();
+ fields.start_minute = start_minute_node.reported();
+ fields.stop_hour = stop_hour_node.reported();
+ fields.stop_minute = stop_minute_node.reported();
+ uic_mqtt_dotdot_unify_schedule_entry_lock_publish_generated_week_day_report_command(
+ unid,
+ endpoint,
+ &fields);
+ return SL_STATUS_OK;
+}
+
+sl_status_t zwave_command_class_publish_generated_year_day_report_command(
+ dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint,
+ attribute_store_node_t ep_node)
+{
+ attribute_store::attribute endpoint_node(ep_node);
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_command_year_day_report_fields_t
+ fields;
+ attribute_store::attribute user_id_node
+ = endpoint_node.child_by_type(ATTRIBUTE(USER_IDENTIFIER));
+ attribute_store::attribute year_day_slot_id_node
+ = user_id_node.child_by_type(ATTRIBUTE(YEAR_DAY_SCHEDULE_SLOT_ID));
+ attribute_store::attribute start_year_node
+ = year_day_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_START_YEAR));
+ attribute_store::attribute start_month_node
+ = year_day_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_START_MONTH));
+ attribute_store::attribute start_day_node
+ = year_day_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_START_DAY));
+ attribute_store::attribute start_hour_node
+ = year_day_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_START_HOUR));
+ attribute_store::attribute start_minute_node
+ = year_day_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_START_MINUTE));
+ attribute_store::attribute stop_year_node
+ = year_day_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_YEAR));
+ attribute_store::attribute stop_month_node
+ = year_day_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_MONTH));
+ attribute_store::attribute stop_day_node
+ = year_day_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_DAY));
+ attribute_store::attribute stop_hour_node
+ = year_day_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_HOUR));
+ attribute_store::attribute stop_minute_node
+ = year_day_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_MINUTE));
+ fields.user_identifier = user_id_node.reported();
+ fields.schedule_slotid = year_day_slot_id_node.reported();
+ fields.start_year = start_year_node.reported();
+ fields.start_month = start_month_node.reported();
+ fields.start_day = start_day_node.reported();
+ fields.start_hour = start_hour_node.reported();
+ fields.start_minute = start_minute_node.reported();
+ fields.stop_year = stop_year_node.reported();
+ fields.stop_month = stop_month_node.reported();
+ fields.stop_day = stop_day_node.reported();
+ fields.stop_hour = stop_hour_node.reported();
+ fields.stop_minute = stop_minute_node.reported();
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_publish_generated_year_day_report_command(
+ unid,
+ endpoint,
+ &fields);
+ return SL_STATUS_OK;
+}
+
+sl_status_t
+ zwave_command_class_publish_generated_daily_repeating_report_command(
+ dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint,
+ attribute_store_node_t ep_node)
+{
+ attribute_store::attribute endpoint_node(ep_node);
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_command_daily_repeating_report_fields_t
+ fields;
+ attribute_store::attribute user_id_node
+ = endpoint_node.child_by_type(ATTRIBUTE(USER_IDENTIFIER));
+ attribute_store::attribute daily_repeating_slot_id_node
+ = user_id_node.child_by_type(ATTRIBUTE(DAILY_REPEATING_SCHEDULE_SLOT_ID));
+ attribute_store::attribute week_day_node
+ = daily_repeating_slot_id_node.child_by_type(
+ ATTRIBUTE(DAILY_REPEATING_WEEK_DAY));
+ attribute_store::attribute start_hour_node
+ = daily_repeating_slot_id_node.child_by_type(
+ ATTRIBUTE(DAILY_REPEATING_START_HOUR));
+ attribute_store::attribute start_minute_node
+ = daily_repeating_slot_id_node.child_by_type(
+ ATTRIBUTE(DAILY_REPEATING_START_MINUTE));
+ attribute_store::attribute duartion_hour_node
+ = daily_repeating_slot_id_node.child_by_type(
+ ATTRIBUTE(DAILY_REPEATING_DURATION_HOUR));
+ attribute_store::attribute duration_minute_node
+ = daily_repeating_slot_id_node.child_by_type(
+ ATTRIBUTE(DAILY_REPEATING_DURATION_MINUTE));
+ fields.user_identifier = user_id_node.reported();
+ fields.schedule_slotid = daily_repeating_slot_id_node.reported();
+ fields.week_day_bitmask = week_day_node.reported();
+ fields.start_hour = start_hour_node.reported();
+ fields.start_minute = start_minute_node.reported();
+ fields.duration_hour = duartion_hour_node.reported();
+ fields.duration_minute = duration_minute_node.reported();
+ uic_mqtt_dotdot_unify_schedule_entry_lock_publish_generated_daily_repeating_report_command(
+ unid,
+ endpoint,
+ &fields);
+ return SL_STATUS_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Init and teardown functions.
+//////////////////////////////////////////////////////////////////////////////
+sl_status_t schedule_entry_lock_cluster_server_init(void)
+{
+ sl_log_debug(LOG_TAG, "Schedule entry lock cluster server initialization");
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_enable_set_callback_set(
+ zwave_command_class_schedule_entry_lock_enable_set_callback);
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_enable_all_set_callback_set(
+ zwave_command_class_schedule_entry_lock_enable_all_set_callback);
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_week_day_set_callback_set(
+ zwave_command_class_schedule_entry_lock_week_day_set_callback);
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_week_day_get_callback_set(
+ zwave_command_class_schedule_entry_lock_week_day_get_callback);
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_year_day_set_callback_set(
+ zwave_command_class_schedule_entry_lock_year_day_set_callback);
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_year_day_get_callback_set(
+ zwave_command_class_schedule_entry_lock_year_day_get_callback);
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_daily_repeating_set_callback_set(
+ zwave_command_class_schedule_entry_lock_daily_repeating_set_callback);
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_daily_repeating_get_callback_set(
+ zwave_command_class_schedule_entry_lock_daily_repeating_get_callback);
+
+ uic_mqtt_dotdot_set_unify_schedule_entry_lock_write_attributes_callback(
+ zwave_command_class_schedule_entry_lock_write_attributes_callback);
+
+ return SL_STATUS_OK;
+}
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 7c959d555..b735453cb 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
@@ -19,6 +19,8 @@
#include "zcl_OTA_cluster_server.hpp"
#include "user_code_cluster_server.h"
#include "fan_control_cluster_server.h"
+#include "multilevel_sensor_cluster_server.h"
+#include "schedule_entry_lock_server.h"
//Includes from other components
#include "attribute_store.h"
@@ -42,6 +44,8 @@ sl_status_t zcl_cluster_servers_init()
init_status |= zcl_scenes_cluster_server_init();
init_status |= user_code_cluster_server_init();
init_status |= fan_control_cluster_server_init();
+ init_status |= multilevel_sensor_cluster_server_init();
+ init_status |= schedule_entry_lock_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 a5142592a..d330362dc 100644
--- a/applications/zpc/components/zcl_cluster_servers/test/CMakeLists.txt
+++ b/applications/zpc/components/zcl_cluster_servers/test/CMakeLists.txt
@@ -88,6 +88,21 @@ target_add_unittest(
uic_contiki_stub
unify)
+# Schedule entry lock server test
+target_add_unittest(
+ zcl_cluster_servers
+ NAME
+ schedule_entry_lock_server_test
+ SOURCES
+ schedule_entry_lock_server_test.cpp
+ DEPENDS
+ zpc_attribute_store_test_helper
+ uic_dotdot_mqtt_mock
+ unify_dotdot_attribute_store
+ zpc_attribute_store_network_helper_mock
+ zwave_command_class_test_helpers
+ )
+
# User Code Cluster Server test
target_add_unittest(
zcl_cluster_servers
@@ -126,4 +141,4 @@ target_add_unittest(
DEPENDS
zpc_attribute_store_test_helper
uic_dotdot_mqtt_mock
- unify_dotdot_attribute_store)
\ No newline at end of file
+ unify_dotdot_attribute_store)
diff --git a/applications/zpc/components/zcl_cluster_servers/test/schedule_entry_lock_server_test.cpp b/applications/zpc/components/zcl_cluster_servers/test/schedule_entry_lock_server_test.cpp
new file mode 100644
index 000000000..4cf3ad045
--- /dev/null
+++ b/applications/zpc/components/zcl_cluster_servers/test/schedule_entry_lock_server_test.cpp
@@ -0,0 +1,524 @@
+/******************************************************************************
+ * # 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 "schedule_entry_lock_server.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 "zpc_attribute_store_network_helper.h"
+
+// ZPC Components
+#include "zwave_unid.h"
+#include "zwave_command_class_schedule_entry_lock.h"
+#include "zwave_command_class_test_helper.hpp"
+
+// Test helpers
+#include "zpc_attribute_store_test_helper.h"
+
+// Attribute macro, shortening those long defines for attribute types:
+#define ATTRIBUTE(type) ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_##type
+using namespace zwave_command_class_test_helper;
+
+extern "C" {
+
+// Mock helper
+#include "dotdot_mqtt_mock.h"
+#include "dotdot_mqtt_generated_commands_mock.h"
+#include "zpc_attribute_store_network_helper_mock.h"
+#include "attribute_store_defined_attribute_types.h"
+#include "unify_dotdot_attribute_store.h"
+
+// private variables
+
+static uic_mqtt_dotdot_unify_schedule_entry_lock_enable_set_callback_t enable_set = NULL;
+static uic_mqtt_dotdot_unify_schedule_entry_lock_enable_all_set_callback_t enable_all_set = NULL;
+static uic_mqtt_dotdot_unify_schedule_entry_lock_week_day_set_callback_t week_day_set = NULL;
+static uic_mqtt_dotdot_unify_schedule_entry_lock_week_day_get_callback_t week_day_get = NULL;
+static uic_mqtt_dotdot_unify_schedule_entry_lock_year_day_set_callback_t year_day_set = NULL;
+static uic_mqtt_dotdot_unify_schedule_entry_lock_year_day_get_callback_t year_day_get = NULL;
+static uic_mqtt_dotdot_unify_schedule_entry_lock_daily_repeating_set_callback_t daily_repeating_set = NULL;
+static uic_mqtt_dotdot_unify_schedule_entry_lock_daily_repeating_get_callback_t daily_repeating_get = NULL;
+static uic_mqtt_dotdot_unify_schedule_entry_lock_write_attributes_callback_t write_attributes_callback = NULL;
+
+void uic_mqtt_dotdot_unify_schedule_entry_lock_enable_set_callback_set_stub(const uic_mqtt_dotdot_unify_schedule_entry_lock_enable_set_callback_t callback,int cmock_num_calls){
+ enable_set = callback;
+}
+
+void uic_mqtt_dotdot_unify_schedule_entry_lock_enable_all_set_callback_set_stub(const uic_mqtt_dotdot_unify_schedule_entry_lock_enable_all_set_callback_t callback,int cmock_num_calls){
+ enable_all_set = callback;
+}
+
+void uic_mqtt_dotdot_unify_schedule_entry_lock_week_day_set_callback_set_stub(const uic_mqtt_dotdot_unify_schedule_entry_lock_week_day_set_callback_t callback,int cmock_num_calls)
+{
+ week_day_set = callback;
+}
+
+void uic_mqtt_dotdot_unify_schedule_entry_lock_week_day_get_callback_set_stub(const uic_mqtt_dotdot_unify_schedule_entry_lock_week_day_get_callback_t callback,int cmock_num_calls)
+{
+ week_day_get = callback;
+}
+
+void uic_mqtt_dotdot_unify_schedule_entry_lock_year_day_set_callback_set_stub(const uic_mqtt_dotdot_unify_schedule_entry_lock_year_day_set_callback_t callback,int cmock_num_calls)
+{
+ year_day_set = callback;
+}
+
+void uic_mqtt_dotdot_unify_schedule_entry_lock_year_day_get_callback_set_stub(const uic_mqtt_dotdot_unify_schedule_entry_lock_year_day_get_callback_t callback,int cmock_num_calls)
+{
+ year_day_get = callback;
+}
+
+void uic_mqtt_dotdot_unify_schedule_entry_lock_daily_repeating_set_callback_set_stub(const uic_mqtt_dotdot_unify_schedule_entry_lock_daily_repeating_set_callback_t callback,int cmock_num_calls){
+ daily_repeating_set = callback;
+}
+
+void uic_mqtt_dotdot_unify_schedule_entry_lock_daily_repeating_get_callback_set_stub(const uic_mqtt_dotdot_unify_schedule_entry_lock_daily_repeating_get_callback_t callback,int cmock_num_calls){
+ daily_repeating_get = callback;
+}
+
+void uic_mqtt_dotdot_set_unify_schedule_entry_lock_write_attributes_callback_stub(const uic_mqtt_dotdot_unify_schedule_entry_lock_write_attributes_callback_t callback, int cmock_num_calls){
+ write_attributes_callback = 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();
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_enable_set_callback_set_Stub(
+ &uic_mqtt_dotdot_unify_schedule_entry_lock_enable_set_callback_set_stub);
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_enable_all_set_callback_set_Stub(
+ &uic_mqtt_dotdot_unify_schedule_entry_lock_enable_all_set_callback_set_stub);
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_week_day_set_callback_set_Stub(
+ &uic_mqtt_dotdot_unify_schedule_entry_lock_week_day_set_callback_set_stub);
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_week_day_get_callback_set_Stub(
+ &uic_mqtt_dotdot_unify_schedule_entry_lock_week_day_get_callback_set_stub);
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_year_day_set_callback_set_Stub(
+ &uic_mqtt_dotdot_unify_schedule_entry_lock_year_day_set_callback_set_stub);
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_year_day_get_callback_set_Stub(
+ &uic_mqtt_dotdot_unify_schedule_entry_lock_year_day_get_callback_set_stub);
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_daily_repeating_set_callback_set_Stub(
+ &uic_mqtt_dotdot_unify_schedule_entry_lock_daily_repeating_set_callback_set_stub);
+
+ uic_mqtt_dotdot_unify_schedule_entry_lock_daily_repeating_get_callback_set_Stub(
+ &uic_mqtt_dotdot_unify_schedule_entry_lock_daily_repeating_get_callback_set_stub);
+
+ uic_mqtt_dotdot_set_unify_schedule_entry_lock_write_attributes_callback_Stub(
+ &uic_mqtt_dotdot_set_unify_schedule_entry_lock_write_attributes_callback_stub);
+
+ // Call init
+ TEST_ASSERT_EQUAL(SL_STATUS_OK, schedule_entry_lock_cluster_server_init());
+}
+
+/// Called after each and every test
+void tearDown()
+{
+ attribute_store_delete_node(attribute_store_get_root());
+}
+
+void test_schedule_entry_lock_enable_set()
+{
+ TEST_ASSERT_NOT_NULL(enable_set);
+ uint8_t user_id = 3;
+ uint8_t enabled = 1;
+
+ attribute_store::attribute ep_node_id(endpoint_id_node);
+
+ auto user_id_node = ep_node_id.emplace_node(ATTRIBUTE(USER_IDENTIFIER));
+ user_id_node.emplace_node(ATTRIBUTE(ENABLED));
+ user_id_node.set_reported(user_id);
+ ep_node_id.emplace_node(ATTRIBUTE(SLOTS_WEEK_DAY));
+ ep_node_id.emplace_node(ATTRIBUTE(HOUR_TZO));
+
+ attribute_store_network_helper_get_node_id_node_IgnoreAndReturn(node_id_node);
+
+ // Support check
+ TEST_ASSERT_EQUAL(
+ SL_STATUS_OK,
+ enable_set(supporting_node_unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK,
+ user_id,
+ enabled));
+
+ // Test callback
+ TEST_ASSERT_EQUAL(
+ SL_STATUS_OK,
+ enable_set(supporting_node_unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL,
+ user_id,
+ enabled));
+}
+
+void test_schedule_entry_lock_enable_all_set(){
+ TEST_ASSERT_NOT_NULL(enable_all_set);
+ uint8_t enabled = 1;
+ attribute_store::attribute ep_node_id(endpoint_id_node);
+ ep_node_id.emplace_node(ATTRIBUTE(ENABLE_ALL));
+ ep_node_id.emplace_node(ATTRIBUTE(SLOTS_WEEK_DAY));
+ ep_node_id.emplace_node(ATTRIBUTE(HOUR_TZO));
+
+
+ attribute_store_network_helper_get_node_id_node_IgnoreAndReturn(node_id_node);
+
+ // Support check
+ TEST_ASSERT_EQUAL(
+ SL_STATUS_OK,
+ enable_all_set(supporting_node_unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK,
+ enabled));
+
+ // Test callback
+ TEST_ASSERT_EQUAL(
+ SL_STATUS_OK,
+ enable_all_set(supporting_node_unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL,
+ enabled));
+
+}
+
+void test_schedule_entry_lock_week_day_set(){
+ TEST_ASSERT_NOT_NULL(week_day_set);
+ uint8_t set_action = 1;
+ uint8_t user_identifier = 1;
+ uint8_t schedule_slotid = 1;
+ uint8_t day_of_week = 2;
+ uint8_t start_hour = 2;
+ uint8_t start_minute = 3;
+ uint8_t stop_hour = 3;
+ uint8_t stop_minute = 4;
+
+ attribute_store::attribute ep_node_id(endpoint_id_node);
+ auto user_id_node = ep_node_id.emplace_node(ATTRIBUTE(USER_IDENTIFIER));
+ auto slot_id_node = user_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_SLOT_ID));
+ user_id_node.set_reported(user_identifier);
+ slot_id_node.set_reported(schedule_slotid);
+ slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_SET_ACTION));
+ slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_DAY_OF_WEEK));
+ slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_START_HOUR));
+ slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_START_MINUTE));
+ slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_STOP_HOUR));
+ slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_STOP_MINUTE));
+
+ ep_node_id.emplace_node(ATTRIBUTE(SLOTS_WEEK_DAY));
+ ep_node_id.emplace_node(ATTRIBUTE(HOUR_TZO));
+
+ attribute_store_network_helper_get_node_id_node_IgnoreAndReturn(node_id_node);
+
+ // Support check
+ TEST_ASSERT_EQUAL(
+ SL_STATUS_OK,
+ week_day_set(supporting_node_unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK,
+ set_action,user_identifier,schedule_slotid,day_of_week,start_hour,start_minute,stop_hour,stop_minute));
+
+ // Test callback
+ TEST_ASSERT_EQUAL(
+ SL_STATUS_OK,
+ week_day_set(supporting_node_unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL,
+ set_action,user_identifier,schedule_slotid,day_of_week,start_hour,start_minute,stop_hour,stop_minute));
+}
+
+void test_schedule_entry_lock_week_day_get(){
+ TEST_ASSERT_NOT_NULL(week_day_get);
+ uint8_t user_identifier = 1;
+ uint8_t schedule_slotid = 1;
+
+ attribute_store::attribute ep_node_id(endpoint_id_node);
+ auto user_id_node = ep_node_id.emplace_node(ATTRIBUTE(USER_IDENTIFIER));
+ auto slot_id_node = user_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_SLOT_ID));
+ user_id_node.set_reported(user_identifier);
+ slot_id_node.set_reported(schedule_slotid);
+ ep_node_id.emplace_node(ATTRIBUTE(SLOTS_WEEK_DAY));
+ ep_node_id.emplace_node(ATTRIBUTE(HOUR_TZO));
+ slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_SET_ACTION));
+
+ attribute_store_network_helper_get_node_id_node_IgnoreAndReturn(node_id_node);
+
+ // Support check
+ TEST_ASSERT_EQUAL(
+ SL_STATUS_OK,
+ week_day_get(supporting_node_unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK,
+ user_identifier,schedule_slotid));
+
+ // Test callback
+ TEST_ASSERT_EQUAL(
+ SL_STATUS_OK,
+ week_day_get(supporting_node_unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL,
+ user_identifier,schedule_slotid));
+}
+
+void test_schedule_entry_lock_year_day_set(){
+ TEST_ASSERT_NOT_NULL(year_day_set);
+ uint8_t set_action = 1;
+ uint8_t user_identifier = 1;
+ uint8_t schedule_slotid = 1;
+ uint8_t start_year = 2;
+ uint8_t start_day = 2;
+ uint8_t start_month = 2;
+ uint8_t start_hour = 2;
+ uint8_t start_minute = 3;
+ uint8_t stop_year = 3;
+ uint8_t stop_month = 3;
+ uint8_t stop_hour = 4;
+ uint8_t stop_day = 4;
+ uint8_t stop_minute = 4;
+
+ attribute_store::attribute ep_node_id(endpoint_id_node);
+ auto user_id_node = ep_node_id.emplace_node(ATTRIBUTE(USER_IDENTIFIER));
+ auto slot_id_node = user_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_SLOT_ID));
+ user_id_node.set_reported(user_identifier);
+ slot_id_node.set_reported(schedule_slotid);
+ ep_node_id.emplace_node(ATTRIBUTE(SLOTS_WEEK_DAY));
+ ep_node_id.emplace_node(ATTRIBUTE(HOUR_TZO));
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_SET_ACTION));
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_YEAR));
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_MONTH));
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_DAY));
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_HOUR));
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_MINUTE));
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_YEAR));
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_MONTH));
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_DAY));
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_HOUR));
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_MINUTE));
+
+ attribute_store_network_helper_get_node_id_node_IgnoreAndReturn(node_id_node);
+
+ // Support check
+ TEST_ASSERT_EQUAL(
+ SL_STATUS_OK,
+ year_day_set(supporting_node_unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK,
+ set_action,user_identifier,schedule_slotid,start_year,start_day,start_hour,start_month,start_minute,stop_year,stop_month,stop_day,stop_hour,stop_minute));
+
+ // Test callback
+ TEST_ASSERT_EQUAL(
+ SL_STATUS_OK,
+ year_day_set(supporting_node_unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL,
+ set_action,user_identifier,schedule_slotid,start_year,start_day,start_hour,start_month,start_minute,stop_year,stop_month,stop_day,stop_hour,stop_minute));
+
+}
+
+void test_schedule_entry_lock_year_day_get(){
+ TEST_ASSERT_NOT_NULL(year_day_get);
+ uint8_t user_identifier = 1;
+ uint8_t schedule_slotid = 1;
+
+ attribute_store::attribute ep_node_id(endpoint_id_node);
+ auto user_id_node = ep_node_id.emplace_node(ATTRIBUTE(USER_IDENTIFIER));
+ auto slot_id_node = user_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_SLOT_ID));
+ user_id_node.set_reported(user_identifier);
+ slot_id_node.set_reported(schedule_slotid);
+ ep_node_id.emplace_node(ATTRIBUTE(SLOTS_WEEK_DAY));
+ ep_node_id.emplace_node(ATTRIBUTE(HOUR_TZO));
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_SET_ACTION));
+
+ attribute_store_network_helper_get_node_id_node_IgnoreAndReturn(node_id_node);
+
+ // Support check
+ TEST_ASSERT_EQUAL(
+ SL_STATUS_OK,
+ year_day_get(supporting_node_unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK,
+ user_identifier,schedule_slotid));
+
+ // Test callback
+ TEST_ASSERT_EQUAL(
+ SL_STATUS_OK,
+ year_day_get(supporting_node_unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL,
+ user_identifier,schedule_slotid));
+
+}
+
+
+void test_schedule_entry_lock_daily_repeating_set(){
+ TEST_ASSERT_NOT_NULL(daily_repeating_set);
+ uint8_t set_action = 1;
+ uint8_t user_identifier = 1;
+ uint8_t schedule_slotid = 1;
+ uint8_t week_day_bitmask = 2;
+ uint8_t start_hour = 2;
+ uint8_t start_minute = 3;
+ uint8_t duration_hour = 3;
+ uint8_t duration_minute = 4;
+
+ attribute_store::attribute ep_node_id(endpoint_id_node);
+ auto user_id_node = ep_node_id.emplace_node(ATTRIBUTE(USER_IDENTIFIER));
+ auto slot_id_node = user_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_SCHEDULE_SLOT_ID));
+ user_id_node.set_reported(user_identifier);
+ slot_id_node.set_reported(schedule_slotid);
+ ep_node_id.emplace_node(ATTRIBUTE(SLOTS_WEEK_DAY));
+ ep_node_id.emplace_node(ATTRIBUTE(HOUR_TZO));
+ slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_SET_ACTION));
+ slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_WEEK_DAY));
+ slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_START_HOUR));
+ slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_START_MINUTE));
+ slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_DURATION_HOUR));
+ slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_DURATION_MINUTE));
+
+ attribute_store_network_helper_get_node_id_node_IgnoreAndReturn(node_id_node);
+
+ // Support check
+ TEST_ASSERT_EQUAL(
+ SL_STATUS_OK,
+ daily_repeating_set(supporting_node_unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK,
+ set_action,user_identifier,schedule_slotid,week_day_bitmask,start_hour,start_minute,duration_hour,duration_minute));
+
+ // Test callback
+ TEST_ASSERT_EQUAL(
+ SL_STATUS_OK,
+ daily_repeating_set(supporting_node_unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL,
+ set_action,user_identifier,schedule_slotid,week_day_bitmask,start_hour,start_minute,duration_hour,duration_minute));
+}
+
+void test_schedule_entry_lock_daily_repeating_get(){
+ TEST_ASSERT_NOT_NULL(daily_repeating_get);
+ uint8_t user_identifier = 1;
+ uint8_t schedule_slotid = 1;
+
+ attribute_store::attribute ep_node_id(endpoint_id_node);
+ auto user_id_node = ep_node_id.emplace_node(ATTRIBUTE(USER_IDENTIFIER));
+ auto slot_id_node = user_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_SCHEDULE_SLOT_ID));
+ user_id_node.set_reported(user_identifier);
+ slot_id_node.set_reported(schedule_slotid);
+ ep_node_id.emplace_node(ATTRIBUTE(SLOTS_WEEK_DAY));
+ ep_node_id.emplace_node(ATTRIBUTE(HOUR_TZO));
+ slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_SET_ACTION));
+
+ attribute_store_network_helper_get_node_id_node_IgnoreAndReturn(node_id_node);
+
+ // Support check
+ TEST_ASSERT_EQUAL(
+ SL_STATUS_OK,
+ daily_repeating_get(supporting_node_unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK,
+ user_identifier,schedule_slotid));
+
+ // Test callback
+ TEST_ASSERT_EQUAL(
+ SL_STATUS_OK,
+ daily_repeating_get(supporting_node_unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL,
+ user_identifier,schedule_slotid));
+}
+
+void test_schedule_entry_lock_write_attributes_callback()
+{
+ TEST_ASSERT_NOT_NULL(write_attributes_callback);
+
+ attribute_store_network_helper_get_node_id_node_IgnoreAndReturn(node_id_node);
+
+ // Define the lock state with sample values
+ uic_mqtt_dotdot_unify_schedule_entry_lock_state_t lock_state = {};
+ lock_state.slots_week_day = 1;
+ lock_state.slots_year_day = 2;
+ lock_state.signtzo = 3;
+ lock_state.hourtzo = 4;
+ lock_state.minutetzo = 5;
+ lock_state.dst_offset_sign = 6;
+ lock_state.dst_offset_minute = 7;
+ lock_state.number_of_slots_daily_repeating = 8;
+
+ // Define the updated state to indicate which attributes are updated
+ uic_mqtt_dotdot_unify_schedule_entry_lock_updated_state_t updated_lock_state = {};
+ updated_lock_state.slots_week_day = true;
+ updated_lock_state.slots_year_day = true;
+ updated_lock_state.signtzo = true;
+ updated_lock_state.hourtzo = true;
+ updated_lock_state.minutetzo = true;
+ updated_lock_state.dst_offset_sign = true;
+ updated_lock_state.dst_offset_minute = true;
+ updated_lock_state.number_of_slots_daily_repeating = true;
+
+ // Mock attribute nodes for testing each field
+ attribute_store::attribute ep_node_id(endpoint_id_node);
+ auto slots_week_day_node = ep_node_id.emplace_node(DOTDOT_ATTRIBUTE_ID_UNIFY_SCHEDULE_ENTRY_LOCK_SLOTS_WEEK_DAY);
+ auto slots_year_day_node = ep_node_id.emplace_node(DOTDOT_ATTRIBUTE_ID_UNIFY_SCHEDULE_ENTRY_LOCK_SLOTS_YEAR_DAY);
+ auto signtzo_node = ep_node_id.emplace_node(DOTDOT_ATTRIBUTE_ID_UNIFY_SCHEDULE_ENTRY_LOCK_SIGNTZO);
+ auto hourtzo_node = ep_node_id.emplace_node(DOTDOT_ATTRIBUTE_ID_UNIFY_SCHEDULE_ENTRY_LOCK_HOURTZO);
+ auto minutetzo_node = ep_node_id.emplace_node(DOTDOT_ATTRIBUTE_ID_UNIFY_SCHEDULE_ENTRY_LOCK_MINUTETZO);
+ auto dst_offset_sign_node = ep_node_id.emplace_node(DOTDOT_ATTRIBUTE_ID_UNIFY_SCHEDULE_ENTRY_LOCK_DST_OFFSET_SIGN);
+ auto dst_offset_minute_node = ep_node_id.emplace_node(DOTDOT_ATTRIBUTE_ID_UNIFY_SCHEDULE_ENTRY_LOCK_DST_OFFSET_MINUTE);
+ auto number_of_slots_daily_repeating_node = ep_node_id.emplace_node(DOTDOT_ATTRIBUTE_ID_UNIFY_SCHEDULE_ENTRY_LOCK_NUMBER_OF_SLOTS_DAILY_REPEATING);
+
+ uic_mqtt_dotdot_set_unify_schedule_entry_lock_write_attributes_callback_Ignore();
+ // Run the callback
+ write_attributes_callback(
+ supporting_node_unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL,
+ lock_state,
+ updated_lock_state
+ );
+
+ // Test the desired values set by the callback
+ TEST_ASSERT_EQUAL_UINT8(lock_state.slots_week_day, slots_week_day_node.desired());
+ TEST_ASSERT_EQUAL_UINT8(lock_state.slots_year_day, slots_year_day_node.desired());
+ TEST_ASSERT_EQUAL_UINT8(lock_state.signtzo, signtzo_node.desired());
+ TEST_ASSERT_EQUAL_UINT8(lock_state.hourtzo, hourtzo_node.desired());
+ TEST_ASSERT_EQUAL_UINT8(lock_state.minutetzo, minutetzo_node.desired());
+ TEST_ASSERT_EQUAL_UINT8(lock_state.dst_offset_sign, dst_offset_sign_node.desired());
+ TEST_ASSERT_EQUAL_UINT8(lock_state.dst_offset_minute, dst_offset_minute_node.desired());
+ TEST_ASSERT_EQUAL_UINT8(lock_state.number_of_slots_daily_repeating, number_of_slots_daily_repeating_node.desired());
+}
+
+} // extern "C"
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 8d5e36adb..0167e691e 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
@@ -305,6 +305,164 @@ DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_DOOR_LOCK_OPERATION_REPORT_TARGET_MODE,
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_DOOR_LOCK_OPERATION_REPORT_DURATION,
((COMMAND_CLASS_DOOR_LOCK << 8) | 0x1e))
+///////////////////////////////////
+// Schedule Entry Lock Command Class
+
+// Version Attribute for the Schedule Entry Lock Command Class
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_VERSION,
+ ZWAVE_CC_VERSION_ATTRIBUTE(COMMAND_CLASS_SCHEDULE_ENTRY_LOCK))
+
+// V1
+// User Identifier Attribute
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_USER_IDENTIFIER,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x02))
+
+// Enabled Attribute
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_ENABLED,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x03))
+
+// Attribute for the Schedule Entry Lock Enable All Set Command (Enabled field)
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_ENABLE_ALL,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x04))
+
+// Number of Slots Week Day Attribute (for Schedule Entry Lock Supported Report Command)
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_SLOTS_WEEK_DAY,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x05))
+
+// Number of Slots Year Day Attribute (for Schedule Entry Lock Supported Report Command)
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_SLOTS_YEAR_DAY,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x06))
+
+// Week Day Schedule Set Action Attribute
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_SET_ACTION,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x07))
+
+// Week Day Schedule Slot ID Attribute
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_SLOT_ID,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x09))
+
+// Week Day Schedule Day of Week Attribute
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_DAY_OF_WEEK,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x0A))
+
+// Week Day Schedule Start Hour Attribute
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_START_HOUR,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x0B))
+
+// Week Day Schedule Start Minute Attribute
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_START_MINUTE,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x0C))
+
+// Week Day Schedule Stop Hour Attribute
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_STOP_HOUR,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x0D))
+
+// Week Day Schedule Stop Minute Attribute
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_STOP_MINUTE,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x0E))
+
+// Year Day Schedule Set Action
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_SET_ACTION,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x0F))
+
+// Year Day Schedule Slot ID
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_SLOT_ID,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x10))
+
+// Year Day Schedule Start Year
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_START_YEAR,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x11))
+
+// Year Day Schedule Start Month
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_START_MONTH,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x12))
+
+// Year Day Schedule Start Day
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_START_DAY,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x13))
+
+// Year Day Schedule Start Hour
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_START_HOUR,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x14))
+
+// Year Day Schedule Start Minutes
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_START_MINUTE,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x15))
+
+// Year Day Schedule Stop Year
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_STOP_YEAR,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x16))
+
+// Year Day Schedule Stop Month
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_STOP_MONTH,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x17))
+
+// Year Day Schedule Stop Day
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_STOP_DAY,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x18))
+
+// Year Day Schedule Stop Hour
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_STOP_HOUR,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x19))
+
+// Year Day Schedule Stop Minutes
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_STOP_MINUTE,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x1A))
+
+// V2
+// Time Zone Offset Sign Attribute
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_SIGN_TZO,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x1B))
+
+// Time Zone Offset Hour Attribute
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_HOUR_TZO,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x1C))
+
+// Time Zone Offset Minute Attribute
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_MINUTE_TZO,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x1D))
+
+// Daylight Saving Time (DST) Offset Sign Attribute
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DST_OFFSET_SIGN,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x1E))
+
+// DST Offset Minute Attribute
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DST_OFFSET_MINUTE,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x1F))
+
+// V3
+/// Number of Slots Daily Repeating
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_NUMBER_OF_SLOTS_DAILY_REPEATING,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x20))
+
+// Daily Repeating Set Action
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_SET_ACTION,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x21))
+
+// Daily Repeating Slot ID
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_SCHEDULE_SLOT_ID,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x22))
+
+// Daily Repeating Week Day
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_WEEK_DAY,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x23))
+
+// Daily Repeating Start Hour
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_START_HOUR,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x24))
+
+// Daily Repeating Start Minute
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_START_MINUTE,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x25))
+
+// Daily Repeating Duration Hour
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_DURATION_HOUR,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x26))
+
+// Daily Repeating Duration Minute
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_DURATION_MINUTE,
+ ((COMMAND_CLASS_SCHEDULE_ENTRY_LOCK << 8) | 0x27))
+
///////////////////////////////////
// Binary Switch Command Class
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_BINARY_SWITCH_VERSION,
@@ -822,7 +980,7 @@ DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_MAX_VALUE,
// 0x0B
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_MAX_VALUE_SCALE,
((COMMAND_CLASS_THERMOSTAT_SETPOINT << 8) | (0x0A + SETPOINT_SCALE_ATTRIBUTE_ID_OFFSET)))
-// 0x0C
+// 0x0C
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_MAX_VALUE_PRECISION,
((COMMAND_CLASS_THERMOSTAT_SETPOINT << 8) | (0x0A + SETPOINT_PRECISION_ATTRIBUTE_ID_OFFSET)))
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 574642769..064366c71 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
@@ -121,7 +121,7 @@ static const std::vector attribute_schema = {
// V3+ report
{ATTRIBUTE_COMMAND_CLASS_BATTERY_LOW_TEMPERATURE, "Battery Low Temperature", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
- // Health report (V2+)
+ // Health report (V2+)
{ATTRIBUTE_COMMAND_CLASS_BATTERY_HEALTH_MAXIMUM_CAPACITY, "Maximum Capacity", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
{ATTRIBUTE_COMMAND_CLASS_BATTERY_HEALTH_SCALE, "Scale", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
{ATTRIBUTE_COMMAND_CLASS_BATTERY_HEALTH_PRECISION, "Precision", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
@@ -406,7 +406,7 @@ static const std::vector attribute_schema = {
/////////////////////////////////////////////////////////////////////
{ATTRIBUTE_COMMAND_CLASS_SUPERVISION_VERSION, "Supervision Version", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
{ATTRIBUTE_COMMAND_CLASS_SUPERVISION_ENABLED, "Supervision Enabled flag", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
-
+
/////////////////////////////////////////////////////////////////////
// Wake Up Command Class attributes
/////////////////////////////////////////////////////////////////////
@@ -514,6 +514,50 @@ static const std::vector attribute_schema = {
{ATTRIBUTE_COMMAND_CLASS_SOUND_SWITCH_TONE_INFO_NAME, "Tone Info Name", ATTRIBUTE_COMMAND_CLASS_SOUND_SWITCH_TONE_INFO_IDENTIFIER, C_STRING_STORAGE_TYPE},
{ATTRIBUTE_COMMAND_CLASS_SOUND_SWITCH_TONE_PLAY, "Tone Play", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
+ /////////////////////////////////////////////////////////////////////
+ // Schedule Entry Lock Class attributes
+ /////////////////////////////////////////////////////////////////////
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_VERSION, "Schedule Entry Lock Version", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_USER_IDENTIFIER, "Schedule Entry Lock User Identifier", ATTRIBUTE_ENDPOINT_ID, U16_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_ENABLED, "Schedule Entry Lock Enable", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_USER_IDENTIFIER, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_ENABLE_ALL, "Schedule Entry Lock All Set Enable", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_SLOTS_WEEK_DAY, "Number Of Slots Week Day", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_SLOTS_YEAR_DAY, "Number Of Slots Year Day", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_SLOT_ID, "Week Day Schedule Slot ID", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_USER_IDENTIFIER, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_SET_ACTION, "Week Day Schedule Set Action", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_DAY_OF_WEEK, "Week Day Schedule Day Of Week", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_START_HOUR, "Week Day Schedule Start Hour", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_START_MINUTE, "Week Day Schedule Start Minute", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_STOP_HOUR, "Week Day Schedule Stop Hour", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_STOP_MINUTE, "Week Day Schedule Stop Minute", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_WEEK_DAY_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_SLOT_ID, "Year Day Schedule Slot ID", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_USER_IDENTIFIER, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_SET_ACTION, "Year Day Schedule Set Action", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_START_YEAR, "Year Day Schedule Start Year", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_START_MONTH, "Year Day Schedule Start Month", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_START_DAY, "Year Day Schedule Start Day", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_START_HOUR, "Year Day Schedule Start Hour", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_START_MINUTE, "Year Day Schedule Start Minute", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_STOP_YEAR, "Year Day Schedule Stop Year", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_STOP_MONTH, "Year Day Schedule Stop Month", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_STOP_DAY, "Year Day Schedule Stop Day", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_STOP_HOUR, "Year Day Schedule Stop Hour", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_STOP_MINUTE, "Year Day Schedule Stop Minute", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_YEAR_DAY_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_SIGN_TZO, "Schedule Entry Lock Sign TZO", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_HOUR_TZO, "Schedule Entry Lock Hour TZO", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_MINUTE_TZO, "Schedule Entry Lock Minute TZO", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DST_OFFSET_SIGN, "Schedule Entry Lock Sign Offset DST", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DST_OFFSET_MINUTE, "Schedule Entry Lock Minute Offset DST", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
+
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_NUMBER_OF_SLOTS_DAILY_REPEATING, "Number of Slots Daily Repeating", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_SET_ACTION, "Daily Repeating Set Action", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_SCHEDULE_SLOT_ID, "Daily Repeating Slot ID", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_USER_IDENTIFIER, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_WEEK_DAY, "Daily Repeating Week Day", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_START_HOUR, "Daily Repeating Start Hour", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_START_MINUTE, "Daily Repeating Start Minute", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_DURATION_HOUR, "Daily Repeating Duration Hour", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_DURATION_MINUTE, "Daily Repeating Duration Minute", ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_SCHEDULE_SLOT_ID, U8_STORAGE_TYPE},
+
//DoorLock Command Class attributes
{ATTRIBUTE_DOOR_LOCK_CONFIGURATION_OPERATION_TYPE, "Door Lock Configuration Operation Type", ATTRIBUTE_ENDPOINT_ID, I32_STORAGE_TYPE },
{ATTRIBUTE_DOOR_LOCK_CONFIGURATION_INSIDE_DOOR_HANDLES_STATE, "Door Lock Configuration Inside Handles State", ATTRIBUTE_ENDPOINT_ID, I32_STORAGE_TYPE },
diff --git a/applications/zpc/components/zwave_command_classes/CMakeLists.txt b/applications/zpc/components/zwave_command_classes/CMakeLists.txt
index 99c75db5f..a6c67d948 100644
--- a/applications/zpc/components/zwave_command_classes/CMakeLists.txt
+++ b/applications/zpc/components/zwave_command_classes/CMakeLists.txt
@@ -41,6 +41,7 @@ add_library(
src/zwave_command_class_scene_activation_control.c
src/zwave_command_class_scene_actuator_configuration_control.c
src/zwave_command_class_scene_controller_configuration_control.c
+ src/zwave_command_class_schedule_entry_lock.cpp
src/zwave_command_class_security_0.c
src/zwave_command_class_security_2.c
src/zwave_command_class_supervision.c
@@ -128,6 +129,7 @@ target_link_libraries(zwave_command_classes
zpc_utils
zpc_scripts
unify
+ zcl_cluster_servers
zwave_definitions)
if(BUILD_TESTING)
diff --git a/applications/zpc/components/zwave_command_classes/src/zwave_command_class_schedule_entry_lock.cpp b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_schedule_entry_lock.cpp
new file mode 100644
index 000000000..19fb0f6a0
--- /dev/null
+++ b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_schedule_entry_lock.cpp
@@ -0,0 +1,977 @@
+/******************************************************************************
+ * # 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_schedule_entry_lock.h"
+#include "zwave_command_classes_utils.h"
+#include "schedule_entry_lock_server.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"
+
+// Attribute macro, shortening those long defines for attribute types:
+#define ATTRIBUTE(type) ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_##type
+
+// Log tag
+constexpr char LOG_TAG[] = "zwave_command_class_schedule_entry_lock";
+
+// Cpp helpers
+namespace
+{
+zwave_frame_generator frame_generator(
+ COMMAND_CLASS_SCHEDULE_ENTRY_LOCK); //NOSONAR - false positive since it is warped in a namespace
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Helper functions
+///////////////////////////////////////////////////////////////////////////////
+zwave_cc_version_t
+ get_current_schedule_entry_lock_version(attribute_store_node_t node)
+{
+ zwave_cc_version_t version = zwave_command_class_get_version_from_node(
+ node,
+ COMMAND_CLASS_SCHEDULE_ENTRY_LOCK);
+
+ if (version == 0) {
+ sl_log_error(LOG_TAG,
+ "schedule_entry_lock Command Class Version not found");
+ }
+
+ return version;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Resolution functions
+///////////////////////////////////////////////////////////////////////////////
+static sl_status_t zwave_command_class_schedule_entry_lock_get(
+ attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
+{
+ if (attribute_store_get_node_type(node) == ATTRIBUTE(SLOTS_WEEK_DAY)) {
+ return frame_generator.generate_no_args_frame(
+ SCHEDULE_ENTRY_TYPE_SUPPORTED_GET,
+ frame,
+ frame_length);
+ }
+
+ return SL_STATUS_INVALID_TYPE;
+}
+
+static sl_status_t zwave_command_class_schedule_entry_lock_time_offset_get(
+ attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
+{
+ if (attribute_store_get_node_type(node) == ATTRIBUTE(HOUR_TZO)) {
+ return frame_generator.generate_no_args_frame(
+ SCHEDULE_ENTRY_LOCK_TIME_OFFSET_GET_V2,
+ frame,
+ frame_length);
+ }
+ return SL_STATUS_INVALID_TYPE;
+}
+
+static sl_status_t zwave_command_class_schedule_entry_lock_week_day_get(
+ attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
+{
+ if (attribute_store_get_node_type(node)
+ == ATTRIBUTE(WEEK_DAY_SCHEDULE_SET_ACTION)) {
+ try {
+ // Retrieve the node attributes
+ attribute_store::attribute weekday_schedule_set_action_node(node);
+ auto weekday_schedule_slot_id_node = weekday_schedule_set_action_node.parent();
+ auto user_id_node = weekday_schedule_slot_id_node.first_parent(
+ ATTRIBUTE(USER_IDENTIFIER));
+
+ // Compute expected size for the set frame
+ const uint8_t expected_frame_size = 4;
+
+ // Initialize the frame for Schedule Entry Lock Time Offset Set command
+ frame_generator.initialize_frame(SCHEDULE_ENTRY_LOCK_WEEK_DAY_GET,
+ frame,
+ expected_frame_size);
+ frame_generator.add_value(user_id_node, DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(weekday_schedule_slot_id_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ // Validate the constructed frame and set the frame length
+ frame_generator.validate_frame(frame_length);
+ } catch (const std::exception &e) {
+ // Log any error that occurs during the frame generation process
+ sl_log_error(LOG_TAG,
+ "Error while generating Schedule Entry Lock Set frame: %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+ }
+ return SL_STATUS_OK;
+}
+
+static sl_status_t zwave_command_class_schedule_entry_lock_year_day_get(
+ attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
+{
+ if (attribute_store_get_node_type(node)
+ == ATTRIBUTE(YEAR_DAY_SCHEDULE_SET_ACTION)) {
+ try {
+ // Retrieve the node attributes
+ attribute_store::attribute yearday_schedule_set_action_node(node);
+ auto yearday_schedule_slot_id_node = yearday_schedule_set_action_node.parent();
+ auto user_id_node = yearday_schedule_slot_id_node.first_parent(
+ ATTRIBUTE(USER_IDENTIFIER));
+
+ // Compute expected size for the set frame
+ const uint8_t expected_frame_size = 4;
+
+ // Initialize the frame for Schedule Entry Lock Time Offset Set command
+ frame_generator.initialize_frame(SCHEDULE_ENTRY_LOCK_YEAR_DAY_GET,
+ frame,
+ expected_frame_size);
+ frame_generator.add_value(user_id_node, DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(yearday_schedule_slot_id_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ // Validate the constructed frame and set the frame length
+ frame_generator.validate_frame(frame_length);
+ } catch (const std::exception &e) {
+ // Log any error that occurs during the frame generation process
+ sl_log_error(LOG_TAG,
+ "Error while generating Schedule Entry Lock Set frame: %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+ }
+ return SL_STATUS_OK;
+}
+
+static sl_status_t zwave_command_class_schedule_entry_lock_daily_repeating_get(
+ attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
+{
+ if (attribute_store_get_node_type(node)
+ == ATTRIBUTE(DAILY_REPEATING_SET_ACTION)) {
+ try {
+ // Retrieve the node attributes
+ attribute_store::attribute dailyrepeating_schedule_set_action_node(node);
+ auto dailyrepeating_schedule_slot_id_node = dailyrepeating_schedule_set_action_node.parent();
+ auto user_id_node = dailyrepeating_schedule_slot_id_node.first_parent(
+ ATTRIBUTE(USER_IDENTIFIER));
+
+ // Compute expected size for the set frame
+ const uint8_t expected_frame_size = 4;
+
+ // Initialize the frame for Schedule Entry Lock Time Offset Set command
+ frame_generator.initialize_frame(
+ SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_GET_V3,
+ frame,
+ expected_frame_size);
+ frame_generator.add_value(user_id_node, DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(dailyrepeating_schedule_slot_id_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ // Validate the constructed frame and set the frame length
+ frame_generator.validate_frame(frame_length);
+ } catch (const std::exception &e) {
+ // Log any error that occurs during the frame generation process
+ sl_log_error(LOG_TAG,
+ "Error while generating Schedule Entry Lock Set frame: %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+ }
+ return SL_STATUS_OK;
+}
+
+static sl_status_t zwave_command_class_schedule_entry_lock_time_offset_set(
+ attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
+{
+ try {
+ // Retrieve the node attributes
+ attribute_store::attribute hour_tzo_node(node);
+ auto endpoint_node = hour_tzo_node.parent();
+ auto minute_tzo_node = endpoint_node.child_by_type(ATTRIBUTE(MINUTE_TZO));
+ auto sign_tzo_node = endpoint_node.child_by_type(ATTRIBUTE(SIGN_TZO));
+ auto sign_offset_dst_node
+ = endpoint_node.child_by_type(ATTRIBUTE(DST_OFFSET_SIGN));
+ auto minute_offset_dst_node
+ = endpoint_node.child_by_type(ATTRIBUTE(DST_OFFSET_MINUTE));
+
+ // Compute expected size for the set frame
+ const uint8_t expected_frame_size = 5;
+
+ // Initialize the frame for Schedule Entry Lock Time Offset Set command
+ frame_generator.initialize_frame(SCHEDULE_ENTRY_LOCK_TIME_OFFSET_SET_V2,
+ frame,
+ expected_frame_size);
+
+ // Create a vector for the values to be shifted into the frame
+ frame_generator.add_shifted_values(
+ {{.left_shift = 7, // Sign TZO (1 bit)
+ .node = sign_tzo_node,
+ .node_value_state = DESIRED_OR_REPORTED_ATTRIBUTE},
+ {.left_shift = 0, // Hour TZO (7 bits)
+ .node = hour_tzo_node,
+ .node_value_state = DESIRED_OR_REPORTED_ATTRIBUTE}});
+ frame_generator.add_value(minute_tzo_node, DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_shifted_values(
+ {{.left_shift = 7, // Sign Offset DST (1 bit)
+ .node = sign_offset_dst_node,
+ .node_value_state = DESIRED_OR_REPORTED_ATTRIBUTE},
+ {.left_shift = 0, // Minute Offset DST (7 bits)
+ .node = minute_offset_dst_node,
+ .node_value_state = DESIRED_OR_REPORTED_ATTRIBUTE}});
+
+ // Validate the constructed frame and set the frame length
+ frame_generator.validate_frame(frame_length);
+
+ } catch (const std::exception &e) {
+ // Log any error that occurs during the frame generation process
+ sl_log_error(LOG_TAG,
+ "Error while generating Schedule Entry Lock Set frame: %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+
+ return SL_STATUS_OK;
+}
+
+static sl_status_t zwave_command_class_schedule_entry_lock_enable_set(
+ attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
+{
+ try {
+ attribute_store::attribute enable_node(node);
+ auto user_id_node = enable_node.parent();
+
+ // Compute expected size for set frame
+ const uint8_t expected_frame_size = 4;
+
+ // Creating the frame
+ frame_generator.initialize_frame(SCHEDULE_ENTRY_LOCK_ENABLE_SET,
+ frame,
+ expected_frame_size);
+ frame_generator.add_value(user_id_node, DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(enable_node, DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.validate_frame(frame_length);
+ } catch (const std::exception &e) {
+ sl_log_error(LOG_TAG,
+ "Error while generating schedule_entry_lock Set frame : %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+
+ return SL_STATUS_OK;
+}
+
+static sl_status_t zwave_command_class_schedule_entry_lock_enable_all_set(
+ attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
+{
+ try {
+ attribute_store::attribute value_node(node);
+
+ // Compute expected size for set frame
+ const uint8_t expected_frame_size = 3;
+
+ // Creating the frame
+ frame_generator.initialize_frame(SCHEDULE_ENTRY_LOCK_ENABLE_ALL_SET,
+ frame,
+ expected_frame_size);
+ frame_generator.add_value(value_node, DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.validate_frame(frame_length);
+ } catch (const std::exception &e) {
+ sl_log_error(LOG_TAG,
+ "Error while generating schedule_entry_lock Set frame : %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+
+ return SL_STATUS_OK;
+}
+
+static sl_status_t zwave_command_class_schedule_entry_lock_week_day_set(
+ attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
+{
+ try {
+ attribute_store::attribute weekday_schedule_set_action_node(node);
+ auto user_id_node = weekday_schedule_set_action_node.first_parent(
+ ATTRIBUTE(USER_IDENTIFIER));
+ auto weekday_schedule_slot_id_node
+ = weekday_schedule_set_action_node.parent();
+ auto weekday_schedule_dayofweek_node
+ = weekday_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_DAY_OF_WEEK));
+ auto weekday_schedule_starthour_node
+ = weekday_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_START_HOUR));
+ auto weekday_schedule_startminute_node
+ = weekday_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_START_MINUTE));
+ auto weekday_schedule_stophour_node
+ = weekday_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_STOP_HOUR));
+ auto weekday_schedule_stopminute_node
+ = weekday_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_STOP_MINUTE));
+
+ // Compute expected size for set frame
+ const uint8_t expected_frame_size = 10;
+
+ // Creating the frame
+ frame_generator.initialize_frame(SCHEDULE_ENTRY_LOCK_WEEK_DAY_SET,
+ frame,
+ expected_frame_size);
+ frame_generator.add_value(weekday_schedule_set_action_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(user_id_node, DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(weekday_schedule_slot_id_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(weekday_schedule_dayofweek_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(weekday_schedule_starthour_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(weekday_schedule_startminute_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(weekday_schedule_stophour_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(weekday_schedule_stopminute_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.validate_frame(frame_length);
+ } catch (const std::exception &e) {
+ sl_log_error(LOG_TAG,
+ "Error while generating schedule_entry_lock Set frame : %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+
+ return SL_STATUS_OK;
+}
+
+static sl_status_t zwave_command_class_schedule_entry_lock_year_day_set(
+ attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
+{
+ try {
+ attribute_store::attribute yearday_schedule_set_action_node(node);
+ auto user_id_node = yearday_schedule_set_action_node.first_parent(
+ ATTRIBUTE(USER_IDENTIFIER));
+ auto yearday_schedule_slot_id_node
+ = yearday_schedule_set_action_node.parent();
+ auto yearday_schedule_startyear_node
+ = yearday_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_START_YEAR));
+ auto yearday_schedule_startmonth_node
+ = yearday_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_START_MONTH));
+ auto yearday_schedule_startday_node
+ = yearday_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_START_DAY));
+ auto yearday_schedule_starthour_node
+ = yearday_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_START_HOUR));
+ auto yearday_schedule_startminute_node
+ = yearday_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_START_MINUTE));
+ auto yearday_schedule_stopyear_node
+ = yearday_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_YEAR));
+ auto yearday_schedule_stopmonth_node
+ = yearday_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_MONTH));
+ auto yearday_schedule_stopday_node
+ = yearday_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_DAY));
+ auto yearday_schedule_stophour_node
+ = yearday_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_HOUR));
+ auto yearday_schedule_stopminute_node
+ = yearday_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_MINUTE));
+
+ // Compute expected size for set frame
+ const uint8_t expected_frame_size = 15;
+
+ // Creating the frame
+ frame_generator.initialize_frame(SCHEDULE_ENTRY_LOCK_YEAR_DAY_SET,
+ frame,
+ expected_frame_size);
+ frame_generator.add_value(yearday_schedule_set_action_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(user_id_node, DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(yearday_schedule_slot_id_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(yearday_schedule_startyear_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(yearday_schedule_startmonth_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(yearday_schedule_startday_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(yearday_schedule_starthour_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(yearday_schedule_startminute_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(yearday_schedule_stopyear_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(yearday_schedule_stopmonth_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(yearday_schedule_stopday_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(yearday_schedule_stophour_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(yearday_schedule_stopminute_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.validate_frame(frame_length);
+ } catch (const std::exception &e) {
+ sl_log_error(LOG_TAG,
+ "Error while generating schedule_entry_lock Set frame : %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+
+ return SL_STATUS_OK;
+}
+
+static sl_status_t zwave_command_class_schedule_entry_lock_daily_repeating_set(
+ attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
+{
+ try {
+ attribute_store::attribute dailyrepeating_schedule_set_action_node(node);
+ auto user_id_node = dailyrepeating_schedule_set_action_node.first_parent(
+ ATTRIBUTE(USER_IDENTIFIER));
+ auto dailyrepeating_schedule_slot_id_node
+ = dailyrepeating_schedule_set_action_node.parent();
+ auto dailyrepeating_weekday_node
+ = dailyrepeating_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(DAILY_REPEATING_WEEK_DAY));
+ auto dailyrepeating_starthour_node
+ = dailyrepeating_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(DAILY_REPEATING_START_HOUR));
+ auto dailyrepeating_startminute_node
+ = dailyrepeating_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(DAILY_REPEATING_START_MINUTE));
+ auto dailyrepeating_durationhour_node
+ = dailyrepeating_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(DAILY_REPEATING_DURATION_HOUR));
+ auto dailyrepeating_durationminute_node
+ = dailyrepeating_schedule_slot_id_node.child_by_type(
+ ATTRIBUTE(DAILY_REPEATING_DURATION_MINUTE));
+
+ // Compute expected size for set frame
+ const uint8_t expected_frame_size = 10;
+
+ // Creating the frame
+ frame_generator.initialize_frame(SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_SET_V3,
+ frame,
+ expected_frame_size);
+ frame_generator.add_value(dailyrepeating_schedule_set_action_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(user_id_node, DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(dailyrepeating_schedule_slot_id_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(dailyrepeating_weekday_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(dailyrepeating_starthour_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(dailyrepeating_startminute_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(dailyrepeating_durationhour_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.add_value(dailyrepeating_durationminute_node,
+ DESIRED_OR_REPORTED_ATTRIBUTE);
+ frame_generator.validate_frame(frame_length);
+ } catch (const std::exception &e) {
+ sl_log_error(LOG_TAG,
+ "Error while generating schedule_entry_lock Set frame : %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+
+ return SL_STATUS_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Frame parsing functions
+///////////////////////////////////////////////////////////////////////////////
+static sl_status_t
+ zwave_command_class_schedule_entry_lock_type_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));
+ auto current_version = get_current_schedule_entry_lock_version(endpoint_node);
+
+ sl_log_debug(LOG_TAG, "schedule_entry_lock Report frame received");
+
+ // Compute expected size for report frame
+ const uint8_t expected_size = 5;
+
+ // 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 schedule_entry_lock Report frame");
+ return SL_STATUS_FAIL;
+ }
+
+ attribute_store::attribute week_day_node
+ = endpoint_node.child_by_type(ATTRIBUTE(SLOTS_WEEK_DAY));
+ parser.read_byte(week_day_node);
+ attribute_store::attribute year_day_node
+ = endpoint_node.child_by_type(ATTRIBUTE(SLOTS_YEAR_DAY));
+ parser.read_byte(year_day_node);
+
+ if (current_version >= 3) {
+ attribute_store::attribute number_of_slot_daily_repeating_node
+ = endpoint_node.child_by_type(
+ ATTRIBUTE(NUMBER_OF_SLOTS_DAILY_REPEATING));
+ parser.read_byte(number_of_slot_daily_repeating_node);
+ }
+
+ } catch (const std::exception &e) {
+ sl_log_error(LOG_TAG,
+ "Error while parsing schedule_entry_lock Report frame : %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+ return SL_STATUS_OK;
+}
+
+static sl_status_t zwave_command_class_schedule_entry_lock_week_day_report(
+ const zwave_controller_connection_info_t *connection_info,
+ const uint8_t *frame_data,
+ uint16_t frame_length)
+{
+ unid_t unid;
+ dotdot_endpoint_id_t endpoint;
+
+ // Setup
+ attribute_store::attribute endpoint_node(
+ zwave_command_class_get_endpoint_node(connection_info));
+
+ sl_log_debug(LOG_TAG, "schedule_entry_lock Report frame received");
+
+ // Compute expected size for report frame
+ const uint8_t expected_size = 9;
+
+ // 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 schedule_entry_lock Report frame");
+ return SL_STATUS_FAIL;
+ }
+
+ attribute_store::attribute user_id_node
+ = endpoint_node.child_by_type(ATTRIBUTE(USER_IDENTIFIER));
+ parser.read_byte(user_id_node);
+ attribute_store::attribute week_day_slot_id_node
+ = user_id_node.child_by_type(ATTRIBUTE(WEEK_DAY_SCHEDULE_SLOT_ID));
+ parser.read_byte(week_day_slot_id_node);
+ attribute_store::attribute day_of_week_node
+ = week_day_slot_id_node.child_by_type(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_DAY_OF_WEEK));
+ parser.read_byte(day_of_week_node);
+ attribute_store::attribute start_hour_node
+ = week_day_slot_id_node.child_by_type(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_START_HOUR));
+ parser.read_byte(start_hour_node);
+ attribute_store::attribute start_minute_node
+ = week_day_slot_id_node.child_by_type(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_START_MINUTE));
+ parser.read_byte(start_minute_node);
+ attribute_store::attribute stop_hour_node
+ = week_day_slot_id_node.child_by_type(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_STOP_HOUR));
+ parser.read_byte(stop_hour_node);
+ attribute_store::attribute stop_minute_node
+ = week_day_slot_id_node.child_by_type(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_STOP_MINUTE));
+ parser.read_byte(stop_minute_node);
+ attribute_store_network_helper_get_unid_from_node(endpoint_node, unid);
+ endpoint = endpoint_node.reported();
+ zwave_command_class_publish_generated_week_day_report_command(
+ unid,
+ endpoint,
+ endpoint_node);
+
+ } catch (const std::exception &e) {
+ sl_log_error(LOG_TAG,
+ "Error while parsing schedule_entry_lock Report frame : %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+ return SL_STATUS_OK;
+}
+
+static sl_status_t zwave_command_class_schedule_entry_lock_year_day_report(
+ const zwave_controller_connection_info_t *connection_info,
+ const uint8_t *frame_data,
+ uint16_t frame_length)
+{
+ unid_t unid;
+ dotdot_endpoint_id_t endpoint;
+
+ // Setup
+ attribute_store::attribute endpoint_node(
+ zwave_command_class_get_endpoint_node(connection_info));
+
+ sl_log_debug(LOG_TAG, "schedule_entry_lock Report frame received");
+
+ // Compute expected size for report frame
+ const uint8_t expected_size = 14;
+
+ // 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 schedule_entry_lock Report frame");
+ return SL_STATUS_FAIL;
+ }
+
+ attribute_store::attribute user_id_node
+ = endpoint_node.child_by_type(ATTRIBUTE(USER_IDENTIFIER));
+ parser.read_byte(user_id_node);
+ attribute_store::attribute year_day_slot_id_node
+ = user_id_node.child_by_type(ATTRIBUTE(YEAR_DAY_SCHEDULE_SLOT_ID));
+ parser.read_byte(year_day_slot_id_node);
+ attribute_store::attribute start_year_node
+ = year_day_slot_id_node.child_by_type(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_YEAR));
+ parser.read_byte(start_year_node);
+ attribute_store::attribute start_month_node
+ = year_day_slot_id_node.child_by_type(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_MONTH));
+ parser.read_byte(start_month_node);
+ attribute_store::attribute start_day_node
+ = year_day_slot_id_node.child_by_type(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_DAY));
+ parser.read_byte(start_day_node);
+ attribute_store::attribute start_hour_node
+ = year_day_slot_id_node.child_by_type(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_HOUR));
+ parser.read_byte(start_hour_node);
+ attribute_store::attribute start_minute_node
+ = year_day_slot_id_node.child_by_type(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_MINUTE));
+ parser.read_byte(start_minute_node);
+ attribute_store::attribute stop_year_node
+ = year_day_slot_id_node.child_by_type(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_YEAR));
+ parser.read_byte(stop_year_node);
+ attribute_store::attribute stop_month_node
+ = year_day_slot_id_node.child_by_type(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_MONTH));
+ parser.read_byte(stop_month_node);
+ attribute_store::attribute stop_day_node
+ = year_day_slot_id_node.child_by_type(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_DAY));
+ parser.read_byte(stop_day_node);
+ attribute_store::attribute stop_hour_node
+ = year_day_slot_id_node.child_by_type(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_HOUR));
+ parser.read_byte(stop_hour_node);
+ attribute_store::attribute stop_minute_node
+ = year_day_slot_id_node.child_by_type(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_MINUTE));
+ parser.read_byte(stop_minute_node);
+ attribute_store_network_helper_get_unid_from_node(endpoint_node, unid);
+ endpoint = endpoint_node.reported();
+ zwave_command_class_publish_generated_year_day_report_command(
+ unid,
+ endpoint,
+ endpoint_node);
+
+ } catch (const std::exception &e) {
+ sl_log_error(LOG_TAG,
+ "Error while parsing schedule_entry_lock Report frame : %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+ return SL_STATUS_OK;
+}
+
+static sl_status_t zwave_command_class_schedule_entry_lock_time_offset_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, "schedule_entry_lock Report frame received");
+
+ // Compute expected size for report frame
+ const uint8_t expected_size = 5;
+
+ // 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 schedule_entry_lock Report frame");
+ return SL_STATUS_FAIL;
+ }
+
+ attribute_store::attribute sign_tzo_node
+ = endpoint_node.child_by_type(ATTRIBUTE(SIGN_TZO));
+ attribute_store::attribute hour_tzo_node
+ = endpoint_node.child_by_type(ATTRIBUTE(HOUR_TZO));
+ std::vector data_first_byte = {
+ {.bitmask = SCHEDULE_ENTRY_LOCK_TIME_OFFSET_REPORT_LEVEL_SIGN_TZO_BIT_MASK_V2, .destination_node = sign_tzo_node},
+ {.bitmask = SCHEDULE_ENTRY_LOCK_TIME_OFFSET_REPORT_LEVEL_HOUR_TZO_MASK_V2, .destination_node = hour_tzo_node}
+ };
+ parser.read_byte_with_bitmask(data_first_byte);
+ attribute_store::attribute minute_tzo_node
+ = endpoint_node.child_by_type(ATTRIBUTE(MINUTE_TZO));
+ parser.read_byte(minute_tzo_node);
+ attribute_store::attribute dst_offset_sign_node
+ = endpoint_node.child_by_type(ATTRIBUTE(DST_OFFSET_SIGN));
+ attribute_store::attribute dst_offset_minute_node
+ = endpoint_node.child_by_type(ATTRIBUTE(DST_OFFSET_MINUTE));
+ std::vector data_third_byte = {
+ {.bitmask = SCHEDULE_ENTRY_LOCK_TIME_OFFSET_REPORT_LEVEL2_SIGN_OFFSET_DST_BIT_MASK_V2, .destination_node = dst_offset_sign_node},
+ {.bitmask = SCHEDULE_ENTRY_LOCK_TIME_OFFSET_REPORT_LEVEL2_MINUTE_OFFSET_DST_MASK_V2, .destination_node = dst_offset_minute_node}
+ };
+ parser.read_byte_with_bitmask(data_third_byte);
+
+ } catch (const std::exception &e) {
+ sl_log_error(LOG_TAG,
+ "Error while parsing schedule_entry_lock Report frame : %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+ return SL_STATUS_OK;
+}
+
+static sl_status_t
+ zwave_command_class_schedule_entry_lock_daily_repeating_report(
+ const zwave_controller_connection_info_t *connection_info,
+ const uint8_t *frame_data,
+ uint16_t frame_length)
+{
+ unid_t unid;
+ dotdot_endpoint_id_t endpoint;
+
+ // Setup
+ attribute_store::attribute endpoint_node(
+ zwave_command_class_get_endpoint_node(connection_info));
+
+ sl_log_debug(LOG_TAG, "schedule_entry_lock Report frame received");
+
+ // Compute expected size for report frame
+ const uint8_t expected_size = 9;
+
+ // 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 schedule_entry_lock Report frame");
+ return SL_STATUS_FAIL;
+ }
+
+ attribute_store::attribute user_id_node
+ = endpoint_node.child_by_type(ATTRIBUTE(USER_IDENTIFIER));
+ parser.read_byte(user_id_node);
+ attribute_store::attribute daily_repeating_slot_id_node
+ = user_id_node.child_by_type(ATTRIBUTE(DAILY_REPEATING_SCHEDULE_SLOT_ID));
+ parser.read_byte(daily_repeating_slot_id_node);
+ attribute_store::attribute week_day_node
+ = daily_repeating_slot_id_node.child_by_type(
+ ATTRIBUTE(DAILY_REPEATING_WEEK_DAY));
+ parser.read_byte(week_day_node);
+ attribute_store::attribute start_hour_node
+ = daily_repeating_slot_id_node.child_by_type(
+ ATTRIBUTE(DAILY_REPEATING_START_HOUR));
+ parser.read_byte(start_hour_node);
+ attribute_store::attribute start_minute_node
+ = daily_repeating_slot_id_node.child_by_type(
+ ATTRIBUTE(DAILY_REPEATING_START_MINUTE));
+ parser.read_byte(start_minute_node);
+ attribute_store::attribute duration_hour_node
+ = daily_repeating_slot_id_node.child_by_type(
+ ATTRIBUTE(DAILY_REPEATING_DURATION_HOUR));
+ parser.read_byte(duration_hour_node);
+ attribute_store::attribute duration_minute_node
+ = daily_repeating_slot_id_node.child_by_type(
+ ATTRIBUTE(DAILY_REPEATING_DURATION_MINUTE));
+ parser.read_byte(duration_minute_node);
+ attribute_store_network_helper_get_unid_from_node(endpoint_node, unid);
+ endpoint = endpoint_node.reported();
+ zwave_command_class_publish_generated_daily_repeating_report_command(
+ unid,
+ endpoint,
+ endpoint_node);
+
+ } catch (const std::exception &e) {
+ sl_log_error(LOG_TAG,
+ "Error while parsing schedule_entry_lock Report frame : %s",
+ e.what());
+ return SL_STATUS_FAIL;
+ }
+ return SL_STATUS_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Incoming commands handler
+///////////////////////////////////////////////////////////////////////////////
+sl_status_t zwave_command_class_schedule_entry_lock_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 SCHEDULE_ENTRY_TYPE_SUPPORTED_REPORT:
+ return zwave_command_class_schedule_entry_lock_type_supported_report(
+ connection_info,
+ frame_data,
+ frame_length);
+ case SCHEDULE_ENTRY_LOCK_WEEK_DAY_REPORT:
+ return zwave_command_class_schedule_entry_lock_week_day_report(
+ connection_info,
+ frame_data,
+ frame_length);
+ case SCHEDULE_ENTRY_LOCK_YEAR_DAY_REPORT:
+ return zwave_command_class_schedule_entry_lock_year_day_report(
+ connection_info,
+ frame_data,
+ frame_length);
+ case SCHEDULE_ENTRY_LOCK_TIME_OFFSET_REPORT_V2:
+ return zwave_command_class_schedule_entry_lock_time_offset_report(
+ connection_info,
+ frame_data,
+ frame_length);
+ case SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_REPORT_V3:
+ return zwave_command_class_schedule_entry_lock_daily_repeating_report(
+ connection_info,
+ frame_data,
+ frame_length);
+ default:
+ return SL_STATUS_NOT_SUPPORTED;
+ }
+}
+///////////////////////////////////////////////////////////////////////////////
+// Attribute Store callback functions
+///////////////////////////////////////////////////////////////////////////////
+static void zwave_command_class_schedule_entry_lock_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;
+ }
+ supporting_node_version = version_node.reported();
+
+ // Now we know we have a schedule_entry_lock supporting endpoint.
+ attribute_store::attribute endpoint_node
+ = version_node.first_parent(ATTRIBUTE_ENDPOINT_ID);
+
+ // Create the schedule_entry_lock attributes
+ attribute_store::attribute user_id_node
+ = endpoint_node.emplace_node(ATTRIBUTE(USER_IDENTIFIER));
+
+ user_id_node.emplace_node(ATTRIBUTE(ENABLED));
+
+ endpoint_node.emplace_node(ATTRIBUTE(ENABLE_ALL));
+
+ endpoint_node.emplace_node(ATTRIBUTE(SLOTS_WEEK_DAY));
+
+ if (supporting_node_version >= 2) {
+ endpoint_node.emplace_node(ATTRIBUTE(HOUR_TZO));
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Public interface functions
+///////////////////////////////////////////////////////////////////////////////
+sl_status_t zwave_command_class_schedule_entry_lock_init()
+{
+ // Attribute store callbacks
+ attribute_store_register_callback_by_type(
+ zwave_command_class_schedule_entry_lock_on_version_attribute_update,
+ ATTRIBUTE(VERSION));
+
+ // Attribute resolver rules
+ attribute_resolver_register_rule(
+ ATTRIBUTE(SLOTS_WEEK_DAY),
+ NULL,
+ &zwave_command_class_schedule_entry_lock_get);
+ attribute_resolver_register_rule(
+ ATTRIBUTE(HOUR_TZO),
+ &zwave_command_class_schedule_entry_lock_time_offset_set,
+ &zwave_command_class_schedule_entry_lock_time_offset_get);
+ attribute_resolver_register_rule(
+ ATTRIBUTE(ENABLED),
+ &zwave_command_class_schedule_entry_lock_enable_set,
+ NULL);
+ attribute_resolver_register_rule(
+ ATTRIBUTE(ENABLE_ALL),
+ &zwave_command_class_schedule_entry_lock_enable_all_set,
+ NULL);
+ attribute_resolver_register_rule(
+ ATTRIBUTE(WEEK_DAY_SCHEDULE_SET_ACTION),
+ &zwave_command_class_schedule_entry_lock_week_day_set,
+ &zwave_command_class_schedule_entry_lock_week_day_get);
+ attribute_resolver_register_rule(
+ ATTRIBUTE(YEAR_DAY_SCHEDULE_SET_ACTION),
+ &zwave_command_class_schedule_entry_lock_year_day_set,
+ &zwave_command_class_schedule_entry_lock_year_day_get);
+ attribute_resolver_register_rule(
+ ATTRIBUTE(DAILY_REPEATING_SET_ACTION),
+ &zwave_command_class_schedule_entry_lock_daily_repeating_set,
+ &zwave_command_class_schedule_entry_lock_daily_repeating_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_schedule_entry_lock_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_SCHEDULE_ENTRY_LOCK;
+ handler.version = SCHEDULE_ENTRY_LOCK_VERSION_V3;
+ handler.command_class_name = "schedule_entry_lock";
+ handler.comments = "";
+
+ zwave_command_handler_register_handler(handler);
+
+ return SL_STATUS_OK;
+}
diff --git a/applications/zpc/components/zwave_command_classes/src/zwave_command_class_schedule_entry_lock.h b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_schedule_entry_lock.h
new file mode 100644
index 000000000..0fcc09428
--- /dev/null
+++ b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_schedule_entry_lock.h
@@ -0,0 +1,44 @@
+/******************************************************************************
+ * # 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 zwave_command_class_schedule_entry_lock
+ * @brief TODO: Write brief for zwave_command_class_schedule_entry_lock
+ *
+ * TODO: Write component description for zwave_command_class_schedule_entry_lock
+ *
+ * @{
+ */
+
+#ifndef ZWAVE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_H
+#define ZWAVE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_H
+
+#include "sl_status.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief This function initialize the schedule Entry Lock Command Class handler
+ *
+ * @return SL_STATUS_OK on success, any other error code for an error.
+ */
+sl_status_t zwave_command_class_schedule_entry_lock_init();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //ZWAVE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_H
+/** @} end zwave_command_class_schedule_entry_lock */
diff --git a/applications/zpc/components/zwave_command_classes/src/zwave_command_classes_fixt.c b/applications/zpc/components/zwave_command_classes/src/zwave_command_classes_fixt.c
index a20c668f3..ec3db086d 100644
--- a/applications/zpc/components/zwave_command_classes/src/zwave_command_classes_fixt.c
+++ b/applications/zpc/components/zwave_command_classes/src/zwave_command_classes_fixt.c
@@ -59,6 +59,7 @@
#include "zwave_command_class_indicator_control.h"
#include "zwave_command_class_manufacturer_specific_control.h"
#include "zwave_command_class_humidity_control_mode.h"
+#include "zwave_command_class_schedule_entry_lock.h"
#include "zwave_command_class_protocol.h"
// Generic includes
@@ -114,6 +115,7 @@ sl_status_t zwave_command_classes_init()
status |= zwave_command_class_scene_controller_configuration_control_init();
status |= zwave_command_class_security_0_init();
status |= zwave_command_class_security_2_init();
+ status |= zwave_command_class_schedule_entry_lock_init();
status |= zwave_command_class_sound_switch_init();
status |= zwave_command_class_supervision_init();
status |= zwave_command_class_switch_color_init();
diff --git a/applications/zpc/components/zwave_command_classes/test/zwave_command_class_schedule_entry_lock_test.cpp b/applications/zpc/components/zwave_command_classes/test/zwave_command_class_schedule_entry_lock_test.cpp
new file mode 100644
index 000000000..ff2c2a233
--- /dev/null
+++ b/applications/zpc/components/zwave_command_classes/test/zwave_command_class_schedule_entry_lock_test.cpp
@@ -0,0 +1,662 @@
+/******************************************************************************
+ * # 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_schedule_entry_lock.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"
+
+// ZPC includes
+#include "attribute_store_defined_attribute_types.h"
+#include "zpc_attribute_store_type_registration.h"
+#include "sl_log.h"
+
+// Test helpers
+#include "zwave_command_class_test_helper.hpp"
+
+constexpr uint8_t SCHEDULE_ENTRY_LOCK_ENABLE = 0x01;
+constexpr uint8_t SCHEDULE_ENTRY_LOCK_DISABLE = 0x00;
+constexpr uint8_t SCHEDULE_ENTRY_LOCK_ERASE_SLOT = 0;
+constexpr uint8_t SCHEDULE_ENTRY_LOCK_MODIFY_SLOT = 1;
+
+// Attribute macro, shortening those long defines for attribute types:
+#define ATTRIBUTE(type) ATTRIBUTE_COMMAND_CLASS_SCHEDULE_ENTRY_LOCK_##type
+
+using namespace zwave_command_class_test_helper;
+
+extern "C" {
+
+// Mock helper
+#include "dotdot_mqtt_mock.h"
+#include "dotdot_mqtt_generated_commands_mock.h"
+#include "zpc_attribute_store_network_helper_mock.h"
+
+/// 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_SCHEDULE_ENTRY_LOCK,
+ .supported_version = SCHEDULE_ENTRY_LOCK_VERSION_V3};
+// Get Set function map
+const resolver_function_map attribute_bindings
+ = {{ATTRIBUTE(SLOTS_WEEK_DAY), {SCHEDULE_ENTRY_TYPE_SUPPORTED_GET, 0}},
+ {ATTRIBUTE(HOUR_TZO),
+ {SCHEDULE_ENTRY_LOCK_TIME_OFFSET_GET_V2,
+ SCHEDULE_ENTRY_LOCK_TIME_OFFSET_SET_V2}},
+ {ATTRIBUTE(ENABLED), {0, SCHEDULE_ENTRY_LOCK_ENABLE_SET}},
+ {ATTRIBUTE(ENABLE_ALL), {0, SCHEDULE_ENTRY_LOCK_ENABLE_ALL_SET}},
+ {ATTRIBUTE(WEEK_DAY_SCHEDULE_SET_ACTION),
+ {SCHEDULE_ENTRY_LOCK_WEEK_DAY_GET, SCHEDULE_ENTRY_LOCK_WEEK_DAY_SET}},
+ {ATTRIBUTE(YEAR_DAY_SCHEDULE_SET_ACTION),
+ {SCHEDULE_ENTRY_LOCK_YEAR_DAY_GET, SCHEDULE_ENTRY_LOCK_YEAR_DAY_SET}},
+ {ATTRIBUTE(DAILY_REPEATING_SET_ACTION),
+ {SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_GET_V3,
+ SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_SET_V3}}};
+
+/// Called before each and every test
+void setUp()
+{
+ zwave_setUp(command_class_handler,
+ &zwave_command_class_schedule_entry_lock_init,
+ attribute_bindings);
+}
+
+void test_switch_all_interview_happy_case()
+{
+ helper_set_version(SCHEDULE_ENTRY_LOCK_VERSION_V3);
+
+ // Verify that we have the correct node(s)
+ auto user_id_node = helper_test_and_get_node(ATTRIBUTE(USER_IDENTIFIER));
+ helper_test_node_exists(ATTRIBUTE(SLOTS_WEEK_DAY));
+ helper_test_node_exists(ATTRIBUTE(HOUR_TZO));
+ helper_test_node_exists(ATTRIBUTE(ENABLED), user_id_node);
+ helper_test_node_exists(ATTRIBUTE(ENABLE_ALL));
+}
+
+void test_schedule_entry_lock_get_happy_case()
+{
+ helper_set_version(SCHEDULE_ENTRY_LOCK_VERSION_V3);
+
+ auto slot_week_day_node = helper_test_and_get_node(ATTRIBUTE(SLOTS_WEEK_DAY));
+
+ helper_test_get_set_frame_happy_case(SCHEDULE_ENTRY_TYPE_SUPPORTED_GET,
+ slot_week_day_node);
+}
+
+void test_schedule_entry_lock_time_offset_get_happy_case()
+{
+ helper_set_version(SCHEDULE_ENTRY_LOCK_VERSION_V3);
+
+ auto hour_tzo_node = helper_test_and_get_node(ATTRIBUTE(HOUR_TZO));
+
+ helper_test_get_set_frame_happy_case(SCHEDULE_ENTRY_LOCK_TIME_OFFSET_GET_V2,
+ hour_tzo_node);
+}
+
+void test_schedule_entry_lock_week_day_get_happy_case()
+{
+ helper_set_version(SCHEDULE_ENTRY_LOCK_VERSION_V3);
+
+ auto user_id_node = helper_test_and_get_node(ATTRIBUTE(USER_IDENTIFIER));
+ auto slot_id_node
+ = user_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_SLOT_ID));
+ auto set_action_node
+ = slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_SET_ACTION));
+
+ uint8_t user_id = 0x01;
+ uint8_t slot_id = 0x02;
+
+ zwave_frame week_day_get;
+ week_day_get.add(user_id);
+ week_day_get.add(slot_id);
+
+ user_id_node.set_reported(user_id);
+ slot_id_node.set_reported(slot_id);
+
+ helper_test_get_set_frame_happy_case(SCHEDULE_ENTRY_LOCK_WEEK_DAY_GET,
+ set_action_node,
+ week_day_get);
+}
+
+void test_schedule_entry_lock_year_day_get_happy_case()
+{
+ helper_set_version(SCHEDULE_ENTRY_LOCK_VERSION_V3);
+
+ auto user_id_node = helper_test_and_get_node(ATTRIBUTE(USER_IDENTIFIER));
+ auto slot_id_node
+ = user_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_SLOT_ID));
+ auto set_action_node
+ = slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_SET_ACTION));
+
+ uint8_t user_id = 0x01;
+ uint8_t slot_id = 0x02;
+
+ zwave_frame year_day_get;
+ year_day_get.add(user_id);
+ year_day_get.add(slot_id);
+
+ user_id_node.set_reported(user_id);
+ slot_id_node.set_reported(slot_id);
+
+ helper_test_get_set_frame_happy_case(SCHEDULE_ENTRY_LOCK_YEAR_DAY_GET,
+ set_action_node,
+ year_day_get);
+}
+
+void test_schedule_entry_lock_daily_repeating_get_happy_case()
+{
+ helper_set_version(SCHEDULE_ENTRY_LOCK_VERSION_V3);
+
+ auto user_id_node = helper_test_and_get_node(ATTRIBUTE(USER_IDENTIFIER));
+ auto slot_id_node
+ = user_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_SCHEDULE_SLOT_ID));
+ auto set_action_node
+ = slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_SET_ACTION));
+
+ uint8_t user_id = 0x01;
+ uint8_t slot_id = 0x02;
+
+ zwave_frame daily_repeating_get;
+ daily_repeating_get.add(user_id);
+ daily_repeating_get.add(slot_id);
+
+ user_id_node.set_reported(user_id);
+ slot_id_node.set_reported(slot_id);
+
+ helper_test_get_set_frame_happy_case(
+ SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_GET_V3,
+ set_action_node,
+ daily_repeating_get);
+}
+
+void test_schedule_entry_lock_enable_set_happy_case()
+{
+ helper_set_version(SCHEDULE_ENTRY_LOCK_VERSION_V3);
+
+ auto user_id_node = helper_test_and_get_node(ATTRIBUTE(USER_IDENTIFIER));
+ auto enable_node = user_id_node.emplace_node(ATTRIBUTE(ENABLED));
+ uint8_t enable = 0x01;
+
+ zwave_frame enable_set;
+ enable_set.add(enable);
+ enable_set.add(SCHEDULE_ENTRY_LOCK_ENABLE);
+
+ // Test with desired value
+ user_id_node.set_reported(enable);
+ enable_node.set_desired(SCHEDULE_ENTRY_LOCK_ENABLE);
+
+ helper_test_get_set_frame_happy_case(SCHEDULE_ENTRY_LOCK_ENABLE_SET,
+ enable_node,
+ enable_set);
+}
+
+void test_schedule_entry_lock_enable_all_set_happy_case()
+{
+ helper_set_version(SCHEDULE_ENTRY_LOCK_VERSION_V3);
+
+ auto enable_all_node = helper_test_and_get_node(ATTRIBUTE(ENABLE_ALL));
+
+ // Test with desired value
+ enable_all_node.set_desired(SCHEDULE_ENTRY_LOCK_ENABLE);
+ helper_test_get_set_frame_happy_case(SCHEDULE_ENTRY_LOCK_ENABLE_ALL_SET,
+ enable_all_node,
+ {SCHEDULE_ENTRY_LOCK_ENABLE});
+}
+
+void test_schedule_entry_lock_week_day_set_happy_case()
+{
+ helper_set_version(SCHEDULE_ENTRY_LOCK_VERSION_V3);
+
+ auto user_id_node = helper_test_and_get_node(ATTRIBUTE(USER_IDENTIFIER));
+ auto slot_id_node
+ = user_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_SLOT_ID));
+ auto set_action_node
+ = slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_SET_ACTION));
+
+ uint8_t set_action = 0x01;
+ uint8_t user_id = 0x02;
+ uint8_t slot_id = 0x03;
+ uint8_t day_of_week = 0x04;
+ uint8_t start_hour = 0x05;
+ uint8_t start_minute = 0x06;
+ uint8_t stop_hour = 0x07;
+ uint8_t stop_minute = 0x08;
+
+ zwave_frame week_day_set;
+ week_day_set.add(set_action);
+ week_day_set.add(user_id);
+ week_day_set.add(slot_id);
+ week_day_set.add(day_of_week);
+ week_day_set.add(start_hour);
+ week_day_set.add(start_minute);
+ week_day_set.add(stop_hour);
+ week_day_set.add(stop_minute);
+
+ set_action_node.set_reported(set_action);
+ user_id_node.set_reported(user_id);
+ slot_id_node.set_reported(slot_id);
+ slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_DAY_OF_WEEK))
+ .set_reported(day_of_week);
+ slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_START_HOUR))
+ .set_reported(start_hour);
+ slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_START_MINUTE))
+ .set_reported(start_minute);
+ slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_STOP_HOUR))
+ .set_reported(stop_hour);
+ slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_STOP_MINUTE))
+ .set_reported(stop_minute);
+
+ helper_test_get_set_frame_happy_case(SCHEDULE_ENTRY_LOCK_WEEK_DAY_SET,
+ set_action_node,
+ week_day_set);
+}
+
+void test_schedule_entry_lock_year_day_set_happy_case()
+{
+ helper_set_version(SCHEDULE_ENTRY_LOCK_VERSION_V3);
+
+ auto user_id_node = helper_test_and_get_node(ATTRIBUTE(USER_IDENTIFIER));
+ auto slot_id_node
+ = user_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_SLOT_ID));
+ auto set_action_node
+ = slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_SET_ACTION));
+
+ uint8_t set_action = 0x01;
+ uint8_t user_id = 0x02;
+ uint8_t slot_id = 0x03;
+ uint8_t start_year = 0x04;
+ uint8_t start_month = 0x05;
+ uint8_t start_day = 0x06;
+ uint8_t start_hour = 0x07;
+ uint8_t start_minute = 0x08;
+ uint8_t stop_year = 0x09;
+ uint8_t stop_month = 0x0a;
+ uint8_t stop_day = 0x0b;
+ uint8_t stop_hour = 0x0c;
+ uint8_t stop_minute = 0x0d;
+
+ zwave_frame year_day_set;
+ year_day_set.add(set_action);
+ year_day_set.add(user_id);
+ year_day_set.add(slot_id);
+ year_day_set.add(start_year);
+ year_day_set.add(start_month);
+ year_day_set.add(start_day);
+ year_day_set.add(start_hour);
+ year_day_set.add(start_minute);
+ year_day_set.add(stop_year);
+ year_day_set.add(stop_month);
+ year_day_set.add(stop_day);
+ year_day_set.add(stop_hour);
+ year_day_set.add(stop_minute);
+
+ set_action_node.set_reported(set_action);
+ user_id_node.set_reported(user_id);
+ slot_id_node.set_reported(slot_id);
+
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_YEAR))
+ .set_reported(start_year);
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_MONTH))
+ .set_reported(start_month);
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_DAY))
+ .set_reported(start_day);
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_HOUR))
+ .set_reported(start_hour);
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_MINUTE))
+ .set_reported(start_minute);
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_YEAR))
+ .set_reported(stop_year);
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_MONTH))
+ .set_reported(stop_month);
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_DAY))
+ .set_reported(stop_day);
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_HOUR))
+ .set_reported(stop_hour);
+ slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_MINUTE))
+ .set_reported(stop_minute);
+
+ helper_test_get_set_frame_happy_case(SCHEDULE_ENTRY_LOCK_YEAR_DAY_SET,
+ set_action_node,
+ year_day_set);
+}
+
+void test_schedule_entry_lock_daily_repeating_set_happy_case()
+{
+ helper_set_version(SCHEDULE_ENTRY_LOCK_VERSION_V3);
+
+ auto user_id_node = helper_test_and_get_node(ATTRIBUTE(USER_IDENTIFIER));
+ auto slot_id_node
+ = user_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_SCHEDULE_SLOT_ID));
+ auto set_action_node
+ = slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_SET_ACTION));
+
+ uint8_t set_action = 0x01;
+ uint8_t user_id = 0x02;
+ uint8_t slot_id = 0x03;
+ uint8_t week_day = 0x04;
+ uint8_t start_hour = 0x05;
+ uint8_t start_minute = 0x06;
+ uint8_t duration_hour = 0x07;
+ uint8_t duration_minute = 0x08;
+
+ zwave_frame daily_repeating_set;
+ daily_repeating_set.add(set_action);
+ daily_repeating_set.add(user_id);
+ daily_repeating_set.add(slot_id);
+ daily_repeating_set.add(week_day);
+ daily_repeating_set.add(start_hour);
+ daily_repeating_set.add(start_minute);
+ daily_repeating_set.add(duration_hour);
+ daily_repeating_set.add(duration_minute);
+
+ set_action_node.set_reported(set_action);
+ user_id_node.set_reported(user_id);
+ slot_id_node.set_reported(slot_id);
+
+ slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_WEEK_DAY))
+ .set_reported(week_day);
+ slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_START_HOUR))
+ .set_reported(start_hour);
+ slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_START_MINUTE))
+ .set_reported(start_minute);
+ slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_DURATION_HOUR))
+ .set_reported(duration_hour);
+ slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_DURATION_MINUTE))
+ .set_reported(duration_minute);
+
+ helper_test_get_set_frame_happy_case(
+ SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_SET_V3,
+ set_action_node,
+ daily_repeating_set);
+}
+
+void test_schedule_entry_lock_time_offset_set_happy_case()
+{
+ helper_set_version(SCHEDULE_ENTRY_LOCK_VERSION_V3);
+
+ auto hour_tzo_node = helper_test_and_get_node(ATTRIBUTE(HOUR_TZO));
+ auto endpoint_node = hour_tzo_node.parent();
+
+ // Set reported values for TZO and DST fields as per Z-Wave specs
+ hour_tzo_node.set_reported(15); // Hour TZO (7 bits)
+
+ endpoint_node.emplace_node(ATTRIBUTE(SIGN_TZO))
+ .set_reported(1); // Sign TZO (1 bit, 0 for positive)
+ endpoint_node.emplace_node(ATTRIBUTE(MINUTE_TZO))
+ .set_reported(0x00); // Minute TZO (7 bits)
+
+ endpoint_node.emplace_node(ATTRIBUTE(DST_OFFSET_SIGN))
+ .set_reported(1); // DST Offset Sign (1 bit, 0 for positive)
+ endpoint_node.emplace_node(ATTRIBUTE(DST_OFFSET_MINUTE))
+ .set_reported(15); // DST Offset Minute (7 bits)
+
+ // Byte 1: Sign TZO (1 bit) + Hour TZO (7 bits)
+ // Byte 2: Minute TZO (7 bits)
+ // Byte 3: Sign Offset DST (1 bit) + Minute Offset DST (7 bits)
+ helper_test_get_set_frame_happy_case(SCHEDULE_ENTRY_LOCK_TIME_OFFSET_SET_V2,
+ hour_tzo_node,
+ {0b10001111, 0x00, 0b10001111});
+}
+
+void test_schedule_entry_lock_type_supported_report_happy_case()
+{
+ helper_set_version(SCHEDULE_ENTRY_LOCK_VERSION_V3);
+ auto slot_week_day_node = helper_test_and_get_node(ATTRIBUTE(SLOTS_WEEK_DAY));
+ auto endpoint_node = slot_week_day_node.parent();
+ auto slot_year_day_node
+ = endpoint_node.emplace_node(ATTRIBUTE(SLOTS_YEAR_DAY));
+ auto slot_daily_repeating_node
+ = endpoint_node.emplace_node(ATTRIBUTE(NUMBER_OF_SLOTS_DAILY_REPEATING));
+ uint8_t slot_week_day = 0x01;
+ uint8_t slot_year_day = 0x02;
+ uint8_t slot_daily_repeating = 0x03;
+
+ zwave_frame type_supported_report;
+ type_supported_report.add(slot_week_day);
+ type_supported_report.add(slot_year_day);
+ type_supported_report.add(slot_daily_repeating);
+
+ attribute_store_network_helper_get_endpoint_node_IgnoreAndReturn(
+ cpp_endpoint_id_node);
+ helper_test_report_frame(SCHEDULE_ENTRY_TYPE_SUPPORTED_REPORT,
+ type_supported_report);
+ TEST_ASSERT_EQUAL(slot_week_day, slot_week_day_node.reported());
+ TEST_ASSERT_EQUAL(slot_year_day, slot_year_day_node.reported());
+ TEST_ASSERT_EQUAL(slot_daily_repeating,
+ slot_daily_repeating_node.reported());
+}
+
+void test_schedule_entry_lock_time_offset_report_report_happy_case()
+{
+ helper_set_version(SCHEDULE_ENTRY_LOCK_VERSION_V3);
+
+ auto hour_tzo_node = helper_test_and_get_node(ATTRIBUTE(HOUR_TZO));
+ auto endpoint_node = hour_tzo_node.parent();
+ auto sign_tzo_node = endpoint_node.emplace_node(ATTRIBUTE(SIGN_TZO));
+ auto minute_tzo_node = endpoint_node.emplace_node(ATTRIBUTE(MINUTE_TZO));
+ auto dst_offset_sign_node
+ = endpoint_node.emplace_node(ATTRIBUTE(DST_OFFSET_SIGN));
+ auto dst_offset_minute_node
+ = endpoint_node.emplace_node(ATTRIBUTE(DST_OFFSET_MINUTE));
+
+ attribute_store_network_helper_get_endpoint_node_IgnoreAndReturn(
+ cpp_endpoint_id_node);
+
+ helper_test_report_frame(SCHEDULE_ENTRY_LOCK_TIME_OFFSET_REPORT_V2,
+ {0b10001111, 0x00, 0b10001111});
+ TEST_ASSERT_EQUAL(1, sign_tzo_node.reported());
+ TEST_ASSERT_EQUAL(15, hour_tzo_node.reported());
+ TEST_ASSERT_EQUAL(0x00, minute_tzo_node.reported());
+ TEST_ASSERT_EQUAL(1, dst_offset_sign_node.reported());
+ TEST_ASSERT_EQUAL(15, dst_offset_minute_node.reported());
+}
+
+void test_schedule_entry_lock_week_day_report_happy_case()
+{
+ helper_set_version(SCHEDULE_ENTRY_LOCK_VERSION_V3);
+ auto user_id_node = helper_test_and_get_node(ATTRIBUTE(USER_IDENTIFIER));
+ auto slot_id_node
+ = user_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_SLOT_ID));
+ auto day_of_week_node
+ = slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_DAY_OF_WEEK));
+ auto start_hour_node
+ = slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_START_HOUR));
+ auto start_minute_node
+ = slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_START_MINUTE));
+ auto stop_hour_node
+ = slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_STOP_HOUR));
+ auto stop_minute_node
+ = slot_id_node.emplace_node(ATTRIBUTE(WEEK_DAY_SCHEDULE_STOP_MINUTE));
+
+ uint8_t user_id = 0x01;
+ uint8_t slot_id = 0x02;
+ uint8_t day_of_week = 0x03;
+ uint8_t start_hour = 0x04;
+ uint8_t start_minute = 0x05;
+ uint8_t stop_hour = 0x06;
+ uint8_t stop_minute = 0x07;
+
+ zwave_frame week_day_set;
+ week_day_set.add(user_id);
+ week_day_set.add(slot_id);
+ week_day_set.add(day_of_week);
+ week_day_set.add(start_hour);
+ week_day_set.add(start_minute);
+ week_day_set.add(stop_hour);
+ week_day_set.add(stop_minute);
+
+ attribute_store_network_helper_get_endpoint_node_IgnoreAndReturn(
+ cpp_endpoint_id_node);
+ attribute_store_network_helper_get_unid_from_node_IgnoreAndReturn(
+ cpp_endpoint_id_node);
+ uic_mqtt_dotdot_unify_schedule_entry_lock_publish_generated_week_day_report_command_Ignore();
+
+ helper_test_report_frame(SCHEDULE_ENTRY_LOCK_WEEK_DAY_REPORT, week_day_set);
+ TEST_ASSERT_EQUAL(user_id, user_id_node.reported());
+ TEST_ASSERT_EQUAL(slot_id, slot_id_node.reported());
+ TEST_ASSERT_EQUAL(day_of_week, day_of_week_node.reported());
+ TEST_ASSERT_EQUAL(start_hour, start_hour_node.reported());
+ TEST_ASSERT_EQUAL(start_minute, start_minute_node.reported());
+ TEST_ASSERT_EQUAL(stop_hour, stop_hour_node.reported());
+ TEST_ASSERT_EQUAL(stop_minute, stop_minute_node.reported());
+}
+
+void test_schedule_entry_lock_year_day_report_happy_case()
+{
+ helper_set_version(SCHEDULE_ENTRY_LOCK_VERSION_V3);
+ auto user_id_node = helper_test_and_get_node(ATTRIBUTE(USER_IDENTIFIER));
+ auto slot_id_node
+ = user_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_SLOT_ID));
+ auto start_year_node
+ = slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_YEAR));
+ auto start_month_node
+ = slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_MONTH));
+ auto start_day_node
+ = slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_DAY));
+ auto start_hour_node
+ = slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_HOUR));
+ auto start_minute_node
+ = slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_START_MINUTE));
+ auto stop_year_node
+ = slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_YEAR));
+ auto stop_month_node
+ = slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_MONTH));
+ auto stop_day_node
+ = slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_DAY));
+ auto stop_hour_node
+ = slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_HOUR));
+ auto stop_minute_node
+ = slot_id_node.emplace_node(ATTRIBUTE(YEAR_DAY_SCHEDULE_STOP_MINUTE));
+
+ uint8_t user_id = 0x01;
+ uint8_t slot_id = 0x02;
+ uint8_t start_year = 0x03;
+ uint8_t start_month = 0x04;
+ uint8_t start_day = 0x05;
+ uint8_t start_hour = 0x06;
+ uint8_t start_minute = 0x07;
+ uint8_t stop_year = 0x08;
+ uint8_t stop_month = 0x09;
+ uint8_t stop_day = 0x0a;
+ uint8_t stop_hour = 0x0b;
+ uint8_t stop_minute = 0x0c;
+
+ zwave_frame year_day_set;
+ year_day_set.add(user_id);
+ year_day_set.add(slot_id);
+ year_day_set.add(start_year);
+ year_day_set.add(start_month);
+ year_day_set.add(start_day);
+ year_day_set.add(start_hour);
+ year_day_set.add(start_minute);
+ year_day_set.add(stop_year);
+ year_day_set.add(stop_month);
+ year_day_set.add(stop_day);
+ year_day_set.add(stop_hour);
+ year_day_set.add(stop_minute);
+
+ attribute_store_network_helper_get_endpoint_node_IgnoreAndReturn(
+ cpp_endpoint_id_node);
+ attribute_store_network_helper_get_unid_from_node_IgnoreAndReturn(
+ cpp_endpoint_id_node);
+ uic_mqtt_dotdot_unify_schedule_entry_lock_publish_generated_year_day_report_command_Ignore();
+ helper_test_report_frame(SCHEDULE_ENTRY_LOCK_YEAR_DAY_REPORT, year_day_set);
+ TEST_ASSERT_EQUAL(user_id, user_id_node.reported());
+ TEST_ASSERT_EQUAL(slot_id, slot_id_node.reported());
+ TEST_ASSERT_EQUAL(start_year, start_year_node.reported());
+ TEST_ASSERT_EQUAL(start_month, start_month_node.reported());
+ TEST_ASSERT_EQUAL(start_day, start_day_node.reported());
+ TEST_ASSERT_EQUAL(start_hour, start_hour_node.reported());
+ TEST_ASSERT_EQUAL(start_minute, start_minute_node.reported());
+ TEST_ASSERT_EQUAL(stop_year, stop_year_node.reported());
+ TEST_ASSERT_EQUAL(stop_month, stop_month_node.reported());
+ TEST_ASSERT_EQUAL(stop_day, stop_day_node.reported());
+ TEST_ASSERT_EQUAL(stop_hour, stop_hour_node.reported());
+ TEST_ASSERT_EQUAL(stop_minute, stop_minute_node.reported());
+}
+
+void test_schedule_entry_lock_daily_repeating_report_happy_case()
+{
+ helper_set_version(SCHEDULE_ENTRY_LOCK_VERSION_V3);
+ auto user_id_node = helper_test_and_get_node(ATTRIBUTE(USER_IDENTIFIER));
+ auto slot_id_node
+ = user_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_SCHEDULE_SLOT_ID));
+ auto week_day_node
+ = slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_WEEK_DAY));
+ auto start_hour_node
+ = slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_START_HOUR));
+ auto start_minute_node
+ = slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_START_MINUTE));
+ auto duration_hour_node
+ = slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_DURATION_HOUR));
+ auto duration_minute_node
+ = slot_id_node.emplace_node(ATTRIBUTE(DAILY_REPEATING_DURATION_MINUTE));
+
+ uint8_t user_id = 0x01;
+ uint8_t slot_id = 0x02;
+ uint8_t week_day = 0x03;
+ uint8_t start_hour = 0x04;
+ uint8_t start_minute = 0x05;
+ uint8_t duration_hour = 0x06;
+ uint8_t duration_minute = 0x07;
+
+ zwave_frame daily_repeating_set;
+ daily_repeating_set.add(user_id);
+ daily_repeating_set.add(slot_id);
+ daily_repeating_set.add(week_day);
+ daily_repeating_set.add(start_hour);
+ daily_repeating_set.add(start_minute);
+ daily_repeating_set.add(duration_hour);
+ daily_repeating_set.add(duration_minute);
+
+ attribute_store_network_helper_get_endpoint_node_IgnoreAndReturn(
+ cpp_endpoint_id_node);
+ attribute_store_network_helper_get_unid_from_node_IgnoreAndReturn(
+ cpp_endpoint_id_node);
+ uic_mqtt_dotdot_unify_schedule_entry_lock_publish_generated_daily_repeating_report_command_Ignore();
+
+ helper_test_report_frame(SCHEDULE_ENTRY_LOCK_DAILY_REPEATING_REPORT_V3,
+ daily_repeating_set);
+ TEST_ASSERT_EQUAL(user_id, user_id_node.reported());
+ TEST_ASSERT_EQUAL(slot_id, slot_id_node.reported());
+ TEST_ASSERT_EQUAL(week_day, week_day_node.reported());
+ TEST_ASSERT_EQUAL(start_hour, start_hour_node.reported());
+ TEST_ASSERT_EQUAL(start_minute, start_minute_node.reported());
+ TEST_ASSERT_EQUAL(duration_hour, duration_hour_node.reported());
+ TEST_ASSERT_EQUAL(duration_minute, duration_minute_node.reported());
+}
+
+} // extern "C"
diff --git a/applications/zpc/doc/command_classes/multilevel_sensor.rst b/applications/zpc/doc/command_classes/multilevel_sensor.rst
index e78562e65..4c64a1d64 100644
--- a/applications/zpc/doc/command_classes/multilevel_sensor.rst
+++ b/applications/zpc/doc/command_classes/multilevel_sensor.rst
@@ -160,6 +160,9 @@ UAM files
* - ``Time_to_MultilevelSensorCC.uam``
- ``Time.xml``
- Use to operate Local Time
+ * - N/A
+ - ``Unify_MultilevelSensor.xml``
+ - Use for reporting sensor values.
Bindings
--------
@@ -197,6 +200,15 @@ Bindings
* - ``SENSOR_VALUE``
- Time MeasuredValue
- If ``SENSOR_TYPE`` = 0x21. Z-Wave -> Cluster (ReadOnly)
+ * - ``SENSOR_VALUE``
+ - SensorValues
+ - ``SENSOR_VALUE`` mapping with ``Value`` field of SensorValues attribute. Z-Wave -> Cluster (ReadOnly)
+ * - ``SCALE``
+ - SensorValues
+ - ``SCALE`` mapping with ``Scale`` field of SensorValues attribute. Z-Wave -> Cluster (ReadOnly)
+ * - ``SENSOR_TYPE``
+ - SensorType
+ - ``SENSOR_TYPE`` mapping with SensorType attribute. Z-Wave -> Cluster (ReadOnly)
Command actions
---------------
@@ -295,3 +307,6 @@ Command actions
* - Get Local Time
- ``ucl/by-unid/+/+/Time/Attributes/LocalTime/Reported { "value": }``
- Only reported values
+ * - Report sensor values
+ - ``ucl/by-unid/+/+//MultilevelSensor/Attributes/SensorValues/Reported {"value": {"Scale": ,"Value": }}``
+ - Only reported values
\ No newline at end of file
diff --git a/patches/UnifySDK/0007-fix-build-Allow-to-regenerate-files-using-zap.patch b/patches/UnifySDK/0007-fix-build-Allow-to-regenerate-files-using-zap.patch
new file mode 100644
index 000000000..49e2f7541
--- /dev/null
+++ b/patches/UnifySDK/0007-fix-build-Allow-to-regenerate-files-using-zap.patch
@@ -0,0 +1,37 @@
+From f1b677b4127c8776244b272bcf20c9afeebe5522 Mon Sep 17 00:00:00 2001
+From: Philippe Coval
+Date: Mon, 15 Sep 2025 10:43:26 +0200
+Subject: [PATCH] fix(build): Allow to regenerate files using zap
+
+For the record, files can be regenerated from developer using:
+
+ rm -rf build ; cmake_options=-DZAP_GENERATE=ON ./helper.mk
+
+For some reasons developer will have to commit also generated files,
+which is a bad practice, but I believe it was intentional to avoid
+propagation to zap as build dependency, this may be revised to avoid
+serialization of development.
+
+Relate-to: https://github.com/project-chip/zap/releases/download/v2025.07.24/zap-linux-x64.deb
+Bug-SiliconLabs: UIC-3222
+Signed-off-by: Philippe Coval
+---
+ helper.mk | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/helper.mk b/helper.mk
+index be052d5af6..75d1051981 100755
+--- a/helper.mk
++++ b/helper.mk
+@@ -16,7 +16,7 @@ project?=unifysdk
+ BUILD_DEV_GUI?=OFF
+ BUILD_IMAGE_PROVIDER?=ON
+
+-cmake_options?=-B ${build_dir}
++cmake_options+=-B ${build_dir}
+
+ CMAKE_GENERATOR?=Ninja
+ export CMAKE_GENERATOR
+--
+2.39.5
+
diff --git a/patches/UnifySDK/0008-UIC-3273-Custom-Unify_MultilevelSensor-cluster.patch b/patches/UnifySDK/0008-UIC-3273-Custom-Unify_MultilevelSensor-cluster.patch
new file mode 100644
index 000000000..06f6ef334
--- /dev/null
+++ b/patches/UnifySDK/0008-UIC-3273-Custom-Unify_MultilevelSensor-cluster.patch
@@ -0,0 +1,538 @@
+From 049707c76ce7f322abe1ef54a1c5b568dc4599ba Mon Sep 17 00:00:00 2001
+From: ptphan
+Date: Wed, 2 Oct 2024 10:40:35 +0700
+Subject: [PATCH] UIC-3273: Custom Unify_MultilevelSensor cluster
+
+[Philippe Coval]
+
+This patch was split in two, this version is the change that apply to
+Unify, please refer to previous commit to undestand the flow, I after
+the failed cherry-pick, I just used patch -p1 < patch and commited
+only the changes that applies to Unify, the same operation should be
+done for z-p-c project (in the opposite way).
+
+Origin: ver_1.7.0-unstable-23-g38f24ffb48
+Bug-SiliconLabs: UIC-3273
+Origin: s.s.com/projects/UIC/repos/uic/pull-requests/2855
+Relate-to: https://github.com/SiliconLabsSoftware/z-wave-protocol-controller/issues/44
+Forwarded: https://github.com/rzr/UnifySDK/tree/z-wave/core/zpc/main
+Forwarded: https://github.com/SiliconLabsSoftware/z-wave-protocol-controller/pull/143
+Signed-off-by: Philippe Coval
+---
+ .../multilevel_sensor_cluster_server.cpp | 181 ++++++++++++++++++
+ .../multilevel_sensor_cluster_server.h | 44 +++++
+ .../zcl_cluster_servers/CMakeLists.txt | 46 +++++
+ .../src/zcl_cluster_servers.cpp | 55 ++++++
+ .../dotdot-xml/Unify_MultilevelSensor.xml | 121 ++++++++++++
+ components/uic_dotdot/dotdot-xml/library.xml | 1 +
+ components/uic_dotdot/zap/addon-helper.js | 1 +
+ 7 files changed, 449 insertions(+)
+ create mode 100644 applications/examples/applications/emulated_end_device/components/eed_attribute_store/include/multilevel_sensor_cluster_server.cpp
+ create mode 100644 applications/examples/applications/emulated_end_device/components/eed_attribute_store/include/multilevel_sensor_cluster_server.h
+ create mode 100644 applications/zpc/components/zcl_cluster_servers/CMakeLists.txt
+ create mode 100644 applications/zpc/components/zcl_cluster_servers/src/zcl_cluster_servers.cpp
+ create mode 100644 components/uic_dotdot/dotdot-xml/Unify_MultilevelSensor.xml
+
+diff --git a/applications/examples/applications/emulated_end_device/components/eed_attribute_store/include/multilevel_sensor_cluster_server.cpp b/applications/examples/applications/emulated_end_device/components/eed_attribute_store/include/multilevel_sensor_cluster_server.cpp
+new file mode 100644
+index 0000000000..0645623b87
+--- /dev/null
++++ b/applications/examples/applications/emulated_end_device/components/eed_attribute_store/include/multilevel_sensor_cluster_server.cpp
+@@ -0,0 +1,181 @@
++/******************************************************************************
++ * # 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 "multilevel_sensor_cluster_server.h"
++#include "zcl_cluster_servers_helpers.hpp"
++
++// Interfaces
++#include "zwave_command_class_version_types.h"
++#include "zwave_command_class_configuration_types.h"
++
++// ZPC includes
++#include "zpc_attribute_store.h"
++#include "zpc_attribute_store_network_helper.h"
++#include "zwave_command_class_generic_types.h"
++#include "attribute_store_defined_attribute_types.h"
++
++// Includes from Unify shared components
++#include "attribute.hpp"
++#include "attribute_store_helper.h"
++#include "sl_log.h"
++
++// Includes from auto-generated files
++#include "dotdot_mqtt.h"
++#include "zap-types.h"
++#include "dotdot_mqtt_helpers.hpp"
++
++// Generic includes
++#include
++#include
++#include
++
++using namespace attribute_store;
++
++// Setup Log ID
++constexpr char LOG_TAG[] = "multilevel_sensor_cluster_server";
++
++// Attribute macro, shortening those long defines for attribute types:
++#define ATTRIBUTE(type) ATTRIBUTE_COMMAND_CLASS_SENSOR_MULTILEVEL_##type
++
++// List of attributes of SensorValues
++namespace
++{
++const std::vector sensor_values_attributes
++ = {ATTRIBUTE(SENSOR_VALUE), ATTRIBUTE(SCALE)};
++}
++
++///////////////////////////////////////////////////////////////////////////////
++// Attribute publication functions
++//////////////////////////////////////////////////////////////////////////////
++
++/**
++ * @brief Publishes the Multilevel Sensor Cluster Server attributes
++ *
++ * @param unid unid for which we want to publish the
++ * SensorValues attributes.
++ * @param endpoint_id Endpoint ID for which we want to publish the
++ * SensorValues attributes.
++ * @param sensor_type Sensor Type node ID for which we want to publish the
++ * SensorValues attributes.
++ */
++static sl_status_t publish_multilevel_sensor_cluster_attributes(
++ const std::string &unid,
++ attribute_store::attribute sensor_type_node,
++ zwave_endpoint_id_t endpoint_id)
++{
++ // Do not publish any state supported commands for ourselves.
++ if (is_zpc_unid(unid.c_str())) {
++ return SL_STATUS_FAIL;
++ }
++
++ // Build the base topic and pass it on to DotDot MQTT.
++ try {
++ // Get reported sensor type ID
++ uint8_t sensor_type = sensor_type_node.reported();
++
++ // Get SensorType name
++ const std::string sensor_type_str
++ = multilevel_sensor_sensor_type_get_enum_value_name(sensor_type);
++
++ // Added sensor type name to base topic
++ const std::string base_topic = "ucl/by-unid/" + std::string(unid) + "/ep"
++ + std::to_string(endpoint_id) + "/"
++ + std::string(sensor_type_str);
++
++ SensorValue value = {0, 0};
++ // Get report sensor value
++ attribute_store::attribute sensor_value_node
++ = sensor_type_node.child_by_type(ATTRIBUTE(SENSOR_VALUE));
++ if (sensor_value_node.reported_exists()) {
++ value.Value = sensor_value_node.reported();
++ }
++ // Get report sensor scale
++ attribute_store::attribute sensor_scale_node
++ = sensor_type_node.child_by_type(ATTRIBUTE(SCALE));
++ if (sensor_scale_node.reported_exists()) {
++ value.Scale = static_cast(sensor_scale_node.reported());
++ }
++
++ // Pulish the sensor value attribute
++ if (SL_STATUS_OK
++ != uic_mqtt_dotdot_multilevel_sensor_sensor_values_publish(
++ base_topic.c_str(),
++ value,
++ UCL_MQTT_PUBLISH_TYPE_REPORTED)) {
++ return SL_STATUS_FAIL;
++ }
++ } catch (const std::exception &e) {
++ sl_log_error(LOG_TAG,
++ "Error while get base topic and sensor data : %s",
++ e.what());
++
++ return SL_STATUS_FAIL;
++ }
++ return SL_STATUS_OK;
++}
++
++///////////////////////////////////////////////////////////////////////////////
++// Attribute store callback functions
++//////////////////////////////////////////////////////////////////////////////
++/**
++ * @brief Listens to updates to the SensorValues then publishes the attributes.
++ *
++ * @param updated_node Attribute Store node that was modified.
++ * @param change Type of change applied to the node.
++ */
++void on_sensor_values_update(attribute_store_node_t updated_node,
++ attribute_store_change_t change)
++{
++ if (change == ATTRIBUTE_CREATED || change == ATTRIBUTE_DELETED) {
++ return;
++ }
++
++ // Go up and find the UNID/Endpoint and its network status.
++ unid_t unid;
++ zwave_endpoint_id_t endpoint_id = 0;
++ if (SL_STATUS_OK
++ != attribute_store_network_helper_get_unid_endpoint_from_node(
++ updated_node,
++ unid,
++ &endpoint_id)) {
++ return;
++ }
++
++ attribute_store::attribute sensor_type_node
++ = attribute_store_get_first_parent_with_type(updated_node,
++ ATTRIBUTE(SENSOR_TYPE));
++
++ // Publish the multilevel sensor values:
++ if (SL_STATUS_OK
++ != publish_multilevel_sensor_cluster_attributes(std::string(unid),
++ sensor_type_node,
++ endpoint_id)) {
++ return;
++ }
++}
++
++///////////////////////////////////////////////////////////////////////////////
++// Init and teardown functions.
++//////////////////////////////////////////////////////////////////////////////
++sl_status_t multilevel_sensor_cluster_server_init(void)
++{
++ sl_log_debug(LOG_TAG, "Multilevel sensor server initialization");
++
++ // Register attribute updates
++
++ attribute_store_register_callback_by_type_to_array(
++ &on_sensor_values_update,
++ sensor_values_attributes.data(),
++ static_cast(sensor_values_attributes.size()));
++
++ return SL_STATUS_OK;
++}
+diff --git a/applications/examples/applications/emulated_end_device/components/eed_attribute_store/include/multilevel_sensor_cluster_server.h b/applications/examples/applications/emulated_end_device/components/eed_attribute_store/include/multilevel_sensor_cluster_server.h
+new file mode 100644
+index 0000000000..7abce74752
+--- /dev/null
++++ b/applications/examples/applications/emulated_end_device/components/eed_attribute_store/include/multilevel_sensor_cluster_server.h
+@@ -0,0 +1,44 @@
++/******************************************************************************
++ * # 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.
++ *
++ *****************************************************************************/
++
++/**
++ * @defgroup multilevel_sensor_cluster_server ZCL Multilevel Sensor cluster
++ * @ingroup zcl_cluster_servers
++ * @brief The module handlers the Multilevel Sensor Cluster attribute and
++ * publish directly the attribute via MQTT.
++ *
++ * @{
++ */
++
++#ifndef MULTILEVEL_SENSOR_CLUSTER_SERVER_H
++#define MULTILEVEL_SENSOR_CLUSTER_SERVER_H
++
++#include "sl_status.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/**
++ * @brief Initialize the Multilevel Sensor Cluster Commands handler.
++ *
++ * @returns SL_STATUS_OK on success, any other code on failure
++ */
++sl_status_t multilevel_sensor_cluster_server_init(void);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif //MULTILEVEL_SENSOR_CLUSTER_SERVER_H
++/** @} end configuration_cluster_mapper */
+diff --git a/applications/zpc/components/zcl_cluster_servers/CMakeLists.txt b/applications/zpc/components/zcl_cluster_servers/CMakeLists.txt
+new file mode 100644
+index 0000000000..41a947535f
+--- /dev/null
++++ b/applications/zpc/components/zcl_cluster_servers/CMakeLists.txt
+@@ -0,0 +1,46 @@
++find_package(Boost REQUIRED)
++
++# Find nlohmann_json, unfortunately the find_package doesn't work for this when
++# cross compiling, thus we use the simplified method find_path instead
++find_path(nlohmann_json_include nlohmann/json.hpp REQUIRED)
++
++# ZCL Cluster server library
++add_library(
++ zcl_cluster_servers
++ src/configuration_parameter_cluster_server.cpp
++ src/humidity_control_cluster_server.c
++ src/user_code_cluster_server.cpp
++ src/fan_control_cluster_server.c
++ src/zcl_binding_cluster_server.cpp
++ src/zcl_cluster_servers.cpp
++ src/zcl_cluster_servers_helpers.cpp
++ src/zcl_OTA_cluster_server.cpp
++ src/zcl_rf_telemetry_cluster_server.c
++ src/zcl_scenes_cluster_server.cpp
++ src/multilevel_sensor_cluster_server.cpp
++ )
++
++target_include_directories(
++ zcl_cluster_servers
++ PUBLIC include
++ PRIVATE src ${nlohmann_json_include} ${Boost_INCLUDE_DIRS})
++
++target_link_libraries(
++ zcl_cluster_servers
++ PUBLIC zwave_handlers zwave_definitions
++ PRIVATE unify
++ zpc_attribute_store
++ zpc_utils
++ ucl_mqtt
++ zwave_command_classes
++ zwave_api_transport
++ dotdot_mapper
++ zwave_network_management)
++
++if(BUILD_TESTING)
++ # Unit tests
++ add_subdirectory(test)
++
++ # Mocks
++ target_add_mock(zcl_cluster_servers)
++endif()
+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
+new file mode 100644
+index 0000000000..736b3d7f39
+--- /dev/null
++++ b/applications/zpc/components/zcl_cluster_servers/src/zcl_cluster_servers.cpp
+@@ -0,0 +1,55 @@
++/******************************************************************************
++ * # 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 from this component
++#include "zcl_cluster_servers.h"
++#include "zcl_rf_telemetry_cluster_server.h"
++#include "configuration_parameter_cluster_server.h"
++#include "zcl_binding_cluster_server.h"
++#include "zcl_scenes_cluster_server.h"
++#include "zcl_OTA_cluster_server.hpp"
++#include "user_code_cluster_server.h"
++#include "fan_control_cluster_server.h"
++#include "multilevel_sensor_cluster_server.h"
++
++//Includes from other components
++#include "attribute_store.h"
++#include "attribute_store_helper.h"
++#include "zpc_attribute_store_network_helper.h"
++#include "attribute_store_defined_attribute_types.h"
++
++// Interfaces
++#include "zwave_controller_types.h"
++
++///////////////////////////////////////////////////////////////////////////////
++// Init and teardown functions.
++//////////////////////////////////////////////////////////////////////////////
++sl_status_t zcl_cluster_servers_init()
++{
++ sl_status_t init_status = SL_STATUS_OK;
++ init_status |= zcl_OTA_cluster_server_init();
++ init_status |= zcl_rf_telemetry_cluster_server_init();
++ init_status |= configuration_parameter_cluster_server_init();
++ init_status |= binding_cluster_server_init();
++ init_status |= zcl_scenes_cluster_server_init();
++ init_status |= user_code_cluster_server_init();
++ init_status |= fan_control_cluster_server_init();
++ init_status |= multilevel_sensor_cluster_server_init();
++
++ return init_status;
++}
++
++int zcl_cluster_servers_teardown()
++{
++ zcl_scenes_cluster_server_teardown();
++ return 0;
++}
+diff --git a/components/uic_dotdot/dotdot-xml/Unify_MultilevelSensor.xml b/components/uic_dotdot/dotdot-xml/Unify_MultilevelSensor.xml
+new file mode 100644
+index 0000000000..126be4bd8e
+--- /dev/null
++++ b/components/uic_dotdot/dotdot-xml/Unify_MultilevelSensor.xml
+@@ -0,0 +1,121 @@
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+diff --git a/components/uic_dotdot/dotdot-xml/library.xml b/components/uic_dotdot/dotdot-xml/library.xml
+index 4210b67fa4..deec70c822 100644
+--- a/components/uic_dotdot/dotdot-xml/library.xml
++++ b/components/uic_dotdot/dotdot-xml/library.xml
+@@ -501,4 +501,5 @@ applicable to this document can be found in the LICENSE.md file.
+
+
+
++
+
+\ No newline at end of file
+diff --git a/components/uic_dotdot/zap/addon-helper.js b/components/uic_dotdot/zap/addon-helper.js
+index 3686fb8395..9d57f82c8b 100644
+--- a/components/uic_dotdot/zap/addon-helper.js
++++ b/components/uic_dotdot/zap/addon-helper.js
+@@ -127,6 +127,7 @@ function isStruct(type) {
+ case 'SSceneTable': return true
+ case 'DeviceTypeStruct': return true
+ case 'CredentialStruct': return true
++ case 'SensorValue': return true
+ default: return false
+ }
+ }
+--
+2.39.5
+
diff --git a/patches/UnifySDK/0009-UIC-3273-Generated-files-for-Unify_MultilevelSensor-.patch b/patches/UnifySDK/0009-UIC-3273-Generated-files-for-Unify_MultilevelSensor-.patch
new file mode 100644
index 000000000..a55cbdaad
--- /dev/null
+++ b/patches/UnifySDK/0009-UIC-3273-Generated-files-for-Unify_MultilevelSensor-.patch
@@ -0,0 +1,3672 @@
+From 15eb74a0f1c4a8fdd9fa20b17d6e3129af53dac0 Mon Sep 17 00:00:00 2001
+From: ptphan
+Date: Wed, 2 Oct 2024 10:38:02 +0700
+Subject: [PATCH] UIC-3273: Generated files for Unify_MultilevelSensor Cluster
+
+[Philippe Coval]
+
+This change has been applied without any change and will be forwarded to:
+
+This change was made from uic repo by exporting patch using:
+
+git format-patch -1 943ae4c683f819ae8b6407ee29aa4f7c9bd69ddf
+
+And then applied on top of z-wave/core/zpc/main (dangling branch of
+Unify, currently in rzr fork, that may be pushed to public Unify repo)
+
+git apply -i 0001-UIC-3273-Generated-files-for-Unify_MultilevelSensor-.patch
+
+Then a patch is generated for z-p-c project using:
+
+ git format-patch --no-numbered \
+ -o ~/mnt/z-wave-protocol-controller/patches/UnifySDK/ \
+ ver_1.7.0
+
+Bug-SiliconLabs: UIC-3273
+Origin: ver_1.7.0-unstable-22-g943ae4c683
+Origin: s.s.com/projects/UIC/repos/uic/pull-requests/2855
+Relate-to: https://github.com/SiliconLabsSoftware/z-wave-protocol-controller/issues/44
+Forwarded: https://github.com/rzr/UnifySDK/tree/z-wave/core/zpc/main
+Forwarded: https://github.com/SiliconLabsSoftware/z-wave-protocol-controller/pull/143
+Signed-off-by: Philippe Coval
+---
+ .../cluster-types/cluster-type-attributes.ts | 2 +-
+ .../include/dotdot_attribute_id_definitions.h | 3 +
+ .../dotdot_cluster_command_id_definitions.h | 2 +
+ .../include/dotdot_cluster_id_definitions.h | 4 +
+ .../zap-generated/include/zap-types.h | 96 ++++
+ .../readme_ucl_mqtt_reference.md | 443 ++++++++++++++++
+ .../src/dotdot_attribute_id_definitions.c | 40 ++
+ .../src/dotdot_cluster_id_definitions.c | 5 +
+ .../zap-generated/include/dotdot_mqtt.h | 183 +++++++
+ .../include/dotdot_mqtt_attributes.h | 35 ++
+ .../include/dotdot_mqtt_generated_commands.h | 22 +
+ .../include/dotdot_mqtt_group_commands.h | 17 +
+ .../include/dotdot_mqtt_helpers.h | 7 +
+ .../include/dotdot_mqtt_helpers.hpp | 17 +
+ ...dotdot_mqtt_supported_generated_commands.h | 28 +
+ .../include/dotdot_mqtt_translators.h | 26 +
+ .../zap-generated/src/dotdot_mqtt.cpp | 488 ++++++++++++++++++
+ .../zap-generated/src/dotdot_mqtt.hpp | 28 +
+ .../src/dotdot_mqtt_attributes.cpp | 206 ++++++++
+ .../src/dotdot_mqtt_command_helpers.cpp | 16 +
+ .../src/dotdot_mqtt_command_helpers.hpp | 12 +
+ .../src/dotdot_mqtt_generated_commands.cpp | 40 ++
+ .../src/dotdot_mqtt_group_commands.cpp | 99 ++++
+ .../zap-generated/src/dotdot_mqtt_helpers.cpp | 246 +++++++++
+ ...tdot_mqtt_supported_generated_commands.cpp | 43 ++
+ .../test/dotdot_mqtt_test.include | 1 +
+ .../include/dotdot_attributes.uam | 4 +
+ .../include/dotdot_attributes_camel_case.uam | 4 +
+ .../unify_dotdot_attribute_store_helpers.h | 240 +++++++++
+ .../unify_dotdot_defined_attribute_types.h | 3 +
+ ...ot_attribute_store_attribute_publisher.cpp | 257 +++++++++
+ ..._force_read_attributes_command_callbacks.c | 37 ++
+ .../unify_dotdot_attribute_store_helpers.cpp | 249 +++++++++
+ ...fy_dotdot_attribute_store_registration.cpp | 48 ++
+ ...store_write_attributes_command_callbacks.c | 33 ++
+ .../test/unify_dotdot_attribute_store_test.c | 28 +
+ .../test/unify_dotdot_attribute_store_test.h | 4 +
+ 37 files changed, 3015 insertions(+), 1 deletion(-)
+
+diff --git a/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/cluster-type-attributes.ts b/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/cluster-type-attributes.ts
+index a46049dbe7..2fa7a4c728 100644
+--- a/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/cluster-type-attributes.ts
++++ b/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/cluster-type-attributes.ts
+@@ -1,7 +1,7 @@
+ //This file is generated automatically. Don't try to change something here.
+ //To add support for new clusters, modify addon-helper.js
+ //To change the stucture of the ClusterTypeAttrs, modify cluster-type-attributes.zapt
+-
++
+
+ //generate ClusterTypes
+ export let ClusterTypeAttrs: any = {
+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 a988971041..52a9683a3b 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
+@@ -831,6 +831,9 @@ typedef enum {
+ #define DOTDOT_NAME_AND_LOCATION_LOCATION_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x1)
+ // Definitions for cluster: ConfigurationParameters
+ #define DOTDOT_CONFIGURATION_PARAMETERS_CONFIGURATION_PARAMETERS_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x0)
++// Definitions for cluster: MultilevelSensor
++#define DOTDOT_MULTILEVEL_SENSOR_SENSOR_VALUES_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x0)
++#define DOTDOT_MULTILEVEL_SENSOR_SENSOR_TYPE_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x1)
+ // Definitions for cluster: AoXLocator
+ #define DOTDOT_AOX_LOCATOR_REPORTING_MODE_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x1)
+ #define DOTDOT_AOX_LOCATOR_POSITION_AND_ORIENTATION_VALID_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x2)
+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 7e33175d4a..c63d48c45f 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
+@@ -353,6 +353,8 @@
+ #define DOTDOT_CONFIGURATION_PARAMETERS_SET_PARAMETER_COMMAND_ID (0x3)
+ #define DOTDOT_CONFIGURATION_PARAMETERS_DISCOVER_PARAMETER_RANGE_COMMAND_ID (0x4)
+
++// Commands for cluster: MultilevelSensor
++
+ // Commands for cluster: AoXLocator
+ #define DOTDOT_AOX_LOCATOR_IQ_REPORT_COMMAND_ID (0x1)
+ #define DOTDOT_AOX_LOCATOR_ANGLE_REPORT_COMMAND_ID (0x2)
+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 34db7d7b79..7432fce84e 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
+@@ -238,6 +238,10 @@
+ #define DOTDOT_CONFIGURATION_PARAMETERS_CLUSTER_ID ((dotdot_cluster_id_t)0xFD07)
+
+
++// Definitions for cluster: MultilevelSensor
++#define DOTDOT_MULTILEVEL_SENSOR_CLUSTER_ID ((dotdot_cluster_id_t)0xFD09)
++
++
+ // Definitions for cluster: AoXLocator
+ #define DOTDOT_AOX_LOCATOR_CLUSTER_ID ((dotdot_cluster_id_t)0xFD10)
+
+diff --git a/components/uic_dotdot/zap-generated/include/zap-types.h b/components/uic_dotdot/zap-generated/include/zap-types.h
+index daf85dbdac..504969219c 100644
+--- a/components/uic_dotdot/zap-generated/include/zap-types.h
++++ b/components/uic_dotdot/zap-generated/include/zap-types.h
+@@ -946,6 +946,96 @@ typedef enum {
+ ZCL_MOVE_STEP_MODE_DOWN = 1,
+ } MoveStepMode;
+
++// Enum for MultilevelSensorSensorType
++typedef enum {
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_AIR_TEMPERATURE = 1,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_ILLUMINANCE = 3,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_POWER = 4,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_HUMIDITY = 5,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_VELOCITY = 6,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_DIRECTION = 7,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_ATMOSPHERIC_PRESSURE = 8,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_BAROMETRIC_PRESSURE = 9,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_SOLAR_RADIATION = 10,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_DEW_POINT = 11,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_RAIN_RATE = 12,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_TIDE_LEVEL = 13,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_WEIGHT = 14,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_VOLTAGE = 15,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_CURRENT = 16,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_CARBON_DIOXIDE_CO2_LEVEL = 17,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_AIR_FLOW = 18,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_TANK_CAPACITY = 19,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_DISTANCE = 20,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_ROTATION = 22,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_WATER_TEMPURATURE = 23,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_SOIL_TEMPURATURE = 24,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_SEISMIC_INTENSITY = 25,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_SEISMIC_MAGNITUDE = 26,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_ULTRAVIOLET = 27,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_ELECTRICAL_RESISTIVITY = 28,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_ELECTRICAL_CONDUCTIVITY = 29,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_LOUDNESS = 30,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_MOISTURE = 31,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_FREQUENCY = 32,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_TIME = 33,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_TARGET_TEMPERATURE = 34,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_PARTICULATE_MATTER2__5 = 35,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_FORMALDEHYDE_LEVEL = 36,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_RADON_CONCENTRATION = 37,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_METHANE_DENSITY = 38,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_VOLATILE_ORGANIC_COMPOUND_LEVEL = 39,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_CARBON_MONOXIDE_LEVEL = 40,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_SOIL_HUMIDITY = 41,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_SOIL_REACTIVITY = 42,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_SOIL_SALINITY = 43,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_HEART_RATE = 44,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_BLOOD_PRESSURE = 45,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_MUSCLE_MASS = 46,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_FAT_MASS = 47,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_BONE_MASS = 48,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_TOTAL_BODY_WATER = 49,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_BASIS_METABOLIC_RATE = 50,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_BODY_MASS_INDEX = 51,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_ACCELERATION_X_AXIS = 52,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_ACCELERATION_Y_AXIS = 53,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_ACCELERATION_Z_AXIS = 54,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_SMOKE_DENSITY = 55,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_WATER_FLOW = 56,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_WATER_PRESSURE = 57,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_RF_SIGNAL_STRENGTH = 58,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_PARTICULATE_MATTER10 = 59,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_RESPIRATORY_RATE = 60,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_RELATIVE_MODULATION_LEVEL = 61,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_BOILER_WATER_TEMPERATURE = 62,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_DOMESTIC_HOT_WATER_TEMPERATURE = 63,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_OUTSIDE_TEMPERATURE = 64,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_EXHAUST_TEMPERATURE = 65,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_WATER_CHLORINE_LEVEL = 66,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_WATER_ACIDITY = 67,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_WATER_OXIDATION_REDUCTION_POTENTIAL = 68,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_HEART_RATE_LFHF_RATIO = 69,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_MOTION_DIRECTION = 70,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_APPLIED_FORCE_ON_THE_SENSOR = 71,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_RETURN_AIR_TEMPERATURE = 72,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_SUPPLY_AIR_TEMPERATURE = 73,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_CONDENSER_COIL_TEMPERATURE = 74,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_EVAPRORATOR_COIL_TEMPERATURE = 75,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_LIQUID_LINE_TEMPERATURE = 76,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_DISCHARGE_LINE_TEMPERATURE = 77,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_SUCTION_PRESSURE = 78,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_DISCHARGE_PRESSURE = 79,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_DEFROST_TEMPERATURE = 80,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_OZONE = 81,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_SULFUR_DIOXIDE = 82,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_NITROGEN_DIOXIDE = 83,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_AMMONIA = 84,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_LEAD = 85,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_PARTICULATE_MATTER1 = 86,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_PERSON_COUNTER_ENTERING = 87,
++ ZCL_MULTILEVEL_SENSOR_SENSOR_TYPE_PERSON_COUNTER_EXITING = 88,
++} MultilevelSensorSensorType;
++
+ // Enum for NM_State
+ typedef enum {
+ ZCL_NM_STATE_IDLE = 0,
+@@ -2284,6 +2374,12 @@ typedef struct _SSceneTable {
+ const char* SceneTableExtensions;
+ } SSceneTable;
+
++// Struct for SensorValue
++typedef struct _SensorValue {
++ int32_t Value;
++ uint8_t Scale;
++} SensorValue;
++
+ // Struct for SphericalCoordinates
+ typedef struct _SphericalCoordinates {
+ double Azimuth;
+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 5316b884c2..82dfa2097d 100644
+--- a/components/uic_dotdot/zap-generated/readme_ucl_mqtt_reference.md
++++ b/components/uic_dotdot/zap-generated/readme_ucl_mqtt_reference.md
+@@ -51886,6 +51886,315 @@ mosquitto_pub -t 'ucl/by-unid///ConfigurationParameters/Commands/Force
+
+
+
++
++
++
++
++
++\page multilevel_sensor MultilevelSensor Cluster
++The following commands and attributes are accepted as JSON payloads for the
++MultilevelSensor cluster.
++
++
++
++
++
++
++\section multilevel_sensor_attrs MultilevelSensor Attributes
++The following attribute topics are used to retrieve the MultilevelSensor cluster state.
++
++
++
++\subsection multilevel_sensor_attr_sensor_values MultilevelSensor/SensorValues Attribute
++
++**MQTT Topic Pattern:**
++
++```
++[PREFIX]/MultilevelSensor/Attributes/SensorValues/Reported
++[PREFIX]/MultilevelSensor/Attributes/SensorValues/Desired
++```
++
++**MQTT Payload JSON Schema:**
++
++```json
++{
++ "$schema": "http://json-schema.org/draft-07/schema#",
++ "title": "MultilevelSensor Cluster SensorValues Attribute Properties",
++ "type": "object",
++ "properties": {
++ "value": {
++ "type": "SensorValue"
++ }
++ },
++ "required": [
++ "value"
++ ]
++}
++```
++
++
++**Example Mosquitto CLI Tool Usage**
++
++To see desired/reported value for SensorValues attribute under the by-unid topic space:
++
++```console
++mosquitto_sub -t 'ucl/by-unid/+/+/MultilevelSensor/Attributes/SensorValues/+'
++
++# Example output
++
++ucl/by-unid//ep0/MultilevelSensor/Attributes/SensorValues/Desired { "value": }
++ucl/by-unid//ep0/MultilevelSensor/Attributes/SensorValues/Reported { "value": }
++
++```
++
++
++
++\subsection multilevel_sensor_attr_sensor_type MultilevelSensor/SensorType Attribute
++
++**MQTT Topic Pattern:**
++
++```
++[PREFIX]/MultilevelSensor/Attributes/SensorType/Reported
++[PREFIX]/MultilevelSensor/Attributes/SensorType/Desired
++```
++
++**MQTT Payload JSON Schema:**
++
++```json
++{
++ "$schema": "http://json-schema.org/draft-07/schema#",
++ "title": "MultilevelSensor Cluster SensorType Attribute Properties",
++ "type": "object",
++ "properties": {
++ "value": {
++ "type": "MultilevelSensorSensorType"
++ }
++ },
++ "required": [
++ "value"
++ ]
++}
++```
++
++
++**Example Mosquitto CLI Tool Usage**
++
++To see desired/reported value for SensorType attribute under the by-unid topic space:
++
++```console
++mosquitto_sub -t 'ucl/by-unid/+/+/MultilevelSensor/Attributes/SensorType/+'
++
++# Example output
++
++ucl/by-unid//ep0/MultilevelSensor/Attributes/SensorType/Desired { "value": }
++ucl/by-unid//ep0/MultilevelSensor/Attributes/SensorType/Reported { "value": }
++
++```
++
++
++
++
++\subsection multilevel_sensor_attr_cluster_revision MultilevelSensor/ClusterRevision Attribute
++
++**MQTT Topic Pattern:**
++
++```
++[PREFIX]/MultilevelSensor/Attributes/ClusterRevision/Reported
++[PREFIX]/MultilevelSensor/Attributes/ClusterRevision/Desired
++```
++
++**MQTT Payload JSON Schema:**
++
++```json
++{
++ "$schema": "http://json-schema.org/draft-07/schema#",
++ "title": "MultilevelSensor 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///MultilevelSensor/Attributes/ClusterRevision/+'
++# Example output
++ucl/by-unid///MultilevelSensor/Attributes/ClusterRevision/Desired { "value": }
++ucl/by-unid///MultilevelSensor/Attributes/ClusterRevision/Reported { "value": }
++```
++
++
++
++
++
++
++
++
++
++
++\section multilevel_sensor_recv_cmd_support MultilevelSensor Command Support
++
++**MQTT Topic Pattern:**
++
++```
++[PREFIX]/MultilevelSensor/SupportedCommands
++[PREFIX]/MultilevelSensor/SupportedGeneratedCommands
++```
++
++**MQTT Payload JSON Schema:**
++
++```json
++{
++ "$schema": "http://json-schema.org/draft-07/schema#",
++ "title": "MultilevelSensor Command Support Properties",
++ "type": "object",
++ "properties": {
++ "value": {
++ "type": "array",
++ "items" : {
++ "type": "string",
++ "enum": [
++ ]
++ }
++ }
++ }
++ },
++ "required": [
++ "value"
++ ]
++}
++```
++
++**Example Mosquitto CLI Tool Usage**
++
++To see supported commands for MultilevelSensor cluster under the by-unid topic space:
++
++```console
++mosquitto_sub -t 'ucl/by-unid///MultilevelSensor/SupportedCommands'
++# Example output
++ucl/by-unid///MultilevelSensor/SupportedCommands { "value": [] }
++```
++
++To see supported generated commands for MultilevelSensor cluster under the by-unid topic space:
++
++```console
++mosquitto_sub -t 'ucl/by-unid///MultilevelSensor/SupportedGeneratedCommands'
++# Example output
++ucl/by-unid///MultilevelSensor/SupportedGeneratedCommands { "value": [] }
++```
++
++
++
++
++
++
++
++
++
++
++\section multilevel_sensor_cmds MultilevelSensor Commands
++
++
++
++\subsection multilevel_sensor_write_attr_cmd MultilevelSensor/WriteAttributes Command
++
++**MQTT Topic Pattern:**
++
++```
++[PREFIX]/MultilevelSensor/Commands/WriteAttributes
++```
++
++**MQTT Payload JSON Schema:**
++
++```json
++{
++ "$schema": "http://json-schema.org/draft-07/schema#",
++ "title": "MultilevelSensor Cluster WriteAttributes Command Properties",
++ "type": "object",
++ "properties": {
++ },
++ "required": [
++ "value"
++ ]
++}
++```
++
++**Example Mosquitto CLI Tool Usage**
++
++To update all MultilevelSensor attributes under the by-unid topic space:
++
++```console
++mosquitto_pub -t 'ucl/by-unid///MultilevelSensor/Commands/WriteAttributes' -m '{ }'
++```
++
++> NOTE: Specify only the list of attributes to write in this command.
++> Unspecified attributes will not be updated.
++
++
++
++\subsection multilevel_sensor_force_read_attr_cmd MultilevelSensor/ForceReadAttributes Command
++
++**MQTT Topic Pattern:**
++
++```
++[PREFIX]/MultilevelSensor/Commands/ForceReadAttributes
++```
++
++**MQTT Payload JSON Schema:**
++
++```json
++{
++ "$schema": "http://json-schema.org/draft-07/schema#",
++ "title": "MultilevelSensor Cluster ForceReadAttributes Command Properties",
++ "type": "object",
++ "properties": {
++ "value": {
++ "type": "array"
++ "items": {
++ "type": "string",
++ "enum": [
++ "SensorValues",
++ "SensorType"
++ ]
++ }
++ }
++ },
++ "required": [
++ "value"
++ ]
++}
++```
++
++**Example Mosquitto CLI Tool Usage**
++
++To force read all MultilevelSensor attributes under the by-unid topic space (by sending an empty array):
++
++```console
++mosquitto_pub -t 'ucl/by-unid///MultilevelSensor/Commands/ForceReadAttributes' -m '{ "value": [] }'
++```
++
++To force read one of the MultilevelSensor attributes under the by-unid topic space:
++
++```console
++mosquitto_pub -t 'ucl/by-unid///MultilevelSensor/Commands/ForceReadAttributes' -m '{ "value": ["SensorValues"] }'
++```
++
++
++
++
++
++
++
++
+
+
+
+@@ -54908,6 +55217,33 @@ mosquitto_pub -t 'ucl/by-unid///UnifyHumidityControl/Commands/ForceRea
+
+
+
++
++
++
++\section struct_sensor_value SensorValue Struct
++
++```json
++{
++ "$schema": "http://json-schema.org/draft-07/schema#",
++ "title": "SensorValue Struct Properties",
++ "type": "object",
++ "properties": {
++ "Value": {
++ "type": "integer"
++ }
++ "Scale": {
++ "type": "integer"
++ }
++ }
++}
++```
++
++
++
++
++
++
++
+
+
+
+@@ -57032,6 +57368,113 @@ mosquitto_pub -t 'ucl/by-unid///UnifyHumidityControl/Commands/ForceRea
+
+
+
++
++
++
++\section enum_multilevel_sensor_sensor_type MultilevelSensorSensorType Enum
++
++```json
++{
++ "$schema": "http://json-schema.org/draft-07/schema#",
++ "title": "MultilevelSensorSensorType Enum Properties",
++ "type": "string",
++ "enum": [
++ "AirTemperature",
++ "Illuminance",
++ "Power",
++ "Humidity",
++ "Velocity",
++ "Direction",
++ "AtmosphericPressure",
++ "BarometricPressure",
++ "SolarRadiation",
++ "DewPoint",
++ "RainRate",
++ "TideLevel",
++ "Weight",
++ "Voltage",
++ "Current",
++ "CarbonDioxideCO2Level",
++ "AirFlow",
++ "TankCapacity",
++ "Distance",
++ "Rotation",
++ "WaterTempurature",
++ "SoilTempurature",
++ "SeismicIntensity",
++ "SeismicMagnitude",
++ "Ultraviolet",
++ "ElectricalResistivity",
++ "ElectricalConductivity",
++ "Loudness",
++ "Moisture",
++ "Frequency",
++ "Time",
++ "TargetTemperature",
++ "ParticulateMatter2.5",
++ "FormaldehydeLevel",
++ "RadonConcentration",
++ "MethaneDensity",
++ "VolatileOrganicCompoundLevel",
++ "CarbonMonoxideLevel",
++ "SoilHumidity",
++ "SoilReactivity",
++ "SoilSalinity",
++ "HeartRate",
++ "BloodPressure",
++ "MuscleMass",
++ "FatMass",
++ "BoneMass",
++ "TotalBodyWater",
++ "BasisMetabolicRate",
++ "BodyMassIndex",
++ "AccelerationX-axis",
++ "AccelerationY-axis",
++ "AccelerationZ-axis",
++ "SmokeDensity",
++ "WaterFlow",
++ "WaterPressure",
++ "RFSignalStrength",
++ "ParticulateMatter10",
++ "RespiratoryRate",
++ "RelativeModulationLevel",
++ "BoilerWaterTemperature",
++ "DomesticHotWaterTemperature",
++ "OutsideTemperature",
++ "ExhaustTemperature",
++ "WaterChlorineLevel",
++ "WaterAcidity",
++ "WaterOxidationReductionPotential",
++ "HeartRateLFHFRatio",
++ "MotionDirection",
++ "AppliedForceOnTheSensor",
++ "ReturnAirTemperature",
++ "SupplyAirTemperature",
++ "CondenserCoilTemperature",
++ "EvaproratorCoilTemperature",
++ "LiquidLineTemperature",
++ "DischargeLineTemperature",
++ "SuctionPressure",
++ "DischargePressure",
++ "DefrostTemperature",
++ "Ozone",
++ "SulfurDioxide",
++ "NitrogenDioxide",
++ "Ammonia",
++ "Lead",
++ "ParticulateMatter1",
++ "PersonCounterEntering",
++ "PersonCounterExiting"
++ ]
++}
++```
++
++
++
++
++
++
++
+
+
+
+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 badc743381..98ebe6435d 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
+@@ -1947,6 +1947,19 @@ const char *uic_dotdot_get_attribute_name(dotdot_cluster_id_t cluster_id,
+ return "Unknown";
+ }
+ // clang-format off
++ case DOTDOT_MULTILEVEL_SENSOR_CLUSTER_ID:
++ // clang-format on
++ switch (attribute_id) {
++ // clang-format off
++ case DOTDOT_MULTILEVEL_SENSOR_SENSOR_VALUES_ATTRIBUTE_ID:
++ return "SensorValues";
++ case DOTDOT_MULTILEVEL_SENSOR_SENSOR_TYPE_ATTRIBUTE_ID:
++ return "SensorType";
++ // clang-format on
++ default:
++ return "Unknown";
++ }
++ // clang-format off
+ case DOTDOT_AOX_LOCATOR_CLUSTER_ID:
+ // clang-format on
+ switch (attribute_id) {
+@@ -4415,6 +4428,14 @@ dotdot_attribute_id_t
+ return DOTDOT_CONFIGURATION_PARAMETERS_CONFIGURATION_PARAMETERS_ATTRIBUTE_ID;
+ }
+ break;
++ case DOTDOT_MULTILEVEL_SENSOR_CLUSTER_ID:
++ if (strcmp ("SensorValues", attribute_name) == 0) {
++ return DOTDOT_MULTILEVEL_SENSOR_SENSOR_VALUES_ATTRIBUTE_ID;
++ }
++ if (strcmp ("SensorType", attribute_name) == 0) {
++ return DOTDOT_MULTILEVEL_SENSOR_SENSOR_TYPE_ATTRIBUTE_ID;
++ }
++ break;
+ case DOTDOT_AOX_LOCATOR_CLUSTER_ID:
+ if (strcmp ("ReportingMode", attribute_name) == 0) {
+ return DOTDOT_AOX_LOCATOR_REPORTING_MODE_ATTRIBUTE_ID;
+@@ -6506,6 +6527,19 @@ dotdot_attribute_json_type_t
+ return JSON_TYPE_UNKNOWN;
+ }
+ // clang-format off
++ case DOTDOT_MULTILEVEL_SENSOR_CLUSTER_ID:
++ // clang-format on
++ switch (attribute_id) {
++ // clang-format off
++ case DOTDOT_MULTILEVEL_SENSOR_SENSOR_VALUES_ATTRIBUTE_ID:
++ return JSON_TYPE_OBJECT;
++ case DOTDOT_MULTILEVEL_SENSOR_SENSOR_TYPE_ATTRIBUTE_ID:
++ return JSON_TYPE_NUMBER;
++ // clang-format on
++ default:
++ return JSON_TYPE_UNKNOWN;
++ }
++ // clang-format off
+ case DOTDOT_AOX_LOCATOR_CLUSTER_ID:
+ // clang-format on
+ switch (attribute_id) {
+@@ -6982,6 +7016,12 @@ bool uic_dotdot_attribute_is_enum(dotdot_cluster_id_t cluster_id,
+ if (64775 == cluster_id) {
+ }
+
++ if (64777 == cluster_id) {
++ if (1 == attribute_id) {
++ return true;
++ }
++ }
++
+ if (64786 == cluster_id) {
+ }
+
+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 8699e827dc..4c251d9e02 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
+@@ -120,6 +120,8 @@ const char* uic_dotdot_get_cluster_name(dotdot_cluster_id_t cluster_id) {
+ return "NameAndLocation";
+ case DOTDOT_CONFIGURATION_PARAMETERS_CLUSTER_ID:
+ return "ConfigurationParameters";
++ case DOTDOT_MULTILEVEL_SENSOR_CLUSTER_ID:
++ return "MultilevelSensor";
+ case DOTDOT_AOX_LOCATOR_CLUSTER_ID:
+ return "AoXLocator";
+ case DOTDOT_AOX_POSITION_ESTIMATION_CLUSTER_ID:
+@@ -293,6 +295,9 @@ dotdot_cluster_id_t uic_dotdot_get_cluster_id(const char* cluster_name) {
+ if (strcmp ("ConfigurationParameters", cluster_name) == 0) {
+ return DOTDOT_CONFIGURATION_PARAMETERS_CLUSTER_ID;
+ }
++ if (strcmp ("MultilevelSensor", cluster_name) == 0) {
++ return DOTDOT_MULTILEVEL_SENSOR_CLUSTER_ID;
++ }
+ if (strcmp ("AoXLocator", cluster_name) == 0) {
+ return DOTDOT_AOX_LOCATOR_CLUSTER_ID;
+ }
+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 bd703a2daf..7606ec4c85 100644
+--- a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt.h
++++ b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt.h
+@@ -39077,6 +39077,189 @@ void uic_mqtt_dotdot_configuration_parameters_publish_supported_commands(
+ void uic_mqtt_dotdot_configuration_parameters_publish_empty_supported_commands(
+ const dotdot_unid_t unid
+ ,dotdot_endpoint_id_t endpoint);
++// Callback types used by the multilevel_sensor cluster
++
++typedef struct {
++ SensorValue sensor_values;
++ uint8_t sensor_type;
++} uic_mqtt_dotdot_multilevel_sensor_state_t;
++
++typedef struct {
++ bool sensor_values;
++ bool sensor_type;
++} uic_mqtt_dotdot_multilevel_sensor_updated_state_t;
++
++typedef sl_status_t (*uic_mqtt_dotdot_multilevel_sensor_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_multilevel_sensor_state_t,
++ uic_mqtt_dotdot_multilevel_sensor_updated_state_t
++);
++
++typedef sl_status_t (*uic_mqtt_dotdot_multilevel_sensor_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_multilevel_sensor_updated_state_t
++);
++
++
++
++
++/**
++ * @brief Setup a callback for WriteAttribute to be called when a
++ * +/multilevel_sensor/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_multilevel_sensor_write_attributes_callback(
++ const uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback_t callback
++);
++/**
++ * @brief Unsets a callback for WriteAttribute to be called when a
++ * +/multilevel_sensor/Commands/WriteAttributes is received.
++ * @param callback Function to be no longer called on command reception
++ */
++void uic_mqtt_dotdot_unset_multilevel_sensor_write_attributes_callback(
++ const uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback_t callback
++);
++/**
++ * @brief Clears all callbacks registered for when
++ * +/multilevel_sensor/Commands/WriteAttributes is received.
++ */
++void uic_mqtt_dotdot_clear_multilevel_sensor_write_attributes_callbacks();
++
++/**
++ * @brief Setup a callback for ForceReadAttributes to be called when a
++ * +/multilevel_sensor/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_multilevel_sensor_force_read_attributes_callback(
++ const uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback_t callback
++);
++/**
++ * @brief Unsets a callback for ForceReadAttributes to be called when a
++ * +/multilevel_sensor/Commands/ForceReadAttributes is received.
++ *
++ * @param callback Function to be no longer called on command reception
++ */
++void uic_mqtt_dotdot_unset_multilevel_sensor_force_read_attributes_callback(
++ const uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback_t callback
++);
++/**
++ * @brief Clears all callbacks registered for when
++ * +/multilevel_sensor/Commands/ForceReadAttributes is received.
++ */
++void uic_mqtt_dotdot_clear_multilevel_sensor_force_read_attributes_callbacks();
++
++/**
++ * @brief Publish the attribute; MultilevelSensor/Attributes/SensorValues
++ *
++ * @param base_topic topic prefix to publish, /sensor_values
++ * 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_multilevel_sensor_sensor_values_publish(
++ const char *base_topic,
++ SensorValue value,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Unretains a published attribute; MultilevelSensor/Attributes/SensorValues
++ *
++ * @param base_topic topic prefix to publish, /sensor_values
++ * 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_multilevel_sensor_sensor_values_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Publish the attribute; MultilevelSensor/Attributes/SensorType
++ *
++ * @param base_topic topic prefix to publish, /sensor_type
++ * 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_multilevel_sensor_sensor_type_publish(
++ const char *base_topic,
++ uint8_t value,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Unretains a published attribute; MultilevelSensor/Attributes/SensorType
++ *
++ * @param base_topic topic prefix to publish, /sensor_type
++ * 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_multilevel_sensor_sensor_type_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++
++/**
++ * @brief Publish the MultilevelSensor/ClusterRevision attribute
++ *
++ * @param base_topic topic prefix to publish, /MultilevelSensor/Attributes/ClusterRevision
++ * will be appended.
++ * @param value Value to publish.
++ */
++void uic_mqtt_dotdot_multilevel_sensor_publish_cluster_revision(const char* base_topic, uint16_t value);
++
++/**
++ * @brief Unretain a publication to MultilevelSensor/ClusterRevision attribute
++ *
++ * @param base_topic topic prefix to publish, /MultilevelSensor/Attributes/ClusterRevision
++ * will be appended.
++ */
++void uic_mqtt_dotdot_multilevel_sensor_unretain_cluster_revision(const char* base_topic);
++
++/**
++ * @brief Publish the SupportedCommands for UNID/EndPoint for the MultilevelSensor Cluster
++ *
++ * This function will iterate over all Commands in the MultilevelSensor 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_multilevel_sensor_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 MultilevelSensor Cluster
++ *
++ * @param unid
++ * @param endpoint )
++ */
++void uic_mqtt_dotdot_multilevel_sensor_publish_empty_supported_commands(
++ const dotdot_unid_t unid
++ ,dotdot_endpoint_id_t endpoint);
+ // Callback types used by the protocol_controller_network_management cluster
+ typedef sl_status_t (*uic_mqtt_dotdot_protocol_controller_network_management_write_callback_t)(
+ dotdot_unid_t unid,
+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 68b51b7e03..003f75549d 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
+@@ -4978,6 +4978,21 @@ typedef sl_status_t (*uic_mqtt_dotdot_configuration_parameters_attribute_configu
+ size_t configuration_parameters_count,
+ const ConfigurationParameter* configuration_parameters
+ );
++// Callback types used by the multilevel_sensor cluster
++typedef sl_status_t (*uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_values_callback_t)(
++ dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint,
++ bool unretained,
++ uic_mqtt_dotdot_attribute_update_type_t update_type,
++ SensorValue sensor_values
++);
++typedef sl_status_t (*uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_type_callback_t)(
++ dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint,
++ bool unretained,
++ uic_mqtt_dotdot_attribute_update_type_t update_type,
++ uint8_t sensor_type
++);
+ // Callback types used by the protocol_controller_network_management cluster
+ typedef sl_status_t (*uic_mqtt_dotdot_protocol_controller_network_management_attribute_network_management_state_callback_t)(
+ dotdot_unid_t unid,
+@@ -9739,6 +9754,26 @@ sl_status_t uic_mqtt_dotdot_configuration_parameters_attributes_init();
+ void uic_mqtt_dotdot_configuration_parameters_attribute_configuration_parameters_callback_set(const uic_mqtt_dotdot_configuration_parameters_attribute_configuration_parameters_callback_t callback);
+
+
++/**
++ * Initializes the attributes features for the MultilevelSensor cluster,
++ * allowing to receive attribute updates from other UNIDs.
++ */
++sl_status_t uic_mqtt_dotdot_multilevel_sensor_attributes_init();
++
++/**
++ * Setup callback to be called when a
++ * MultilevelSensor/Attributes/sensor_values/# is received. Setting
++ * this callback will overwrite the previous set callback
++ */
++void uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_values_callback_set(const uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_values_callback_t callback);
++/**
++ * Setup callback to be called when a
++ * MultilevelSensor/Attributes/sensor_type/# is received. Setting
++ * this callback will overwrite the previous set callback
++ */
++void uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_type_callback_set(const uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_type_callback_t callback);
++
++
+ /**
+ * Initializes the attributes features for the ProtocolController-NetworkManagement cluster,
+ * allowing to receive attribute updates from other UNIDs.
+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 011a75ddf9..aa8ac95998 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
+@@ -4838,6 +4838,28 @@ void uic_mqtt_dotdot_configuration_parameters_publish_generated_write_attributes
+ uic_mqtt_dotdot_configuration_parameters_updated_state_t attribute_list
+ );
+
++
++/**
++ * @brief Publishes an incoming/generated WriteAttributes command for
++ * the MultilevelSensor cluster.
++ *
++ * Publication will be made at the following topic
++ * ucl/by-unid/UNID/epID/MultilevelSensor/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_multilevel_sensor_publish_generated_write_attributes_command(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint,
++ uic_mqtt_dotdot_multilevel_sensor_state_t attribute_values,
++ uic_mqtt_dotdot_multilevel_sensor_updated_state_t attribute_list
++);
++
+ /**
+ * @brief Publishes an incoming/generated Write command for
+ * the ProtocolController-NetworkManagement cluster.
+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 ac85664a4f..caeee80ffa 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
+@@ -3610,6 +3610,23 @@ void uic_mqtt_dotdot_by_group_configuration_parameters_write_attributes_callback
+
+
+
++typedef void (*uic_mqtt_dotdot_by_group_multilevel_sensor_write_attributes_callback_t)(
++ const dotdot_group_id_t group_id,
++ uic_mqtt_dotdot_multilevel_sensor_state_t,
++ uic_mqtt_dotdot_multilevel_sensor_updated_state_t
++);
++
++/**
++ * Setup a callback for WriteAttribute to be called when a
++ * ucl/by-group/+/multilevel_sensor/Commands/WriteAttributes is received.
++ * Setting this callback will overwrite any previously set callback.
++ */
++void uic_mqtt_dotdot_by_group_multilevel_sensor_write_attributes_callback_set(
++ const uic_mqtt_dotdot_by_group_multilevel_sensor_write_attributes_callback_t callback
++);
++
++
++
+ typedef void (*uic_mqtt_dotdot_by_group_descriptor_write_attributes_callback_t)(
+ const dotdot_group_id_t group_id,
+ uic_mqtt_dotdot_descriptor_state_t,
+diff --git a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_helpers.h b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_helpers.h
+index 80d87abc45..a9b42d482c 100644
+--- a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_helpers.h
++++ b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_helpers.h
+@@ -538,6 +538,13 @@ char *move_step_mode_get_enum_value_name_c(
+ uint32_t value, char *result, size_t max_result_size);
+ /** Get move_step_mode enum representation from string. */
+ uint32_t move_step_mode_get_enum_value_number_c(const char *str);
++#define MULTILEVEL_SENSOR_SENSOR_TYPE_ENUM_NAME_AVAILABLE 1
++
++/** Get multilevel_sensor_sensor_type string representation from enum. */
++char *multilevel_sensor_sensor_type_get_enum_value_name_c(
++ uint32_t value, char *result, size_t max_result_size);
++/** Get multilevel_sensor_sensor_type enum representation from string. */
++uint32_t multilevel_sensor_sensor_type_get_enum_value_number_c(const char *str);
+ #define NM_STATE_ENUM_NAME_AVAILABLE 1
+
+ /** Get nm_state string representation from enum. */
+diff --git a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_helpers.hpp b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_helpers.hpp
+index 14befa43ce..d227c69cc2 100644
+--- a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_helpers.hpp
++++ b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_helpers.hpp
+@@ -1271,6 +1271,23 @@ std::string move_step_mode_get_enum_value_name(
+ */
+ uint32_t move_step_mode_get_enum_value_number(const std::string &str);
+
++#define MULTILEVEL_SENSOR_SENSOR_TYPE_ENUM_NAME_AVAILABLE 1
++
++/**
++ * @brief Finds the name of a field for the MultilevelSensorSensorType enum
++ *
++ * @returns A string representation of the value.
++ */
++std::string multilevel_sensor_sensor_type_get_enum_value_name(
++ uint32_t value);
++
++/**
++ * @brief Finds the enum number of a string representation for the MultilevelSensorSensorType enum
++ *
++ * @returns A number enum value.
++ */
++uint32_t multilevel_sensor_sensor_type_get_enum_value_number(const std::string &str);
++
+ #define NM_STATE_ENUM_NAME_AVAILABLE 1
+
+ /**
+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 3ee01c0c62..31b5b4443d 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
+@@ -1552,6 +1552,34 @@ void uic_mqtt_dotdot_configuration_parameters_publish_supported_generated_comman
+ );
+
+
++/**
++ * @brief Struct containing the list of commands for MultilevelSensor
++ */
++typedef struct _uic_mqtt_dotdot_multilevel_sensor_supported_commands_ {
++ bool write_attributes;
++} uic_mqtt_dotdot_multilevel_sensor_supported_commands_t;
++
++/**
++ * @brief Sends/Publishes a the SupportedGenerated commands for
++ * the MultilevelSensor cluster for a UNID/Endpoint
++ *
++ * Publication will be made at the following topic
++ * ucl/by-unid/UNID/epID/MultilevelSensor/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_multilevel_sensor_publish_supported_generated_commands(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint,
++ const uic_mqtt_dotdot_multilevel_sensor_supported_commands_t *command_list
++);
++
++
+ /**
+ * @brief Struct containing the list of commands for ProtocolController-NetworkManagement
+ */
+diff --git a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_translators.h b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_translators.h
+index d72db40ead..999d4c726e 100644
+--- a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_translators.h
++++ b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_translators.h
+@@ -493,6 +493,32 @@ inline void to_json(nlohmann::json& jsn, const SSceneTable& field)
+ }
+
+
++/**
++ * Parse SensorValue type from json object.
++ *
++ * @param jsn JSON object to parse from.
++ * @param field field to be populated from JSON object.
++ */
++inline void from_json(const nlohmann::json& jsn, SensorValue& field)
++{
++ jsn.at("Value").get_to(field.Value);
++ jsn.at("Scale").get_to(field.Scale);
++}
++
++
++/**
++ * Build JSON object from SensorValue type.
++ *
++ * @param jsn JSON object to be populated.
++ * @param field Reference data.
++ */
++inline void to_json(nlohmann::json& jsn, const SensorValue& field)
++{
++ jsn["Value"] = field.Value;
++ jsn["Scale"] = field.Scale;
++}
++
++
+ /**
+ * Parse SphericalCoordinates type from json object.
+ *
+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 d1122bf8dd..fb910272aa 100644
+--- a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.cpp
++++ b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.cpp
+@@ -91829,6 +91829,340 @@ sl_status_t uic_mqtt_dotdot_configuration_parameters_init()
+ return SL_STATUS_OK;
+ }
+
++// Callbacks pointers
++static std::set uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback;
++static std::set uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback;
++
++// Callbacks setters
++
++void uic_mqtt_dotdot_set_multilevel_sensor_write_attributes_callback(
++ const uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback_t callback)
++{
++ if (callback != nullptr) {
++ uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback.insert(callback);
++ }
++}
++void uic_mqtt_dotdot_unset_multilevel_sensor_write_attributes_callback(
++ const uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback_t callback)
++{
++ uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback.erase(callback);
++}
++void uic_mqtt_dotdot_clear_multilevel_sensor_write_attributes_callbacks()
++{
++ uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback.clear();
++}
++std::set& get_uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback()
++{
++ return uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback;
++}
++
++void uic_mqtt_dotdot_set_multilevel_sensor_force_read_attributes_callback(
++ const uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback_t callback)
++{
++ if (callback != nullptr) {
++ uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback.insert(callback);
++ }
++}
++void uic_mqtt_dotdot_unset_multilevel_sensor_force_read_attributes_callback(
++ const uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback_t callback)
++{
++ uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback.erase(callback);
++}
++void uic_mqtt_dotdot_clear_multilevel_sensor_force_read_attributes_callbacks()
++{
++ uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback.clear();
++}
++
++
++// Callback function for incoming publications on ucl/by-unid/+/+/MultilevelSensor/Commands/WriteAttributes
++void uic_mqtt_dotdot_on_multilevel_sensor_WriteAttributes(
++ const char *topic,
++ const char *message,
++ const size_t message_length)
++{
++ if (uic_mqtt_dotdot_multilevel_sensor_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_multilevel_sensor_state_t new_state = {};
++ uic_mqtt_dotdot_multilevel_sensor_updated_state_t new_updated_state = {};
++
++
++ nlohmann::json jsn;
++ try {
++ jsn = nlohmann::json::parse(std::string(message));
++
++ uic_mqtt_dotdot_parse_multilevel_sensor_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, "MultilevelSensor", "WriteAttributes");
++ return;
++ } catch (const nlohmann::json::exception& e) {
++ // Catch JSON object field parsing errors
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "MultilevelSensor", "WriteAttributes", e.what());
++ return;
++ } catch (const std::exception& e) {
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "MultilevelSensor", "WriteAttributes", "");
++ return;
++ }
++
++ for (const auto& callback: uic_mqtt_dotdot_multilevel_sensor_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_multilevel_sensor_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_multilevel_sensor_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_multilevel_sensor_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.sensor_values = true;
++ force_update.sensor_type = true;
++ trigger_handler = true;
++ } else {
++ std::unordered_map supported_attrs = {
++ {"SensorValues", &force_update.sensor_values },
++ {"SensorType", &force_update.sensor_type },
++ };
++
++ 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_multilevel_sensor_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, "MultilevelSensor/Commands/ForceReadAttributes: Unable to parse JSON payload");
++ return;
++ }
++}
++
++sl_status_t uic_mqtt_dotdot_multilevel_sensor_sensor_values_publish(
++ const char *base_topic,
++ SensorValue value,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++)
++{
++ nlohmann::json jsn;
++
++ // This is a single value
++
++ nlohmann::json json_object = nlohmann::json::object();
++ json_object["Value"] = value.Value;
++ json_object["Scale"] = value.Scale;
++ jsn["value"]= json_object;
++
++
++ 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, "MultilevelSensor/Attributes/SensorValues", e.what());
++ return SL_STATUS_OK;
++ }
++
++
++ std::string topic = std::string(base_topic) + "/MultilevelSensor/Attributes/SensorValues";
++ 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_multilevel_sensor_sensor_values_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type)
++{
++ // clang-format on
++ std::string topic
++ = std::string(base_topic)
++ + "/MultilevelSensor/Attributes/SensorValues";
++
++ 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_multilevel_sensor_sensor_type_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
++
++ #ifdef MULTILEVEL_SENSOR_SENSOR_TYPE_ENUM_NAME_AVAILABLE
++ jsn["value"] = multilevel_sensor_sensor_type_get_enum_value_name((uint32_t)value);
++ #elif defined(ENUM8_ENUM_NAME_AVAILABLE)
++ jsn["value"] = enum8_get_enum_value_name((uint32_t)value);
++ #else
++ sl_log_warning(LOG_TAG,"Warning: Enum name not available for MULTILEVEL_SENSOR_SENSOR_TYPE. Using number instead.");
++ jsn["value"] = static_cast(value);
++ #endif
++
++
++ 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, "MultilevelSensor/Attributes/SensorType", e.what());
++ return SL_STATUS_OK;
++ }
++
++
++ std::string topic = std::string(base_topic) + "/MultilevelSensor/Attributes/SensorType";
++ 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_multilevel_sensor_sensor_type_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type)
++{
++ // clang-format on
++ std::string topic
++ = std::string(base_topic)
++ + "/MultilevelSensor/Attributes/SensorType";
++
++ 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_multilevel_sensor_init()
++{
++ std::string base_topic = "ucl/by-unid/+/+/";
++
++ std::string subscription_topic;
++ if(!uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback.empty()) {
++ subscription_topic = base_topic + "MultilevelSensor/Commands/WriteAttributes";
++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_multilevel_sensor_WriteAttributes);
++ }
++
++ if(!uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback.empty()) {
++ subscription_topic = base_topic + "MultilevelSensor/Commands/ForceReadAttributes";
++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_multilevel_sensor_force_read_attributes);
++ }
++
++ // Init the attributes for that cluster
++ uic_mqtt_dotdot_multilevel_sensor_attributes_init();
++
++ uic_mqtt_dotdot_by_group_multilevel_sensor_init();
++
++ return SL_STATUS_OK;
++}
++
+ // Callbacks pointers
+ static std::set uic_mqtt_dotdot_protocol_controller_network_management_write_callback;
+ static std::set uic_mqtt_dotdot_protocol_controller_network_management_generated_write_callback;
+@@ -95747,6 +96081,10 @@ sl_status_t uic_mqtt_dotdot_init() {
+ status_flag = uic_mqtt_dotdot_configuration_parameters_init();
+ }
+
++ if (status_flag == SL_STATUS_OK) {
++ status_flag = uic_mqtt_dotdot_multilevel_sensor_init();
++ }
++
+ if (status_flag == SL_STATUS_OK) {
+ status_flag = uic_mqtt_dotdot_protocol_controller_network_management_init();
+ }
+@@ -95824,6 +96162,7 @@ void uic_mqtt_dotdot_publish_supported_commands(
+ uic_mqtt_dotdot_application_monitoring_publish_supported_commands(unid, 0);
+ uic_mqtt_dotdot_name_and_location_publish_supported_commands(unid, endpoint_id);
+ uic_mqtt_dotdot_configuration_parameters_publish_supported_commands(unid, endpoint_id);
++ uic_mqtt_dotdot_multilevel_sensor_publish_supported_commands(unid, endpoint_id);
+ uic_mqtt_dotdot_protocol_controller_network_management_publish_supported_commands(unid, 0);
+ uic_mqtt_dotdot_descriptor_publish_supported_commands(unid, endpoint_id);
+ uic_mqtt_dotdot_unify_fan_control_publish_supported_commands(unid, endpoint_id);
+@@ -95883,6 +96222,7 @@ void uic_mqtt_dotdot_publish_empty_supported_commands(
+ uic_mqtt_dotdot_application_monitoring_publish_empty_supported_commands(unid);
+ uic_mqtt_dotdot_name_and_location_publish_empty_supported_commands(unid, endpoint_id);
+ uic_mqtt_dotdot_configuration_parameters_publish_empty_supported_commands(unid, endpoint_id);
++ uic_mqtt_dotdot_multilevel_sensor_publish_empty_supported_commands(unid, endpoint_id);
+ uic_mqtt_dotdot_protocol_controller_network_management_publish_empty_supported_commands(unid);
+ uic_mqtt_dotdot_descriptor_publish_empty_supported_commands(unid, endpoint_id);
+ uic_mqtt_dotdot_unify_fan_control_publish_empty_supported_commands(unid, endpoint_id);
+@@ -108646,6 +108986,154 @@ void uic_mqtt_dotdot_configuration_parameters_publish_empty_supported_commands(
+ }
+ }
+
++// Publishing Cluster Revision for MultilevelSensor Cluster
++void uic_mqtt_dotdot_multilevel_sensor_publish_cluster_revision(const char* base_topic, uint16_t value)
++{
++ std::string cluster_topic = std::string(base_topic) + "/MultilevelSensor/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 MultilevelSensor Cluster
++void uic_mqtt_dotdot_multilevel_sensor_unretain_cluster_revision(const char* base_topic)
++{
++ // clang-format on
++ std::string cluster_topic
++ = std::string(base_topic)
++ + "/MultilevelSensor/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_multilevel_sensor_write_attributes_is_supported(
++ const dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint_id)
++{
++ for (const auto& callback: uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback) {
++ uic_mqtt_dotdot_multilevel_sensor_state_t multilevel_sensor_new_state = {};
++ uic_mqtt_dotdot_multilevel_sensor_updated_state_t multilevel_sensor_new_updated_state = {};
++
++ if (callback(
++ unid,
++ endpoint_id,
++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK,
++ multilevel_sensor_new_state,
++ multilevel_sensor_new_updated_state
++ ) == SL_STATUS_OK) {
++ return true;
++ }
++ }
++ return false;
++}
++
++static inline bool uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_is_supported(
++ const dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint_id)
++{
++ for (const auto& callback: uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback) {
++ uic_mqtt_dotdot_multilevel_sensor_updated_state_t multilevel_sensor_force_update = {0};
++ if (callback(
++ unid,
++ endpoint_id,
++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK,
++ multilevel_sensor_force_update
++ ) == SL_STATUS_OK) {
++ return true;
++ }
++ }
++ return false;
++}
++
++// Publishing Supported Commands for MultilevelSensor Cluster
++void uic_mqtt_dotdot_multilevel_sensor_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
++
++ // Check for a WriteAttributes Callback
++ if(uic_mqtt_dotdot_multilevel_sensor_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_multilevel_sensor_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 += "/MultilevelSensor/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 += "/MultilevelSensor/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 MultilevelSensor Cluster
++void uic_mqtt_dotdot_multilevel_sensor_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 += "/MultilevelSensor/SupportedCommands";
++
++ if (uic_mqtt_count_topics(topic.c_str()) > 0) {
++ uic_mqtt_publish(topic.c_str(),
++ EMPTY_VALUE_ARRAY,
++ strlen(EMPTY_VALUE_ARRAY),
++ true);
++ }
++}
++
+ // Publishing Cluster Revision for ProtocolController-NetworkManagement Cluster
+ void uic_mqtt_dotdot_protocol_controller_network_management_publish_cluster_revision(const char* base_topic, uint16_t value)
+ {
+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 63ed3b0949..9fbbc1ede6 100644
+--- a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.hpp
++++ b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.hpp
+@@ -343,6 +343,13 @@ sl_status_t uic_mqtt_dotdot_by_group_name_and_location_init();
+ */
+ sl_status_t uic_mqtt_dotdot_by_group_configuration_parameters_init();
+
++/**
++ * @brief Initialize MultilevelSensor dotdot bygroup command handlers
++ *
++ * @returns SL_STATUS_OK on success, error otherwise.
++ */
++sl_status_t uic_mqtt_dotdot_by_group_multilevel_sensor_init();
++
+ /**
+ * @brief Initialize Descriptor dotdot bygroup command handlers
+ *
+@@ -4915,6 +4922,27 @@ void uic_mqtt_dotdot_on_configuration_parameters_WriteAttributes(
+ 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_multilevel_sensor_write_attributes_callback();
++
++/**
++ * @brief MQTT Subscribe handler for incoming publications on:
++ * ucl/by-unid/+/+/MultilevelSensor/Commands/WriteAttributes
++ */
++// clang-format off
++void uic_mqtt_dotdot_on_multilevel_sensor_WriteAttributes(
++ const char *topic,
++ const char *message,
++ const size_t message_length);
++
++
+ // clang-format on
+
+ /**
+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 51bb0cd1eb..25ce61e26a 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
+@@ -61125,6 +61125,212 @@ void uic_mqtt_dotdot_configuration_parameters_attribute_configuration_parameters
+
+ // End of supported cluster.
+
++///////////////////////////////////////////////////////////////////////////////
++// Callback pointers for MultilevelSensor
++///////////////////////////////////////////////////////////////////////////////
++static uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_values_callback_t uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_values_callback = nullptr;
++static uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_type_callback_t uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_type_callback = nullptr;
++
++///////////////////////////////////////////////////////////////////////////////
++// Attribute update handlers for MultilevelSensor
++///////////////////////////////////////////////////////////////////////////////
++static void uic_mqtt_dotdot_on_multilevel_sensor_sensor_values_attribute_update(
++ const char *topic,
++ const char *message,
++ const size_t message_length) {
++ if (uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_values_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;
++ }
++
++
++ SensorValue sensor_values = {};
++
++ 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, "MultilevelSensor::SensorValues: Missing attribute element: 'value'\n");
++ return;
++ }
++// Start parsing value
++ sensor_values.Value = json_payload.at("value").at("Value").get();
++ sensor_values.Scale = json_payload.at("value").at("Scale").get();
++
++ // End parsing value
++ }
++
++ } catch (const std::exception& e) {
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "value", message);
++ return;
++ }
++
++ uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_values_callback(
++ static_cast(unid.c_str()),
++ endpoint,
++ unretained,
++ update_type,
++ sensor_values
++ );
++
++}
++static void uic_mqtt_dotdot_on_multilevel_sensor_sensor_type_attribute_update(
++ const char *topic,
++ const char *message,
++ const size_t message_length) {
++ if (uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_type_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 sensor_type = {};
++
++ 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, "MultilevelSensor::SensorType: Missing attribute element: 'value'\n");
++ return;
++ }
++// Start parsing value
++ uint32_t tmp = get_enum_decimal_value("value", json_payload);
++ if (tmp == numeric_limits::max()) {
++ #ifdef MULTILEVEL_SENSOR_SENSOR_TYPE_ENUM_NAME_AVAILABLE
++ tmp = multilevel_sensor_sensor_type_get_enum_value_number(json_payload.at("value").get());
++ #elif defined(SENSOR_TYPE_ENUM_NAME_AVAILABLE)
++ tmp = sensor_type_get_enum_value_number(json_payload.at("value").get());
++ #endif
++ }
++ sensor_type = static_cast(tmp);
++
++ // End parsing value
++ }
++
++ } catch (const std::exception& e) {
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "value", message);
++ return;
++ }
++
++ uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_type_callback(
++ static_cast(unid.c_str()),
++ endpoint,
++ unretained,
++ update_type,
++ sensor_type
++ );
++
++}
++
++///////////////////////////////////////////////////////////////////////////////
++// Attribute init functions for MultilevelSensor
++///////////////////////////////////////////////////////////////////////////////
++sl_status_t uic_mqtt_dotdot_multilevel_sensor_attributes_init()
++{
++ std::string base_topic = "ucl/by-unid/+/+/";
++
++ std::string subscription_topic;
++ if(uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_values_callback) {
++ subscription_topic = base_topic + "MultilevelSensor/Attributes/SensorValues/#";
++ uic_mqtt_subscribe(subscription_topic.c_str(), &uic_mqtt_dotdot_on_multilevel_sensor_sensor_values_attribute_update);
++ }
++ if(uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_type_callback) {
++ subscription_topic = base_topic + "MultilevelSensor/Attributes/SensorType/#";
++ uic_mqtt_subscribe(subscription_topic.c_str(), &uic_mqtt_dotdot_on_multilevel_sensor_sensor_type_attribute_update);
++ }
++
++ return SL_STATUS_OK;
++}
++
++
++///////////////////////////////////////////////////////////////////////////////
++// Callback setters and getters for MultilevelSensor
++///////////////////////////////////////////////////////////////////////////////
++void uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_values_callback_set(const uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_values_callback_t callback)
++{
++ uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_values_callback = callback;
++}
++void uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_type_callback_set(const uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_type_callback_t callback)
++{
++ uic_mqtt_dotdot_multilevel_sensor_attribute_sensor_type_callback = callback;
++}
++
++// End of supported cluster.
++
+ ///////////////////////////////////////////////////////////////////////////////
+ // Callback pointers for ProtocolController-NetworkManagement
+ ///////////////////////////////////////////////////////////////////////////////
+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 a738479fb0..25c2c2aced 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
+@@ -14318,6 +14318,22 @@ void uic_mqtt_dotdot_parse_configuration_parameters_write_attributes(
+
+
+
++}
++
++
++/**
++ * @brief JSON parser for ::WriteAttributes command arguments.
++ *
++ * Parse incoming JSON object to populate command arguments passed in by reference.
++ */
++void uic_mqtt_dotdot_parse_multilevel_sensor_write_attributes(
++ nlohmann::json &jsn,
++ uic_mqtt_dotdot_multilevel_sensor_state_t &new_state,
++ uic_mqtt_dotdot_multilevel_sensor_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 6f34c390dc..4bb5c71735 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
+@@ -5915,6 +5915,18 @@ void uic_mqtt_dotdot_parse_configuration_parameters_write_attributes(
+ );
+
+
++/**
++ * @brief JSON parser for MultilevelSensor WriteAttributes command arguments.
++ *
++ * Parse incoming JSON object to populate command arguments passed in by reference.
++ */
++void uic_mqtt_dotdot_parse_multilevel_sensor_write_attributes(
++ nlohmann::json &jsn,
++ uic_mqtt_dotdot_multilevel_sensor_state_t &new_state,
++ uic_mqtt_dotdot_multilevel_sensor_updated_state_t &new_updated_state
++);
++
++
+ /**
+ * @brief Private helper function that will create a JSON string based on the
+ * fields of a ProtocolController/NetworkManagement Write command
+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 6faf125b5f..9c5b838ded 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
+@@ -10915,6 +10915,46 @@ void uic_mqtt_dotdot_configuration_parameters_publish_generated_write_attributes
+ false);
+ }
+
++
++
++/**
++ * @brief Publishes an incoming/generated WriteAttributes command for
++ * the MultilevelSensor cluster.
++ *
++ * Publication will be made at the following topic
++ * ucl/by-unid/UNID/epID/MultilevelSensor/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_multilevel_sensor_publish_generated_write_attributes_command(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint,
++ uic_mqtt_dotdot_multilevel_sensor_state_t attribute_values,
++ uic_mqtt_dotdot_multilevel_sensor_updated_state_t attribute_list
++){
++ // Create the topic
++ std::string topic = "ucl/by-unid/"+ std::string(unid) + "/ep" +
++ std::to_string(endpoint) + "/";
++ topic += "MultilevelSensor/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);
++}
++
+ /**
+ * @brief Publishes an incoming/generated Write command for
+ * the ProtocolController-NetworkManagement cluster.
+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 7c2fca7faf..36023fc2e7 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
+@@ -354,6 +354,9 @@ static uic_mqtt_dotdot_by_group_configuration_parameters_discover_parameter_rang
+ static uic_mqtt_dotdot_by_group_configuration_parameters_write_attributes_callback_t uic_mqtt_dotdot_by_group_configuration_parameters_write_attributes_callback = nullptr;
+
+
++static uic_mqtt_dotdot_by_group_multilevel_sensor_write_attributes_callback_t uic_mqtt_dotdot_by_group_multilevel_sensor_write_attributes_callback = nullptr;
++
++
+ static uic_mqtt_dotdot_by_group_descriptor_write_attributes_callback_t uic_mqtt_dotdot_by_group_descriptor_write_attributes_callback = nullptr;
+
+
+@@ -1835,6 +1838,15 @@ void uic_mqtt_dotdot_by_group_configuration_parameters_write_attributes_callback
+
+
+
++// Callbacks setters
++void uic_mqtt_dotdot_by_group_multilevel_sensor_write_attributes_callback_set(
++ const uic_mqtt_dotdot_by_group_multilevel_sensor_write_attributes_callback_t callback)
++{
++ uic_mqtt_dotdot_by_group_multilevel_sensor_write_attributes_callback = callback;
++}
++
++
++
+ // Callbacks setters
+ void uic_mqtt_dotdot_by_group_descriptor_write_attributes_callback_set(
+ const uic_mqtt_dotdot_by_group_descriptor_write_attributes_callback_t callback)
+@@ -22908,6 +22920,91 @@ sl_status_t uic_mqtt_dotdot_by_group_configuration_parameters_init()
+
+
+
++static void uic_mqtt_dotdot_on_by_group_multilevel_sensor_WriteAttributes(
++ const char *topic,
++ const char *message,
++ const size_t message_length)
++{
++
++ if ((group_dispatch_callback == nullptr) && (uic_mqtt_dotdot_by_group_multilevel_sensor_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_multilevel_sensor_write_attributes_callback().empty())) {
++ try {
++ group_dispatch_callback(group_id,
++ "MultilevelSensor",
++ "WriteAttributes",
++ message,
++ message_length,
++ uic_mqtt_dotdot_on_multilevel_sensor_WriteAttributes);
++
++ } catch (...) {
++ sl_log_debug(LOG_TAG, "MultilevelSensor: Unable to parse JSON payload.\n");
++ return;
++ }
++ } else if (uic_mqtt_dotdot_by_group_multilevel_sensor_write_attributes_callback != nullptr) {
++
++ uic_mqtt_dotdot_multilevel_sensor_state_t new_state = {};
++ uic_mqtt_dotdot_multilevel_sensor_updated_state_t new_updated_state = {};
++
++
++ nlohmann::json jsn;
++ try {
++ jsn = nlohmann::json::parse(std::string(message));
++
++ uic_mqtt_dotdot_parse_multilevel_sensor_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, "MultilevelSensor", "WriteAttributes");
++ return;
++ } catch (const nlohmann::json::exception& e) {
++ // Catch JSON object field parsing errors
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "MultilevelSensor", "WriteAttributes", e.what());
++ return;
++ } catch (const std::exception& e) {
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "MultilevelSensor", "WriteAttributes", "");
++ return;
++ }
++
++ uic_mqtt_dotdot_by_group_multilevel_sensor_write_attributes_callback(
++ group_id,
++ new_state,
++ new_updated_state
++ );
++ }
++}
++
++sl_status_t uic_mqtt_dotdot_by_group_multilevel_sensor_init()
++{
++ std::string subscription_topic;
++ const std::string topic_bygroup = TOPIC_BY_GROUP_PREFIX;
++ if(uic_mqtt_dotdot_by_group_multilevel_sensor_write_attributes_callback) {
++ subscription_topic = topic_bygroup + "MultilevelSensor/Commands/WriteAttributes";
++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_by_group_multilevel_sensor_WriteAttributes);
++ }
++
++ return SL_STATUS_OK;
++}
++
++
++
++
+ static void uic_mqtt_dotdot_on_by_group_descriptor_WriteAttributes(
+ const char *topic,
+ const char *message,
+@@ -23882,6 +23979,8 @@ void uic_mqtt_dotdot_set_group_dispatch_callback(group_dispatch_t callback)
+ uic_mqtt_subscribe("ucl/by-group/+/ConfigurationParameters/Commands/SetParameter", uic_mqtt_dotdot_on_by_group_configuration_parameters_set_parameter);
+ uic_mqtt_subscribe("ucl/by-group/+/ConfigurationParameters/Commands/DiscoverParameterRange", uic_mqtt_dotdot_on_by_group_configuration_parameters_discover_parameter_range);
+
++ uic_mqtt_subscribe("ucl/by-group/+/MultilevelSensor/Commands/WriteAttributes", uic_mqtt_dotdot_on_by_group_multilevel_sensor_WriteAttributes);
++
+ uic_mqtt_subscribe("ucl/by-group/+/Descriptor/Commands/WriteAttributes", uic_mqtt_dotdot_on_by_group_descriptor_WriteAttributes);
+
+ uic_mqtt_subscribe("ucl/by-group/+/UnifyFanControl/Commands/WriteAttributes", uic_mqtt_dotdot_on_by_group_unify_fan_control_WriteAttributes);
+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 c1531c376c..3cfdb34365 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
+@@ -3423,6 +3423,211 @@ uint32_t move_step_mode_get_enum_value_number(const std::string &str)
+ return std::numeric_limits::max();
+ }
+
++// Enum to string map for MultilevelSensorSensorType
++const std::map multilevel_sensor_sensor_type_enum_id_to_string_map {
++ { 1, "AirTemperature" },
++ { 3, "Illuminance" },
++ { 4, "Power" },
++ { 5, "Humidity" },
++ { 6, "Velocity" },
++ { 7, "Direction" },
++ { 8, "AtmosphericPressure" },
++ { 9, "BarometricPressure" },
++ { 10, "SolarRadiation" },
++ { 11, "DewPoint" },
++ { 12, "RainRate" },
++ { 13, "TideLevel" },
++ { 14, "Weight" },
++ { 15, "Voltage" },
++ { 16, "Current" },
++ { 17, "CarbonDioxideCO2Level" },
++ { 18, "AirFlow" },
++ { 19, "TankCapacity" },
++ { 20, "Distance" },
++ { 22, "Rotation" },
++ { 23, "WaterTempurature" },
++ { 24, "SoilTempurature" },
++ { 25, "SeismicIntensity" },
++ { 26, "SeismicMagnitude" },
++ { 27, "Ultraviolet" },
++ { 28, "ElectricalResistivity" },
++ { 29, "ElectricalConductivity" },
++ { 30, "Loudness" },
++ { 31, "Moisture" },
++ { 32, "Frequency" },
++ { 33, "Time" },
++ { 34, "TargetTemperature" },
++ { 35, "ParticulateMatter2.5" },
++ { 36, "FormaldehydeLevel" },
++ { 37, "RadonConcentration" },
++ { 38, "MethaneDensity" },
++ { 39, "VolatileOrganicCompoundLevel" },
++ { 40, "CarbonMonoxideLevel" },
++ { 41, "SoilHumidity" },
++ { 42, "SoilReactivity" },
++ { 43, "SoilSalinity" },
++ { 44, "HeartRate" },
++ { 45, "BloodPressure" },
++ { 46, "MuscleMass" },
++ { 47, "FatMass" },
++ { 48, "BoneMass" },
++ { 49, "TotalBodyWater" },
++ { 50, "BasisMetabolicRate" },
++ { 51, "BodyMassIndex" },
++ { 52, "AccelerationX-axis" },
++ { 53, "AccelerationY-axis" },
++ { 54, "AccelerationZ-axis" },
++ { 55, "SmokeDensity" },
++ { 56, "WaterFlow" },
++ { 57, "WaterPressure" },
++ { 58, "RFSignalStrength" },
++ { 59, "ParticulateMatter10" },
++ { 60, "RespiratoryRate" },
++ { 61, "RelativeModulationLevel" },
++ { 62, "BoilerWaterTemperature" },
++ { 63, "DomesticHotWaterTemperature" },
++ { 64, "OutsideTemperature" },
++ { 65, "ExhaustTemperature" },
++ { 66, "WaterChlorineLevel" },
++ { 67, "WaterAcidity" },
++ { 68, "WaterOxidationReductionPotential" },
++ { 69, "HeartRateLFHFRatio" },
++ { 70, "MotionDirection" },
++ { 71, "AppliedForceOnTheSensor" },
++ { 72, "ReturnAirTemperature" },
++ { 73, "SupplyAirTemperature" },
++ { 74, "CondenserCoilTemperature" },
++ { 75, "EvaproratorCoilTemperature" },
++ { 76, "LiquidLineTemperature" },
++ { 77, "DischargeLineTemperature" },
++ { 78, "SuctionPressure" },
++ { 79, "DischargePressure" },
++ { 80, "DefrostTemperature" },
++ { 81, "Ozone" },
++ { 82, "SulfurDioxide" },
++ { 83, "NitrogenDioxide" },
++ { 84, "Ammonia" },
++ { 85, "Lead" },
++ { 86, "ParticulateMatter1" },
++ { 87, "PersonCounterEntering" },
++ { 88, "PersonCounterExiting" },
++};
++
++// String to enum map for MultilevelSensorSensorType
++const std::map multilevel_sensor_sensor_type_enum_string_to_id_map {
++ { "AirTemperature", 1 },
++ { "Illuminance", 3 },
++ { "Power", 4 },
++ { "Humidity", 5 },
++ { "Velocity", 6 },
++ { "Direction", 7 },
++ { "AtmosphericPressure", 8 },
++ { "BarometricPressure", 9 },
++ { "SolarRadiation", 10 },
++ { "DewPoint", 11 },
++ { "RainRate", 12 },
++ { "TideLevel", 13 },
++ { "Weight", 14 },
++ { "Voltage", 15 },
++ { "Current", 16 },
++ { "CarbonDioxideCO2Level", 17 },
++ { "AirFlow", 18 },
++ { "TankCapacity", 19 },
++ { "Distance", 20 },
++ { "Rotation", 22 },
++ { "WaterTempurature", 23 },
++ { "SoilTempurature", 24 },
++ { "SeismicIntensity", 25 },
++ { "SeismicMagnitude", 26 },
++ { "Ultraviolet", 27 },
++ { "ElectricalResistivity", 28 },
++ { "ElectricalConductivity", 29 },
++ { "Loudness", 30 },
++ { "Moisture", 31 },
++ { "Frequency", 32 },
++ { "Time", 33 },
++ { "TargetTemperature", 34 },
++ { "ParticulateMatter2.5", 35 },
++ { "FormaldehydeLevel", 36 },
++ { "RadonConcentration", 37 },
++ { "MethaneDensity", 38 },
++ { "VolatileOrganicCompoundLevel", 39 },
++ { "CarbonMonoxideLevel", 40 },
++ { "SoilHumidity", 41 },
++ { "SoilReactivity", 42 },
++ { "SoilSalinity", 43 },
++ { "HeartRate", 44 },
++ { "BloodPressure", 45 },
++ { "MuscleMass", 46 },
++ { "FatMass", 47 },
++ { "BoneMass", 48 },
++ { "TotalBodyWater", 49 },
++ { "BasisMetabolicRate", 50 },
++ { "BodyMassIndex", 51 },
++ { "AccelerationX-axis", 52 },
++ { "AccelerationY-axis", 53 },
++ { "AccelerationZ-axis", 54 },
++ { "SmokeDensity", 55 },
++ { "WaterFlow", 56 },
++ { "WaterPressure", 57 },
++ { "RFSignalStrength", 58 },
++ { "ParticulateMatter10", 59 },
++ { "RespiratoryRate", 60 },
++ { "RelativeModulationLevel", 61 },
++ { "BoilerWaterTemperature", 62 },
++ { "DomesticHotWaterTemperature", 63 },
++ { "OutsideTemperature", 64 },
++ { "ExhaustTemperature", 65 },
++ { "WaterChlorineLevel", 66 },
++ { "WaterAcidity", 67 },
++ { "WaterOxidationReductionPotential", 68 },
++ { "HeartRateLFHFRatio", 69 },
++ { "MotionDirection", 70 },
++ { "AppliedForceOnTheSensor", 71 },
++ { "ReturnAirTemperature", 72 },
++ { "SupplyAirTemperature", 73 },
++ { "CondenserCoilTemperature", 74 },
++ { "EvaproratorCoilTemperature", 75 },
++ { "LiquidLineTemperature", 76 },
++ { "DischargeLineTemperature", 77 },
++ { "SuctionPressure", 78 },
++ { "DischargePressure", 79 },
++ { "DefrostTemperature", 80 },
++ { "Ozone", 81 },
++ { "SulfurDioxide", 82 },
++ { "NitrogenDioxide", 83 },
++ { "Ammonia", 84 },
++ { "Lead", 85 },
++ { "ParticulateMatter1", 86 },
++ { "PersonCounterEntering", 87 },
++ { "PersonCounterExiting", 88 },
++};
++
++std::string multilevel_sensor_sensor_type_get_enum_value_name(
++ uint32_t value)
++{
++ auto it = multilevel_sensor_sensor_type_enum_id_to_string_map.find(value);
++ if (it != multilevel_sensor_sensor_type_enum_id_to_string_map.end()){
++ return it->second;
++ }
++
++ // No known name value is set for this field.
++ // Set it to a string version of the value.
++ return std::to_string(value);
++}
++
++uint32_t multilevel_sensor_sensor_type_get_enum_value_number(const std::string &str)
++{
++ auto it = multilevel_sensor_sensor_type_enum_string_to_id_map.find(str);
++ if (it != multilevel_sensor_sensor_type_enum_string_to_id_map.end()){
++ return it->second;
++ }
++
++ // No known numeric value is set for this string.
++ // Return UINT32_MAX to indicate an error.
++ return std::numeric_limits::max();
++}
++
+ // Enum to string map for NM_State
+ const std::map nm_state_enum_id_to_string_map {
+ { 0, "idle" },
+@@ -10193,6 +10398,21 @@ std::string get_enum_value_name(
+ #endif
+ }
+
++ if (64777 == cluster_id) {
++ #ifdef MULTILEVEL_SENSOR_SENSOR_VALUES_ENUM_NAME_AVAILABLE
++ if (0 == attribute_id) {
++ // FIXME: Some attributes don't work because multi-upper case names end up like this: multilevel_sensorsensor_values instead of this: multilevel_sensor_sensor_values
++ return multilevel_sensor_sensor_values_get_enum_value_name(value);
++ }
++ #endif
++ #ifdef MULTILEVEL_SENSOR_SENSOR_TYPE_ENUM_NAME_AVAILABLE
++ if (1 == attribute_id) {
++ // FIXME: Some attributes don't work because multi-upper case names end up like this: multilevel_sensorsensor_type instead of this: multilevel_sensor_sensor_type
++ return multilevel_sensor_sensor_type_get_enum_value_name(value);
++ }
++ #endif
++ }
++
+ if (64786 == cluster_id) {
+ #ifdef PROTOCOL_CONTROLLER_NETWORK_MANAGEMENT_NETWORK_MANAGEMENT_STATE_ENUM_NAME_AVAILABLE
+ if (1 == attribute_id) {
+@@ -14700,6 +14920,21 @@ uint32_t get_enum_name_value(
+ #endif
+ }
+
++ if (64777 == cluster_id) {
++ #ifdef MULTILEVEL_SENSOR_SENSOR_VALUES_ENUM_NAME_AVAILABLE
++ if (0 == attribute_id) {
++ // FIXME: Some attributes don't work because multi-upper case names end up like this: multilevel_sensorsensor_values instead of this: multilevel_sensor_sensor_values
++ return multilevel_sensor_sensor_values_get_enum_value_number(name);
++ }
++ #endif
++ #ifdef MULTILEVEL_SENSOR_SENSOR_TYPE_ENUM_NAME_AVAILABLE
++ if (1 == attribute_id) {
++ // FIXME: Some attributes don't work because multi-upper case names end up like this: multilevel_sensorsensor_type instead of this: multilevel_sensor_sensor_type
++ return multilevel_sensor_sensor_type_get_enum_value_number(name);
++ }
++ #endif
++ }
++
+ if (64786 == cluster_id) {
+ #ifdef PROTOCOL_CONTROLLER_NETWORK_MANAGEMENT_NETWORK_MANAGEMENT_STATE_ENUM_NAME_AVAILABLE
+ if (1 == attribute_id) {
+@@ -15688,6 +15923,17 @@ uint32_t move_step_mode_get_enum_value_number_c(const char *str)
+ {
+ return move_step_mode_get_enum_value_number(std::string(str));
+ }
++char *multilevel_sensor_sensor_type_get_enum_value_name_c(
++ uint32_t value, char *result, size_t max_result_size)
++{
++ snprintf(result, max_result_size, "%s", multilevel_sensor_sensor_type_get_enum_value_name(value).c_str());
++ return result;
++}
++
++uint32_t multilevel_sensor_sensor_type_get_enum_value_number_c(const char *str)
++{
++ return multilevel_sensor_sensor_type_get_enum_value_number(std::string(str));
++}
+ char *nm_state_get_enum_value_name_c(
+ uint32_t value, char *result, size_t max_result_size)
+ {
+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 4d6e0f16c3..f7db295e9c 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
+@@ -2635,6 +2635,49 @@ void uic_mqtt_dotdot_configuration_parameters_publish_supported_generated_comman
+ }
+
+
++/**
++ * @brief Sends/Publishes a the SupportedGenerated commands for
++ * the MultilevelSensor cluster for a UNID/Endpoint
++ *
++ * Publication will be made at the following topic
++ * ucl/by-unid/UNID/epID/MultilevelSensor/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_multilevel_sensor_publish_supported_generated_commands(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint,
++ const uic_mqtt_dotdot_multilevel_sensor_supported_commands_t *command_list)
++{
++ std::string topic = "ucl/by-unid/" + std::string(unid);
++ topic += "/ep"+ std::to_string(endpoint);
++ topic += "/MultilevelSensor/SupportedGeneratedCommands";
++
++ // Assemble of vector of strings for the Supported Commands:
++ std::vector command_vector;
++ 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);
++
++}
++
++
+ /**
+ * @brief Sends/Publishes a the SupportedGenerated commands for
+ * the ProtocolController-NetworkManagement cluster for a UNID/Endpoint
+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 f3ec21da18..c1fe725721 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
+@@ -3653,6 +3653,7 @@ static void unset_all_callbacks()
+ uic_mqtt_dotdot_configuration_parameters_set_parameter_callback_clear();
+ uic_mqtt_dotdot_configuration_parameters_discover_parameter_range_callback_clear();
+ uic_mqtt_dotdot_clear_configuration_parameters_write_attributes_callbacks();
++ uic_mqtt_dotdot_clear_multilevel_sensor_write_attributes_callbacks();
+ uic_mqtt_dotdot_protocol_controller_network_management_write_callback_clear();
+ uic_mqtt_dotdot_clear_protocol_controller_network_management_write_attributes_callbacks();
+ uic_mqtt_dotdot_clear_descriptor_write_attributes_callbacks();
+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 2bf45a75f1..0c168c053a 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
+@@ -834,6 +834,10 @@ def DOTDOT_ATTRIBUTE_ID_NAME_AND_LOCATION_LOCATION 0xfd060001
+ // This represents the attributes in the DotDot ConfigurationParameters cluster
+ def DOTDOT_ATTRIBUTE_ID_CONFIGURATION_PARAMETERS_CONFIGURATION_PARAMETERS 0xfd070000
+
++// This represents the attributes in the DotDot MultilevelSensor cluster
++def DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_VALUES 0xfd090000
++def DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_TYPE 0xfd090001
++
+ // This represents the attributes in the DotDot AoXLocator cluster
+ def DOTDOT_ATTRIBUTE_ID_AOX_LOCATOR_REPORTING_MODE 0xfd100001
+ def DOTDOT_ATTRIBUTE_ID_AOX_LOCATOR_POSITION_AND_ORIENTATION_VALID 0xfd100002
+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 ceb159d2c2..b867ea5a05 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
+@@ -834,6 +834,10 @@ def zb_Location 0xfd060001
+ // This represents short CamelCase labels the attributes in the DotDot ConfigurationParameters cluster
+ def zb_ConfigurationParameters 0xfd070000
+
++// This represents short CamelCase labels the attributes in the DotDot MultilevelSensor cluster
++def zb_SensorValues 0xfd090000
++def zb_SensorType 0xfd090001
++
+ // This represents short CamelCase labels the attributes in the DotDot AoXLocator cluster
+ def zb_ReportingMode 0xfd100001
+ def zb_PositionAndOrientationValid 0xfd100002
+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 f99ee31747..e98230c88f 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
+@@ -75293,6 +75293,246 @@ bool dotdot_is_any_configuration_parameters_writable_attribute_supported(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint_id);
+
++////////////////////////////////////////////////////////////////////////////////
++// Start of cluster MultilevelSensor
++////////////////////////////////////////////////////////////////////////////////
++// MultilevelSensor SensorValues
++/**
++ * @brief Verifies if the DotDot MultilevelSensor - SensorValues is supported
++ * under a UNID/EndpoinID
++ *
++ * @param unid Node's UNID
++ * @param endpoint_id Endpoint ID
++ *
++ * @returns true if SensorValues is supported
++ * @returns false if SensorValues is not supported
++ */
++bool dotdot_is_supported_multilevel_sensor_sensor_values (
++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id);
++
++/**
++ * @brief Gets the DotDot MultilevelSensor - SensorValues 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 SensorValues attribute
++ */
++SensorValue dotdot_get_multilevel_sensor_sensor_values(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint_id,
++ attribute_store_node_value_state_t value_state);
++
++/**
++ * @brief Set the DotDot MultilevelSensor - SensorValues 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_sensor_values new value to set
++ * @returns sl_status_t SL_STATUS_OK on success
++ */
++sl_status_t dotdot_set_multilevel_sensor_sensor_values(
++ const dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint_id,
++ attribute_store_node_value_state_t value_state,
++ SensorValue new_sensor_values
++ );
++
++/**
++ * @brief Undefines the Reported value of the the DotDot MultilevelSensor - SensorValues
++ * 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_multilevel_sensor_sensor_values_undefine_reported(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint_id);
++
++/**
++ * @brief Undefines the Desired value of the DotDot
++ * MultilevelSensor - SensorValues 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_multilevel_sensor_sensor_values_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
++ * MultilevelSensor - SensorValues 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_multilevel_sensor_sensor_values_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
++ * MultilevelSensor - SensorValues 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_multilevel_sensor_sensor_values_is_desired_defined(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint_id);
++
++/**
++ * @brief Creates a DotDot MultilevelSensor - SensorValues 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_multilevel_sensor_sensor_values(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint_id);
++// MultilevelSensor SensorType
++/**
++ * @brief Verifies if the DotDot MultilevelSensor - SensorType is supported
++ * under a UNID/EndpoinID
++ *
++ * @param unid Node's UNID
++ * @param endpoint_id Endpoint ID
++ *
++ * @returns true if SensorType is supported
++ * @returns false if SensorType is not supported
++ */
++bool dotdot_is_supported_multilevel_sensor_sensor_type (
++ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id);
++
++/**
++ * @brief Gets the DotDot MultilevelSensor - SensorType 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 SensorType attribute
++ */
++uint8_t dotdot_get_multilevel_sensor_sensor_type(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint_id,
++ attribute_store_node_value_state_t value_state);
++
++/**
++ * @brief Set the DotDot MultilevelSensor - SensorType 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_sensor_type new value to set
++ * @returns sl_status_t SL_STATUS_OK on success
++ */
++sl_status_t dotdot_set_multilevel_sensor_sensor_type(
++ const dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint_id,
++ attribute_store_node_value_state_t value_state,
++ uint8_t new_sensor_type
++ );
++
++/**
++ * @brief Undefines the Reported value of the the DotDot MultilevelSensor - SensorType
++ * 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_multilevel_sensor_sensor_type_undefine_reported(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint_id);
++
++/**
++ * @brief Undefines the Desired value of the DotDot
++ * MultilevelSensor - SensorType 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_multilevel_sensor_sensor_type_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
++ * MultilevelSensor - SensorType 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_multilevel_sensor_sensor_type_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
++ * MultilevelSensor - SensorType 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_multilevel_sensor_sensor_type_is_desired_defined(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint_id);
++
++/**
++ * @brief Creates a DotDot MultilevelSensor - SensorType 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_multilevel_sensor_sensor_type(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint_id);
++
++/**
++ * @brief Checks if a UNID/Endpoint supports any attribute for the MultilevelSensor
++ * 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_multilevel_sensor_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
++ * MultilevelSensor 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_multilevel_sensor_writable_attribute_supported(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint_id);
++
+ ////////////////////////////////////////////////////////////////////////////////
+ // Start of cluster ProtocolController-NetworkManagement
+ ////////////////////////////////////////////////////////////////////////////////
+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 46668d1948..6150a9ae87 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
+@@ -769,6 +769,9 @@ DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_NAME_AND_LOCATION_NAME , 0xfd060000)
+ DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_NAME_AND_LOCATION_LOCATION , 0xfd060001)
+ // Attribute Defines for ConfigurationParameters
+ DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_CONFIGURATION_PARAMETERS_CONFIGURATION_PARAMETERS , 0xfd070000)
++// Attribute Defines for MultilevelSensor
++DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_VALUES , 0xfd090000)
++DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_TYPE , 0xfd090001)
+ // Attribute Defines for ProtocolController-NetworkManagement
+ DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_PROTOCOL_CONTROLLER_NETWORK_MANAGEMENT_NETWORK_MANAGEMENT_STATE , 0xfd120001)
+ // Attribute Defines for Descriptor
+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 8446b11a47..d208971476 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
+@@ -24477,6 +24477,235 @@ static void configuration_parameters_cluster_cluster_revision_callback(
+ }
+
+
++/**
++ * @brief Publishes the desired value of an updated attribute store node for
++ * the MultilevelSensor cluster.
++ * @param updated_node Updated attribute store node
++ * @param change Type of change applied
++ */
++static void multilevel_sensor_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);
++ // Skip attribute SensorValues because it is a struct,
++ // we typically don't save them as structs in the attribute store.
++ sl_log_debug(LOG_TAG,"Warning: Cannot publish desired value for attribute MultilevelSensor SensorValues. Structs are not supported");
++ if (type == DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_TYPE) {
++ uic_mqtt_dotdot_multilevel_sensor_sensor_type_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 MultilevelSensor cluster.
++ * @param updated_node Updated attribute store node
++ * @param change Type of change applied
++ */
++static void multilevel_sensor_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_MULTILEVEL_SENSOR_SENSOR_VALUES:
++ // clang-format on
++ sl_log_debug(LOG_TAG,
++ "Unretaining MultilevelSensor::SensorValues under topic %s",
++ base_topic.c_str());
++ // clang-format off
++ uic_mqtt_dotdot_multilevel_sensor_sensor_values_unretain(base_topic.c_str(), UCL_MQTT_PUBLISH_TYPE_ALL);
++ break;
++ case DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_TYPE:
++ // clang-format on
++ sl_log_debug(LOG_TAG,
++ "Unretaining MultilevelSensor::SensorType under topic %s",
++ base_topic.c_str());
++ // clang-format off
++ uic_mqtt_dotdot_multilevel_sensor_sensor_type_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);
++ // Skip attribute SensorValues because it is a struct,
++ // we typically don't save them as structs in the attribute store.
++ sl_log_debug(LOG_TAG,"Warning: Cannot publish reported value for attribute MultilevelSensor SensorValues. Structs are not supported");
++ if (type == DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_TYPE) {
++ uic_mqtt_dotdot_multilevel_sensor_sensor_type_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 multilevel_sensor_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 + "/MultilevelSensor/Attributes/ClusterRevision";
++ if (uic_mqtt_count_topics(cluster_revision_topic.c_str()) == 0) {
++ uic_mqtt_dotdot_multilevel_sensor_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_multilevel_sensor_attribute_supported(unid, endpoint_id)) {
++ base_topic += "/MultilevelSensor";
++ sl_log_debug(LOG_TAG, "No more attributes supported for MultilevelSensor 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());
++ }
++ }
++}
++
++
+ /**
+ * @brief Publishes the desired value of an updated attribute store node for
+ * the ProtocolController-NetworkManagement cluster.
+@@ -35755,6 +35984,34 @@ sl_status_t unify_dotdot_attribute_store_attribute_publisher_init()
+ configuration_parameters_cluster_cluster_revision_callback,
+ DOTDOT_ATTRIBUTE_ID_CONFIGURATION_PARAMETERS_CONFIGURATION_PARAMETERS);
+ //Desired attribute state
++ attribute_store_register_callback_by_type_and_state(
++ multilevel_sensor_cluster_publish_desired_value_callback,
++ DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_VALUES,
++ DESIRED_ATTRIBUTE);
++ //Reported attribute state
++ attribute_store_register_callback_by_type_and_state(
++ multilevel_sensor_cluster_publish_reported_value_callback,
++ DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_VALUES,
++ REPORTED_ATTRIBUTE);
++ //registering a callback when an attribute is created for publishing cluster revision
++ attribute_store_register_callback_by_type(
++ multilevel_sensor_cluster_cluster_revision_callback,
++ DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_VALUES);
++ //Desired attribute state
++ attribute_store_register_callback_by_type_and_state(
++ multilevel_sensor_cluster_publish_desired_value_callback,
++ DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_TYPE,
++ DESIRED_ATTRIBUTE);
++ //Reported attribute state
++ attribute_store_register_callback_by_type_and_state(
++ multilevel_sensor_cluster_publish_reported_value_callback,
++ DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_TYPE,
++ REPORTED_ATTRIBUTE);
++ //registering a callback when an attribute is created for publishing cluster revision
++ attribute_store_register_callback_by_type(
++ multilevel_sensor_cluster_cluster_revision_callback,
++ DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_TYPE);
++ //Desired attribute state
+ attribute_store_register_callback_by_type_and_state(
+ protocol_controller_network_management_cluster_publish_desired_value_callback,
+ DOTDOT_ATTRIBUTE_ID_PROTOCOL_CONTROLLER_NETWORK_MANAGEMENT_NETWORK_MANAGEMENT_STATE,
+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 8237315595..9774152fb6 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
+@@ -4325,6 +4325,41 @@ static sl_status_t uic_mqtt_dotdot_configuration_parameters_force_read_attribute
+ return SL_STATUS_OK;
+ }
+ ////////////////////////////////////////////////////////////////////////////////
++// Start of cluster MultilevelSensor
++////////////////////////////////////////////////////////////////////////////////
++static sl_status_t uic_mqtt_dotdot_multilevel_sensor_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_multilevel_sensor_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_multilevel_sensor_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.sensor_values) {
++ if (SL_STATUS_OK == dotdot_multilevel_sensor_sensor_values_undefine_reported(unid, endpoint_id)) {
++ sl_log_debug(LOG_TAG, "Undefined Reported value of MultilevelSensor::SensorValues under %s - Endpoint %d", unid, endpoint_id);
++ }
++ }
++ if (true == attribute_list.sensor_type) {
++ if (SL_STATUS_OK == dotdot_multilevel_sensor_sensor_type_undefine_reported(unid, endpoint_id)) {
++ sl_log_debug(LOG_TAG, "Undefined Reported value of MultilevelSensor::SensorType under %s - Endpoint %d", unid, endpoint_id);
++ }
++ }
++ return SL_STATUS_OK;
++}
++////////////////////////////////////////////////////////////////////////////////
+ // Start of cluster Descriptor
+ ////////////////////////////////////////////////////////////////////////////////
+ static sl_status_t uic_mqtt_dotdot_descriptor_force_read_attributes_callback (
+@@ -4657,6 +4692,8 @@ sl_status_t
+
+ uic_mqtt_dotdot_set_configuration_parameters_force_read_attributes_callback(&uic_mqtt_dotdot_configuration_parameters_force_read_attributes_callback);
+
++ uic_mqtt_dotdot_set_multilevel_sensor_force_read_attributes_callback(&uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback);
++
+
+ uic_mqtt_dotdot_set_descriptor_force_read_attributes_callback(&uic_mqtt_dotdot_descriptor_force_read_attributes_callback);
+
+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 bbcc3f7fad..95fffa41fc 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
+@@ -81051,6 +81051,255 @@ bool dotdot_is_any_configuration_parameters_writable_attribute_supported(
+ const dotdot_endpoint_id_t endpoint_id) {
+
+
++ return false;
++}
++////////////////////////////////////////////////////////////////////////////////
++// Start of cluster MultilevelSensor
++////////////////////////////////////////////////////////////////////////////////
++bool dotdot_is_supported_multilevel_sensor_sensor_values(
++ 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_MULTILEVEL_SENSOR_SENSOR_VALUES);
++ return attribute_store_node_exists(node);
++}
++
++SensorValue dotdot_get_multilevel_sensor_sensor_values(
++ 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_MULTILEVEL_SENSOR_SENSOR_VALUES);
++
++ SensorValue result = {};
++ attribute_store_read_value(node,
++ value_state,
++ (uint8_t *)&result,
++ sizeof(result));
++ return result;
++}
++
++sl_status_t dotdot_set_multilevel_sensor_sensor_values(
++ const dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint_id,
++ attribute_store_node_value_state_t value_state,
++ SensorValue new_sensor_values
++ )
++{
++ 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_MULTILEVEL_SENSOR_SENSOR_VALUES);
++
++ // Skip attribute SensorValues because it is a struct,
++ // we typically don't save them as structs in the attribute store.
++ sl_log_error(LOG_TAG, "Error, skipping to change the desired value of SensorValues, Attribute %d, "
++ "because it is a complicated type (struct: SensorValue). "
++ "Please change the code to do this manually.", node);
++ return SL_STATUS_FAIL;
++}
++
++sl_status_t dotdot_multilevel_sensor_sensor_values_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_MULTILEVEL_SENSOR_SENSOR_VALUES);
++ attribute_store_undefine_reported(node);
++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL;
++}
++
++sl_status_t dotdot_multilevel_sensor_sensor_values_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_MULTILEVEL_SENSOR_SENSOR_VALUES);
++ attribute_store_undefine_desired(node);
++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL;
++}
++
++
++bool dotdot_multilevel_sensor_sensor_values_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_MULTILEVEL_SENSOR_SENSOR_VALUES);
++ return attribute_store_is_reported_defined(node);
++}
++
++bool dotdot_multilevel_sensor_sensor_values_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_MULTILEVEL_SENSOR_SENSOR_VALUES);
++ return attribute_store_is_desired_defined(node);
++}
++
++sl_status_t dotdot_create_multilevel_sensor_sensor_values(
++ 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_MULTILEVEL_SENSOR_SENSOR_VALUES);
++
++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL;
++}
++bool dotdot_is_supported_multilevel_sensor_sensor_type(
++ 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_MULTILEVEL_SENSOR_SENSOR_TYPE);
++ return attribute_store_node_exists(node);
++}
++
++uint8_t dotdot_get_multilevel_sensor_sensor_type(
++ 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_MULTILEVEL_SENSOR_SENSOR_TYPE);
++
++ uint8_t result = {};
++ attribute_store_read_value(node,
++ value_state,
++ (uint8_t *)&result,
++ sizeof(result));
++ return result;
++}
++
++sl_status_t dotdot_set_multilevel_sensor_sensor_type(
++ const dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint_id,
++ attribute_store_node_value_state_t value_state,
++ uint8_t new_sensor_type
++ )
++{
++ 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_MULTILEVEL_SENSOR_SENSOR_TYPE);
++
++ return attribute_store_set_node_attribute_value(node,
++ value_state,
++ (uint8_t *)&new_sensor_type,
++ sizeof(uint8_t));
++ }
++
++sl_status_t dotdot_multilevel_sensor_sensor_type_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_MULTILEVEL_SENSOR_SENSOR_TYPE);
++ attribute_store_undefine_reported(node);
++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL;
++}
++
++sl_status_t dotdot_multilevel_sensor_sensor_type_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_MULTILEVEL_SENSOR_SENSOR_TYPE);
++ attribute_store_undefine_desired(node);
++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL;
++}
++
++
++bool dotdot_multilevel_sensor_sensor_type_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_MULTILEVEL_SENSOR_SENSOR_TYPE);
++ return attribute_store_is_reported_defined(node);
++}
++
++bool dotdot_multilevel_sensor_sensor_type_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_MULTILEVEL_SENSOR_SENSOR_TYPE);
++ return attribute_store_is_desired_defined(node);
++}
++
++sl_status_t dotdot_create_multilevel_sensor_sensor_type(
++ 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_MULTILEVEL_SENSOR_SENSOR_TYPE);
++
++ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL;
++}
++
++bool dotdot_is_any_multilevel_sensor_attribute_supported(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint_id) {
++
++ if (true == dotdot_is_supported_multilevel_sensor_sensor_values(unid, endpoint_id)) {
++ return true;
++ }
++ if (true == dotdot_is_supported_multilevel_sensor_sensor_type(unid, endpoint_id)) {
++ return true;
++ }
++
++ return false;
++}
++
++bool dotdot_is_any_multilevel_sensor_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 a321941cf6..bbc56dd97a 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
+@@ -16807,6 +16807,54 @@ sl_status_t unify_dotdot_attribute_store_registration_init()
+ // clang-format off
+ // clang-format on
+
++ {
++ // SensorValue // SensorValue // SensorValue
++ std::string attribute_type_string = "SensorValue";
++ attribute_store_storage_type_t storage_type = UNKNOWN_STORAGE_TYPE;
++
++ // clang-format off
++ storage_type = BYTE_ARRAY_STORAGE_TYPE;
++
++ if (storage_type == UNKNOWN_STORAGE_TYPE) {
++ sl_log_warning(LOG_TAG,
++ "Unkown storage type for ZCL MultilevelSensor SensorValues, "
++ "type: SensorValue // SensorValue");
++ }
++
++ status |= attribute_store_register_type(
++ DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_VALUES,
++ "ZCL MultilevelSensor SensorValues",
++ ATTRIBUTE_STORE_INVALID_ATTRIBUTE_TYPE,
++ storage_type);
++ }
++
++ // clang-format off
++ // clang-format on
++
++ {
++ // enum8 // enum8 // 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 MultilevelSensor SensorType, "
++ "type: enum8 // uint8_t");
++ }
++
++ status |= attribute_store_register_type(
++ DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_TYPE,
++ "ZCL MultilevelSensor SensorType",
++ ATTRIBUTE_STORE_INVALID_ATTRIBUTE_TYPE,
++ storage_type);
++ }
++
++ // clang-format off
++ // clang-format on
++
+ {
+ // NetworkManagementState // NetworkManagementState // NetworkManagementState
+ std::string attribute_type_string = "NetworkManagementState";
+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 799780c184..0eb24791b3 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
+@@ -2398,6 +2398,36 @@ static sl_status_t configuration_parameters_cluster_write_attributes_callback(
+ return SL_STATUS_OK;
+ }
+ ////////////////////////////////////////////////////////////////////////////////
++// Start of cluster MultilevelSensor
++////////////////////////////////////////////////////////////////////////////////
++// WriteAttribute Callbacks multilevel_sensor
++static sl_status_t multilevel_sensor_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_multilevel_sensor_state_t attributes,
++ uic_mqtt_dotdot_multilevel_sensor_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_multilevel_sensor_writable_attribute_supported(unid, endpoint_id) ?
++ SL_STATUS_OK : SL_STATUS_FAIL;
++ } else {
++ return SL_STATUS_FAIL;
++ }
++ }
++
++ sl_log_debug(LOG_TAG,
++ "multilevel_sensor: Incoming WriteAttributes command for %s, endpoint %d.\n",
++ unid,
++ endpoint_id);
++ return SL_STATUS_OK;
++}
++////////////////////////////////////////////////////////////////////////////////
+ // Start of cluster ProtocolController-NetworkManagement
+ ////////////////////////////////////////////////////////////////////////////////
+ // WriteAttribute Callbacks protocol_controller_network_management
+@@ -2710,6 +2740,9 @@ sl_status_t
+ uic_mqtt_dotdot_set_configuration_parameters_write_attributes_callback(
+ &configuration_parameters_cluster_write_attributes_callback);
+
++ uic_mqtt_dotdot_set_multilevel_sensor_write_attributes_callback(
++ &multilevel_sensor_cluster_write_attributes_callback);
++
+ uic_mqtt_dotdot_set_protocol_controller_network_management_write_attributes_callback(
+ &protocol_controller_network_management_cluster_write_attributes_callback);
+
+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 d43942b157..a5dd3ae27f 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
+@@ -1260,6 +1260,16 @@ static uic_mqtt_dotdot_configuration_parameters_discover_parameter_range_callbac
+ uic_mqtt_dotdot_configuration_parameters_discover_parameter_range_callback_t get_uic_mqtt_dotdot_configuration_parameters_discover_parameter_range_callback(){
+ return test_uic_mqtt_dotdot_configuration_parameters_discover_parameter_range_callback;
+ }
++static uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback_t test_uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback = NULL;
++static uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback_t test_uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback = NULL;
++
++uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback_t get_uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback(){
++ return test_uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback;
++}
++uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback_t get_uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback(){
++ return test_uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback;
++}
++
+ static uic_mqtt_dotdot_protocol_controller_network_management_force_read_attributes_callback_t test_uic_mqtt_dotdot_protocol_controller_network_management_force_read_attributes_callback = NULL;
+ static uic_mqtt_dotdot_protocol_controller_network_management_write_attributes_callback_t test_uic_mqtt_dotdot_protocol_controller_network_management_write_attributes_callback = NULL;
+
+@@ -2856,6 +2866,16 @@ void uic_mqtt_dotdot_configuration_parameters_discover_parameter_range_callback_
+ {
+ test_uic_mqtt_dotdot_configuration_parameters_discover_parameter_range_callback = callback;
+ }
++void set_uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback_stub(
++ const uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback_t callback, int cmock_num_calls)
++{
++ test_uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback = callback;
++}
++void set_uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback_stub(
++ const uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback_t callback, int cmock_num_calls)
++{
++ test_uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback = callback;
++}
+ void set_uic_mqtt_dotdot_protocol_controller_network_management_force_read_attributes_callback_stub(
+ const uic_mqtt_dotdot_protocol_controller_network_management_force_read_attributes_callback_t callback, int cmock_num_calls)
+ {
+@@ -3818,6 +3838,12 @@ void setUp()
+ test_uic_mqtt_dotdot_configuration_parameters_discover_parameter_range_callback = NULL;
+ uic_mqtt_dotdot_configuration_parameters_discover_parameter_range_callback_set_Stub(
+ &uic_mqtt_dotdot_configuration_parameters_discover_parameter_range_callback_set_stub);
++ test_uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback = NULL;
++ uic_mqtt_dotdot_set_multilevel_sensor_force_read_attributes_callback_Stub(
++ &set_uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback_stub);
++ test_uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback = NULL;
++ uic_mqtt_dotdot_set_multilevel_sensor_write_attributes_callback_Stub(
++ &set_uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback_stub);
+ test_uic_mqtt_dotdot_protocol_controller_network_management_force_read_attributes_callback = NULL;
+ uic_mqtt_dotdot_set_protocol_controller_network_management_force_read_attributes_callback_Stub(
+ &set_uic_mqtt_dotdot_protocol_controller_network_management_force_read_attributes_callback_stub);
+@@ -4604,6 +4630,8 @@ void test_automatic_deduction_of_supported_commands()
+ TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_name_and_location_name(expected_unid,expected_endpoint_id) );
+ TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_name_and_location_location(expected_unid,expected_endpoint_id) );
+ TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_configuration_parameters_configuration_parameters(expected_unid,expected_endpoint_id) );
++ TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_multilevel_sensor_sensor_values(expected_unid,expected_endpoint_id) );
++ TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_multilevel_sensor_sensor_type(expected_unid,expected_endpoint_id) );
+ TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_protocol_controller_network_management_network_management_state(expected_unid,expected_endpoint_id) );
+ TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_descriptor_device_type_list(expected_unid,expected_endpoint_id) );
+ TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_unify_fan_control_z_wave_fan_mode(expected_unid,expected_endpoint_id) );
+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 73c36434ca..35ada30800 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
+@@ -769,6 +769,10 @@
+ uic_mqtt_dotdot_configuration_parameters_discover_parameter_range_callback_t get_uic_mqtt_dotdot_configuration_parameters_discover_parameter_range_callback();
+
+
++ uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback_t get_uic_mqtt_dotdot_multilevel_sensor_force_read_attributes_callback();
++ uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback_t get_uic_mqtt_dotdot_multilevel_sensor_write_attributes_callback();
++
++
+ uic_mqtt_dotdot_protocol_controller_network_management_force_read_attributes_callback_t get_uic_mqtt_dotdot_protocol_controller_network_management_force_read_attributes_callback();
+ uic_mqtt_dotdot_protocol_controller_network_management_write_attributes_callback_t get_uic_mqtt_dotdot_protocol_controller_network_management_write_attributes_callback();
+
+--
+2.39.5
+
diff --git a/patches/UnifySDK/0010-UIC-3273-Generated-files-for-Unify_MultilevelSensor-.patch b/patches/UnifySDK/0010-UIC-3273-Generated-files-for-Unify_MultilevelSensor-.patch
new file mode 100644
index 000000000..bf261c225
--- /dev/null
+++ b/patches/UnifySDK/0010-UIC-3273-Generated-files-for-Unify_MultilevelSensor-.patch
@@ -0,0 +1,101 @@
+From 6bb1911c76658081391ac3bd8c268c374e3617f0 Mon Sep 17 00:00:00 2001
+From: Philippe Coval
+Date: Tue, 16 Sep 2025 10:58:38 +0200
+Subject: [PATCH] UIC-3273: Generated files for Unify_MultilevelSensor using
+ latest zap
+
+Relate-to: https://github.com/project-chip/zap/releases/download/v2025.07.24/zap-linux-x64.deb
+Signed-off-by: Philippe Coval
+---
+ .../src/eed_attribute_store_clusters.c | 8 +++++
+ .../src/eed_dotdot_create_clusters.cpp | 34 +++++++++++++++++++
+ 2 files changed, 42 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 8780c887c8..981d5e7ef4 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
+@@ -2687,6 +2687,14 @@ sl_status_t eed_attribute_store_clusters_init()
+ &on_zcl_desired_value_update,
+ DOTDOT_ATTRIBUTE_ID_CONFIGURATION_PARAMETERS_CONFIGURATION_PARAMETERS,
+ DESIRED_ATTRIBUTE);
++ attribute_store_register_callback_by_type_and_state(
++ &on_zcl_desired_value_update,
++ DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_VALUES,
++ DESIRED_ATTRIBUTE);
++ attribute_store_register_callback_by_type_and_state(
++ &on_zcl_desired_value_update,
++ DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_TYPE,
++ DESIRED_ATTRIBUTE);
+ attribute_store_register_callback_by_type_and_state(
+ &on_zcl_desired_value_update,
+ DOTDOT_ATTRIBUTE_ID_DESCRIPTOR_DEVICE_TYPE_LIST,
+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 8230ced6c8..0a74dd6e3e 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
+@@ -3990,6 +3990,22 @@ void dotdot_create_configuration_parameters_wrapper(const dotdot_unid_t unid, co
+
+ }
+
++void dotdot_create_multilevel_sensor_wrapper(const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id){
++ // Create and set a default value if undefined.
++ dotdot_create_multilevel_sensor_sensor_values(unid,endpoint_id);
++ if (false == dotdot_multilevel_sensor_sensor_values_is_reported_defined(unid,endpoint_id)){
++ SensorValue value = {};
++ dotdot_set_multilevel_sensor_sensor_values(unid,endpoint_id,REPORTED_ATTRIBUTE, value);
++ }
++
++ // Create and set a default value if undefined.
++ dotdot_create_multilevel_sensor_sensor_type(unid,endpoint_id);
++ if (false == dotdot_multilevel_sensor_sensor_type_is_reported_defined(unid,endpoint_id)){
++ dotdot_set_multilevel_sensor_sensor_type(unid,endpoint_id,REPORTED_ATTRIBUTE, static_cast(0));
++ }
++
++}
++
+ void dotdot_create_descriptor_wrapper(const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id){
+ // Create and set a default value if undefined.
+ dotdot_create_descriptor_device_type_list(unid,endpoint_id);
+@@ -6515,6 +6531,22 @@ void dotdot_unretain_configuration_parameters_wrapper(const dotdot_unid_t unid,
+ uic_mqtt_dotdot_configuration_parameters_publish_empty_supported_commands(unid, endpoint_id);
+ }
+
++void dotdot_unretain_multilevel_sensor_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_multilevel_sensor_sensor_values_unretain(base_topic,UCL_MQTT_PUBLISH_TYPE_ALL);
++ ep_node.child_by_type(DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_VALUES).delete_node();
++
++ uic_mqtt_dotdot_multilevel_sensor_sensor_type_unretain(base_topic,UCL_MQTT_PUBLISH_TYPE_ALL);
++ ep_node.child_by_type(DOTDOT_ATTRIBUTE_ID_MULTILEVEL_SENSOR_SENSOR_TYPE).delete_node();
++
++
++ uic_mqtt_dotdot_multilevel_sensor_unretain_cluster_revision(base_topic);
++ uic_mqtt_dotdot_multilevel_sensor_publish_empty_supported_commands(unid, endpoint_id);
++}
++
+ void dotdot_unretain_descriptor_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);
+@@ -6707,6 +6739,7 @@ std::map CreateClusterMap = {
+ { "Binding", dotdot_create_binding_wrapper },
+ { "NameAndLocation", dotdot_create_name_and_location_wrapper },
+ { "ConfigurationParameters", dotdot_create_configuration_parameters_wrapper },
++{ "MultilevelSensor", dotdot_create_multilevel_sensor_wrapper },
+ { "Descriptor", dotdot_create_descriptor_wrapper },
+ { "UnifyFanControl", dotdot_create_unify_fan_control_wrapper },
+ { "UnifyThermostat", dotdot_create_unify_thermostat_wrapper },
+@@ -6758,6 +6791,7 @@ std::map CreateUnretainMap = {
+ { "Binding", dotdot_unretain_binding_wrapper },
+ { "NameAndLocation", dotdot_unretain_name_and_location_wrapper },
+ { "ConfigurationParameters", dotdot_unretain_configuration_parameters_wrapper },
++{ "MultilevelSensor", dotdot_unretain_multilevel_sensor_wrapper },
+ { "Descriptor", dotdot_unretain_descriptor_wrapper },
+ { "UnifyFanControl", dotdot_unretain_unify_fan_control_wrapper },
+ { "UnifyThermostat", dotdot_unretain_unify_thermostat_wrapper },
+--
+2.39.5
+
diff --git a/patches/UnifySDK/0011-UIC-3438-dot-dot-mapper-setup-for-schedule-entry-loc.patch b/patches/UnifySDK/0011-UIC-3438-dot-dot-mapper-setup-for-schedule-entry-loc.patch
new file mode 100644
index 000000000..9d6221d30
--- /dev/null
+++ b/patches/UnifySDK/0011-UIC-3438-dot-dot-mapper-setup-for-schedule-entry-loc.patch
@@ -0,0 +1,302 @@
+From 9660b5676577440cc94dfb83f73b30dc117744d4 Mon Sep 17 00:00:00 2001
+From: Thirupathi S
+Date: Tue, 17 Sep 2024 13:13:38 +0000
+Subject: [PATCH] UIC-3438: dot dot mapper setup for schedule entry lock CC
+
+Merge in UIC/uic from feature/UIC-3438-dotdot-mapper-Setup-Schedule-Entry-Lock-CC to feature/UIC-3271-Schedule-Entry-Lock-CC
+---
+ .../dotdot-xml/Unify_ScheduleEntryLock.xml | 282 ++++++++++++++++++
+ 1 file changed, 282 insertions(+)
+ create mode 100644 components/uic_dotdot/dotdot-xml/Unify_ScheduleEntryLock.xml
+
+diff --git a/components/uic_dotdot/dotdot-xml/Unify_ScheduleEntryLock.xml b/components/uic_dotdot/dotdot-xml/Unify_ScheduleEntryLock.xml
+new file mode 100644
+index 0000000000..8d37540615
+--- /dev/null
++++ b/components/uic_dotdot/dotdot-xml/Unify_ScheduleEntryLock.xml
+@@ -0,0 +1,282 @@
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+--
+2.39.5
+
diff --git a/patches/UnifySDK/0012-UIC-3494-dotdot-command-handlers-in-ZPC-ScheduleEntr.patch b/patches/UnifySDK/0012-UIC-3494-dotdot-command-handlers-in-ZPC-ScheduleEntr.patch
new file mode 100644
index 000000000..4fee525fd
--- /dev/null
+++ b/patches/UnifySDK/0012-UIC-3494-dotdot-command-handlers-in-ZPC-ScheduleEntr.patch
@@ -0,0 +1,9790 @@
+From 0bf584e7c1a862d0cace11019900f0b29c9d9bdb Mon Sep 17 00:00:00 2001
+From: Thirupathi S
+Date: Wed, 25 Sep 2024 13:15:55 +0000
+Subject: [PATCH] UIC-3494:dotdot command handlers in ZPC ScheduleEntryLock CC
+
+Merge in UIC/uic from feature/UIC-3494-dotdot-command-handlers-in-ZPC-ScheduleEntryLock-CC to feature/UIC-3271-Schedule-Entry-Lock-CC
+---
+ .../cluster-types/cluster-type-attributes.ts | 245 ++
+ .../src/cluster-types/cluster-types.ts | 1 +
+ .../src/cluster-types/supported-clusters.js | 1 +
+ .../dev_ui/dev_gui/zap/addon-helper.js | 3 +-
+ .../dotdot-xml/Unify_ScheduleEntryLock.xml | 47 +-
+ components/uic_dotdot/dotdot-xml/library.xml | 5 +-
+ .../zap-generated/include/dotdot_mqtt.h | 629 +++++
+ .../include/dotdot_mqtt_attributes.h | 113 +
+ .../include/dotdot_mqtt_generated_commands.h | 85 +
+ .../include/dotdot_mqtt_group_commands.h | 65 +
+ .../include/dotdot_mqtt_send_commands.h | 117 +
+ ...dotdot_mqtt_supported_generated_commands.h | 31 +
+ .../zap-generated/src/dotdot_mqtt.cpp | 2017 ++++++++++++++++-
+ .../zap-generated/src/dotdot_mqtt.hpp | 85 +
+ .../src/dotdot_mqtt_attributes.cpp | 707 ++++++
+ .../src/dotdot_mqtt_command_helpers.cpp | 462 ++++
+ .../src/dotdot_mqtt_command_helpers.hpp | 142 ++
+ .../src/dotdot_mqtt_generated_commands.cpp | 228 ++
+ .../src/dotdot_mqtt_group_commands.cpp | 528 +++++
+ .../zap-generated/src/dotdot_mqtt_helpers.cpp | 102 +
+ .../src/dotdot_mqtt_send_commands.cpp | 222 ++
+ ...tdot_mqtt_supported_generated_commands.cpp | 52 +
+ .../test/dotdot_mqtt_test.include | 98 +
+ .../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 | 955 ++++++++
+ ...fy_dotdot_attribute_store_registration.cpp | 192 ++
+ ...store_write_attributes_command_callbacks.c | 65 +
+ .../test/unify_dotdot_attribute_store_test.c | 320 +++
+ .../test/unify_dotdot_attribute_store_test.h | 13 +
+ 34 files changed, 8900 insertions(+), 83 deletions(-)
+
+diff --git a/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/cluster-type-attributes.ts b/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/cluster-type-attributes.ts
+index 2fa7a4c728..c8f421a395 100644
+--- a/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/cluster-type-attributes.ts
++++ b/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/cluster-type-attributes.ts
+@@ -15352,4 +15352,249 @@ export let ClusterTypeAttrs: any = {
+ ]
+ }
+ },
++ UnifyScheduleEntryLock: {
++ server:{
++ attributes: [
++ {
++ id: 1,
++ name: "SlotsWeekDay",
++ type: "number",
++ max: 255,
++ min: 0,
++ required: true,
++ reportRequired: false,
++ sceneRequired: false,
++ writable: true,
++ isArray: false,
++ },
++ {
++ id: 2,
++ name: "SlotsYearDay",
++ type: "number",
++ max: 255,
++ min: 0,
++ required: true,
++ reportRequired: false,
++ sceneRequired: false,
++ writable: true,
++ isArray: false,
++ },
++ {
++ id: 3,
++ name: "SignTZO",
++ type: "number",
++ required: true,
++ reportRequired: false,
++ sceneRequired: false,
++ writable: true,
++ isArray: false,
++ },
++ {
++ id: 4,
++ name: "HourTZO",
++ type: "number",
++ required: true,
++ reportRequired: false,
++ sceneRequired: false,
++ writable: true,
++ isArray: false,
++ },
++ {
++ id: 5,
++ name: "MinuteTZO",
++ type: "number",
++ required: true,
++ reportRequired: false,
++ sceneRequired: false,
++ writable: true,
++ isArray: false,
++ },
++ {
++ id: 6,
++ name: "DSTOffsetSign",
++ type: "number",
++ required: true,
++ reportRequired: false,
++ sceneRequired: false,
++ writable: true,
++ isArray: false,
++ },
++ {
++ id: 7,
++ name: "DSTOffsetMinute",
++ type: "number",
++ required: true,
++ reportRequired: false,
++ sceneRequired: false,
++ writable: true,
++ isArray: false,
++ },
++ {
++ id: 8,
++ name: "NumberOfSlotsDailyRepeating",
++ type: "number",
++ max: 255,
++ min: 0,
++ required: true,
++ reportRequired: false,
++ sceneRequired: false,
++ writable: true,
++ isArray: false,
++ }
++ ],
++ commands: [
++ {
++ id: 1,
++ name: "ScheduleEntryLockWeekDayReport",
++ required: true,
++ fields: [
++ {
++ name: "UserIdentifier",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "ScheduleSlotID",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "DayOfWeek",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "StartHour",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "StartMinute",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "StopHour",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "StopMinute",
++ type: "number",
++ isArray: false,
++ }
++ ]
++ },
++ {
++ id: 2,
++ name: "ScheduleEntryLockYearDayReport",
++ required: true,
++ fields: [
++ {
++ name: "SetAction",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "UserIdentifier",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "ScheduleSlotID",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "StartYear",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "StartDay",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "StartHour",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "StartMinute",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "StopYear",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "StopDay",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "StopHour",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "StopMinute",
++ type: "number",
++ isArray: false,
++ }
++ ]
++ },
++ {
++ id: 3,
++ name: "ScheduleEntryLockDailyRepeatingReport",
++ required: true,
++ fields: [
++ {
++ name: "SetAction",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "UserIdentifier",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "ScheduleSlotID",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "WeekDayBitmask",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "StartHour",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "StartMinute",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "DurationHour",
++ type: "number",
++ isArray: false,
++ },
++ {
++ name: "DurationMinute",
++ type: "number",
++ isArray: false,
++ }
++ ]
++ }
++ ]
++ }
++ },
+ }
+diff --git a/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/cluster-types.ts b/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/cluster-types.ts
+index 192c0f68f9..b420ab28f5 100644
+--- a/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/cluster-types.ts
++++ b/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/cluster-types.ts
+@@ -29,6 +29,7 @@ export enum ClusterTypes {
+ SoilMoisture = "SoilMoisture",
+ TemperatureMeasurement = "TemperatureMeasurement",
+ Thermostat = "Thermostat",
++ UnifyScheduleEntryLock = "UnifyScheduleEntryLock",
+ WindSpeedMeasurement = "WindSpeedMeasurement",
+ WindowCovering = "WindowCovering"
+ }
+diff --git a/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/supported-clusters.js b/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/supported-clusters.js
+index e19a8e938b..3fdf6d4432 100644
+--- a/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/supported-clusters.js
++++ b/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/supported-clusters.js
+@@ -32,6 +32,7 @@ const SupportedClusters = {
+ SoilMoisture: "SoilMoisture",
+ TemperatureMeasurement: "TemperatureMeasurement",
+ Thermostat: "Thermostat",
++ UnifyScheduleEntryLock: "UnifyScheduleEntryLock",
+ WindSpeedMeasurement: "WindSpeedMeasurement",
+ WindowCovering: "WindowCovering"
+ }
+diff --git a/applications/dev_ui/dev_gui/zap/addon-helper.js b/applications/dev_ui/dev_gui/zap/addon-helper.js
+index aa013c9f1a..1af98954be 100644
+--- a/applications/dev_ui/dev_gui/zap/addon-helper.js
++++ b/applications/dev_ui/dev_gui/zap/addon-helper.js
+@@ -31,6 +31,7 @@ const supportedClusters = [
+ "SystemMetrics",
+ "TemperatureMeasurement",
+ "Thermostat",
++ "UnifyScheduleEntryLock",
+ "WindSpeedMeasurement",
+ "WindowCovering"
+ ];
+@@ -272,4 +273,4 @@ exports.getClusterName = getClusterName
+ exports.isStruct = isStruct
+ exports.isArray = isArray
+ exports.getEnum = getEnum
+-exports.getBitmap = getBitmap
+\ No newline at end of file
++exports.getBitmap = getBitmap
+diff --git a/components/uic_dotdot/dotdot-xml/Unify_ScheduleEntryLock.xml b/components/uic_dotdot/dotdot-xml/Unify_ScheduleEntryLock.xml
+index 8d37540615..8b9f0685d6 100644
+--- a/components/uic_dotdot/dotdot-xml/Unify_ScheduleEntryLock.xml
++++ b/components/uic_dotdot/dotdot-xml/Unify_ScheduleEntryLock.xml
+@@ -8,32 +8,29 @@
+
+
+
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
++
++
++
++
++
++
++
++
++
++
+
+-
++
+
+
+
+
+
+-
++
+
+
+
+
+-
++
+
+
+
+@@ -65,13 +62,13 @@
+
+
+
+-
++
+
+
+
+
+
+-
++
+
+
+
+@@ -118,13 +115,13 @@
+
+
+
+-
++
+
+
+
+
+
+-
++
+
+
+
+@@ -156,7 +153,7 @@
+
+
+
+-
++
+
+
+
+@@ -167,7 +164,7 @@
+
+
+
+-
++
+
+
+
+@@ -198,9 +195,8 @@
+
+
+
+-
++
+
+-
+
+
+
+@@ -245,9 +241,8 @@
+
+
+
+-
++
+
+-
+
+
+
+diff --git a/components/uic_dotdot/dotdot-xml/library.xml b/components/uic_dotdot/dotdot-xml/library.xml
+index deec70c822..2fdb5c5778 100644
+--- a/components/uic_dotdot/dotdot-xml/library.xml
++++ b/components/uic_dotdot/dotdot-xml/library.xml
+@@ -208,7 +208,7 @@ applicable to this document can be found in the LICENSE.md file.
+
+
+
+-
++
+
+
+
+@@ -502,4 +502,5 @@ applicable to this document can be found in the LICENSE.md file.
+
+
+
+-
+\ No newline at end of file
++
++
+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 7606ec4c85..0a57bcf5ad 100644
+--- a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt.h
++++ b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt.h
+@@ -40139,6 +40139,635 @@ void uic_mqtt_dotdot_unify_thermostat_publish_supported_commands(
+ void uic_mqtt_dotdot_unify_thermostat_publish_empty_supported_commands(
+ const dotdot_unid_t unid
+ ,dotdot_endpoint_id_t endpoint);
++// Callback types used by the unify_schedule_entry_lock cluster
++typedef sl_status_t (*uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_t)(
++ dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint,
++ uic_mqtt_dotdot_callback_call_type_t call_type,
++ uint8_t user_identifier,
++
++ uint8_t schedule_slotid,
++
++ uint8_t day_of_week,
++
++ uint8_t start_hour,
++
++ uint8_t start_minute,
++
++ uint8_t stop_hour,
++
++ uint8_t stop_minute
++
++);
++typedef sl_status_t (*uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_t)(
++ dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint,
++ uic_mqtt_dotdot_callback_call_type_t call_type,
++ uint8_t set_action,
++
++ uint8_t user_identifier,
++
++ uint8_t schedule_slotid,
++
++ uint8_t start_year,
++
++ uint8_t start_day,
++
++ uint8_t start_hour,
++
++ uint8_t start_minute,
++
++ uint8_t stop_year,
++
++ uint8_t stop_day,
++
++ uint8_t stop_hour,
++
++ uint8_t stop_minute
++
++);
++typedef sl_status_t (*uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_t)(
++ dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint,
++ uic_mqtt_dotdot_callback_call_type_t call_type,
++ uint8_t set_action,
++
++ uint8_t user_identifier,
++
++ uint8_t schedule_slotid,
++
++ uint8_t week_day_bitmask,
++
++ uint8_t start_hour,
++
++ uint8_t start_minute,
++
++ uint8_t duration_hour,
++
++ uint8_t duration_minute
++
++);
++
++typedef struct {
++ uint8_t slots_week_day;
++ uint8_t slots_year_day;
++ uint8_t signtzo;
++ uint8_t hourtzo;
++ uint8_t minutetzo;
++ uint8_t dst_offset_sign;
++ uint8_t dst_offset_minute;
++ uint8_t number_of_slots_daily_repeating;
++} uic_mqtt_dotdot_unify_schedule_entry_lock_state_t;
++
++typedef struct {
++ bool slots_week_day;
++ bool slots_year_day;
++ bool signtzo;
++ bool hourtzo;
++ bool minutetzo;
++ bool dst_offset_sign;
++ bool dst_offset_minute;
++ bool number_of_slots_daily_repeating;
++} uic_mqtt_dotdot_unify_schedule_entry_lock_updated_state_t;
++
++typedef sl_status_t (*uic_mqtt_dotdot_unify_schedule_entry_lock_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_schedule_entry_lock_state_t,
++ uic_mqtt_dotdot_unify_schedule_entry_lock_updated_state_t
++);
++
++typedef sl_status_t (*uic_mqtt_dotdot_unify_schedule_entry_lock_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_schedule_entry_lock_updated_state_t
++);
++
++
++/**
++ * @brief Command fields for UnifyScheduleEntryLock/ScheduleEntryLockWeekDayReport
++ */
++typedef struct {
++ uint8_t user_identifier;
++
++ uint8_t schedule_slotid;
++
++ uint8_t day_of_week;
++
++ uint8_t start_hour;
++
++ uint8_t start_minute;
++
++ uint8_t stop_hour;
++
++ uint8_t stop_minute;
++} uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_week_day_report_fields_t;
++
++/**
++ * @brief Command fields for UnifyScheduleEntryLock/ScheduleEntryLockYearDayReport
++ */
++typedef struct {
++ uint8_t set_action;
++
++ uint8_t user_identifier;
++
++ uint8_t schedule_slotid;
++
++ uint8_t start_year;
++
++ uint8_t start_day;
++
++ uint8_t start_hour;
++
++ uint8_t start_minute;
++
++ uint8_t stop_year;
++
++ uint8_t stop_day;
++
++ uint8_t stop_hour;
++
++ uint8_t stop_minute;
++} uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_year_day_report_fields_t;
++
++/**
++ * @brief Command fields for UnifyScheduleEntryLock/ScheduleEntryLockDailyRepeatingReport
++ */
++typedef struct {
++ uint8_t set_action;
++
++ uint8_t user_identifier;
++
++ uint8_t schedule_slotid;
++
++ uint8_t week_day_bitmask;
++
++ uint8_t start_hour;
++
++ uint8_t start_minute;
++
++ uint8_t duration_hour;
++
++ uint8_t duration_minute;
++} uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_daily_repeating_report_fields_t;
++
++
++/**
++ * @brief Setup callback to be called when a
++ * UnifyScheduleEntryLock/Commands/schedule_entry_lock_week_day_report 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_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_t callback);
++/**
++ * @brief Unsets callback to be called when a
++ * UnifyScheduleEntryLock/Commands/schedule_entry_lock_week_day_report is received.
++ *
++ * @param callback Function to be no longer called on command reception
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_unset(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_t callback);
++/**
++ * @brief Clears all callbacks registered for when
++ * UnifyScheduleEntryLock/Commands/schedule_entry_lock_week_day_report is received.
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_clear();
++
++/**
++ * @brief Setup callback to be called when a
++ * +/UnifyScheduleEntryLock/GeneratedCommands/schedule_entry_lock_week_day_report 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_schedule_entry_lock_generated_schedule_entry_lock_week_day_report_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_t callback);
++/**
++ * @brief Unsets callback to be called when a
++ * +/UnifyScheduleEntryLock/GeneratedCommands/schedule_entry_lock_week_day_report is received.
++ * @param callback Function to be no longer called on command reception
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_week_day_report_callback_unset(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_t callback);
++/**
++ * @brief Clears all callbacks registered for when
++ * +/UnifyScheduleEntryLock/GeneratedCommands/schedule_entry_lock_week_day_report is received.
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_week_day_report_callback_clear();
++/**
++ * @brief Setup callback to be called when a
++ * UnifyScheduleEntryLock/Commands/schedule_entry_lock_year_day_report 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_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_t callback);
++/**
++ * @brief Unsets callback to be called when a
++ * UnifyScheduleEntryLock/Commands/schedule_entry_lock_year_day_report is received.
++ *
++ * @param callback Function to be no longer called on command reception
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_unset(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_t callback);
++/**
++ * @brief Clears all callbacks registered for when
++ * UnifyScheduleEntryLock/Commands/schedule_entry_lock_year_day_report is received.
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_clear();
++
++/**
++ * @brief Setup callback to be called when a
++ * +/UnifyScheduleEntryLock/GeneratedCommands/schedule_entry_lock_year_day_report 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_schedule_entry_lock_generated_schedule_entry_lock_year_day_report_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_t callback);
++/**
++ * @brief Unsets callback to be called when a
++ * +/UnifyScheduleEntryLock/GeneratedCommands/schedule_entry_lock_year_day_report is received.
++ * @param callback Function to be no longer called on command reception
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_year_day_report_callback_unset(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_t callback);
++/**
++ * @brief Clears all callbacks registered for when
++ * +/UnifyScheduleEntryLock/GeneratedCommands/schedule_entry_lock_year_day_report is received.
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_year_day_report_callback_clear();
++/**
++ * @brief Setup callback to be called when a
++ * UnifyScheduleEntryLock/Commands/schedule_entry_lock_daily_repeating_report 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_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_t callback);
++/**
++ * @brief Unsets callback to be called when a
++ * UnifyScheduleEntryLock/Commands/schedule_entry_lock_daily_repeating_report is received.
++ *
++ * @param callback Function to be no longer called on command reception
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_unset(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_t callback);
++/**
++ * @brief Clears all callbacks registered for when
++ * UnifyScheduleEntryLock/Commands/schedule_entry_lock_daily_repeating_report is received.
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_clear();
++
++/**
++ * @brief Setup callback to be called when a
++ * +/UnifyScheduleEntryLock/GeneratedCommands/schedule_entry_lock_daily_repeating_report 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_schedule_entry_lock_generated_schedule_entry_lock_daily_repeating_report_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_t callback);
++/**
++ * @brief Unsets callback to be called when a
++ * +/UnifyScheduleEntryLock/GeneratedCommands/schedule_entry_lock_daily_repeating_report is received.
++ * @param callback Function to be no longer called on command reception
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_daily_repeating_report_callback_unset(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_t callback);
++/**
++ * @brief Clears all callbacks registered for when
++ * +/UnifyScheduleEntryLock/GeneratedCommands/schedule_entry_lock_daily_repeating_report is received.
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_daily_repeating_report_callback_clear();
++
++/**
++ * @brief Setup a callback for WriteAttribute to be called when a
++ * +/unify_schedule_entry_lock/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_schedule_entry_lock_write_attributes_callback(
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_write_attributes_callback_t callback
++);
++/**
++ * @brief Unsets a callback for WriteAttribute to be called when a
++ * +/unify_schedule_entry_lock/Commands/WriteAttributes is received.
++ * @param callback Function to be no longer called on command reception
++ */
++void uic_mqtt_dotdot_unset_unify_schedule_entry_lock_write_attributes_callback(
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_write_attributes_callback_t callback
++);
++/**
++ * @brief Clears all callbacks registered for when
++ * +/unify_schedule_entry_lock/Commands/WriteAttributes is received.
++ */
++void uic_mqtt_dotdot_clear_unify_schedule_entry_lock_write_attributes_callbacks();
++
++/**
++ * @brief Setup a callback for ForceReadAttributes to be called when a
++ * +/unify_schedule_entry_lock/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_schedule_entry_lock_force_read_attributes_callback(
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_force_read_attributes_callback_t callback
++);
++/**
++ * @brief Unsets a callback for ForceReadAttributes to be called when a
++ * +/unify_schedule_entry_lock/Commands/ForceReadAttributes is received.
++ *
++ * @param callback Function to be no longer called on command reception
++ */
++void uic_mqtt_dotdot_unset_unify_schedule_entry_lock_force_read_attributes_callback(
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_force_read_attributes_callback_t callback
++);
++/**
++ * @brief Clears all callbacks registered for when
++ * +/unify_schedule_entry_lock/Commands/ForceReadAttributes is received.
++ */
++void uic_mqtt_dotdot_clear_unify_schedule_entry_lock_force_read_attributes_callbacks();
++
++/**
++ * @brief Publish the attribute; UnifyScheduleEntryLock/Attributes/SlotsWeekDay
++ *
++ * @param base_topic topic prefix to publish, /slots_week_day
++ * 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_schedule_entry_lock_slots_week_day_publish(
++ const char *base_topic,
++ uint8_t value,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Unretains a published attribute; UnifyScheduleEntryLock/Attributes/SlotsWeekDay
++ *
++ * @param base_topic topic prefix to publish, /slots_week_day
++ * 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_schedule_entry_lock_slots_week_day_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Publish the attribute; UnifyScheduleEntryLock/Attributes/SlotsYearDay
++ *
++ * @param base_topic topic prefix to publish, /slots_year_day
++ * 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_schedule_entry_lock_slots_year_day_publish(
++ const char *base_topic,
++ uint8_t value,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Unretains a published attribute; UnifyScheduleEntryLock/Attributes/SlotsYearDay
++ *
++ * @param base_topic topic prefix to publish, /slots_year_day
++ * 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_schedule_entry_lock_slots_year_day_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Publish the attribute; UnifyScheduleEntryLock/Attributes/SignTZO
++ *
++ * @param base_topic topic prefix to publish, /signtzo
++ * 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_schedule_entry_lock_signtzo_publish(
++ const char *base_topic,
++ uint8_t value,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Unretains a published attribute; UnifyScheduleEntryLock/Attributes/SignTZO
++ *
++ * @param base_topic topic prefix to publish, /signtzo
++ * 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_schedule_entry_lock_signtzo_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Publish the attribute; UnifyScheduleEntryLock/Attributes/HourTZO
++ *
++ * @param base_topic topic prefix to publish, /hourtzo
++ * 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_schedule_entry_lock_hourtzo_publish(
++ const char *base_topic,
++ uint8_t value,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Unretains a published attribute; UnifyScheduleEntryLock/Attributes/HourTZO
++ *
++ * @param base_topic topic prefix to publish, /hourtzo
++ * 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_schedule_entry_lock_hourtzo_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Publish the attribute; UnifyScheduleEntryLock/Attributes/MinuteTZO
++ *
++ * @param base_topic topic prefix to publish, /minutetzo
++ * 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_schedule_entry_lock_minutetzo_publish(
++ const char *base_topic,
++ uint8_t value,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Unretains a published attribute; UnifyScheduleEntryLock/Attributes/MinuteTZO
++ *
++ * @param base_topic topic prefix to publish, /minutetzo
++ * 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_schedule_entry_lock_minutetzo_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Publish the attribute; UnifyScheduleEntryLock/Attributes/DSTOffsetSign
++ *
++ * @param base_topic topic prefix to publish, /dst_offset_sign
++ * 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_schedule_entry_lock_dst_offset_sign_publish(
++ const char *base_topic,
++ uint8_t value,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Unretains a published attribute; UnifyScheduleEntryLock/Attributes/DSTOffsetSign
++ *
++ * @param base_topic topic prefix to publish, /dst_offset_sign
++ * 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_schedule_entry_lock_dst_offset_sign_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Publish the attribute; UnifyScheduleEntryLock/Attributes/DSTOffsetMinute
++ *
++ * @param base_topic topic prefix to publish, /dst_offset_minute
++ * 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_schedule_entry_lock_dst_offset_minute_publish(
++ const char *base_topic,
++ uint8_t value,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Unretains a published attribute; UnifyScheduleEntryLock/Attributes/DSTOffsetMinute
++ *
++ * @param base_topic topic prefix to publish, /dst_offset_minute
++ * 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_schedule_entry_lock_dst_offset_minute_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Publish the attribute; UnifyScheduleEntryLock/Attributes/NumberOfSlotsDailyRepeating
++ *
++ * @param base_topic topic prefix to publish, /number_of_slots_daily_repeating
++ * 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_schedule_entry_lock_number_of_slots_daily_repeating_publish(
++ const char *base_topic,
++ uint8_t value,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++/**
++ * @brief Unretains a published attribute; UnifyScheduleEntryLock/Attributes/NumberOfSlotsDailyRepeating
++ *
++ * @param base_topic topic prefix to publish, /number_of_slots_daily_repeating
++ * 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_schedule_entry_lock_number_of_slots_daily_repeating_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type
++);
++
++
++/**
++ * @brief Publish the UnifyScheduleEntryLock/ClusterRevision attribute
++ *
++ * @param base_topic topic prefix to publish, /UnifyScheduleEntryLock/Attributes/ClusterRevision
++ * will be appended.
++ * @param value Value to publish.
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_publish_cluster_revision(const char* base_topic, uint16_t value);
++
++/**
++ * @brief Unretain a publication to UnifyScheduleEntryLock/ClusterRevision attribute
++ *
++ * @param base_topic topic prefix to publish, /UnifyScheduleEntryLock/Attributes/ClusterRevision
++ * will be appended.
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_unretain_cluster_revision(const char* base_topic);
++
++/**
++ * @brief Publish the SupportedCommands for UNID/EndPoint for the UnifyScheduleEntryLock Cluster
++ *
++ * This function will iterate over all Commands in the UnifyScheduleEntryLock 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_schedule_entry_lock_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 UnifyScheduleEntryLock Cluster
++ *
++ * @param unid
++ * @param endpoint )
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_publish_empty_supported_commands(
++ const dotdot_unid_t unid
++ ,dotdot_endpoint_id_t endpoint);
+ // Callback types used by the unify_humidity_control cluster
+ typedef sl_status_t (*uic_mqtt_dotdot_unify_humidity_control_mode_set_callback_t)(
+ dotdot_unid_t unid,
+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 003f75549d..e8d7b7b258 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
+@@ -5054,6 +5054,63 @@ typedef sl_status_t (*uic_mqtt_dotdot_unify_thermostat_attribute_operating_state
+ uic_mqtt_dotdot_attribute_update_type_t update_type,
+ uint8_t operating_state
+ );
++// Callback types used by the unify_schedule_entry_lock cluster
++typedef sl_status_t (*uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_slots_week_day_callback_t)(
++ dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint,
++ bool unretained,
++ uic_mqtt_dotdot_attribute_update_type_t update_type,
++ uint8_t slots_week_day
++);
++typedef sl_status_t (*uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_slots_year_day_callback_t)(
++ dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint,
++ bool unretained,
++ uic_mqtt_dotdot_attribute_update_type_t update_type,
++ uint8_t slots_year_day
++);
++typedef sl_status_t (*uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_signtzo_callback_t)(
++ dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint,
++ bool unretained,
++ uic_mqtt_dotdot_attribute_update_type_t update_type,
++ uint8_t signtzo
++);
++typedef sl_status_t (*uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_hourtzo_callback_t)(
++ dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint,
++ bool unretained,
++ uic_mqtt_dotdot_attribute_update_type_t update_type,
++ uint8_t hourtzo
++);
++typedef sl_status_t (*uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_minutetzo_callback_t)(
++ dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint,
++ bool unretained,
++ uic_mqtt_dotdot_attribute_update_type_t update_type,
++ uint8_t minutetzo
++);
++typedef sl_status_t (*uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_dst_offset_sign_callback_t)(
++ dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint,
++ bool unretained,
++ uic_mqtt_dotdot_attribute_update_type_t update_type,
++ uint8_t dst_offset_sign
++);
++typedef sl_status_t (*uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_dst_offset_minute_callback_t)(
++ dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint,
++ bool unretained,
++ uic_mqtt_dotdot_attribute_update_type_t update_type,
++ uint8_t dst_offset_minute
++);
++typedef sl_status_t (*uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_number_of_slots_daily_repeating_callback_t)(
++ dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint,
++ bool unretained,
++ uic_mqtt_dotdot_attribute_update_type_t update_type,
++ uint8_t number_of_slots_daily_repeating
++);
+ // Callback types used by the unify_humidity_control cluster
+ typedef sl_status_t (*uic_mqtt_dotdot_unify_humidity_control_attribute_reporting_mode_callback_t)(
+ dotdot_unid_t unid,
+@@ -9854,6 +9911,62 @@ void uic_mqtt_dotdot_unify_thermostat_attribute_supported_thermostat_mode_callba
+ void uic_mqtt_dotdot_unify_thermostat_attribute_operating_state_callback_set(const uic_mqtt_dotdot_unify_thermostat_attribute_operating_state_callback_t callback);
+
+
++/**
++ * Initializes the attributes features for the UnifyScheduleEntryLock cluster,
++ * allowing to receive attribute updates from other UNIDs.
++ */
++sl_status_t uic_mqtt_dotdot_unify_schedule_entry_lock_attributes_init();
++
++/**
++ * Setup callback to be called when a
++ * UnifyScheduleEntryLock/Attributes/slots_week_day/# is received. Setting
++ * this callback will overwrite the previous set callback
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_slots_week_day_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_slots_week_day_callback_t callback);
++/**
++ * Setup callback to be called when a
++ * UnifyScheduleEntryLock/Attributes/slots_year_day/# is received. Setting
++ * this callback will overwrite the previous set callback
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_slots_year_day_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_slots_year_day_callback_t callback);
++/**
++ * Setup callback to be called when a
++ * UnifyScheduleEntryLock/Attributes/signtzo/# is received. Setting
++ * this callback will overwrite the previous set callback
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_signtzo_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_signtzo_callback_t callback);
++/**
++ * Setup callback to be called when a
++ * UnifyScheduleEntryLock/Attributes/hourtzo/# is received. Setting
++ * this callback will overwrite the previous set callback
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_hourtzo_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_hourtzo_callback_t callback);
++/**
++ * Setup callback to be called when a
++ * UnifyScheduleEntryLock/Attributes/minutetzo/# is received. Setting
++ * this callback will overwrite the previous set callback
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_minutetzo_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_minutetzo_callback_t callback);
++/**
++ * Setup callback to be called when a
++ * UnifyScheduleEntryLock/Attributes/dst_offset_sign/# is received. Setting
++ * this callback will overwrite the previous set callback
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_dst_offset_sign_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_dst_offset_sign_callback_t callback);
++/**
++ * Setup callback to be called when a
++ * UnifyScheduleEntryLock/Attributes/dst_offset_minute/# is received. Setting
++ * this callback will overwrite the previous set callback
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_dst_offset_minute_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_dst_offset_minute_callback_t callback);
++/**
++ * Setup callback to be called when a
++ * UnifyScheduleEntryLock/Attributes/number_of_slots_daily_repeating/# is received. Setting
++ * this callback will overwrite the previous set callback
++ */
++void uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_number_of_slots_daily_repeating_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_number_of_slots_daily_repeating_callback_t callback);
++
++
+ /**
+ * Initializes the attributes features for the UnifyHumidityControl cluster,
+ * allowing to receive attribute updates from other UNIDs.
+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 aa8ac95998..04e8e6b1a2 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
+@@ -4997,6 +4997,91 @@ void uic_mqtt_dotdot_unify_thermostat_publish_generated_write_attributes_command
+ uic_mqtt_dotdot_unify_thermostat_updated_state_t attribute_list
+ );
+
++/**
++ * @brief Publishes an incoming/generated ScheduleEntryLockWeekDayReport command for
++ * the UnifyScheduleEntryLock cluster.
++ *
++ * Publication will be made at the following topic
++ * ucl/by-unid/UNID/epID/UnifyScheduleEntryLock/GeneratedCommands/ScheduleEntryLockWeekDayReport
++ *
++ * @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_schedule_entry_lock_publish_generated_schedule_entry_lock_week_day_report_command(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint,
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_week_day_report_fields_t *fields
++
++);
++/**
++ * @brief Publishes an incoming/generated ScheduleEntryLockYearDayReport command for
++ * the UnifyScheduleEntryLock cluster.
++ *
++ * Publication will be made at the following topic
++ * ucl/by-unid/UNID/epID/UnifyScheduleEntryLock/GeneratedCommands/ScheduleEntryLockYearDayReport
++ *
++ * @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_schedule_entry_lock_publish_generated_schedule_entry_lock_year_day_report_command(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint,
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_year_day_report_fields_t *fields
++
++);
++/**
++ * @brief Publishes an incoming/generated ScheduleEntryLockDailyRepeatingReport command for
++ * the UnifyScheduleEntryLock cluster.
++ *
++ * Publication will be made at the following topic
++ * ucl/by-unid/UNID/epID/UnifyScheduleEntryLock/GeneratedCommands/ScheduleEntryLockDailyRepeatingReport
++ *
++ * @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_schedule_entry_lock_publish_generated_schedule_entry_lock_daily_repeating_report_command(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint,
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_daily_repeating_report_fields_t *fields
++
++);
++
++/**
++ * @brief Publishes an incoming/generated WriteAttributes command for
++ * the UnifyScheduleEntryLock cluster.
++ *
++ * Publication will be made at the following topic
++ * ucl/by-unid/UNID/epID/UnifyScheduleEntryLock/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_schedule_entry_lock_publish_generated_write_attributes_command(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint,
++ uic_mqtt_dotdot_unify_schedule_entry_lock_state_t attribute_values,
++ uic_mqtt_dotdot_unify_schedule_entry_lock_updated_state_t attribute_list
++);
++
+ /**
+ * @brief Publishes an incoming/generated ModeSet command for
+ * the UnifyHumidityControl cluster.
+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 caeee80ffa..7220d03d38 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
+@@ -3709,6 +3709,71 @@ void uic_mqtt_dotdot_by_group_unify_thermostat_write_attributes_callback_set(
+
+
+
++/**
++ * @brief Callback signature for by-group UnifyScheduleEntryLock::ScheduleEntryLockWeekDayReport command.
++ */
++typedef void (*uic_mqtt_dotdot_by_group_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_t)(
++ const dotdot_group_id_t group_id,
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_week_day_report_fields_t *fields
++);
++
++/**
++ * Setup handler to be called when a
++ * ucl/by-group/+/UnifyScheduleEntryLock/schedule_entry_lock_week_day_report is received.
++ * Setting this callback will overwrite the previous set callback.
++ *
++ */
++void uic_mqtt_dotdot_by_group_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_set(const uic_mqtt_dotdot_by_group_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_t callback);
++
++/**
++ * @brief Callback signature for by-group UnifyScheduleEntryLock::ScheduleEntryLockYearDayReport command.
++ */
++typedef void (*uic_mqtt_dotdot_by_group_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_t)(
++ const dotdot_group_id_t group_id,
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_year_day_report_fields_t *fields
++);
++
++/**
++ * Setup handler to be called when a
++ * ucl/by-group/+/UnifyScheduleEntryLock/schedule_entry_lock_year_day_report is received.
++ * Setting this callback will overwrite the previous set callback.
++ *
++ */
++void uic_mqtt_dotdot_by_group_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_set(const uic_mqtt_dotdot_by_group_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_t callback);
++
++/**
++ * @brief Callback signature for by-group UnifyScheduleEntryLock::ScheduleEntryLockDailyRepeatingReport command.
++ */
++typedef void (*uic_mqtt_dotdot_by_group_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_t)(
++ const dotdot_group_id_t group_id,
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_daily_repeating_report_fields_t *fields
++);
++
++/**
++ * Setup handler to be called when a
++ * ucl/by-group/+/UnifyScheduleEntryLock/schedule_entry_lock_daily_repeating_report is received.
++ * Setting this callback will overwrite the previous set callback.
++ *
++ */
++void uic_mqtt_dotdot_by_group_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_set(const uic_mqtt_dotdot_by_group_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_t callback);
++
++typedef void (*uic_mqtt_dotdot_by_group_unify_schedule_entry_lock_write_attributes_callback_t)(
++ const dotdot_group_id_t group_id,
++ uic_mqtt_dotdot_unify_schedule_entry_lock_state_t,
++ uic_mqtt_dotdot_unify_schedule_entry_lock_updated_state_t
++);
++
++/**
++ * Setup a callback for WriteAttribute to be called when a
++ * ucl/by-group/+/unify_schedule_entry_lock/Commands/WriteAttributes is received.
++ * Setting this callback will overwrite any previously set callback.
++ */
++void uic_mqtt_dotdot_by_group_unify_schedule_entry_lock_write_attributes_callback_set(
++ const uic_mqtt_dotdot_by_group_unify_schedule_entry_lock_write_attributes_callback_t callback
++);
++
++
++
+ /**
+ * @brief Callback signature for by-group UnifyHumidityControl::ModeSet command.
+ */
+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 b49b9a5c1a..098475c6d2 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
+@@ -7108,6 +7108,123 @@ void uic_mqtt_dotdot_unify_fan_control_publish_turn_off_command(
+ void uic_mqtt_dotdot_unify_fan_control_publish_turn_off_command_to_group(
+ uint16_t destination_group_id
+ );
++/**
++ * @brief Sends/Publishes a ScheduleEntryLockWeekDayReport command for
++ * the UnifyScheduleEntryLock cluster to a destination.
++ *
++ * Publication will be made at the following topic
++ * ucl/by-unid/UNID/epID/UnifyScheduleEntryLock/Commands/ScheduleEntryLockWeekDayReport
++ *
++ * @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_schedule_entry_lock_publish_schedule_entry_lock_week_day_report_command(
++ const dotdot_unid_t destination_unid,
++ const dotdot_endpoint_id_t destination_endpoint,
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_week_day_report_fields_t *fields
++
++);
++
++/**
++ * @brief Sends/Publishes a ScheduleEntryLockWeekDayReport command for
++ * the UnifyScheduleEntryLock cluster to a group.
++ *
++ * Publication will be made at the following topic
++ * ucl/by-group/GroupID/UnifyScheduleEntryLock/Commands/ScheduleEntryLockWeekDayReport
++ *
++ * @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_schedule_entry_lock_publish_schedule_entry_lock_week_day_report_command_to_group(
++ uint16_t destination_group_id,
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_week_day_report_fields_t *fields
++
++);
++/**
++ * @brief Sends/Publishes a ScheduleEntryLockYearDayReport command for
++ * the UnifyScheduleEntryLock cluster to a destination.
++ *
++ * Publication will be made at the following topic
++ * ucl/by-unid/UNID/epID/UnifyScheduleEntryLock/Commands/ScheduleEntryLockYearDayReport
++ *
++ * @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_schedule_entry_lock_publish_schedule_entry_lock_year_day_report_command(
++ const dotdot_unid_t destination_unid,
++ const dotdot_endpoint_id_t destination_endpoint,
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_year_day_report_fields_t *fields
++
++);
++
++/**
++ * @brief Sends/Publishes a ScheduleEntryLockYearDayReport command for
++ * the UnifyScheduleEntryLock cluster to a group.
++ *
++ * Publication will be made at the following topic
++ * ucl/by-group/GroupID/UnifyScheduleEntryLock/Commands/ScheduleEntryLockYearDayReport
++ *
++ * @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_schedule_entry_lock_publish_schedule_entry_lock_year_day_report_command_to_group(
++ uint16_t destination_group_id,
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_year_day_report_fields_t *fields
++
++);
++/**
++ * @brief Sends/Publishes a ScheduleEntryLockDailyRepeatingReport command for
++ * the UnifyScheduleEntryLock cluster to a destination.
++ *
++ * Publication will be made at the following topic
++ * ucl/by-unid/UNID/epID/UnifyScheduleEntryLock/Commands/ScheduleEntryLockDailyRepeatingReport
++ *
++ * @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_schedule_entry_lock_publish_schedule_entry_lock_daily_repeating_report_command(
++ const dotdot_unid_t destination_unid,
++ const dotdot_endpoint_id_t destination_endpoint,
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_daily_repeating_report_fields_t *fields
++
++);
++
++/**
++ * @brief Sends/Publishes a ScheduleEntryLockDailyRepeatingReport command for
++ * the UnifyScheduleEntryLock cluster to a group.
++ *
++ * Publication will be made at the following topic
++ * ucl/by-group/GroupID/UnifyScheduleEntryLock/Commands/ScheduleEntryLockDailyRepeatingReport
++ *
++ * @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_schedule_entry_lock_publish_schedule_entry_lock_daily_repeating_report_command_to_group(
++ uint16_t destination_group_id,
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_daily_repeating_report_fields_t *fields
++
++);
+ /**
+ * @brief Sends/Publishes a ModeSet command for
+ * the UnifyHumidityControl cluster to a destination.
+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 31b5b4443d..3778a1ec8c 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
+@@ -1692,6 +1692,37 @@ void uic_mqtt_dotdot_unify_thermostat_publish_supported_generated_commands(
+ );
+
+
++/**
++ * @brief Struct containing the list of commands for UnifyScheduleEntryLock
++ */
++typedef struct _uic_mqtt_dotdot_unify_schedule_entry_lock_supported_commands_ {
++ bool schedule_entry_lock_week_day_report;
++ bool schedule_entry_lock_year_day_report;
++ bool schedule_entry_lock_daily_repeating_report;
++ bool write_attributes;
++} uic_mqtt_dotdot_unify_schedule_entry_lock_supported_commands_t;
++
++/**
++ * @brief Sends/Publishes a the SupportedGenerated commands for
++ * the UnifyScheduleEntryLock cluster for a UNID/Endpoint
++ *
++ * Publication will be made at the following topic
++ * ucl/by-unid/UNID/epID/UnifyScheduleEntryLock/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_schedule_entry_lock_publish_supported_generated_commands(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint,
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_supported_commands_t *command_list
++);
++
++
+ /**
+ * @brief Struct containing the list of commands for UnifyHumidityControl
+ */
+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 fb910272aa..02a9105975 100644
+--- a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.cpp
++++ b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.cpp
+@@ -93961,6 +93961,1486 @@ sl_status_t uic_mqtt_dotdot_unify_thermostat_init()
+ return SL_STATUS_OK;
+ }
+
++// Callbacks pointers
++static std::set uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback;
++static std::set uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_week_day_report_callback;
++static std::set uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback;
++static std::set uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_year_day_report_callback;
++static std::set uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback;
++static std::set uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_daily_repeating_report_callback;
++static std::set uic_mqtt_dotdot_unify_schedule_entry_lock_write_attributes_callback;
++static std::set uic_mqtt_dotdot_unify_schedule_entry_lock_force_read_attributes_callback;
++
++// Callbacks setters
++void uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_t callback)
++{
++ if (callback != nullptr) {
++ uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback.insert(callback);
++ }
++}
++void uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_unset(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_t callback)
++{
++ uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback.erase(callback);
++}
++void uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_clear()
++{
++ uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback.clear();
++}
++std::set& get_uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback()
++{
++ return uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback;
++}
++
++void uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_week_day_report_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_t callback)
++{
++ if (callback != nullptr) {
++ uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_week_day_report_callback.insert(callback);
++ }
++}
++void uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_week_day_report_callback_unset(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback_t callback)
++{
++ uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_week_day_report_callback.erase(callback);
++}
++void uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_week_day_report_callback_clear()
++{
++ uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_week_day_report_callback.clear();
++}
++void uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_t callback)
++{
++ if (callback != nullptr) {
++ uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback.insert(callback);
++ }
++}
++void uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_unset(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_t callback)
++{
++ uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback.erase(callback);
++}
++void uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_clear()
++{
++ uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback.clear();
++}
++std::set& get_uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback()
++{
++ return uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback;
++}
++
++void uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_year_day_report_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_t callback)
++{
++ if (callback != nullptr) {
++ uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_year_day_report_callback.insert(callback);
++ }
++}
++void uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_year_day_report_callback_unset(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback_t callback)
++{
++ uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_year_day_report_callback.erase(callback);
++}
++void uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_year_day_report_callback_clear()
++{
++ uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_year_day_report_callback.clear();
++}
++void uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_t callback)
++{
++ if (callback != nullptr) {
++ uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback.insert(callback);
++ }
++}
++void uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_unset(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_t callback)
++{
++ uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback.erase(callback);
++}
++void uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_clear()
++{
++ uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback.clear();
++}
++std::set& get_uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback()
++{
++ return uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback;
++}
++
++void uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_daily_repeating_report_callback_set(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_t callback)
++{
++ if (callback != nullptr) {
++ uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_daily_repeating_report_callback.insert(callback);
++ }
++}
++void uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_daily_repeating_report_callback_unset(const uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback_t callback)
++{
++ uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_daily_repeating_report_callback.erase(callback);
++}
++void uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_daily_repeating_report_callback_clear()
++{
++ uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_daily_repeating_report_callback.clear();
++}
++
++void uic_mqtt_dotdot_set_unify_schedule_entry_lock_write_attributes_callback(
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_write_attributes_callback_t callback)
++{
++ if (callback != nullptr) {
++ uic_mqtt_dotdot_unify_schedule_entry_lock_write_attributes_callback.insert(callback);
++ }
++}
++void uic_mqtt_dotdot_unset_unify_schedule_entry_lock_write_attributes_callback(
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_write_attributes_callback_t callback)
++{
++ uic_mqtt_dotdot_unify_schedule_entry_lock_write_attributes_callback.erase(callback);
++}
++void uic_mqtt_dotdot_clear_unify_schedule_entry_lock_write_attributes_callbacks()
++{
++ uic_mqtt_dotdot_unify_schedule_entry_lock_write_attributes_callback.clear();
++}
++std::set& get_uic_mqtt_dotdot_unify_schedule_entry_lock_write_attributes_callback()
++{
++ return uic_mqtt_dotdot_unify_schedule_entry_lock_write_attributes_callback;
++}
++
++void uic_mqtt_dotdot_set_unify_schedule_entry_lock_force_read_attributes_callback(
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_force_read_attributes_callback_t callback)
++{
++ if (callback != nullptr) {
++ uic_mqtt_dotdot_unify_schedule_entry_lock_force_read_attributes_callback.insert(callback);
++ }
++}
++void uic_mqtt_dotdot_unset_unify_schedule_entry_lock_force_read_attributes_callback(
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_force_read_attributes_callback_t callback)
++{
++ uic_mqtt_dotdot_unify_schedule_entry_lock_force_read_attributes_callback.erase(callback);
++}
++void uic_mqtt_dotdot_clear_unify_schedule_entry_lock_force_read_attributes_callbacks()
++{
++ uic_mqtt_dotdot_unify_schedule_entry_lock_force_read_attributes_callback.clear();
++}
++
++
++// Callback function for incoming publications on ucl/by-unid/+/+/UnifyScheduleEntryLock/Commands/ScheduleEntryLockWeekDayReport
++void uic_mqtt_dotdot_on_unify_schedule_entry_lock_schedule_entry_lock_week_day_report(
++ const char *topic,
++ const char *message,
++ const size_t message_length)
++{
++ if (message_length == 0 || (uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_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 user_identifier = {};
++ uint8_t schedule_slotid = {};
++ uint8_t day_of_week = {};
++ uint8_t start_hour = {};
++ uint8_t start_minute = {};
++ uint8_t stop_hour = {};
++ uint8_t stop_minute = {};
++
++
++ nlohmann::json jsn;
++ try {
++ jsn = nlohmann::json::parse(std::string(message));
++
++
++ uic_mqtt_dotdot_parse_unify_schedule_entry_lock_schedule_entry_lock_week_day_report(
++ jsn,
++ user_identifier,
++
++ schedule_slotid,
++
++ day_of_week,
++
++ start_hour,
++
++ start_minute,
++
++ stop_hour,
++
++ stop_minute
++ );
++
++ } catch (const nlohmann::json::parse_error& e) {
++ // Catch JSON object field parsing errors
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_PARSE_FAIL, "UnifyScheduleEntryLock", "ScheduleEntryLockWeekDayReport");
++ return;
++ } catch (const nlohmann::json::exception& e) {
++ // Catch JSON object field parsing errors
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyScheduleEntryLock", "ScheduleEntryLockWeekDayReport", e.what());
++ return;
++ } catch (const std::exception& e) {
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyScheduleEntryLock", "ScheduleEntryLockWeekDayReport", "");
++ return;
++ }
++
++
++
++ for (const auto& callback: uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback){
++ callback(
++ static_cast(unid.c_str()),
++ endpoint,
++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL,
++ user_identifier,
++
++ schedule_slotid,
++
++ day_of_week,
++
++ start_hour,
++
++ start_minute,
++
++ stop_hour,
++
++ stop_minute
++
++ );
++ }
++
++}
++
++// Callback function for incoming publications on ucl/by-unid/+/+/UnifyScheduleEntryLock/GeneratedCommands/ScheduleEntryLockWeekDayReport
++static void uic_mqtt_dotdot_on_generated_unify_schedule_entry_lock_schedule_entry_lock_week_day_report(
++ const char *topic,
++ const char *message,
++ const size_t message_length)
++{
++ if (message_length == 0 || (uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_week_day_report_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 user_identifier = {};
++ uint8_t schedule_slotid = {};
++ uint8_t day_of_week = {};
++ uint8_t start_hour = {};
++ uint8_t start_minute = {};
++ uint8_t stop_hour = {};
++ uint8_t stop_minute = {};
++
++
++ nlohmann::json jsn;
++ try {
++ jsn = nlohmann::json::parse(std::string(message));
++
++
++ uic_mqtt_dotdot_parse_unify_schedule_entry_lock_schedule_entry_lock_week_day_report(
++ jsn,
++ user_identifier,
++
++ schedule_slotid,
++
++ day_of_week,
++
++ start_hour,
++
++ start_minute,
++
++ stop_hour,
++
++ stop_minute
++ );
++
++ } catch (const nlohmann::json::parse_error& e) {
++ // Catch JSON object field parsing errors
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_PARSE_FAIL, "UnifyScheduleEntryLock", "ScheduleEntryLockWeekDayReport");
++ return;
++ } catch (const nlohmann::json::exception& e) {
++ // Catch JSON object field parsing errors
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyScheduleEntryLock", "ScheduleEntryLockWeekDayReport", e.what());
++ return;
++ } catch (const std::exception& e) {
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyScheduleEntryLock", "ScheduleEntryLockWeekDayReport", "");
++ return;
++ }
++
++
++
++
++ for (const auto& callback: uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_week_day_report_callback){
++ callback(
++ static_cast(unid.c_str()),
++ endpoint,
++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL,
++ user_identifier,
++
++ schedule_slotid,
++
++ day_of_week,
++
++ start_hour,
++
++ start_minute,
++
++ stop_hour,
++
++ stop_minute
++
++ );
++ }
++}
++
++
++// Callback function for incoming publications on ucl/by-unid/+/+/UnifyScheduleEntryLock/Commands/ScheduleEntryLockYearDayReport
++void uic_mqtt_dotdot_on_unify_schedule_entry_lock_schedule_entry_lock_year_day_report(
++ const char *topic,
++ const char *message,
++ const size_t message_length)
++{
++ if (message_length == 0 || (uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_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 set_action = {};
++ uint8_t user_identifier = {};
++ uint8_t schedule_slotid = {};
++ uint8_t start_year = {};
++ uint8_t start_day = {};
++ uint8_t start_hour = {};
++ uint8_t start_minute = {};
++ uint8_t stop_year = {};
++ uint8_t stop_day = {};
++ uint8_t stop_hour = {};
++ uint8_t stop_minute = {};
++
++
++ nlohmann::json jsn;
++ try {
++ jsn = nlohmann::json::parse(std::string(message));
++
++
++ uic_mqtt_dotdot_parse_unify_schedule_entry_lock_schedule_entry_lock_year_day_report(
++ jsn,
++ set_action,
++
++ user_identifier,
++
++ schedule_slotid,
++
++ start_year,
++
++ start_day,
++
++ start_hour,
++
++ start_minute,
++
++ stop_year,
++
++ stop_day,
++
++ stop_hour,
++
++ stop_minute
++ );
++
++ } catch (const nlohmann::json::parse_error& e) {
++ // Catch JSON object field parsing errors
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_PARSE_FAIL, "UnifyScheduleEntryLock", "ScheduleEntryLockYearDayReport");
++ return;
++ } catch (const nlohmann::json::exception& e) {
++ // Catch JSON object field parsing errors
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyScheduleEntryLock", "ScheduleEntryLockYearDayReport", e.what());
++ return;
++ } catch (const std::exception& e) {
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyScheduleEntryLock", "ScheduleEntryLockYearDayReport", "");
++ return;
++ }
++
++
++
++ for (const auto& callback: uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback){
++ callback(
++ static_cast(unid.c_str()),
++ endpoint,
++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL,
++ set_action,
++
++ user_identifier,
++
++ schedule_slotid,
++
++ start_year,
++
++ start_day,
++
++ start_hour,
++
++ start_minute,
++
++ stop_year,
++
++ stop_day,
++
++ stop_hour,
++
++ stop_minute
++
++ );
++ }
++
++}
++
++// Callback function for incoming publications on ucl/by-unid/+/+/UnifyScheduleEntryLock/GeneratedCommands/ScheduleEntryLockYearDayReport
++static void uic_mqtt_dotdot_on_generated_unify_schedule_entry_lock_schedule_entry_lock_year_day_report(
++ const char *topic,
++ const char *message,
++ const size_t message_length)
++{
++ if (message_length == 0 || (uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_year_day_report_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 set_action = {};
++ uint8_t user_identifier = {};
++ uint8_t schedule_slotid = {};
++ uint8_t start_year = {};
++ uint8_t start_day = {};
++ uint8_t start_hour = {};
++ uint8_t start_minute = {};
++ uint8_t stop_year = {};
++ uint8_t stop_day = {};
++ uint8_t stop_hour = {};
++ uint8_t stop_minute = {};
++
++
++ nlohmann::json jsn;
++ try {
++ jsn = nlohmann::json::parse(std::string(message));
++
++
++ uic_mqtt_dotdot_parse_unify_schedule_entry_lock_schedule_entry_lock_year_day_report(
++ jsn,
++ set_action,
++
++ user_identifier,
++
++ schedule_slotid,
++
++ start_year,
++
++ start_day,
++
++ start_hour,
++
++ start_minute,
++
++ stop_year,
++
++ stop_day,
++
++ stop_hour,
++
++ stop_minute
++ );
++
++ } catch (const nlohmann::json::parse_error& e) {
++ // Catch JSON object field parsing errors
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_PARSE_FAIL, "UnifyScheduleEntryLock", "ScheduleEntryLockYearDayReport");
++ return;
++ } catch (const nlohmann::json::exception& e) {
++ // Catch JSON object field parsing errors
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyScheduleEntryLock", "ScheduleEntryLockYearDayReport", e.what());
++ return;
++ } catch (const std::exception& e) {
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyScheduleEntryLock", "ScheduleEntryLockYearDayReport", "");
++ return;
++ }
++
++
++
++
++ for (const auto& callback: uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_year_day_report_callback){
++ callback(
++ static_cast(unid.c_str()),
++ endpoint,
++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL,
++ set_action,
++
++ user_identifier,
++
++ schedule_slotid,
++
++ start_year,
++
++ start_day,
++
++ start_hour,
++
++ start_minute,
++
++ stop_year,
++
++ stop_day,
++
++ stop_hour,
++
++ stop_minute
++
++ );
++ }
++}
++
++
++// Callback function for incoming publications on ucl/by-unid/+/+/UnifyScheduleEntryLock/Commands/ScheduleEntryLockDailyRepeatingReport
++void uic_mqtt_dotdot_on_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report(
++ const char *topic,
++ const char *message,
++ const size_t message_length)
++{
++ if (message_length == 0 || (uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_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 set_action = {};
++ uint8_t user_identifier = {};
++ uint8_t schedule_slotid = {};
++ uint8_t week_day_bitmask = {};
++ uint8_t start_hour = {};
++ uint8_t start_minute = {};
++ uint8_t duration_hour = {};
++ uint8_t duration_minute = {};
++
++
++ nlohmann::json jsn;
++ try {
++ jsn = nlohmann::json::parse(std::string(message));
++
++
++ uic_mqtt_dotdot_parse_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report(
++ jsn,
++ set_action,
++
++ user_identifier,
++
++ schedule_slotid,
++
++ week_day_bitmask,
++
++ start_hour,
++
++ start_minute,
++
++ duration_hour,
++
++ duration_minute
++ );
++
++ } catch (const nlohmann::json::parse_error& e) {
++ // Catch JSON object field parsing errors
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_PARSE_FAIL, "UnifyScheduleEntryLock", "ScheduleEntryLockDailyRepeatingReport");
++ return;
++ } catch (const nlohmann::json::exception& e) {
++ // Catch JSON object field parsing errors
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyScheduleEntryLock", "ScheduleEntryLockDailyRepeatingReport", e.what());
++ return;
++ } catch (const std::exception& e) {
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyScheduleEntryLock", "ScheduleEntryLockDailyRepeatingReport", "");
++ return;
++ }
++
++
++
++ for (const auto& callback: uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback){
++ callback(
++ static_cast(unid.c_str()),
++ endpoint,
++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL,
++ set_action,
++
++ user_identifier,
++
++ schedule_slotid,
++
++ week_day_bitmask,
++
++ start_hour,
++
++ start_minute,
++
++ duration_hour,
++
++ duration_minute
++
++ );
++ }
++
++}
++
++// Callback function for incoming publications on ucl/by-unid/+/+/UnifyScheduleEntryLock/GeneratedCommands/ScheduleEntryLockDailyRepeatingReport
++static void uic_mqtt_dotdot_on_generated_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report(
++ const char *topic,
++ const char *message,
++ const size_t message_length)
++{
++ if (message_length == 0 || (uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_daily_repeating_report_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 set_action = {};
++ uint8_t user_identifier = {};
++ uint8_t schedule_slotid = {};
++ uint8_t week_day_bitmask = {};
++ uint8_t start_hour = {};
++ uint8_t start_minute = {};
++ uint8_t duration_hour = {};
++ uint8_t duration_minute = {};
++
++
++ nlohmann::json jsn;
++ try {
++ jsn = nlohmann::json::parse(std::string(message));
++
++
++ uic_mqtt_dotdot_parse_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report(
++ jsn,
++ set_action,
++
++ user_identifier,
++
++ schedule_slotid,
++
++ week_day_bitmask,
++
++ start_hour,
++
++ start_minute,
++
++ duration_hour,
++
++ duration_minute
++ );
++
++ } catch (const nlohmann::json::parse_error& e) {
++ // Catch JSON object field parsing errors
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_PARSE_FAIL, "UnifyScheduleEntryLock", "ScheduleEntryLockDailyRepeatingReport");
++ return;
++ } catch (const nlohmann::json::exception& e) {
++ // Catch JSON object field parsing errors
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyScheduleEntryLock", "ScheduleEntryLockDailyRepeatingReport", e.what());
++ return;
++ } catch (const std::exception& e) {
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyScheduleEntryLock", "ScheduleEntryLockDailyRepeatingReport", "");
++ return;
++ }
++
++
++
++
++ for (const auto& callback: uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_daily_repeating_report_callback){
++ callback(
++ static_cast(unid.c_str()),
++ endpoint,
++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_NORMAL,
++ set_action,
++
++ user_identifier,
++
++ schedule_slotid,
++
++ week_day_bitmask,
++
++ start_hour,
++
++ start_minute,
++
++ duration_hour,
++
++ duration_minute
++
++ );
++ }
++}
++
++
++// Callback function for incoming publications on ucl/by-unid/+/+/UnifyScheduleEntryLock/Commands/WriteAttributes
++void uic_mqtt_dotdot_on_unify_schedule_entry_lock_WriteAttributes(
++ const char *topic,
++ const char *message,
++ const size_t message_length)
++{
++ if (uic_mqtt_dotdot_unify_schedule_entry_lock_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_schedule_entry_lock_state_t new_state = {};
++ uic_mqtt_dotdot_unify_schedule_entry_lock_updated_state_t new_updated_state = {};
++
++
++ nlohmann::json jsn;
++ try {
++ jsn = nlohmann::json::parse(std::string(message));
++
++ uic_mqtt_dotdot_parse_unify_schedule_entry_lock_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, "UnifyScheduleEntryLock", "WriteAttributes");
++ return;
++ } catch (const nlohmann::json::exception& e) {
++ // Catch JSON object field parsing errors
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyScheduleEntryLock", "WriteAttributes", e.what());
++ return;
++ } catch (const std::exception& e) {
++ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyScheduleEntryLock", "WriteAttributes", "");
++ return;
++ }
++
++ for (const auto& callback: uic_mqtt_dotdot_unify_schedule_entry_lock_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_schedule_entry_lock_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_schedule_entry_lock_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_schedule_entry_lock_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.slots_week_day = true;
++ force_update.slots_year_day = true;
++ force_update.signtzo = true;
++ force_update.hourtzo = true;
++ force_update.minutetzo = true;
++ force_update.dst_offset_sign = true;
++ force_update.dst_offset_minute = true;
++ force_update.number_of_slots_daily_repeating = true;
++ trigger_handler = true;
++ } else {
++ std::unordered_map supported_attrs = {
++ {"SlotsWeekDay", &force_update.slots_week_day },
++ {"SlotsYearDay", &force_update.slots_year_day },
++ {"SignTZO", &force_update.signtzo },
++ {"HourTZO", &force_update.hourtzo },
++ {"MinuteTZO", &force_update.minutetzo },
++ {"DSTOffsetSign", &force_update.dst_offset_sign },
++ {"DSTOffsetMinute", &force_update.dst_offset_minute },
++ {"NumberOfSlotsDailyRepeating", &force_update.number_of_slots_daily_repeating },
++ };
++
++ 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_schedule_entry_lock_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, "UnifyScheduleEntryLock/Commands/ForceReadAttributes: Unable to parse JSON payload");
++ return;
++ }
++}
++
++sl_status_t uic_mqtt_dotdot_unify_schedule_entry_lock_slots_week_day_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(64801,1,value)) {
++ jsn["value"] = uic_dotdot_get_attribute_value_name(64801,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, "UnifyScheduleEntryLock/Attributes/SlotsWeekDay", e.what());
++ return SL_STATUS_OK;
++ }
++
++
++ std::string topic = std::string(base_topic) + "/UnifyScheduleEntryLock/Attributes/SlotsWeekDay";
++ 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_schedule_entry_lock_slots_week_day_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type)
++{
++ // clang-format on
++ std::string topic
++ = std::string(base_topic)
++ + "/UnifyScheduleEntryLock/Attributes/SlotsWeekDay";
++
++ 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_schedule_entry_lock_slots_year_day_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(64801,2,value)) {
++ jsn["value"] = uic_dotdot_get_attribute_value_name(64801,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, "UnifyScheduleEntryLock/Attributes/SlotsYearDay", e.what());
++ return SL_STATUS_OK;
++ }
++
++
++ std::string topic = std::string(base_topic) + "/UnifyScheduleEntryLock/Attributes/SlotsYearDay";
++ 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_schedule_entry_lock_slots_year_day_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type)
++{
++ // clang-format on
++ std::string topic
++ = std::string(base_topic)
++ + "/UnifyScheduleEntryLock/Attributes/SlotsYearDay";
++
++ 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_schedule_entry_lock_signtzo_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(64801,3,value)) {
++ jsn["value"] = uic_dotdot_get_attribute_value_name(64801,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, "UnifyScheduleEntryLock/Attributes/SignTZO", e.what());
++ return SL_STATUS_OK;
++ }
++
++
++ std::string topic = std::string(base_topic) + "/UnifyScheduleEntryLock/Attributes/SignTZO";
++ 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_schedule_entry_lock_signtzo_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type)
++{
++ // clang-format on
++ std::string topic
++ = std::string(base_topic)
++ + "/UnifyScheduleEntryLock/Attributes/SignTZO";
++
++ 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_schedule_entry_lock_hourtzo_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(64801,4,value)) {
++ jsn["value"] = uic_dotdot_get_attribute_value_name(64801,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, "UnifyScheduleEntryLock/Attributes/HourTZO", e.what());
++ return SL_STATUS_OK;
++ }
++
++
++ std::string topic = std::string(base_topic) + "/UnifyScheduleEntryLock/Attributes/HourTZO";
++ 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_schedule_entry_lock_hourtzo_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type)
++{
++ // clang-format on
++ std::string topic
++ = std::string(base_topic)
++ + "/UnifyScheduleEntryLock/Attributes/HourTZO";
++
++ 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_schedule_entry_lock_minutetzo_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(64801,5,value)) {
++ jsn["value"] = uic_dotdot_get_attribute_value_name(64801,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, "UnifyScheduleEntryLock/Attributes/MinuteTZO", e.what());
++ return SL_STATUS_OK;
++ }
++
++
++ std::string topic = std::string(base_topic) + "/UnifyScheduleEntryLock/Attributes/MinuteTZO";
++ 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_schedule_entry_lock_minutetzo_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type)
++{
++ // clang-format on
++ std::string topic
++ = std::string(base_topic)
++ + "/UnifyScheduleEntryLock/Attributes/MinuteTZO";
++
++ 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_schedule_entry_lock_dst_offset_sign_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(64801,6,value)) {
++ jsn["value"] = uic_dotdot_get_attribute_value_name(64801,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, "UnifyScheduleEntryLock/Attributes/DSTOffsetSign", e.what());
++ return SL_STATUS_OK;
++ }
++
++
++ std::string topic = std::string(base_topic) + "/UnifyScheduleEntryLock/Attributes/DSTOffsetSign";
++ 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_schedule_entry_lock_dst_offset_sign_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type)
++{
++ // clang-format on
++ std::string topic
++ = std::string(base_topic)
++ + "/UnifyScheduleEntryLock/Attributes/DSTOffsetSign";
++
++ 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_schedule_entry_lock_dst_offset_minute_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(64801,7,value)) {
++ jsn["value"] = uic_dotdot_get_attribute_value_name(64801,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, "UnifyScheduleEntryLock/Attributes/DSTOffsetMinute", e.what());
++ return SL_STATUS_OK;
++ }
++
++
++ std::string topic = std::string(base_topic) + "/UnifyScheduleEntryLock/Attributes/DSTOffsetMinute";
++ 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_schedule_entry_lock_dst_offset_minute_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type)
++{
++ // clang-format on
++ std::string topic
++ = std::string(base_topic)
++ + "/UnifyScheduleEntryLock/Attributes/DSTOffsetMinute";
++
++ 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_schedule_entry_lock_number_of_slots_daily_repeating_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(64801,8,value)) {
++ jsn["value"] = uic_dotdot_get_attribute_value_name(64801,8,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, "UnifyScheduleEntryLock/Attributes/NumberOfSlotsDailyRepeating", e.what());
++ return SL_STATUS_OK;
++ }
++
++
++ std::string topic = std::string(base_topic) + "/UnifyScheduleEntryLock/Attributes/NumberOfSlotsDailyRepeating";
++ 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_schedule_entry_lock_number_of_slots_daily_repeating_unretain(
++ const char *base_topic,
++ uic_mqtt_dotdot_attribute_publish_type_t publish_type)
++{
++ // clang-format on
++ std::string topic
++ = std::string(base_topic)
++ + "/UnifyScheduleEntryLock/Attributes/NumberOfSlotsDailyRepeating";
++
++ 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_schedule_entry_lock_init()
++{
++ std::string base_topic = "ucl/by-unid/+/+/";
++
++ std::string subscription_topic;
++ if(!uic_mqtt_dotdot_unify_schedule_entry_lock_write_attributes_callback.empty()) {
++ subscription_topic = base_topic + "UnifyScheduleEntryLock/Commands/WriteAttributes";
++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_unify_schedule_entry_lock_WriteAttributes);
++ }
++
++ if(!uic_mqtt_dotdot_unify_schedule_entry_lock_force_read_attributes_callback.empty()) {
++ subscription_topic = base_topic + "UnifyScheduleEntryLock/Commands/ForceReadAttributes";
++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_unify_schedule_entry_lock_force_read_attributes);
++ }
++ if (!uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback.empty()) {
++ subscription_topic = base_topic + "UnifyScheduleEntryLock/Commands/ScheduleEntryLockWeekDayReport";
++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_unify_schedule_entry_lock_schedule_entry_lock_week_day_report);
++ }
++ if (!uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_week_day_report_callback.empty()) {
++ subscription_topic = base_topic + "UnifyScheduleEntryLock/GeneratedCommands/ScheduleEntryLockWeekDayReport";
++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_generated_unify_schedule_entry_lock_schedule_entry_lock_week_day_report);
++ }
++ if (!uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback.empty()) {
++ subscription_topic = base_topic + "UnifyScheduleEntryLock/Commands/ScheduleEntryLockYearDayReport";
++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_unify_schedule_entry_lock_schedule_entry_lock_year_day_report);
++ }
++ if (!uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_year_day_report_callback.empty()) {
++ subscription_topic = base_topic + "UnifyScheduleEntryLock/GeneratedCommands/ScheduleEntryLockYearDayReport";
++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_generated_unify_schedule_entry_lock_schedule_entry_lock_year_day_report);
++ }
++ if (!uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback.empty()) {
++ subscription_topic = base_topic + "UnifyScheduleEntryLock/Commands/ScheduleEntryLockDailyRepeatingReport";
++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report);
++ }
++ if (!uic_mqtt_dotdot_unify_schedule_entry_lock_generated_schedule_entry_lock_daily_repeating_report_callback.empty()) {
++ subscription_topic = base_topic + "UnifyScheduleEntryLock/GeneratedCommands/ScheduleEntryLockDailyRepeatingReport";
++ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_generated_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report);
++ }
++
++ // Init the attributes for that cluster
++ uic_mqtt_dotdot_unify_schedule_entry_lock_attributes_init();
++
++ uic_mqtt_dotdot_by_group_unify_schedule_entry_lock_init();
++
++ return SL_STATUS_OK;
++}
++
+ // Callbacks pointers
+ static std::set uic_mqtt_dotdot_unify_humidity_control_mode_set_callback;
+ static std::set uic_mqtt_dotdot_unify_humidity_control_generated_mode_set_callback;
+@@ -96101,6 +97581,10 @@ sl_status_t uic_mqtt_dotdot_init() {
+ status_flag = uic_mqtt_dotdot_unify_thermostat_init();
+ }
+
++ if (status_flag == SL_STATUS_OK) {
++ status_flag = uic_mqtt_dotdot_unify_schedule_entry_lock_init();
++ }
++
+ if (status_flag == SL_STATUS_OK) {
+ status_flag = uic_mqtt_dotdot_unify_humidity_control_init();
+ }
+@@ -96167,6 +97651,7 @@ void uic_mqtt_dotdot_publish_supported_commands(
+ uic_mqtt_dotdot_descriptor_publish_supported_commands(unid, endpoint_id);
+ 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_schedule_entry_lock_publish_supported_commands(unid, endpoint_id);
+ uic_mqtt_dotdot_unify_humidity_control_publish_supported_commands(unid, endpoint_id);
+ }
+
+@@ -96227,6 +97712,7 @@ void uic_mqtt_dotdot_publish_empty_supported_commands(
+ uic_mqtt_dotdot_descriptor_publish_empty_supported_commands(unid, endpoint_id);
+ 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_schedule_entry_lock_publish_empty_supported_commands(unid, endpoint_id);
+ uic_mqtt_dotdot_unify_humidity_control_publish_empty_supported_commands(unid, endpoint_id);
+ }
+
+@@ -109531,8 +111017,170 @@ static inline bool uic_mqtt_dotdot_unify_fan_control_write_attributes_is_support
+ unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK,
+- unify_fan_control_new_state,
+- unify_fan_control_new_updated_state
++ unify_fan_control_new_state,
++ unify_fan_control_new_updated_state
++ ) == SL_STATUS_OK) {
++ return true;
++ }
++ }
++ return false;
++}
++
++static inline bool uic_mqtt_dotdot_unify_fan_control_force_read_attributes_is_supported(
++ const dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint_id)
++{
++ for (const auto& callback: uic_mqtt_dotdot_unify_fan_control_force_read_attributes_callback) {
++ uic_mqtt_dotdot_unify_fan_control_updated_state_t unify_fan_control_force_update = {0};
++ if (callback(
++ unid,
++ endpoint_id,
++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK,
++ unify_fan_control_force_update
++ ) == SL_STATUS_OK) {
++ return true;
++ }
++ }
++ return false;
++}
++
++// Publishing Supported Commands for UnifyFanControl Cluster
++void uic_mqtt_dotdot_unify_fan_control_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_fan_control_set_fan_mode_is_supported(unid, endpoint_id)) {
++ if (first_command == false) {
++ ss << ", ";
++ }
++ first_command = false;
++ ss << R"("SetFanMode")";
++ }
++ if (uic_mqtt_dotdot_unify_fan_control_turn_off_is_supported(unid, endpoint_id)) {
++ if (first_command == false) {
++ ss << ", ";
++ }
++ first_command = false;
++ ss << R"("TurnOff")";
++ }
++
++ // Check for a WriteAttributes Callback
++ if(uic_mqtt_dotdot_unify_fan_control_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_fan_control_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 += "/UnifyFanControl/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 += "/UnifyFanControl/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 UnifyFanControl Cluster
++void uic_mqtt_dotdot_unify_fan_control_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 += "/UnifyFanControl/SupportedCommands";
++
++ if (uic_mqtt_count_topics(topic.c_str()) > 0) {
++ uic_mqtt_publish(topic.c_str(),
++ EMPTY_VALUE_ARRAY,
++ strlen(EMPTY_VALUE_ARRAY),
++ true);
++ }
++}
++
++// Publishing Cluster Revision for UnifyThermostat Cluster
++void uic_mqtt_dotdot_unify_thermostat_publish_cluster_revision(const char* base_topic, uint16_t value)
++{
++ std::string cluster_topic = std::string(base_topic) + "/UnifyThermostat/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 UnifyThermostat Cluster
++void uic_mqtt_dotdot_unify_thermostat_unretain_cluster_revision(const char* base_topic)
++{
++ // clang-format on
++ std::string cluster_topic
++ = std::string(base_topic)
++ + "/UnifyThermostat/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_thermostat_write_attributes_is_supported(
++ const dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint_id)
++{
++ for (const auto& callback: uic_mqtt_dotdot_unify_thermostat_write_attributes_callback) {
++ uic_mqtt_dotdot_unify_thermostat_state_t unify_thermostat_new_state = {};
++ uic_mqtt_dotdot_unify_thermostat_updated_state_t unify_thermostat_new_updated_state = {};
++
++ if (callback(
++ unid,
++ endpoint_id,
++ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK,
++ unify_thermostat_new_state,
++ unify_thermostat_new_updated_state
+ ) == SL_STATUS_OK) {
+ return true;
+ }
+@@ -109540,17 +111188,17 @@ static inline bool uic_mqtt_dotdot_unify_fan_control_write_attributes_is_support
+ return false;
+ }
+
+-static inline bool uic_mqtt_dotdot_unify_fan_control_force_read_attributes_is_supported(
++static inline bool uic_mqtt_dotdot_unify_thermostat_force_read_attributes_is_supported(
+ const dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint_id)
+ {
+- for (const auto& callback: uic_mqtt_dotdot_unify_fan_control_force_read_attributes_callback) {
+- uic_mqtt_dotdot_unify_fan_control_updated_state_t unify_fan_control_force_update = {0};
++ for (const auto& callback: uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback) {
++ uic_mqtt_dotdot_unify_thermostat_updated_state_t unify_thermostat_force_update = {0};
+ if (callback(
+ unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK,
+- unify_fan_control_force_update
++ unify_thermostat_force_update
+ ) == SL_STATUS_OK) {
+ return true;
+ }
+@@ -109558,8 +111206,8 @@ static inline bool uic_mqtt_dotdot_unify_fan_control_force_read_attributes_is_su
+ return false;
+ }
+
+-// Publishing Supported Commands for UnifyFanControl Cluster
+-void uic_mqtt_dotdot_unify_fan_control_publish_supported_commands(
++// Publishing Supported Commands for UnifyThermostat Cluster
++void uic_mqtt_dotdot_unify_thermostat_publish_supported_commands(
+ const dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint_id)
+ {
+@@ -109568,23 +111216,9 @@ void uic_mqtt_dotdot_unify_fan_control_publish_supported_commands(
+ ss.str("");
+
+ // check if there is callback for each command
+- if (uic_mqtt_dotdot_unify_fan_control_set_fan_mode_is_supported(unid, endpoint_id)) {
+- if (first_command == false) {
+- ss << ", ";
+- }
+- first_command = false;
+- ss << R"("SetFanMode")";
+- }
+- if (uic_mqtt_dotdot_unify_fan_control_turn_off_is_supported(unid, endpoint_id)) {
+- if (first_command == false) {
+- ss << ", ";
+- }
+- first_command = false;
+- ss << R"("TurnOff")";
+- }
+
+ // Check for a WriteAttributes Callback
+- if(uic_mqtt_dotdot_unify_fan_control_write_attributes_is_supported(unid, endpoint_id)) {
++ if(uic_mqtt_dotdot_unify_thermostat_write_attributes_is_supported(unid, endpoint_id)) {
+ if (first_command == false) {
+ ss << ", ";
+ }
+@@ -109593,7 +111227,7 @@ void uic_mqtt_dotdot_unify_fan_control_publish_supported_commands(
+ }
+
+ // Check for a ForceReadAttributes Callback
+- if (uic_mqtt_dotdot_unify_fan_control_force_read_attributes_is_supported(unid, endpoint_id)) {
++ if (uic_mqtt_dotdot_unify_thermostat_force_read_attributes_is_supported(unid, endpoint_id)) {
+ if (first_command == false) {
+ ss << ", ";
+ }
+@@ -109604,7 +111238,7 @@ void uic_mqtt_dotdot_unify_fan_control_publish_supported_commands(
+ // Publish supported commands
+ std::string topic = "ucl/by-unid/" + std::string(unid);
+ topic += "/ep"+ std::to_string(endpoint_id);
+- topic += "/UnifyFanControl/SupportedCommands";
++ topic += "/UnifyThermostat/SupportedCommands";
+ std::string payload_str("{\"value\": [" + ss.str() + "]" + "}");
+ if (first_command == false) {
+ uic_mqtt_publish(topic.c_str(),
+@@ -109616,7 +111250,7 @@ void uic_mqtt_dotdot_unify_fan_control_publish_supported_commands(
+ // 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 += "/UnifyFanControl/Attributes";
++ attributes_topic += "/UnifyThermostat/Attributes";
+
+ if (uic_mqtt_count_topics(attributes_topic.c_str()) > 0) {
+ uic_mqtt_publish(topic.c_str(),
+@@ -109627,14 +111261,14 @@ void uic_mqtt_dotdot_unify_fan_control_publish_supported_commands(
+ }
+ }
+
+-// Publishing empty/no Supported Commands for UnifyFanControl Cluster
+-void uic_mqtt_dotdot_unify_fan_control_publish_empty_supported_commands(
++// Publishing empty/no Supported Commands for UnifyThermostat Cluster
++void uic_mqtt_dotdot_unify_thermostat_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 += "/UnifyFanControl/SupportedCommands";
++ topic += "/UnifyThermostat/SupportedCommands";
+
+ if (uic_mqtt_count_topics(topic.c_str()) > 0) {
+ uic_mqtt_publish(topic.c_str(),
+@@ -109644,10 +111278,10 @@ void uic_mqtt_dotdot_unify_fan_control_publish_empty_supported_commands(
+ }
+ }
+
+-// Publishing Cluster Revision for UnifyThermostat Cluster
+-void uic_mqtt_dotdot_unify_thermostat_publish_cluster_revision(const char* base_topic, uint16_t value)
++// Publishing Cluster Revision for UnifyScheduleEntryLock Cluster
++void uic_mqtt_dotdot_unify_schedule_entry_lock_publish_cluster_revision(const char* base_topic, uint16_t value)
+ {
+- std::string cluster_topic = std::string(base_topic) + "/UnifyThermostat/Attributes/ClusterRevision";
++ std::string cluster_topic = std::string(base_topic) + "/UnifyScheduleEntryLock/Attributes/ClusterRevision";
+ // Publish Desired
+ std::string pub_topic_des = cluster_topic + "/Desired";
+ std::string payload = std::string(R"({"value": )")
+@@ -109664,13 +111298,13 @@ void uic_mqtt_dotdot_unify_thermostat_publish_cluster_revision(const char* base_
+ true);
+ }
+
+-// Unretain Cluster Revision for UnifyThermostat Cluster
+-void uic_mqtt_dotdot_unify_thermostat_unretain_cluster_revision(const char* base_topic)
++// Unretain Cluster Revision for UnifyScheduleEntryLock Cluster
++void uic_mqtt_dotdot_unify_schedule_entry_lock_unretain_cluster_revision(const char* base_topic)
+ {
+ // clang-format on
+ std::string cluster_topic
+ = std::string(base_topic)
+- + "/UnifyThermostat/Attributes/ClusterRevision";
++ + "/UnifyScheduleEntryLock/Attributes/ClusterRevision";
+ // Publish Desired
+ std::string desired_topic = cluster_topic + "/Desired";
+ uic_mqtt_publish(desired_topic.c_str(), NULL, 0, true);
+@@ -109680,21 +111314,167 @@ void uic_mqtt_dotdot_unify_thermostat_unretain_cluster_revision(const char* base
+ // clang-format off
+ }
+
++static inline bool uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_is_supported(
++ const dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint_id)
++{
++ uint8_t user_identifier_value;
++ memset(&user_identifier_value, 0x00, sizeof(user_identifier_value));
++ uint8_t schedule_slotid_value;
++ memset(&schedule_slotid_value, 0x00, sizeof(schedule_slotid_value));
++ uint8_t day_of_week_value;
++ memset(&day_of_week_value, 0x00, sizeof(day_of_week_value));
++ uint8_t start_hour_value;
++ memset(&start_hour_value, 0x00, sizeof(start_hour_value));
++ uint8_t start_minute_value;
++ memset(&start_minute_value, 0x00, sizeof(start_minute_value));
++ uint8_t stop_hour_value;
++ memset(&stop_hour_value, 0x00, sizeof(stop_hour_value));
++ uint8_t stop_minute_value;
++ memset(&stop_minute_value, 0x00, sizeof(stop_minute_value));
++ for (const auto& callback: uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback) {
++ if (callback( unid, endpoint_id, UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK
++ ,
++ user_identifier_value,
++
++ schedule_slotid_value,
++
++ day_of_week_value,
++
++ start_hour_value,
++
++ start_minute_value,
++
++ stop_hour_value,
++
++ stop_minute_value
++
++ ) == SL_STATUS_OK) {
++ return true;
++ }
++ }
++
++ return false;
++}
++static inline bool uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_is_supported(
++ const dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint_id)
++{
++ uint8_t set_action_value;
++ memset(&set_action_value, 0x00, sizeof(set_action_value));
++ uint8_t user_identifier_value;
++ memset(&user_identifier_value, 0x00, sizeof(user_identifier_value));
++ uint8_t schedule_slotid_value;
++ memset(&schedule_slotid_value, 0x00, sizeof(schedule_slotid_value));
++ uint8_t start_year_value;
++ memset(&start_year_value, 0x00, sizeof(start_year_value));
++ uint8_t start_day_value;
++ memset(&start_day_value, 0x00, sizeof(start_day_value));
++ uint8_t start_hour_value;
++ memset(&start_hour_value, 0x00, sizeof(start_hour_value));
++ uint8_t start_minute_value;
++ memset(&start_minute_value, 0x00, sizeof(start_minute_value));
++ uint8_t stop_year_value;
++ memset(&stop_year_value, 0x00, sizeof(stop_year_value));
++ uint8_t stop_day_value;
++ memset(&stop_day_value, 0x00, sizeof(stop_day_value));
++ uint8_t stop_hour_value;
++ memset(&stop_hour_value, 0x00, sizeof(stop_hour_value));
++ uint8_t stop_minute_value;
++ memset(&stop_minute_value, 0x00, sizeof(stop_minute_value));
++ for (const auto& callback: uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback) {
++ if (callback( unid, endpoint_id, UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK
++ ,
++ set_action_value,
++
++ user_identifier_value,
++
++ schedule_slotid_value,
++
++ start_year_value,
++
++ start_day_value,
++
++ start_hour_value,
++
++ start_minute_value,
++
++ stop_year_value,
++
++ stop_day_value,
++
++ stop_hour_value,
++
++ stop_minute_value
++
++ ) == SL_STATUS_OK) {
++ return true;
++ }
++ }
+
+-static inline bool uic_mqtt_dotdot_unify_thermostat_write_attributes_is_supported(
++ return false;
++}
++static inline bool uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_is_supported(
+ const dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint_id)
+ {
+- for (const auto& callback: uic_mqtt_dotdot_unify_thermostat_write_attributes_callback) {
+- uic_mqtt_dotdot_unify_thermostat_state_t unify_thermostat_new_state = {};
+- uic_mqtt_dotdot_unify_thermostat_updated_state_t unify_thermostat_new_updated_state = {};
++ uint8_t set_action_value;
++ memset(&set_action_value, 0x00, sizeof(set_action_value));
++ uint8_t user_identifier_value;
++ memset(&user_identifier_value, 0x00, sizeof(user_identifier_value));
++ uint8_t schedule_slotid_value;
++ memset(&schedule_slotid_value, 0x00, sizeof(schedule_slotid_value));
++ uint8_t week_day_bitmask_value;
++ memset(&week_day_bitmask_value, 0x00, sizeof(week_day_bitmask_value));
++ uint8_t start_hour_value;
++ memset(&start_hour_value, 0x00, sizeof(start_hour_value));
++ uint8_t start_minute_value;
++ memset(&start_minute_value, 0x00, sizeof(start_minute_value));
++ uint8_t duration_hour_value;
++ memset(&duration_hour_value, 0x00, sizeof(duration_hour_value));
++ uint8_t duration_minute_value;
++ memset(&duration_minute_value, 0x00, sizeof(duration_minute_value));
++ for (const auto& callback: uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback) {
++ if (callback( unid, endpoint_id, UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK
++ ,
++ set_action_value,
++
++ user_identifier_value,
++
++ schedule_slotid_value,
++
++ week_day_bitmask_value,
++
++ start_hour_value,
++
++ start_minute_value,
++
++ duration_hour_value,
++
++ duration_minute_value
++
++ ) == SL_STATUS_OK) {
++ return true;
++ }
++ }
++
++ return false;
++}
++
++static inline bool uic_mqtt_dotdot_unify_schedule_entry_lock_write_attributes_is_supported(
++ const dotdot_unid_t unid,
++ dotdot_endpoint_id_t endpoint_id)
++{
++ for (const auto& callback: uic_mqtt_dotdot_unify_schedule_entry_lock_write_attributes_callback) {
++ uic_mqtt_dotdot_unify_schedule_entry_lock_state_t unify_schedule_entry_lock_new_state = {};
++ uic_mqtt_dotdot_unify_schedule_entry_lock_updated_state_t unify_schedule_entry_lock_new_updated_state = {};
+
+ if (callback(
+ unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK,
+- unify_thermostat_new_state,
+- unify_thermostat_new_updated_state
++ unify_schedule_entry_lock_new_state,
++ unify_schedule_entry_lock_new_updated_state
+ ) == SL_STATUS_OK) {
+ return true;
+ }
+@@ -109702,17 +111482,17 @@ static inline bool uic_mqtt_dotdot_unify_thermostat_write_attributes_is_supporte
+ return false;
+ }
+
+-static inline bool uic_mqtt_dotdot_unify_thermostat_force_read_attributes_is_supported(
++static inline bool uic_mqtt_dotdot_unify_schedule_entry_lock_force_read_attributes_is_supported(
+ const dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint_id)
+ {
+- for (const auto& callback: uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback) {
+- uic_mqtt_dotdot_unify_thermostat_updated_state_t unify_thermostat_force_update = {0};
++ for (const auto& callback: uic_mqtt_dotdot_unify_schedule_entry_lock_force_read_attributes_callback) {
++ uic_mqtt_dotdot_unify_schedule_entry_lock_updated_state_t unify_schedule_entry_lock_force_update = {0};
+ if (callback(
+ unid,
+ endpoint_id,
+ UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK,
+- unify_thermostat_force_update
++ unify_schedule_entry_lock_force_update
+ ) == SL_STATUS_OK) {
+ return true;
+ }
+@@ -109720,8 +111500,8 @@ static inline bool uic_mqtt_dotdot_unify_thermostat_force_read_attributes_is_sup
+ return false;
+ }
+
+-// Publishing Supported Commands for UnifyThermostat Cluster
+-void uic_mqtt_dotdot_unify_thermostat_publish_supported_commands(
++// Publishing Supported Commands for UnifyScheduleEntryLock Cluster
++void uic_mqtt_dotdot_unify_schedule_entry_lock_publish_supported_commands(
+ const dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint_id)
+ {
+@@ -109730,9 +111510,30 @@ void uic_mqtt_dotdot_unify_thermostat_publish_supported_commands(
+ ss.str("");
+
+ // check if there is callback for each command
++ if (uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_is_supported(unid, endpoint_id)) {
++ if (first_command == false) {
++ ss << ", ";
++ }
++ first_command = false;
++ ss << R"("ScheduleEntryLockWeekDayReport")";
++ }
++ if (uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_is_supported(unid, endpoint_id)) {
++ if (first_command == false) {
++ ss << ", ";
++ }
++ first_command = false;
++ ss << R"("ScheduleEntryLockYearDayReport")";
++ }
++ if (uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_is_supported(unid, endpoint_id)) {
++ if (first_command == false) {
++ ss << ", ";
++ }
++ first_command = false;
++ ss << R"("ScheduleEntryLockDailyRepeatingReport")";
++ }
+
+ // Check for a WriteAttributes Callback
+- if(uic_mqtt_dotdot_unify_thermostat_write_attributes_is_supported(unid, endpoint_id)) {
++ if(uic_mqtt_dotdot_unify_schedule_entry_lock_write_attributes_is_supported(unid, endpoint_id)) {
+ if (first_command == false) {
+ ss << ", ";
+ }
+@@ -109741,7 +111542,7 @@ void uic_mqtt_dotdot_unify_thermostat_publish_supported_commands(
+ }
+
+ // Check for a ForceReadAttributes Callback
+- if (uic_mqtt_dotdot_unify_thermostat_force_read_attributes_is_supported(unid, endpoint_id)) {
++ if (uic_mqtt_dotdot_unify_schedule_entry_lock_force_read_attributes_is_supported(unid, endpoint_id)) {
+ if (first_command == false) {
+ ss << ", ";
+ }
+@@ -109752,7 +111553,7 @@ void uic_mqtt_dotdot_unify_thermostat_publish_supported_commands(
+ // Publish supported commands
+ std::string topic = "ucl/by-unid/" + std::string(unid);
+ topic += "/ep"+ std::to_string(endpoint_id);
+- topic += "/UnifyThermostat/SupportedCommands";
++ topic += "/UnifyScheduleEntryLock/SupportedCommands";
+ std::string payload_str("{\"value\": [" + ss.str() + "]" + "}");
+ if (first_command == false) {
+ uic_mqtt_publish(topic.c_str(),
+@@ -109764,7 +111565,7 @@ void uic_mqtt_dotdot_unify_thermostat_publish_supported_commands(
+ // 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 += "/UnifyThermostat/Attributes";
++ attributes_topic += "/UnifyScheduleEntryLock/Attributes";
+
+ if (uic_mqtt_count_topics(attributes_topic.c_str()) > 0) {
+ uic_mqtt_publish(topic.c_str(),
+@@ -109775,14 +111576,14 @@ void uic_mqtt_dotdot_unify_thermostat_publish_supported_commands(
+ }
+ }
+
+-// Publishing empty/no Supported Commands for UnifyThermostat Cluster
+-void uic_mqtt_dotdot_unify_thermostat_publish_empty_supported_commands(
++// Publishing empty/no Supported Commands for UnifyScheduleEntryLock Cluster
++void uic_mqtt_dotdot_unify_schedule_entry_lock_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 += "/UnifyThermostat/SupportedCommands";
++ topic += "/UnifyScheduleEntryLock/SupportedCommands";
+
+ if (uic_mqtt_count_topics(topic.c_str()) > 0) {
+ uic_mqtt_publish(topic.c_str(),
+@@ -116638,6 +118439,114 @@ void uic_mqtt_dotdot_unify_fan_control_publish_generated_turn_off_command(
+ payload.size(),
+ false);
+ }
++/**
++ * @brief Publishes an incoming/generated ScheduleEntryLockWeekDayReport command for
++ * the UnifyScheduleEntryLock cluster.
++ *
++ * Publication will be made at the following topic
++ * ucl/by-unid/UNID/epID/UnifyScheduleEntryLock/GeneratedCommands/ScheduleEntryLockWeekDayReport
++ *
++ * @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_schedule_entry_lock_publish_generated_schedule_entry_lock_week_day_report_command(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint,
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_week_day_report_fields_t *fields
++
++) {
++ // Create the topic
++ std::string topic = "ucl/by-unid/"+ std::string(unid) + "/ep" +
++ std::to_string(endpoint) + "/";
++ topic += "UnifyScheduleEntryLock/GeneratedCommands/ScheduleEntryLockWeekDayReport";
++
++ std::string payload =
++ get_json_payload_for_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_command(
++ fields);
++
++ // Publish our command
++ uic_mqtt_publish(topic.c_str(),
++ payload.c_str(),
++ payload.size(),
++ false);
++}
++/**
++ * @brief Publishes an incoming/generated ScheduleEntryLockYearDayReport command for
++ * the UnifyScheduleEntryLock cluster.
++ *
++ * Publication will be made at the following topic
++ * ucl/by-unid/UNID/epID/UnifyScheduleEntryLock/GeneratedCommands/ScheduleEntryLockYearDayReport
++ *
++ * @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_schedule_entry_lock_publish_generated_schedule_entry_lock_year_day_report_command(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint,
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_year_day_report_fields_t *fields
++
++) {
++ // Create the topic
++ std::string topic = "ucl/by-unid/"+ std::string(unid) + "/ep" +
++ std::to_string(endpoint) + "/";
++ topic += "UnifyScheduleEntryLock/GeneratedCommands/ScheduleEntryLockYearDayReport";
++
++ std::string payload =
++ get_json_payload_for_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_command(
++ fields);
++
++ // Publish our command
++ uic_mqtt_publish(topic.c_str(),
++ payload.c_str(),
++ payload.size(),
++ false);
++}
++/**
++ * @brief Publishes an incoming/generated ScheduleEntryLockDailyRepeatingReport command for
++ * the UnifyScheduleEntryLock cluster.
++ *
++ * Publication will be made at the following topic
++ * ucl/by-unid/UNID/epID/UnifyScheduleEntryLock/GeneratedCommands/ScheduleEntryLockDailyRepeatingReport
++ *
++ * @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_schedule_entry_lock_publish_generated_schedule_entry_lock_daily_repeating_report_command(
++ const dotdot_unid_t unid,
++ const dotdot_endpoint_id_t endpoint,
++ const uic_mqtt_dotdot_unify_schedule_entry_lock_command_schedule_entry_lock_daily_repeating_report_fields_t *fields
++
++) {
++ // Create the topic
++ std::string topic = "ucl/by-unid/"+ std::string(unid) + "/ep" +
++ std::to_string(endpoint) + "/";
++ topic += "UnifyScheduleEntryLock/GeneratedCommands/ScheduleEntryLockDailyRepeatingReport";
++
++ std::string payload =
++ get_json_payload_for_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_command(
++ fields);
++
++ // Publish our command
++ uic_mqtt_publish(topic.c_str(),
++ payload.c_str(),
++ payload.size(),
++ false);
++}
+ /**
+ * @brief Publishes an incoming/generated ModeSet command for
+ * the UnifyHumidityControl cluster.
+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 9fbbc1ede6..bb5785ac9c 100644
+--- a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.hpp
++++ b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.hpp
+@@ -371,6 +371,13 @@ sl_status_t uic_mqtt_dotdot_by_group_unify_fan_control_init();
+ */
+ sl_status_t uic_mqtt_dotdot_by_group_unify_thermostat_init();
+
++/**
++ * @brief Initialize UnifyScheduleEntryLock dotdot bygroup command handlers
++ *
++ * @returns SL_STATUS_OK on success, error otherwise.
++ */
++sl_status_t uic_mqtt_dotdot_by_group_unify_schedule_entry_lock_init();
++
+ /**
+ * @brief Initialize UnifyHumidityControl dotdot bygroup command handlers
+ *
+@@ -5063,6 +5070,84 @@ void uic_mqtt_dotdot_on_unify_fan_control_WriteAttributes(
+ const size_t message_length);
+
+
++// clang-format on
++
++/**
++ * @brief Retrieves the container with callbacks pointer for
++ * by-unid UnifyScheduleEntryLock/Commands/ScheduleEntryLockWeekDayReport messages
++ *
++ * @returns std::set of callbacks.
++ */
++std::set &get_uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_week_day_report_callback();
++
++/**
++ * @brief MQTT Subscribe handler for incoming publications on:
++ * ucl/by-unid/+/+/UnifyScheduleEntryLock/Commands/ScheduleEntryLockWeekDayReport
++ */
++// clang-format off
++void uic_mqtt_dotdot_on_unify_schedule_entry_lock_schedule_entry_lock_week_day_report(
++ const char *topic,
++ const char *message,
++ const size_t message_length);
++// clang-format on
++
++/**
++ * @brief Retrieves the container with callbacks pointer for
++ * by-unid UnifyScheduleEntryLock/Commands/ScheduleEntryLockYearDayReport messages
++ *
++ * @returns std::set of callbacks.
++ */
++std::set &get_uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_year_day_report_callback();
++
++/**
++ * @brief MQTT Subscribe handler for incoming publications on:
++ * ucl/by-unid/+/+/UnifyScheduleEntryLock/Commands/ScheduleEntryLockYearDayReport
++ */
++// clang-format off
++void uic_mqtt_dotdot_on_unify_schedule_entry_lock_schedule_entry_lock_year_day_report(
++ const char *topic,
++ const char *message,
++ const size_t message_length);
++// clang-format on
++
++/**
++ * @brief Retrieves the container with callbacks pointer for
++ * by-unid UnifyScheduleEntryLock/Commands/ScheduleEntryLockDailyRepeatingReport messages
++ *
++ * @returns std::set of callbacks.
++ */
++std::set &get_uic_mqtt_dotdot_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report_callback();
++
++/**
++ * @brief MQTT Subscribe handler for incoming publications on:
++ * ucl/by-unid/+/+/UnifyScheduleEntryLock/Commands/ScheduleEntryLockDailyRepeatingReport
++ */
++// clang-format off
++void uic_mqtt_dotdot_on_unify_schedule_entry_lock_schedule_entry_lock_daily_repeating_report(
++ 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_schedule_entry_lock_write_attributes_callback();
++
++/**
++ * @brief MQTT Subscribe handler for incoming publications on:
++ * ucl/by-unid/+/+/UnifyScheduleEntryLock/Commands/WriteAttributes
++ */
++// clang-format off
++void uic_mqtt_dotdot_on_unify_schedule_entry_lock_WriteAttributes(
++ const char *topic,
++ const char *message,
++ const size_t message_length);
++
++
+ // clang-format on
+
+ /**
+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 25ce61e26a..d83f8e50ea 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
+@@ -62164,6 +62164,713 @@ void uic_mqtt_dotdot_unify_thermostat_attribute_operating_state_callback_set(con
+
+ // End of supported cluster.
+
++///////////////////////////////////////////////////////////////////////////////
++// Callback pointers for UnifyScheduleEntryLock
++///////////////////////////////////////////////////////////////////////////////
++static uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_slots_week_day_callback_t uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_slots_week_day_callback = nullptr;
++static uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_slots_year_day_callback_t uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_slots_year_day_callback = nullptr;
++static uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_signtzo_callback_t uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_signtzo_callback = nullptr;
++static uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_hourtzo_callback_t uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_hourtzo_callback = nullptr;
++static uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_minutetzo_callback_t uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_minutetzo_callback = nullptr;
++static uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_dst_offset_sign_callback_t uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_dst_offset_sign_callback = nullptr;
++static uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_dst_offset_minute_callback_t uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_dst_offset_minute_callback = nullptr;
++static uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_number_of_slots_daily_repeating_callback_t uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_number_of_slots_daily_repeating_callback = nullptr;
++
++///////////////////////////////////////////////////////////////////////////////
++// Attribute update handlers for UnifyScheduleEntryLock
++///////////////////////////////////////////////////////////////////////////////
++static void uic_mqtt_dotdot_on_unify_schedule_entry_lock_slots_week_day_attribute_update(
++ const char *topic,
++ const char *message,
++ const size_t message_length) {
++ if (uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_slots_week_day_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 slots_week_day = {};
++
++ 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, "UnifyScheduleEntryLock::SlotsWeekDay: Missing attribute element: 'value'\n");
++ return;
++ }
++// Start parsing value
++ slots_week_day = 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_schedule_entry_lock_attribute_slots_week_day_callback(
++ static_cast(unid.c_str()),
++ endpoint,
++ unretained,
++ update_type,
++ slots_week_day
++ );
++
++}
++static void uic_mqtt_dotdot_on_unify_schedule_entry_lock_slots_year_day_attribute_update(
++ const char *topic,
++ const char *message,
++ const size_t message_length) {
++ if (uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_slots_year_day_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 slots_year_day = {};
++
++ 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, "UnifyScheduleEntryLock::SlotsYearDay: Missing attribute element: 'value'\n");
++ return;
++ }
++// Start parsing value
++ slots_year_day = 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_schedule_entry_lock_attribute_slots_year_day_callback(
++ static_cast(unid.c_str()),
++ endpoint,
++ unretained,
++ update_type,
++ slots_year_day
++ );
++
++}
++static void uic_mqtt_dotdot_on_unify_schedule_entry_lock_signtzo_attribute_update(
++ const char *topic,
++ const char *message,
++ const size_t message_length) {
++ if (uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_signtzo_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 signtzo = {};
++
++ 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, "UnifyScheduleEntryLock::SignTZO: Missing attribute element: 'value'\n");
++ return;
++ }
++// Start parsing value
++ signtzo = 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_schedule_entry_lock_attribute_signtzo_callback(
++ static_cast(unid.c_str()),
++ endpoint,
++ unretained,
++ update_type,
++ signtzo
++ );
++
++}
++static void uic_mqtt_dotdot_on_unify_schedule_entry_lock_hourtzo_attribute_update(
++ const char *topic,
++ const char *message,
++ const size_t message_length) {
++ if (uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_hourtzo_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 hourtzo = {};
++
++ 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, "UnifyScheduleEntryLock::HourTZO: Missing attribute element: 'value'\n");
++ return;
++ }
++// Start parsing value
++ hourtzo = 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_schedule_entry_lock_attribute_hourtzo_callback(
++ static_cast(unid.c_str()),
++ endpoint,
++ unretained,
++ update_type,
++ hourtzo
++ );
++
++}
++static void uic_mqtt_dotdot_on_unify_schedule_entry_lock_minutetzo_attribute_update(
++ const char *topic,
++ const char *message,
++ const size_t message_length) {
++ if (uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_minutetzo_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 minutetzo = {};
++
++ 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, "UnifyScheduleEntryLock::MinuteTZO: Missing attribute element: 'value'\n");
++ return;
++ }
++// Start parsing value
++ minutetzo = 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_schedule_entry_lock_attribute_minutetzo_callback(
++ static_cast(unid.c_str()),
++ endpoint,
++ unretained,
++ update_type,
++ minutetzo
++ );
++
++}
++static void uic_mqtt_dotdot_on_unify_schedule_entry_lock_dst_offset_sign_attribute_update(
++ const char *topic,
++ const char *message,
++ const size_t message_length) {
++ if (uic_mqtt_dotdot_unify_schedule_entry_lock_attribute_dst_offset_sign_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 dst_offset_sign = {};
++
++ 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, "UnifyScheduleEntryLock::DSTOffsetSign: Missing attribute element: 'value'\n");
++ return;
++ }
++// Start parsing value
++ dst_offset_sign = json_payload.at("value").get