Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions components/nspanel_easy/page_screensaver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// page_screensaver.cpp

#ifdef NSPANEL_EASY_PAGE_SCREENSAVER

#include "page_screensaver.h"

/**
* @file page_screensaver.cpp
* @brief Definitions for the Screensaver page.
*
* Provides the out-of-line definitions for variables declared in
* page_screensaver.h.
*/

namespace esphome {
namespace nspanel_easy {} // namespace nspanel_easy
} // namespace esphome

#endif // NSPANEL_EASY_PAGE_SCREENSAVER
57 changes: 57 additions & 0 deletions components/nspanel_easy/page_screensaver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// page_screensaver.h

#pragma once

#ifdef NSPANEL_EASY_PAGE_SCREENSAVER

#include "nextion_components.h" // For HMIComponent
#include "pages.h" // For page_names and get_page_id

/**
* @file page_screensaver.h
* @brief Nextion component definitions for the Screensaver page.
*
* This file contains all component constants specific to the Screensaver page
* of the NSPanel interface, along with the persistent visibility flag used to
* avoid redundant display updates.
*/

namespace esphome {
namespace nspanel_easy {

namespace hmi {
namespace screensaver {

/**
* @namespace screensaver
* @brief Components for the Screensaver page.
*
* Component ID mapping for the Screensaver page (index 9 in page_names array).
* Based on the Nextion HMI design file.
* Note: All components are local scope, so names do not include a page prefix.
*/

// Page definition
constexpr HMIComponent PAGE = {"screensaver", get_page_id("screensaver")};

// Display components
constexpr HMIComponent TEXT = {"text", 4}; ///< Time/clock label (word-wrap enabled, 1000 chars max)

// Touch capture components
constexpr HMIComponent WAKEUP = {"wakeup", 1}; ///< Full-screen wake-up touch area
constexpr HMIComponent SWIPE = {"swipe", 2}; ///< Swipe gesture capture area

// Timers (for reference — not visual, excluded from ALL[])
constexpr HMIComponent TIMER_SWIPESTORE = {"swipestore", 3}; ///< Swipe coordinate sampling timer (50 ms)

// All visual components for iteration (timers and touch caps excluded)
constexpr HMIComponent ALL[] = {PAGE, TEXT};

constexpr size_t COMPONENT_COUNT = sizeof(ALL) / sizeof(ALL[0]);

} // namespace screensaver
} // namespace hmi
} // namespace nspanel_easy
} // namespace esphome

#endif // NSPANEL_EASY_PAGE_SCREENSAVER
4 changes: 2 additions & 2 deletions esphome/nspanel_esphome_base.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,13 @@ script:
watchdog_round->stop();
return;
}
ESP_LOGD("${TAG_BASE}", "The watchdog is starting a round");
ESP_LOGV("${TAG_BASE}", "The watchdog is starting a round");
watchdog_round_wait_to_end->execute();

- id: watchdog_round_wait_to_end
mode: single
then:
- script.wait: watchdog_round
- lambda: |-
ESP_LOGD("${TAG_BASE}", "The watchdog completed the round");
ESP_LOGV("${TAG_BASE}", "The watchdog completed the round");
...
31 changes: 27 additions & 4 deletions esphome/nspanel_esphome_datetime.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,15 @@ script:
mode: restart
then:
- lambda: |-
if (system_flags.tft_upload_active) // Do not refresh if uploading TFT
return;
if (system_flags.tft_upload_active) return; // Do not refresh if uploading TFT

// Time
ESPTime now = id(time_provider).now();
if (!now.is_valid()) {
ESP_LOGW("${TAG_DATETIME}", "refresh_datetime: time provider not yet synchronized");
return;
}

std::string time_format_str = id(mui_time_format);

// Resolve %-H (no-padding 24h hour)
Expand Down Expand Up @@ -101,7 +105,7 @@ script:
disp1->set_component_text("home.time", now.strftime(time_format_str).c_str());

// Date
render_date->execute("home.date", 0);
render_date->execute("home.date", static_cast<uint32_t>(now.timestamp));

