diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 5ff7e81d..25a93358 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -81,6 +81,51 @@ Updated scripts require adjustments to these customizations: ## Noteworthy Changes +### Core and Standard Functionality Split +In this release, we are introducing a new split between "Core" and "Standard" functionalities. +This change is aimed at advanced users who wish to customize their panel by selectively removing +certain functionalities to free up resources for other uses. + +> [!IMPORTANT] +> Unless you want to remove some functionality, no changes are needed on your panel's yaml. + +#### Background +Previously, we introduced the concept of `add-ons`, which allowed your panel to act as a Bluetooth proxy, +local thermostat, or cover control, extending its capabilities beyond the core functionality. +Now, we’re taking a step further by splitting the core functionality into "Core" and "Standard" categories: +- **Core Functionality:** Essential features required for any panel installation. +- **Standard Functionality:** Common features included by default in regular installations, but optional for advanced users. + +#### Benefits of the Split +1. **Resource Optimization:** + Advanced users can remove unused functionalities, freeing up memory for custom uses unrelated to this project. + - Example: If you’re not using hardware relays, you can remove the package for Hardware Relays to free up resources. + - Similarly, if cover control is not used, you can exclude the related code. + +2. **Improved Code Management:** + Each feature is now encapsulated in a dedicated package, making it easier to locate and customize specific functionality. + Developers and troubleshooters can focus on isolated areas of the code without interfering with unrelated parts. + +3. **Future Accessibility:** + While currently targeted at advanced users, this split lays the groundwork for making functionality selection + more accessible for all users, including entry-level users, in future releases. + +#### Example Use Case +To customize your installation and include only the functionalities you need: +```yaml +packages: + # Include only the features you need: + standard_relay: !include packages/standard_relay.yaml # Remove this line if relays are not needed + standard_cover: !include packages/standard_cover.yaml # Remove this line if cover control is not needed + core: !include packages/core.yaml # Core functionality (mandatory) +``` +This split not only optimizes resources but also simplifies customization, troubleshooting, and development, +making it easier to focus on specific areas of the code without affecting others. + +#### What's Next +While this change is currently focused on advanced users, we are working towards making it easier for all users, +allowing everyone to select what functionalities they want during installation in a more intuitive way. + ### Dynamic QR Code Assign an entity (input text or sensor) to a QR code. The QR code updates dynamically with entity value changes. QR code length limit extended to 96 chars for more complex codes. diff --git a/components/nspanel_ha_blueprint/core_boot.cpp b/components/nspanel_ha_blueprint/core_boot.cpp index 6b96dbfd..0817c37c 100644 --- a/components/nspanel_ha_blueprint/core_boot.cpp +++ b/components/nspanel_ha_blueprint/core_boot.cpp @@ -1,80 +1,83 @@ // core_boot.cpp +#ifdef NSPANEL_HA_BLUEPRINT_CORE_BOOT + #include "core_boot.h" // Include the header file for function and variable declarations. namespace nspanel_ha_blueprint { - // Definition of the global variable to track completed boot steps. - // Each bit in this variable represents whether a boot step has been completed. - DRAM_ATTR uint32_t completed_boot_steps = 0; + // Total number of defined boot steps. + uint8_t total_boot_steps = 0; + uint32_t completed_boot_steps = 0; + uint32_t registered_applications = 0; // Function to mark a boot step as completed. - // Parameters: - // step - The boot step constant representing the step to be marked as completed. bool complete_boot_step(const uint32_t step) { // Validate that the step is a power of two (i.e., only one bit is set). - // This ensures that only valid boot step constants are accepted. if (step == 0 || (step & (step - 1)) != 0) { - // If the step is zero or not a power of two, it's invalid. return false; } // Use bitwise OR to set the corresponding bit in completed_boot_steps. - // This marks the boot step as completed. completed_boot_steps |= step; return true; } + // Function to register an application for boot. + bool register_application(const uint32_t app_bit) { + // Validate that the app_bit is a power of two (i.e., only one bit is set). + if (app_bit == 0 || (app_bit & (app_bit - 1)) != 0) { + return false; + } + // Check if the application is already registered, if not, increment total_boot_steps. + if ((registered_applications & app_bit) == 0) { + total_boot_steps++; + } + // Use bitwise OR to set the corresponding bit in registered_applications. + registered_applications |= app_bit; + return true; + } + // Helper function to count the number of bits set to '1' in a uint32_t value. - // Parameters: - // value - The uint32_t value whose bits are to be counted. - // Returns: - // The number of bits set to '1' as an integer. uint8_t count_bits_set(uint32_t value) { uint8_t count = 0; while (value) { - // Increment count if the least significant bit is '1'. count += value & 1; - // Right-shift the value to check the next bit. value >>= 1; } return count; } // Function to get the number of unique boot steps that have been completed. - // Returns: - // The count of completed boot steps as an integer. uint8_t get_boot_steps_completed() { return count_bits_set(completed_boot_steps); } // Function to calculate the boot progress percentage with rounding. - // Returns: - // The boot progress percentage as a uint8_t between 0 and 100. uint8_t get_boot_progress_percentage() { - // Calculate the percentage with rounding - return static_cast((get_boot_steps_completed() * 100 + TOTAL_BOOT_STEPS / 2) / TOTAL_BOOT_STEPS); + if (total_boot_steps == 0) { + return 0; + } + return static_cast((get_boot_steps_completed() * 100 + total_boot_steps / 2) / total_boot_steps); } - // Function to check if all boot steps have been completed. - // Returns: - // true if all boot steps are completed, false otherwise. + // Function to check if all registered applications have completed boot. bool is_boot_complete() { - return get_boot_steps_completed() == TOTAL_BOOT_STEPS; + // Boot is complete if all bits set in registered_applications are also set in completed_boot_steps. + return (registered_applications & completed_boot_steps) == registered_applications; } - // Function to reset the completed boot steps to zero. - // This clears all tracked boot steps. + // Function to reset the completed boot steps and registered applications to zero. void reset_boot_steps() { + total_boot_steps = 0; completed_boot_steps = 0; + registered_applications = 0; } // Function to check if a specific boot step has been completed. - // Parameters: - // step - The boot step constant representing the step to check. - // Returns: - // true if the boot step has been completed; false otherwise. bool is_boot_step_completed(uint32_t step) { return (completed_boot_steps & step) != 0; } } // namespace nspanel_ha_blueprint + +#endif // NSPANEL_HA_BLUEPRINT_CORE_BOOT diff --git a/components/nspanel_ha_blueprint/core_boot.h b/components/nspanel_ha_blueprint/core_boot.h index 25ee4983..a9ebc79e 100644 --- a/components/nspanel_ha_blueprint/core_boot.h +++ b/components/nspanel_ha_blueprint/core_boot.h @@ -2,25 +2,32 @@ #pragma once // Include guard to prevent multiple inclusions of this header file +#ifdef NSPANEL_HA_BLUEPRINT_CORE_BOOT + #include // Include standard integer types -#include "esp_attr.h" // Include for PSRAM attributes namespace nspanel_ha_blueprint { // Total number of defined boot steps. - const uint8_t TOTAL_BOOT_STEPS = 30; // Update as needed. - - // Extern declaration of the global variable to track completed boot steps. - // This variable is defined in boot.cpp. + extern uint8_t total_boot_steps; extern uint32_t completed_boot_steps; + extern uint32_t registered_applications; // Function to mark a boot step as completed. // Parameters: // step - The boot step constant representing the step to be marked as completed. // Returns: - // true if the boot step has been sucessfuly marked completed; + // true if the boot step has been successfully marked completed; // false otherwise (like in the case of an invalid step constant). bool complete_boot_step(const uint32_t step); + // Function to register an application for boot. + // Parameters: + // app_bit - The application bit representing the application to be registered. + // Returns: + // true if the application has been successfully registered; + // false otherwise (e.g., invalid bit). + bool register_application(const uint32_t app_bit); + // Function to get the number of unique boot steps that have been completed. // Returns: // The count of completed boot steps as an integer. @@ -31,13 +38,13 @@ namespace nspanel_ha_blueprint { // The boot progress percentage as a uint8_t between 0 and 100. uint8_t get_boot_progress_percentage(); - // Function to check if all boot steps have been completed. + // Function to check if all registered applications have completed boot. // Returns: - // true if all boot steps are completed, false otherwise. + // true if all registered applications have completed boot, false otherwise. bool is_boot_complete(); - // Function to reset the completed boot steps to zero. - // This clears all tracked boot steps. + // Function to reset the completed boot steps and registered applications to zero. + // This clears all tracked boot steps and applications. void reset_boot_steps(); // Function to check if a specific boot step has been completed. @@ -48,3 +55,5 @@ namespace nspanel_ha_blueprint { bool is_boot_step_completed(uint32_t step); } // namespace nspanel_ha_blueprint + +#endif // NSPANEL_HA_BLUEPRINT_CORE_BOOT diff --git a/components/nspanel_ha_blueprint/core_page_utilities.h b/components/nspanel_ha_blueprint/core_page_utilities.h deleted file mode 100644 index c2a7761c..00000000 --- a/components/nspanel_ha_blueprint/core_page_utilities.h +++ /dev/null @@ -1,44 +0,0 @@ -// core_page_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]; // 10 characters + null terminator - int8_t direction; - }; - - 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/ha_to_nextion.cpp b/components/nspanel_ha_blueprint/ha_to_nextion.cpp deleted file mode 100644 index e79f9cc7..00000000 --- a/components/nspanel_ha_blueprint/ha_to_nextion.cpp +++ /dev/null @@ -1,129 +0,0 @@ -// ha_to_nextion.cpp - -#include "ha_to_nextion.h" - -namespace nspanel_ha_blueprint { - - DRAM_ATTR uint64_t callback_counter = 0; - - // Singleton instance of HaToNextionManager - HaToNextionManager& HaToNextionManager::getInstance() { - static HaToNextionManager instance; - return instance; - } - - HaToNextionManager::HaToNextionManager() = default; - - HaToNextionManager::~HaToNextionManager() { - resetSubscriptions(); - } - - void HaToNextionManager::addSubscription(const std::string &entity_id, const std::string &page, - const std::string &component, bool is_global) { - esphome::ESP_LOGD(TAG_HA_TO_NEXTION, "New subscription requested to '%s', page '%s', and component '%s'", - entity_id.c_str(), page.c_str(), component.c_str()); - if (findSubscription(page, component) != nullptr) { - esphome::ESP_LOGW(TAG_HA_TO_NEXTION, "Subscription for page '%s', and component '%s' already exists!", - page.c_str(), component.c_str()); - return; - } - esphome::ESP_LOGD(TAG_HA_TO_NEXTION, "No previous subscription found"); - - // Allocate the buffer dynamically - esphome::ESP_LOGD(TAG_HA_TO_NEXTION, "Allocating memory"); - esphome::ExternalRAMAllocator - allocator(esphome::ExternalRAMAllocator::ALLOW_FAILURE); - EntityTarget *new_entity_target = allocator.allocate(sizeof(EntityTarget)); - if (!new_entity_target || new_entity_target == nullptr) { - esphome::ESP_LOGE(TAG_HA_TO_NEXTION, "Failed to allocate memory for new EntityTarget."); - return; - } - esphome::ESP_LOGD(TAG_HA_TO_NEXTION, "Memory allocated"); - - // Initialize the new entity target with the provided data - copyStringToCharArray(new_entity_target->entity_id, entity_id); - copyStringToCharArray(new_entity_target->page, page); - copyStringToCharArray(new_entity_target->component, component); - new_entity_target->is_global = is_global; - new_entity_target->nextion_updated = false; - copyStringToCharArray(new_entity_target->last_state_sent, ""); - - // Add the newly created subscription to the list - if (subscriptions_.max_size() == subscriptions_.size()) { - esphome::ESP_LOGE(TAG_HA_TO_NEXTION, "Subscription list capacity reached. Failed to add new subscription."); - free(new_entity_target); - return; - } - subscriptions_.push_back(new_entity_target); - esphome::ESP_LOGI(TAG_HA_TO_NEXTION, - "Successfully added subscription: entity_id='%s', page='%s', component='%s', global=%s", - entity_id.c_str(), page.c_str(), component.c_str(), is_global ? "true" : "false"); - } - - void HaToNextionManager::setupSubscriptions() { - for (auto* subscription : subscriptions_) { - if (subscription == nullptr) continue; - esphome::api::global_api_server->subscribe_home_assistant_state( - subscription->entity_id, {}, [this, subscription](const std::string &state) { - callback_counter++; - if (state == subscription->last_state_sent) { - esphome::ESP_LOGD(TAG_HA_TO_NEXTION, "State for entity '%s' has not changed, no update sent.", - subscription->entity_id); - return; - } - copyStringToCharArray(subscription->last_state_sent, state); - if (subscription->is_global || isCurrentPage(subscription->page)) { - updateNextionDisplay(subscription, state); - } else { - esphome::ESP_LOGD(TAG_HA_TO_NEXTION, - "Skipping update for entity '%s' as current page does not match target page '%s'.", - subscription->entity_id, subscription->page); - } - }); - esphome::ESP_LOGI(TAG_HA_TO_NEXTION, "Subscribed to entity: %s for target component '%s' on page '%s'", - subscription->entity_id, subscription->component, - subscription->page); - } - } - - void HaToNextionManager::resetSubscriptions() { - for (auto* subscription : subscriptions_) { - if (subscription != nullptr) { - free(subscription); - } - } - subscriptions_.clear(); - esphome::ESP_LOGI(TAG_HA_TO_NEXTION, "All subscriptions have been reset. You can now add new subscriptions."); - } - - EntityTarget* HaToNextionManager::findSubscription(const std::string &page, const std::string &component) { - for (auto* subscription : subscriptions_) { - if (subscription && - strcmp(subscription->page, page.c_str()) == 0 && - strcmp(subscription->component, component.c_str()) == 0) { - return subscription; - } - } - return nullptr; - } - - bool HaToNextionManager::isCurrentPage(const std::string &page) { - // Placeholder: replace this with actual logic to check the current Nextion page - return true; // Assume it's always true for now - } - - void HaToNextionManager::updateNextionDisplay(EntityTarget* subscription, const std::string &state) { - if (subscription->is_global) { - esphome::ESP_LOGD(TAG_HA_TO_NEXTION, "Global Component: Sending update to Nextion for entity '%s' with value: %s", - subscription->entity_id, state.c_str()); - } else { - esphome::ESP_LOGD(TAG_HA_TO_NEXTION, "Component '%s' on page '%s': Sending update to Nextion with value: %s", - subscription->component, subscription->page, state.c_str()); - } - // Example Nextion command to update the component value (pseudo-code) - // sendCommandToNextion(subscription->page, subscription->component, state); - } - - std::vector HaToNextionManager::subscriptions_; - -} // namespace nspanel_ha_blueprint diff --git a/components/nspanel_ha_blueprint/ha_to_nextion.h b/components/nspanel_ha_blueprint/ha_to_nextion.h deleted file mode 100644 index 5c4bd90a..00000000 --- a/components/nspanel_ha_blueprint/ha_to_nextion.h +++ /dev/null @@ -1,49 +0,0 @@ -// ha_to_nextion.h - -#pragma once - -#include -#include -#include "esp_attr.h" // Include for PSRAM attributes -#include "esphome/core/log.h" -#include "esphome/components/api/api_server.h" -#include "text.h" - -namespace nspanel_ha_blueprint { - - static const char* TAG_HA_TO_NEXTION = "nspanel_ha_blueprint.ha_to_nextion"; - - extern uint64_t callback_counter; - - struct EntityTarget { - char entity_id[256]; // The Home Assistant entity_id to subscribe to - char page[15]; // The target page on the Nextion display - char component[15]; // The target component on the specified page - bool is_global; // If true, always send update regardless of the current page - bool nextion_updated; // Is Nextion updated with the latest state - char last_state_sent[256]; // Track the last state sent to avoid duplicate updates - }; - - class HaToNextionManager { - public: - static HaToNextionManager& getInstance(); - - void addSubscription(const std::string &entity_id, const std::string &page, - const std::string &component, bool is_global); - - void setupSubscriptions(); - void resetSubscriptions(); - - private: - HaToNextionManager(); - ~HaToNextionManager(); - - EntityTarget* findSubscription(const std::string &page, const std::string &component); - - static std::vector subscriptions_; - - bool isCurrentPage(const std::string &page); - void updateNextionDisplay(EntityTarget* subscription, const std::string &state); - }; - -} // namespace nspanel_ha_blueprint diff --git a/components/nspanel_ha_blueprint/pages.cpp b/components/nspanel_ha_blueprint/pages.cpp index ff4d674a..e2c94703 100644 --- a/components/nspanel_ha_blueprint/pages.cpp +++ b/components/nspanel_ha_blueprint/pages.cpp @@ -7,6 +7,9 @@ namespace nspanel_ha_blueprint { // Definition of the global current_page_id DRAM_ATTR uint8_t current_page_id = 0; + // Definition of the global next_page_id + DRAM_ATTR uint8_t next_page_id = UINT8_MAX; + // Definition of the global previous_page_id DRAM_ATTR uint8_t previous_page_id = 0; @@ -49,6 +52,7 @@ namespace nspanel_ha_blueprint { DRAM_ATTR uint32_t WEATHER_PAGE_MASK = (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6); DRAM_ATTR uint32_t ENTITY_ID_PAGE_MASK = (1 << 24) | (1 << 7) | (1 << 11) | (1 << 22) | (1 << 10) | (1 << 25) | (1 << 27) | (1 << 23); + DRAM_ATTR uint32_t NON_API_ID_PAGE_MASK = (1 << 0) | (1 << 1) | (1 << 8) | (1 << 9) | (1 << 26); // Implementation of is_page_in_group bool is_page_in_group(uint32_t group_mask, uint8_t page_id) { diff --git a/components/nspanel_ha_blueprint/pages.h b/components/nspanel_ha_blueprint/pages.h index f0571f1c..10a8fbce 100644 --- a/components/nspanel_ha_blueprint/pages.h +++ b/components/nspanel_ha_blueprint/pages.h @@ -14,6 +14,10 @@ namespace nspanel_ha_blueprint { // Updated by Nextion `on_page` on nspanel_esphome_core_hw_display.yaml extern uint8_t current_page_id; + // Used to register the next page id + // Updated by script `goto_page` on nspanel_esphome_core_hw_display.yaml + extern uint8_t next_page_id; + // Used to register the previous page id // Updated by script `page_changed` on nspanel_esphome_core_hw_display.yaml extern uint8_t previous_page_id; @@ -40,6 +44,8 @@ namespace nspanel_ha_blueprint { extern uint32_t WEATHER_PAGE_MASK; // Pages using `entity_id`: Alarm, Climate, Cover, Fan, Light, Media Player, Confirm, Keyb Num extern uint32_t ENTITY_ID_PAGE_MASK; + // Pages not requiring API to be connected: Blank, Boot, Confirm, Home, Screen saver, Settings + extern uint32_t NON_API_ID_PAGE_MASK; // Generic function to check if a page ID belongs to a specific group, based on the provided mask bool is_page_in_group(uint32_t group_mask, uint8_t page_id = current_page_id); diff --git a/components/nspanel_ha_blueprint/core_page_buttons.h b/components/nspanel_ha_blueprint/standard_page_buttons.h similarity index 94% rename from components/nspanel_ha_blueprint/core_page_buttons.h rename to components/nspanel_ha_blueprint/standard_page_buttons.h index a33fdc3e..9730e413 100644 --- a/components/nspanel_ha_blueprint/core_page_buttons.h +++ b/components/nspanel_ha_blueprint/standard_page_buttons.h @@ -1,8 +1,8 @@ -// core_page_buttons.h +// standard_page_buttons.h #pragma once -#ifdef NSPANEL_HA_BLUEPRINT_CORE_PAGE_BUTTONS +#ifdef NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_BUTTONS #include #include @@ -11,7 +11,7 @@ namespace nspanel_ha_blueprint { - static const char* TAG_NEXTION = "nspanel_ha_blueprint.nextion"; + static const char* TAG_NEXTION = "nspanel_ha_blueprint.standard_page_buttons"; bool PageButtonsButtonInitilized = false; uint32_t PageButtonsMaskEnabled = 0; @@ -40,7 +40,7 @@ namespace nspanel_ha_blueprint { // Allocate PageButtonsButton dynamically esphome::ExternalRAMAllocator allocator(esphome::ExternalRAMAllocator::ALLOW_FAILURE); - buttonpage_buttons = allocator.allocate(32); + buttonpage_buttons = allocator.allocate(32*sizeof(PageButtonsButton)); if (!buttonpage_buttons || buttonpage_buttons == nullptr) { esphome::ESP_LOGE(TAG_NEXTION, "Failed to allocate memory for buttonpage_buttons."); return; // Memory allocation failed, do not proceed @@ -119,4 +119,4 @@ namespace nspanel_ha_blueprint { } // namespace nspanel_ha_blueprint -#endif // NSPANEL_HA_BLUEPRINT_CORE_PAGE_BUTTONS +#endif // NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_BUTTONS diff --git a/components/nspanel_ha_blueprint/core_page_utilities.cpp b/components/nspanel_ha_blueprint/standard_page_utilities.cpp similarity index 91% rename from components/nspanel_ha_blueprint/core_page_utilities.cpp rename to components/nspanel_ha_blueprint/standard_page_utilities.cpp index e53af103..57b6409c 100644 --- a/components/nspanel_ha_blueprint/core_page_utilities.cpp +++ b/components/nspanel_ha_blueprint/standard_page_utilities.cpp @@ -1,12 +1,14 @@ -// core_page_utilities.cpp +// standard_page_utilities.cpp -#include "core_page_utilities.h" +#ifdef NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_UTILITIES + +#include "standard_page_utilities.h" #include "esphome/core/log.h" #include "esphome/core/helpers.h" namespace nspanel_ha_blueprint { - static const char* TAG_UTILITIES = "nspanel_ha_blueprint.core_page_utilities"; + static const char* TAG_UTILITIES = "nspanel_ha_blueprint.standard_page_utilities"; UtilitiesGroupValues *UtilitiesGroups = nullptr; @@ -72,3 +74,5 @@ namespace nspanel_ha_blueprint { } } // namespace nspanel_ha_blueprint + +#endif // NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_UTILITIES diff --git a/components/nspanel_ha_blueprint/standard_page_utilities.h b/components/nspanel_ha_blueprint/standard_page_utilities.h new file mode 100644 index 00000000..7ce90887 --- /dev/null +++ b/components/nspanel_ha_blueprint/standard_page_utilities.h @@ -0,0 +1,28 @@ +// standard_page_utilities.h + +#pragma once + +#ifdef NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_UTILITIES + +#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]; // 10 characters + null terminator + int8_t direction; + }; + + extern UtilitiesGroupValues *UtilitiesGroups; + + void resetUtilitiesGroups(); + void cleanupUtilitiesGroups(); + uint8_t findUtilitiesGroupIndex(const char* group_id); + +} // namespace nspanel_ha_blueprint + +#endif // NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_UTILITIES diff --git a/components/nspanel_ha_blueprint/addon_upload_tft.cpp b/components/nspanel_ha_blueprint/standard_upload_tft.cpp similarity index 88% rename from components/nspanel_ha_blueprint/addon_upload_tft.cpp rename to components/nspanel_ha_blueprint/standard_upload_tft.cpp index 768650a4..49cd511f 100644 --- a/components/nspanel_ha_blueprint/addon_upload_tft.cpp +++ b/components/nspanel_ha_blueprint/standard_upload_tft.cpp @@ -1,8 +1,8 @@ -// addon_upload_tft.cpp +// standard_upload_tft.cpp -#ifdef NSPANEL_HA_BLUEPRINT_ADDON_UPLOAD_TFT +#ifdef NSPANEL_HA_BLUEPRINT_STANDARD_UPLOAD_TFT -#include "addon_upload_tft.h" +#include "standard_upload_tft.h" namespace nspanel_ha_blueprint { @@ -27,4 +27,4 @@ namespace nspanel_ha_blueprint { } // namespace nspanel_ha_blueprint -#endif // NSPANEL_HA_BLUEPRINT_ADDON_UPLOAD_TFT +#endif // NSPANEL_HA_BLUEPRINT_STANDARD_UPLOAD_TFT diff --git a/components/nspanel_ha_blueprint/addon_upload_tft.h b/components/nspanel_ha_blueprint/standard_upload_tft.h similarity index 90% rename from components/nspanel_ha_blueprint/addon_upload_tft.h rename to components/nspanel_ha_blueprint/standard_upload_tft.h index e9b51618..7c2932e2 100644 --- a/components/nspanel_ha_blueprint/addon_upload_tft.h +++ b/components/nspanel_ha_blueprint/standard_upload_tft.h @@ -1,8 +1,8 @@ -// addon_upload_tft.h +// standard_upload_tft.h #pragma once -#ifdef NSPANEL_HA_BLUEPRINT_ADDON_UPLOAD_TFT +#ifdef NSPANEL_HA_BLUEPRINT_STANDARD_UPLOAD_TFT #include @@ -29,4 +29,4 @@ namespace nspanel_ha_blueprint { } // namespace nspanel_ha_blueprint -#endif // NSPANEL_HA_BLUEPRINT_ADDON_UPLOAD_TFT +#endif // NSPANEL_HA_BLUEPRINT_STANDARD_UPLOAD_TFT diff --git a/components/nspanel_ha_blueprint/text.cpp b/components/nspanel_ha_blueprint/text.cpp index cb984615..41ea6650 100644 --- a/components/nspanel_ha_blueprint/text.cpp +++ b/components/nspanel_ha_blueprint/text.cpp @@ -7,20 +7,6 @@ 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; diff --git a/components/nspanel_ha_blueprint/text.h b/components/nspanel_ha_blueprint/text.h index bb280ab1..8927fce2 100644 --- a/components/nspanel_ha_blueprint/text.h +++ b/components/nspanel_ha_blueprint/text.h @@ -5,6 +5,7 @@ #include #include #include +#include namespace nspanel_ha_blueprint { @@ -17,84 +18,48 @@ namespace nspanel_ha_blueprint { * @param src The source std::string to copy. */ template - void copyStringToCharArray(char (&dest)[N], const std::string& src); + 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'; + } - // Function to compare the beginning of the string inline bool starts_with(const char* str, const char* prefix) { return std::strncmp(str, prefix, std::strlen(prefix)) == 0; } - /** - * 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. - */ - inline bool isNumberChar(char c); + inline bool isNumberChar(char c) { + return std::isdigit(static_cast(c)) || c == '.' || c == '-' || c == ','; + } - /** - * 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); - /** - * Processes the given time format string by replacing specific placeholders with actual values. - * - * @param time_format The input time format string containing placeholders such as "%-H" and "%-I". - * @param current_hour The current hour in 24-hour format (0-23). - * @param meridiem_am The string representation for AM. - * @param meridiem_pm The string representation for PM. - * @return The processed time format string with placeholders replaced by the actual values. - */ std::string process_time_format(const std::string &time_format, int current_hour, const std::string &meridiem_am, const std::string &meridiem_pm); - /** - * @brief Decode the first UTF-8 character from a C-style string and return its Unicode code point. - * - * This function extracts and decodes the first character of a UTF-8 encoded string. - * It determines how many bytes the UTF-8 character takes (1 to 4 bytes), and computes - * the corresponding Unicode code point. - * - * @param bytes A pointer to the UTF-8 encoded character (C-style string). - * @return uint32_t The Unicode code point of the first character in the input string. - */ inline uint32_t decode_utf8(const char* bytes) { - // Ensure the input is not null and not an empty string if (!bytes || bytes[0] == '\0') { - return 0; // Invalid input or empty string, return 0 as an error value + return 0; } uint32_t code_point = 0; unsigned char byte = static_cast(bytes[0]); if ((byte & 0x80) == 0x00) { - // 1-byte UTF-8 character (ASCII), 0xxxxxxx code_point = byte; } else if ((byte & 0xE0) == 0xC0 && bytes[1] != '\0') { - // 2-byte UTF-8 character, 110xxxxx 10xxxxxx code_point = ((byte & 0x1F) << 6) | (static_cast(bytes[1]) & 0x3F); } else if ((byte & 0xF0) == 0xE0 && bytes[1] != '\0' && bytes[2] != '\0') { - // 3-byte UTF-8 character, 1110xxxx 10xxxxxx 10xxxxxx code_point = ((byte & 0x0F) << 12) | - ((static_cast(bytes[1]) & 0x3F) << 6) | - (static_cast(bytes[2]) & 0x3F); + ((static_cast(bytes[1]) & 0x3F) << 6) | + (static_cast(bytes[2]) & 0x3F); } else if ((byte & 0xF8) == 0xF0 && bytes[1] != '\0' && bytes[2] != '\0' && bytes[3] != '\0') { - // 4-byte UTF-8 character, 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx code_point = ((byte & 0x07) << 18) | - ((static_cast(bytes[1]) & 0x3F) << 12) | - ((static_cast(bytes[2]) & 0x3F) << 6) | - (static_cast(bytes[3]) & 0x3F); + ((static_cast(bytes[1]) & 0x3F) << 12) | + ((static_cast(bytes[2]) & 0x3F) << 6) | + (static_cast(bytes[3]) & 0x3F); } else { - // Invalid UTF-8 sequence, return 0 to indicate an error code_point = 0; } - return code_point; // Return the decoded Unicode code point + return code_point; } inline std::string get_page_and_component(const std::string& page, const std::string& component) { diff --git a/docs/api.md b/docs/api.md index 16f8b3a1..fb2f4d86 100644 --- a/docs/api.md +++ b/docs/api.md @@ -446,7 +446,7 @@ data: > Replace `` with your specific panel name as configured in Home Assistant. > Using "default" fetches the URL associated with the selected display model in Home Assistant settings, simplifying updates or customizations. -> [!ATTENTION] +> [!IMPORTANT] > The "Upload TFT" add-on must be installed for this action to be available, enhancing the panel's flexibility for interface customization or troubleshooting. diff --git a/docs/customization.md b/docs/customization.md index f3ae6ea2..3ff766df 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -232,7 +232,7 @@ api: ### Manual IP Set IP address manually. -> [!ATTENTION] +> [!IMPORTANT] > At least one DNS server is required to enable TFT transfer direcly from GitHub, otherwise use `nextion_update_base_url`. ```yaml diff --git a/docs/howto.md b/docs/howto.md index 2c57d248..bc80d2b9 100644 --- a/docs/howto.md +++ b/docs/howto.md @@ -176,7 +176,7 @@ trigger: ``` ## Climate control with Relays -> [!ATTENTION] +> [!IMPORTANT] > Although these instructions are still valid, since v4.0 there is a better way to setup a climate control using the panel's relays an the [add-on climate](addon_climate.md), > which will continue to work even if Home Assistant and/or WiFi are not available. > You probably only want to use this approach, if you are not using the build-in thermometer. diff --git a/docs/install.md b/docs/install.md index 801096a1..6ca5134c 100644 --- a/docs/install.md +++ b/docs/install.md @@ -456,9 +456,73 @@ Before customizing your system, we encourage you to share any enhancements you m Consider creating a [Pull Request](https://github.com/Blackymas/NSPanel_HA_Blueprint/pulls) to the `dev` branch to share your discoveries with the community. ### Advanced ESPHome Configuration +If you want to use your panel in a non-standard way, there are some possibilities for advanced configuration. + +> [!WARNING] +> Any advanced configuration listed here isn’t fully supported, so you may be on your own if you decide to use these. + +#### Customizations For advanced customization with ESPHome, start with "Customizations." -We have a dedicated page for this, and your contributions are welcome: [Customization](customization.md). +We have a dedicated page for customizations, and we welcome your contributions: [Customization](customization.md). + +#### Selecting Remote Packages +You can edit your panel’s YAML to selectively use files from the remote packages. +Typically, a standard installation includes both the "**Core**" and "**Standard**" packages. + +If needed, you can modify these packages to control exactly what is installed. +This lets you remove or customize specific functionalities, using [local packages](#local-packages) if required. +This example YAML includes the same components as the standard package, but makes it easier to remove specific functionalities: + +```yaml +substitutions: + # Settings - Editable values + device_name: "YOUR_NSPANEL_NAME" + friendly_name: "Your panel's friendly name" + wifi_ssid: !secret wifi_ssid + wifi_password: !secret wifi_password + # Add-on configuration (if needed) + # heater_relay: "1" # Possible values: "1" or "2" + +# Core and optional configurations +packages: + remote_package: + url: https://github.com/Blackymas/NSPanel_HA_Blueprint + ref: main + refresh: 300s + files: + - esphome/nspanel_esphome_advanced.yaml # Core configuration required for basic functionality + # Optional (and recommended) packages + - esphome/nspanel_esphome_standard_hw_buzzer.yaml # Hardware - Buzzer + - esphome/nspanel_esphome_standard_hw_relays.yaml # Hardware - Relays + - esphome/nspanel_esphome_standard_hw_temperature.yaml # Hardware - Temperature Sensor + - esphome/nspanel_esphome_standard_page_alarm.yaml # Page Alarm + - esphome/nspanel_esphome_standard_page_blank.yaml # Blank Page + - esphome/nspanel_esphome_standard_page_buttons.yaml # Button Pages + - esphome/nspanel_esphome_standard_page_climate.yaml # Climate Page + - esphome/nspanel_esphome_standard_page_cover.yaml # Cover Page + - esphome/nspanel_esphome_standard_page_entities.yaml # Entity Pages + - esphome/nspanel_esphome_standard_page_fan.yaml # Fan Page + - esphome/nspanel_esphome_standard_page_keyb_num.yaml # Numeric Keyboard Page + - esphome/nspanel_esphome_standard_page_light.yaml # Light Page + - esphome/nspanel_esphome_standard_page_media_player.yaml # Media Player Page + - esphome/nspanel_esphome_standard_page_notification.yaml # Notification Page + - esphome/nspanel_esphome_standard_page_qrcode.yaml # QR Code Page + - esphome/nspanel_esphome_standard_page_settings.yaml # Settings Page + - esphome/nspanel_esphome_standard_page_utilities.yaml # Utilities Page + - esphome/nspanel_esphome_standard_page_weather.yaml # Weather Page + - esphome/nspanel_esphome_standard_upload_tft.yaml # TFT Upload Capability + # Optional advanced and add-on configurations + # - esphome/nspanel_esphome_advanced.yaml + # - esphome/nspanel_esphome_addon_ble_tracker.yaml + # - esphome/nspanel_esphome_addon_bluetooth_proxy.yaml + # - esphome/nspanel_esphome_addon_climate_cool.yaml + # - esphome/nspanel_esphome_addon_climate_heat.yaml + # - esphome/nspanel_esphome_addon_climate_dual.yaml + # - esphome/nspanel_esphome_addon_cover.yaml +``` + +#### Local Packages To use a local copy of `nspanel_esphome.yaml`, copy the file from GitHub to your local file system and include it in your ESPHome settings as follows: ```yaml @@ -479,6 +543,10 @@ packages: local_package: !include packages/nspanel_esphome.yaml ``` +> [!NOTE] +> Using local packages allows for greater control and quicker customization since you can modify the configuration without relying on a remote source. +> This can be useful for offline use or if you want to test changes before sharing them. + ### Advanced Blueprint Configuration The Blueprint file `nspanel_blueprint.yaml` can be installed manually. You can also edit your local copy of the Blueprint, but be aware that reloading the Blueprint from the repository will overwrite local changes. diff --git a/docs/tft_upload.md b/docs/tft_upload.md index 7e72b9a3..e7b24646 100644 --- a/docs/tft_upload.md +++ b/docs/tft_upload.md @@ -148,7 +148,8 @@ esp32: - **Issue**: Your firmware might be missing some important library, you may be using an outdated version, or the ESP may be out of memory. - **Solution**: Remove all add-ons and non-essential customization and flash your panel again. - **Step-by-Step Guide**: - 1. Look at your yaml file and comment out all the customization (typically in a section named "My customizations") and any of the remote files other than `nspanel_esphome.yaml`. + 1. Look at your yaml file and comment out all the customization (typically in a section named "My customizations") + and any of the packages/files other than `nspanel_esphome.yaml`. 2. Flash your panel with the new cleaner yaml. You can do this over the air/wirelessly, although it is recommended to use serial when changing between frameworks. 3. Try to update the TFT file again. 4. Add the add-ons and removed customization back and then flash it again. diff --git a/esphome/nspanel_esphome_core.yaml b/esphome/nspanel_esphome_core.yaml index d51f155b..9e89f74b 100644 --- a/esphome/nspanel_esphome_core.yaml +++ b/esphome/nspanel_esphome_core.yaml @@ -5,10 +5,6 @@ ##### For normal use with the Blueprint, no changes are necessary. ##### ##################################################################################################### --- -api: - id: api_server - reboot_timeout: 60min - esphome: platformio_options: build_flags: @@ -16,36 +12,21 @@ esphome: packages: # yamllint disable rule:colons + ## Core packages + versioning: !include nspanel_esphome_core_versioning.yaml + api: !include nspanel_esphome_core_api.yaml base: !include nspanel_esphome_core_base.yaml boot: !include nspanel_esphome_core_boot.yaml datetime: !include nspanel_esphome_core_datetime.yaml hw_buttons: !include nspanel_esphome_core_hw_buttons.yaml - hw_buzzer: !include nspanel_esphome_core_hw_buzzer.yaml hw_display: !include nspanel_esphome_core_hw_display.yaml hw_display_timers: !include nspanel_esphome_core_hw_display_timers.yaml hw_memory: !include nspanel_esphome_core_hw_memory.yaml - hw_relays: !include nspanel_esphome_core_hw_relays.yaml - hw_temperature: !include nspanel_esphome_core_hw_temperature.yaml hw_wifi: !include nspanel_esphome_core_hw_wifi.yaml - page_alarm: !include nspanel_esphome_core_page_alarm.yaml - page_blank: !include nspanel_esphome_core_page_blank.yaml page_boot: !include nspanel_esphome_core_page_boot.yaml - page_buttons: !include nspanel_esphome_core_page_buttons.yaml - page_climate: !include nspanel_esphome_core_page_climate.yaml - page_confirm: !include nspanel_esphome_core_page_confirm.yaml - page_cover: !include nspanel_esphome_core_page_cover.yaml - page_entities: !include nspanel_esphome_core_page_entities.yaml - page_fan: !include nspanel_esphome_core_page_fan.yaml + page_confirm: !include nspanel_esphome_core_page_confirm.yaml # Can be on Standard if upload_tft is modified page_home: !include nspanel_esphome_core_page_home.yaml - page_keyb_num: !include nspanel_esphome_core_page_keyb_num.yaml - page_light: !include nspanel_esphome_core_page_light.yaml - page_media_player: !include nspanel_esphome_core_page_media_player.yaml - page_notification: !include nspanel_esphome_core_page_notification.yaml - page_qrcode: !include nspanel_esphome_core_page_qrcode.yaml page_screensaver: !include nspanel_esphome_core_page_screensaver.yaml - page_settings: !include nspanel_esphome_core_page_settings.yaml - page_utilities: !include nspanel_esphome_core_page_utilities.yaml - page_weather: !include nspanel_esphome_core_page_weather.yaml - versioning: !include nspanel_esphome_core_versioning.yaml +# standard: !include nspanel_esphome_standard.yaml # yamllint enable rule:colons ... diff --git a/esphome/nspanel_esphome_core_api.yaml b/esphome/nspanel_esphome_core_api.yaml new file mode 100644 index 00000000..87d42701 --- /dev/null +++ b/esphome/nspanel_esphome_core_api.yaml @@ -0,0 +1,157 @@ +##################################################################################################### +##### NSPANEL ESPHOME created by Blackymas - https://github.com/Blackymas/NSPanel_HA_Blueprint ##### +##### ESPHOME CORE - API ##### +##### PLEASE only make changes if it is necessary and also the required knowledge is available. ##### +##### For normal use with the Blueprint, no changes are necessary. ##### +##################################################################################################### + +--- +substitutions: + ############################## + ## Change only in your ## + ## local yaml substitutions ## + device_name: nspanel + name: ${device_name} + friendly_name: ${device_name} + ota_password: ${wifi_password} + project_tag: nspanel_ha_blueprint + ############################## + BOOT_STEP_API: '1UL << 30' + +api: + id: api_server + reboot_timeout: 60min + + on_client_connected: + then: + - lambda: |- + boot_log->execute("API", (client_info + " connected (" + client_address + ")").c_str()); + if (client_info.find("Home Assistant ") == 0) + id(api_is_updated) = true; + else + dump_config->execute(); + + actions: + - action: set_bool + variables: + component: string + val: bool + then: + - script.execute: + id: set_var_bool + component: !lambda return component; + val: !lambda return val; + + - action: set_int + variables: + component: string + val: int + then: + - script.execute: + id: set_var_int + component: !lambda return component; + val: !lambda return val; + + - action: set_string + variables: + component: string + val: string + then: + - script.execute: + id: set_var_string + component: !lambda return component; + val: !lambda return val; + +esphome: + platformio_options: + build_flags: + - -D NSPANEL_HA_BLUEPRINT_CORE_API + +globals: + - id: api_is_updated + type: bool + restore_value: false + initial_value: 'false' + +script: + - id: api_reset + mode: restart + then: + - lambda: id(api_is_updated) = false; + - wait_until: + condition: + - lambda: return id(api_is_updated); + timeout: 10s + - if: + condition: + - lambda: return not id(api_is_updated); + then: + - logger.log: Resetting API + - delay: 2s + - lambda: api_server->on_shutdown(); + + - id: ha_button + mode: parallel + parameters: + page_id: uint8_t + component: string + command: string + then: + - homeassistant.event: + event: esphome.nspanel_ha_blueprint + data: + device_name: !lambda return device_name->state.c_str(); + esphome_version: ${version} + type: button_click + page: !lambda return page_names[page_id]; + component: !lambda return component.c_str(); + command: !lambda return command.c_str(); + + - id: ha_call_action + mode: parallel + parameters: + action: string + key: string + value: string + entity: string + then: + - homeassistant.event: + event: esphome.nspanel_ha_blueprint + data: + device_name: !lambda return device_name->state.c_str(); + esphome_version: ${version} + type: action_call + action: !lambda return action.c_str(); + key: !lambda return key.c_str(); + value: !lambda return value.c_str(); + entity: !lambda return entity.c_str(); + + - id: set_var_bool + mode: queued + parameters: + component: string + val: bool + then: # There's nothing here so far + + - id: set_var_int + mode: queued + parameters: + component: string + val: float + then: # There's nothing here so far + + - id: set_var_string + mode: queued + parameters: + component: string + val: string + then: # There's nothing here so far + + - id: stop_all + mode: restart + then: + - lambda: |- + api_reset->stop(); + ha_button->stop(); + ha_call_action->stop(); +... diff --git a/esphome/nspanel_esphome_core_base.yaml b/esphome/nspanel_esphome_core_base.yaml index dc900554..4aa82c37 100644 --- a/esphome/nspanel_esphome_core_base.yaml +++ b/esphome/nspanel_esphome_core_base.yaml @@ -18,49 +18,6 @@ substitutions: ############################## BOOT_STEP_BASE: '1UL << 0' -api: - id: !extend api_server - - on_client_connected: - then: - - lambda: |- - boot_log->execute("API", (client_info + " connected (" + client_address + ")").c_str()); - if (client_info.find("Home Assistant ") == 0) - id(api_is_updated) = true; - else - dump_config->execute(); - - actions: - - action: set_bool - variables: - component: string - val: bool - then: - - script.execute: - id: set_var_bool - component: !lambda return component; - val: !lambda return val; - - - action: set_int - variables: - component: string - val: int - then: - - script.execute: - id: set_var_int - component: !lambda return component; - val: !lambda return val; - - - action: set_string - variables: - component: string - val: string - then: - - script.execute: - id: set_var_string - component: !lambda return component; - val: !lambda return val; - button: - id: nspanel_factory_reset # Factory Reset button - Used to clean values from flash name: Factory reset @@ -101,11 +58,6 @@ external_components: refresh: 300s globals: - - id: api_is_updated - type: bool - restore_value: false - initial_value: 'false' - - id: is_safe_mode type: bool restore_value: false @@ -162,22 +114,6 @@ safe_mode: - script.execute: safe_mode_loop script: - - id: api_reset - mode: restart - then: - - lambda: id(api_is_updated) = false; - - wait_until: - condition: - - lambda: return id(api_is_updated); - timeout: 10s - - if: - condition: - - lambda: return not id(api_is_updated); - then: - - logger.log: Resetting API - - delay: 2s - - lambda: api_server->on_shutdown(); - - id: !extend boot_progress_dump then: - lambda: |- @@ -262,42 +198,6 @@ script: # - nspanel_esphome_prebuild.yaml # - wall_display.yaml - - id: ha_button - mode: parallel - parameters: - page: string - component: string - command: string - then: - - homeassistant.event: - event: esphome.nspanel_ha_blueprint - data: - device_name: !lambda return device_name->state.c_str(); - esphome_version: ${version} - type: button_click - page: !lambda return page.c_str(); - component: !lambda return component.c_str(); - command: !lambda return command.c_str(); - - - id: ha_call_action - mode: parallel - parameters: - action: string - key: string - value: string - entity: string - then: - - homeassistant.event: - event: esphome.nspanel_ha_blueprint - data: - device_name: !lambda return device_name->state.c_str(); - esphome_version: ${version} - type: action_call - action: !lambda return action.c_str(); - key: !lambda return key.c_str(); - value: !lambda return value.c_str(); - entity: !lambda return entity.c_str(); - - id: safe_mode_loop mode: restart then: @@ -311,35 +211,11 @@ script: - switch.turn_off: screen_power - delay: 30s - - id: set_var_bool - mode: queued - parameters: - component: string - val: bool - then: # There's nothing here so far - - - id: set_var_int - mode: queued - parameters: - component: string - val: float - then: # There's nothing here so far - - - id: set_var_string - mode: queued - parameters: - component: string - val: string - then: # There's nothing here so far - - id: stop_all mode: restart then: - lambda: |- - api_reset->stop(); dump_config->stop(); - ha_button->stop(); - ha_call_action->stop(); safe_mode_loop->stop(); time_watchdog->stop(); @@ -347,14 +223,7 @@ script: mode: restart then: - lambda: |- - if (!api_server->is_connected() and - current_page_id != ${PAGE_ID_BLANK} and - current_page_id != ${PAGE_ID_BOOT} and - current_page_id != ${PAGE_ID_CONFIRM} and - current_page_id != ${PAGE_ID_HOME} and - current_page_id != ${PAGE_ID_QRCODE} and - current_page_id != ${PAGE_ID_SCREENSAVER} and - current_page_id != ${PAGE_ID_SETTINGS}) { + if (!api_server->is_connected() and !is_page_in_group(NON_API_ID_PAGE_MASK)) { ESP_LOGW("script.time_watchdog", "API disconnected. Falling back to Home page."); goto_page_id->execute(${PAGE_ID_HOME}, false); reset_boot_steps(); diff --git a/esphome/nspanel_esphome_core_boot.yaml b/esphome/nspanel_esphome_core_boot.yaml index 197d2188..71f87879 100644 --- a/esphome/nspanel_esphome_core_boot.yaml +++ b/esphome/nspanel_esphome_core_boot.yaml @@ -10,7 +10,6 @@ substitutions: BOOT_STEP_BOOT: '1UL << 1' api: - id: !extend api_service on_client_connected: then: - script.execute: @@ -45,7 +44,11 @@ esphome: build_flags: - -D NSPANEL_HA_BLUEPRINT_CORE_BOOT on_boot: - - priority: 600.0 + - priority: 1000.1 + then: + - script.execute: boot_initialize + + - priority: 600.1 then: - script.execute: boot_sequence @@ -84,7 +87,7 @@ script: boot_progress_dump_timer->execute(); complete_boot_step(step); ESP_LOGI("script.boot_progress", "Boot step completed: %s (step %i of %i - %i%%)", step_name.c_str(), - get_boot_steps_completed(), TOTAL_BOOT_STEPS, get_boot_progress_percentage()); + get_boot_steps_completed(), total_boot_steps, get_boot_progress_percentage()); if (is_boot_complete()) ESP_LOGI("script.boot_progress", "Progress: Boot sequence completed"); @@ -119,7 +122,6 @@ script: - id: boot_sequence mode: single then: - - script.execute: boot_initialize - lambda: |- if (!disp1->is_setup()) boot_log->execute("Boot", "Waiting for Nextion"); @@ -171,10 +173,6 @@ script: - lambda: |- set_variable_value->execute("brightness_dim", static_cast(display_dim_brightness->state)); set_variable_value->execute("brightness", static_cast(display_brightness->state)); - set_component_value->execute(${PAGE_ID_SETTINGS}, "dimslider", - static_cast(display_dim_brightness->state)); - set_component_value->execute(${PAGE_ID_SETTINGS}, "brightslider", - static_cast(display_brightness->state)); set_brightness->execute(display_brightness->state); boot_progress->execute(${BOOT_STEP_BOOT}, "Boot"); boot_event->execute(); @@ -184,10 +182,10 @@ script: - lambda: |- if (is_boot_complete()) ESP_LOGCONFIG("${project_tag}", "Boot steps: %" PRIu8 "/%" PRIu8 " (100%%)", - get_boot_steps_completed(), TOTAL_BOOT_STEPS); + get_boot_steps_completed(), total_boot_steps); else { ESP_LOGW("${project_tag}", "Boot steps: %" PRIu8 "/%" PRIu8 " (%" PRIu8 "%% - %" PRIu32 ")", - get_boot_steps_completed(), TOTAL_BOOT_STEPS, + get_boot_steps_completed(), total_boot_steps, get_boot_progress_percentage(), completed_boot_steps); ESP_LOGW("${project_tag}", " State: %s", ((wifi_component->is_connected()) and api_server->is_connected()) ? "Pending" : "DISCONNECTED"); diff --git a/esphome/nspanel_esphome_core_hw_buttons.yaml b/esphome/nspanel_esphome_core_hw_buttons.yaml index cbcd18ef..d27c57f9 100644 --- a/esphome/nspanel_esphome_core_hw_buttons.yaml +++ b/esphome/nspanel_esphome_core_hw_buttons.yaml @@ -38,19 +38,14 @@ binary_sensor: then: - lambda: |- ESP_LOGI("binary_sensor.left_button.on_multi_click", "Left button - Long click"); - ha_button->execute(page_names[current_page_id], "hw_bt_left", "long_click"); + ha_button->execute(current_page_id, "hw_bt_left", "long_click"); - timing: &short_click-timing - ON for at most 0.8s invalid_cooldown: ${invalid_cooldown} then: - lambda: |- ESP_LOGI("binary_sensor.left_button.on_multi_click", "Left button - Short click"); - if ( - id(relay1_local) or - (id(relay1_fallback) and (!api_server->is_connected() or !wifi_component->is_connected())) - ) - relay_1->toggle(); - ha_button->execute(page_names[current_page_id], "hw_bt_left", "short_click"); + ha_button->execute(current_page_id, "hw_bt_left", "short_click"); - id: right_button # RIGHT BUTTON BELOW DISPLAY TO TOGGLE RELAY name: Right Button @@ -72,18 +67,13 @@ binary_sensor: then: - lambda: |- ESP_LOGI("binary_sensor.right_button.on_multi_click", "Right button - Long click"); - ha_button->execute(page_names[current_page_id], "hw_bt_right", "long_click"); + ha_button->execute(current_page_id, "hw_bt_right", "long_click"); - timing: *short_click-timing invalid_cooldown: ${invalid_cooldown} then: - lambda: |- ESP_LOGI("binary_sensor.right_button.on_multi_click", "Right button - Short click"); - if ( - id(relay2_local) or - (id(relay2_fallback) and (!api_server->is_connected() or !wifi_component->is_connected())) - ) - relay_2->toggle(); - ha_button->execute(page_names[current_page_id], "hw_bt_right", "short_click"); + ha_button->execute(current_page_id, "hw_bt_right", "short_click"); esphome: platformio_options: diff --git a/esphome/nspanel_esphome_core_hw_display.yaml b/esphome/nspanel_esphome_core_hw_display.yaml index 12479bc0..1909a1f7 100644 --- a/esphome/nspanel_esphome_core_hw_display.yaml +++ b/esphome/nspanel_esphome_core_hw_display.yaml @@ -12,7 +12,6 @@ substitutions: DISPLAY_CHARSET_CJK: '2' api: - id: !extend api_server actions: # Sends custom commands directly to the display for dynamic interactions and updates. - action: command @@ -61,30 +60,8 @@ api: back_page: string # Specifies the page to return to. Accepts "home" or "buttonpage01" to "buttonpage04". then: - lambda: |- - if (not entity_id.empty() and not back_page.empty()) { - size_t dotPos = entity_id.find("."); - std::string domain; // The domain part of the entity, like "light" or "switch". - std::string id; - if (dotPos != std::string::npos) { - // Extract domain and id from the entity_id string - domain = entity_id.substr(0, dotPos); - id = entity_id.substr(dotPos + 1); - } else { - // No dot found, the entire entity_id is considered as id. - domain = "invalid"; - id = entity_id; - } - if (entity_id == "embedded_climate" or domain != "invalid") { - detailed_entity->publish_state(entity_id.c_str()); - std::string new_page = (entity_id == "embedded_climate" ? "climate" : - (domain == "alarm_control_panel" ? "alarm" : domain)); - goto_page_id->execute(get_page_id(new_page.c_str()), true); - set_variable_value->execute("back_page_id", get_page_id(back_page.c_str())); - if (new_page == "climate") - set_component_value->execute(${PAGE_ID_CLIMATE}, "embedded", - entity_id == "embedded_climate" ? 1 : 0); - } - } + if (not entity_id.empty() and not back_page.empty()) + entity_details_show_action->execute(entity_id.c_str(), get_page_id(back_page.c_str())); binary_sensor: ## Delays initial info from HA to the display ##### @@ -113,11 +90,11 @@ display: on_setup: then: - lambda: |- - page_changed->execute(${PAGE_ID_BOOT}); // Set the current baud rate into the display disp1->send_command_printf("bauds=%" PRIu32, tf_uart->get_baud_rate()); # Extended by: # - nspanel_esphome_core_boot.yaml + # - nspanel_esphome_core_page_boot.yaml on_touch: then: @@ -302,7 +279,8 @@ script: - id: !extend boot_initialize then: - - lambda: setup_components(); + - lambda: |- + setup_components(); - id: display_component_action mode: parallel @@ -601,6 +579,33 @@ script: else ESP_LOGCONFIG(TAG, " TFT: %s", id(version_tft).c_str()); + - id: entity_details_show_action + mode: restart + parameters: + entity_id: string # The ID of the entity for which details are shown ("embedded_climate" for built-in climate). + back_page_id: uint8_t # Specifies the page to return to. Accepts "home" or "buttonpage01" to "buttonpage04". + then: + - lambda: |- + size_t dotPos = entity_id.find("."); + std::string domain; // The domain part of the entity, like "light" or "switch". + std::string id; + if (dotPos != std::string::npos) { + // Extract domain and id from the entity_id string + domain = entity_id.substr(0, dotPos); + id = entity_id.substr(dotPos + 1); + } else { + // No dot found, the entire entity_id is considered as id. + domain = "invalid"; + id = entity_id; + } + if (entity_id == "embedded_climate" or domain != "invalid") { + detailed_entity->publish_state(entity_id.c_str()); + std::string new_page = (entity_id == "embedded_climate" ? "climate" : + (domain == "alarm_control_panel" ? "alarm" : domain)); + goto_page_id->execute(get_page_id(new_page.c_str()), true); + set_variable_value->execute("back_page_id", back_page_id); + } + - id: event_from_display mode: parallel parameters: @@ -661,7 +666,9 @@ script: page_id: uint8_t reset_timers: bool then: - - lambda: disp1->goto_page(page_id); + - lambda: |- + next_page_id = page_id; + disp1->goto_page(page_id); # Extended by: # - nspanel_esphome_core_hw_display_timers.yaml @@ -678,6 +685,7 @@ script: previous_page_id = current_page_id; current_page_id = new_page_id; current_page->publish_state(page_names[current_page_id]); + next_page_id = UINT8_MAX; } if (is_new_page or new_page_id == ${PAGE_ID_BOOT}) { // Report new page to logs @@ -889,6 +897,7 @@ script: display_component_send_text->stop(); display_component_send_visibility->stop(); display_wrapped_text->stop(); + entity_details_show_action->stop(); event_from_display->stop(); goto_page_id->stop(); page_changed->stop(); diff --git a/esphome/nspanel_esphome_core_hw_display_timers.yaml b/esphome/nspanel_esphome_core_hw_display_timers.yaml index 3a03af70..f7327874 100644 --- a/esphome/nspanel_esphome_core_hw_display_timers.yaml +++ b/esphome/nspanel_esphome_core_hw_display_timers.yaml @@ -7,7 +7,6 @@ --- api: - id: !extend api_server actions: # Wake Up action - action: wake_up @@ -161,21 +160,11 @@ script: - if: condition: - lambda: |- - return (timeout_page->state >= 1 and - current_page_id != ${PAGE_ID_BOOT} and - current_page_id != ${PAGE_ID_CONFIRM} and - current_page_id != ${PAGE_ID_HOME} and - current_page_id != ${PAGE_ID_NOTIFICATION} and - current_page_id != ${PAGE_ID_SCREENSAVER}); + return (timeout_page->state >= 1 and not is_page_in_group(NON_API_ID_PAGE_MASK)); then: - delay: !lambda return (timeout_page->state *1000); - lambda: |- - if (timeout_page->state >= 1 and - current_page_id != ${PAGE_ID_BOOT} and - current_page_id != ${PAGE_ID_CONFIRM} and - current_page_id != ${PAGE_ID_HOME} and - current_page_id != ${PAGE_ID_NOTIFICATION} and - current_page_id != ${PAGE_ID_SCREENSAVER}) { + if (timeout_page->state >= 1 and not is_page_in_group(NON_API_ID_PAGE_MASK)) { ESP_LOGI("script.timer_page", "Fallback to page Home"); goto_page_id->execute(${PAGE_ID_HOME}, false); } diff --git a/esphome/nspanel_esphome_core_hw_wifi.yaml b/esphome/nspanel_esphome_core_hw_wifi.yaml index 3f535027..e8a90b88 100644 --- a/esphome/nspanel_esphome_core_hw_wifi.yaml +++ b/esphome/nspanel_esphome_core_hw_wifi.yaml @@ -20,7 +20,6 @@ substitutions: MDI_ICON_WIFI_OFF: "\uE5A9" # mdi:wifi-off api: - id: !extend api_server on_client_connected: then: - script.execute: refresh_wifi_icon diff --git a/esphome/nspanel_esphome_core_page_boot.yaml b/esphome/nspanel_esphome_core_page_boot.yaml index 5aefcfe2..93e84369 100644 --- a/esphome/nspanel_esphome_core_page_boot.yaml +++ b/esphome/nspanel_esphome_core_page_boot.yaml @@ -10,6 +10,13 @@ substitutions: BOOT_STEP_PAGE_BOOT: '1UL << 29' PAGE_ID_BOOT: '0' +display: + - id: !extend disp1 + on_setup: + then: + - lambda: |- + page_changed->execute(${PAGE_ID_BOOT}); + esphome: platformio_options: build_flags: diff --git a/esphome/nspanel_esphome_core_page_home.yaml b/esphome/nspanel_esphome_core_page_home.yaml index 119f4938..4d9a941b 100644 --- a/esphome/nspanel_esphome_core_page_home.yaml +++ b/esphome/nspanel_esphome_core_page_home.yaml @@ -56,7 +56,6 @@ script: id(home_time)->global = true; id(home_meridiem) = get_component(${PAGE_ID_HOME}, "meridiem"); id(home_meridiem)->global = false; - refresh_datetime->execute(); - id: !extend boot_progress_dump then: diff --git a/esphome/nspanel_esphome_standard.yaml b/esphome/nspanel_esphome_standard.yaml new file mode 100644 index 00000000..29bd09d9 --- /dev/null +++ b/esphome/nspanel_esphome_standard.yaml @@ -0,0 +1,36 @@ +##################################################################################################### +##### NSPANEL ESPHOME created by Blackymas - https://github.com/Blackymas/NSPanel_HA_Blueprint ##### +##### ESPHOME STANDARD ##### +##### PLEASE only make changes if it is necessary and also the required knowledge is available. ##### +##### For normal use with the Blueprint, no changes are necessary. ##### +##################################################################################################### +--- +esphome: + platformio_options: + build_flags: + - -D NSPANEL_HA_BLUEPRINT_STANDARD + +packages: + # yamllint disable rule:colons + ## Standard packages + hw_buzzer: !include nspanel_esphome_standard_hw_buzzer.yaml + hw_relays: !include nspanel_esphome_standard_hw_relays.yaml + hw_temperature: !include nspanel_esphome_standard_hw_temperature.yaml + page_alarm: !include nspanel_esphome_standard_page_alarm.yaml + page_blank: !include nspanel_esphome_standard_page_blank.yaml + page_buttons: !include nspanel_esphome_standard_page_buttons.yaml + page_climate: !include nspanel_esphome_standard_page_climate.yaml + page_cover: !include nspanel_esphome_standard_page_cover.yaml + page_entities: !include nspanel_esphome_standard_page_entities.yaml + page_fan: !include nspanel_esphome_standard_page_fan.yaml + page_keyb_num: !include nspanel_esphome_standard_page_keyb_num.yaml + page_light: !include nspanel_esphome_standard_page_light.yaml + page_media_player: !include nspanel_esphome_standard_page_media_player.yaml + page_notification: !include nspanel_esphome_standard_page_notification.yaml + page_qrcode: !include nspanel_esphome_standard_page_qrcode.yaml + page_settings: !include nspanel_esphome_standard_page_settings.yaml + page_utilities: !include nspanel_esphome_standard_page_utilities.yaml + page_weather: !include nspanel_esphome_standard_page_weather.yaml + upload_tft: !include nspanel_esphome_standard_upload_tft.yaml + # yamllint enable rule:colons +... diff --git a/esphome/nspanel_esphome_core_hw_buzzer.yaml b/esphome/nspanel_esphome_standard_hw_buzzer.yaml similarity index 98% rename from esphome/nspanel_esphome_core_hw_buzzer.yaml rename to esphome/nspanel_esphome_standard_hw_buzzer.yaml index 23303ac7..7a8734c5 100644 --- a/esphome/nspanel_esphome_core_hw_buzzer.yaml +++ b/esphome/nspanel_esphome_standard_hw_buzzer.yaml @@ -14,7 +14,6 @@ substitutions: tone_volume_change: "scale_up:d=32,o=5,b=100:c,c#,d#,e,f#,g#,a#,b" # Use to "none" for no sound api: - id: !extend api_server actions: - action: rtttl_play variables: @@ -41,7 +40,7 @@ display: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_HW_BUZZER + - -D NSPANEL_HA_BLUEPRINT_STANDARD_HW_BUZZER number: - id: buzzer_gain diff --git a/esphome/nspanel_esphome_core_hw_relays.yaml b/esphome/nspanel_esphome_standard_hw_relays.yaml similarity index 90% rename from esphome/nspanel_esphome_core_hw_relays.yaml rename to esphome/nspanel_esphome_standard_hw_relays.yaml index 86d1c99e..c7e77941 100644 --- a/esphome/nspanel_esphome_core_hw_relays.yaml +++ b/esphome/nspanel_esphome_standard_hw_relays.yaml @@ -12,7 +12,7 @@ substitutions: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_HW_RELAYS + - -D NSPANEL_HA_BLUEPRINT_STANDARD_HW_RELAYS globals: - id: relay1_local @@ -93,6 +93,18 @@ script: } } + - id: !extend ha_button + then: + - lambda: |- + if (component == "hw_bt_left" and command == "short_click" and + (id(relay1_local) or + (id(relay1_fallback) and (!api_server->is_connected() or !wifi_component->is_connected())))) + relay_1->toggle(); + else if (component == "hw_bt_right" and command == "short_click" and + (id(relay2_local) or + (id(relay2_fallback) and (!api_server->is_connected() or !wifi_component->is_connected())))) + relay_2->toggle(); + - id: !extend page_home then: - script.execute: refresh_relays diff --git a/esphome/nspanel_esphome_core_hw_temperature.yaml b/esphome/nspanel_esphome_standard_hw_temperature.yaml similarity index 96% rename from esphome/nspanel_esphome_core_hw_temperature.yaml rename to esphome/nspanel_esphome_standard_hw_temperature.yaml index 567cbe88..e2cf80c2 100644 --- a/esphome/nspanel_esphome_core_hw_temperature.yaml +++ b/esphome/nspanel_esphome_standard_hw_temperature.yaml @@ -20,7 +20,7 @@ substitutions: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_HW_TEMPERATURE + - -D NSPANEL_HA_BLUEPRINT_STANDARD_HW_TEMPERATURE globals: ##### Is embedded sensor used for indoor temperature? ##### @@ -65,10 +65,8 @@ script: then: - lambda: |- std::string temp_units = "${temp_units}"; - id(temperature_is_celsius) = not (temp_units == "°F" || - temp_units == "F" || - temp_units == "°f" || - temp_units == "f"); + id(temperature_is_celsius) = not (temp_units == "°F" || temp_units == "F" || + temp_units == "°f" || temp_units == "f"); - id: !extend boot_progress_dump then: diff --git a/esphome/nspanel_esphome_core_page_alarm.yaml b/esphome/nspanel_esphome_standard_page_alarm.yaml similarity index 99% rename from esphome/nspanel_esphome_core_page_alarm.yaml rename to esphome/nspanel_esphome_standard_page_alarm.yaml index 1ce7339a..4336d944 100644 --- a/esphome/nspanel_esphome_core_page_alarm.yaml +++ b/esphome/nspanel_esphome_standard_page_alarm.yaml @@ -14,7 +14,6 @@ substitutions: PAGE_ID_ALARM: '23' api: - id: !extend api_server actions: # Updates the alarm settings page with current state and configuration, integrating with the panel's interface. - action: page_alarm @@ -50,7 +49,7 @@ api: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_PAGE_ALARM + - -D NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_ALARM script: - id: alarm_button_renderer diff --git a/esphome/nspanel_esphome_core_page_blank.yaml b/esphome/nspanel_esphome_standard_page_blank.yaml similarity index 97% rename from esphome/nspanel_esphome_core_page_blank.yaml rename to esphome/nspanel_esphome_standard_page_blank.yaml index 3a52571f..2697d8af 100644 --- a/esphome/nspanel_esphome_core_page_blank.yaml +++ b/esphome/nspanel_esphome_standard_page_blank.yaml @@ -13,7 +13,7 @@ substitutions: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_PAGE_BLANK + - -D NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_BLANK script: - id: !extend boot_progress_dump diff --git a/esphome/nspanel_esphome_core_page_buttons.yaml b/esphome/nspanel_esphome_standard_page_buttons.yaml similarity index 99% rename from esphome/nspanel_esphome_core_page_buttons.yaml rename to esphome/nspanel_esphome_standard_page_buttons.yaml index 7e7a3890..16831d82 100644 --- a/esphome/nspanel_esphome_core_page_buttons.yaml +++ b/esphome/nspanel_esphome_standard_page_buttons.yaml @@ -18,7 +18,6 @@ substitutions: BUTTON_LONG_PRESS_DELAY: 800ms api: - id: !extend api_server actions: # Dynamically configures button properties on a specified page, # enhancing UI interactivity by allowing updates to button appearance and behavior based on given parameters. @@ -90,7 +89,7 @@ display: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_PAGE_BUTTONS + - -D NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_BUTTONS script: - id: !extend boot_initialize diff --git a/esphome/nspanel_esphome_core_page_climate.yaml b/esphome/nspanel_esphome_standard_page_climate.yaml similarity index 97% rename from esphome/nspanel_esphome_core_page_climate.yaml rename to esphome/nspanel_esphome_standard_page_climate.yaml index 6ef76fb5..1beddb68 100644 --- a/esphome/nspanel_esphome_core_page_climate.yaml +++ b/esphome/nspanel_esphome_standard_page_climate.yaml @@ -14,7 +14,6 @@ substitutions: PAGE_ID_CLIMATE: '7' api: - id: !extend api_server actions: # Dynamically updates the climate page with the latest climate control settings and status. - action: page_climate @@ -73,7 +72,7 @@ display: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_PAGE_CLIMATE + - -D NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_CLIMATE globals: - id: is_climate @@ -110,6 +109,12 @@ script: detailed_entity->state.c_str()); } + - id: !extend entity_details_show_action # Defined by nspanel_esphome_core_hw_display.yaml + then: + - lambda: |- + if (next_page_id == ${PAGE_ID_CLIMATE}) + set_component_value->execute(${PAGE_ID_CLIMATE}, "embedded", entity_id == "embedded_climate" ? 1 : 0); + - id: !extend event_from_display # Defined by nspanel_esphome_core_hw_display.yaml then: - if: @@ -258,5 +263,4 @@ script: - lambda: |- if (component == "is_climate") id(is_climate) = val; - ... diff --git a/esphome/nspanel_esphome_core_page_cover.yaml b/esphome/nspanel_esphome_standard_page_cover.yaml similarity index 96% rename from esphome/nspanel_esphome_core_page_cover.yaml rename to esphome/nspanel_esphome_standard_page_cover.yaml index c00eb760..bca82e60 100644 --- a/esphome/nspanel_esphome_core_page_cover.yaml +++ b/esphome/nspanel_esphome_standard_page_cover.yaml @@ -13,7 +13,7 @@ substitutions: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_PAGE_COVER + - -D NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_COVER script: - id: !extend boot_progress_dump diff --git a/esphome/nspanel_esphome_core_page_entities.yaml b/esphome/nspanel_esphome_standard_page_entities.yaml similarity index 98% rename from esphome/nspanel_esphome_core_page_entities.yaml rename to esphome/nspanel_esphome_standard_page_entities.yaml index 0d6d837d..ed2d8ddc 100644 --- a/esphome/nspanel_esphome_core_page_entities.yaml +++ b/esphome/nspanel_esphome_standard_page_entities.yaml @@ -17,7 +17,7 @@ substitutions: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_PAGE_ENTITIES + - -D NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_ENTITIES globals: - id: page_entity_value_horizontal_alignment diff --git a/esphome/nspanel_esphome_core_page_fan.yaml b/esphome/nspanel_esphome_standard_page_fan.yaml similarity index 97% rename from esphome/nspanel_esphome_core_page_fan.yaml rename to esphome/nspanel_esphome_standard_page_fan.yaml index e2abd220..f41e9499 100644 --- a/esphome/nspanel_esphome_core_page_fan.yaml +++ b/esphome/nspanel_esphome_standard_page_fan.yaml @@ -33,7 +33,7 @@ display: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_PAGE_FAN + - -D NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_FAN script: - id: !extend boot_progress_dump diff --git a/esphome/nspanel_esphome_core_page_keyb_num.yaml b/esphome/nspanel_esphome_standard_page_keyb_num.yaml similarity index 97% rename from esphome/nspanel_esphome_core_page_keyb_num.yaml rename to esphome/nspanel_esphome_standard_page_keyb_num.yaml index f86e9977..c03537f8 100644 --- a/esphome/nspanel_esphome_core_page_keyb_num.yaml +++ b/esphome/nspanel_esphome_standard_page_keyb_num.yaml @@ -13,7 +13,7 @@ substitutions: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_PAGE_KEYB_NUM + - -D NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_KEYB_NUM script: - id: !extend boot_progress_dump diff --git a/esphome/nspanel_esphome_core_page_light.yaml b/esphome/nspanel_esphome_standard_page_light.yaml similarity index 98% rename from esphome/nspanel_esphome_core_page_light.yaml rename to esphome/nspanel_esphome_standard_page_light.yaml index 7d283639..25bcadb0 100644 --- a/esphome/nspanel_esphome_core_page_light.yaml +++ b/esphome/nspanel_esphome_standard_page_light.yaml @@ -27,7 +27,7 @@ display: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_PAGE_LIGHT + - -D NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_LIGHT script: - id: !extend boot_progress_dump diff --git a/esphome/nspanel_esphome_core_page_media_player.yaml b/esphome/nspanel_esphome_standard_page_media_player.yaml similarity index 99% rename from esphome/nspanel_esphome_core_page_media_player.yaml rename to esphome/nspanel_esphome_standard_page_media_player.yaml index 12d20fc9..87fec80c 100644 --- a/esphome/nspanel_esphome_core_page_media_player.yaml +++ b/esphome/nspanel_esphome_standard_page_media_player.yaml @@ -39,7 +39,6 @@ substitutions: MDI_ICON_VOLUME_LOW: "\uE57E" # mdi:volume-low api: - id: !extend api_server actions: # Dynamically updates the media player page with current state and media information. - action: page_media_player @@ -178,7 +177,7 @@ display: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_PAGE_MEDIA_PLAYER + - -D NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_MEDIA_PLAYER globals: - id: media_player_last_volume_level # Last volume level from Home Assistant diff --git a/esphome/nspanel_esphome_core_page_notification.yaml b/esphome/nspanel_esphome_standard_page_notification.yaml similarity index 96% rename from esphome/nspanel_esphome_core_page_notification.yaml rename to esphome/nspanel_esphome_standard_page_notification.yaml index d7212ee1..20248a33 100644 --- a/esphome/nspanel_esphome_core_page_notification.yaml +++ b/esphome/nspanel_esphome_standard_page_notification.yaml @@ -12,7 +12,6 @@ substitutions: tone_notification: "two short:d=4,o=5,b=100:16e6,16e6" api: - id: !extend api_server actions: # This action removes any displayed notifications from the screen, # helping to keep the user interface clean and focused on its primary functions. @@ -56,7 +55,7 @@ display: if (page_id == ${PAGE_ID_NOTIFICATION}) { // Page Notification switch (component_id) { case 7: // bt_accept - ha_button->execute("notification", "bt_accept", touch_event ? "press" : "released"); + ha_button->execute(${PAGE_ID_NOTIFICATION}, "bt_accept", touch_event ? "press" : "released"); if (!touch_event) { // Release notification_label->publish_state(""); notification_text->publish_state(""); @@ -66,7 +65,7 @@ display: } break; case 8: // bt_clear - ha_button->execute("notification", "bt_clear", touch_event ? "press" : "released"); + ha_button->execute(${PAGE_ID_NOTIFICATION}, "bt_clear", touch_event ? "press" : "released"); if (!touch_event) { // Release notification_unread->publish_state(false); goto_page_id->execute(${PAGE_ID_HOME}, false); @@ -78,7 +77,7 @@ display: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_PAGE_NOTIFICATION + - -D NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_NOTIFICATION on_boot: - priority: 600.21 then: diff --git a/esphome/nspanel_esphome_core_page_qrcode.yaml b/esphome/nspanel_esphome_standard_page_qrcode.yaml similarity index 96% rename from esphome/nspanel_esphome_core_page_qrcode.yaml rename to esphome/nspanel_esphome_standard_page_qrcode.yaml index 7b2f923b..5f3aef94 100644 --- a/esphome/nspanel_esphome_core_page_qrcode.yaml +++ b/esphome/nspanel_esphome_standard_page_qrcode.yaml @@ -11,7 +11,6 @@ substitutions: PAGE_ID_QRCODE: '17' api: - id: !extend api_server actions: # Dynamically displays QR codes on the ESPHome UI for sharing information such as WiFi passwords or website links. - action: qrcode @@ -29,7 +28,7 @@ api: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_PAGE_QRCODE + - -D NSPANEL_HA_BLUEPRINT_STANDARD_QRCODE script: - id: !extend boot_progress_dump diff --git a/esphome/nspanel_esphome_core_page_settings.yaml b/esphome/nspanel_esphome_standard_page_settings.yaml similarity index 85% rename from esphome/nspanel_esphome_core_page_settings.yaml rename to esphome/nspanel_esphome_standard_page_settings.yaml index a0e0c878..6a98497f 100644 --- a/esphome/nspanel_esphome_core_page_settings.yaml +++ b/esphome/nspanel_esphome_standard_page_settings.yaml @@ -29,7 +29,7 @@ display: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_PAGE_SETTINGS + - -D NSPANEL_HA_BLUEPRINT_STANDARD_SETTINGS number: - id: !extend display_brightness @@ -54,6 +54,14 @@ script: - lambda: |- boot_progress_dump_item->execute(${BOOT_STEP_PAGE_SETTINGS}, "Page Settings"); + - id: !extend boot_sequence + then: + - lambda: |- + set_component_value->execute(${PAGE_ID_SETTINGS}, "dimslider", + static_cast(display_dim_brightness->state)); + set_component_value->execute(${PAGE_ID_SETTINGS}, "brightslider", + static_cast(display_brightness->state)); + - id: !extend set_var_bool then: - lambda: |- diff --git a/esphome/nspanel_esphome_core_page_utilities.yaml b/esphome/nspanel_esphome_standard_page_utilities.yaml similarity index 97% rename from esphome/nspanel_esphome_core_page_utilities.yaml rename to esphome/nspanel_esphome_standard_page_utilities.yaml index fffef36a..bd15d914 100644 --- a/esphome/nspanel_esphome_core_page_utilities.yaml +++ b/esphome/nspanel_esphome_standard_page_utilities.yaml @@ -14,7 +14,6 @@ substitutions: PAGE_ID_UTILITIES: '27' api: - id: !extend api_server actions: # Utilities group refresh - action: utilities_group_refresh @@ -57,7 +56,7 @@ api: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_PAGE_UTILITIES + - -D NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_UTILITIES script: - id: !extend boot_progress_dump diff --git a/esphome/nspanel_esphome_core_page_weather.yaml b/esphome/nspanel_esphome_standard_page_weather.yaml similarity index 97% rename from esphome/nspanel_esphome_core_page_weather.yaml rename to esphome/nspanel_esphome_standard_page_weather.yaml index af92220d..d9137cef 100644 --- a/esphome/nspanel_esphome_core_page_weather.yaml +++ b/esphome/nspanel_esphome_standard_page_weather.yaml @@ -35,7 +35,7 @@ display: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_CORE_PAGE_WEATHER + - -D NSPANEL_HA_BLUEPRINT_STANDARD_PAGE_WEATHER globals: - id: weather_pages_show diff --git a/esphome/nspanel_esphome_addon_upload_tft.yaml b/esphome/nspanel_esphome_standard_upload_tft.yaml similarity index 99% rename from esphome/nspanel_esphome_addon_upload_tft.yaml rename to esphome/nspanel_esphome_standard_upload_tft.yaml index 02335ff1..84112604 100644 --- a/esphome/nspanel_esphome_addon_upload_tft.yaml +++ b/esphome/nspanel_esphome_standard_upload_tft.yaml @@ -12,6 +12,7 @@ substitutions: # Just in case user forgets to set something # nextion_update_base_url: "https://raw.githubusercontent.com/Blackymas/NSPanel_HA_Blueprint/" ############################################## + BOOT_STEP_UPLOAD_TFT: '1UL << ' # yamllint disable rule:comments-indentation api: @@ -77,7 +78,7 @@ display: esphome: platformio_options: build_flags: - - -D NSPANEL_HA_BLUEPRINT_ADDON_UPLOAD_TFT + - -D NSPANEL_HA_BLUEPRINT_STANDARD_UPLOAD_TFT globals: - id: tft_upload_attempt diff --git a/nspanel_blueprint.yaml b/nspanel_blueprint.yaml index eb667474..52b98824 100644 --- a/nspanel_blueprint.yaml +++ b/nspanel_blueprint.yaml @@ -8420,35 +8420,37 @@ actions: else 0 }} # Boot Step Constants - BOOT_STEP_BASE: 1 # 1 << 0 - BOOT_STEP_BOOT: 2 # 1 << 1 - BOOT_STEP_DATETIME: 4 # 1 << 2 - BOOT_STEP_HW_BUTTONS: 8 # 1 << 3 - BOOT_STEP_HW_BUZZER: 16 # 1 << 4 - BOOT_STEP_HW_DISPLAY: 32 # 1 << 5 - BOOT_STEP_HW_MEMORY: 64 # 1 << 6 - BOOT_STEP_HW_RELAYS: 128 # 1 << 7 - BOOT_STEP_HW_TEMPERATURE: 256 # 1 << 8 - BOOT_STEP_HW_WIFI: 512 # 1 << 9 - BOOT_STEP_PAGE_ALARM: 1024 # 1 << 10 - BOOT_STEP_PAGE_BUTTONS: 2048 # 1 << 11 - BOOT_STEP_PAGE_CLIMATE: 4096 # 1 << 12 - BOOT_STEP_PAGE_CONFIRM: 8192 # 1 << 13 - BOOT_STEP_PAGE_COVER: 16384 # 1 << 14 - BOOT_STEP_PAGE_ENTITIES: 32768 # 1 << 15 - BOOT_STEP_PAGE_FAN: 65536 # 1 << 16 - BOOT_STEP_PAGE_HOME: 131072 # 1 << 17 - BOOT_STEP_PAGE_KEYBOARD_NUM: 262144 # 1 << 18 - BOOT_STEP_PAGE_LIGHT: 524288 # 1 << 19 - BOOT_STEP_PAGE_MEDIA_PLAYER: 1048576 # 1 << 20 - BOOT_STEP_PAGE_NOTIFICATION: 2097152 # 1 << 21 - BOOT_STEP_PAGE_QRCODE: 4194304 # 1 << 22 - BOOT_STEP_PAGE_SCREENSAVER: 8388608 # 1 << 23 - BOOT_STEP_PAGE_UTILITIES: 16777216 # 1 << 24 - BOOT_STEP_PAGE_WEATHER: 33554432 # 1 << 25 - BOOT_STEP_VERSION: 67108864 # 1 << 26 - BOOT_STEP_PAGE_BLANK: 134217728 # 1 << 27 - BOOT_STEP_PAGE_SETTINGS: 268435456 # 1 << 28 + BOOT_STEP_BASE: 1 # 1 << 0 + BOOT_STEP_BOOT: 2 # 1 << 1 + BOOT_STEP_DATETIME: 4 # 1 << 2 + BOOT_STEP_HW_BUTTONS: 8 # 1 << 3 + BOOT_STEP_HW_BUZZER: 16 # 1 << 4 + BOOT_STEP_HW_DISPLAY: 32 # 1 << 5 + BOOT_STEP_HW_MEMORY: 64 # 1 << 6 + BOOT_STEP_HW_RELAYS: 128 # 1 << 7 + BOOT_STEP_HW_TEMPERATURE: 256 # 1 << 8 + BOOT_STEP_HW_WIFI: 512 # 1 << 9 + BOOT_STEP_PAGE_ALARM: 1024 # 1 << 10 + BOOT_STEP_PAGE_BUTTONS: 2048 # 1 << 11 + BOOT_STEP_PAGE_CLIMATE: 4096 # 1 << 12 + BOOT_STEP_PAGE_CONFIRM: 8192 # 1 << 13 + BOOT_STEP_PAGE_COVER: 16384 # 1 << 14 + BOOT_STEP_PAGE_ENTITIES: 32768 # 1 << 15 + BOOT_STEP_PAGE_FAN: 65536 # 1 << 16 + BOOT_STEP_PAGE_HOME: 131072 # 1 << 17 + BOOT_STEP_PAGE_KEYBOARD_NUM: 262144 # 1 << 18 + BOOT_STEP_PAGE_LIGHT: 524288 # 1 << 19 + BOOT_STEP_PAGE_MEDIA_PLAYER: 1048576 # 1 << 20 + BOOT_STEP_PAGE_NOTIFICATION: 2097152 # 1 << 21 + BOOT_STEP_PAGE_QRCODE: 4194304 # 1 << 22 + BOOT_STEP_PAGE_SCREENSAVER: 8388608 # 1 << 23 + BOOT_STEP_PAGE_UTILITIES: 16777216 # 1 << 24 + BOOT_STEP_PAGE_WEATHER: 33554432 # 1 << 25 + BOOT_STEP_VERSION: 67108864 # 1 << 26 + BOOT_STEP_PAGE_BLANK: 134217728 # 1 << 27 + BOOT_STEP_PAGE_SETTINGS: 268435456 # 1 << 28 + BOOT_STEP_UPLOAD_TFT: 536870912 # 1 << 29 + BOOT_STEP_API: 1073741824 # 1 << 30 - alias: BOOT_STEP_VERSION if: '{{ completed_boot_steps | bitwise_and(BOOT_STEP_VERSION) == 0 }}' @@ -10229,6 +10231,34 @@ actions: val: true continue_on_error: true + - alias: BOOT_STEP_UPLOAD_TFT + if: '{{ completed_boot_steps | bitwise_and(BOOT_STEP_UPLOAD_TFT) == 0 }}' + then: # There's nothing here so far + - *boot_delay + - alias: Set BOOT_STEP_UPLOAD_TFT + sequence: + - *delay_default + - alias: set_bool.BOOT_STEP_UPLOAD_TFT + action: 'esphome.{{ nspanel_name }}_set_bool' + data: + component: BOOT_STEP_UPLOAD_TFT + val: true + continue_on_error: true + + - alias: BOOT_STEP_API + if: '{{ completed_boot_steps | bitwise_and(BOOT_STEP_API) == 0 }}' + then: # There's nothing here so far + - *boot_delay + - alias: Set BOOT_STEP_API + sequence: + - *delay_default + - alias: set_bool.BOOT_STEP_API + action: 'esphome.{{ nspanel_name }}_set_bool' + data: + component: BOOT_STEP_API + val: true + continue_on_error: true + - &ADD_ON sequence: - &ADD_ON_CLIMATE diff --git a/nspanel_esphome.yaml b/nspanel_esphome.yaml index 44f9a7bf..be89d652 100644 --- a/nspanel_esphome.yaml +++ b/nspanel_esphome.yaml @@ -1,5 +1,7 @@ --- packages: - core_package: !include esphome/nspanel_esphome_core.yaml - upload_tft_package: !include esphome/nspanel_esphome_addon_upload_tft.yaml + # yamllint disable rule:colons + core: !include esphome/nspanel_esphome_core.yaml + standard: !include esphome/nspanel_esphome_standard.yaml + # yamllint enable rule:colons ...