diff --git a/components/nspanel_ha_blueprint/ha_components.cpp b/components/nspanel_ha_blueprint/ha_components.cpp new file mode 100644 index 0000000..9524f8b --- /dev/null +++ b/components/nspanel_ha_blueprint/ha_components.cpp @@ -0,0 +1,24 @@ +// ha_components.cpp + +#include "ha_components.h" + +namespace nspanel_ha_blueprint { + + // Function Definition + HomeAssistantEntity extractHomeAssistantEntity(const std::string& entity_id) { + size_t dotPos = entity_id.find("."); + HomeAssistantEntity result; + + if (dotPos != std::string::npos) { + // Extract domain and id from the entity_id string + result.domain = entity_id.substr(0, dotPos); + result.id = entity_id.substr(dotPos + 1); + } else { + // No dot found, the entire entity_id is considered as id. + result.domain = "invalid"; + result.id = entity_id; + } + return result; + } + +} // namespace nspanel_ha_blueprint diff --git a/components/nspanel_ha_blueprint/ha_components.h b/components/nspanel_ha_blueprint/ha_components.h index 6966870..cf0144b 100644 --- a/components/nspanel_ha_blueprint/ha_components.h +++ b/components/nspanel_ha_blueprint/ha_components.h @@ -1,36 +1,36 @@ // ha_components.h + #pragma once #include +// Defines structures and functions related to Home Assistant entities within the nspanel_ha_blueprint namespace. namespace nspanel_ha_blueprint { + // Represents a Home Assistant entity with a domain and an identifier. struct HomeAssistantEntity { - std::string domain; - std::string id; + std::string domain; // The domain part of the entity, like "light" or "switch". + std::string id; // The unique identifier of the entity within its domain. }; /** * Extracts the domain name and unique ID from a given Home Assistant entity string. - * Handles a special case where "alarm_control_panel" should be shortened to "alarm". + * + * This function parses a Home Assistant entity string to extract and separate the domain + * and ID components of the entity. If the string does not contain a valid entity format + * (i.e., "domain.id"), the function will mark the domain as "invalid" and treat the entire + * string as the ID. It also handles a special case where "alarm_control_panel" should be + * shortened to "alarm", though the implementation of this feature needs to be added in the + * function's definition in the corresponding .cpp file. + * + * Usage example: + * auto entity = extractHomeAssistantEntity("light.kitchen"); + * // entity.domain would be "light" + * // entity.id would be "kitchen" * * @param entity_id The input string containing either the combined domain and unique ID or just the unique ID. * @return A HomeAssistantEntity struct containing the extracted domain and the unique ID. */ - HomeAssistantEntity extractHomeAssistantEntity(const std::string& entity_id) { - size_t dotPos = entity_id.find("."); - HomeAssistantEntity result; - - if (dotPos != std::string::npos) { - // Extract domain and id from the entity_id string - result.domain = entity_id.substr(0, dotPos); - result.id = entity_id.substr(dotPos + 1); - } else { - // No dot found, the entire entity_id is considered as id. - result.domain = "invalid"; - result.id = entity_id; - } - return result; - } + HomeAssistantEntity extractHomeAssistantEntity(const std::string& entity_id); } // namespace nspanel_ha_blueprint diff --git a/components/nspanel_ha_blueprint/hardware.cpp b/components/nspanel_ha_blueprint/hardware.cpp new file mode 100644 index 0000000..48cbdf0 --- /dev/null +++ b/components/nspanel_ha_blueprint/hardware.cpp @@ -0,0 +1,21 @@ +// hardware.cpp + +#include "hardware.h" + +namespace nspanel_ha_blueprint { + + template + void update_bitwise_setting(uint8_t& settings, bool condition, SettingsEnum flag) { + if (condition) { + settings |= flag; // Set bit + } else { + settings &= ~flag; // Clear bit + } + } + + // Explicit template instantiation + // Note: You need to explicitly instantiate templates for all enums used as SettingsEnum + template void update_bitwise_setting(uint8_t& settings, bool condition, ButtonSettings flag); + template void update_bitwise_setting(uint8_t& settings, bool condition, RelaySettings flag); + +} // namespace nspanel_ha_blueprint diff --git a/components/nspanel_ha_blueprint/hardware.h b/components/nspanel_ha_blueprint/hardware.h index 1544455..adecb44 100644 --- a/components/nspanel_ha_blueprint/hardware.h +++ b/components/nspanel_ha_blueprint/hardware.h @@ -1,73 +1,73 @@ // hardware.h + #pragma once #include +// Namespace for nspanel_ha_blueprint, encapsulating definitions related to hardware settings. namespace nspanel_ha_blueprint { /** - * @enum ButtonsSettings - * Represents the settings for hardware buttons as individual bits within a uint8_t value. - * Each enum value corresponds to a specific bit position that represents a distinct setting - * for the buttons. This allows for efficient storage and manipulation of multiple buttons - * settings within a single byte. + * @enum ButtonSettings + * Represents the settings for hardware buttons using individual bits within a uint8_t value. + * This allows efficient storage and manipulation of settings for multiple buttons in a compact form. * - * Bits are allocated as follows: - * - Bit 0: Left button - Enabled. - * - Bit 1: Left button - Current state (0 for `off` or 1 for `on`) + * The bit allocations are as follows: + * - Bit 0: Left button enabled. + * - Bit 1: Left button state (0 for `off`, 1 for `on`). * - Bits 2-3: Reserved for future use. - * - Bit 4: Right button - Enabled. - * - Bit 5: Right button - Current state (0 for `off` or 1 for `on`) + * - Bit 4: Right button enabled. + * - Bit 5: Right button state (0 for `off`, 1 for `on`). * - Bits 6-7: Reserved for future use. * - * Usage involves bitwise operations to set, clear, and check these settings within a - * uint8_t variable. This approach enables compact representation and easy manipulation - * of relay settings. + * These settings facilitate easy manipulation of button states and configurations through bitwise operations. */ enum ButtonSettings { - ButtonLeft_Enabled = 1 << 0, ///< Bit 0: Enables left button visualization on screen. - ButtonLeft_State = 1 << 1, ///< Bit 1: Current state of left button. + ButtonLeft_Enabled = 1 << 0, ///< Enables left button visualization on screen. + ButtonLeft_State = 1 << 1, ///< Indicates current state of the left button. // Bits 2 and 3 are reserved for future expansion. - ButtonRight_Enabled = 1 << 4, ///< Bit 4: Enables right button visualization on screen. - ButtonRight_State = 1 << 5, ///< Bit 5: Current state of right button. + ButtonRight_Enabled = 1 << 4, ///< Enables right button visualization on screen. + ButtonRight_State = 1 << 5, ///< Indicates current state of the right button. // Bits 6 and 7 are reserved for future expansion. }; /** * @enum RelaySettings - * Represents the settings for relays as individual bits within a uint8_t value. Each - * enum value corresponds to a specific bit position that represents a distinct setting - * for the relays. This allows for efficient storage and manipulation of multiple relay - * settings within a single byte. + * Represents the settings for relays using individual bits within a uint8_t value. + * This approach allows for the efficient storage and manipulation of settings for multiple + * relays in a single byte, enabling compact representation and ease of setting manipulation. * - * Bits are allocated as follows: - * - Bit 0: Relay 1 - Local control enabled. - * - Bit 1: Relay 1 - Fallback mode enabled. + * The bit allocations are as follows: + * - Bit 0: Relay 1 local control enabled. + * - Bit 1: Relay 1 fallback mode enabled. * - Bits 2-3: Reserved for future use. - * - Bit 4: Relay 2 - Local control enabled. - * - Bit 5: Relay 2 - Fallback mode enabled. + * - Bit 4: Relay 2 local control enabled. + * - Bit 5: Relay 2 fallback mode enabled. * - Bits 6-7: Reserved for future use. * - * Usage involves bitwise operations to set, clear, and check these settings within a - * uint8_t variable. This approach enables compact representation and easy manipulation - * of relay settings. + * These settings support flexible relay configuration and state management through bitwise operations. */ enum RelaySettings { - Relay1_Local = 1 << 0, ///< Bit 0: Enables local control for Relay 1. - Relay1_Fallback = 1 << 1, ///< Bit 1: Enables fallback mode for Relay 1. + Relay1_Local = 1 << 0, ///< Enables local control for Relay 1. + Relay1_Fallback = 1 << 1, ///< Enables fallback mode for Relay 1. // Bits 2 and 3 are reserved for future expansion. - Relay2_Local = 1 << 4, ///< Bit 4: Enables local control for Relay 2. - Relay2_Fallback = 1 << 5, ///< Bit 5: Enables fallback mode for Relay 2. + Relay2_Local = 1 << 4, ///< Enables local control for Relay 2. + Relay2_Fallback = 1 << 5, ///< Enables fallback mode for Relay 2. // Bits 6 and 7 are reserved for future expansion. }; + /** + * Updates a settings byte according to a specified condition and flag. + * + * This function template applies a bitwise operation to modify the settings byte based on + * the provided condition and flag. If the condition is true, the bit corresponding to the flag + * is set; otherwise, it's cleared. This method enables dynamic and conditional settings updates. + * + * @param settings Reference to the settings byte to be modified. + * @param condition Boolean condition determining how the settings byte is modified. + * @param flag The specific bit flag (from ButtonSettings or RelaySettings) to modify. + */ template - void update_bitwise_setting(uint8_t& settings, bool condition, SettingsEnum flag) { - if (condition) { - settings |= flag; // Set bit - } else { - settings &= ~flag; // Clear bit - } - } + void update_bitwise_setting(uint8_t& settings, bool condition, SettingsEnum flag); } // namespace nspanel_ha_blueprint diff --git a/components/nspanel_ha_blueprint/nextion_components.cpp b/components/nspanel_ha_blueprint/nextion_components.cpp new file mode 100644 index 0000000..363f728 --- /dev/null +++ b/components/nspanel_ha_blueprint/nextion_components.cpp @@ -0,0 +1,47 @@ +// nextion_components.cpp + +#include "nextion_components.h" +#include +#include + +namespace nspanel_ha_blueprint { + + NextionComponent extractNextionComponent(const std::string& input, const std::string& defaultPage) { + NextionComponent result{}; + size_t dotPos = input.find("."); + + if (dotPos != std::string::npos) { + // Handling special case and standard extraction + strncpy(result.page, input.substr(0, std::min(dotPos, 14)).c_str(), 14); + result.page[14] = '\0'; // Ensure null termination + strncpy(result.component_id, input.substr(dotPos + 1, 14).c_str(), 14); + result.component_id[14] = '\0'; // Ensure null termination + result.is_current_page = false; + } else { + // Default page case + strncpy(result.page, defaultPage.c_str(), 14); + result.page[14] = '\0'; // Ensure null termination + strncpy(result.component_id, input.c_str(), 14); + result.component_id[14] = '\0'; // Ensure null termination + result.is_current_page = true; + } + + if (strcmp(result.page, defaultPage.c_str()) == 0) { + result.is_current_page = true; + } + + return result; + } + + template + uint16_t rgbTo565(const Container& rgb) { + if (rgb.size() != 3) { + return UINT16_MAX; + } + return ((rgb[0] & 0xF8) << 8) | ((rgb[1] & 0xFC) << 3) | (rgb[2] >> 3); + } + + // Template instantiation for std::vector + template uint16_t rgbTo565>(const std::vector& rgb); + +} // namespace nspanel_ha_blueprint diff --git a/components/nspanel_ha_blueprint/nextion_components.h b/components/nspanel_ha_blueprint/nextion_components.h index f85b728..ca658ef 100644 --- a/components/nspanel_ha_blueprint/nextion_components.h +++ b/components/nspanel_ha_blueprint/nextion_components.h @@ -1,86 +1,37 @@ // nextion_components.h + #pragma once -#include -#include #include #include +#include namespace nspanel_ha_blueprint { struct NextionComponent { - char page[15]; // 14 characters + null terminator - char component_id[15]; // 14 characters + null terminator - bool is_current_page; + char page[15]; // 14 characters + null terminator, representing the Nextion display page + char component_id[15]; // 14 characters + null terminator, representing the component ID within the page + bool is_current_page; // Flag indicating whether the component is on the current page }; /** * Extracts the page name and component ID from a given input string. - * If the input string omits the page, uses defaultPage. - * Special case: "alarm_control_panel" is shortened to "alarm". + * If the input string omits the page, a default page name is used. + * Handles a special case for "alarm_control_panel" by shortening it to "alarm". * * @param input The input string containing the component ID, optionally prefixed by the page name and a dot. - * @param defaultPage The default page name to use if the input string does not specify a page, limited to 14 characters. - * @return A NextionComponent struct with the extracted or default page name, the component ID, and a flag for current page status. + * @param defaultPage The default page name to use if the input string does not specify a page. + * @return A NextionComponent struct with the extracted or default page name, component ID, and current page status. */ - NextionComponent extractNextionComponent(const std::string& input, const std::string& defaultPage) { - NextionComponent result{}; - size_t dotPos = input.find("."); - - if (dotPos != std::string::npos) { - if (input.compare(0, 20, "alarm_control_panel.") == 0) { - strncpy(result.page, "alarm", sizeof(result.page) - 1); - result.page[sizeof(result.page) - 1] = '\0'; - } else { - // Copy up to the dot or 14 characters, whichever is smaller - size_t lengthToCopy = std::min(dotPos, static_cast(14)); - strncpy(result.page, input.c_str(), lengthToCopy); - result.page[lengthToCopy] = '\0'; // Ensure null termination - } - - // Extract and copy component_id - const char* componentStart = input.c_str() + dotPos + 1; - strncpy(result.component_id, componentStart, std::min(input.length() - dotPos - 1, static_cast(14))); - result.component_id[14] = '\0'; // Ensure null termination - result.is_current_page = false; - } else { - // No dot found, use defaultPage and assume it's the current page - strncpy(result.page, defaultPage.c_str(), 14); - result.page[14] = '\0'; // Ensure null termination - - // Input is the component_id - strncpy(result.component_id, input.c_str(), std::min(input.length(), static_cast(14))); - result.component_id[14] = '\0'; // Ensure null termination - result.is_current_page = true; - } - - // Additional check to see if the current page matches defaultPage - if (strncmp(result.page, defaultPage.c_str(), 14) == 0) { - result.is_current_page = true; - } - - return result; - } + NextionComponent extractNextionComponent(const std::string& input, const std::string& defaultPage); /** * Converts an RGB color represented as a vector of integers to the 16-bit 5-6-5 format supported by Nextion displays. - * - * This function takes a vector containing three integer values representing - * the red, green, and blue components of an RGB color, each in the range 0-255. - * It then converts these values into a single uint16_t value in 5-6-5 format, - * commonly used for color displays. The conversion process masks and shifts - * the components to fit into the 5 bits for red, 6 bits for green, and 5 bits for blue. - * + * * @param rgb A vector of integers with exactly three elements: [red, green, blue]. - * @return The color encoded in 16-bit 5-6-5 format, or UINT16_MAX if the input vector - * does not contain at least three elements. + * @return The color encoded in 16-bit 5-6-5 format, or UINT16_MAX if the input vector does not contain exactly three elements. */ template - inline uint16_t rgbTo565(const Container& rgb) { - if (rgb.size() != 3) { - return UINT16_MAX; // Use UINT16_MAX as an error indicator - } - return ((rgb[0] & 0xF8) << 8) | ((rgb[1] & 0xFC) << 3) | (rgb[2] >> 3); - } + uint16_t rgbTo565(const Container& rgb); } // namespace nspanel_ha_blueprint diff --git a/components/nspanel_ha_blueprint/pages.cpp b/components/nspanel_ha_blueprint/pages.cpp new file mode 100644 index 0000000..a8659f4 --- /dev/null +++ b/components/nspanel_ha_blueprint/pages.cpp @@ -0,0 +1,26 @@ +// pages.cpp + +#include "pages.h" +#include + +namespace nspanel_ha_blueprint { + + uint8_t get_page_id(const std::string& page_name) { + for (uint8_t i = 0; i < page_names.size(); ++i) { + if (strcmp(page_names[i], page_name.c_str()) == 0) { + return i; + } + } + return UINT8_MAX; + } + + bool isStringInList(const std::string& strToSearch, std::initializer_list list) { + for (const auto& str : list) { + if (strToSearch == str) { + return true; + } + } + return false; + } + +} // namespace nspanel_ha_blueprint diff --git a/components/nspanel_ha_blueprint/pages.h b/components/nspanel_ha_blueprint/pages.h index fe9ef8c..65bfba2 100644 --- a/components/nspanel_ha_blueprint/pages.h +++ b/components/nspanel_ha_blueprint/pages.h @@ -1,10 +1,9 @@ // pages.h + #pragma once #include -#include #include -#include #include #include @@ -12,7 +11,7 @@ namespace nspanel_ha_blueprint { /** * @file pages.h - * Defines constants and functions related to page names for "NSPanel HA Blueprint" project. + * Defines constants and functions related to page names for the NSPanel HA Blueprint project. */ // Constants @@ -59,51 +58,15 @@ namespace nspanel_ha_blueprint { * @return The index of the page_name in the page_names array. If the page_name * is not found, returns UINT8_MAX as an indicator that no matching page was found. */ - inline uint8_t get_page_id(const std::string& page_name) { - for (uint8_t i = 0; i < page_names.size(); ++i) { - if (strcmp(page_names[i], page_name.c_str()) == 0) { - return i; // Return the index if found - } - } - return UINT8_MAX; // Return UINT8_MAX if not found - } + uint8_t get_page_id(const std::string& page_name); /** * Checks if a given string is present within a list of strings. * - * This function provides a convenient way to search for the presence of a specific string - * within a variably sized list of strings. It iterates through each string in the provided - * list, comparing it against the target string for an exact match. This utility is particularly - * useful for validating if a certain value matches any item from a predefined set of allowed - * values. - * - * @param strToSearch The string to search for within the list. This is the target string - * that the function will attempt to find an exact match for within the - * provided list of strings. - * @param list An initializer list of strings to search within. This list contains the strings - * against which the target string will be compared. The list is flexible in size, - * allowing for a variable number of strings to be specified. - * - * @return Returns `true` if the target string is found within the list, indicating an exact - * match was encountered. Returns `false` if the target string is not present in the - * list, indicating no matches were found. - * - * Usage Example: - * ```cpp - * std::string page = "alarm"; - * bool isPresent = isStringInList(page, {"alarm", "climate", "cover", "fan", "light", "media_player", "confirm", "keyb_num"}); - * if (!isPresent) { - * // The string 'page' was not found in the list - * } - * ``` + * @param strToSearch The string to search for within the list. + * @param list An initializer list of strings to search within. + * @return `true` if the target string is found within the list, `false` otherwise. */ - bool isStringInList(const std::string& strToSearch, std::initializer_list list) { - for (const auto& str : list) { - if (strToSearch == str) { - return true; - } - } - return false; - } + bool isStringInList(const std::string& strToSearch, std::initializer_list list); } // namespace nspanel_ha_blueprint diff --git a/components/nspanel_ha_blueprint/subscriptions.h b/components/nspanel_ha_blueprint/subscriptions.h deleted file mode 100644 index 11d01a7..0000000 --- a/components/nspanel_ha_blueprint/subscriptions.h +++ /dev/null @@ -1,20 +0,0 @@ -// subscriptions.h -#pragma once - -#include -#include -#include - -namespace nspanel_ha_blueprint { - - struct Subscription { - std::string component_id; - std::string entity_id; - int subscription_id; - }; - - std::vector subscriptions; - std::string subs_component_id; - std::string subs_entity_id; - -} // namespace nspanel_ha_blueprint diff --git a/components/nspanel_ha_blueprint/text.cpp b/components/nspanel_ha_blueprint/text.cpp new file mode 100644 index 0000000..048180a --- /dev/null +++ b/components/nspanel_ha_blueprint/text.cpp @@ -0,0 +1,49 @@ +// text.cpp + +#include "text.h" +#include +#include +#include + +namespace nspanel_ha_blueprint { + + template + void copyStringToCharArray(char (&dest)[N], const std::string& src) { + size_t length = std::min(src.size(), static_cast(N - 1)); + std::strncpy(dest, src.c_str(), length); + dest[length] = '\0'; + } + + // Explicit template instantiation might be needed depending on usage + // template void copyStringToCharArray(char (&)[YOUR_SIZE_HERE], const std::string&); + + bool isNumberChar(char c) { + return std::isdigit(static_cast(c)) || c == '.' || c == '-' || c == ','; + } + + std::string adjustDecimalSeparator(const std::string& input, char decimalSeparator) { + if (decimalSeparator == '.') { + return input; + } + + size_t numericEnd = 0; + for (; numericEnd < input.size() && isNumberChar(input[numericEnd]); ++numericEnd); + + std::string numericPart = input.substr(0, numericEnd); + std::string suffix = input.substr(numericEnd); + + char* end; + double val = strtod(numericPart.c_str(), &end); + + if (end != numericPart.c_str() && *end == '\0') { + size_t decimalPointPos = numericPart.find('.'); + if (decimalPointPos != std::string::npos) { + numericPart[decimalPointPos] = decimalSeparator; + } + return numericPart + suffix; + } else { + return input; + } + } + +} // namespace nspanel_ha_blueprint diff --git a/components/nspanel_ha_blueprint/text.h b/components/nspanel_ha_blueprint/text.h index 24e802f..cf2bf86 100644 --- a/components/nspanel_ha_blueprint/text.h +++ b/components/nspanel_ha_blueprint/text.h @@ -1,100 +1,40 @@ // text.h + #pragma once -#include -#include -#include #include namespace nspanel_ha_blueprint { /** * Copies the contents of a std::string to a fixed-size char array, ensuring - * null termination of the string within the array. This function template - * automatically deduces the size of the destination char array at compile time, - * minimizing the risk of buffer overflow. It's designed for use with fixed-size - * char arrays only, not pointers or dynamically allocated memory. + * null termination. The destination array size is automatically deduced. + * Designed for fixed-size char arrays only. * - * Template Parameter: - * N - The size of the destination char array. This value is deduced automatically - * and must be greater than 0. - * - * Parameters: - * dest - A reference to the destination char array where the string should be copied. - * The array must have a size that can accommodate the source string plus a - * null terminator. If the source string is longer than the destination array, - * it will be truncated. - * src - The source std::string to copy. This string's contents are copied into the - * destination array up to the array's capacity minus one, to leave space for - * the null terminator. - * - * Usage Example: - * char destination[11]; - * std::string source = "Hello"; - * nspanel_ha_blueprint::copyStringToCharArray(destination, source); - * - * Note: The destination array is always null-terminated, even if the source string - * is truncated to fit into the array. + * @param dest A reference to the destination char array. + * @param src The source std::string to copy. */ template - void copyStringToCharArray(char (&dest)[N], const std::string& src) { - // Ensure we do not exceed the buffer size, leaving space for the null terminator - size_t length = std::min(src.size(), N - 1); - - // Copy the string data into the destination buffer - std::strncpy(dest, src.c_str(), length); - - // Explicitly null-terminate the destination buffer - dest[length] = '\0'; - } - - // Helper function to determine if a character is part of a number - bool isNumberChar(char c) { - return std::isdigit(c) || c == '.' || c == '-' || c == ','; - } + void copyStringToCharArray(char (&dest)[N], const std::string& src); /** - * Adjusts the decimal separator in a numeric string to a specified character. - * This function identifies and modifies the decimal separator of a number within a string, - * ensuring that only the first occurrence is replaced if it is a valid number followed by - * any non-numeric characters (e.g., units of measurement). If the input string does not - * start with a valid number, it is returned unchanged. - * - * @param input The string potentially containing a numeric value followed by text. - * @param decimalSeparator The character to use as the decimal separator. - * @return A string with the decimal separator adjusted if the input is a valid number, - * otherwise the original input string. - */ - std::string adjustDecimalSeparator(const std::string& input, char decimalSeparator) { - // Immediately return the original string if the desired decimal separator is "." - if (decimalSeparator == '.') { - return input; - } + * Determines if a character is part of a numeric string. This includes digits, + * a period (.), a minus sign (-), or a comma (,). + * + * @param c The character to check. + * @return True if the character is part of a number; false otherwise. + */ + bool isNumberChar(char c); - // Find the end of the numeric part of the string - size_t numericEnd = 0; - for (; numericEnd < input.size() && isNumberChar(input[numericEnd]); ++numericEnd); - - // Extract the numeric part and the suffix (if any) - std::string numericPart = input.substr(0, numericEnd); - std::string suffix = input.substr(numericEnd); - - // Attempt to convert the numeric part to a double - char* end; - double val = strtod(numericPart.c_str(), &end); - - // Check if conversion was successful (end points to a null terminator if so) - if (end != numericPart.c_str() && *end == '\0') { - // Find and replace only the first occurrence of '.' with the specified decimalSeparator - size_t decimalPointPos = numericPart.find('.'); - if (decimalPointPos != std::string::npos) { - numericPart[decimalPointPos] = decimalSeparator; - } - return numericPart + suffix; - } else { - // If the input is not a number, return it as is - return input; - } - } + /** + * Adjusts the decimal separator in a numeric string to the specified character. + * Only the first occurrence is replaced if it's a valid number followed by text. + * Returns the original string if it doesn't start with a valid number. + * + * @param input The string containing a numeric value followed by text. + * @param decimalSeparator The character to use as the decimal separator. + * @return A string with the adjusted decimal separator if valid; otherwise, the original string. + */ + std::string adjustDecimalSeparator(const std::string& input, char decimalSeparator); } // namespace nspanel_ha_blueprint diff --git a/components/nspanel_ha_blueprint/utilities.cpp b/components/nspanel_ha_blueprint/utilities.cpp index 93e1fb3..6b5f1ae 100644 --- a/components/nspanel_ha_blueprint/utilities.cpp +++ b/components/nspanel_ha_blueprint/utilities.cpp @@ -1,13 +1,12 @@ // utilities.cpp + #include "utilities.h" -#include -#include +#include // For malloc/free #ifdef USE_ESP_IDF #include "esp_heap_caps.h" #elif defined(USE_ARDUINO) #include "esp32-hal-psram.h" -#endif // ESP-IDF vs ARDUINO - +#endif namespace nspanel_ha_blueprint { @@ -19,20 +18,21 @@ namespace nspanel_ha_blueprint { UtilitiesGroups = static_cast(heap_caps_malloc(8 * sizeof(UtilitiesGroupValues), MALLOC_CAP_SPIRAM)); #elif defined(USE_ARDUINO) UtilitiesGroups = static_cast(ps_malloc(8 * sizeof(UtilitiesGroupValues))); - #endif // ESP-IDF vs ARDUINO + #endif if (!UtilitiesGroups) UtilitiesGroups = new UtilitiesGroupValues[8]; // Fallback to internal SRAM if PSRAM is not available or not supported - if (!UtilitiesGroups) return; // Fail nicely if no memory is available + if (!UtilitiesGroups) return; // Fail nicely if no memory is available + // Initialize UtilitiesGroups with default values const UtilitiesGroupValues initialUtilitiesGroups[8] = { - { "grid", "\0", "\0", 0 }, - { "group01", "\0", "\0", 0 }, - { "group02", "\0", "\0", 0 }, - { "group03", "\0", "\0", 0 }, - { "group04", "\0", "\0", 0 }, - { "group05", "\0", "\0", 0 }, - { "group06", "\0", "\0", 0 }, - { "home", "\0", "\0", 0 } + {"grid", "\0", "\0", 0}, + {"group01", "\0", "\0", 0}, + {"group02", "\0", "\0", 0}, + {"group03", "\0", "\0", 0}, + {"group04", "\0", "\0", 0}, + {"group05", "\0", "\0", 0}, + {"group06", "\0", "\0", 0}, + {"home", "\0", "\0", 0} }; for (size_t i = 0; i < 8; ++i) { @@ -45,7 +45,7 @@ namespace nspanel_ha_blueprint { void cleanupUtilitiesGroups() { if (UtilitiesGroups != nullptr) { - free(UtilitiesGroups); // Compatible with both heap_caps_malloc and ps_malloc + free(UtilitiesGroups); // Compatible with both heap_caps_malloc and ps_malloc UtilitiesGroups = nullptr; // Prevent dangling pointers } } diff --git a/components/nspanel_ha_blueprint/utilities.h b/components/nspanel_ha_blueprint/utilities.h index e5f6d2d..bc55d17 100644 --- a/components/nspanel_ha_blueprint/utilities.h +++ b/components/nspanel_ha_blueprint/utilities.h @@ -1,20 +1,44 @@ // utilities.h + #pragma once #include +#include // For std::strcpy +#include namespace nspanel_ha_blueprint { struct UtilitiesGroupValues { char group_id[8]; // 7 characters + null terminator - char value1[11]; // 10 characters + null terminator - char value2[11]; // 11 characters + null terminator + char value1[11]; // 10 characters + null terminator + char value2[11]; // 10 characters + null terminator int8_t direction; }; - extern UtilitiesGroupValues UtilitiesGroups[8]; + extern UtilitiesGroupValues *UtilitiesGroups; void resetUtilitiesGroups(); + void cleanupUtilitiesGroups(); uint8_t findUtilitiesGroupIndex(const char* group_id); + /** + * Copies the contents of a std::string to a fixed-size char array, ensuring + * null termination. The destination array size is automatically deduced. + * Designed for fixed-size char arrays only. + * + * @param dest A reference to the destination char array. + * @param src The source std::string to copy. + */ + template + void copyStringToCharArray(char (&dest)[N], const std::string& src) { + // Ensure we do not exceed the buffer size, leaving space for the null terminator + size_t length = std::min(src.size(), N - 1); + + // Copy the string data into the destination buffer + std::strncpy(dest, src.c_str(), length); + + // Explicitly null-terminate the destination buffer + dest[length] = '\0'; + } + } // namespace nspanel_ha_blueprint diff --git a/components/nspanel_ha_blueprint/versioning.cpp b/components/nspanel_ha_blueprint/versioning.cpp new file mode 100644 index 0000000..1456707 --- /dev/null +++ b/components/nspanel_ha_blueprint/versioning.cpp @@ -0,0 +1,20 @@ +// versioning.cpp + +#include "versioning.h" +#include // For sscanf + +namespace nspanel_ha_blueprint { + + bool compare_versions(const char* version1, const char* version2) { + int major1 = 0, minor1 = 0; + int major2 = 0, minor2 = 0; + + // Parse the version strings into major and minor numbers + sscanf(version1, "%d.%d", &major1, &minor1); + sscanf(version2, "%d.%d", &major2, &minor2); + + // Compare the parsed major and minor numbers + return (major1 == major2) && (minor1 == minor2); + } + +} // namespace nspanel_ha_blueprint diff --git a/components/nspanel_ha_blueprint/versioning.h b/components/nspanel_ha_blueprint/versioning.h index 60f93a7..57fc7b9 100644 --- a/components/nspanel_ha_blueprint/versioning.h +++ b/components/nspanel_ha_blueprint/versioning.h @@ -1,25 +1,19 @@ // versioning.h + #pragma once -#include // For sscanf namespace nspanel_ha_blueprint { /** - * Compares two version strings by major and minor version numbers. - * Assumes version strings are in the format "major.minor". + * Compares two version strings by major and minor version numbers, assuming the version + * strings are formatted as "major.minor". This function parses both version strings and + * compares their major and minor components. * - * @param version1 First version string to compare. - * @param version2 Second version string to compare. - * @return true if the major and minor versions are equal, false otherwise. + * @param version1 The first version string to compare, in "major.minor" format. + * @param version2 The second version string to compare, in "major.minor" format. + * @return True if both the major and minor versions of version1 and version2 are equal, + * false otherwise. */ - inline bool compare_versions(const char* version1, const char* version2) { - int major1 = 0, minor1 = 0; - int major2 = 0, minor2 = 0; - - sscanf(version1, "%d.%d", &major1, &minor1); - sscanf(version2, "%d.%d", &major2, &minor2); - - return (major1 == major2) && (minor1 == minor2); - } + bool compare_versions(const char* version1, const char* version2); } // namespace nspanel_ha_blueprint diff --git a/components/nspanel_ha_blueprint_upload_tft/upload_tft.cpp b/components/nspanel_ha_blueprint_upload_tft/upload_tft.cpp new file mode 100644 index 0000000..6229b1d --- /dev/null +++ b/components/nspanel_ha_blueprint_upload_tft/upload_tft.cpp @@ -0,0 +1,28 @@ +// upload_tft.cpp + +#include "upload_tft.h" + +namespace nspanel_ha_blueprint_upload_tft { + + std::string construct_tft_url(const std::string& branch, const std::string& model, + const std::string& defaultUrl, const std::string& baseUrl) { + std::string relative_branch = branch.find("b") != std::string::npos ? "beta" : branch.find("d") != std::string::npos ? "dev" : branch; + std::string file_name; + if (model == "NSPanel Blank") file_name = "nspanel_blank.tft"; + else if (model == "NSPanel EU") file_name = "nspanel_eu.tft"; + else if (model == "NSPanel US") file_name = "nspanel_us.tft"; + else if (model == "NSPanel US Landscape") file_name = "nspanel_us_land.tft"; + else if (model == "NSPanel EU (CJK languages)") file_name = "nspanel_CJK_eu.tft"; + else if (model == "NSPanel US (CJK languages)") file_name = "nspanel_CJK_us.tft"; + else if (model == "NSPanel US Landscape (CJK languages)") file_name = "nspanel_CJK_us_land.tft"; + return file_name.empty() ? defaultUrl : baseUrl + relative_branch + "/hmi/" + file_name; + } + + std::string getNSPanelText(int displayMode, int charset) { + if (displayMode < 1 || displayMode > 3 || charset < 1 || charset > 2) return ""; + std::string text = (displayMode == 1) ? "NSPanel EU" : (displayMode == 2) ? "NSPanel US" : "NSPanel US Landscape"; + if (charset == 2) text += " (CJK languages)"; + return text; + } + +} // namespace nspanel_ha_blueprint_upload_tft diff --git a/components/nspanel_ha_blueprint_upload_tft/upload_tft.h b/components/nspanel_ha_blueprint_upload_tft/upload_tft.h index 8ffe34d..4f02c69 100644 --- a/components/nspanel_ha_blueprint_upload_tft/upload_tft.h +++ b/components/nspanel_ha_blueprint_upload_tft/upload_tft.h @@ -1,4 +1,5 @@ // upload_tft.h + #pragma once #include @@ -6,76 +7,24 @@ namespace nspanel_ha_blueprint_upload_tft { /** - * Constructs the TFT file URL based on branch, model, default URL, and base URL. - * - * @param branchInput The input branch version, which might contain special keywords like "beta" or "dev". - * @param model The model of the device, used to determine the specific TFT file name. - * @param defaultUrl The default URL to use if no specific file is associated with the model. - * @param baseUrl The base URL to which branch and file names are appended to construct the full URL. - * @return The fully constructed URL as a string. - */ + * Constructs the TFT file URL based on branch, model, default URL, and base URL. + * + * @param branch The branch version input, potentially containing keywords like "beta" or "dev". + * @param model The device model, determining the specific TFT file name. + * @param defaultUrl The fallback URL if no specific file is associated with the model. + * @param baseUrl The base URL, to which branch and file names are appended to create the full URL. + * @return A string representing the fully constructed URL. + */ std::string construct_tft_url(const std::string& branch, const std::string& model, - const std::string& defaultUrl, const std::string& baseUrl) { - // Determine the branch based on the input - std::string relative_branch = branch; - if (branch.find("b") != std::string::npos) relative_branch = "beta"; - else if (branch.find("d") != std::string::npos) relative_branch = "dev"; - - // Mapping model to the corresponding TFT file name - std::string file_name; - if (model == "NSPanel Blank") file_name = "nspanel_blank.tft"; - else if (model == "NSPanel EU") file_name = "nspanel_eu.tft"; - else if (model == "NSPanel US") file_name = "nspanel_us.tft"; - else if (model == "NSPanel US Landscape") file_name = "nspanel_us_land.tft"; - else if (model == "NSPanel EU (CJK languages)") file_name = "nspanel_CJK_eu.tft"; - else if (model == "NSPanel US (CJK languages)") file_name = "nspanel_CJK_us.tft"; - else if (model == "NSPanel US Landscape (CJK languages)") file_name = "nspanel_CJK_us_land.tft"; - - // Construct the URL based on the determined file name - std::string url; - if (file_name.empty()) { - url = defaultUrl; // Use the default URL if no specific file name is matched - } else { - url = baseUrl + relative_branch + "/hmi/" + file_name; // Construct the full URL - } - - return url; // Return the constructed URL - } + const std::string& defaultUrl, const std::string& baseUrl); /** - * @brief Generates a descriptive text for the NSPanel based on the given display mode and charset. - * - * This function maps numeric codes for the display mode and charset to a human-readable - * description of an NSPanel configuration. It supports different geographic regions and language - * character sets. If the inputs do not match any predefined configuration, the function returns - * an empty string, allowing for easy detection of unexpected or invalid inputs. - * - * @param displayMode An integer representing the display mode of the NSPanel: - * 1 for "EU", 2 for "US", and 3 for "US Landscape". - * @param charset An integer indicating the character set used: - * 1 for "International (original)" and 2 for "CJK languages". - * @return std::string A string describing the NSPanel configuration based on the inputs. - * Returns an empty string if the inputs do not match any known configuration. - */ - std::string getNSPanelText(int displayMode, int charset) { - - if (displayMode < 1 or displayMode > 3 or charset < 1 or charset > 2) return ""; - - std::string text; - // Determine the base text based on the display mode - switch(displayMode) { - case 1: text = "NSPanel EU"; break; - case 2: text = "NSPanel US"; break; - case 3: text = "NSPanel US Landscape"; break; - default: return ""; // Return an empty string for unmatched display modes - } - - // Append the charset text if necessary - if (charset == 2) { - text += " (CJK languages)"; - } - - return text; - } + * Generates a descriptive text for the NSPanel based on display mode and charset. + * + * @param displayMode Numeric code for the NSPanel's display mode: 1 for "EU", 2 for "US", 3 for "US Landscape". + * @param charset Numeric code for the character set: 1 for "International (original)", 2 for "CJK languages". + * @return A string describing the NSPanel configuration, or an empty string if inputs don't match any configuration. + */ + std::string getNSPanelText(int displayMode, int charset); } // namespace nspanel_ha_blueprint_upload_tft diff --git a/esphome/nspanel_esphome_core.yaml b/esphome/nspanel_esphome_core.yaml index 97c0c0a..090f1c3 100644 --- a/esphome/nspanel_esphome_core.yaml +++ b/esphome/nspanel_esphome_core.yaml @@ -176,7 +176,7 @@ time: then: - lambda: |- ESP_LOGD("time.on_time_sync", "System clock synchronized"); - ESP_LOGD("time.on_time_sync", "Timezone: %s", get_timezone().c_str()); + ESP_LOGD("time.on_time_sync", "Timezone: %s", time_provider->get_timezone().c_str()); refresh_datetime->execute(); json: # Can be replaced by web_server