- id: render_date
mode: restart
Expand Down Expand Up @@ -151,6 +155,17 @@ script:
if (timestamp > 0)
dt = ESPTime::from_epoch_local(timestamp);

if (!dt.is_valid()) {
if (timestamp > 0) {
ESP_LOGW("${TAG_DATETIME}", "render_date(%s): invalid time from epoch %" PRIu32,
component.c_str(), timestamp);
} else {
ESP_LOGW("${TAG_DATETIME}", "render_date(%s): time provider not yet synchronized",
component.c_str());
}
return;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

const int dow = (dt.day_of_week + 5) % 7;
const int mon = dt.month - 1;

Expand All @@ -159,8 +174,16 @@ script:
nspanel_easy::replace_all(date_str, "%a", weekdays_short[dow]);
nspanel_easy::replace_all(date_str, "%B", months[mon]);
nspanel_easy::replace_all(date_str, "%b", months_short[mon]);
nspanel_easy::replace_all(date_str, "%-d", to_string(dt.day_of_month).c_str());
nspanel_easy::replace_all(date_str, "%-m", to_string(dt.month).c_str());

disp1->set_component_text(component.c_str(), dt.strftime(date_str).c_str());
const std::string date_string = dt.strftime(date_str);
if (date_string == "ERROR") {
ESP_LOGW("${TAG_DATETIME}", "render_date(%s): strftime failed - format '%s' (raw: '%s')",
component.c_str(), date_str.c_str(), id(mui_date_format).c_str());
return;
}
disp1->set_component_text(component.c_str(), date_string.c_str());

- id: !extend stop_all
then:
Expand Down
10 changes: 5 additions & 5 deletions esphome/nspanel_esphome_hw_display.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ display:
uart_id: tf_uart
command_spacing: 10ms # Increased from 5ms to prevent "Nextion Buffer Overflow"
# dump_device_info: true # To-do: Enable when pr#13566 is released
max_commands_per_loop: 15
# max_commands_per_loop: 15
# max_queue_size: 128 # Enable with v2026.6.0
update_interval: never
on_setup:
Expand Down Expand Up @@ -314,7 +314,7 @@ script:
new_page_id != get_page_id("confirm") &&
new_page_id != get_page_id("keyb_num")) {
detailed_entity->publish_state("");
disp1->send_command("back_page_id=1");
disp1->send_command_printf("back_page_id=%" PRIu8, get_page_id("home"));
} else { // Report detailed entity
ESP_LOGD("${TAG_HW_DISPLAY}", "Entity shown: %s", detailed_entity->state.c_str());
}
Expand All @@ -325,9 +325,9 @@ script:
}

