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 15eb5413cb..339469d26c 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
@@ -15863,5 +15863,5 @@ export let ClusterTypeAttrs: any = {
commands: [
]
}
- }
+ },
}
diff --git a/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/cluster-type-attributes.ts.rej b/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/cluster-type-attributes.ts.rej
new file mode 100644
index 0000000000..34b0a9a75f
--- /dev/null
+++ b/applications/dev_ui/dev_gui/zap-generated/src/cluster-types/cluster-type-attributes.ts.rej
@@ -0,0 +1,10 @@
+diff 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 (rejected hunks)
+@@ -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/applications/zpc/components/dotdot_mapper/rules/Thermostat.uam b/applications/zpc/components/dotdot_mapper/rules/Thermostat.uam
index 233aaeaea1..b75a1959d0 100644
--- a/applications/zpc/components/dotdot_mapper/rules/Thermostat.uam
+++ b/applications/zpc/components/dotdot_mapper/rules/Thermostat.uam
@@ -21,6 +21,9 @@ def zwTHERMOSTAT_MODE_VERSION 0x4001
def zwTHERMOSTAT_MODE 0x4002
def zwTHERMOSTAT_SUPPORTED_MODES 0x4003
+//Thermostat Operating State CC
+def zwTHERMOSTAT_OPERATING_STATE_MODE 0x4202
+
// Thermostat Cluster
def zb_LocalTemperature 0x02010000
def zb_HVACSystemTypeConfiguration 0x02010009
@@ -40,6 +43,7 @@ def zb_SystemMode 0x0201001c
def zb_TemperatureSetpointHold 0x02010023
def zb_TemperatureSetpointHoldDuration 0x02010024
def zb_ThermostatProgrammingOperationMode 0x02010025
+def zb_ThermostatRunningState 0x02010029
def zb_OccupiedSetback 0x02010034
def zb_OccupiedSetbackMin 0x02010035
def zb_OccupiedSetbackMax 0x02010036
@@ -54,7 +58,11 @@ def zb_ACLouverPosition 0x02010045
def zb_ACCoilTemperature 0x02010046
def zb_ACCapacityFormat 0x02010047
+// Unify thermostat cluster
+def zb_OperatingState 0xfd150003
+
def thermostat_setpoint_supported (e'zwTHERMOSTAT_SETPOINT_TYPE[2].zwTHERMOSTAT_SETPOINT_VALUE_SCALE | e'zwTHERMOSTAT_SETPOINT_TYPE[1].zwTHERMOSTAT_SETPOINT_VALUE_SCALE)
+def no_thermostat_operating_state (e'zwTHERMOSTAT_OPERATING_STATE_MODE == 0)
scope 0 {
// We map Setpoint setpoint_type 0x01 (HEATING) and 0x02 (COOLING)
@@ -252,4 +260,21 @@ scope 0 chain_reaction(0) {
d'zb_ACCapacityFormat =
if (r'zb_ACCapacityFormat != d'zb_ACCapacityFormat) r'zb_ACCapacityFormat
undefined
+
+ // Thermostat Operating State
+ // UCL bindings
+ r'zb_ThermostatRunningState =
+ if (no_thermostat_operating_state) undefined
+ if (r'zwTHERMOSTAT_OPERATING_STATE_MODE == 0x00) 0x00
+ if (r'zwTHERMOSTAT_OPERATING_STATE_MODE == 0x01) 0x01
+ if (r'zwTHERMOSTAT_OPERATING_STATE_MODE == 0x02) 0x02
+ if (r'zwTHERMOSTAT_OPERATING_STATE_MODE == 0x03) 0x04
+ if (r'zwTHERMOSTAT_OPERATING_STATE_MODE == 0x08) 0x08
+ if (r'zwTHERMOSTAT_OPERATING_STATE_MODE == 0x09) 0x10
+ if (r'zwTHERMOSTAT_OPERATING_STATE_MODE == 0x0A) 0x20
+ if (r'zwTHERMOSTAT_OPERATING_STATE_MODE == 0x0B) 0x40
+ undefined // Default state
+
+ // Custom cluster binding
+ r'zb_OperatingState = r'zwTHERMOSTAT_OPERATING_STATE_MODE
}
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 78ca2909e5..d45d4ebe59 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
@@ -691,6 +691,39 @@ DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_MAX_VALUE,
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_MAX_VALUE_SCALE,
((COMMAND_CLASS_THERMOSTAT_SETPOINT << 8) | 0x09))
+/////////////////////////////////////////////////
+// Thermostat Operating State Command Class
+/// zwave_cc_version_t
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_VERSION,
+ ZWAVE_CC_VERSION_ATTRIBUTE(COMMAND_CLASS_THERMOSTAT_OPERATING_STATE))
+/// Current State
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_CURRENT_STATE,
+ ((COMMAND_CLASS_THERMOSTAT_OPERATING_STATE << 8) | 0x02))
+/// Log supported count (v2)
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_SUPPORTED_BITMASK,
+ ((COMMAND_CLASS_THERMOSTAT_OPERATING_STATE << 8) | 0x03))
+/// Log supported (v2)
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_SUPPORTED,
+ ((COMMAND_CLASS_THERMOSTAT_OPERATING_STATE << 8) | 0x04))
+/// Log count (v2)
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_BITMASK,
+ ((COMMAND_CLASS_THERMOSTAT_OPERATING_STATE << 8) | 0x05))
+/// Log State (v2)
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_STATE,
+ ((COMMAND_CLASS_THERMOSTAT_OPERATING_STATE << 8) | 0x06))
+/// Log Usage Today (hours) (v2)
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_USAGE_TODAY_HOURS,
+ ((COMMAND_CLASS_THERMOSTAT_OPERATING_STATE << 8) | 0x07))
+/// Log Usage Today (min) (v2)
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_USAGE_TODAY_MIN,
+ ((COMMAND_CLASS_THERMOSTAT_OPERATING_STATE << 8) | 0x08))
+/// Log Usage Yesterday (hours) (v2)
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_USAGE_YESTERDAY_HOURS,
+ ((COMMAND_CLASS_THERMOSTAT_OPERATING_STATE << 8) | 0x09))
+/// Log Usage Yesterday (min) (v2)
+DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_USAGE_YESTERDAY_MIN,
+ ((COMMAND_CLASS_THERMOSTAT_OPERATING_STATE << 8) | 0x0A))
+
/////////////////////////////////////////////////
// Wakeup command class
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_WAKE_UP_VERSION,
diff --git a/applications/zpc/components/zpc_attribute_store/include/command_class_types/zwave_command_class_thermostat_operating_state_types.h b/applications/zpc/components/zpc_attribute_store/include/command_class_types/zwave_command_class_thermostat_operating_state_types.h
new file mode 100644
index 0000000000..12a95d457d
--- /dev/null
+++ b/applications/zpc/components/zpc_attribute_store/include/command_class_types/zwave_command_class_thermostat_operating_state_types.h
@@ -0,0 +1,41 @@
+/******************************************************************************
+ * # 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_thermostat_operating_state_types Type definitions for attribute storage of the Thermostat Operating State Command Class
+ * @ingroup zpc_attribute_store_command_classes_types
+ * @brief Type definitions for the Thermostat Operating State Command Class.
+ *
+ * @{
+ */
+
+#ifndef ZWAVE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_TYPES_H
+#define ZWAVE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_TYPES_H
+
+#include
+
+///> Operating State. uint8_t
+typedef uint8_t thermostat_operating_state_t;
+///> Usage representation (v2). uint8_t
+typedef uint8_t thermostat_operating_state_usage_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //ZWAVE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_TYPES_H
+/** @} end zwave_command_class_thermostat_operating_state_types */
diff --git a/applications/zpc/components/zpc_attribute_store/src/zpc_attribute_store_type_registration.cpp b/applications/zpc/components/zpc_attribute_store/src/zpc_attribute_store_type_registration.cpp
index 774ba2882d..1585c82d3e 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
@@ -302,6 +302,22 @@ static const std::vector attribute_schema = {
{ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_MIN_VALUE_SCALE, "Min Value Scale", ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_TYPE, U32_STORAGE_TYPE},
{ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_MAX_VALUE, "Max Value", ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_TYPE, I32_STORAGE_TYPE},
{ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_MAX_VALUE_SCALE, "Max Value Scale", ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_TYPE, U32_STORAGE_TYPE},
+
+ /////////////////////////////////////////////////////////////////////
+ // Thermostat Operating State Command Class attributes
+ /////////////////////////////////////////////////////////////////////
+ {ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_VERSION, "Thermostat Operating State Version", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_CURRENT_STATE, "Thermostat Operating State", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
+ // V2
+ {ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_SUPPORTED_BITMASK, "Thermostat Operating State Log Supported Count", ATTRIBUTE_ENDPOINT_ID, U32_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_SUPPORTED, "Thermostat Operating State Log Supported", ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_SUPPORTED_BITMASK, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_BITMASK, "Thermostat Operating State Log", ATTRIBUTE_ENDPOINT_ID, U32_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_STATE, "Thermostat Operating State Log State", ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_BITMASK, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_USAGE_TODAY_HOURS, "Thermostat Operating State Log Usage Today (Hours)", ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_STATE, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_USAGE_TODAY_MIN, "Thermostat Operating State Log Usage Today (Min)", ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_STATE, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_USAGE_YESTERDAY_HOURS, "Thermostat Operating State Log Usage Yesterday (Hours)", ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_STATE, U8_STORAGE_TYPE},
+ {ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_USAGE_YESTERDAY_MIN, "Thermostat Operating State Log Usage Yesterday (Hours)", ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_STATE, U8_STORAGE_TYPE},
+
/////////////////////////////////////////////////////////////////////
// Supervision Command Class attributes
/////////////////////////////////////////////////////////////////////
diff --git a/applications/zpc/components/zwave_command_classes/CMakeLists.txt b/applications/zpc/components/zwave_command_classes/CMakeLists.txt
index 90bec52fee..0172ec1c1c 100644
--- a/applications/zpc/components/zwave_command_classes/CMakeLists.txt
+++ b/applications/zpc/components/zwave_command_classes/CMakeLists.txt
@@ -46,6 +46,7 @@ add_library(
src/zwave_command_class_switch_multilevel.c
src/zwave_command_class_thermostat_mode.c
src/zwave_command_class_thermostat_setpoint.c
+ src/zwave_command_class_thermostat_operating_state.c
src/zwave_command_class_time.c
src/zwave_command_class_user_code.c
src/zwave_command_class_version.c
diff --git a/applications/zpc/components/zwave_command_classes/src/zwave_command_class_thermostat_operating_state.c b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_thermostat_operating_state.c
new file mode 100644
index 0000000000..be71eac1a8
--- /dev/null
+++ b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_thermostat_operating_state.c
@@ -0,0 +1,452 @@
+/******************************************************************************
+ * # 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.
+ *
+ *****************************************************************************/
+
+// System
+#include
+
+#include "zwave_command_class_thermostat_operating_state.h"
+#include "zwave_command_class_thermostat_operating_state_types.h"
+#include "zwave_command_classes_utils.h"
+#include "ZW_classcmd.h"
+
+// Includes from other ZPC Components
+#include "zwave_command_class_indices.h"
+#include "zwave_command_handler.h"
+#include "zwave_command_class_version_types.h"
+#include "zpc_attribute_store_network_helper.h"
+#include "attribute_store_defined_attribute_types.h"
+
+// Unify
+#include "attribute_resolver.h"
+#include "attribute_store.h"
+#include "attribute_store_helper.h"
+#include "sl_log.h"
+
+#define LOG_TAG "zwave_command_class_thermostat_operating_state"
+
+#define MAX_SUPPORTED_OPERATING_STATE 16
+
+/////////////////////////////////////////////////////////////////////////////
+// Version & Attribute Creation
+/////////////////////////////////////////////////////////////////////////////
+static void
+ zwave_command_class_thermostat_operating_state_on_version_attribute_update(
+ attribute_store_node_t updated_node, attribute_store_change_t change)
+{
+ if (change == ATTRIBUTE_DELETED) {
+ return;
+ }
+
+ zwave_cc_version_t version = 0;
+ attribute_store_get_reported(updated_node, &version, sizeof(version));
+
+ if (version == 0) {
+ return;
+ }
+
+ attribute_store_node_t endpoint_node
+ = attribute_store_get_first_parent_with_type(updated_node,
+ ATTRIBUTE_ENDPOINT_ID);
+
+ // The order of the attribute matter since it defines the order of the
+ // Z-Wave get command order.
+ const attribute_store_type_t attributes[]
+ = {ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_CURRENT_STATE};
+
+ attribute_store_add_if_missing(endpoint_node,
+ attributes,
+ COUNT_OF(attributes));
+
+ if (version == 2) {
+ const attribute_store_type_t attributes_v2[] = {
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_SUPPORTED_BITMASK};
+
+ attribute_store_add_if_missing(endpoint_node,
+ attributes_v2,
+ COUNT_OF(attributes_v2));
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Thermostat Operating State Get/Report
+/////////////////////////////////////////////////////////////////////////////
+
+static sl_status_t zwave_command_class_thermostat_operating_state_get(
+ attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
+{
+ (void)node; // unused.
+ ZW_THERMOSTAT_OPERATING_STATE_GET_FRAME *get_frame
+ = (ZW_THERMOSTAT_OPERATING_STATE_GET_FRAME *)frame;
+ get_frame->cmdClass = COMMAND_CLASS_THERMOSTAT_OPERATING_STATE;
+ get_frame->cmd = THERMOSTAT_OPERATING_STATE_GET;
+ *frame_length = sizeof(ZW_THERMOSTAT_OPERATING_STATE_GET_FRAME);
+ return SL_STATUS_OK;
+}
+
+sl_status_t zwave_command_class_thermostat_operating_state_handle_report(
+ const zwave_controller_connection_info_t *connection_info,
+ const uint8_t *frame_data,
+ uint16_t frame_length)
+{
+ if (frame_length < 3) {
+ return SL_STATUS_FAIL;
+ }
+
+ attribute_store_node_t endpoint_node
+ = zwave_command_class_get_endpoint_node(connection_info);
+
+ thermostat_operating_state_t operating_state = frame_data[2];
+
+ attribute_store_set_child_reported(
+ endpoint_node,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_CURRENT_STATE,
+ &operating_state,
+ sizeof(operating_state));
+
+ return SL_STATUS_OK;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Thermostat Operating State Logging Supported Get/Report
+/////////////////////////////////////////////////////////////////////////////
+static sl_status_t
+ zwave_command_class_thermostat_operating_state_logging_supported_get(
+ attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
+{
+ (void)node; // unused.
+ ZW_THERMOSTAT_OPERATING_STATE_LOGGING_SUPPORTED_GET_V2_FRAME *get_frame
+ = (ZW_THERMOSTAT_OPERATING_STATE_LOGGING_SUPPORTED_GET_V2_FRAME *)frame;
+ get_frame->cmdClass = COMMAND_CLASS_THERMOSTAT_OPERATING_STATE;
+ get_frame->cmd = THERMOSTAT_OPERATING_STATE_LOGGING_SUPPORTED_GET_V2;
+ *frame_length
+ = sizeof(ZW_THERMOSTAT_OPERATING_STATE_LOGGING_SUPPORTED_GET_V2_FRAME);
+ return SL_STATUS_OK;
+}
+
+sl_status_t
+ zwave_command_class_thermostat_operating_state_logging_supported_report(
+ const zwave_controller_connection_info_t *connection_info,
+ const uint8_t *frame_data,
+ uint16_t frame_length)
+{
+ if (frame_length < 3) {
+ return SL_STATUS_NOT_SUPPORTED;
+ }
+
+ attribute_store_node_t endpoint_node
+ = zwave_command_class_get_endpoint_node(connection_info);
+
+ uint32_t notification_types_bits = 0x0000;
+ uint32_t notification_type_mask = 0x0000;
+ uint8_t number_of_supported_states = 0;
+ thermostat_operating_state_t supported_states[MAX_SUPPORTED_OPERATING_STATE];
+ uint8_t number_of_bit_masks = frame_length - 2;
+
+ // Since we are using uint32_t we can't have more that 4 bit mask
+ if (number_of_bit_masks > 4) {
+ sl_log_error(LOG_TAG,
+ "Supported Fan mode type Bit Mask length is not supported\n");
+ return SL_STATUS_NOT_SUPPORTED;
+ }
+
+ for (int i = number_of_bit_masks; i > 0; i--) {
+ notification_types_bits
+ = (notification_types_bits << 8) | frame_data[1 + i];
+ }
+
+ for (size_t i = 0; i <= MAX_SUPPORTED_OPERATING_STATE; i++) {
+ notification_type_mask = 1 << i;
+ notification_type_mask &= notification_types_bits;
+ if (notification_type_mask) {
+ switch (notification_type_mask) {
+ case 0b1:
+ supported_states[number_of_supported_states]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_HEATING;
+ break;
+ case 0b10:
+ supported_states[number_of_supported_states]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_COOLING;
+ break;
+ case 0b100:
+ supported_states[number_of_supported_states]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_FAN_ONLY;
+ break;
+ case 0b1000:
+ supported_states[number_of_supported_states]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_PENDING_HEAT;
+ break;
+ case 0b10000:
+ supported_states[number_of_supported_states]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_PENDING_COOL;
+ break;
+ case 0b100000:
+ supported_states[number_of_supported_states]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_VENT_ECONOMIZER;
+ break;
+ case 0b1000000:
+ supported_states[number_of_supported_states]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_AUX_HEATING_V2;
+ break;
+ case 0b10000000:
+ supported_states[number_of_supported_states]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_2ND_STAGE_HEATING_V2;
+ break;
+ case 0b100000000:
+ supported_states[number_of_supported_states]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_2ND_STAGE_COOLING_V2;
+ break;
+ case 0b1000000000:
+ supported_states[number_of_supported_states]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_2ND_STAGE_AUX_HEAT_V2;
+ break;
+ case 0b10000000000:
+ supported_states[number_of_supported_states]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_3RD_STAGE_AUX_HEAT_V2;
+ break;
+ default:
+ continue;
+ }
+ number_of_supported_states++;
+ }
+ }
+
+ attribute_store_node_t supported_logging_operating_state_bitmask_node
+ = attribute_store_get_node_child_by_type(
+ endpoint_node,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_SUPPORTED_BITMASK,
+ 0);
+
+ if (supported_logging_operating_state_bitmask_node
+ == ATTRIBUTE_STORE_INVALID_NODE) {
+ sl_log_error(LOG_TAG,
+ "Can't find supported supported logging state bitmask node.");
+ return SL_STATUS_NOT_SUPPORTED;
+ }
+
+ // Clear previously reported values
+ attribute_store_delete_all_children(
+ supported_logging_operating_state_bitmask_node);
+
+ // And Set the new ones
+ for (uint8_t i = 0; i < number_of_supported_states; i++) {
+ attribute_store_node_t current_supported_fan_mode_node
+ = attribute_store_add_node(
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_SUPPORTED,
+ supported_logging_operating_state_bitmask_node);
+
+ attribute_store_set_node_attribute_value(current_supported_fan_mode_node,
+ REPORTED_ATTRIBUTE,
+ &supported_states[i],
+ sizeof(supported_states[i]));
+ }
+
+ sl_status_t result = attribute_store_set_reported(
+ supported_logging_operating_state_bitmask_node,
+ ¬ification_types_bits,
+ sizeof(notification_types_bits));
+
+ if (result != SL_STATUS_OK) {
+ sl_log_warning(LOG_TAG,
+ "Can't set supported logging operating state bitmask.");
+ }
+
+ attribute_store_node_t log_node = attribute_store_add_node(
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_BITMASK,
+ endpoint_node);
+
+ result = attribute_store_set_desired(log_node,
+ ¬ification_types_bits,
+ sizeof(notification_types_bits));
+
+ if (result != SL_STATUS_OK) {
+ sl_log_warning(LOG_TAG, "Can't set log desired states.");
+ }
+
+ return SL_STATUS_OK;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Thermostat Operating State Logging Get/Report
+/////////////////////////////////////////////////////////////////////////////
+static sl_status_t zwave_command_class_thermostat_operating_state_logging_get(
+ attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
+{
+ // Extract bitmap from value
+ uint32_t full_bitmask = 0;
+ sl_status_t result
+ = attribute_store_get_desired(node, &full_bitmask, sizeof(full_bitmask));
+
+ if (result != SL_STATUS_OK) {
+ sl_log_warning(
+ LOG_TAG,
+ "Unable to get bitmask for THERMOSTAT_OPERATING_STATE_LOGGING_GET");
+ return SL_STATUS_IS_WAITING;
+ }
+
+ // Convert 32 bit mask into chunk of 8 bit masks
+ const uint8_t MAX_BITMASKS = 2;
+ uint8_t bitmasks[MAX_BITMASKS];
+ for (int i = 0; i < MAX_BITMASKS; i++) {
+ uint32_t mask = ((1 << 8) - 1) << 8 * i;
+ bitmasks[i] = (full_bitmask & mask) >> 8 * i;
+ }
+
+ ZW_THERMOSTAT_OPERATING_STATE_LOGGING_GET_2BYTE_V2_FRAME *get_frame
+ = (ZW_THERMOSTAT_OPERATING_STATE_LOGGING_GET_2BYTE_V2_FRAME *)frame;
+ get_frame->cmdClass = COMMAND_CLASS_THERMOSTAT_OPERATING_STATE;
+ get_frame->cmd = THERMOSTAT_OPERATING_STATE_LOGGING_GET_V2;
+ get_frame->bitMask1 = bitmasks[0];
+ get_frame->bitMask2 = bitmasks[1];
+ *frame_length
+ = sizeof(ZW_THERMOSTAT_OPERATING_STATE_LOGGING_GET_2BYTE_V2_FRAME);
+ return SL_STATUS_OK;
+}
+
+attribute_store_node_t helper_add_log_node(attribute_store_node_t log_node,
+ attribute_store_type_t node_type,
+ uint8_t value)
+{
+ attribute_store_node_t new_node
+ = attribute_store_add_node(node_type, log_node);
+
+ attribute_store_set_reported(new_node, &value, sizeof(value));
+
+ return new_node;
+}
+
+sl_status_t zwave_command_class_thermostat_operating_state_logging_report(
+ const zwave_controller_connection_info_t *connection_info,
+ const uint8_t *frame_data,
+ uint16_t frame_length)
+{
+ if (frame_length < 3) {
+ return SL_STATUS_NOT_SUPPORTED;
+ }
+
+ // Just retrieve the data and save it.
+ attribute_store_node_t endpoint_node
+ = zwave_command_class_get_endpoint_node(connection_info);
+ attribute_store_node_t log_node = attribute_store_get_first_child_by_type(
+ endpoint_node,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_BITMASK);
+
+ uint8_t report_count = frame_data[2];
+
+ // Clear previously reported values
+ attribute_store_delete_all_children(log_node);
+
+ const uint8_t REPORT_FIELD_COUNT = 4;
+
+ for (uint8_t i = 0; i < report_count; i++) {
+ thermostat_operating_state_t state
+ = frame_data[3 + (REPORT_FIELD_COUNT * i) + i]
+ & THERMOSTAT_OPERATING_STATE_REPORT_PROPERTIES1_OPERATING_STATE_MASK_V2;
+
+ attribute_store_node_t state_node = helper_add_log_node(
+ log_node,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_STATE,
+ state);
+
+ const attribute_store_type_t attribute_store_types[] = {
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_USAGE_TODAY_HOURS,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_USAGE_TODAY_MIN,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_USAGE_YESTERDAY_HOURS,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_USAGE_YESTERDAY_MIN};
+
+ for (int j = 0; j < REPORT_FIELD_COUNT; j++) {
+ const uint8_t base_index = 4 + j;
+ const uint8_t offset = (REPORT_FIELD_COUNT * i) + i;
+ thermostat_operating_state_usage_t current_value
+ = frame_data[base_index + offset];
+
+ helper_add_log_node(state_node, attribute_store_types[j], current_value);
+ }
+ }
+
+ attribute_store_set_reported_as_desired(log_node);
+ return SL_STATUS_OK;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Control handler (report)
+/////////////////////////////////////////////////////////////////////////////
+sl_status_t zwave_command_class_thermostat_operating_state_control_handler(
+ const zwave_controller_connection_info_t *connection_info,
+ const uint8_t *frame_data,
+ uint16_t frame_length)
+{
+ if (frame_length <= COMMAND_INDEX) {
+ return SL_STATUS_NOT_SUPPORTED;
+ }
+
+ switch (frame_data[COMMAND_INDEX]) {
+ case THERMOSTAT_OPERATING_STATE_REPORT:
+ return zwave_command_class_thermostat_operating_state_handle_report(
+ connection_info,
+ frame_data,
+ frame_length);
+ case THERMOSTAT_OPERATING_LOGGING_SUPPORTED_REPORT_V2:
+ return zwave_command_class_thermostat_operating_state_logging_supported_report(
+ connection_info,
+ frame_data,
+ frame_length);
+ case THERMOSTAT_OPERATING_STATE_LOGGING_REPORT_V2:
+ return zwave_command_class_thermostat_operating_state_logging_report(
+ connection_info,
+ frame_data,
+ frame_length);
+
+ default:
+ return SL_STATUS_NOT_SUPPORTED;
+ }
+
+ return SL_STATUS_FAIL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Init
+/////////////////////////////////////////////////////////////////////////////
+sl_status_t zwave_command_class_thermostat_operating_state_init()
+{
+ attribute_store_register_callback_by_type(
+ &zwave_command_class_thermostat_operating_state_on_version_attribute_update,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_VERSION);
+
+ attribute_resolver_register_rule(
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_CURRENT_STATE,
+ NULL,
+ &zwave_command_class_thermostat_operating_state_get);
+
+ attribute_resolver_register_rule(
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_SUPPORTED_BITMASK,
+ NULL,
+ &zwave_command_class_thermostat_operating_state_logging_supported_get);
+
+ attribute_resolver_register_rule(
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_BITMASK,
+ NULL,
+ &zwave_command_class_thermostat_operating_state_logging_get);
+
+ zwave_command_handler_t handler = {};
+ handler.support_handler = NULL;
+ handler.control_handler
+ = zwave_command_class_thermostat_operating_state_control_handler;
+ handler.minimal_scheme = ZWAVE_CONTROLLER_ENCAPSULATION_NONE;
+ handler.manual_security_validation = false;
+ handler.command_class = COMMAND_CLASS_THERMOSTAT_OPERATING_STATE;
+ handler.version = THERMOSTAT_OPERATING_STATE_VERSION_V2;
+ handler.command_class_name = "Thermostat Operating State";
+ handler.comments = "Experimental. Log related functions are not yet exposed to MQTT.";
+
+ return zwave_command_handler_register_handler(handler);
+}
\ No newline at end of file
diff --git a/applications/zpc/components/zwave_command_classes/src/zwave_command_class_thermostat_operating_state.h b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_thermostat_operating_state.h
new file mode 100644
index 0000000000..5cf1568a08
--- /dev/null
+++ b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_thermostat_operating_state.h
@@ -0,0 +1,40 @@
+/******************************************************************************
+ * # 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_thermostat_operating_state
+ * @brief Thermostat Operating State Command Class handlers and control function
+ *
+ * This module implement some of the functions to control the
+ * Thermostat Operating State Command Class
+ *
+ * @{
+ */
+
+#ifndef ZWAVE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_H
+#define ZWAVE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_H
+
+#include "sl_status.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+sl_status_t zwave_command_class_thermostat_operating_state_init();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //ZWAVE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_H
+/** @} end zwave_command_class_thermostat_operating_state */
\ No newline at end of file
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 cac0a8c665..f07bc8f6a9 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
@@ -41,6 +41,7 @@
#include "zwave_command_class_switch_multilevel.h"
#include "zwave_command_class_thermostat_mode.h"
#include "zwave_command_class_thermostat_setpoint.h"
+#include "zwave_command_class_thermostat_operating_state.h"
#include "zwave_command_class_version.h"
#include "zwave_command_class_wake_up.h"
#include "zwave_command_class_time.h"
@@ -109,6 +110,7 @@ sl_status_t zwave_command_classes_init()
status |= zwave_command_class_switch_multilevel_init();
status |= zwave_command_class_thermostat_mode_init();
status |= zwave_command_class_thermostat_setpoint_init();
+ status |= zwave_command_class_thermostat_operating_state_init();
status |= zwave_command_class_time_init();
status |= zwave_command_class_transport_service_init();
status |= zwave_command_class_user_code_init();
diff --git a/applications/zpc/components/zwave_command_classes/test/CMakeLists.txt b/applications/zpc/components/zwave_command_classes/test/CMakeLists.txt
index 4d72dfb0ef..5f2552a90c 100644
--- a/applications/zpc/components/zwave_command_classes/test/CMakeLists.txt
+++ b/applications/zpc/components/zwave_command_classes/test/CMakeLists.txt
@@ -637,6 +637,21 @@ DEPENDS
uic_dotdot_mqtt_mock
)
+# Thermostat operating state test
+target_add_unittest(
+ zwave_command_classes
+ NAME
+ zwave_command_class_thermostat_operating_state_test
+ SOURCES
+ zwave_command_class_thermostat_operating_state_test.c
+ DEPENDS
+ zpc_attribute_store_test_helper
+ zwave_controller
+ zwave_command_handler_mock
+ uic_attribute_resolver_mock
+ zpc_attribute_resolver_mock
+ uic_dotdot_mqtt_mock)
+
# Tests for generated command classes
set(GEN_TEST_INCLUDES
"${CMAKE_SOURCE_DIR}/applications/zpc/components/zwave_controller/include"
diff --git a/applications/zpc/components/zwave_command_classes/test/zwave_command_class_thermostat_operating_state_test.c b/applications/zpc/components/zwave_command_classes/test/zwave_command_class_thermostat_operating_state_test.c
new file mode 100644
index 0000000000..85bc3e34a1
--- /dev/null
+++ b/applications/zpc/components/zwave_command_classes/test/zwave_command_class_thermostat_operating_state_test.c
@@ -0,0 +1,580 @@
+/******************************************************************************
+ * # 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.
+ *
+ *****************************************************************************/
+
+#include "zwave_command_class_thermostat_operating_state.h"
+#include "zwave_command_class_thermostat_operating_state_types.h"
+#include "zwave_command_classes_utils.h"
+#include "unity.h"
+
+// Generic includes
+#include
+
+// Includes from other components
+#include "datastore.h"
+#include "attribute_store.h"
+#include "attribute_store_helper.h"
+#include "attribute_store_fixt.h"
+#include "zpc_attribute_store_type_registration.h"
+
+// Interface includes
+#include "attribute_store_defined_attribute_types.h"
+#include "ZW_classcmd.h"
+#include "zwave_utils.h"
+#include "zwave_controller_types.h"
+
+// Test helpers
+#include "zpc_attribute_store_test_helper.h"
+
+// Mock includes
+#include "attribute_resolver_mock.h"
+#include "zpc_attribute_resolver_mock.h"
+#include "zwave_command_handler_mock.h"
+#include "dotdot_mqtt_mock.h"
+#include "dotdot_mqtt_generated_commands_mock.h"
+
+static zwave_command_handler_t handler = {};
+
+static attribute_resolver_function_t operating_state_get = NULL;
+static attribute_resolver_function_t logging_supported_get = NULL;
+static attribute_resolver_function_t logging_get = NULL;
+
+// Buffer for frame
+static uint8_t received_frame[255] = {};
+static uint16_t received_frame_size = 0;
+
+// Stub functions
+static sl_status_t
+ attribute_resolver_register_rule_stub(attribute_store_type_t node_type,
+ attribute_resolver_function_t set_func,
+ attribute_resolver_function_t get_func,
+ int cmock_num_calls)
+{
+ if (node_type
+ == ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_CURRENT_STATE) {
+ TEST_ASSERT_NULL(set_func);
+ TEST_ASSERT_NOT_NULL(get_func);
+ operating_state_get = get_func;
+ } else if (
+ node_type
+ == ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_SUPPORTED_BITMASK) {
+ TEST_ASSERT_NULL(set_func);
+ TEST_ASSERT_NOT_NULL(get_func);
+ logging_supported_get = get_func;
+ } else if (
+ node_type
+ == ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_BITMASK) {
+ TEST_ASSERT_NULL(set_func);
+ TEST_ASSERT_NOT_NULL(get_func);
+ logging_get = get_func;
+ }
+
+ return SL_STATUS_OK;
+}
+
+static sl_status_t zwave_command_handler_register_handler_stub(
+ zwave_command_handler_t new_command_class_handler, int cmock_num_calls)
+{
+ handler = new_command_class_handler;
+
+ TEST_ASSERT_EQUAL(ZWAVE_CONTROLLER_ENCAPSULATION_NONE,
+ handler.minimal_scheme);
+ TEST_ASSERT_EQUAL(COMMAND_CLASS_THERMOSTAT_OPERATING_STATE,
+ handler.command_class);
+ TEST_ASSERT_EQUAL(THERMOSTAT_OPERATING_STATE_VERSION_V2, handler.version);
+ TEST_ASSERT_NOT_NULL(handler.control_handler);
+ TEST_ASSERT_NULL(handler.support_handler);
+ TEST_ASSERT_FALSE(handler.manual_security_validation);
+
+ return SL_STATUS_OK;
+}
+
+/// 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;
+}
+
+/// Called before each and every test
+void setUp()
+{
+ zpc_attribute_store_test_helper_create_network();
+
+ // Unset previous definition get/set functions
+ operating_state_get = NULL;
+ logging_supported_get = NULL;
+ logging_get = NULL;
+
+ memset(received_frame, 0, sizeof(received_frame));
+ received_frame_size = 0;
+ // Unset previous definition of handler
+ memset(&handler, 0, sizeof(zwave_command_handler_t));
+
+ // Resolution functions
+ attribute_resolver_register_rule_Stub(&attribute_resolver_register_rule_stub);
+ // Handler registration
+ zwave_command_handler_register_handler_Stub(
+ &zwave_command_handler_register_handler_stub);
+ // Call init
+ TEST_ASSERT_EQUAL(SL_STATUS_OK,
+ zwave_command_class_thermostat_operating_state_init());
+}
+
+/// Called after each and every test
+void tearDown() {}
+
+////////////////////////////////////////////////////////////////////////////
+// UTILS
+////////////////////////////////////////////////////////////////////////////
+
+// Set version and thus initialize the attribute tree
+void set_version(zwave_cc_version_t version)
+{
+ attribute_store_node_t version_node = attribute_store_add_node(
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_VERSION,
+ endpoint_id_node);
+
+ attribute_store_set_reported(version_node, &version, sizeof(version));
+}
+
+////////////////////////////////////////////////////////////////////////////
+// Versioning
+////////////////////////////////////////////////////////////////////////////
+void test_thermostat_operating_state_v1_happy_case()
+{
+ set_version(1);
+
+ attribute_store_node_t state_node = attribute_store_get_first_child_by_type(
+ endpoint_id_node,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_CURRENT_STATE);
+
+ TEST_ASSERT_NOT_EQUAL(ATTRIBUTE_STORE_INVALID_NODE, state_node);
+
+ attribute_store_node_t log_supported_node
+ = attribute_store_get_first_child_by_type(
+ endpoint_id_node,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_SUPPORTED_BITMASK);
+ TEST_ASSERT_EQUAL(ATTRIBUTE_STORE_INVALID_NODE, log_supported_node);
+}
+
+void test_thermostat_operating_state_v2_happy_case()
+{
+ set_version(2);
+
+ attribute_store_node_t state_node = attribute_store_get_first_child_by_type(
+ endpoint_id_node,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_CURRENT_STATE);
+
+ TEST_ASSERT_NOT_EQUAL(ATTRIBUTE_STORE_INVALID_NODE, state_node);
+
+ attribute_store_node_t log_supported_node
+ = attribute_store_get_first_child_by_type(
+ endpoint_id_node,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_SUPPORTED_BITMASK);
+ TEST_ASSERT_NOT_EQUAL(ATTRIBUTE_STORE_INVALID_NODE, log_supported_node);
+}
+
+////////////////////////////////////////////////////////////////////////////
+// Operating State Get/Report
+////////////////////////////////////////////////////////////////////////////
+void test_thermostat_operating_state_get_happy_case()
+{
+ // Ask for a Get Command, should always be the same
+ TEST_ASSERT_NOT_NULL(operating_state_get);
+ operating_state_get(0, received_frame, &received_frame_size);
+ const uint8_t expected_frame[] = {COMMAND_CLASS_THERMOSTAT_OPERATING_STATE,
+ THERMOSTAT_OPERATING_STATE_GET};
+ TEST_ASSERT_EQUAL(sizeof(expected_frame), received_frame_size);
+ TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_frame,
+ received_frame,
+ received_frame_size);
+}
+
+void test_thermostat_operating_state_report_happy_case()
+{
+ zwave_controller_connection_info_t info = {};
+ info.remote.node_id = node_id;
+ info.remote.endpoint_id = endpoint_id;
+ info.local.is_multicast = false;
+
+ TEST_ASSERT_NOT_NULL(handler.control_handler);
+ TEST_ASSERT_EQUAL(SL_STATUS_NOT_SUPPORTED,
+ handler.control_handler(&info, NULL, 0));
+
+ thermostat_operating_state_t operating_state
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_HEATING;
+ const uint8_t frame[] = {COMMAND_CLASS_THERMOSTAT_OPERATING_STATE,
+ THERMOSTAT_OPERATING_STATE_REPORT,
+ operating_state};
+
+ TEST_ASSERT_EQUAL(SL_STATUS_OK,
+ handler.control_handler(&info, frame, sizeof(frame)));
+
+ attribute_store_node_t operating_state_node
+ = attribute_store_get_node_child_by_type(
+ endpoint_id_node,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_CURRENT_STATE,
+ 0);
+ TEST_ASSERT_EQUAL(operating_state,
+ attribute_store_get_reported_number(operating_state_node));
+}
+
+////////////////////////////////////////////////////////////////////////////
+// Supported Log Get/Report
+////////////////////////////////////////////////////////////////////////////
+void test_thermostat_operating_state_log_supported_get_happy_case()
+{
+ // Ask for a Get Command, should always be the same
+ TEST_ASSERT_NOT_NULL(operating_state_get);
+ logging_supported_get(0, received_frame, &received_frame_size);
+ const uint8_t expected_frame[]
+ = {COMMAND_CLASS_THERMOSTAT_OPERATING_STATE,
+ THERMOSTAT_OPERATING_STATE_LOGGING_SUPPORTED_GET_V2};
+ TEST_ASSERT_EQUAL(sizeof(expected_frame), received_frame_size);
+ TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_frame,
+ received_frame,
+ received_frame_size);
+}
+
+void helper_thermostat_operating_state_log_supported_report_happy_case(
+ uint8_t test_case)
+{
+ printf("test_thermostat_operating_state_log_supported_report_happy_case test "
+ "#%d\n",
+ test_case);
+
+ zwave_controller_connection_info_t info = {};
+ info.remote.node_id = node_id;
+ info.remote.endpoint_id = endpoint_id;
+ info.local.is_multicast = false;
+
+ TEST_ASSERT_NOT_NULL(handler.control_handler);
+ TEST_ASSERT_EQUAL(SL_STATUS_NOT_SUPPORTED,
+ handler.control_handler(&info, NULL, 0));
+
+ uint8_t supported_log_count = 11;
+ uint8_t bitmask1 = 0b11111111;
+ uint8_t bitmask2 = 0b11111111;
+ thermostat_operating_state_t expecting_states[11];
+
+ switch (test_case) {
+ case 1: // All types
+ supported_log_count = 11;
+ bitmask1 = 0b11111111;
+ bitmask2 = 0b11111111;
+ expecting_states[0]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_HEATING;
+ expecting_states[1]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_COOLING;
+ expecting_states[2]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_FAN_ONLY;
+ expecting_states[3]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_PENDING_HEAT;
+ expecting_states[4]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_PENDING_COOL;
+ expecting_states[5]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_VENT_ECONOMIZER;
+ expecting_states[6]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_AUX_HEATING_V2;
+ expecting_states[7]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_2ND_STAGE_HEATING_V2;
+ expecting_states[8]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_2ND_STAGE_COOLING_V2;
+ expecting_states[9]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_2ND_STAGE_AUX_HEAT_V2;
+ expecting_states[10]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_3RD_STAGE_AUX_HEAT_V2;
+ break;
+
+ case 2: // Only bit 1
+ supported_log_count = 2;
+ bitmask1 = 0b10000001;
+ bitmask2 = 0b00000000;
+ expecting_states[0]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_HEATING;
+ expecting_states[1]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_2ND_STAGE_HEATING_V2;
+ break;
+
+ case 3: // Only bit 2
+ supported_log_count = 2;
+ bitmask1 = 0b00000000;
+ bitmask2 = 0b00000011;
+ expecting_states[0]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_2ND_STAGE_COOLING_V2;
+ expecting_states[1]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_2ND_STAGE_AUX_HEAT_V2;
+ break;
+
+ case 4: // Bit of both
+ supported_log_count = 4;
+ bitmask1 = 0b00101010; // 3 Here
+ bitmask2 = 0b11000100; // Only 1 here
+ expecting_states[0]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_COOLING;
+ expecting_states[1]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_PENDING_HEAT;
+ expecting_states[2]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_VENT_ECONOMIZER;
+ expecting_states[3]
+ = THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_3RD_STAGE_AUX_HEAT_V2;
+ break;
+
+ default:
+ TEST_MESSAGE("Undefined test_case aborting");
+ TEST_ABORT();
+ }
+
+ const uint8_t frame[] = {COMMAND_CLASS_THERMOSTAT_OPERATING_STATE,
+ THERMOSTAT_OPERATING_LOGGING_SUPPORTED_REPORT_V2,
+ bitmask1,
+ bitmask2};
+
+ TEST_ASSERT_EQUAL(SL_STATUS_OK,
+ handler.control_handler(&info, frame, sizeof(frame)));
+
+ attribute_store_node_t operating_state_node
+ = attribute_store_get_node_child_by_type(
+ endpoint_id_node,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_SUPPORTED_BITMASK,
+ 0);
+
+ TEST_ASSERT_EQUAL((bitmask2 << 8) + bitmask1,
+ attribute_store_get_reported_number(operating_state_node));
+
+ TEST_ASSERT_EQUAL(supported_log_count,
+ attribute_store_get_node_child_count(operating_state_node));
+
+ for (int i = 0; i < supported_log_count; i++) {
+ thermostat_operating_state_t expected_state = expecting_states[i];
+
+ attribute_store_node_t current_node
+ = attribute_store_get_node_child_by_type(
+ operating_state_node,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_SUPPORTED,
+ i);
+
+ TEST_ASSERT_NOT_EQUAL(ATTRIBUTE_STORE_INVALID_NODE, current_node);
+
+ thermostat_operating_state_t reported_state;
+ sl_status_t status = attribute_store_get_reported(current_node,
+ &reported_state,
+ sizeof(reported_state));
+
+ TEST_ASSERT_EQUAL(SL_STATUS_OK, status);
+ TEST_ASSERT_EQUAL(expected_state, reported_state);
+ }
+
+ // Check if ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_BITMASK is created once we have the supported states
+ attribute_store_node_t log_bitmask_node
+ = attribute_store_get_first_child_by_type(
+ endpoint_id_node,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_BITMASK);
+
+ TEST_ASSERT_NOT_EQUAL(ATTRIBUTE_STORE_INVALID_NODE, log_bitmask_node);
+}
+
+void test_thermostat_operating_state_log_supported_report_happy_case()
+{
+ set_version(2);
+ for (int i = 1; i <= 4; i++) {
+ helper_thermostat_operating_state_log_supported_report_happy_case(i);
+ }
+}
+
+void test_thermostat_operating_state_log_supported_report_versioning()
+{
+ zwave_controller_connection_info_t info = {};
+ info.remote.node_id = node_id;
+ info.remote.endpoint_id = endpoint_id;
+ info.local.is_multicast = false;
+
+ TEST_ASSERT_NOT_NULL(handler.control_handler);
+ TEST_ASSERT_EQUAL(SL_STATUS_NOT_SUPPORTED,
+ handler.control_handler(&info, NULL, 0));
+
+ const uint8_t frame[] = {COMMAND_CLASS_THERMOSTAT_OPERATING_STATE,
+ THERMOSTAT_OPERATING_LOGGING_SUPPORTED_REPORT_V2,
+ 0b0000000,
+ 0b0000000};
+ // Undefined in v1
+ set_version(1);
+ TEST_ASSERT_EQUAL(SL_STATUS_NOT_SUPPORTED,
+ handler.control_handler(&info, frame, sizeof(frame)));
+
+ set_version(2);
+ TEST_ASSERT_EQUAL(SL_STATUS_OK,
+ handler.control_handler(&info, frame, sizeof(frame)));
+}
+
+////////////////////////////////////////////////////////////////////////////
+// Log Get/Report
+////////////////////////////////////////////////////////////////////////////
+
+void test_thermostat_operating_state_log_get_happy_case()
+{
+ // Ask for a Get Command, should always be the same
+ TEST_ASSERT_NOT_NULL(operating_state_get);
+ sl_status_t status = logging_get(0, received_frame, &received_frame_size);
+
+ // No ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_BITMASK yet
+ TEST_ASSERT_EQUAL(SL_STATUS_IS_WAITING, status);
+
+ // We add it and test
+ attribute_store_node_t log_node = attribute_store_add_node(
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_BITMASK,
+ endpoint_id_node);
+
+ TEST_ASSERT_TRUE(attribute_store_node_exists(log_node));
+
+ uint32_t expected_bitmask = 0b0000000100000110;
+ attribute_store_set_desired(log_node,
+ &expected_bitmask,
+ sizeof(expected_bitmask));
+
+ status = logging_get(log_node, received_frame, &received_frame_size);
+ TEST_ASSERT_EQUAL(SL_STATUS_OK, status);
+
+ const uint8_t expected_frame[] = {COMMAND_CLASS_THERMOSTAT_OPERATING_STATE,
+ THERMOSTAT_OPERATING_STATE_LOGGING_GET_V2,
+ 0b00000110,
+ 0b00000001};
+ TEST_ASSERT_EQUAL(sizeof(expected_frame), received_frame_size);
+ TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_frame,
+ received_frame,
+ received_frame_size);
+}
+
+void test_thermostat_operating_state_log_no_report_happy_case()
+{
+ zwave_controller_connection_info_t info = {};
+ info.remote.node_id = node_id;
+ info.remote.endpoint_id = endpoint_id;
+ info.local.is_multicast = false;
+
+ attribute_store_add_node(
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_BITMASK,
+ endpoint_id_node);
+
+ TEST_ASSERT_NOT_NULL(handler.control_handler);
+ TEST_ASSERT_EQUAL(SL_STATUS_NOT_SUPPORTED,
+ handler.control_handler(&info, NULL, 0));
+
+ const uint8_t frame[] = {COMMAND_CLASS_THERMOSTAT_OPERATING_STATE,
+ THERMOSTAT_OPERATING_STATE_LOGGING_REPORT_V2,
+ 0};
+
+ TEST_ASSERT_EQUAL(SL_STATUS_OK,
+ handler.control_handler(&info, frame, sizeof(frame)));
+}
+
+void test_thermostat_operating_state_log_report_happy_case()
+{
+ zwave_controller_connection_info_t info = {};
+ info.remote.node_id = node_id;
+ info.remote.endpoint_id = endpoint_id;
+ info.local.is_multicast = false;
+
+ attribute_store_node_t log_node = attribute_store_add_node(
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_BITMASK,
+ endpoint_id_node);
+
+ TEST_ASSERT_NOT_NULL(handler.control_handler);
+ TEST_ASSERT_EQUAL(SL_STATUS_NOT_SUPPORTED,
+ handler.control_handler(&info, NULL, 0));
+ const uint8_t report_number = 2;
+ const uint8_t reports[]
+ = {THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_HEATING,
+ 11,
+ 12,
+ 13,
+ 14,
+ THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_VENT_ECONOMIZER,
+ 21,
+ 22,
+ 23,
+ 24};
+
+ const uint8_t frame[] = {
+ COMMAND_CLASS_THERMOSTAT_OPERATING_STATE,
+ THERMOSTAT_OPERATING_STATE_LOGGING_REPORT_V2,
+ report_number,
+ 0b11110001, // Test if we correctly ignore the first 4 bits (THERMOSTAT_OPERATING_STATE_REPORT_OPERATING_STATE_HEATING)
+ reports[1],
+ reports[2],
+ reports[3],
+ reports[4],
+ reports[5],
+ reports[6],
+ reports[7],
+ reports[8],
+ reports[9],
+ };
+
+ TEST_ASSERT_EQUAL(SL_STATUS_OK,
+ handler.control_handler(&info, frame, sizeof(frame)));
+
+ TEST_ASSERT_EQUAL(report_number,
+ attribute_store_get_node_child_count(log_node));
+
+ const attribute_store_type_t attribute_store_types[] = {
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_USAGE_TODAY_HOURS,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_USAGE_TODAY_MIN,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_USAGE_YESTERDAY_HOURS,
+ ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_OPERATING_STATE_LOG_USAGE_YESTERDAY_MIN};
+
+ for (uint8_t i = 0; i < report_number; i++) {
+ attribute_store_node_t current_report_node
+ = attribute_store_get_node_child(log_node, i);
+
+ thermostat_operating_state_t reported_state;
+ attribute_store_get_reported(current_report_node,
+ &reported_state,
+ sizeof(reported_state));
+ // Expected index :
+ // 0
+ // 5
+ TEST_ASSERT_EQUAL_MESSAGE(reports[(5 * i)],
+ reported_state,
+ "Error while checking Operating State Log Type");
+
+ for (int j = 0; j < 4; j++) {
+ thermostat_operating_state_usage_t reported_value;
+
+ attribute_store_get_child_reported(current_report_node,
+ attribute_store_types[j],
+ &reported_value,
+ sizeof(reported_value));
+ // Expected index :
+ // 1,2,3,4 (1 + (5*i) + j)
+ // 6,7,8,9
+ const uint8_t index = 1 + (5 * i) + j;
+ printf("Checking report value of type %d with index %d\n",
+ attribute_store_types[j],
+ index);
+ TEST_ASSERT_EQUAL_MESSAGE(
+ reports[index],
+ reported_value,
+ "Error while checking Operating State Log contents");
+ }
+ }
+}
\ No newline at end of file
diff --git a/components/uic_dotdot/dotdot-xml/Unify_Thermostat.xml b/components/uic_dotdot/dotdot-xml/Unify_Thermostat.xml
new file mode 100644
index 0000000000..54b8c7d8ed
--- /dev/null
+++ b/components/uic_dotdot/dotdot-xml/Unify_Thermostat.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/uic_dotdot/dotdot-xml/library.xml b/components/uic_dotdot/dotdot-xml/library.xml
index 78c9d8140a..41096c633f 100644
--- a/components/uic_dotdot/dotdot-xml/library.xml
+++ b/components/uic_dotdot/dotdot-xml/library.xml
@@ -490,5 +490,5 @@ applicable to this document can be found in the LICENSE.md file.
-
+
diff --git a/components/uic_dotdot/zap-generated/include/dotdot_attribute_id_definitions.h b/components/uic_dotdot/zap-generated/include/dotdot_attribute_id_definitions.h
index 70c0a280c2..60293859a2 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
@@ -856,6 +856,8 @@ typedef enum {
#define DOTDOT_PROTOCOL_CONTROLLER_NETWORK_MANAGEMENT_NETWORK_MANAGEMENT_STATE_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x1)
// Definitions for cluster: Descriptor
#define DOTDOT_DESCRIPTOR_DEVICE_TYPE_LIST_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x0)
+// Definitions for cluster: UnifyThermostat
+#define DOTDOT_UNIFY_THERMOSTAT_OPERATING_STATE_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x3)
// clang-format on
diff --git a/components/uic_dotdot/zap-generated/include/dotdot_cluster_command_id_definitions.h b/components/uic_dotdot/zap-generated/include/dotdot_cluster_command_id_definitions.h
index 2833fd9544..a553279a68 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
@@ -364,6 +364,8 @@
// Commands for cluster: Descriptor
+// Commands for cluster: UnifyThermostat
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/components/uic_dotdot/zap-generated/include/dotdot_cluster_id_definitions.h b/components/uic_dotdot/zap-generated/include/dotdot_cluster_id_definitions.h
index 1878448a59..12890d4ec4 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
@@ -254,6 +254,10 @@
#define DOTDOT_DESCRIPTOR_CLUSTER_ID ((dotdot_cluster_id_t)0xFD13)
+// Definitions for cluster: UnifyThermostat
+#define DOTDOT_UNIFY_THERMOSTAT_CLUSTER_ID ((dotdot_cluster_id_t)0xFD15)
+
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/components/uic_dotdot/zap-generated/include/zap-types.h b/components/uic_dotdot/zap-generated/include/zap-types.h
index fb82f117ca..0310bd4877 100644
--- a/components/uic_dotdot/zap-generated/include/zap-types.h
+++ b/components/uic_dotdot/zap-generated/include/zap-types.h
@@ -1271,6 +1271,22 @@ typedef enum {
ZCL_TX_REPORT_TRANSMISSION_SPEED_UNKNOWN = 255,
} TxReportTransmissionSpeed;
+// Enum for UnifyThermostatOperatingState
+typedef enum {
+ ZCL_UNIFY_THERMOSTAT_OPERATING_STATE_OFF = 0,
+ ZCL_UNIFY_THERMOSTAT_OPERATING_STATE_HEATING = 1,
+ ZCL_UNIFY_THERMOSTAT_OPERATING_STATE_COOLING = 2,
+ ZCL_UNIFY_THERMOSTAT_OPERATING_STATE_FAN_ONLY = 3,
+ ZCL_UNIFY_THERMOSTAT_OPERATING_STATE_PENDING_HEAT = 4,
+ ZCL_UNIFY_THERMOSTAT_OPERATING_STATE_PENDING_COOL = 5,
+ ZCL_UNIFY_THERMOSTAT_OPERATING_STATE_VENT_ECONOMIZER = 6,
+ ZCL_UNIFY_THERMOSTAT_OPERATING_STATE_AUX_HEATING = 7,
+ ZCL_UNIFY_THERMOSTAT_OPERATING_STATE_2ND_STAGE_HEATING = 8,
+ ZCL_UNIFY_THERMOSTAT_OPERATING_STATE_2ND_STAGE_COOLING = 9,
+ ZCL_UNIFY_THERMOSTAT_OPERATING_STATE_2ND_STAGE_AUX_HEAT = 10,
+ ZCL_UNIFY_THERMOSTAT_OPERATING_STATE_3RD_STAGE_AUX_HEAT = 11,
+} UnifyThermostatOperatingState;
+
// Enum for WindowCoveringWindowCoveringType
typedef enum {
ZCL_WINDOW_COVERING_WINDOW_COVERING_TYPE_ROLLERSHADE = 0,
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 dbdfa36ecb..54d2d73e58 100644
--- a/components/uic_dotdot/zap-generated/readme_ucl_mqtt_reference.md
+++ b/components/uic_dotdot/zap-generated/readme_ucl_mqtt_reference.md
@@ -53949,6 +53949,270 @@ mosquitto_pub -t 'ucl/by-unid///Descriptor/Commands/ForceReadAttribute
+
+
+
+
+
+
+
+
+\page unify_thermostat UnifyThermostat Cluster
+The following commands and attributes are accepted as JSON payloads for the
+UnifyThermostat cluster.
+
+
+
+
+
+
+\section unify_thermostat_attrs UnifyThermostat Attributes
+The following attribute topics are used to retrieve the UnifyThermostat cluster state.
+
+
+
+\subsection unify_thermostat_attr_operating_state UnifyThermostat/OperatingState Attribute
+
+**MQTT Topic Pattern:**
+
+```
+[PREFIX]/UnifyThermostat/Attributes/OperatingState/Reported
+[PREFIX]/UnifyThermostat/Attributes/OperatingState/Desired
+```
+
+**MQTT Payload JSON Schema:**
+
+```json
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "UnifyThermostat Cluster OperatingState Attribute Properties",
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "UnifyThermostatOperatingState"
+ }
+ },
+ "required": [
+ "value"
+ ]
+}
+```
+
+
+**Example Mosquitto CLI Tool Usage**
+
+To see desired/reported value for OperatingState attribute under the by-unid topic space:
+
+```console
+mosquitto_sub -t 'ucl/by-unid/+/+/UnifyThermostat/Attributes/OperatingState/+'
+
+# Example output
+
+ucl/by-unid//ep0/UnifyThermostat/Attributes/OperatingState/Desired { "value": }
+ucl/by-unid//ep0/UnifyThermostat/Attributes/OperatingState/Reported { "value": }
+
+```
+
+
+
+
+\subsection unify_thermostat_attr_cluster_revision UnifyThermostat/ClusterRevision Attribute
+
+**MQTT Topic Pattern:**
+
+```
+[PREFIX]/UnifyThermostat/Attributes/ClusterRevision/Reported
+[PREFIX]/UnifyThermostat/Attributes/ClusterRevision/Desired
+```
+
+**MQTT Payload JSON Schema:**
+
+```json
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "UnifyThermostat 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///UnifyThermostat/Attributes/ClusterRevision/+'
+# Example output
+ucl/by-unid///UnifyThermostat/Attributes/ClusterRevision/Desired { "value": }
+ucl/by-unid///UnifyThermostat/Attributes/ClusterRevision/Reported { "value": }
+```
+
+
+
+
+
+
+
+
+
+
+\section unify_thermostat_recv_cmd_support UnifyThermostat Command Support
+
+**MQTT Topic Pattern:**
+
+```
+[PREFIX]/UnifyThermostat/SupportedCommands
+[PREFIX]/UnifyThermostat/SupportedGeneratedCommands
+```
+
+**MQTT Payload JSON Schema:**
+
+```json
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "UnifyThermostat 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 UnifyThermostat cluster under the by-unid topic space:
+
+```console
+mosquitto_sub -t 'ucl/by-unid///UnifyThermostat/SupportedCommands'
+# Example output
+ucl/by-unid///UnifyThermostat/SupportedCommands { "value": [] }
+```
+
+To see supported generated commands for UnifyThermostat cluster under the by-unid topic space:
+
+```console
+mosquitto_sub -t 'ucl/by-unid///UnifyThermostat/SupportedGeneratedCommands'
+# Example output
+ucl/by-unid///UnifyThermostat/SupportedGeneratedCommands { "value": [] }
+```
+
+
+
+
+
+
+
+
+
+
+\section unify_thermostat_cmds UnifyThermostat Commands
+
+
+
+\subsection unify_thermostat_write_attr_cmd UnifyThermostat/WriteAttributes Command
+
+**MQTT Topic Pattern:**
+
+```
+[PREFIX]/UnifyThermostat/Commands/WriteAttributes
+```
+
+**MQTT Payload JSON Schema:**
+
+```json
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "UnifyThermostat Cluster WriteAttributes Command Properties",
+ "type": "object",
+ "properties": {
+ },
+ "required": [
+ "value"
+ ]
+}
+```
+
+**Example Mosquitto CLI Tool Usage**
+
+To update all UnifyThermostat attributes under the by-unid topic space:
+
+```console
+mosquitto_pub -t 'ucl/by-unid///UnifyThermostat/Commands/WriteAttributes' -m '{ }'
+```
+
+> NOTE: Specify only the list of attributes to write in this command.
+> Unspecified attributes will not be updated.
+
+
+
+\subsection unify_thermostat_force_read_attr_cmd UnifyThermostat/ForceReadAttributes Command
+
+**MQTT Topic Pattern:**
+
+```
+[PREFIX]/UnifyThermostat/Commands/ForceReadAttributes
+```
+
+**MQTT Payload JSON Schema:**
+
+```json
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "UnifyThermostat Cluster ForceReadAttributes Command Properties",
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "array"
+ "items": {
+ "type": "string",
+ "enum": [
+ "OperatingState"
+ ]
+ }
+ }
+ },
+ "required": [
+ "value"
+ ]
+}
+```
+
+**Example Mosquitto CLI Tool Usage**
+
+To force read all UnifyThermostat attributes under the by-unid topic space (by sending an empty array):
+
+```console
+mosquitto_pub -t 'ucl/by-unid///UnifyThermostat/Commands/ForceReadAttributes' -m '{ "value": [] }'
+```
+
+To force read one of the UnifyThermostat attributes under the by-unid topic space:
+
+```console
+mosquitto_pub -t 'ucl/by-unid///UnifyThermostat/Commands/ForceReadAttributes' -m '{ "value": ["OperatingState"] }'
+```
+
+
+
+
+
@@ -57545,6 +57809,39 @@ mosquitto_pub -t 'ucl/by-unid///Descriptor/Commands/ForceReadAttribute
+
+
+
+\section enum_unify_thermostat_operating_state UnifyThermostatOperatingState Enum
+
+```json
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "UnifyThermostatOperatingState Enum Properties",
+ "type": "string",
+ "enum": [
+ "Off",
+ "Heating",
+ "Cooling",
+ "FanOnly",
+ "PendingHeat",
+ "PendingCool",
+ "Vent/Economizer",
+ "AuxHeating",
+ "2ndStageHeating",
+ "2ndStageCooling",
+ "2ndStageAuxHeat",
+ "3rdStageAuxHeat"
+ ]
+}
+```
+
+
+
+
+
+
+
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 cd3e175e69..75a469c49a 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
@@ -2025,6 +2025,17 @@ const char *uic_dotdot_get_attribute_name(dotdot_cluster_id_t cluster_id,
return "Unknown";
}
// clang-format off
+ case DOTDOT_UNIFY_THERMOSTAT_CLUSTER_ID:
+ // clang-format on
+ switch (attribute_id) {
+ // clang-format off
+ case DOTDOT_UNIFY_THERMOSTAT_OPERATING_STATE_ATTRIBUTE_ID:
+ return "OperatingState";
+ // clang-format on
+ default:
+ return "Unknown";
+ }
+ // clang-format off
// clang-format on
default:
return "Unknown";
@@ -4409,6 +4420,11 @@ dotdot_attribute_id_t
return DOTDOT_DESCRIPTOR_DEVICE_TYPE_LIST_ATTRIBUTE_ID;
}
break;
+ case DOTDOT_UNIFY_THERMOSTAT_CLUSTER_ID:
+ if (strcmp ("OperatingState", attribute_name) == 0) {
+ return DOTDOT_UNIFY_THERMOSTAT_OPERATING_STATE_ATTRIBUTE_ID;
+ }
+ break;
default:
return DOTDOT_INVALID_ATTRIBUTE_ID;
}
@@ -6426,6 +6442,17 @@ dotdot_attribute_json_type_t
return JSON_TYPE_UNKNOWN;
}
// clang-format off
+ case DOTDOT_UNIFY_THERMOSTAT_CLUSTER_ID:
+ // clang-format on
+ switch (attribute_id) {
+ // clang-format off
+ case DOTDOT_UNIFY_THERMOSTAT_OPERATING_STATE_ATTRIBUTE_ID:
+ return JSON_TYPE_NUMBER;
+ // clang-format on
+ default:
+ return JSON_TYPE_UNKNOWN;
+ }
+ // clang-format off
// clang-format on
default:
return JSON_TYPE_UNKNOWN;
@@ -6774,5 +6801,11 @@ bool uic_dotdot_attribute_is_enum(dotdot_cluster_id_t cluster_id,
if (64787 == cluster_id) {
}
+ if (64789 == cluster_id) {
+ if (3 == attribute_id) {
+ return true;
+ }
+ }
+
return false;
}
diff --git a/components/uic_dotdot/zap-generated/src/dotdot_cluster_id_definitions.c b/components/uic_dotdot/zap-generated/src/dotdot_cluster_id_definitions.c
index 18b5402fa7..dd4cb03a04 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
@@ -128,6 +128,8 @@ const char* uic_dotdot_get_cluster_name(dotdot_cluster_id_t cluster_id) {
return "ProtocolController-NetworkManagement";
case DOTDOT_DESCRIPTOR_CLUSTER_ID:
return "Descriptor";
+ case DOTDOT_UNIFY_THERMOSTAT_CLUSTER_ID:
+ return "UnifyThermostat";
default:
return "Unknown";
}
@@ -299,6 +301,9 @@ dotdot_cluster_id_t uic_dotdot_get_cluster_id(const char* cluster_name) {
if (strcmp ("Descriptor", cluster_name) == 0) {
return DOTDOT_DESCRIPTOR_CLUSTER_ID;
}
+ if (strcmp ("UnifyThermostat", cluster_name) == 0) {
+ return DOTDOT_UNIFY_THERMOSTAT_CLUSTER_ID;
+ }
// Return an invalid ID if we did not get any match.
return DOTDOT_INVALID_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 f0dc62b095..591b43c730 100644
--- a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt.h
+++ b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt.h
@@ -40444,6 +40444,157 @@ void uic_mqtt_dotdot_descriptor_publish_supported_commands(
void uic_mqtt_dotdot_descriptor_publish_empty_supported_commands(
const dotdot_unid_t unid
,dotdot_endpoint_id_t endpoint);
+// Callback types used by the unify_thermostat cluster
+
+typedef struct {
+ uint8_t operating_state;
+} uic_mqtt_dotdot_unify_thermostat_state_t;
+
+typedef struct {
+ bool operating_state;
+} uic_mqtt_dotdot_unify_thermostat_updated_state_t;
+
+typedef sl_status_t (*uic_mqtt_dotdot_unify_thermostat_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_thermostat_state_t,
+ uic_mqtt_dotdot_unify_thermostat_updated_state_t
+);
+
+typedef sl_status_t (*uic_mqtt_dotdot_unify_thermostat_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_thermostat_updated_state_t
+);
+
+
+
+
+/**
+ * @brief Setup a callback for WriteAttribute to be called when a
+ * +/unify_thermostat/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_thermostat_write_attributes_callback(
+ const uic_mqtt_dotdot_unify_thermostat_write_attributes_callback_t callback
+);
+/**
+ * @brief Unsets a callback for WriteAttribute to be called when a
+ * +/unify_thermostat/Commands/WriteAttributes is received.
+ * @param callback Function to be no longer called on command reception
+ */
+void uic_mqtt_dotdot_unset_unify_thermostat_write_attributes_callback(
+ const uic_mqtt_dotdot_unify_thermostat_write_attributes_callback_t callback
+);
+/**
+ * @brief Clears all callbacks registered for when
+ * +/unify_thermostat/Commands/WriteAttributes is received.
+ */
+void uic_mqtt_dotdot_clear_unify_thermostat_write_attributes_callbacks();
+
+/**
+ * @brief Setup a callback for ForceReadAttributes to be called when a
+ * +/unify_thermostat/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_thermostat_force_read_attributes_callback(
+ const uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback_t callback
+);
+/**
+ * @brief Unsets a callback for ForceReadAttributes to be called when a
+ * +/unify_thermostat/Commands/ForceReadAttributes is received.
+ *
+ * @param callback Function to be no longer called on command reception
+ */
+void uic_mqtt_dotdot_unset_unify_thermostat_force_read_attributes_callback(
+ const uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback_t callback
+);
+/**
+ * @brief Clears all callbacks registered for when
+ * +/unify_thermostat/Commands/ForceReadAttributes is received.
+ */
+void uic_mqtt_dotdot_clear_unify_thermostat_force_read_attributes_callbacks();
+
+/**
+ * @brief Publish the attribute; UnifyThermostat/Attributes/OperatingState
+ *
+ * @param base_topic topic prefix to publish, /operating_state
+ * 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_thermostat_operating_state_publish(
+ const char *base_topic,
+ uint8_t value,
+ uic_mqtt_dotdot_attribute_publish_type_t publish_type
+);
+
+/**
+ * @brief Unretains a published attribute; UnifyThermostat/Attributes/OperatingState
+ *
+ * @param base_topic topic prefix to publish, /operating_state
+ * 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_thermostat_operating_state_unretain(
+ const char *base_topic,
+ uic_mqtt_dotdot_attribute_publish_type_t publish_type
+);
+
+
+/**
+ * @brief Publish the UnifyThermostat/ClusterRevision attribute
+ *
+ * @param base_topic topic prefix to publish, /UnifyThermostat/Attributes/ClusterRevision
+ * will be appended.
+ * @param value Value to publish.
+ */
+void uic_mqtt_dotdot_unify_thermostat_publish_cluster_revision(const char* base_topic, uint16_t value);
+
+/**
+ * @brief Unretain a publication to UnifyThermostat/ClusterRevision attribute
+ *
+ * @param base_topic topic prefix to publish, /UnifyThermostat/Attributes/ClusterRevision
+ * will be appended.
+ */
+void uic_mqtt_dotdot_unify_thermostat_unretain_cluster_revision(const char* base_topic);
+
+/**
+ * @brief Publish the SupportedCommands for UNID/EndPoint for the UnifyThermostat Cluster
+ *
+ * This function will iterate over all Commands in the UnifyThermostat 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_thermostat_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 UnifyThermostat Cluster
+ *
+ * @param unid
+ * @param endpoint )
+ */
+void uic_mqtt_dotdot_unify_thermostat_publish_empty_supported_commands(
+ const dotdot_unid_t unid
+ ,dotdot_endpoint_id_t endpoint);
/**
* @brief Publish the SupportedCommands for UNID/EndPoint
diff --git a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_attributes.h b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_attributes.h
index 92daf48a23..afde171fdf 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
@@ -5134,6 +5134,14 @@ typedef sl_status_t (*uic_mqtt_dotdot_descriptor_attribute_device_type_list_call
size_t device_type_list_count,
const DeviceTypeStruct* device_type_list
);
+// Callback types used by the unify_thermostat cluster
+typedef sl_status_t (*uic_mqtt_dotdot_unify_thermostat_attribute_operating_state_callback_t)(
+ dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint,
+ bool unretained,
+ uic_mqtt_dotdot_attribute_update_type_t update_type,
+ uint8_t operating_state
+);
#ifdef __cplusplus
extern "C" {
@@ -9858,6 +9866,20 @@ sl_status_t uic_mqtt_dotdot_descriptor_attributes_init();
void uic_mqtt_dotdot_descriptor_attribute_device_type_list_callback_set(const uic_mqtt_dotdot_descriptor_attribute_device_type_list_callback_t callback);
+/**
+ * Initializes the attributes features for the UnifyThermostat cluster,
+ * allowing to receive attribute updates from other UNIDs.
+ */
+sl_status_t uic_mqtt_dotdot_unify_thermostat_attributes_init();
+
+/**
+ * Setup callback to be called when a
+ * UnifyThermostat/Attributes/operating_state/# is received. Setting
+ * this callback will overwrite the previous set callback
+ */
+void uic_mqtt_dotdot_unify_thermostat_attribute_operating_state_callback_set(const uic_mqtt_dotdot_unify_thermostat_attribute_operating_state_callback_t callback);
+
+
#ifdef __cplusplus
}
#endif // __cplusplus
diff --git a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_generated_commands.h b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_generated_commands.h
index 16d97617d4..01bbaadead 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
@@ -4987,6 +4987,28 @@ void uic_mqtt_dotdot_descriptor_publish_generated_write_attributes_command(
);
+/**
+ * @brief Publishes an incoming/generated WriteAttributes command for
+ * the UnifyThermostat cluster.
+ *
+ * Publication will be made at the following topic
+ * ucl/by-unid/UNID/epID/UnifyThermostat/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_thermostat_publish_generated_write_attributes_command(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint,
+ uic_mqtt_dotdot_unify_thermostat_state_t attribute_values,
+ uic_mqtt_dotdot_unify_thermostat_updated_state_t attribute_list
+);
+
+
#ifdef __cplusplus
}
#endif // __cplusplus
diff --git a/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_group_commands.h b/components/uic_dotdot_mqtt/zap-generated/include/dotdot_mqtt_group_commands.h
index a5c1d17ef9..c17a3b068d 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,23 @@ void uic_mqtt_dotdot_by_group_descriptor_write_attributes_callback_set(
+typedef void (*uic_mqtt_dotdot_by_group_unify_thermostat_write_attributes_callback_t)(
+ const dotdot_group_id_t group_id,
+ uic_mqtt_dotdot_unify_thermostat_state_t,
+ uic_mqtt_dotdot_unify_thermostat_updated_state_t
+);
+
+/**
+ * Setup a callback for WriteAttribute to be called when a
+ * ucl/by-group/+/unify_thermostat/Commands/WriteAttributes is received.
+ * Setting this callback will overwrite any previously set callback.
+ */
+void uic_mqtt_dotdot_by_group_unify_thermostat_write_attributes_callback_set(
+ const uic_mqtt_dotdot_by_group_unify_thermostat_write_attributes_callback_t callback
+);
+
+
+
#ifdef __cplusplus
}
#endif // __cplusplus
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 dcc29ad5f1..d397d4e972 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
@@ -811,6 +811,13 @@ char *tx_report_transmission_speed_get_enum_value_name_c(
uint32_t value, char *result, size_t max_result_size);
/** Get tx_report_transmission_speed enum representation from string. */
uint32_t tx_report_transmission_speed_get_enum_value_number_c(const char *str);
+#define UNIFY_THERMOSTAT_OPERATING_STATE_ENUM_NAME_AVAILABLE 1
+
+/** Get unify_thermostat_operating_state string representation from enum. */
+char *unify_thermostat_operating_state_get_enum_value_name_c(
+ uint32_t value, char *result, size_t max_result_size);
+/** Get unify_thermostat_operating_state enum representation from string. */
+uint32_t unify_thermostat_operating_state_get_enum_value_number_c(const char *str);
#define WINDOW_COVERING_WINDOW_COVERING_TYPE_ENUM_NAME_AVAILABLE 1
/** Get window_covering_window_covering_type 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 8db91a511c..5eb54ab03a 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
@@ -1934,6 +1934,23 @@ std::string tx_report_transmission_speed_get_enum_value_name(
*/
uint32_t tx_report_transmission_speed_get_enum_value_number(const std::string &str);
+#define UNIFY_THERMOSTAT_OPERATING_STATE_ENUM_NAME_AVAILABLE 1
+
+/**
+ * @brief Finds the name of a field for the UnifyThermostatOperatingState enum
+ *
+ * @returns A string representation of the value.
+ */
+std::string unify_thermostat_operating_state_get_enum_value_name(
+ uint32_t value);
+
+/**
+ * @brief Finds the enum number of a string representation for the UnifyThermostatOperatingState enum
+ *
+ * @returns A number enum value.
+ */
+uint32_t unify_thermostat_operating_state_get_enum_value_number(const std::string &str);
+
#define WINDOW_COVERING_WINDOW_COVERING_TYPE_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 3180bd0498..af6b1f805b 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
@@ -1664,6 +1664,34 @@ void uic_mqtt_dotdot_descriptor_publish_supported_generated_commands(
);
+/**
+ * @brief Struct containing the list of commands for UnifyThermostat
+ */
+typedef struct _uic_mqtt_dotdot_unify_thermostat_supported_commands_ {
+ bool write_attributes;
+} uic_mqtt_dotdot_unify_thermostat_supported_commands_t;
+
+/**
+ * @brief Sends/Publishes a the SupportedGenerated commands for
+ * the UnifyThermostat cluster for a UNID/Endpoint
+ *
+ * Publication will be made at the following topic
+ * ucl/by-unid/UNID/epID/UnifyThermostat/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_thermostat_publish_supported_generated_commands(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint,
+ const uic_mqtt_dotdot_unify_thermostat_supported_commands_t *command_list
+);
+
+
#ifdef __cplusplus
}
diff --git a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.cpp b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.cpp
index 5dbf0c607a..46e857b6e1 100644
--- a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.cpp
+++ b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.cpp
@@ -94739,6 +94739,269 @@ sl_status_t uic_mqtt_dotdot_descriptor_init()
return SL_STATUS_OK;
}
+// Callbacks pointers
+static std::set uic_mqtt_dotdot_unify_thermostat_write_attributes_callback;
+static std::set uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback;
+
+// Callbacks setters
+
+void uic_mqtt_dotdot_set_unify_thermostat_write_attributes_callback(
+ const uic_mqtt_dotdot_unify_thermostat_write_attributes_callback_t callback)
+{
+ if (callback != nullptr) {
+ uic_mqtt_dotdot_unify_thermostat_write_attributes_callback.insert(callback);
+ }
+}
+void uic_mqtt_dotdot_unset_unify_thermostat_write_attributes_callback(
+ const uic_mqtt_dotdot_unify_thermostat_write_attributes_callback_t callback)
+{
+ uic_mqtt_dotdot_unify_thermostat_write_attributes_callback.erase(callback);
+}
+void uic_mqtt_dotdot_clear_unify_thermostat_write_attributes_callbacks()
+{
+ uic_mqtt_dotdot_unify_thermostat_write_attributes_callback.clear();
+}
+std::set& get_uic_mqtt_dotdot_unify_thermostat_write_attributes_callback()
+{
+ return uic_mqtt_dotdot_unify_thermostat_write_attributes_callback;
+}
+
+void uic_mqtt_dotdot_set_unify_thermostat_force_read_attributes_callback(
+ const uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback_t callback)
+{
+ if (callback != nullptr) {
+ uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback.insert(callback);
+ }
+}
+void uic_mqtt_dotdot_unset_unify_thermostat_force_read_attributes_callback(
+ const uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback_t callback)
+{
+ uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback.erase(callback);
+}
+void uic_mqtt_dotdot_clear_unify_thermostat_force_read_attributes_callbacks()
+{
+ uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback.clear();
+}
+
+
+// Callback function for incoming publications on ucl/by-unid/+/+/UnifyThermostat/Commands/WriteAttributes
+void uic_mqtt_dotdot_on_unify_thermostat_WriteAttributes(
+ const char *topic,
+ const char *message,
+ const size_t message_length)
+{
+ if (uic_mqtt_dotdot_unify_thermostat_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_thermostat_state_t new_state = {};
+ uic_mqtt_dotdot_unify_thermostat_updated_state_t new_updated_state = {};
+
+
+ nlohmann::json jsn;
+ try {
+ jsn = nlohmann::json::parse(std::string(message));
+
+ uic_mqtt_dotdot_parse_unify_thermostat_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, "UnifyThermostat", "WriteAttributes");
+ return;
+ } catch (const nlohmann::json::exception& e) {
+ // Catch JSON object field parsing errors
+ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyThermostat", "WriteAttributes", e.what());
+ return;
+ } catch (const std::exception& e) {
+ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyThermostat", "WriteAttributes", "");
+ return;
+ }
+
+ for (const auto& callback: uic_mqtt_dotdot_unify_thermostat_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_thermostat_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_thermostat_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_thermostat_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.operating_state = true;
+ trigger_handler = true;
+ } else {
+ std::unordered_map supported_attrs = {
+ {"OperatingState", &force_update.operating_state },
+ };
+
+ 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_thermostat_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, "UnifyThermostat/Commands/ForceReadAttributes: Unable to parse JSON payload");
+ return;
+ }
+}
+
+sl_status_t uic_mqtt_dotdot_unify_thermostat_operating_state_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 UNIFY_THERMOSTAT_OPERATING_STATE_ENUM_NAME_AVAILABLE
+ jsn["value"] = unify_thermostat_operating_state_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 UNIFY_THERMOSTAT_OPERATING_STATE. 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, "UnifyThermostat/Attributes/OperatingState", e.what());
+ return SL_STATUS_OK;
+ }
+
+
+ std::string topic = std::string(base_topic) + "/UnifyThermostat/Attributes/OperatingState";
+ 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_thermostat_operating_state_unretain(
+ const char *base_topic,
+ uic_mqtt_dotdot_attribute_publish_type_t publish_type)
+{
+ // clang-format on
+ std::string topic
+ = std::string(base_topic)
+ + "/UnifyThermostat/Attributes/OperatingState";
+
+ 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_thermostat_init()
+{
+ std::string base_topic = "ucl/by-unid/+/+/";
+
+ std::string subscription_topic;
+ if(!uic_mqtt_dotdot_unify_thermostat_write_attributes_callback.empty()) {
+ subscription_topic = base_topic + "UnifyThermostat/Commands/WriteAttributes";
+ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_unify_thermostat_WriteAttributes);
+ }
+
+ if(!uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback.empty()) {
+ subscription_topic = base_topic + "UnifyThermostat/Commands/ForceReadAttributes";
+ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_unify_thermostat_force_read_attributes);
+ }
+
+ // Init the attributes for that cluster
+ uic_mqtt_dotdot_unify_thermostat_attributes_init();
+
+ uic_mqtt_dotdot_by_group_unify_thermostat_init();
+
+ return SL_STATUS_OK;
+}
+
sl_status_t uic_mqtt_dotdot_init() {
@@ -94952,6 +95215,10 @@ sl_status_t uic_mqtt_dotdot_init() {
status_flag = uic_mqtt_dotdot_descriptor_init();
}
+ if (status_flag == SL_STATUS_OK) {
+ status_flag = uic_mqtt_dotdot_unify_thermostat_init();
+ }
+
return status_flag;
}
@@ -95013,6 +95280,7 @@ void uic_mqtt_dotdot_publish_supported_commands(
uic_mqtt_dotdot_aox_position_estimation_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_thermostat_publish_supported_commands(unid, endpoint_id);
}
void uic_mqtt_dotdot_publish_empty_supported_commands(
@@ -95071,6 +95339,7 @@ void uic_mqtt_dotdot_publish_empty_supported_commands(
uic_mqtt_dotdot_aox_position_estimation_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_thermostat_publish_empty_supported_commands(unid, endpoint_id);
}
// Publishing Cluster Revision for Basic Cluster
@@ -108533,6 +108802,154 @@ void uic_mqtt_dotdot_descriptor_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)
+{
+ 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;
+ }
+ }
+ return false;
+}
+
+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_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_thermostat_force_update
+ ) == SL_STATUS_OK) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// 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)
+{
+ 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_unify_thermostat_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_thermostat_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 += "/UnifyThermostat/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 += "/UnifyThermostat/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 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 += "/UnifyThermostat/SupportedCommands";
+
+ if (uic_mqtt_count_topics(topic.c_str()) > 0) {
+ uic_mqtt_publish(topic.c_str(),
+ EMPTY_VALUE_ARRAY,
+ strlen(EMPTY_VALUE_ARRAY),
+ true);
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// Generated Commands publications functions
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 156e7b356d..87e323a05c 100644
--- a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.hpp
+++ b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt.hpp
@@ -367,6 +367,13 @@ sl_status_t uic_mqtt_dotdot_by_group_aox_position_estimation_init();
*/
sl_status_t uic_mqtt_dotdot_by_group_descriptor_init();
+/**
+ * @brief Initialize UnifyThermostat dotdot bygroup command handlers
+ *
+ * @returns SL_STATUS_OK on success, error otherwise.
+ */
+sl_status_t uic_mqtt_dotdot_by_group_unify_thermostat_init();
+
// clang-format on
@@ -5052,6 +5059,27 @@ void uic_mqtt_dotdot_on_descriptor_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_unify_thermostat_write_attributes_callback();
+
+/**
+ * @brief MQTT Subscribe handler for incoming publications on:
+ * ucl/by-unid/+/+/UnifyThermostat/Commands/WriteAttributes
+ */
+// clang-format off
+void uic_mqtt_dotdot_on_unify_thermostat_WriteAttributes(
+ const char *topic,
+ const char *message,
+ const size_t message_length);
+
+
// All bitmaps are defined as the cluster label for the bitmap plus the command/attribute name
diff --git a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_attributes.cpp b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_attributes.cpp
index 43090fc989..a079b69c1e 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
@@ -63117,3 +63117,123 @@ void uic_mqtt_dotdot_descriptor_attribute_device_type_list_callback_set(const ui
// End of supported cluster.
+///////////////////////////////////////////////////////////////////////////////
+// Callback pointers for UnifyThermostat
+///////////////////////////////////////////////////////////////////////////////
+static uic_mqtt_dotdot_unify_thermostat_attribute_operating_state_callback_t uic_mqtt_dotdot_unify_thermostat_attribute_operating_state_callback = nullptr;
+
+///////////////////////////////////////////////////////////////////////////////
+// Attribute update handlers for UnifyThermostat
+///////////////////////////////////////////////////////////////////////////////
+static void uic_mqtt_dotdot_on_unify_thermostat_operating_state_attribute_update(
+ const char *topic,
+ const char *message,
+ const size_t message_length) {
+ if (uic_mqtt_dotdot_unify_thermostat_attribute_operating_state_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 operating_state = {};
+
+ 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, "UnifyThermostat::OperatingState: 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 UNIFY_THERMOSTAT_OPERATING_STATE_ENUM_NAME_AVAILABLE
+ tmp = unify_thermostat_operating_state_get_enum_value_number(json_payload.at("value").get());
+ #elif defined(OPERATING_STATE_ENUM_NAME_AVAILABLE)
+ tmp = operating_state_get_enum_value_number(json_payload.at("value").get());
+ #endif
+ }
+ operating_state = 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_unify_thermostat_attribute_operating_state_callback(
+ static_cast(unid.c_str()),
+ endpoint,
+ unretained,
+ update_type,
+ operating_state
+ );
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Attribute init functions for UnifyThermostat
+///////////////////////////////////////////////////////////////////////////////
+sl_status_t uic_mqtt_dotdot_unify_thermostat_attributes_init()
+{
+ std::string base_topic = "ucl/by-unid/+/+/";
+
+ std::string subscription_topic;
+ if(uic_mqtt_dotdot_unify_thermostat_attribute_operating_state_callback) {
+ subscription_topic = base_topic + "UnifyThermostat/Attributes/OperatingState/#";
+ uic_mqtt_subscribe(subscription_topic.c_str(), &uic_mqtt_dotdot_on_unify_thermostat_operating_state_attribute_update);
+ }
+
+ return SL_STATUS_OK;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Callback setters and getters for UnifyThermostat
+///////////////////////////////////////////////////////////////////////////////
+void uic_mqtt_dotdot_unify_thermostat_attribute_operating_state_callback_set(const uic_mqtt_dotdot_unify_thermostat_attribute_operating_state_callback_t callback)
+{
+ uic_mqtt_dotdot_unify_thermostat_attribute_operating_state_callback = callback;
+}
+
+// End of supported cluster.
+
diff --git a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_command_helpers.cpp b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_command_helpers.cpp
index 0ee153812b..32da8bb9b6 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
@@ -14797,5 +14797,21 @@ void uic_mqtt_dotdot_parse_descriptor_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_unify_thermostat_write_attributes(
+ nlohmann::json &jsn,
+ uic_mqtt_dotdot_unify_thermostat_state_t &new_state,
+ uic_mqtt_dotdot_unify_thermostat_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 21f137181d..94e4e8594f 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
@@ -6071,6 +6071,18 @@ void uic_mqtt_dotdot_parse_descriptor_write_attributes(
);
+/**
+ * @brief JSON parser for UnifyThermostat WriteAttributes command arguments.
+ *
+ * Parse incoming JSON object to populate command arguments passed in by reference.
+ */
+void uic_mqtt_dotdot_parse_unify_thermostat_write_attributes(
+ nlohmann::json &jsn,
+ uic_mqtt_dotdot_unify_thermostat_state_t &new_state,
+ uic_mqtt_dotdot_unify_thermostat_updated_state_t &new_updated_state
+);
+
+
#endif //DOTDOT_MQTT_COMMAND_HELPERS_HPP
/** @} end dotdot_mqtt_command_helpers */
diff --git a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_generated_commands.cpp b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_generated_commands.cpp
index a09f1a69cf..e2f9193f69 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
@@ -11396,3 +11396,43 @@ void uic_mqtt_dotdot_descriptor_publish_generated_write_attributes_command(
false);
}
+
+
+/**
+ * @brief Publishes an incoming/generated WriteAttributes command for
+ * the UnifyThermostat cluster.
+ *
+ * Publication will be made at the following topic
+ * ucl/by-unid/UNID/epID/UnifyThermostat/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_thermostat_publish_generated_write_attributes_command(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint,
+ uic_mqtt_dotdot_unify_thermostat_state_t attribute_values,
+ uic_mqtt_dotdot_unify_thermostat_updated_state_t attribute_list
+){
+ // Create the topic
+ std::string topic = "ucl/by-unid/"+ std::string(unid) + "/ep" +
+ std::to_string(endpoint) + "/";
+ topic += "UnifyThermostat/GeneratedCommands/WriteAttributes";
+
+ nlohmann::json json_object = nlohmann::json::object();
+
+
+ // Payload contains data from end nodes, which we cannot control, thus we handle if there are non-utf8 characters
+ std::string payload = json_object.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace);
+
+ // Publish our command
+ uic_mqtt_publish(topic.c_str(),
+ payload.c_str(),
+ payload.size(),
+ false);
+}
+
diff --git a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_group_commands.cpp b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_group_commands.cpp
index 5d85d166d8..b0168f71a4 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
@@ -366,6 +366,9 @@ static uic_mqtt_dotdot_by_group_aox_position_estimation_write_attributes_callbac
static uic_mqtt_dotdot_by_group_descriptor_write_attributes_callback_t uic_mqtt_dotdot_by_group_descriptor_write_attributes_callback = nullptr;
+static uic_mqtt_dotdot_by_group_unify_thermostat_write_attributes_callback_t uic_mqtt_dotdot_by_group_unify_thermostat_write_attributes_callback = nullptr;
+
+
// Callbacks setters
@@ -1876,6 +1879,15 @@ void uic_mqtt_dotdot_by_group_descriptor_write_attributes_callback_set(
+// Callbacks setters
+void uic_mqtt_dotdot_by_group_unify_thermostat_write_attributes_callback_set(
+ const uic_mqtt_dotdot_by_group_unify_thermostat_write_attributes_callback_t callback)
+{
+ uic_mqtt_dotdot_by_group_unify_thermostat_write_attributes_callback = callback;
+}
+
+
+
// Callback function for incoming publications on ucl/by-group/+/Basic/Commands/ResetToFactoryDefaults
static void uic_mqtt_dotdot_on_by_group_basic_reset_to_factory_defaults(
@@ -23492,6 +23504,91 @@ sl_status_t uic_mqtt_dotdot_by_group_descriptor_init()
+
+static void uic_mqtt_dotdot_on_by_group_unify_thermostat_WriteAttributes(
+ const char *topic,
+ const char *message,
+ const size_t message_length)
+{
+
+ if ((group_dispatch_callback == nullptr) && (uic_mqtt_dotdot_by_group_unify_thermostat_write_attributes_callback == nullptr)) {
+ return;
+ }
+ if (message_length == 0) {
+ return;
+ }
+
+ dotdot_group_id_t group_id = 0U;
+ if(!uic_dotdot_mqtt::parse_topic_group_id(topic,group_id)) {
+ sl_log_debug(LOG_TAG,
+ "Failed to parse GroupId from topic %s. Ignoring",
+ topic);
+ return;
+ }
+
+ if ((group_dispatch_callback != nullptr) && (!get_uic_mqtt_dotdot_unify_thermostat_write_attributes_callback().empty())) {
+ try {
+ group_dispatch_callback(group_id,
+ "UnifyThermostat",
+ "WriteAttributes",
+ message,
+ message_length,
+ uic_mqtt_dotdot_on_unify_thermostat_WriteAttributes);
+
+ } catch (...) {
+ sl_log_debug(LOG_TAG, "UnifyThermostat: Unable to parse JSON payload.\n");
+ return;
+ }
+ } else if (uic_mqtt_dotdot_by_group_unify_thermostat_write_attributes_callback != nullptr) {
+
+ uic_mqtt_dotdot_unify_thermostat_state_t new_state = {};
+ uic_mqtt_dotdot_unify_thermostat_updated_state_t new_updated_state = {};
+
+
+ nlohmann::json jsn;
+ try {
+ jsn = nlohmann::json::parse(std::string(message));
+
+ uic_mqtt_dotdot_parse_unify_thermostat_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, "UnifyThermostat", "WriteAttributes");
+ return;
+ } catch (const nlohmann::json::exception& e) {
+ // Catch JSON object field parsing errors
+ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyThermostat", "WriteAttributes", e.what());
+ return;
+ } catch (const std::exception& e) {
+ sl_log_debug(LOG_TAG, LOG_FMT_JSON_ERROR, "UnifyThermostat", "WriteAttributes", "");
+ return;
+ }
+
+ uic_mqtt_dotdot_by_group_unify_thermostat_write_attributes_callback(
+ group_id,
+ new_state,
+ new_updated_state
+ );
+ }
+}
+
+sl_status_t uic_mqtt_dotdot_by_group_unify_thermostat_init()
+{
+ std::string subscription_topic;
+ const std::string topic_bygroup = TOPIC_BY_GROUP_PREFIX;
+ if(uic_mqtt_dotdot_by_group_unify_thermostat_write_attributes_callback) {
+ subscription_topic = topic_bygroup + "UnifyThermostat/Commands/WriteAttributes";
+ uic_mqtt_subscribe(subscription_topic.c_str(), uic_mqtt_dotdot_on_by_group_unify_thermostat_WriteAttributes);
+ }
+
+ return SL_STATUS_OK;
+}
+
+
+
void uic_mqtt_dotdot_set_group_dispatch_callback(group_dispatch_t callback)
{
// Check for uninitialized value in order to subscribe with on_group handlers
@@ -23773,6 +23870,8 @@ void uic_mqtt_dotdot_set_group_dispatch_callback(group_dispatch_t callback)
uic_mqtt_subscribe("ucl/by-group/+/Descriptor/Commands/WriteAttributes", uic_mqtt_dotdot_on_by_group_descriptor_WriteAttributes);
+ uic_mqtt_subscribe("ucl/by-group/+/UnifyThermostat/Commands/WriteAttributes", uic_mqtt_dotdot_on_by_group_unify_thermostat_WriteAttributes);
+
}
group_dispatch_callback = callback;
diff --git a/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_helpers.cpp b/components/uic_dotdot_mqtt/zap-generated/src/dotdot_mqtt_helpers.cpp
index e777d585ab..6a5b97ece5 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
@@ -5064,6 +5064,63 @@ uint32_t tx_report_transmission_speed_get_enum_value_number(const std::string &s
return std::numeric_limits::max();
}
+// Enum to string map for UnifyThermostatOperatingState
+const std::map unify_thermostat_operating_state_enum_id_to_string_map {
+ { 0, "Off" },
+ { 1, "Heating" },
+ { 2, "Cooling" },
+ { 3, "FanOnly" },
+ { 4, "PendingHeat" },
+ { 5, "PendingCool" },
+ { 6, "Vent/Economizer" },
+ { 7, "AuxHeating" },
+ { 8, "2ndStageHeating" },
+ { 9, "2ndStageCooling" },
+ { 10, "2ndStageAuxHeat" },
+ { 11, "3rdStageAuxHeat" },
+};
+
+// String to enum map for UnifyThermostatOperatingState
+const std::map unify_thermostat_operating_state_enum_string_to_id_map {
+ { "Off", 0 },
+ { "Heating", 1 },
+ { "Cooling", 2 },
+ { "FanOnly", 3 },
+ { "PendingHeat", 4 },
+ { "PendingCool", 5 },
+ { "Vent/Economizer", 6 },
+ { "AuxHeating", 7 },
+ { "2ndStageHeating", 8 },
+ { "2ndStageCooling", 9 },
+ { "2ndStageAuxHeat", 10 },
+ { "3rdStageAuxHeat", 11 },
+};
+
+std::string unify_thermostat_operating_state_get_enum_value_name(
+ uint32_t value)
+{
+ auto it = unify_thermostat_operating_state_enum_id_to_string_map.find(value);
+ if (it != unify_thermostat_operating_state_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 unify_thermostat_operating_state_get_enum_value_number(const std::string &str)
+{
+ auto it = unify_thermostat_operating_state_enum_string_to_id_map.find(str);
+ if (it != unify_thermostat_operating_state_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 WindowCoveringWindowCoveringType
const std::map window_covering_window_covering_type_enum_id_to_string_map {
{ 0, "Rollershade" },
@@ -9908,6 +9965,15 @@ std::string get_enum_value_name(
#endif
}
+ if (64789 == cluster_id) {
+ #ifdef UNIFY_THERMOSTAT_OPERATING_STATE_ENUM_NAME_AVAILABLE
+ if (3 == attribute_id) {
+ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_thermostatoperating_state instead of this: unify_thermostat_operating_state
+ return unify_thermostat_operating_state_get_enum_value_name(value);
+ }
+ #endif
+ }
+
std::string value_name;
return value_name;
@@ -14376,6 +14442,15 @@ uint32_t get_enum_name_value(
#endif
}
+ if (64789 == cluster_id) {
+ #ifdef UNIFY_THERMOSTAT_OPERATING_STATE_ENUM_NAME_AVAILABLE
+ if (3 == attribute_id) {
+ // FIXME: Some attributes don't work because multi-upper case names end up like this: unify_thermostatoperating_state instead of this: unify_thermostat_operating_state
+ return unify_thermostat_operating_state_get_enum_value_number(name);
+ }
+ #endif
+ }
+
// No known numeric value is set for this string.
// Return UINT32_MAX to indicate an error.
@@ -15616,6 +15691,17 @@ uint32_t tx_report_transmission_speed_get_enum_value_number_c(const char *str)
{
return tx_report_transmission_speed_get_enum_value_number(std::string(str));
}
+char *unify_thermostat_operating_state_get_enum_value_name_c(
+ uint32_t value, char *result, size_t max_result_size)
+{
+ snprintf(result, max_result_size, "%s", unify_thermostat_operating_state_get_enum_value_name(value).c_str());
+ return result;
+}
+
+uint32_t unify_thermostat_operating_state_get_enum_value_number_c(const char *str)
+{
+ return unify_thermostat_operating_state_get_enum_value_number(std::string(str));
+}
char *window_covering_window_covering_type_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 a2d5d754d8..c5aa5ff47d 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
@@ -2812,3 +2812,46 @@ void uic_mqtt_dotdot_descriptor_publish_supported_generated_commands(
}
+
+/**
+ * @brief Sends/Publishes a the SupportedGenerated commands for
+ * the UnifyThermostat cluster for a UNID/Endpoint
+ *
+ * Publication will be made at the following topic
+ * ucl/by-unid/UNID/epID/UnifyThermostat/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_thermostat_publish_supported_generated_commands(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint,
+ const uic_mqtt_dotdot_unify_thermostat_supported_commands_t *command_list)
+{
+ std::string topic = "ucl/by-unid/" + std::string(unid);
+ topic += "/ep"+ std::to_string(endpoint);
+ topic += "/UnifyThermostat/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);
+
+}
+
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 4884cdd28a..824a87d6a2 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
@@ -3649,6 +3649,7 @@ static void unset_all_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();
+ uic_mqtt_dotdot_clear_unify_thermostat_write_attributes_callbacks();
}
static void reset_callback_counters()
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 88967fac0a..f2944bc866 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
@@ -863,3 +863,6 @@ def DOTDOT_ATTRIBUTE_ID_PROTOCOL_CONTROLLER_NETWORK_MANAGEMENT_NETWORK_MANAGEMEN
// This represents the attributes in the DotDot Descriptor cluster
def DOTDOT_ATTRIBUTE_ID_DESCRIPTOR_DEVICE_TYPE_LIST 0xfd130000
+// This represents the attributes in the DotDot UnifyThermostat cluster
+def DOTDOT_ATTRIBUTE_ID_UNIFY_THERMOSTAT_OPERATING_STATE 0xfd150003
+
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 c4ef2c208c..4d3667dbae 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
@@ -863,3 +863,6 @@ def zb_NetworkManagementState 0xfd120001
// This represents short CamelCase labels the attributes in the DotDot Descriptor cluster
def zb_DeviceTypeList 0xfd130000
+// This represents short CamelCase labels the attributes in the DotDot UnifyThermostat cluster
+def zb_OperatingState 0xfd150003
+
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 16d75f051f..db84c6b080 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
@@ -77649,6 +77649,140 @@ bool dotdot_is_any_descriptor_writable_attribute_supported(
const dotdot_unid_t unid,
const dotdot_endpoint_id_t endpoint_id);
+////////////////////////////////////////////////////////////////////////////////
+// Start of cluster UnifyThermostat
+////////////////////////////////////////////////////////////////////////////////
+// UnifyThermostat OperatingState
+/**
+ * @brief Verifies if the DotDot UnifyThermostat - OperatingState is supported
+ * under a UNID/EndpoinID
+ *
+ * @param unid Node's UNID
+ * @param endpoint_id Endpoint ID
+ *
+ * @returns true if OperatingState is supported
+ * @returns false if OperatingState is not supported
+ */
+bool dotdot_is_supported_unify_thermostat_operating_state (
+ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id);
+
+/**
+ * @brief Gets the DotDot UnifyThermostat - OperatingState 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 OperatingState attribute
+ */
+uint8_t dotdot_get_unify_thermostat_operating_state(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint_id,
+ attribute_store_node_value_state_t value_state);
+
+/**
+ * @brief Set the DotDot UnifyThermostat - OperatingState 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_operating_state new value to set
+ * @returns sl_status_t SL_STATUS_OK on success
+ */
+sl_status_t dotdot_set_unify_thermostat_operating_state(
+ const dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint_id,
+ attribute_store_node_value_state_t value_state,
+ uint8_t new_operating_state
+ );
+
+/**
+ * @brief Undefines the Reported value of the the DotDot UnifyThermostat - OperatingState
+ * attribute under a UNID/EndpoinID
+ *
+ * @param unid Node's UNID
+ * @param endpoint_id Endpoint ID
+ * @returns sl_status_t SL_STATUS_OK on success
+ */
+sl_status_t dotdot_unify_thermostat_operating_state_undefine_reported(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint_id);
+
+/**
+ * @brief Undefines the Desired value of the DotDot
+ * UnifyThermostat - OperatingState attribute under a UNID/EndpointID
+ *
+ * @param unid Node's UNID
+ * @param endpoint_id Endpoint ID
+ * @returns sl_status_t SL_STATUS_OK on success
+ */
+sl_status_t dotdot_unify_thermostat_operating_state_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
+ * UnifyThermostat - OperatingState attribute under a UNID/EndpointID
+ *
+ * @param unid Node's UNID
+ * @param endpoint_id Endpoint ID
+ * @returns true if defined, false is undefined or non-existent
+ */
+bool dotdot_unify_thermostat_operating_state_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
+ * UnifyThermostat - OperatingState attribute under a UNID/EndpointID
+ *
+ * @param unid Node's UNID
+ * @param endpoint_id Endpoint ID
+ * @returns true if defined, false is undefined or non-existent
+ */
+bool dotdot_unify_thermostat_operating_state_is_desired_defined(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint_id);
+
+/**
+ * @brief Creates a DotDot UnifyThermostat - OperatingState attribute under a UNID/EndpoinID
+ *
+ * @param unid Node's UNID
+ * @param endpoint_id Endpoint ID
+ * @returns sl_status_t SL_STATUS_OK on success
+ */
+sl_status_t dotdot_create_unify_thermostat_operating_state(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint_id);
+
+/**
+ * @brief Checks if a UNID/Endpoint supports any attribute for the UnifyThermostat
+ * Cluster
+ *
+ * @param unid Node's UNID
+ * @param endpoint_id Endpoint ID
+ * @returns true if at least 1 attribute in the Attribute Store, false otherwise
+ */
+bool dotdot_is_any_unify_thermostat_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
+ * UnifyThermostat Cluster
+ *
+ * @param unid Node's UNID
+ * @param endpoint_id Endpoint ID
+ * @returns true if at least 1 writable attribute in the Attribute Store, false otherwise
+ */
+bool dotdot_is_any_unify_thermostat_writable_attribute_supported(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint_id);
+
#ifdef __cplusplus
}
#endif // __cplusplus
diff --git a/components/unify_dotdot_attribute_store/zap-generated/include/unify_dotdot_defined_attribute_types.h b/components/unify_dotdot_attribute_store/zap-generated/include/unify_dotdot_defined_attribute_types.h
index 0118d5ba2d..c8228fe1fb 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
@@ -794,6 +794,8 @@ DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_AOX_POSITION_ESTIMATION_POSITION , 0xfd1100
DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_PROTOCOL_CONTROLLER_NETWORK_MANAGEMENT_NETWORK_MANAGEMENT_STATE , 0xfd120001)
// Attribute Defines for Descriptor
DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_DESCRIPTOR_DEVICE_TYPE_LIST , 0xfd130000)
+// Attribute Defines for UnifyThermostat
+DEFINE_ATTRIBUTE(DOTDOT_ATTRIBUTE_ID_UNIFY_THERMOSTAT_OPERATING_STATE , 0xfd150003)
// Additional manually defined types:
diff --git a/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_attribute_publisher.cpp b/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_attribute_publisher.cpp
index 2aba63453d..1f6d1186dd 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
@@ -25633,6 +25633,221 @@ static void descriptor_cluster_cluster_revision_callback(
}
+/**
+ * @brief Publishes the desired value of an updated attribute store node for
+ * the UnifyThermostat cluster.
+ * @param updated_node Updated attribute store node
+ * @param change Type of change applied
+ */
+static void unify_thermostat_cluster_publish_desired_value_callback(
+ attribute_store_node_t updated_node, attribute_store_change_t change)
+{
+ // clang-format on
+ if (false == is_publish_desired_attribute_values_to_mqtt_enabled()) {
+ return;
+ }
+ if (change == ATTRIBUTE_DELETED || change == ATTRIBUTE_CREATED) {
+ return;
+ }
+ // Scene exception: check that the attribute is not under the Scene Table extension, which is a config and not the node's state.
+ if (ATTRIBUTE_STORE_INVALID_NODE
+ != attribute_store_get_first_parent_with_type(
+ updated_node,
+ DOTDOT_ATTRIBUTE_ID_SCENES_SCENE_TABLE)) {
+ return;
+ }
+
+ // Get the UNID and EndPoint, and prepare the basic topic
+ char unid[MAXIMUM_UNID_SIZE] = {};
+ // clang-format off
+ // clang-format on
+ dotdot_endpoint_id_t endpoint_id = 0;
+ if (SL_STATUS_OK
+ != unify_dotdot_attributes_get_unid_endpoint()(updated_node,
+ unid,
+ &endpoint_id)) {
+ return;
+ }
+ // clang-format off
+ // clang-format on
+
+ std::string base_topic = "ucl/by-unid/" + std::string(unid);
+ // clang-format off
+ base_topic += "/ep" + std::to_string(endpoint_id);
+ // clang-format on
+
+ attribute_store_type_t type = attribute_store_get_node_type(updated_node);
+ if (type == ATTRIBUTE_STORE_INVALID_ATTRIBUTE_TYPE) {
+ sl_log_debug(LOG_TAG,
+ "Warning: Invalid type for Attribute ID %d, "
+ "this should not happen.",
+ updated_node);
+ return;
+ }
+
+ // If the value got updated but both Reported and Desired undefined, we skip publication
+ if (false == attribute_store_is_reported_defined(updated_node)
+ && false == attribute_store_is_desired_defined(updated_node)) {
+ sl_log_debug(LOG_TAG,
+ "Reported/Desired values are undefined. "
+ "Skipping publication");
+ return;
+ }
+
+ // clang-format off
+ try {
+ attribute_store::attribute attr(updated_node);
+ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_THERMOSTAT_OPERATING_STATE) {
+ uic_mqtt_dotdot_unify_thermostat_operating_state_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 UnifyThermostat cluster.
+ * @param updated_node Updated attribute store node
+ * @param change Type of change applied
+ */
+static void unify_thermostat_cluster_publish_reported_value_callback(
+ attribute_store_node_t updated_node, attribute_store_change_t change)
+{
+ // clang-format on
+ if (false == is_publish_reported_attribute_values_to_mqtt_enabled()) {
+ return;
+ }
+ if (change == ATTRIBUTE_CREATED) {
+ return;
+ }
+ // Scene exception: check that the attribute is not under the Scene Table extension, which is a config and not the node's state.
+ if (ATTRIBUTE_STORE_INVALID_NODE
+ != attribute_store_get_first_parent_with_type(
+ updated_node,
+ DOTDOT_ATTRIBUTE_ID_SCENES_SCENE_TABLE)) {
+ return;
+ }
+
+ // Get the UNID and EndPoint, and prepare the basic topic
+ char unid[MAXIMUM_UNID_SIZE] = {};
+ // clang-format off
+ // clang-format on
+ dotdot_endpoint_id_t endpoint_id = 0;
+ if (SL_STATUS_OK
+ != unify_dotdot_attributes_get_unid_endpoint()(updated_node,
+ unid,
+ &endpoint_id)) {
+ return;
+ }
+ // clang-format off
+ // clang-format on
+
+ std::string base_topic = "ucl/by-unid/" + std::string(unid);
+ // clang-format off
+ base_topic += "/ep" + std::to_string(endpoint_id);
+ // clang-format on
+
+ attribute_store_type_t type = attribute_store_get_node_type(updated_node);
+ if (type == ATTRIBUTE_STORE_INVALID_ATTRIBUTE_TYPE) {
+ sl_log_debug(LOG_TAG,
+ "Warning: Invalid type for Attribute ID %d, "
+ "this should not happen.",
+ updated_node);
+ return;
+ }
+
+ // Deletion case:
+ if (change == ATTRIBUTE_DELETED) {
+ // clang-format off
+ switch(type) {
+ case DOTDOT_ATTRIBUTE_ID_UNIFY_THERMOSTAT_OPERATING_STATE:
+ // clang-format on
+ sl_log_debug(LOG_TAG,
+ "Unretaining UnifyThermostat::OperatingState under topic %s",
+ base_topic.c_str());
+ // clang-format off
+ uic_mqtt_dotdot_unify_thermostat_operating_state_unretain(base_topic.c_str(), UCL_MQTT_PUBLISH_TYPE_ALL);
+ break;
+ default:
+ break;
+ }
+ // clang-format on
+ return;
+ }
+
+ // If the value got updated but undefined, we skip publication
+ if (false == attribute_store_is_reported_defined(updated_node)) {
+ sl_log_debug(LOG_TAG, "Reported value is undefined. Skipping publication");
+ return;
+ }
+
+ // Else we assume update case:
+ // clang-format off
+ try {
+ attribute_store::attribute attr(updated_node);
+ if (type == DOTDOT_ATTRIBUTE_ID_UNIFY_THERMOSTAT_OPERATING_STATE) {
+ uic_mqtt_dotdot_unify_thermostat_operating_state_publish(
+ base_topic.c_str(),
+ static_cast(attr.reported()),
+ (attr.desired_exists() && !attribute_store_is_value_matched(updated_node)) ? UCL_MQTT_PUBLISH_TYPE_REPORTED : UCL_MQTT_PUBLISH_TYPE_ALL);
+ return;
+ }
+ } catch (std::exception &ex) {
+ sl_log_warning(LOG_TAG, "Failed to publish the Reported attribute value: %s", ex.what());
+ }
+}
+
+static void unify_thermostat_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 + "/UnifyThermostat/Attributes/ClusterRevision";
+ if (uic_mqtt_count_topics(cluster_revision_topic.c_str()) == 0) {
+ uic_mqtt_dotdot_unify_thermostat_publish_cluster_revision(base_topic.c_str(), 1);
+ }
+ }
+
+ if (change == ATTRIBUTE_DELETED) {
+ // Check if we just erased the last attribute under a cluster, if yes, unretain
+ // the Cluster revision too.
+ if (false == dotdot_is_any_unify_thermostat_attribute_supported(unid, endpoint_id)) {
+ base_topic += "/UnifyThermostat";
+ sl_log_debug(LOG_TAG, "No more attributes supported for UnifyThermostat cluster for UNID %s Endpoint %d. Unretaining leftover topics at %s",unid, endpoint_id, base_topic.c_str());
+ uic_mqtt_unretain(base_topic.c_str());
+ }
+ }
+}
+
+
// Initialization of the component.
sl_status_t unify_dotdot_attribute_store_attribute_publisher_init()
@@ -35675,6 +35890,20 @@ sl_status_t unify_dotdot_attribute_store_attribute_publisher_init()
attribute_store_register_callback_by_type(
descriptor_cluster_cluster_revision_callback,
DOTDOT_ATTRIBUTE_ID_DESCRIPTOR_DEVICE_TYPE_LIST);
+ //Desired attribute state
+ attribute_store_register_callback_by_type_and_state(
+ unify_thermostat_cluster_publish_desired_value_callback,
+ DOTDOT_ATTRIBUTE_ID_UNIFY_THERMOSTAT_OPERATING_STATE,
+ DESIRED_ATTRIBUTE);
+ //Reported attribute state
+ attribute_store_register_callback_by_type_and_state(
+ unify_thermostat_cluster_publish_reported_value_callback,
+ DOTDOT_ATTRIBUTE_ID_UNIFY_THERMOSTAT_OPERATING_STATE,
+ REPORTED_ATTRIBUTE);
+ //registering a callback when an attribute is created for publishing cluster revision
+ attribute_store_register_callback_by_type(
+ unify_thermostat_cluster_cluster_revision_callback,
+ DOTDOT_ATTRIBUTE_ID_UNIFY_THERMOSTAT_OPERATING_STATE);
return SL_STATUS_OK;
}
diff --git a/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_force_read_attributes_command_callbacks.c b/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_force_read_attributes_command_callbacks.c
index 5d488fb5a1..5661e49b04 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
@@ -4499,6 +4499,36 @@ static sl_status_t uic_mqtt_dotdot_descriptor_force_read_attributes_callback (
}
return SL_STATUS_OK;
}
+////////////////////////////////////////////////////////////////////////////////
+// Start of cluster UnifyThermostat
+////////////////////////////////////////////////////////////////////////////////
+static sl_status_t uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback (
+ const dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint_id,
+ uic_mqtt_dotdot_callback_call_type_t call_type,
+ uic_mqtt_dotdot_unify_thermostat_updated_state_t attribute_list) {
+
+ if (false == is_force_read_attributes_enabled()){
+ return SL_STATUS_FAIL;
+ }
+
+ if (call_type == UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK) {
+ if (is_automatic_deduction_of_supported_commands_enabled()) {
+ return dotdot_is_any_unify_thermostat_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.operating_state) {
+ if (SL_STATUS_OK == dotdot_unify_thermostat_operating_state_undefine_reported(unid, endpoint_id)) {
+ sl_log_debug(LOG_TAG, "Undefined Reported value of UnifyThermostat::OperatingState under %s - Endpoint %d", unid, endpoint_id);
+ }
+ }
+ return SL_STATUS_OK;
+}
// clang-format on
////////////////////////////////////////////////////////////////////////////////
@@ -4609,6 +4639,8 @@ sl_status_t
uic_mqtt_dotdot_set_descriptor_force_read_attributes_callback(&uic_mqtt_dotdot_descriptor_force_read_attributes_callback);
+ uic_mqtt_dotdot_set_unify_thermostat_force_read_attributes_callback(&uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback);
+
// clang-format on
return SL_STATUS_OK;
diff --git a/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_helpers.cpp b/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_helpers.cpp
index e170bb45b1..67ea8768fc 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
@@ -83593,5 +83593,138 @@ bool dotdot_is_any_descriptor_writable_attribute_supported(
const dotdot_endpoint_id_t endpoint_id) {
+ return false;
+}
+////////////////////////////////////////////////////////////////////////////////
+// Start of cluster UnifyThermostat
+////////////////////////////////////////////////////////////////////////////////
+bool dotdot_is_supported_unify_thermostat_operating_state(
+ const dotdot_unid_t unid, const dotdot_endpoint_id_t endpoint_id)
+{
+ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id);
+ attribute_store_node_t node
+ = attribute_store_get_first_child_by_type(
+ endpoint_node,
+ DOTDOT_ATTRIBUTE_ID_UNIFY_THERMOSTAT_OPERATING_STATE);
+ return attribute_store_node_exists(node);
+}
+
+uint8_t dotdot_get_unify_thermostat_operating_state(
+ const dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint_id,
+ attribute_store_node_value_state_t value_state)
+{
+ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id);
+ attribute_store_node_t node
+ = attribute_store_get_first_child_by_type(
+ endpoint_node,
+ DOTDOT_ATTRIBUTE_ID_UNIFY_THERMOSTAT_OPERATING_STATE);
+
+ uint8_t result = {};
+ attribute_store_read_value(node,
+ value_state,
+ (uint8_t *)&result,
+ sizeof(result));
+ return result;
+}
+
+sl_status_t dotdot_set_unify_thermostat_operating_state(
+ const dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint_id,
+ attribute_store_node_value_state_t value_state,
+ uint8_t new_operating_state
+ )
+{
+ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id);
+
+ attribute_store_node_t node
+ = attribute_store_get_first_child_by_type(
+ endpoint_node,
+ DOTDOT_ATTRIBUTE_ID_UNIFY_THERMOSTAT_OPERATING_STATE);
+
+ return attribute_store_set_node_attribute_value(node,
+ value_state,
+ (uint8_t *)&new_operating_state,
+ sizeof(uint8_t));
+ }
+
+sl_status_t dotdot_unify_thermostat_operating_state_undefine_reported(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint_id) {
+ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id);
+ attribute_store_node_t node
+ = attribute_store_get_first_child_by_type(
+ endpoint_node,
+ DOTDOT_ATTRIBUTE_ID_UNIFY_THERMOSTAT_OPERATING_STATE);
+ attribute_store_undefine_reported(node);
+ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL;
+}
+
+sl_status_t dotdot_unify_thermostat_operating_state_undefine_desired(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint_id) {
+
+ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id);
+ attribute_store_node_t node
+ = attribute_store_get_first_child_by_type(
+ endpoint_node,
+ DOTDOT_ATTRIBUTE_ID_UNIFY_THERMOSTAT_OPERATING_STATE);
+ attribute_store_undefine_desired(node);
+ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL;
+}
+
+
+bool dotdot_unify_thermostat_operating_state_is_reported_defined(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint_id)
+{
+ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id);
+ attribute_store_node_t node
+ = attribute_store_get_first_child_by_type(
+ endpoint_node,
+ DOTDOT_ATTRIBUTE_ID_UNIFY_THERMOSTAT_OPERATING_STATE);
+ return attribute_store_is_reported_defined(node);
+}
+
+bool dotdot_unify_thermostat_operating_state_is_desired_defined(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint_id)
+{
+ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id);
+ attribute_store_node_t node
+ = attribute_store_get_first_child_by_type(
+ endpoint_node,
+ DOTDOT_ATTRIBUTE_ID_UNIFY_THERMOSTAT_OPERATING_STATE);
+ return attribute_store_is_desired_defined(node);
+}
+
+sl_status_t dotdot_create_unify_thermostat_operating_state(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint_id) {
+
+ attribute_store_node_t endpoint_node = unify_dotdot_attributes_get_endpoint_node()(unid, endpoint_id);
+ attribute_store_node_t node =
+ attribute_store_create_child_if_missing(endpoint_node,
+ DOTDOT_ATTRIBUTE_ID_UNIFY_THERMOSTAT_OPERATING_STATE);
+
+ return (node != ATTRIBUTE_STORE_INVALID_NODE) ? SL_STATUS_OK : SL_STATUS_FAIL;
+}
+
+bool dotdot_is_any_unify_thermostat_attribute_supported(
+ const dotdot_unid_t unid,
+ const dotdot_endpoint_id_t endpoint_id) {
+
+ if (true == dotdot_is_supported_unify_thermostat_operating_state(unid, endpoint_id)) {
+ return true;
+ }
+
+ return false;
+}
+
+bool dotdot_is_any_unify_thermostat_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 0423e9305d..566b563cbb 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
@@ -17311,6 +17311,30 @@ sl_status_t unify_dotdot_attribute_store_registration_init()
// 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 UnifyThermostat OperatingState, "
+ "type: enum8 // uint8_t");
+ }
+
+ status |= attribute_store_register_type(
+ DOTDOT_ATTRIBUTE_ID_UNIFY_THERMOSTAT_OPERATING_STATE,
+ "ZCL UnifyThermostat OperatingState",
+ ATTRIBUTE_STORE_INVALID_ATTRIBUTE_TYPE,
+ storage_type);
+ }
+
+ // clang-format off
+ // clang-format on
+
// Additional attributes:
for (auto const &a: zcl_additional_attribute_schema) {
status |= attribute_store_register_type(a.type,
diff --git a/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_write_attributes_command_callbacks.c b/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_write_attributes_command_callbacks.c
index f45d19784b..d607a5be7c 100644
--- a/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_write_attributes_command_callbacks.c
+++ b/components/unify_dotdot_attribute_store/zap-generated/src/unify_dotdot_attribute_store_write_attributes_command_callbacks.c
@@ -2585,6 +2585,36 @@ static sl_status_t descriptor_cluster_write_attributes_callback(
endpoint_id);
return SL_STATUS_OK;
}
+////////////////////////////////////////////////////////////////////////////////
+// Start of cluster UnifyThermostat
+////////////////////////////////////////////////////////////////////////////////
+// WriteAttribute Callbacks unify_thermostat
+static sl_status_t unify_thermostat_cluster_write_attributes_callback(
+ const dotdot_unid_t unid,
+ dotdot_endpoint_id_t endpoint_id,
+ uic_mqtt_dotdot_callback_call_type_t call_type,
+ uic_mqtt_dotdot_unify_thermostat_state_t attributes,
+ uic_mqtt_dotdot_unify_thermostat_updated_state_t updated_attributes)
+{
+ if (false == is_write_attributes_enabled()) {
+ return SL_STATUS_FAIL;
+ }
+
+ if (call_type == UIC_MQTT_DOTDOT_CALLBACK_TYPE_SUPPORT_CHECK) {
+ if (is_automatic_deduction_of_supported_commands_enabled()) {
+ return dotdot_is_any_unify_thermostat_writable_attribute_supported(unid, endpoint_id) ?
+ SL_STATUS_OK : SL_STATUS_FAIL;
+ } else {
+ return SL_STATUS_FAIL;
+ }
+ }
+
+ sl_log_debug(LOG_TAG,
+ "unify_thermostat: Incoming WriteAttributes command for %s, endpoint %d.\n",
+ unid,
+ endpoint_id);
+ return SL_STATUS_OK;
+}
// clang-format on
////////////////////////////////////////////////////////////////////////////////
@@ -2752,6 +2782,9 @@ sl_status_t
uic_mqtt_dotdot_set_descriptor_write_attributes_callback(
&descriptor_cluster_write_attributes_callback);
+ uic_mqtt_dotdot_set_unify_thermostat_write_attributes_callback(
+ &unify_thermostat_cluster_write_attributes_callback);
+
// clang-format on
return SL_STATUS_OK;
diff --git a/components/unify_dotdot_attribute_store/zap-generated/test/unify_dotdot_attribute_store_test.c b/components/unify_dotdot_attribute_store/zap-generated/test/unify_dotdot_attribute_store_test.c
index fda0a48f1a..7cec514812 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
@@ -1312,6 +1312,16 @@ uic_mqtt_dotdot_descriptor_write_attributes_callback_t get_uic_mqtt_dotdot_descr
return test_uic_mqtt_dotdot_descriptor_write_attributes_callback;
}
+static uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback_t test_uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback = NULL;
+static uic_mqtt_dotdot_unify_thermostat_write_attributes_callback_t test_uic_mqtt_dotdot_unify_thermostat_write_attributes_callback = NULL;
+
+uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback_t get_uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback(){
+ return test_uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback;
+}
+uic_mqtt_dotdot_unify_thermostat_write_attributes_callback_t get_uic_mqtt_dotdot_unify_thermostat_write_attributes_callback(){
+ return test_uic_mqtt_dotdot_unify_thermostat_write_attributes_callback;
+}
+
// clang-format on
#define TEST_UNID "test-unid-123"
@@ -2878,6 +2888,16 @@ void set_uic_mqtt_dotdot_descriptor_write_attributes_callback_stub(
{
test_uic_mqtt_dotdot_descriptor_write_attributes_callback = callback;
}
+void set_uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback_stub(
+ const uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback_t callback, int cmock_num_calls)
+{
+ test_uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback = callback;
+}
+void set_uic_mqtt_dotdot_unify_thermostat_write_attributes_callback_stub(
+ const uic_mqtt_dotdot_unify_thermostat_write_attributes_callback_t callback, int cmock_num_calls)
+{
+ test_uic_mqtt_dotdot_unify_thermostat_write_attributes_callback = callback;
+}
// clang-format on
// Test functions
@@ -3798,6 +3818,12 @@ void setUp()
test_uic_mqtt_dotdot_descriptor_write_attributes_callback = NULL;
uic_mqtt_dotdot_set_descriptor_write_attributes_callback_Stub(
&set_uic_mqtt_dotdot_descriptor_write_attributes_callback_stub);
+ test_uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback = NULL;
+ uic_mqtt_dotdot_set_unify_thermostat_force_read_attributes_callback_Stub(
+ &set_uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback_stub);
+ test_uic_mqtt_dotdot_unify_thermostat_write_attributes_callback = NULL;
+ uic_mqtt_dotdot_set_unify_thermostat_write_attributes_callback_Stub(
+ &set_uic_mqtt_dotdot_unify_thermostat_write_attributes_callback_stub);
// clang-format on
group_command_dispatch = NULL;
@@ -4560,6 +4586,7 @@ void test_automatic_deduction_of_supported_commands()
TEST_ASSERT_EQUAL(SL_STATUS_OK, dotdot_create_aox_position_estimation_position(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_thermostat_operating_state(expected_unid,expected_endpoint_id) );
// clang-format on
// ColorControl checks the value in the bitmask:
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 5d7b13dc5e..ec8e607e04 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
@@ -793,4 +793,8 @@
uic_mqtt_dotdot_descriptor_force_read_attributes_callback_t get_uic_mqtt_dotdot_descriptor_force_read_attributes_callback();
uic_mqtt_dotdot_descriptor_write_attributes_callback_t get_uic_mqtt_dotdot_descriptor_write_attributes_callback();
+
+ uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback_t get_uic_mqtt_dotdot_unify_thermostat_force_read_attributes_callback();
+ uic_mqtt_dotdot_unify_thermostat_write_attributes_callback_t get_uic_mqtt_dotdot_unify_thermostat_write_attributes_callback();
+
#endif // UNIFY_DOTDOT_ATTRIBUTE_STORE_TEST_H
\ No newline at end of file