diff --git a/applications/zpc/components/zpc_attribute_store/include/attribute_store_defined_attribute_types.h b/applications/zpc/components/zpc_attribute_store/include/attribute_store_defined_attribute_types.h index 7f5a3a9bf..c0a0b5b75 100644 --- a/applications/zpc/components/zpc_attribute_store/include/attribute_store_defined_attribute_types.h +++ b/applications/zpc/components/zpc_attribute_store/include/attribute_store_defined_attribute_types.h @@ -544,6 +544,17 @@ DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_HUMIDITY_CONTROL_MODE_SUPPORTED_MODES, DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_HUMIDITY_CONTROL_MODE_CURRENT_MODE, ((COMMAND_CLASS_HUMIDITY_CONTROL_MODE << 8) | 0x03)) +///////////////////////////////////////////////// +// Humidity Control Operating State Command Class +///< This represents the version of the Humidity Control Mode Command class. +/// zwave_cc_version_t +DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE_VERSION, + ZWAVE_CC_VERSION_ATTRIBUTE(COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE)) + +// Current state +DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE_CURRENT_STATE, + ((COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE << 8) | 0x02)) + ///////////////////////////////////////////////// // Inclusion Controller Command Class ///< This represents the version of the Inclusion Controller Command class. diff --git a/applications/zpc/components/zpc_attribute_store/include/command_class_types/zwave_command_class_humidity_control_types.h b/applications/zpc/components/zpc_attribute_store/include/command_class_types/zwave_command_class_humidity_control_types.h index a33e68584..67add5d86 100644 --- a/applications/zpc/components/zpc_attribute_store/include/command_class_types/zwave_command_class_humidity_control_types.h +++ b/applications/zpc/components/zpc_attribute_store/include/command_class_types/zwave_command_class_humidity_control_types.h @@ -37,6 +37,10 @@ typedef uint8_t humidity_control_mode_t; ///> Humidity Control Suppoted Mode Bitmask. uint8_t typedef uint8_t humidity_control_supported_modes_t; +//>> Humidity Control Operating State CC +///> Humidity Control Operating State. uint8_t +typedef uint8_t humidity_control_operating_state_t; + #ifdef __cplusplus extern "C" { #endif diff --git a/applications/zpc/components/zpc_attribute_store/src/zpc_attribute_store_type_registration.cpp b/applications/zpc/components/zpc_attribute_store/src/zpc_attribute_store_type_registration.cpp index 61c7ede1a..379afc5cc 100644 --- a/applications/zpc/components/zpc_attribute_store/src/zpc_attribute_store_type_registration.cpp +++ b/applications/zpc/components/zpc_attribute_store/src/zpc_attribute_store_type_registration.cpp @@ -201,6 +201,12 @@ static const std::vector attribute_schema = { {ATTRIBUTE_COMMAND_CLASS_HUMIDITY_CONTROL_MODE_SUPPORTED_MODES, "Humidity Control Mode Supported Modes", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE}, {ATTRIBUTE_COMMAND_CLASS_HUMIDITY_CONTROL_MODE_CURRENT_MODE, "Humidity Control Mode Current Mode", ATTRIBUTE_INDICATOR_INDICATOR_ID, U8_STORAGE_TYPE}, + ///////////////////////////////////////////////////////////////////// + // Humidity Control Operating State Command Class attributes + ///////////////////////////////////////////////////////////////////// + {ATTRIBUTE_COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE_VERSION, "Humidity Control Operating State Version", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE}, + {ATTRIBUTE_COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE_CURRENT_STATE, "Humidity Control Operating State Current State", ATTRIBUTE_INDICATOR_INDICATOR_ID, U8_STORAGE_TYPE}, + ///////////////////////////////////////////////////////////////////// // Meter Command Class attributes ///////////////////////////////////////////////////////////////////// diff --git a/applications/zpc/components/zwave_command_classes/CMakeLists.txt b/applications/zpc/components/zwave_command_classes/CMakeLists.txt index e221b20bf..85dd73816 100644 --- a/applications/zpc/components/zwave_command_classes/CMakeLists.txt +++ b/applications/zpc/components/zwave_command_classes/CMakeLists.txt @@ -22,6 +22,7 @@ add_library( src/zwave_command_class_door_lock_control.cpp src/zwave_command_class_firmware_update.c src/zwave_command_class_humidity_control_mode.c + src/zwave_command_class_humidity_control_operating_state.c src/zwave_command_class_indicator.c src/zwave_command_class_indicator_control.cpp src/zwave_command_class_manufacturer_specific.c diff --git a/applications/zpc/components/zwave_command_classes/src/zwave_command_class_humidity_control_operating_state.c b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_humidity_control_operating_state.c new file mode 100644 index 000000000..8ede12930 --- /dev/null +++ b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_humidity_control_operating_state.c @@ -0,0 +1,155 @@ + +/****************************************************************************** + * # License + * Copyright 2024 Silicon Laboratories Inc. www.silabs.com + ****************************************************************************** + * The licensor of this software is Silicon Laboratories Inc. Your use of this + * software is governed by the terms of Silicon Labs Master Software License + * Agreement (MSLA) available at + * www.silabs.com/about-us/legal/master-software-license-agreement. This + * software is distributed to you in Source Code format and is governed by the + * sections of the MSLA applicable to Source Code. + * + *****************************************************************************/ + +// System +#include + +#include "zwave_command_class_humidity_control_operating_state.h" +#include "zwave_command_class_humidity_control_types.h" +#include "zwave_command_classes_utils.h" +#include "ZW_classcmd.h" + +// Includes from other ZPC Components +#include "zwave_command_class_indices.h" +#include "zwave_command_handler.h" +#include "zwave_command_class_version_types.h" +#include "zpc_attribute_store_network_helper.h" +#include "attribute_store_defined_attribute_types.h" + +// Unify +#include "attribute_resolver.h" +#include "attribute_store.h" +#include "attribute_store_helper.h" +#include "sl_log.h" + +#define LOG_TAG "zwave_command_class_humidity_control_operating_state" + +///////////////////////////////////////////////////////////////////////////// +// Version & Attribute Creation +///////////////////////////////////////////////////////////////////////////// +static void + zwave_command_class_humidity_control_operating_state_on_version_attribute_update( + attribute_store_node_t updated_node, attribute_store_change_t change) +{ + if (change == ATTRIBUTE_DELETED) { + return; + } + + zwave_cc_version_t version = 0; + attribute_store_get_reported(updated_node, &version, sizeof(version)); + + if (version == 0) { + return; + } + + attribute_store_node_t endpoint_node + = attribute_store_get_first_parent_with_type(updated_node, + ATTRIBUTE_ENDPOINT_ID); + + // The order of the attribute matter since it defines the order of the + // Z-Wave get command order. + const attribute_store_type_t attributes[] + = {ATTRIBUTE_COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE_CURRENT_STATE}; + + attribute_store_add_if_missing(endpoint_node, + attributes, + COUNT_OF(attributes)); +} + +///////////////////////////////////////////////////////////////////////////// +// Humidity Control Operating State State Get/Report +///////////////////////////////////////////////////////////////////////////// + +static sl_status_t zwave_command_class_humidity_control_operating_state_get( + attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length) +{ + (void)node; // unused. + ZW_HUMIDITY_CONTROL_OPERATING_STATE_GET_FRAME *get_frame + = (ZW_HUMIDITY_CONTROL_OPERATING_STATE_GET_FRAME *)frame; + get_frame->cmdClass = COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE; + get_frame->cmd = HUMIDITY_CONTROL_OPERATING_STATE_GET; + *frame_length = sizeof(ZW_HUMIDITY_CONTROL_OPERATING_STATE_GET_FRAME); + return SL_STATUS_OK; +} + +sl_status_t zwave_command_class_humidity_control_operating_state_handle_report( + const zwave_controller_connection_info_t *connection_info, + const uint8_t *frame_data, + uint16_t frame_length) +{ + if (frame_length < 3) { + return SL_STATUS_FAIL; + } + + humidity_control_operating_state_t fan_state + = frame_data[2] + & HUMIDITY_CONTROL_OPERATING_STATE_REPORT_PROPERTIES1_OPERATING_STATE_MASK; + + attribute_store_node_t endpoint_node + = zwave_command_class_get_endpoint_node(connection_info); + + attribute_store_set_child_reported( + endpoint_node, + ATTRIBUTE_COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE_CURRENT_STATE, + &fan_state, + sizeof(fan_state)); + + return SL_STATUS_OK; +} + +sl_status_t + zwave_command_class_humidity_control_operating_state_control_handler( + const zwave_controller_connection_info_t *connection_info, + const uint8_t *frame_data, + uint16_t frame_length) +{ + if (frame_length <= COMMAND_INDEX) { + return SL_STATUS_NOT_SUPPORTED; + } + + switch (frame_data[COMMAND_INDEX]) { + case HUMIDITY_CONTROL_OPERATING_STATE_REPORT: + return zwave_command_class_humidity_control_operating_state_handle_report( + connection_info, + frame_data, + frame_length); + default: + return SL_STATUS_NOT_SUPPORTED; + } +} + +sl_status_t zwave_command_class_humidity_control_operating_state_init() +{ + attribute_store_register_callback_by_type( + &zwave_command_class_humidity_control_operating_state_on_version_attribute_update, + ATTRIBUTE_COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE_VERSION); + + attribute_resolver_register_rule( + ATTRIBUTE_COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE_CURRENT_STATE, + NULL, + &zwave_command_class_humidity_control_operating_state_get); + + zwave_command_handler_t handler = {}; + handler.support_handler = NULL; + handler.control_handler + = zwave_command_class_humidity_control_operating_state_control_handler; + handler.minimal_scheme = ZWAVE_CONTROLLER_ENCAPSULATION_NONE; + handler.manual_security_validation = false; + handler.command_class = COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE; + handler.version = 1; + handler.command_class_name = "Humidity Control Operating State"; + handler.comments = "Experimental"; + + return zwave_command_handler_register_handler(handler); +} \ No newline at end of file diff --git a/applications/zpc/components/zwave_command_classes/src/zwave_command_class_humidity_control_operating_state.h b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_humidity_control_operating_state.h new file mode 100644 index 000000000..505b59461 --- /dev/null +++ b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_humidity_control_operating_state.h @@ -0,0 +1,41 @@ + +/****************************************************************************** + * # License + * Copyright 2024 Silicon Laboratories Inc. www.silabs.com + ****************************************************************************** + * The licensor of this software is Silicon Laboratories Inc. Your use of this + * software is governed by the terms of Silicon Labs Master Software License + * Agreement (MSLA) available at + * www.silabs.com/about-us/legal/master-software-license-agreement. This + * software is distributed to you in Source Code format and is governed by the + * sections of the MSLA applicable to Source Code. + * + *****************************************************************************/ + +/** + * @defgroup zwave_command_class_humidity_control_operating_state + * @brief Humidity Control Operating State Command Class handlers and control function + * + * This module implement some of the functions to control the + * Humidity Control Operating State Command Class + * + * @{ + */ + +#ifndef ZWAVE_COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE_H +#define ZWAVE_COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE_H + +#include "sl_status.h" + +#ifdef __cplusplus +extern "C" { +#endif + +sl_status_t zwave_command_class_humidity_control_operating_state_init(); + +#ifdef __cplusplus +} +#endif + +#endif //ZWAVE_COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE_H + /** @} end zwave_command_class_humidity_control_operating_state */ \ No newline at end of file diff --git a/applications/zpc/components/zwave_command_classes/test/CMakeLists.txt b/applications/zpc/components/zwave_command_classes/test/CMakeLists.txt index 2d8dab49b..3c60bd5ea 100644 --- a/applications/zpc/components/zwave_command_classes/test/CMakeLists.txt +++ b/applications/zpc/components/zwave_command_classes/test/CMakeLists.txt @@ -742,5 +742,20 @@ target_add_unittest( zpc_attribute_resolver_mock uic_dotdot_mqtt_mock) + # Humidity Control Mode test +target_add_unittest( + zwave_command_classes + NAME + zwave_command_class_humidity_control_operating_state_test + SOURCES + zwave_command_class_humidity_control_operating_state_test.c + DEPENDS + zpc_attribute_store_test_helper + zwave_controller + zwave_command_handler_mock + uic_attribute_resolver_mock + zpc_attribute_resolver_mock + uic_dotdot_mqtt_mock) + \ No newline at end of file diff --git a/applications/zpc/components/zwave_command_classes/test/zwave_command_class_humidity_control_operating_state_test.c b/applications/zpc/components/zwave_command_classes/test/zwave_command_class_humidity_control_operating_state_test.c new file mode 100644 index 000000000..cca8833b7 --- /dev/null +++ b/applications/zpc/components/zwave_command_classes/test/zwave_command_class_humidity_control_operating_state_test.c @@ -0,0 +1,192 @@ +/****************************************************************************** + * # License + * Copyright 2024 Silicon Laboratories Inc. www.silabs.com + ****************************************************************************** + * The licensor of this software is Silicon Laboratories Inc. Your use of this + * software is governed by the terms of Silicon Labs Master Software License + * Agreement (MSLA) available at + * www.silabs.com/about-us/legal/master-software-license-agreement. This + * software is distributed to you in Source Code format and is governed by the + * sections of the MSLA applicable to Source Code. + * + *****************************************************************************/ + +#include "zwave_command_class_humidity_control_operating_state.h" +#include "zwave_command_class_humidity_control_types.h" +#include "zwave_command_classes_utils.h" +#include "unity.h" + +// Generic includes +#include + +// Includes from other components +#include "datastore.h" +#include "attribute_store.h" +#include "attribute_store_helper.h" +#include "attribute_store_fixt.h" +#include "zpc_attribute_store_type_registration.h" + +// Interface includes +#include "attribute_store_defined_attribute_types.h" +#include "ZW_classcmd.h" +#include "zwave_utils.h" +#include "zwave_controller_types.h" + +// Test helpers +#include "zpc_attribute_store_test_helper.h" + +// Mock includes +#include "attribute_resolver_mock.h" +#include "zpc_attribute_resolver_mock.h" +#include "zwave_command_handler_mock.h" +#include "dotdot_mqtt_mock.h" +#include "dotdot_mqtt_generated_commands_mock.h" + +static zwave_command_handler_t handler = {}; + +static attribute_resolver_function_t current_humidity_control_state_get = NULL; + +// Buffer for frame +static uint8_t received_frame[255] = {}; +static uint16_t received_frame_size = 0; + +// Stub functions +static sl_status_t + attribute_resolver_register_rule_stub(attribute_store_type_t node_type, + attribute_resolver_function_t set_func, + attribute_resolver_function_t get_func, + int cmock_num_calls) +{ + if ( + node_type + == ATTRIBUTE_COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE_CURRENT_STATE) { + TEST_ASSERT_NULL(set_func); + TEST_ASSERT_NOT_NULL(get_func); + current_humidity_control_state_get = get_func; + } + + return SL_STATUS_OK; +} + +static sl_status_t zwave_command_handler_register_handler_stub( + zwave_command_handler_t new_command_class_handler, int cmock_num_calls) +{ + handler = new_command_class_handler; + + TEST_ASSERT_EQUAL(ZWAVE_CONTROLLER_ENCAPSULATION_NONE, + handler.minimal_scheme); + TEST_ASSERT_EQUAL(COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE, + handler.command_class); + TEST_ASSERT_EQUAL(1, handler.version); + TEST_ASSERT_NOT_NULL(handler.control_handler); + TEST_ASSERT_NULL(handler.support_handler); + TEST_ASSERT_FALSE(handler.manual_security_validation); + + return SL_STATUS_OK; +} + +/// Setup the test suite (called once before all test_xxx functions are called) +void suiteSetUp() +{ + datastore_init(":memory:"); + attribute_store_init(); + zpc_attribute_store_register_known_attribute_types(); +} + +/// Teardown the test suite (called once after all test_xxx functions are called) +int suiteTearDown(int num_failures) +{ + attribute_store_teardown(); + datastore_teardown(); + return num_failures; +} + +/// Called before each and every test +void setUp() +{ + zpc_attribute_store_test_helper_create_network(); + + // Unset previous definition get/set functions + current_humidity_control_state_get = NULL; + memset(received_frame, 0, sizeof(received_frame)); + received_frame_size = 0; + // Unset previous definition of handler + memset(&handler, 0, sizeof(zwave_command_handler_t)); + + // Resolution functions + attribute_resolver_register_rule_Stub(&attribute_resolver_register_rule_stub); + // Handler registration + zwave_command_handler_register_handler_Stub( + &zwave_command_handler_register_handler_stub); + // Call init + TEST_ASSERT_EQUAL( + SL_STATUS_OK, + zwave_command_class_humidity_control_operating_state_init()); +} + +/// Called after each and every test +void tearDown() {} + +//////////////////////////////////////////////////////////////////////////// +// HELPERS +//////////////////////////////////////////////////////////////////////////// +// Happy case : not setting reserved bit to 1 +void helper_humidity_control_state_report( + humidity_control_operating_state_t expected_state, bool happy_case) +{ + uint8_t happy_case_mask = happy_case ? 0x00 : 0xF0; + + const uint8_t frame[] = {COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE, + HUMIDITY_CONTROL_OPERATING_STATE_REPORT, + expected_state | happy_case_mask}; + + zwave_controller_connection_info_t info = {}; + info.remote.node_id = node_id; + info.remote.endpoint_id = endpoint_id; + info.local.is_multicast = false; + + TEST_ASSERT_EQUAL(SL_STATUS_OK, + handler.control_handler(&info, frame, sizeof(frame))); + + attribute_store_node_t humidity_control_state_node + = attribute_store_get_node_child_by_type( + endpoint_id_node, + ATTRIBUTE_COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE_CURRENT_STATE, + 0); + + TEST_ASSERT_NOT_EQUAL(ATTRIBUTE_STORE_INVALID_NODE, + humidity_control_state_node); + + humidity_control_operating_state_t reported_state = 0x00; + attribute_store_get_reported(humidity_control_state_node, + &reported_state, + sizeof(reported_state)); + TEST_ASSERT_EQUAL(expected_state, reported_state); +} + +//////////////////////////////////////////////////////////////////////////// +// THERMOSTAT_FAN_STATE +//////////////////////////////////////////////////////////////////////////// +void test_humidity_control_operating_state_get_happy_case() +{ + // Ask for a Get Command, should always be the same + TEST_ASSERT_NOT_NULL(current_humidity_control_state_get); + current_humidity_control_state_get(0, received_frame, &received_frame_size); + const uint8_t expected_frame[] + = {COMMAND_CLASS_HUMIDITY_CONTROL_OPERATING_STATE, + HUMIDITY_CONTROL_OPERATING_STATE_GET}; + TEST_ASSERT_EQUAL(sizeof(expected_frame), received_frame_size); + TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_frame, + received_frame, + received_frame_size); +} + +void test_humidity_control_operating_state_report_happy_case() +{ + helper_humidity_control_state_report(0x02, true); +} + +void test_humidity_control_operating_state_report_off_bit() +{ + helper_humidity_control_state_report(0x03, false); +} \ No newline at end of file