// Reset timers
if (current_page_id != get_page_id("screen_saver")) {
ESP_LOGV("${TAG_HW_DISPLAY}", "Reset timers");
timer_reset_all->execute();
if (new_page_id != get_page_id("screensaver")) {
ESP_LOGV("${TAG_HW_DISPLAY}", "Reset timers");
timer_reset_all->execute();
}

# Wait for other constructors to stop before telling the blueprint about a new page
Expand Down
4 changes: 2 additions & 2 deletions esphome/nspanel_esphome_localization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4134,8 +4134,8 @@ substitutions:
LANG_ALARM_BYPASS: "${LOCALIZATION[LANG].alarm.bypass}"
LANG_ALARM_DISARM: "${LOCALIZATION[LANG].alarm.disarm}"
SENTINEL_NO_NAME: "__no_name__"
SENTINEL_UNAVAILABLE: "__unavailable__"
SENTINEL_UNKNOWN: "__unknown__"
SENTINEL_UNAVAILABLE: "_{_unavailable_}_"
SENTINEL_UNKNOWN: "_{_unknown_}_"

esphome:
platformio_options:
Expand Down
100 changes: 59 additions & 41 deletions esphome/nspanel_esphome_page_screensaver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ esphome:
- -D NSPANEL_EASY_PAGE_SCREENSAVER

globals:
- id: screensaver_background_color
type: uint16_t
restore_value: true
initial_value: 'Colors::RGB565_BLACK'
- id: screensaver_display_time
type: bool
restore_value: true
Expand Down Expand Up @@ -75,13 +79,17 @@ script:
- id: !extend action_component_color
then:
- lambda: |-
if (page != "screensaver") return;
if (component == "text") {
if (page != "mem") return;
if (component == hmi::screensaver::TEXT.name) {
id(screensaver_display_time_color) = color;
if (id(screensaver_display_time) and current_page_id == get_page_id("screensaver")) {
disp1->set_component_foreground_color(hmi::screensaver::TEXT.name, id(screensaver_display_time_color));
}
return;
}
if (component == "screensaver_bco") {
disp1->set_component_value("screensaver_bco", color);
if (component == "screensaver_bco" and id(screensaver_background_color) != color) {
id(screensaver_background_color) = color;
disp1->send_command_printf("screensaver_bco=%" PRIu16, id(screensaver_background_color));
return;
}

Expand All @@ -90,11 +98,14 @@ script:
- lambda: |-
if (page != "mem") return;
if (component == "screensaver_display_time") {
id(screensaver_display_time) = (val > 0);
page_screensaver->execute();
const bool temp_display_time = (val > 0);
if (id(screensaver_display_time) != temp_display_time) {
id(screensaver_display_time) = temp_display_time;
page_screensaver->execute();
}
return;
}
if (component == "screensaver_time_font") {
if (component == "screensaver_time_font" and id(screensaver_display_time_font) != val) {
id(screensaver_display_time_font) = val;
page_screensaver->execute();
return;
Expand All @@ -107,49 +118,59 @@ script:
timer_reset_all->execute();
return;
}
static const bool wakeup_with_button_press = ${'true' if wakeup_with_button_press else 'false'};
ESP_LOGV("${TAG_PAGE_SCREENSAVER}", "wakeup_with_button_press: %s", YESNO(wakeup_with_button_press));
if (not wakeup_with_button_press) return;
wakeup->execute(true);
ESP_LOGV("${TAG_PAGE_SCREENSAVER}", "wakeup_with_button_press: ${wakeup_with_button_press}");
if (${wakeup_with_button_press | lower}) {
wakeup->execute(true);
}

- id: !extend boot_nextion
then:
- lambda: |-
disp1->send_command_printf("screensaver_bco=%" PRIu16, id(screensaver_background_color));

- id: !extend page_change
then:
- lambda: |-
if (new_page_id == get_page_id("screensaver"))
page_screensaver->execute();
if (new_page_id != get_page_id("screensaver")) return;
page_screensaver->execute();

- id: page_screensaver
mode: single
mode: restart
then:
- if:
condition:
- lambda: |-
return (current_page_id == get_page_id("screensaver") and not system_flags.tft_upload_active);
then:
- lambda: |-
page_screensaver_set_brightness->execute();
disp1->send_command_printf("wakeup_page_id=%" PRIu8, wakeup_page_id);
if (id(screensaver_display_time)) {
disp1->set_component_font("text", id(screensaver_display_time_font));
disp1->set_component_font_color("text", id(screensaver_display_time_color));
disp1->show_component("text");
refresh_datetime->execute();
}
- delay: 5s
- script.execute: page_screensaver_set_brightness
- lambda: |-
if (current_page_id != get_page_id("screensaver")) return;
page_screensaver_set_brightness->execute();
disp1->send_command_printf("wakeup_page_id=%" PRIu8, wakeup_page_id);
disp1->set_component_background_color("screensaver", id(screensaver_background_color));
if (id(screensaver_display_time)) {
disp1->set_component_background_color(hmi::screensaver::TEXT.name, id(screensaver_background_color));
disp1->set_component_foreground_color(hmi::screensaver::TEXT.name, id(screensaver_display_time_color));
disp1->set_component_font(hmi::screensaver::TEXT.name, id(screensaver_display_time_font));
disp1->show_component(hmi::screensaver::TEXT.name);
}
refresh_hardware_buttons_bars->execute(3);
if (id(screensaver_display_time)) refresh_datetime->execute();
page_screensaver_set_brightness_with_wait->execute();

- id: page_screensaver_set_brightness
mode: single
then:
- lambda: |-
if (current_page_id == get_page_id("screensaver"))
set_brightness->execute(int(display_sleep_brightness->state));
if (current_page_id != get_page_id("screensaver")) return;
set_brightness->execute(int(display_sleep_brightness->state));

- id: page_screensaver_set_brightness_with_wait
mode: restart
then:
- delay: 5s
- script.execute: page_screensaver_set_brightness

- id: !extend stop_all
then:
- lambda: |-
page_screensaver->stop();
page_screensaver_set_brightness->stop();
page_screensaver_set_brightness_with_wait->stop();
timer_sleep->stop();

- id: timer_sleep # Handles the sleep (go to screensaver page) after a timeout
Expand All @@ -161,15 +182,12 @@ script:
then:
- delay: !lambda return (int(timeout_sleep->state) *1000);
- lambda: |-
if (
timeout_sleep->state > 0 and
current_page_id != get_page_id("screensaver") and
current_page_id != ${PAGE_BOOT_ID}
) {
ESP_LOGD("${TAG_PAGE_SCREENSAVER}", "Sleep from '%s'", page_names[current_page_id]);
goto_page->execute(get_page_id("screensaver"));
set_brightness->execute(display_sleep_brightness->state);
}
if (timeout_sleep->state <= 0) return; // Sleep is disabled
if (current_page_id == get_page_id("screensaver")) return; // Already sleeping
if (current_page_id == get_page_id("boot")) return; // Don't sleep during boot
ESP_LOGD("${TAG_PAGE_SCREENSAVER}", "Sleep from '%s'", page_names[current_page_id]);
goto_page->execute(get_page_id("screensaver"));
set_brightness->execute(display_sleep_brightness->state);

- id: !extend timer_reset_all
then:
Expand Down
16 changes: 9 additions & 7 deletions esphome/nspanel_esphome_page_weather.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,6 @@ script:
ESP_LOGW("${TAG_PAGE_WEATHER}", "Unexpected page_index: %" PRIu8, page_index);
return;
}
const ESPTime now = id(time_provider).now();
// Anchor to local noon to avoid DST boundary edge cases where
// adding 86400s could resolve to the wrong calendar date
const int32_t seconds_to_noon = (12 - static_cast<int32_t>(now.hour)) * 3600;
const uint32_t timestamp = static_cast<uint32_t>(
static_cast<int64_t>(now.timestamp) + seconds_to_noon + (page_index * ${SECONDS_PER_DAY}));

static const char* const relative_days[5] = {
"${LOCALIZATION[LANG].relative_day.today}",
Expand All @@ -74,8 +68,16 @@ script:
"${LOCALIZATION[LANG].relative_day.in_3_days}",
"${LOCALIZATION[LANG].relative_day.in_4_days}"
};

disp1->set_component_text("day", relative_days[page_index]);

const ESPTime now = id(time_provider).now();
if (!now.is_valid()) return;

// Anchor to local noon to avoid DST boundary edge cases where
// adding 86400s could resolve to the wrong calendar date
const int32_t seconds_to_noon = (12 - static_cast<int32_t>(now.hour)) * 3600;
const uint32_t timestamp = static_cast<uint32_t>(
static_cast<int64_t>(now.timestamp) + seconds_to_noon + (page_index * ${SECONDS_PER_DAY}));
render_date->execute("date", timestamp);

- id: !extend stop_page_constructors
Expand Down
2 changes: 1 addition & 1 deletion esphome/nspanel_esphome_version.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ substitutions:
# Value is imported from versioning/version.yaml
<<: !include ../versioning/version.yaml
# Minimum required versions for compatibility
min_blueprint_version: 14
min_blueprint_version: 15
min_tft_version: 14
min_esphome_compiler_version: 2026.1.0
TAG_VERSIONING: nspanel.versioning
Expand Down
Loading
Loading