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/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..5ade3955d1 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,273 @@ 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": { + "OperatingState": { + "type": "UnifyThermostatOperatingState" + } + }, + "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 '{ "OperatingState": }' +``` + +> 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 +57812,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..9b2a80fe30 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 @@ -14799,3 +14799,34 @@ 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 +) { + + + if (jsn.find("OperatingState") != jsn.end()) { + + uint32_t tmp = get_enum_decimal_value("OperatingState", jsn); + if (tmp == std::numeric_limits::max()) { + #ifdef UNIFY_THERMOSTAT_OPERATING_STATE_ENUM_NAME_AVAILABLE + tmp = unify_thermostat_operating_state_get_enum_value_number(jsn.at("OperatingState").get()); + #elif defined(OPERATING_STATE_ENUM_NAME_AVAILABLE) + tmp = operating_state_get_enum_value_number(jsn.at("OperatingState").get()); + #endif + } + new_state.operating_state = tmp; + + new_updated_state.operating_state = true; + } + + +} + 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..209854ffc9 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,57 @@ 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(); + + + if (attribute_list.operating_state == true) { + + // This is a single value + + #ifdef UNIFY_THERMOSTAT_OPERATING_STATE_ENUM_NAME_AVAILABLE + json_object["OperatingState"] = unify_thermostat_operating_state_get_enum_value_name((uint32_t)attribute_values.operating_state); + #else + json_object["OperatingState"] = static_cast(attribute_values.operating_state); + #endif + + + } + + + // 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..dbc828a94b 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,141 @@ 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) { + + if (true == dotdot_is_supported_unify_thermostat_operating_state(unid, endpoint_id)) { + return true; + } + 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..bdff38772b 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,40 @@ 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); + if (true == updated_attributes.operating_state) { + sl_log_debug(LOG_TAG, "Updating desired value for OperatingState attribute"); + dotdot_set_unify_thermostat_operating_state(unid, endpoint_id, DESIRED_ATTRIBUTE, attributes.operating_state); + } + return SL_STATUS_OK; +} // clang-format on //////////////////////////////////////////////////////////////////////////////// @@ -2752,6 +2786,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