Closed electrocamuk closed 6 months ago
To add, I realise my ESPhome is a little out of date, I've just updated one panel to latest and will test over the weekend, will report back :)
It should work fine with ESPhome 2023.12.9.
Do you mind sharing your panel's yaml (from ESPHome Dashboard)? Please remove any sensitive info when sharing.
Thanks, Just notes on the YAML below, a custom nextion_update_url was used as I had issues flashing and discovered flashing the blank FW before flashing the normal/updated FW yielded a successful TFT flash, I see that the newer implementation has a nice dropdown box to select the TFT firmware, this worked great, I still flashed to blank before flashing the new firmware to be on the safe side and both panels flashed perfectly, great feature! Thanks in advance,
My nspanel YAML--
substitutions:
###### CHANGE ME START ######
device_name: "nspanel"
wifi_ssid: "SSID"
wifi_password: "WPA2"
nextion_update_url: "http://192.168.0.1/ha/nspanel_eu.tft" # URL to local tft File
# nextion_update_url: "http://192.168.0.220:8123/local/nspanel_eu.tft" # URL to local tft File
# nextion_update_url: "https://raw.githubusercontent.com/Blackymas/NSPanel_HA_Blueprint/main/nspanel_us.tft" # URL to Github
##### CHANGE ME END #####
##### DO NOT CHANGE ANYTHING! #####
##### Original URL https://github.com/Blackymas/NSPanel_HA_Blueprint #####
packages:
##### download esphome code from Github
remote_package:
url: https://github.com/Blackymas/NSPanel_HA_Blueprint
ref: main
files: [nspanel_esphome.yaml]
refresh: 300s
##### DO NOT CHANGE ANYTHING! #####
The Nspanel I did upgrade the ESPhome version on last night, did crash/reboot this morning at 03:02am, thanks in advance :)
I noticed the same behaviar since i upgraded from v 4.2.4 to v4.2.6 the last one is on esphome Firmware: 2023.12.9 (Feb 19 2024, 18:51:29)
I don't really have logs as esphome doen not maintain logs after reboot.
what I noticed was some automations kicking in after a switch state change and a short blue boot screen.
I noticed this with 4.2.5 also.
On Fri, 23 Feb 2024, 21.05 bkbartk, @.***> wrote:
I noticed the same behaviar since i upgraded from v 4.2.4 to v4.2.6 the last one is on esphome Firmware: 2023.12.9 (Feb 19 2024, 18:51:29)
I don't really have logs as esphome doen not maintain logs after reboot.
what I noticed was some automations kicking in after a switch state change and a short blue boot screen.
— Reply to this email directly, view it on GitHub https://github.com/Blackymas/NSPanel_HA_Blueprint/issues/1832#issuecomment-1961846386, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAB2JCNTWTHAXCW7M7IBHLLYVDR67AVCNFSM6AAAAABDVT2Q4WVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNRRHA2DMMZYGY . You are receiving this because you are subscribed to this thread.Message ID: @.***>
The watchdog (in the logs) shows Free heap
.
How much is it showing? I know it changes all the time, but I just wanna have an idea.
Could you please add this to your panel's yaml (in the customization area, or at the end of the file) so we can try to capture the reason for the restart?
debug:
text_sensor:
- platform: debug
device:
name: "Device Info"
reset_reason:
name: "Reset Reason"
sensor:
- platform: debug
free:
name: "Heap Free"
block:
name: "Heap Max Block"
loop_time:
name: "Loop Time"
Thanks Edward I've added the debug code and I have the debug sensors show up now, I'll leave the panel to crash then report back the sensor status post crash - unless you want them immediately in which case I've attached! Thanks, -Dave
Screenshot from my phone. The rest of the info I have to gather later
60kb is half of what I was expecting. It probably can't sustain a TFT upload... Are you running any BLE?
60kb is half of what I was expecting. It probably can't sustain a TFT upload... Are you running any BLE?
Not BLE. But another external component for Udp syncing. I also have the tft add on still installed. That one I ofc can remove after uploading.
Edit: it’s true that I need to disable this component during the tft upload. Else it always fails.
Memory leak?
Looks like. 😩
Anyone else seeing a similar trend? Unfortunately I have all my panel off this weekend, so I cannot duplicate it.
I don't think 40 minutes of measuring including one intentional reboot would be enough. but this morning the heap was 60KB,
I'm wondering if everyone is on arduino framework here
I have one of my panels with Arduino, but cannot start the tests until Monday. 😩
after 3 hours of testing I think I can say the trend is the same
@bkbartk, do you mind sharing the yaml of this panel? Please remember to hide any private info before sharing.
of course
# - priority: 800.0 # This is where all hardware initialization of vital components is executed. For example setting switches to their initial state.
# then:
# - wait_until:
# condition:
# - wifi.connected
# timeout: 60s
# - lambda: id(started) = 'true';
substitutions:
device_name: "switch-kamer-achter"
nextion_update_url: "http://192.168.180.149/nspanel_eu.tft"
packages:
base: !include .base.yaml
device: !include .nspanel.yaml
tftupload: !include .nspanel_esphome_addon_upload_tft.yaml
external_components:
- source: github://Cossid/tasmotadevicegroupsforesphome@main
components: [ device_groups ]
refresh: 10 min
device_groups:
- group_name: "bulbkamervoor" # Tasmota device group name
send_mask: 1
receive_mask: 1
switches:
- relay_1
- group_name: "bulbkamerachter" # Tasmota device group name
send_mask: 1
receive_mask: 1
switches:
- relay_2
globals:
- id: started
type: bool
initial_value: 'false'
restore_value: no
switch:
##### PHYSICAL SWITCH 1 #####
- name: ${device_name} Relay 1
platform: template
id: relay_1
restore_mode: RESTORE_DEFAULT_OFF
optimistic: true
on_turn_on:
then:
- lambda: |-
id(detailed_entity).publish_state("light.bulb_kamer_voor_bulb_kamer_voor");
id(disp1).goto_page("light");
id(disp1).set_component_text_printf("back_page", "home");
id(disp1).set_component_text_printf("page_label", "Kamer voor");
id(disp1).set_component_text_printf("icon_state", "\uF10F"); // mdi:lightbulb - https://htmlpreview.github.io/?https://github.com/jobr99/Generate-HASP-Fonts/blob/master/cheatsheet.html
on_turn_off:
then:
- script.execute:
id: refresh_relays
##### PHYSICAL SWITCH 2 ######
- name: ${device_name} Relay 2
platform: template
id: relay_2
optimistic: true
restore_mode: RESTORE_DEFAULT_OFF
on_turn_on:
then:
- if:
condition:
switch.is_off: Real_Right
then:
- switch.turn_on: Real_Right
- lambda: |-
id(detailed_entity).publish_state("light.bulb_kamer_achter_bulb_kamer_achter");
id(disp1).goto_page("light");
id(disp1).set_component_text_printf("back_page", "home");
id(disp1).set_component_text_printf("page_label", "Kamer achter");
id(disp1).set_component_text_printf("icon_state", "\uF060"); // mdi:lightbulb - https://htmlpreview.github.io/?https://github.com/jobr99/Generate-HASP-Fonts/blob/master/cheatsheet.html
on_turn_off:
then:
- if:
condition:
or:
- and:
- lambda: "return id(started);"
- not:
- wifi.connected
- and:
- lambda: 'return !id(started);'
- lambda: 'return id(reset_reason).state == "Power On Reset";'
then:
- switch.turn_off: Real_Right
- script.execute:
id: refresh_relays
##### Real Buttons######
- name: ${device_name} Real Left
id: Real_Left
platform: gpio
pin:
number: 22
restore_mode: ALWAYS_OFF
- name: ${device_name} Real Right
id: Real_Right
platform: gpio
pin:
number: 19
restore_mode: RESTORE_DEFAULT_ON
debug:
text_sensor:
- platform: debug
device:
name: "Device Info"
reset_reason:
id: reset_reason
name: "Reset Reason"
sensor:
- platform: debug
free:
name: "Heap Free"
block:
name: "Heap Max Block"
loop_time:
name: "Loop Time"
then .base.yaml
wifi:
id: wifiId
ssid: !secret wifi_ssid
password: !secret wifi_password
# power_save_mode: NONE
power_save_mode: HIGH
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "${device_name}"
password: !secret wifi_password
captive_portal:
# Enable logging
logger:
api:
encryption:
key: !secret api_encryption_key
reboot_timeout: 0s
ota:
safe_mode: true
reboot_timeout: 3min
num_attempts: 3
password: !secret ota_password
web_server:
port: 80
local: true
auth:
username: admin
password: !secret web_server_password
button:
- platform: restart
name: "${device_name} switch Restart"
icon: "mdi:restart"
- platform: safe_mode
name: "${device_name} Restart (Safe Mode)"
icon: "mdi:restart-alert"
.nspanel.yaml (there are a few changes to not conflict with base or the original yaml, but nothing important.
#####################################################################################################
##### NSPANEL ESPHOME created by Blackymas - https://github.com/Blackymas/NSPanel_HA_Blueprint #####
##### ESPHOME CORE #####
##### 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 ##
temp_units: "°C"
invalid_cooldown: "100ms"
ota_password: ${wifi_password}
ap_password: ${wifi_password}
device_name: NSPanel
name: ${device_name}
friendly_name: ${device_name}
wifi_timeout: '15'
##### DON'T CHANGE THIS ######
version: "4.2.6"
##############################
##### External components #####
external_components:
- source:
type: git
url: https://github.com/edwardtfn/esphome
ref: nextion-v425
components:
- nextion # Change this when that PR#6192 gets released (2024.3?)
refresh: 300s
##### ESPHOME CONFIGURATION #####
esphome:
name: ${name}
friendly_name: ${friendly_name}
min_version: 2023.12.0
platformio_options:
build_flags:
- -Wno-missing-field-initializers
on_boot:
- priority: 600.0 # This is where most sensors are set up.
then:
- script.execute: restore_settings
- wait_until:
condition:
- lambda: return disp1->is_setup();
timeout: 60s
- if:
condition:
- lambda: return (not disp1->is_detected());
then:
- switch.turn_off: screen_power
- delay: 2s
- switch.turn_on: screen_power
- delay: 5s
- priority: 800.0 # This is where all hardware initialization of vital components is executed. For example setting switches to their initial state.
then:
- wait_until:
condition:
- wifi.connected
timeout: 60s
- lambda: id(started) = "true";
on_shutdown:
- priority: 0
then:
- lambda: |-
// Make it unavailable to blueprint calls
nextion_init->publish_state(false);
// Update Wi-Fi icon
disp1->set_component_text_printf("home.wifi_icon", "\uE708");
// Update Wi-Fi icon color
disp1->set_component_font_color("home.wifi_icon", 63488);
- priority: 600.0
then:
- switch.turn_off: screen_power
##### TYPE OF ESP BOARD #####
esp32:
board: esp32dev
##### WIFI SETUP #####
wifi:
id: wifi_component
on_connect:
then:
- script.execute: watchdog
on_disconnect:
then:
- script.execute: watchdog
##### JSON - Used to parse json and for Upload TFT #####
json:
##### LOGGER #####
logger:
id: logger_std
baud_rate: 0
##### ENABLE RINGTONE MUSIC SUPPORT #####
rtttl:
id: buzzer
output: buzzer_out
##### CONFIGURE INTERNAL BUZZER #####
output:
##### BUZZER FOR PLAYING RINGTONES #####
- id: buzzer_out
platform: ledc
pin:
number: 21
##### UART FOR NEXTION DISPLAY #####
uart:
- id: tf_uart
tx_pin: 16
rx_pin: 17
baud_rate: 115200
##### Keeps time display updated #####
time:
- id: time_provider
platform: homeassistant
on_time:
- seconds: 0
then:
- script.execute: refresh_datetime
- seconds: 30
then:
- script.execute: watchdog
on_time_sync:
then:
- logger.log: "System clock synchronized"
- script.execute: refresh_datetime
##### START - API CONFIGURATION #####
api:
id: api_server
reboot_timeout: 0s
on_client_connected:
- script.execute: watchdog
on_client_disconnected:
- script.execute: watchdog
services:
##### Service to send a command "printf" directly to the display #####
- service: send_command_printf
variables:
cmd: string
then:
- lambda: |-
if (!id(is_uploading_tft))
disp1->send_command_printf("%s", cmd.c_str());
##### Service to send a command "text_printf" directly to the display #####
- service: send_command_text_printf
variables:
component: string
message: string
then:
- lambda: |-
if (!id(is_uploading_tft))
disp1->set_component_text_printf(component.c_str(), "%s", message.c_str());
##### Service to send a command "component_value (Dualstate Button)" directly to the display #####
- service: send_command_value
variables:
component: string
val: int
then:
- lambda: |-
if (!id(is_uploading_tft))
disp1->set_component_value(component.c_str(), val);
##### Service to send a command "hide componente" directly to the display #####
- service: send_command_hide
variables:
component: string
then:
- lambda: |-
if (!id(is_uploading_tft))
disp1->hide_component(component.c_str());
##### Service to send a command "show componente" directly to the display #####
- service: send_command_show
variables:
component: string
then:
- lambda: |-
if (!id(is_uploading_tft))
disp1->show_component(component.c_str());
##### Service to send a command "font color" directly to the display #####
- service: set_component_color
variables:
component: string
foreground: int[]
then:
- lambda: |-
if (!id(is_uploading_tft))
set_component_color->execute(component, foreground);
##### Service to play a rtttl tones #####
# Example tones : https://codebender.cc/sketch:109888#RTTTL%20Songs.ino
- service: play_rtttl
variables:
song_str: string
then:
- rtttl.play:
rtttl: !lambda 'return song_str;'
#### Service to populate the alarm settings page #####
- service: alarm_settings
variables:
page_title: string
state: string
supported_features: int
code_format: string
code_arm_required: bool
entity: string
mui_alarm: string[]
then:
- lambda: |-
// Is page Alarm visible?
if (current_page->state == "alarm" and not id(is_uploading_tft)) // To do: This page constructor should be moved to Blueprint
{ // Update alarm page
detailed_entity->publish_state(entity);
// Alarm page - Header
update_alarm_icon->execute("icon_state", state.c_str());
if (page_title.find("\\r") != std::string::npos) {
page_title = page_title.replace(page_title.find("\\r"), 2, " ");
}
disp1->set_component_text_printf("page_label", "%s", page_title.c_str());
disp1->set_component_text_printf("code_format", "%s", code_format.c_str());
if (code_arm_required) disp1->set_component_text_printf("code_arm_req", "1");
else disp1->set_component_text_printf("code_arm_req", "0");
// Alarm page - Button's text
display_wrapped_text->execute("bt_home_text", mui_alarm[0].c_str(), 10);
display_wrapped_text->execute("bt_away_text", mui_alarm[1].c_str(), 10);
display_wrapped_text->execute("bt_night_text", mui_alarm[2].c_str(), 10);
display_wrapped_text->execute("bt_vacat_text", mui_alarm[3].c_str(), 10);
display_wrapped_text->execute("bt_bypass_text", mui_alarm[4].c_str(), 10);
display_wrapped_text->execute("bt_disarm_text", mui_alarm[5].c_str(), 10);
// Alarm page - Buttons
if (supported_features & 1 or state == "armed_home") // Alarm - Button - Home
{
disp1->send_command_printf("bt_home_pic.pic=%i", (state == "armed_home") ? 43 : 42);
disp1->set_component_background_color("bt_home_text", (state == "armed_home") ? 19818 : 52857);
disp1->set_component_background_color("bt_home_icon", (state == "armed_home") ? 19818 : 52857);
disp1->set_component_font_color("bt_home_text", (state == "armed_home") ? 65535 : 0);
disp1->set_component_font_color("bt_home_icon", (state == "armed_home") ? 65535 : 0);
if (state == "armed_home") disp1->hide_component("bt_home"); else disp1->show_component("bt_home");
}
if (supported_features & 2 or state == "armed_away") // Alarm - Button - Away
{
disp1->send_command_printf("bt_away_pic.pic=%i", (state == "armed_away") ? 43 : 42);
disp1->set_component_background_color("bt_away_text", (state == "armed_away") ? 19818 : 52857);
disp1->set_component_background_color("bt_away_icon", (state == "armed_away") ? 19818 : 52857);
disp1->set_component_font_color("bt_away_text", (state == "armed_away") ? 65535 : 0);
disp1->set_component_font_color("bt_away_icon", (state == "armed_away") ? 65535 : 0);
if (state == "armed_away") disp1->hide_component("bt_away"); else disp1->show_component("bt_away");
}
if (supported_features & 4 or state == "armed_night") // Alarm - Button - Night
{
disp1->send_command_printf("bt_night_pic.pic=%i", (state == "armed_night") ? 43 : 42);
disp1->set_component_background_color("bt_night_text", (state == "armed_night") ? 19818 : 52857);
disp1->set_component_background_color("bt_night_icon", (state == "armed_night") ? 19818 : 52857);
disp1->set_component_font_color("bt_night_text", (state == "armed_night") ? 65535 : 0);
disp1->set_component_font_color("bt_night_icon", (state == "armed_night") ? 65535 : 0);
if (state == "armed_night") disp1->hide_component("bt_night"); else disp1->show_component("bt_night");
}
if (supported_features & 32 or state == "armed_vacation") // Alarm - Button - Vacation
{
disp1->send_command_printf("bt_vacat_pic.pic=%i", (state == "armed_vacation") ? 43 : 42);
disp1->set_component_background_color("bt_vacat_text", (state == "armed_vacation") ? 19818 : 52857);
disp1->set_component_background_color("bt_vacat_icon", (state == "armed_vacation") ? 19818 : 52857);
disp1->set_component_font_color("bt_vacat_text", (state == "armed_vacation") ? 65535 : 0);
disp1->set_component_font_color("bt_vacat_icon", (state == "armed_vacation") ? 65535 : 0);
if (state == "armed_vacation") disp1->hide_component("bt_vacat"); else disp1->show_component("bt_vacat");
}
if (supported_features & 16 or state == "armed_bypass") // Alarm - Button - Custom bypass
{
disp1->send_command_printf("bt_bypass_pic.pic=%i", (state == "armed_bypass") ? 43 : 42);
disp1->set_component_background_color("bt_bypass_text", (state == "armed_bypass") ? 19818 : 52857);
disp1->set_component_background_color("bt_bypass_icon", (state == "armed_bypass") ? 19818 : 52857);
disp1->set_component_font_color("bt_bypass_text", (state == "armed_bypass") ? 65535 : 0);
disp1->set_component_font_color("bt_bypass_icon", (state == "armed_bypass") ? 65535 : 0);
if (state == "armed_bypass") disp1->hide_component("bt_bypass"); else disp1->show_component("bt_bypass");
}
if ( true ) // Alarm - Button - Disarm
{
disp1->send_command_printf("bt_disarm_pic.pic=%i", (state == "disarmed") ? 43 : 42);
disp1->set_component_background_color("bt_disarm_text", (state == "disarmed") ? 19818 : 52857);
disp1->set_component_background_color("bt_disarm_icon", (state == "disarmed") ? 19818 : 52857);
disp1->set_component_font_color("bt_disarm_text", (state == "disarmed") ? 65535 : 0);
disp1->set_component_font_color("bt_disarm_icon", (state == "disarmed") ? 65535 : 0);
if (state == "disarmed") disp1->hide_component("bt_disarm"); else disp1->show_component("bt_disarm");
}
}
##### Service for transferring relay's settings from the blueprint to ESPHome #####
- service: relay_settings
variables:
relay1_local_control: bool
relay1_icon: string
relay1_icon_color: int
relay1_fallback: bool
relay2_local_control: bool
relay2_icon: string
relay2_icon_color: int
relay2_fallback: bool
then:
- script.execute:
id: relay_settings
relay1_local_control: !lambda "return relay1_local_control;"
relay1_icon: !lambda "return relay1_icon;"
relay1_icon_color: !lambda "return relay1_icon_color;"
relay1_fallback: !lambda "return relay1_fallback;"
relay2_local_control: !lambda "return relay2_local_control;"
relay2_icon: !lambda "return relay2_icon;"
relay2_icon_color: !lambda "return relay2_icon_color;"
relay2_fallback: !lambda "return relay2_fallback;"
- script.wait: relay_settings
- lambda: |-
blueprint_status->publish_state(int(blueprint_status->raw_state) | (1 << 4));
##### Service for transferring global settings from the blueprint to ESPHome #####
- service: global_settings
variables:
blueprint_version: string
embedded_climate: bool
embedded_climate_friendly_name: string
embedded_indoor_temperature: bool
temperature_unit_is_fahrenheit: bool # Deprecated
mui_please_confirm: string
mui_unavailable: string
screensaver_time: bool
screensaver_time_color: int[]
then:
- script.execute:
id: global_settings
blueprint_version: !lambda "return blueprint_version;"
embedded_climate: !lambda "return embedded_climate;"
embedded_climate_friendly_name: !lambda "return embedded_climate_friendly_name;"
embedded_indoor_temperature: !lambda "return embedded_indoor_temperature;"
# temperature_unit_is_fahrenheit: !lambda "return temperature_unit_is_fahrenheit;" # Deprecated
mui_please_confirm: !lambda "return mui_please_confirm;"
mui_unavailable: !lambda "return mui_unavailable;"
screensaver_time: !lambda "return screensaver_time;"
screensaver_time_color: !lambda "return screensaver_time_color;"
- script.wait: global_settings
- lambda: |-
blueprint_status->publish_state(int(blueprint_status->raw_state) | (1 << 5));
##### Service to show a notification-message on the screen #####
- service: notification_show
variables:
label: string
message: string
then:
- lambda: |-
if (!id(is_uploading_tft)) {
ESP_LOGV("service.notification_show", "Starting");
disp1->goto_page("notification");
disp1->set_component_text_printf("notification.notifi_label", "%s", label.c_str());
display_wrapped_text->execute("notification.notifi_text01", message.c_str(), display_mode->state == 2 ? 23 : 32);
notification_label->publish_state(label.c_str());
notification_text->publish_state(message.c_str());
timer_reset_all->execute(current_page->state.c_str());
refresh_notification->execute();
notification_unread->turn_on();
if (notification_sound->state) buzzer->play("two short:d=4,o=5,b=100:16e6,16e6");
}
##### Service to clear the notification #####
- service: notification_clear
then:
- script.execute: notification_clear
##### Service to open information for settings-page(s)
- service: open_entity_settings_page
variables:
page: string
page_label: string
page_icon: string
page_icon_color: int[]
entity: string
back_page: string
then:
- script.execute:
id: open_entity_settings_page
page: !lambda "return page;"
page_label: !lambda "return page_label;"
page_icon: !lambda "return page_icon;"
page_icon_color: !lambda "return page_icon_color;"
entity: !lambda "return entity;"
back_page: !lambda "return back_page;"
# Service to show a QR code on the display (ex. for WiFi password)
- service: qrcode
variables:
title: string
qrcode: string
show: bool
then:
- lambda: |-
if (!id(is_uploading_tft)) {
disp1->set_component_text_printf("qrcode.qrcode_label", "%s", title.c_str());
disp1->set_component_text_printf("qrcode.qrcode_value", "%s", qrcode.c_str());
if (show) disp1->goto_page("qrcode");
blueprint_status->publish_state(int(blueprint_status->raw_state) | (1 << 2));
}
#### Service to set climate state ####
- service: set_climate
variables:
current_temp: float
supported_features: int
target_temp: float
target_temp_high: float
target_temp_low: float
temp_step: int
total_steps: int
temp_offset: int
climate_icon: string
embedded_climate: bool
entity: string
then:
- if:
condition:
lambda: 'return not id(is_uploading_tft);'
then:
- lambda: |-
if (current_page->state == "climate") detailed_entity->publish_state(entity);
- script.execute:
id: set_climate
current_temp: !lambda "return current_temp;"
supported_features: !lambda "return supported_features;"
target_temp: !lambda "return target_temp;"
target_temp_high: !lambda "return target_temp_high;"
target_temp_low: !lambda "return target_temp_low;"
temp_step: !lambda "return temp_step;"
total_steps: !lambda "return total_steps;"
temp_offset: !lambda "return temp_offset;"
climate_icon: !lambda "return climate_icon;"
embedded_climate: !lambda "return embedded_climate;"
#### Service to set the buttons ####
- service: set_button
variables:
page: string
id: string
state: bool
icon: string
icon_color: int[]
icon_font: int
bri: string
label: string
then:
- lambda: |-
if (page == current_page->state and not id(is_uploading_tft)) {
std::string btnicon = id.c_str() + std::string("icon");
std::string btntext = id.c_str() + std::string("text");
std::string btnbri = id.c_str() + std::string("bri");
std::string btnpic = id.c_str() + std::string("pic");
uint8_t bg_pic = state ? 47 : 46;
uint16_t txt_color = state ? 10597 : 65535;
disp1->send_command_printf("%spic.picc=%u", id.c_str(), bg_pic);
disp1->send_command_printf("%sbri.picc=%u", id.c_str(), bg_pic);
disp1->send_command_printf("%stext.picc=%u", id.c_str(), bg_pic);
disp1->send_command_printf("%sicon.picc=%u", id.c_str(), bg_pic);
disp1->send_command_printf("%sicon.font=%" PRIu32, id.c_str(), icon_font);
disp1->set_component_foreground_color(btnbri.c_str(), txt_color);
disp1->set_component_foreground_color(btntext.c_str(), txt_color);
set_component_color->execute(btnicon.c_str(), icon_color);
disp1->set_component_text_printf(btnicon.c_str(), "%s", icon.c_str());
display_wrapped_text->execute(btntext.c_str(), label.c_str(), 10);
if (strcmp(bri.c_str(), "0") != 0)
disp1->set_component_text_printf(btnbri.c_str(), "%s", bri.c_str());
else
disp1->set_component_text_printf(btnbri.c_str(), " ");
disp1->show_component(btnpic.c_str());
disp1->show_component(btnicon.c_str());
disp1->show_component(btntext.c_str());
disp1->show_component(btnbri.c_str());
disp1->show_component(id.c_str());
} else {
ESP_LOGW("service.set_button", "Skipping button `%s.%s` update.", page.c_str(), id.c_str());
}
##### SERVICE TO WAKE UP THE DISPLAY #####
- service: wake_up
variables:
reset_timer: bool
then:
- lambda: |-
if (not id(is_uploading_tft)) {
if (current_page->state == "screensaver") disp1->goto_page(wakeup_page_name->state.c_str());
if (reset_timer)
timer_reset_all->execute(wakeup_page_name->state.c_str());
else {
timer_sleep->execute(wakeup_page_name->state.c_str(), int(timeout_sleep->state));
timer_dim->execute(wakeup_page_name->state.c_str(), int(timeout_dim->state));
}
}
#### Service to set the entities ####
- service: set_entity
variables:
ent_id: string
ent_icon: string
ent_label: string
ent_value: string
ent_value_xcen: string
then:
- lambda: |-
if (not id(is_uploading_tft)) {
std::string enticon = ent_id.c_str() + std::string("_pic");
std::string entlabel = ent_id.c_str() + std::string("_label");
std::string entxcen = ent_id.c_str() + std::string(".xcen=") + ent_value_xcen.c_str();
disp1->set_component_text_printf(enticon.c_str(), "%s", ent_icon.c_str());
if (strcmp(ent_icon.c_str(), "0") != 0) disp1->set_component_text_printf(enticon.c_str(), "%s", ent_icon.c_str());
disp1->set_component_text_printf(entlabel.c_str(), "%s", ent_label.c_str());
disp1->set_component_text_printf(ent_id.c_str(), "%s", ent_value.c_str());
if (strcmp(ent_value_xcen.c_str(), "0") != 0) disp1->send_command_printf("%s", entxcen.c_str());
}
#### Service to populate the page Home #####
- service: page_home
variables:
date_color: int
time_format: string
time_color: int
meridiem: string[]
chip_font_size: int
custom_buttons_font_size: int
notification_icon: string
notification_icon_color_normal: int[]
notification_icon_color_unread: int[]
qrcode: bool
qrcode_icon: string
qrcode_icon_color: int[]
entities_pages: bool
entities_pages_icon: string
entities_pages_icon_color: int[]
then:
- lambda: |-
if (not id(is_uploading_tft)) {
static const char *const TAG = "service.page_home";
ESP_LOGV(TAG, "date_color: %" PRIi32, date_color);
ESP_LOGV(TAG, "time_format: %s", time_format.c_str());
ESP_LOGV(TAG, "time_color: %" PRIi32, time_color);
ESP_LOGV(TAG, "meridiem: %i", meridiem.size());
ESP_LOGV(TAG, "chip_font_size: %" PRIi32, chip_font_size);
ESP_LOGV(TAG, "custom_buttons_font_size: %" PRIi32, custom_buttons_font_size);
ESP_LOGV(TAG, "notification_icon: %s", notification_icon.c_str());
ESP_LOGV(TAG, "notification_icon_color_normal: %i", notification_icon_color_normal.size());
ESP_LOGV(TAG, "notification_icon_color_unread: %i", notification_icon_color_unread.size());
ESP_LOGV(TAG, "qrcode: %s", YESNO(qrcode));
ESP_LOGV(TAG, "qrcode_icon: %s", qrcode_icon.c_str());
ESP_LOGV(TAG, "qrcode_icon_color: %i", qrcode_icon_color.size());
ESP_LOGV(TAG, "entities_pages: %s", YESNO(entities_pages));
ESP_LOGV(TAG, "entities_pages_icon: %s", entities_pages_icon.c_str());
ESP_LOGV(TAG, "entities_pages_icon_color: %i", entities_pages_icon_color.size());
// Localization
ESP_LOGV(TAG, "Load localization");
id(mui_time_format) = time_format;
id(mui_meridiem) = meridiem;
// Date/Time colors
ESP_LOGV(TAG, "Load date/time colors");
disp1->set_component_font_color("home.date", date_color);
disp1->set_component_font_color("home.time", time_color);
id(home_date_color) = date_color;
id(home_time_color) = time_color;
// Chips icon size
ESP_LOGV(TAG, "Chips size");
for (int i = 1; i <= 10; ++i) {
disp1->send_command_printf("home.icon_top_%02d.font=%" PRIu32, i, chip_font_size);
}
disp1->send_command_printf("home.wifi_icon.font=%" PRIu32, chip_font_size);
id(home_chip_font_size) = chip_font_size;
// Custom buttons icon size
ESP_LOGV(TAG, "Custom buttons sizes");
id(home_custom_buttons_font_size) = custom_buttons_font_size;
for (int i = 1; i <= 7; ++i) {
disp1->send_command_printf("home.button%02d.font=%i", i, id(home_custom_buttons_font_size));
}
disp1->send_command_printf("home.bt_notific.font=%i", id(home_custom_buttons_font_size));
disp1->send_command_printf("home.bt_qrcode.font=%i", id(home_custom_buttons_font_size));
disp1->send_command_printf("home.bt_entities.font=%i", id(home_custom_buttons_font_size));
// Notification button
ESP_LOGV(TAG, "Set Notification button");
disp1->send_command_printf("is_notification=%i", (notification_text->state.empty() and notification_label->state.empty()) ? 0 : 1);
disp1->set_component_text_printf("home.bt_notific", "%s", notification_icon.c_str());
set_component_color->execute("home.bt_notific", notification_unread->state ? notification_icon_color_unread : notification_icon_color_normal);
id(home_notify_icon_color_normal) = notification_icon_color_normal;
id(home_notify_icon_color_unread) = notification_icon_color_unread;
// QRCode button
ESP_LOGV(TAG, "Set QRCode button");
disp1->send_command_printf("is_qrcode=%i", qrcode ? 1 : 0);
disp1->set_component_text_printf("home.bt_qrcode", "%s", qrcode_icon.c_str());
set_component_color->execute("home.bt_qrcode", qrcode_icon_color);
// Entities pages button
ESP_LOGV(TAG, "Set Entities button");
disp1->send_command_printf("is_entities=%i", entities_pages ? 1 : 0);
disp1->set_component_text_printf("home.bt_entities", "%s", entities_pages_icon.c_str());
//set_component_color->execute("home.bt_entities", entities_pages_icon_color);
set_component_color->execute("home.bt_entities", entities_pages_icon_color);
blueprint_status->publish_state(int(blueprint_status->raw_state) | (1 << 1));
}
#### Service to populate the page Settings #####
- service: page_settings
variables:
reboot: string
brightness: string
bright: string
dim: string
then:
- lambda: |-
if (not id(is_uploading_tft)) {
if (not reboot.empty()) disp1->set_component_text_printf("settings.lbl_reboot", " %s", reboot.c_str());
disp1->set_component_text_printf("settings.lbl_brightness", " %s", brightness.c_str());
display_wrapped_text->execute("settings.lbl_bright", bright.c_str(), display_mode->state == 2 ? 25 : 10);
display_wrapped_text->execute("settings.lbl_dim", dim.c_str(), display_mode->state == 2 ? 25 : 10);
blueprint_status->publish_state(int(blueprint_status->raw_state) | (1 << 3));
}
#### Service to populate the media player page #####
- service: media_player
variables:
entity: string
state: string
is_volume_muted: bool
friendly_name: string
volume_level: int
media_title: string
media_artist: string
media_duration: float
media_position: float
media_position_delta: float
supported_features: int
then:
- lambda: |-
if (current_page->state == "media_player" and not id(is_uploading_tft)) {
detailed_entity->publish_state(entity);
disp1->set_component_text_printf("page_label", "%s", friendly_name.c_str());
display_wrapped_text->execute("track", media_title.c_str(), display_mode->state == 2 ? 16 : 27);
display_wrapped_text->execute("artist", media_artist.c_str(), display_mode->state == 2 ? 26 : 40);
// on/off button
if (supported_features & 128 and state == "off") { //TURN_ON
disp1->set_component_foreground_color("bt_on_off", 65535);
disp1->show_component("bt_on_off");
} else if (supported_features & 256 and state != "off") { //TURN_OFF
disp1->set_component_foreground_color("bt_on_off", 10597);
disp1->show_component("bt_on_off");
} else disp1->hide_component("bt_on_off");
// play/pause button
if ((supported_features & 512 or supported_features & 16384) and state != "playing" and state != "off") { //PLAY_MEDIA+PLAY
disp1->set_component_text_printf("bt_play_pause", "%s", "\uE409"); // mdi:play
disp1->show_component("bt_play_pause");
} else if (supported_features & 1 and state == "playing" ) { //PAUSE
disp1->set_component_text_printf("bt_play_pause", "%s", "\uE3E3"); // mdi:pause
disp1->show_component("bt_play_pause");
} else disp1->hide_component("bt_play_pause");
// bt_prev button - PREVIOUS_TRACK
if (supported_features & 16 and state != "off") disp1->show_component("bt_prev"); else disp1->hide_component("bt_prev");
// bt_next button - NEXT_TRACK
if (supported_features & 32 and state != "off") disp1->show_component("bt_next"); else disp1->hide_component("bt_next");
// Stop button - STOP
//if (supported_features & 4096 and (state == "playing" or state == "paused")) disp1->show_component("bt_stop"); else disp1->hide_component("bt_stop");
// mute/unmute button - VOLUME_MUTE
disp1->set_component_value("is_muted", is_volume_muted ? 1 : 0);
if (supported_features & 8 and is_volume_muted) { // unmute
disp1->set_component_text_printf("bt_mute", "%s", "\uEE07"); // mdi:volume-variant-off
disp1->show_component("bt_mute");
} else if (supported_features & 8) { // mute
disp1->set_component_text_printf("bt_mute", "%s", "\uE57E"); // mdi:volume-low
disp1->show_component("bt_mute");
} else disp1->hide_component("bt_mute");
// VOLUME_SET
if (supported_features & 4) {
if (volume_level != id(last_volume_level)) {
id(last_volume_level) = volume_level;
disp1->set_component_text_printf("vol_text", "%" PRIu32 "%%", volume_level);
disp1->set_component_value("vol_slider", volume_level);
}
disp1->show_component("vol_slider");
disp1->show_component("bt_vol_down");
disp1->show_component("bt_vol_up");
disp1->show_component("vol_text");
} else {
disp1->hide_component("vol_slider");
disp1->hide_component("bt_vol_down");
disp1->hide_component("bt_vol_up");
disp1->hide_component("vol_text");
}
if (media_duration > 0) {
if (media_duration != id(last_media_duration) or media_position != id(last_media_position)) {
id(last_media_duration) = media_duration;
id(last_media_position) = media_position;
disp1->set_component_value("prg_current", int(round(min(media_position + media_position_delta, media_duration))));
}
disp1->set_component_value("prg_total", int(round(media_duration)));
disp1->send_command_printf("prg_timer.en=%i", (state == "playing") ? 1 : 0);
disp1->show_component("time_current");
disp1->show_component("time_total");
disp1->show_component("time_progress");
} else {
disp1->send_command_printf("prg_timer.en=0");
disp1->hide_component("time_current");
disp1->hide_component("time_total");
disp1->hide_component("time_progress");
}
}
##### START - DISPLAY START CONFIGURATION #####
display:
- id: disp1
platform: nextion
uart_id: tf_uart
on_setup:
- script.execute: setup_sequence
on_page:
lambda: |-
static const char *const TAG = "display.disp1.on_page";
if (id(is_uploading_tft)) {
ESP_LOGD(TAG, "Page changed ignored as a TFT upload is in progress");
} else if (x > id(page_names).size()) {
ESP_LOGW(TAG, "Invalid page index: %i", int(x));
} else {
ESP_LOGD(TAG, "Nextion page changed");
ESP_LOGD(TAG, "New page: %s (%i)" , id(page_names)[x].c_str(), x);
page_id->update();
if (current_page->state != id(page_names)[x].c_str() or x == 9) {
current_page->publish_state(id(page_names)[x].c_str());
page_changed->execute(id(page_names)[x].c_str());
}
}
on_touch:
lambda: |-
static const char *const TAG = "display.disp1.on_touch";
ESP_LOGV(TAG, "Nextion touch event detected!");
ESP_LOGV(TAG, "Page: %s", id(page_names)[page_id].c_str());
ESP_LOGV(TAG, "Component Id: %i", component_id);
ESP_LOGV(TAG, "Event type: %s", touch_event ? "Press" : "Release");
timer_reset_all->execute(id(page_names)[page_id].c_str());
##### START - GLOBALS CONFIGURATION #####
globals:
##### Wi-Fi timeout #####
- id: wifi_timeout
type: uint
restore_value: false
initial_value: ${wifi_timeout}
##### Is uploading TFT #####
- id: is_uploading_tft
type: bool
restore_value: false
initial_value: 'false'
##### Is boot sequence completed? #####
- id: setup_sequence_completed
type: bool
restore_value: false
initial_value: 'false'
###### Last volume level from Home Assistant ######
- id: last_volume_level
type: uint
restore_value: false
initial_value: '0'
###### Last duration from Home Assistant ######
- id: last_media_duration
type: uint
restore_value: false
initial_value: '0'
###### Last duration from Home Assistant ######
- id: last_media_position
type: uint
restore_value: false
initial_value: '0'
###### Relay fallback even when buttons have other entities? ######
- id: relay_1_fallback
type: bool
restore_value: true
initial_value: 'false'
- id: relay_2_fallback
type: bool
restore_value: true
initial_value: 'false'
##### Is embedded thermostat set as main climate entity? #####
- id: is_embedded_thermostat
type: bool
restore_value: true
initial_value: 'false'
##### Save Display Brightness for NSPanel reboot #####
- id: display_brightness_global
type: uint
restore_value: true
initial_value: '100'
##### Save Display DIM Brightness for NSPanel reboot
- id: display_dim_brightness_global
type: uint
restore_value: true
initial_value: '10'
##### Is embedded sensor used for indoor temperature? #####
- id: embedded_indoor_temp
type: bool
restore_value: true
initial_value: 'false'
##### Date/time formats #####
- id: home_date_color
type: uint
restore_value: true
initial_value: '65535'
- id: mui_time_format
type: std::string
restore_value: true
initial_value: '"%H:%M"'
- id: home_time_color
type: uint
restore_value: true
initial_value: '65535'
- id: mui_meridiem
type: std::vector<std::string>
restore_value: false
initial_value: '{"AM", "PM"}'
#### MUI strings ####
- id: mui_please_confirm_global
type: std::string
restore_value: true
initial_value: '"Please confirm"'
- id: mui_unavailable_global
type: std::string
restore_value: true
initial_value: '"Unavailable"'
##### Chips #####
- id: home_chip_font_size
type: uint
restore_value: true
initial_value: '7'
#### Custom buttons ####
- id: home_custom_buttons_font_size
type: uint
restore_value: true
initial_value: '8'
##### Relay icons #####
- id: home_relay1_icon
type: std::string
restore_value: true
initial_value: ''
- id: home_relay1_icon_color
type: uint16_t
restore_value: true
initial_value: '65535'
- id: home_relay2_icon
type: std::string
restore_value: true
initial_value: ''
- id: home_relay2_icon_color
type: uint16_t
restore_value: true
initial_value: '65535'
- id: home_notify_icon_color_normal
type: std::vector<int32_t>
restore_value: false
- id: home_notify_icon_color_unread
type: std::vector<int32_t>
restore_value: false
##### Screensaver #####
- id: screensaver_display_time
type: bool
restore_value: false
initial_value: 'false'
- id: screensaver_display_time_color
type: std::vector<int32_t>
restore_value: false
initial_value: '{64, 64, 64}'
- id: page_names
type: std::vector<std::string>
restore_value: false
initial_value:
'{
"home",
"weather01",
"weather02",
"weather03",
"weather04",
"weather05",
"climate",
"settings",
"boot",
"screensaver",
"light",
"cover",
"buttonpage01",
"buttonpage02",
"buttonpage03",
"buttonpage04",
"notification",
"qrcode",
"entitypage01",
"entitypage02",
"entitypage03",
"entitypage04",
"fan",
"alarm",
"keyb_num",
"media_player",
"confirm"
}'
- id: framework
type: uint8_t
restore_value: false
initial_value: '0' # 0 = unknown, 1 = Arduino, 2 = ESP-IDF
##### START - BINARY SENSOR CONFIGURATION #####
binary_sensor:
###### LEFT BUTTON BELOW DISPLAY TO TOGGLE RELAY#####
- name: Left Button
platform: gpio
id: left_button
pin:
number: 14
inverted: true
on_multi_click:
- timing: &long_click-timing
- ON for at least 0.8s
invalid_cooldown: ${invalid_cooldown}
then:
- logger.log: "Left button - Long click"
- script.execute:
id: ha_button
page: !lambda return current_page->state.c_str();
component: "hw_bt_left"
command: "long_click"
- timing: &short_click-timing
- ON for at most 0.8s
invalid_cooldown: ${invalid_cooldown}
then:
- logger.log: "Left button - Short click"
- if:
condition:
or:
- switch.is_on: relay1_local
- and:
- lambda: !lambda return id(relay_1_fallback);
- or:
- not:
- api.connected:
- not:
- wifi.connected:
then:
- switch.toggle: relay_1
- script.execute:
id: ha_button
page: !lambda return current_page->state.c_str();
component: "hw_bt_left"
command: "short_click"
- timing: &hold_to_restart-timing
- ON for at least 15.0s
invalid_cooldown: ${invalid_cooldown}
then:
- switch.turn_off: screen_power
- delay: 5s
- switch.turn_on: screen_power
- delay: 2s
- lambda: disp1->soft_reset();
- delay: 2s
- script.execute: setup_sequence
##### RIGHT BUTTON BELOW DISPLAY TO TOGGLE RELAY #####
- name: Right Button
platform: gpio
id: right_button
pin:
number: 27
inverted: true
on_multi_click:
- timing: *long_click-timing
invalid_cooldown: ${invalid_cooldown}
then:
- logger.log: "Right button - Long click"
- script.execute:
id: ha_button
page: !lambda return current_page->state.c_str();
component: "hw_bt_right"
command: "long_click"
- timing: *short_click-timing
invalid_cooldown: ${invalid_cooldown}
then:
- logger.log: "Right button - Short click"
- if:
condition:
or:
- switch.is_on: relay2_local
- and:
- lambda: !lambda return id(relay_2_fallback);
- or:
- not:
- api.connected:
- not:
- wifi.connected:
then:
- switch.toggle: relay_2
- script.execute:
id: ha_button
page: !lambda return current_page->state.c_str();
component: "hw_bt_right"
command: "short_click"
- timing: *hold_to_restart-timing
invalid_cooldown: ${invalid_cooldown}
then: # Restart the panel
- button.press: restart_nspanel
##### Restart NSPanel Button - Setting Page #####
- name: Restart
platform: nextion
page_id: 7
component_id: 9
internal: true
on_click:
- button.press: restart_nspanel
##### Restart NSPanel Button - Boot Page #####
- name: Restart
platform: nextion
page_id: 8
component_id: 4
internal: true
on_click:
- button.press: restart_nspanel
## Delays initial info from HA to the display #####
- name: Nextion display
id: nextion_init
platform: template
device_class: connectivity
publish_initial_state: true
entity_category: diagnostic
icon: mdi:tablet-dashboard
##### API connection status
- name: Status
platform: status
id: api_status
on_state:
then:
- script.execute: watchdog
##### START - BUTTON CONFIGURATION #####
button:
###### Factory Reset button #####
- name: Factory reset
platform: factory_reset
id: nspanel_factory_reset
internal: false
disabled_by_default: true
icon: mdi:restart-alert
###### REBOOT BUTTON #####
- name: Restart
platform: restart
id: restart_nspanel
###### Power cycle Nextion Display ######
- name: Nextion display - Power cycle
id: screen_power_cycle
platform: template
internal: false
disabled_by_default: true
icon: mdi:power-cycle
entity_category: diagnostic
on_press:
- switch.turn_off: screen_power
- delay: 1s
- switch.turn_on: screen_power
##### START - NUMBER CONFIGURATION #####
number:
##### SCREEN BRIGHTNESS #####
- name: Display Brightness
id: display_brightness
platform: template
entity_category: config
unit_of_measurement: '%'
min_value: 1
max_value: 100
initial_value: 100
step: 1
restore_value: true
optimistic: true
set_action:
then:
- lambda: |-
id(display_brightness_global) = int(x);
disp1->send_command_printf("brightness=%i", int(x));
disp1->send_command_printf("settings.brightslider.val=%i", int(x));
if (current_page->state != "screensaver")
{
disp1->set_backlight_brightness(x/100);
current_brightness->update();
timer_dim->execute(current_page->state.c_str(), int(timeout_dim->state));
timer_sleep->execute(current_page->state.c_str(), int(timeout_sleep->state));
if (current_page->state == "settings") disp1->set_component_text_printf("bright_text", "%i%%", int(x));
}
##### SCREEN BRIGHTNESS DIMMED DOWN #####
- name: Display Brightness Dimdown
id: display_dim_brightness
platform: template
entity_category: config
unit_of_measurement: '%'
min_value: 1
max_value: 100
initial_value: 25
step: 1
restore_value: true
optimistic: true
set_action:
then:
- lambda: |-
id(display_dim_brightness_global) = int(x);
disp1->send_command_printf("brightness_dim=%i", int(x));
disp1->send_command_printf("settings.dimslider.val=%i", int(x));
if (current_page->state != "screensaver" and (current_brightness->state <= id(display_dim_brightness_global)))
{
set_brightness->execute(x);
timer_sleep->execute(current_page->state.c_str(), int(timeout_sleep->state));
if (current_page->state == "settings") disp1->set_component_text_printf("dim_text", "%i%%", int(x));
}
##### SCREEN BRIGHTNESS SLEEP #####
- name: Display Brightness Sleep
id: display_sleep_brightness
platform: template
entity_category: config
unit_of_measurement: '%'
min_value: 0
max_value: 100
initial_value: 0
step: 1
restore_value: true
optimistic: true
set_action:
then:
- lambda: |-
id(display_dim_brightness_global) = int(x);
disp1->send_command_printf("brightness_sleep=%i", int(x));
page_screensaver->execute();
##### Temperature Correction #####
- name: Temperature Correction
platform: template
id: temperature_correction
entity_category: config
unit_of_measurement: °C
min_value: -10
max_value: 10
initial_value: 0
step: 0.1
mode: box
restore_value: true
internal: false
optimistic: true
set_action:
- logger.log: Temperature correction changed.
- delay: 1s
- lambda: temp_nspanel->publish_state(temp_nspanel->raw_state);
##### Timers settings #####
- name: Timeout Page
platform: template
id: timeout_page
entity_category: config
min_value: 0
max_value: 86400
initial_value: 15
step: 1
restore_value: true
optimistic: true
icon: mdi:timer
unit_of_measurement: "s"
set_action:
- lambda: timer_page->execute(current_page->state.c_str(), int(x));
- name: Timeout Dimming
platform: template
id: timeout_dim
entity_category: config
min_value: 0
max_value: 86400
initial_value: 30
step: 1
restore_value: true
optimistic: true
icon: mdi:timer
unit_of_measurement: "s"
set_action:
- lambda: timer_dim->execute(current_page->state.c_str(), int(x));
- name: Timeout Sleep
platform: template
id: timeout_sleep
entity_category: config
min_value: 0
max_value: 86400
initial_value: 60
step: 1
restore_value: true
optimistic: true
icon: mdi:timer
unit_of_measurement: "s"
set_action:
- lambda: |-
timer_dim->execute(current_page->state.c_str(), int(timeout_dim->state));
timer_sleep->execute(current_page->state.c_str(), int(x));
##### START - SELECT CONFIGURATION #####
select:
- id: baud_rate
name: Baud rate
platform: template
options:
- "2400"
- "4800"
- "9600"
- "19200"
- "31250"
- "38400"
- "57600"
- "115200"
- "230400"
- "250000"
- "256000"
- "512000"
- "921600"
initial_option: "115200"
optimistic: true
restore_value: true
internal: false
entity_category: config
disabled_by_default: true
icon: mdi:swap-horizontal
on_value:
- lambda: set_baud_rate->execute(stoi(x), true);
- id: wakeup_page_name
name: Wake-up page
platform: template
options:
- buttonpage01
- buttonpage02
- buttonpage03
- buttonpage04
- climate
- entitypage01
- entitypage02
- entitypage03
- entitypage04
- home
- qrcode
initial_option: home
optimistic: true
restore_value: true
internal: false
entity_category: config
icon: mdi:page-next-outline
on_value:
- lambda: |-
static const char *const TAG = "select.wakeup_page_name";
ESP_LOGD(TAG, "New wake-up page selected: %s", x.c_str());
page_screensaver->execute();
##### START - SENSOR CONFIGURATION #####
sensor:
##### Blueprint status #####
# Bit # Settings step #
# 0 # reserved #
# 1 # page_home #
# 2 # qrcode #
# 3 # page_settings #
# 4 # relay_settings #
# 5 # global_settings #
# 6 # reserved #
# 7 # reserved #
##############################
- name: Blueprint
id: blueprint_status
platform: template
unit_of_measurement: "%"
accuracy_decimals: 1
entity_category: diagnostic
icon: mdi:link-variant
internal: false
disabled_by_default: false
filters:
- lambda: return (x / 62) * 100.0f;
on_value:
then:
- lambda: |-
static const char *const TAG = "sensor.blueprint_status";
ESP_LOGD(TAG, "Blueprint progress: %i%%", int(round(x)));
// Update api value on Nextion
disp1->send_command_printf("api=%i", (x > 99) ? 1 : 0);
##### INTERNAL TEMPERATURE SENSOR, ADC VALUE #####
- id: ntc_source
platform: adc
pin: 38
update_interval: 60s
attenuation: 11db
##### INTERNAL TEMPERATURE SENSOR, adc reading converted to resistance (calculation)#####
- id: resistance_sensor
platform: resistance
sensor: ntc_source
configuration: DOWNSTREAM
resistor: 11.2kOhm
##### INTERNAL TEMPERATURE SENSOR, resistance to temperature (calculation) #####
- id: temp_nspanel
name: Temperature
platform: ntc
sensor: resistance_sensor
unit_of_measurement: °C
internal: false
calibration:
b_constant: 3950
reference_temperature: 25°C
reference_resistance: 10kOhm
filters:
- lambda: |-
return x + temperature_correction->state;
on_value:
then:
# Show panel's temperature if API or Wi-Fi are out
- lambda: display_embedded_temp->execute();
###### Display Brightness GET VALUE FROM NSPanel SLIDER #####
- id: brightslider
name: brightness Slider
platform: nextion
variable_name: brightslider
internal: true
on_value:
then:
- number.set:
id: display_brightness
value: !lambda 'return int(x);'
- lambda: |-
timer_reset_all->execute("settings");
###### Display DIM Brightness GET VALUE FROM NSPanel SLIDER #####
- id: dimslider
name: dim brightness slider
platform: nextion
variable_name: dimslider
internal: true
on_value:
then:
- number.set:
id: display_dim_brightness
value: !lambda 'return int(x);'
- lambda: |-
timer_reset_all->execute("settings");
###### Display Brightness - Current value (%) #####
- id: current_brightness
name: Display Current brightness
platform: nextion
variable_name: dim
precision: 0
accuracy_decimals: 0
unit_of_measurement: "%"
icon: mdi:brightness-percent
internal: false
disabled_by_default: false
on_value:
then:
- lambda: |-
static const char *const TAG = "sensor.current_brightness";
ESP_LOGD(TAG, "Current brightness: %i%%", int(x));
###### Page Id - Current #####
- id: page_id
name: Page Id
platform: nextion
variable_name: dp
precision: 0
accuracy_decimals: 0
internal: true
entity_category: diagnostic
on_value:
then:
- lambda: |-
static const char *const TAG = "sensor.page_id";
ESP_LOGD(TAG, "New page Id: %i", int(x));
if (id(is_uploading_tft)) {
ESP_LOGD(TAG, "Skipping actions as a TFT upload is in progress");
} else if (x > id(page_names).size()) {
ESP_LOGW(TAG, "Invalid page index: %i", int(x));
} else if (current_page->state != id(page_names)[x].c_str()) {
current_page->publish_state(id(page_names)[x].c_str());
page_changed->execute(id(page_names)[x].c_str());
}
##### Display mode (1 = EU, 2 = US, 3 = US Landscape)
- id: display_mode
name: Display mode
platform: nextion
variable_name: display_mode
precision: 0
accuracy_decimals: 0
internal: false
icon: mdi:phone-rotate-portrait
entity_category: diagnostic
##### Charset (1 = International (original), 2 = CJK languages)
- name: Display charset
id: display_charset
platform: nextion
variable_name: charset
precision: 0
accuracy_decimals: 0
internal: false
icon: mdi:translate
entity_category: diagnostic
##### Wi-Fi Signal stregth
- name: RSSI
id: wifi_rssi
platform: wifi_signal
internal: false
disabled_by_default: false
icon: mdi:wifi
entity_category: diagnostic
##### START - SWITCH CONFIGURATION #####
switch:
##### Notification unread #####
- name: Notification unread
platform: template
id: notification_unread
entity_category: config
optimistic: true
restore_mode: ALWAYS_OFF
on_turn_on:
- wait_until:
condition:
- lambda: !lambda return (blueprint_status->state > 99);
- lambda: set_component_color->execute("home.bt_notific", id(home_notify_icon_color_unread));
on_turn_off:
- wait_until:
condition:
- lambda: !lambda return (blueprint_status->state > 99);
- lambda: set_component_color->execute("home.bt_notific", id(home_notify_icon_color_normal));
##### Notification sound #####
- name: Notification sound
platform: template
id: notification_sound
entity_category: config
optimistic: true
restore_mode: RESTORE_DEFAULT_OFF
# ##### PHYSICAL SWITCH 1 #####
# - name: Relay 1
# platform: gpio
# id: relay_1
# pin:
# number: 22
# restore_mode: RESTORE_DEFAULT_OFF
# on_turn_on:
# then:
# - script.execute: refresh_relays
# on_turn_off:
# then:
# - script.execute: refresh_relays
# ##### PHYSICAL SWITCH 2 ######
# - name: Relay 2
# platform: gpio
# id: relay_2
# pin:
# number: 19
# restore_mode: RESTORE_DEFAULT_OFF
# on_turn_on:
# then:
# - script.execute: refresh_relays
# on_turn_off:
# then:
# - script.execute: refresh_relays
##### DISPLAY ALWAYS ON #####
- name: Nextion display - Power
platform: gpio
id: screen_power
entity_category: diagnostic
pin:
number: 4
inverted: true
restore_mode: ALWAYS_ON
internal: true
disabled_by_default: false
on_turn_on:
- wait_until:
condition:
- lambda: !lambda return disp1->is_setup();
timeout: 20s
- lambda: |-
if (id(setup_sequence_completed)) {
nextion_init->publish_state(disp1->is_setup());
disp1->goto_page(wakeup_page_name->state.c_str());
}
on_turn_off:
- lambda: |-
nextion_init->publish_state(false);
##### Relay Local control #####
- name: Relay 1 Local
platform: template
id: relay1_local
entity_category: config
optimistic: true
restore_mode: RESTORE_DEFAULT_OFF
internal: true
on_turn_on:
- logger.log: "Relay 1 Local turned On!"
on_turn_off:
- logger.log: "Relay 1 Local turned Off!"
- name: Relay 2 Local
platform: template
id: relay2_local
entity_category: config
optimistic: true
restore_mode: RESTORE_DEFAULT_OFF
internal: true
on_turn_on:
- logger.log: "Relay 2 Local turned On!"
on_turn_off:
- logger.log: "Relay 2 Local turned Off!"
##### START - TEXT SENSOR CONFIGURATION #####
text_sensor:
##### Entity Id of the entity displayed on the detailed pages
- name: Detailed Entity
id: detailed_entity
platform: template
icon: mdi:tablet-dashboard
internal: false
disabled_by_default: false
##### Current page name #####
- name: Current page
id: current_page
platform: template
icon: mdi:tablet-dashboard
internal: false
disabled_by_default: false
- name: Notification Label
platform: template
id: notification_label
- name: Notification Text
platform: template
id: notification_text
##### NSPanel event sensor, the main action sensor - push to HA #####
- name: NSPanel event
platform: nextion
nextion_id: disp1
id: disp1_nspanel_event
component_name: nspanelevent
internal: true
filters:
- lambda: |-
x = x.c_str();
x.shrink_to_fit();
return x;
on_value:
then:
- lambda: |-
static const char *const TAG = "text_sensor.disp1_nspanel_event";
ESP_LOGW(TAG, "Starting");
DynamicJsonDocument doc(1024);
deserializeJson(doc, x);
std::string page = doc["page"];
std::string component = doc["component"];
if (not (component == "currentpage" and (page == "screensaver" or page == "home"))) timer_reset_all->execute(page.c_str());
std::string value = doc["value"];
std::string entity = detailed_entity->state.c_str(); // doc["entity"];
ESP_LOGW(TAG, "page: %s", page.c_str());
ESP_LOGW(TAG, "component: %s", component.c_str());
ESP_LOGW(TAG, "value: %s", value.c_str());
ESP_LOGW(TAG, "entity: %s", entity.c_str());
auto ha_event = new esphome::api::CustomAPIDevice();
ha_event->fire_homeassistant_event("esphome.nspanel_ha_blueprint",
{
{"type", "generic"},
{"page", page},
{"component", component},
{"value", value},
{"entity", entity}
});
##### NSPanel event - Execute actions from ESPHome - NO push to HA #####
- name: NSPanel local event
platform: nextion
nextion_id: disp1
id: disp1_local_event
component_name: localevent
internal: true
filters:
- lambda: |-
x = x.c_str();
x.shrink_to_fit();
return x;
on_value:
then:
- lambda: |-
static const char *const TAG = "text_sensor.localevent";
DynamicJsonDocument doc(1024);
deserializeJson(doc, x);
std::string page = doc["page"];
std::string event = doc["event"];
std::string component = doc["component"];
std::string key = doc["key"];
std::string value = doc["value"];
std::string entity = detailed_entity->state.c_str(); // doc["entity"];
int embedded = doc["embedded"];
std::string service = "";
// Send event to Home Assistant
if (event == "short_click" or event == "long_click") {
ha_button->execute(page.c_str(), component.c_str(), event.c_str());
} else if (event == "click" and page == "home" and component == "climate") {
detailed_entity->publish_state((id(is_embedded_thermostat)) ? "embedded_climate" : "");
disp1->set_component_value("climate.embedded", id(is_embedded_thermostat) ? 1 : 0);
disp1->goto_page("climate");
} else if (page == "light" or page == "climate" or page == "notification") { // Generic event
auto ha_event = new esphome::api::CustomAPIDevice();
ha_event->fire_homeassistant_event("esphome.nspanel_ha_blueprint", {
{"type", "generic"},
{"page", page},
{"event", event},
{"value", value},
{"entity", entity}
});
}
// page based actions
if (page == "alarm")
{
std::string code_format = doc["code_format"];
std::string code_arm_req = doc["code_arm_req"];
std::string title = doc["mui"];
if (code_format == "number" and (key == "disarm" or code_arm_req == "1"))
{
disp1->goto_page("keyb_num");
disp1->set_component_value("keyb_num.page_id", 23); //Calling from Alarm page
disp1->set_component_text_printf("keyb_num.domain", "%s", page.c_str());
disp1->set_component_text_printf("keyb_num.key", "%s", key.c_str());
disp1->set_component_text_printf("keyb_num.value", "%s", value.c_str());
disp1->set_component_text_printf("keyb_num.entity", "%s", entity.c_str());
disp1->set_component_text_printf("keyb_num.title", "%s", title.c_str());
}
else service_call_alarm_control_panel->execute(entity.c_str(), key.c_str(), code_format.c_str(), "");
}
else if (page == "climate") {
change_climate_state->execute((embedded==1), key.c_str(), value.c_str());
}
else if (page == "cover") {
if (key == "position") ha_call_service->execute("cover.set_cover_position", key.c_str(), value.c_str(), entity.c_str());
else ha_call_service->execute((std::string("cover.") + key.c_str()), "", "", entity.c_str());
}
else if (page == "fan") {
if (key == "stop" or value == "0") ha_call_service->execute("fan.turn_off", "", "", entity.c_str());
else ha_call_service->execute("fan.turn_on", key.c_str(), value.c_str(), entity.c_str());
}
else if (page == "keyb_num") {
std::string base_domain = doc["base_domain"];
if (base_domain == "alarm") {
std::string code_format = doc["code_format"];
std::string pin = doc["pin"];
service_call_alarm_control_panel->execute(entity.c_str(), key.c_str(), code_format.c_str(), pin.c_str());
}
else if (base_domain == "" or base_domain.empty()) base_domain = "home";
disp1->goto_page(base_domain.c_str());
}
else if (page == "light") ha_call_service->execute("light.turn_on", key.c_str(), value.c_str(), entity.c_str());
else if (page == "media_player") {
if (key == "volume_mute") ha_call_service->execute("media_player.volume_mute", "is_volume_muted", value.c_str(), entity.c_str());
else if (key == "volume_set") ha_call_service->execute("media_player.volume_set", "volume_level", to_string(stof(value) / 100), entity.c_str());
else if (not key.empty()) ha_call_service->execute((std::string("media_player.") + key.c_str()), "", "", entity.c_str());
}
##### Versioning #####
- id: version_blueprint
name: Version Blueprint
platform: template
entity_category: diagnostic
icon: mdi:tag-text-outline
internal: false
update_interval: never
lambda: |-
return {"unknown"};
on_value:
- lambda: |-
static const char *const TAG = "text_sensor.version_blueprint";
ESP_LOGD(TAG, "Blueprint version: %s", x.c_str());
disp1->set_component_text_printf("boot.bluep_version", "%s", x.c_str());
if (current_page->state == "boot") {
disp1->send_command_printf("tm_esphome.en=0");
page_boot->execute();
timer_reset_all->execute("boot");
}
check_versions->execute();
- id: version_esphome
name: Version ESPHome
platform: template
entity_category: diagnostic
icon: mdi:tag-text-outline
internal: false
lambda: |-
return {"${version}"};
on_value:
- lambda: |-
static const char *const TAG = "text_sensor.version_esphome";
ESP_LOGD(TAG, "ESPHome version: %s", x.c_str());
disp1->set_component_text_printf("boot.esph_version", x.c_str());
if (current_page->state == "boot") {
disp1->send_command_printf("tm_esphome.en=0");
page_boot->execute();
timer_reset_all->execute("boot");
}
check_versions->execute();
- id: version_tft
name: Version TFT
platform: nextion
component_name: boot.tft_version
entity_category: diagnostic
icon: mdi:tag-text-outline
internal: false
update_interval: never
on_value:
- lambda: |-
static const char *const TAG = "text_sensor.version_tft";
ESP_LOGD(TAG, "TFT version: %s", x.c_str());
if (current_page->state == "boot") {
disp1->send_command_printf("tm_esphome.en=0");
page_boot->execute();
timer_reset_all->execute("boot");
}
check_versions->execute();
### Scripts ######
script:
- id: change_climate_state
mode: restart
parameters:
embedded: bool
key: string
value: string
then:
- lambda: |-
if (id(is_uploading_tft)) change_climate_state->stop();
if (!embedded) {
if (key == "temperature" or key == "target_temp_high" or key == "target_temp_low")
ha_call_service->execute("climate.set_temperature", key.c_str(), to_string(stof(value) / 10), detailed_entity->state.c_str());
else if (key == "hvac_mode")
ha_call_service->execute("climate.set_hvac_mode", key.c_str(), value.c_str(), detailed_entity->state.c_str());
}
- id: check_versions
mode: restart
then:
- wait_until:
condition:
- lambda: |-
auto compareVersions = [](const char* version1, const char* version2) -> bool
{
int major1 = 0, minor1 = 0;
int major2 = 0, minor2 = 0;
sscanf(version1, "%d.%d", &major1, &minor1);
sscanf(version2, "%d.%d", &major2, &minor2);
return (major1 == major2) && (minor1 == minor2);
};
return (compareVersions("${version}", version_tft->state.c_str()) and compareVersions("${version}", version_blueprint->state.c_str()));
timeout: 60s
- lambda: |-
if (id(is_uploading_tft)) check_versions->stop();
static const char *const TAG = "script.check_versions";
auto compareVersions = [](const char* version1, const char* version2) -> bool
{
int major1 = 0, minor1 = 0;
int major2 = 0, minor2 = 0;
sscanf(version1, "%d.%d", &major1, &minor1);
sscanf(version2, "%d.%d", &major2, &minor2);
return (major1 == major2) && (minor1 == minor2);
};
ESP_LOGD(TAG, "Versions:");
ESP_LOGD(TAG, " ESPHome: ${version}");
ESP_LOGD(TAG, " TFT: %s", version_tft->state.c_str());
if (not compareVersions("${version}", version_tft->state.c_str())) ESP_LOGE(TAG, "TFT version mismatch!");
ESP_LOGD(TAG, " Blueprint: %s", version_blueprint->state.c_str());
if (not compareVersions("${version}", version_blueprint->state.c_str())) ESP_LOGE(TAG, "Blueprint version mismatch!");
auto ha_event = new esphome::api::CustomAPIDevice();
ha_event->fire_homeassistant_event("esphome.nspanel_ha_blueprint",
{
{"type", "version"},
{"tft", version_tft->state.c_str()},
{"esphome", "${version}"},
{"blueprint", version_blueprint->state.c_str()}
});
- id: display_embedded_temp
mode: restart
then:
- lambda: |-
if (id(embedded_indoor_temp) or (!wifi_component->is_connected()) or (!api_server->is_connected())) {
float unit_based_temperature = temp_nspanel->state;
std::string temp_units = "${temp_units}";
if (temp_units == "°F" || temp_units == "F" || temp_units == "°f" || temp_units == "f")
unit_based_temperature = (unit_based_temperature * 9 / 5) + 32;
disp1->set_component_text_printf("home.current_temp", "%.1f${temp_units}", unit_based_temperature);
}
- id: display_wrapped_text
mode: queued
parameters:
component: string
text_to_display: string
line_length_limit: uint
then:
- lambda: |-
int startPos = 0;
int endPos = 0;
std::string wrappedText = "";
if (text_to_display.find("\\r") != std::string::npos) {
wrappedText = text_to_display;
} else {
while (startPos < text_to_display.length()) {
while (text_to_display[startPos] == ' ' and startPos < text_to_display.length()) { startPos++; }
int endPos = startPos + line_length_limit;
if (endPos >= text_to_display.length()) endPos = text_to_display.length();
else
{
while (endPos > startPos && text_to_display[endPos] != ' ') { endPos--; }
if (endPos == startPos) endPos = startPos + line_length_limit; // Handle case of long word
}
wrappedText += text_to_display.substr(startPos, endPos-startPos);
if (endPos < text_to_display.length())
{
while (text_to_display[endPos] == ' ') { endPos--; }
if (endPos >= startPos) wrappedText += "\\r";
}
startPos = endPos + 1; // Skip the space
while (text_to_display[startPos] == ' ' and startPos < text_to_display.length()) { startPos++; }
}
}
disp1->set_component_text_printf(component.c_str(), "%s", wrappedText.c_str());
- id: global_settings
mode: restart
parameters:
blueprint_version: string
embedded_climate: bool
embedded_climate_friendly_name: string
embedded_indoor_temperature: bool
# temperature_unit_is_fahrenheit: bool # Deprecated
mui_please_confirm: string
mui_unavailable: string
screensaver_time: bool
screensaver_time_color: int32_t[]
then:
- lambda: |-
if (id(is_uploading_tft)) global_settings->stop();
static const char *const TAG = "script.global_settings";
// Blueprint version
ESP_LOGV(TAG, "Check Blueprint version");
version_blueprint->publish_state(blueprint_version.c_str());
check_versions->execute();
// Embedded thermostat
ESP_LOGV(TAG, "Load embedded thermostat");
id(is_embedded_thermostat) = embedded_climate;
// Indoor temperature
ESP_LOGV(TAG, "Set indoor temperature");
id(embedded_indoor_temp) = embedded_indoor_temperature;
display_embedded_temp->execute();
// MUI strings
id(mui_please_confirm_global) = mui_please_confirm;
id(mui_unavailable_global) = mui_unavailable;
// Screen saver page (sleep)
ESP_LOGV(TAG, "Setup screensaver page");
id(screensaver_display_time) = screensaver_time;
id(screensaver_display_time_color) = screensaver_time_color;
page_screensaver->execute();
if (current_page->state != "boot") {
// Update current page
ESP_LOGV(TAG, "Update current page");
page_changed->execute(current_page->state.c_str());
}
ESP_LOGV(TAG, "Current page: %s", current_page->state.c_str());
disp1->set_component_text_printf("boot.bluep_version", "%s", blueprint_version.c_str());
- if:
condition:
- text_sensor.state: # Is boot page visible?
id: current_page
state: boot
then:
- lambda: |-
ESP_LOGV("script.global_settings", "Boot page is visible");
- wait_until:
condition:
- not:
- text_sensor.state: # Is boot page visible?
id: current_page
state: 'boot'
timeout: 2s
- if:
condition:
- text_sensor.state: # Avoid this being called twice by multiple boot triggers
id: current_page
state: 'boot'
then:
- lambda: |-
ESP_LOGV("script.global_settings", "Boot page still visible");
- if:
condition:
switch.is_on: notification_sound
then:
- rtttl.play:
rtttl: 'two short:d=4,o=5,b=100:16e6,16e6'
- lambda: |-
ESP_LOGD("script.global_settings", "Jump to wake-up page: %s", wakeup_page_name->state.c_str());
disp1->goto_page(wakeup_page_name->state.c_str());
timer_reset_all->execute(wakeup_page_name->state.c_str());
- lambda: |-
ESP_LOGV("script.global_settings", "Finished");
- id: ha_button
mode: parallel
parameters:
page: string
component: string
command: string
then:
- lambda: |-
if (id(is_uploading_tft)) ha_button->stop();
timer_reset_all->execute(page.c_str());
auto ha_event = new esphome::api::CustomAPIDevice();
ha_event->fire_homeassistant_event("esphome.nspanel_ha_blueprint",
{
{"type", "button_click"},
{"page", page},
{"component", component},
{"command", command}
});
- id: ha_call_service
mode: restart
parameters:
service: string
key: string
value: string
entity: string
then:
- lambda: |-
if (id(is_uploading_tft)) ha_call_service->stop();
static const char *const TAG = "script.ha_call_service";
ESP_LOGV(TAG, "Calling Home Assisant service");
ESP_LOGV(TAG, " Type: service_call");
ESP_LOGV(TAG, " Service: %s", service.c_str());
ESP_LOGV(TAG, " Entity: %s", entity.c_str());
ESP_LOGV(TAG, " Key: %s", key.c_str());
ESP_LOGV(TAG, " Value: %s", value.c_str());
if (service != "" and not service.empty())
{
auto ha_event = new esphome::api::CustomAPIDevice();
ha_event->fire_homeassistant_event("esphome.nspanel_ha_blueprint",
{
{"type", "service_call"},
{"service", service},
{"entity", entity},
{"key", key},
{"value", value}
});
}
ESP_LOGV(TAG, "Finished");
- id: nextion_status
mode: restart
then:
- lambda: |-
static const char *const TAG = "script.nextion_status";
ESP_LOGD(TAG, "Nextion status:");
ESP_LOGD(TAG, " Is detected: %s", YESNO(disp1->is_detected()));
ESP_LOGD(TAG, " Is setup: %s", YESNO(disp1->is_setup()));
ESP_LOGD(TAG, " Queue size: %d", disp1->queue_size());
- id: notification_clear
mode: restart
then:
- lambda: |-
if (not id(is_uploading_tft)) {
notification_label->publish_state("");
notification_text->publish_state("");
notification_unread->turn_off();
refresh_notification->execute();
if (current_page->state == "notification") disp1->goto_page("home");
}
- id: open_entity_settings_page
mode: restart
parameters:
page: string
page_label: string
page_icon: string
page_icon_color: int32_t[]
entity: string
back_page: string
then:
- lambda: |-
if (not id(is_uploading_tft)) {
detailed_entity->publish_state(entity);
if (page == "alarm_control_panel") page = "alarm";
std::string cmd_page = std::string("page ") + page.c_str();
disp1->send_command_printf(cmd_page.c_str());
if (page_label.find("\\r") != std::string::npos)
page_label = page_label.replace(page_label.find("\\r"), 2, " ");
disp1->set_component_text_printf("page_label", "%s", page_label.c_str());
set_page_id->execute("back_page_id", back_page.c_str());
if (page == "climate")
disp1->set_component_value("embedded", (entity == "embedded_climate") ? 1 : 0);
else
{
if ((page_icon != std::string()) and (page_icon != ""))
disp1->set_component_text_printf("icon_state", "%s", page_icon.c_str());
set_component_color->execute("icon_state", page_icon_color);
}
}
- id: page_alarm
mode: restart
then: # There's nothing here so far
- id: page_blank
mode: restart
then:
- lambda: |-
static const char *const TAG = "script.page_blank";
ESP_LOGV(TAG, "Construct blank page");
disp1->set_component_text_printf("esp_version", "ESP: ${version}"); // ESPHome version
disp1->set_component_text_printf("framework", "%s", id(framework) == 1 ? "Arduino" :
(id(framework) == 2 ? "ESP-IDF" : "Unknown")); // ESPHome framework
disp1->send_command_printf("tm_esphome.en=0");
- id: page_boot
mode: restart
then:
- lambda: |-
static const char *const TAG = "script.page_boot";
ESP_LOGV(TAG, "Construct boot page");
set_brightness->execute(100);
disp1->set_component_text_printf("boot.esph_version", "${version}"); // ESPHome version
disp1->set_component_text_printf("framework", "%s", id(framework) == 1 ? "Arduino" :
(id(framework) == 2 ? "ESP-IDF" : "Unknown")); // ESPHome framework
disp1->send_command_printf("tm_esphome.en=0");
// disp1->show_component("bt_reboot");
- id: page_buttonpage
mode: restart
parameters:
page_number: uint
then: # There's nothing here so far
- id: page_buttonpage01
mode: restart
then:
- script.execute:
id: page_buttonpage
page_number: 1
- id: page_buttonpage02
mode: restart
then:
- script.execute:
id: page_buttonpage
page_number: 2
- id: page_buttonpage03
mode: restart
then:
- script.execute:
id: page_buttonpage
page_number: 3
- id: page_buttonpage04
mode: restart
then:
- script.execute:
id: page_buttonpage
page_number: 4
- id: page_changed
mode: restart
parameters:
page: string
then:
- lambda: |-
static const char *const TAG = "script.page_changed";
// Go to boot page if not initiated
if (page != "boot" and not nextion_init->state) disp1->goto_page("boot");
// Reset globals
if (page != "alarm" && //DEBOG
page != "climate" &&
page != "cover" &&
page != "fan" &&
page != "light" &&
page != "media_player" &&
page != "confirm" &&
page != "keyb_num") {
detailed_entity->publish_state("");
disp1->send_command_printf("back_page_id=0");
}
if (page != "media_player") {
id(last_volume_level) = 0;
id(last_media_duration) = 0;
id(last_media_position) = 0;
}
// Report new page to logs
ESP_LOGD(TAG, "New page: %s", page.c_str());
if (!detailed_entity->state.empty()) ESP_LOGD(TAG, "Entity shown: %s", detailed_entity->state.c_str());
// Reset timers
timer_reset_all->execute(page.c_str());
// Report new page to Home Assistant
ESP_LOGV(TAG, "Trigger HA event");
auto ha_event = new esphome::api::CustomAPIDevice();
ha_event->fire_homeassistant_event("esphome.nspanel_ha_blueprint",
{
{"type", "page_changed"},
{"page", page.c_str()},
{"entity", detailed_entity->state.c_str()}
});
// Call page constructor
if (page == "alarm") page_alarm->execute();
else if (page == "blank") page_blank->execute();
else if (page == "boot") page_boot->execute();
else if (page == "buttonpage01") page_buttonpage01->execute();
else if (page == "buttonpage02") page_buttonpage02->execute();
else if (page == "buttonpage03") page_buttonpage03->execute();
else if (page == "buttonpage04") page_buttonpage04->execute();
else if (page == "climate") page_climate->execute();
else if (page == "confirm") page_confirm->execute();
else if (page == "cover") page_cover->execute();
else if (page == "entitypage01") page_entitypage01->execute();
else if (page == "entitypage02") page_entitypage02->execute();
else if (page == "entitypage03") page_entitypage03->execute();
else if (page == "entitypage04") page_entitypage04->execute();
else if (page == "fan") page_fan->execute();
else if (page == "home") page_home->execute();
else if (page == "keyb_num") page_keyb_num->execute();
else if (page == "light") page_light->execute();
else if (page == "media_player") page_media_player->execute();
else if (page == "notification") page_notification->execute();
else if (page == "qrcode") page_qrcode->execute();
else if (page == "screensaver") page_screensaver->execute();
else if (page == "settings") page_settings->execute();
else if (page == "weather01") page_weather01->execute();
else if (page == "weather02") page_weather02->execute();
else if (page == "weather03") page_weather03->execute();
else if (page == "weather04") page_weather04->execute();
else if (page == "weather05") page_weather05->execute();
- id: page_climate
mode: restart
then: # There's nothing here so far
- id: page_confirm
mode: restart
then:
- lambda: |-
if (not id(is_uploading_tft)) display_wrapped_text->execute("confirm.title", id(mui_please_confirm_global).c_str(), 15);
- id: page_cover
mode: restart
then: # There's nothing here so far
- id: page_entitypage
mode: restart
parameters:
page_number: uint
then: # There's nothing here so far
- id: page_entitypage01
mode: restart
then:
- script.execute:
id: page_entitypage
page_number: 1
- id: page_entitypage02
mode: restart
then:
- script.execute:
id: page_entitypage
page_number: 2
- id: page_entitypage03
mode: restart
then:
- script.execute:
id: page_entitypage
page_number: 3
- id: page_entitypage04
mode: restart
then:
- script.execute:
id: page_entitypage
page_number: 4
- id: page_fan
mode: restart
then: # There's nothing here so far
- id: page_home
mode: restart
then:
- script.execute: refresh_relays
- script.execute: refresh_wifi_icon
- script.execute: refresh_notification
- id: page_keyb_num
mode: restart
then: # There's nothing here so far
- id: page_light
mode: restart
then: # There's nothing here so far
- id: page_media_player
mode: restart
then: # There's nothing here so far
- id: page_notification
mode: restart
then:
- lambda: |-
static const char *const TAG = "script.page_notification";
ESP_LOGV(TAG, "Updating notification page");
disp1->set_component_text_printf("notification.notifi_label", "%s", notification_label->state.c_str());
display_wrapped_text->execute("notification.notifi_text01", notification_text->state.c_str(), display_mode->state == 2 ? 23 : 32);
- id: page_qrcode
mode: restart
then: # There's nothing here so far
- id: page_screensaver
mode: restart
then:
- lambda: |-
if (current_page->state == "screensaver" and not id(is_uploading_tft)) {
static const char *const TAG = "script.page_screensaver";
ESP_LOGV(TAG, "Updating screensaver page");
set_page_id->execute("back_page_id", wakeup_page_name->state.c_str());
// disp1->send_command_printf("back_page_id=%i", id(wakeup_page_id));
if (id(screensaver_display_time)) {
disp1->show_component("text");
set_component_color->execute("screensaver.text",id(screensaver_display_time_color));
refresh_datetime->execute();
} else {
disp1->set_backlight_brightness(0.0f);
}
current_brightness->update();
}
- id: page_settings
mode: restart
then:
- lambda: |-
static const char *const TAG = "script.page_settings";
ESP_LOGV(TAG, "Construct settings page");
//disp1->set_component_text_printf("bt_sleep", "%s", (id(sleep_mode).state) ? "\uEA19" : "\uEA18"); //mdi:toggle-switch-outline or mdi:toggle-switch-off-outline
disp1->hide_component("lbl_sleep");
disp1->hide_component("bt_sleep");
- id: page_weather
mode: restart
parameters:
page_number: uint
then: # There's nothing here so far
- id: page_weather01
mode: restart
then:
- script.execute:
id: page_weather
page_number: 1
- id: page_weather02
mode: restart
then:
- script.execute:
id: page_weather
page_number: 2
- id: page_weather03
mode: restart
then:
- script.execute:
id: page_weather
page_number: 3
- id: page_weather04
mode: restart
then:
- script.execute:
id: page_weather
page_number: 4
- id: page_weather05
mode: restart
then:
- script.execute:
id: page_weather
page_number: 5
- id: refresh_datetime
mode: restart
then:
- lambda: |-
static const char *const TAG = "script.refresh_datetime";
ESP_LOGV(TAG, "Updating time display");
std::string time_format_str = id(mui_time_format);
if (time_format_str.find("%-H") != std::string::npos) {
time_format_str = time_format_str.replace(time_format_str.find("%-H"), sizeof("%-H")-1,
to_string((int)(id(time_provider).now().hour)));
}
if (time_format_str.find("%-I") != std::string::npos) {
if (id(time_provider).now().hour>12) {
time_format_str = time_format_str.replace(time_format_str.find("%-I"), sizeof("%-I")-1,
to_string((int)(id(time_provider).now().hour-12)));
} else if (id(time_provider).now().hour==0) {
time_format_str = time_format_str.replace(time_format_str.find("%-I"), sizeof("%-I")-1, "12");
} else {
time_format_str = time_format_str.replace(time_format_str.find("%-I"), sizeof("%-I")-1,
to_string((int)(id(time_provider).now().hour)));
}
}
std::string meridiem_text = (id(time_provider).now().hour<12) ? id(mui_meridiem)[0] : id(mui_meridiem)[1];
if (current_page->state == "screensaver" and id(screensaver_display_time)) {
ESP_LOGV(TAG, "Updating time on screensaver page");
std::string time_format_str_sleep = time_format_str;
if (time_format_str_sleep.find("%p") != std::string::npos)
time_format_str_sleep.replace(time_format_str_sleep.find("%p"), sizeof("%p")-1, meridiem_text.c_str());
disp1->set_component_text_printf("text", "%s", id(time_provider).now().strftime(time_format_str_sleep).c_str());
}
ESP_LOGV(TAG, "Updating home page meridiem");
disp1->set_component_text_printf("home.meridiem", "%s", (time_format_str.find("%p") != std::string::npos) ? meridiem_text.c_str() : " ");
ESP_LOGV(TAG, "Updating home page time");
disp1->set_component_text_printf("home.time", "%s", id(time_provider).now().strftime(time_format_str).c_str());
- id: refresh_notification
mode: restart
then:
- wait_until:
condition:
- lambda: !lambda return id(setup_sequence_completed);
- lambda: |-
static const char *const TAG = "script.refresh_notification";
bool is_notification = ((not notification_text->state.empty()) or (not notification_label->state.empty()));
ESP_LOGV(TAG, "Notification: %s", YESNO(is_notification));
disp1->send_command_printf("is_notification=%i", is_notification ? 0 : 1);
if (current_page->state == "home") {
if (is_notification) {
disp1->show_component("bt_notific");
} else {
disp1->hide_component("bt_notific");
}
}
- wait_until:
condition:
- lambda: return (blueprint_status->state > 99);
- lambda: |-
set_component_color->execute("home.bt_notific", notification_unread->state ? id(home_notify_icon_color_unread) : id(home_notify_icon_color_normal));
- id: refresh_relays
mode: restart
then:
- lambda: |-
// Chips - Relays
disp1->set_component_text_printf("home.icon_top_01", "%s", (relay_1->state) ? id(home_relay1_icon).c_str() : "\uFFFF");
disp1->set_component_text_printf("home.icon_top_02", "%s", (relay_2->state) ? id(home_relay2_icon).c_str() : "\uFFFF");
// Hardware buttons bars - Fallback mode
if (relay1_local->state) disp1->send_command_printf("home.left_bt_pic.val=%i", (relay_1->state) ? 1 : 0);
if (relay2_local->state) disp1->send_command_printf("home.right_bt_pic.val=%i", (relay_2->state) ? 1 : 0);
- id: refresh_wifi_icon
mode: restart
then:
- lambda: |-
if (nextion_init->state) {
// Update Wi-Fi icon color
disp1->set_component_font_color("home.wifi_icon", (blueprint_status->state > 99) ? (wifi_rssi->state > -70 ? 33808 : 64992) : 63488);
// Update Wi-Fi icon
disp1->set_component_text_printf("home.wifi_icon", "%s",
wifi_component->is_connected() ?
(api_server->is_connected() ?
((blueprint_status->state > 99) ? "\uE5A8" : // mdi:wifi - All right!
"\uE7CF") : // mdi:home-assistant - Blueprint is out
"\uF256") : // mdi:api-off
"\uE5A9"); // mdi:wifi-off
}
- id: relay_settings
mode: restart
parameters:
relay1_local_control: bool
relay1_icon: string
relay1_icon_color: int
relay1_fallback: bool
relay2_local_control: bool
relay2_icon: string
relay2_icon_color: int
relay2_fallback: bool
then:
- if:
condition:
lambda: 'return id(is_uploading_tft);'
then:
- script.stop: relay_settings
- lambda: |-
static const char *const TAG = "script.relay_settings";
// Relays
ESP_LOGV(TAG, "Setup relays");
relay1_local->publish_state(relay1_local_control);
relay2_local->publish_state(relay2_local_control);
id(relay_1_fallback) = relay1_fallback;
id(relay_2_fallback) = relay2_fallback;
disp1->set_component_font_color("home.icon_top_01", relay1_icon_color);
disp1->set_component_font_color("home.icon_top_02", relay2_icon_color);
disp1->set_component_text_printf("home.icon_top_01", "%s", relay1_icon.c_str());
disp1->set_component_text_printf("home.icon_top_02", "%s", relay2_icon.c_str());
id(home_relay1_icon) = relay1_icon.c_str();
id(home_relay2_icon) = relay2_icon.c_str();
id(home_relay1_icon_color) = relay1_icon_color;
id(home_relay2_icon_color) = relay2_icon_color;
ESP_LOGV(TAG, "Finished");
- id: restore_settings
mode: restart
then:
- lambda: |-
ESP_LOGD("script.restore_settings", "Restoring settings");
#ifdef ARDUINO
id(framework) = 1;
#elif defined(USE_ESP_IDF)
id(framework) = 2;
#endif
// ESP_LOGV(TAG, "Restoring wake-up page selector");
// auto wakeup_page_name_call = id(wakeup_page_name).make_call();
// wakeup_page_name_call.set_option(id(page_names)[id(wakeup_page_id)]);
// wakeup_page_name_call.perform();
// id(is_restored_settings) = true;
- wait_until:
condition:
- lambda: return (not isnan(stoi(baud_rate->state)));
- lambda: |-
ESP_LOGV("script.restore_settings", "Restoring baud rate");
set_baud_rate->execute(stoi(baud_rate->state), true);
ESP_LOGV("script.restore_settings", "Done!");
- id: service_call_alarm_control_panel
mode: restart
parameters:
entity: string
key: string
code_format: string
pin: string
then:
- lambda: |-
std::string service = "";
if (key == "home") service = "alarm_control_panel.alarm_arm_home";
else if (key == "away") service = "alarm_control_panel.alarm_arm_away";
else if (key == "night") service = "alarm_control_panel.alarm_arm_night";
else if (key == "vacation") service = "alarm_control_panel.alarm_arm_vacation";
else if (key == "bypass") service = "alarm_control_panel.alarm_arm_custom_bypass";
else if (key == "disarm") service = "alarm_control_panel.alarm_disarm";
if (service != "" and not service.empty())
{
HomeassistantServiceResponse resp;
HomeassistantServiceMap resp_kv;
resp.service = service.c_str();
resp_kv.key = "entity_id";
resp_kv.value = entity.c_str();
resp.data.push_back(resp_kv);
if (pin != "" and not pin.empty())
{
resp_kv.key = "code";
resp_kv.value = pin.c_str();
resp.data.push_back(resp_kv);
}
api_server->send_homeassistant_service_call(resp);
}
- id: set_baud_rate
mode: restart
parameters:
baud_rate: uint32_t
definitive: bool
then:
- if:
condition:
- lambda: !lambda return (tf_uart->get_baud_rate() != baud_rate);
then:
- lambda: |-
static const char *const TAG = "script.set_baud_rate";
ESP_LOGD(TAG, "Baud rate changing from %" PRIu32 " to %" PRIu32 " bps", tf_uart->get_baud_rate(), baud_rate);
ESP_LOGD(TAG, "Flush UART");
- wait_until:
condition:
- lambda: !lambda return (tf_uart->available() < 1);
timeout: 5s
- lambda: |-
static const char *const TAG = "script.set_baud_rate";
ESP_LOGD(TAG, "Sending instruction '%s=%" PRIu32 "' to Nextion", definitive ? "bauds" : "baud", baud_rate);
disp1->send_command_printf("%s=%" PRIu32, definitive ? "bauds" : "baud", baud_rate);
ESP_LOGD(TAG, "Flush UART");
- wait_until:
condition:
- lambda: !lambda return (tf_uart->available() < 1);
timeout: 5s
- lambda: |-
static const char *const TAG = "script.set_baud_rate";
ESP_LOGD(TAG, "Set ESPHome new baud rate to %" PRIu32 " bps", baud_rate);
tf_uart->set_baud_rate(baud_rate);
tf_uart->load_settings();
ESP_LOGD(TAG, "Current baud rate: %" PRIu32 " bps", tf_uart->get_baud_rate());
- id: set_brightness
mode: restart
parameters:
brightness: uint
then:
- lambda: |-
static const char *const TAG = "script.set_brightness";
ESP_LOGD(TAG, "brightness: %i%%", brightness);
if (brightness == id(display_brightness_global) and current_page->state != "screensaver")
disp1->send_command_printf("wakeup_timer.en=1");
else
disp1->set_backlight_brightness(static_cast<float>(brightness) / 100.0f);
current_brightness->update();
- delay: 5s
- lambda: current_brightness->update();
- id: set_climate
mode: restart
parameters:
current_temp: float
supported_features: int
target_temp: float
target_temp_high: float
target_temp_low: float
temp_step: uint
total_steps: uint
temp_offset: int
climate_icon: string
embedded_climate: bool
then:
- lambda: |-
if (id(is_uploading_tft)) set_climate->stop();
static const char *const TAG = "script.set_climate";
ESP_LOGD(TAG, "Starting");
ESP_LOGD(TAG, " current_temp: %f", current_temp);
ESP_LOGD(TAG, " supported_features: %i", supported_features);
ESP_LOGD(TAG, " target_temp: %f", target_temp);
ESP_LOGD(TAG, " target_temp_high: %f", target_temp_high);
ESP_LOGD(TAG, " target_temp_low: %f", target_temp_low);
ESP_LOGD(TAG, " temp_step: %d", temp_step);
ESP_LOGD(TAG, " total_steps: %d", total_steps);
ESP_LOGD(TAG, " temp_offset: %i", temp_offset);
ESP_LOGD(TAG, " climate_icon: %s", climate_icon.c_str());
ESP_LOGD(TAG, " embedded_climate: %s", YESNO(embedded_climate));
if (current_page->state == "climate") {
ESP_LOGD(TAG, "Page climate is visible");
disp1->send_command_printf("climateslider.maxval=%i", total_steps);
disp1->send_command_printf("slider_high.maxval=%i", total_steps);
disp1->send_command_printf("slider_low.maxval=%i", total_steps);
disp1->set_component_value("temp_offset", temp_offset);
disp1->set_component_value("temp_step", temp_step);
disp1->show_component("current_temp");
if (current_temp > -999)
disp1->set_component_text_printf("current_temp", "%.1f°", current_temp);
else
disp1->set_component_text_printf("current_temp", id(mui_unavailable_global).c_str());
if (target_temp > -999) { // Target temp enabled
disp1->set_component_value("active_slider", 0);
disp1->hide_component("slider_high");
disp1->hide_component("slider_low");
disp1->hide_component("target_low");
disp1->set_component_text_printf("target_high", "%.1f°", target_temp);
disp1->show_component("target_high");
disp1->set_component_value("climateslider", round(((10*target_temp) - temp_offset) / temp_step));
disp1->show_component("climateslider");
} else {
disp1->hide_component("slider_high");
if (target_temp_low > -999) { // Target temp low enabled
disp1->set_component_value("active_slider", 2);
disp1->set_component_text_printf("target_low", "%.1f°", target_temp_low);
disp1->show_component("target_low");
disp1->set_component_value("slider_low", round(((10*target_temp_low) - temp_offset) / temp_step));
disp1->show_component("slider_low");
} else {
disp1->hide_component("target_low");
disp1->hide_component("slider_low");
}
if (target_temp_high > -999) { // Target temp high enabled
disp1->set_component_value("active_slider", 1);
disp1->set_component_text_printf("target_high", "%.1f°", target_temp_high);
disp1->show_component("target_high");
disp1->set_component_value("slider_high", round(((10*target_temp_high) - temp_offset) / temp_step));
disp1->show_component("slider_high");
} else {
disp1->hide_component("target_high");
disp1->hide_component("slider_high");
}
}
if (target_temp > -999 or target_temp_high > -999 or target_temp_low > -999) {
disp1->set_component_text_printf("target_icon", "%s", climate_icon.c_str());
disp1->show_component("target_icon");
disp1->show_component("decrease_temp");
disp1->show_component("increase_temp");
} else {
disp1->hide_component("target_icon");
disp1->hide_component("decrease_temp");
disp1->hide_component("increase_temp");
}
disp1->set_component_value("embedded", (embedded_climate) ? 1 : 0);
}
ESP_LOGD(TAG, "Finished");
- id: set_component_color
mode: queued
parameters:
component: string
foreground: int32_t[]
then:
- lambda: |-
if (id(is_uploading_tft)) set_component_color->stop();
static const char *const TAG = "script.set_component_color";
ESP_LOGVV(TAG, "Starting:");
ESP_LOGVV(TAG, " Component: %s", component.c_str());
int fg565 = -1;
// Foreground
if (foreground.size() == 3 and
foreground[0] >= 0 and
foreground[1] >= 0 and
foreground[2] >= 0) {
ESP_LOGVV(TAG, " Foreground: {%i, %i, %i}", foreground[0], foreground[1], foreground[2]);
fg565 = ((foreground[0] & 0b11111000) << 8) | ((foreground[1] & 0b11111100) << 3) | (foreground[2] >> 3);
}
else if (foreground.size() == 1) fg565 = foreground[0];
else {
ESP_LOGE(TAG, " Component: %s", component.c_str());
ESP_LOGE(TAG, " Foreground size: %i", foreground.size());
fg565 = -1;
}
ESP_LOGVV(TAG, " Foreground: %i", fg565);
if (fg565 >= 0) disp1->set_component_font_color(component.c_str(), fg565);
- id: set_page_id
mode: queued
parameters:
variable: string
page: string
then:
- lambda: |-
static const char *const TAG = "script.set_page_id";
ESP_LOGV(TAG, "Starting:");
ESP_LOGV(TAG, " Variable: %s", variable.c_str());
ESP_LOGV(TAG, " Page: %s", page.c_str());
auto pageIndex = [](const std::string& page_name) -> uint8_t {
for (uint8_t i = 0; i < id(page_names).size(); ++i) {
if (id(page_names)[i] == page_name) {
return i; // Return the index if found
}
}
return 0u; // Return 0 (home page) if not found
};
uint detected_page_id = pageIndex(page.c_str());
ESP_LOGV(TAG, "%s=%i", variable.c_str(), detected_page_id);
disp1->send_command_printf("%s=%i", variable.c_str(), detected_page_id);
- id: setup_sequence
mode: restart
then:
- lambda: |-
static const char *const TAG = "script.setup_sequence";
ESP_LOGD(TAG, "Starting Nextion setup sequence");
ESP_LOGD(TAG, "Fetching Page Id");
page_id->update();
- wait_until:
condition:
- lambda: !lambda return (not isnan(page_id->state));
timeout: 15s
- lambda: |-
static const char *const TAG = "script.setup_sequence";
ESP_LOGD(TAG, "Fetching charset");
display_charset->update();
- wait_until:
condition:
- lambda: !lambda return (not isnan(display_charset->state));
timeout: 5s
- lambda: |-
static const char *const TAG = "script.setup_sequence";
ESP_LOGD(TAG, "Fetching display mode");
display_mode->update();
- wait_until:
condition:
- lambda: !lambda return (not isnan(display_mode->state));
timeout: 5s
- if:
condition:
- lambda: !lambda return (not isnan(display_mode->state));
then: # Project's TFT detected
- lambda: |-
static const char *const TAG = "script.setup_sequence";
ESP_LOGD(TAG, "Goto page Boot");
disp1->goto_page("boot");
ESP_LOGD(TAG, "Fetching TFT version");
version_tft->update();
- wait_until:
condition:
- lambda: !lambda return (not version_tft->state.empty());
timeout: 5s
- lambda: |-
static const char *const TAG = "script.setup_sequence";
ESP_LOGD(TAG, "Wait for Wi-Fi");
- wait_until:
condition:
- lambda: !lambda return (wifi_component->is_connected());
timeout: 10s
- if:
condition:
- lambda: !lambda return (wifi_component->is_connected());
then: # Wi-Fi connected
- lambda: |-
static const char *const TAG = "script.setup_sequence";
if (current_page->state == "boot") {
ESP_LOGD(TAG, "Publish IP address on screen");
disp1->set_component_text_printf("boot.ip_addr", "%s", network::get_ip_address().str().c_str());
set_brightness->execute(100);
}
ESP_LOGD(TAG, "Wait for API");
- wait_until:
condition:
- lambda: !lambda return (api_server->is_connected());
timeout: 10s
- if:
condition:
- lambda: !lambda return (api_server->is_connected());
then: # API connected
- lambda: |-
static const char *const TAG = "script.setup_sequence";
ESP_LOGD(TAG, "Publish IP address on screen");
ESP_LOGD(TAG, "Report setup to Home Assistant");
auto ha_event = new esphome::api::CustomAPIDevice();
ha_event->fire_homeassistant_event("esphome.nspanel_ha_blueprint",
{
{"type", "boot"},
{"step", "start"}
});
else: # API not connected
- lambda: |-
static const char *const TAG = "script.setup_sequence";
ESP_LOGE(TAG, "API not available");
else: # Wi-Fi not connected
- lambda: |-
static const char *const TAG = "script.setup_sequence";
ESP_LOGE(TAG, "Wi-Fi not available");
- lambda: |-
static const char *const TAG = "script.setup_sequence";
ESP_LOGE(TAG, "Wi-Fi not available");
- wait_until:
condition:
- lambda: !lambda return id(setup_sequence_completed);
timeout: 1s
- lambda: |-
static const char *const TAG = "script.setup_sequence";
ESP_LOGD(TAG, "Set dimming values");
display_brightness->publish_state(id(display_brightness_global));
display_dim_brightness->publish_state(id(display_dim_brightness_global));
set_brightness->execute(id(display_brightness_global));
ESP_LOGD(TAG, "Set page Settings");
disp1->send_command_printf("brightness=%i", id(display_brightness_global));
disp1->send_command_printf("settings.brightslider.val=%i", id(display_brightness_global));
disp1->send_command_printf("brightness_dim=%i", id(display_dim_brightness_global));
disp1->send_command_printf("settings.dimslider.val=%i", id(display_dim_brightness_global));
disp1->send_command_printf("brightness_sleep=%i", int(display_sleep_brightness->state));
ESP_LOGD(TAG, "Report to Home Assistant");
nextion_init->publish_state(disp1->is_setup());
if (api_server->is_connected() and disp1->is_setup()) {
auto ha_event = new esphome::api::CustomAPIDevice();
ha_event->fire_homeassistant_event("esphome.nspanel_ha_blueprint",
{
{"type", "boot"},
{"step", "nextion_init"}
});
}
// Chips icon size
ESP_LOGV(TAG, "Adjusting icon's sizes");
for (int i = 1; i <= 10; ++i) {
disp1->send_command_printf("home.icon_top_%02d.font=%i", i, id(home_chip_font_size));
}
// Custom buttons icon size
ESP_LOGV(TAG, "Adjusting custom buttons sizes");
for (int i = 1; i <= 7; ++i) {
disp1->send_command_printf("home.button%02d.font=%i", i, id(home_custom_buttons_font_size));
}
disp1->send_command_printf("home.bt_notific.font=%i", id(home_custom_buttons_font_size));
disp1->send_command_printf("home.bt_qrcode.font=%i", id(home_custom_buttons_font_size));
disp1->send_command_printf("home.bt_entities.font=%i", id(home_custom_buttons_font_size));
disp1->send_command_printf("home.wifi_icon.font=%i", id(home_chip_font_size));
ESP_LOGV(TAG, "Restoring relay's icons");
disp1->set_component_text_printf("home.icon_top_01", "%s", id(home_relay1_icon).c_str());
disp1->set_component_text_printf("home.icon_top_02", "%s", id(home_relay2_icon).c_str());
timer_reset_all->execute("boot");
notification_clear->execute();
id(setup_sequence_completed) = true;
ESP_LOGD(TAG, "Wait for leaving boot page");
- wait_until:
condition:
- not:
- text_sensor.state: # Is boot page visible?
id: current_page
state: boot
timeout: 10s
- lambda: |-
if (current_page->state == "boot") disp1->goto_page(wakeup_page_name->state.c_str());
else: # Unknown TFT
- lambda: |-
static const char *const TAG = "script.setup_sequence";
ESP_LOGE(TAG, "No compatible TFT detected");
ESP_LOGE(TAG, "Display mode: %f", display_mode->state);
- lambda: |-
static const char *const TAG = "script.setup_sequence";
ESP_LOGD(TAG, "Nextion setup sequence finished!");
- id: stop_all
mode: restart
then:
- lambda: |-
static const char *const TAG = "script.stop_all";
ESP_LOGD(TAG, "Stopping scripts...");
change_climate_state->stop();
check_versions->stop();
display_embedded_temp->stop();
display_wrapped_text->stop();
global_settings->stop();
ha_button->stop();
ha_call_service->stop();
nextion_status->stop();
notification_clear->stop();
open_entity_settings_page->stop();
page_alarm->stop();
page_blank->stop();
page_boot->stop();
page_buttonpage01->stop();
page_buttonpage02->stop();
page_buttonpage03->stop();
page_buttonpage04->stop();
page_buttonpage->stop();
page_climate->stop();
page_changed->stop();
page_confirm->stop();
page_cover->stop();
page_entitypage01->stop();
page_entitypage02->stop();
page_entitypage03->stop();
page_entitypage04->stop();
page_entitypage->stop();
page_fan->stop();
page_home->stop();
page_keyb_num->stop();
page_light->stop();
page_media_player->stop();
page_notification->stop();
page_qrcode->stop();
page_screensaver->stop();
page_settings->stop();
page_weather01->stop();
page_weather02->stop();
page_weather03->stop();
page_weather04->stop();
page_weather05->stop();
page_weather->stop();
refresh_datetime->stop();
refresh_relays->stop();
refresh_wifi_icon->stop();
relay_settings->stop();
service_call_alarm_control_panel->stop();
set_baud_rate->stop();
set_brightness->stop();
set_climate->stop();
set_component_color->stop();
set_page_id->stop();
setup_sequence->stop();
timer_dim->stop();
timer_page->stop();
timer_reset_all->stop();
timer_sleep->stop();
update_alarm_icon->stop();
update_climate_icon->stop();
watchdog->stop();
ESP_LOGD(TAG, "Finished");
###### Timers ######
- id: timer_reset_all # Global timer reset - Triggered with a touch on the screen
mode: restart
parameters:
page: string
then:
- lambda: |-
ESP_LOGV("script.timer_reset_all", "Reset timers");
timer_page->execute(page.c_str(), int(timeout_page->state));
timer_dim->execute(page.c_str(), int(timeout_dim->state));
timer_sleep->execute(page.c_str(), int(timeout_sleep->state));
- id: timer_page # Handles the fallback to home page after a timeout
mode: restart
parameters:
page: string
timeout: uint
then:
- lambda: |-
ESP_LOGV("script.timer_page", "Reset timer: %is", timeout);
- if:
condition:
- lambda: |-
return (timeout >= 1 and
page != "boot" and
page != "confirm" and
page != "home" and
page != "notification" and
page != "screensaver");
then:
- delay: !lambda return (timeout *1000);
- lambda: |-
ESP_LOGV("script.timer_page", "Timed out on page: %s", current_page->state.c_str());
if (timeout >= 1 and
current_page->state != "boot" and
current_page->state != "confirm" and
current_page->state != "home" and
current_page->state != "notification" and
current_page->state != "screensaver")
{
ESP_LOGD("script.timer_page", "Fallback to page Home");
disp1->goto_page("home");
}
- id: timer_dim # Handles the brightness dimming after a timeout
mode: restart
parameters:
page: string
timeout: uint
then:
- lambda: |-
ESP_LOGV("script.timer_dim", "Reset timer: %is", timeout);
if (current_brightness->state <= id(display_dim_brightness_global)
and page != "screensaver"
and page != "boot"
and page != "blank-screensaver") {
ESP_LOGD("script.timer_dim", "Waking up on page: %s", page.c_str());
set_brightness->execute(id(display_brightness_global));
}
- if:
condition:
- lambda: !lambda return (timeout >= 1);
then:
- delay: !lambda return (timeout *1000);
- lambda: |-
if (current_page->state != "screensaver" and
current_page->state != "blank-screensaver" and
current_page->state != "boot" and
timeout >= 1) {
set_brightness->execute(id(display_dim_brightness_global));
}
- id: timer_sleep # Handles the sleep (go to screensaver page) after a timeout
mode: restart
parameters:
page: string
timeout: uint
then:
- lambda: |-
ESP_LOGV("script.timer_sleep", "Reset timer: %is", timeout);
- if:
condition:
- lambda: |-
return (timeout >= 1 and current_page->state != "screensaver" and current_page->state != "boot");
then:
- delay: !lambda return (timeout *1000);
- lambda: |-
if (current_page->state != "screensaver" and
current_page->state != "boot" and
timeout >= 1) {
ESP_LOGD("script.timer_sleep", "Going to sleep from page %s", current_page->state.c_str());
disp1->goto_page("screensaver");
set_brightness->execute(display_sleep_brightness->state);
}
- id: update_alarm_icon # To do: Move to blueprint
mode: restart
parameters:
component: string
state: string
then:
- lambda: |-
std::string alarm_icon = "\uEECC"; //mdi:shield-alert-outline
int alarm_color = 65535;
if (state == "disarmed")
{
alarm_icon = "\uE99B"; //mdi:shield-off-outline
alarm_color = 65535;
}
else if (state == "armed_home")
{
alarm_icon = "\uECCA"; //mdi:shield-home-outline
alarm_color = 19818;
}
else if (state == "armed_away")
{
alarm_icon = "\uECCB"; //mdi:shield-lock-outline
alarm_color = 19818;
}
else if (state == "armed_night")
{
alarm_icon = "\uF828"; //mdi:shield-moon-outline
alarm_color = 19818;
}
else if (state == "armed_vacation")
{
alarm_icon = "\uECC6"; //mdi:shield-airplane-outline
alarm_color = 19818;
}
else if (state == "armed_custom_bypass")
{
alarm_icon = "\uE77F"; //mdi:shield-half-full
alarm_color = 19818;
}
else if (state == "pending" or state == "arming")
{
alarm_icon = "\uE498"; //mdi:shield-outline
alarm_color = 65024;
}
else if (state == "disarming")
{
alarm_icon = "\uE99B"; //mdi:shield-off-outline
alarm_color = 65024;
}
else if (state == "triggered")
{
alarm_icon = "\uEECC"; //mdi:shield-alert-outline
alarm_color = 63488;
}
disp1->set_component_text_printf(component.c_str(), alarm_icon.c_str());
disp1->set_component_font_color(component.c_str(), alarm_color);
- id: update_climate_icon
mode: restart
parameters:
component: string
action: uint
mode: uint
then:
- lambda: |-
switch (action) // CLIMATE_ACTION_OFF = 0, CLIMATE_ACTION_COOLING = 2, CLIMATE_ACTION_HEATING = 3, CLIMATE_ACTION_IDLE = 4, CLIMATE_ACTION_DRYING = 5, CLIMATE_ACTION_FAN = 6
{
case 0: //CLIMATE_ACTION_OFF
switch (mode) // CLIMATE_MODE_OFF = 0, CLIMATE_MODE_HEAT_COOL = 1, CLIMATE_MODE_COOL = 2, CLIMATE_MODE_HEAT = 3, CLIMATE_MODE_FAN_ONLY = 4, CLIMATE_MODE_DRY = 5, CLIMATE_MODE_AUTO = 6
{
case 0: //CLIMATE_MODE_OFF
disp1->set_component_text_printf(component.c_str(), "%s", "\uFFFF"); // (E424) Don't show icon when off
disp1->set_component_font_color(component.c_str(), 35921); // grey (off)
break;
case 1: //CLIMATE_MODE_HEAT_COOL
disp1->set_component_text_printf(component.c_str(), "%s", "\uE069"); // mdi:autorenew
disp1->set_component_font_color(component.c_str(), 35921); // grey (off)
break;
case 2: //CLIMATE_MODE_COOL
disp1->set_component_text_printf(component.c_str(), "%s", "\uE716"); // mdi:snowflake
disp1->set_component_font_color(component.c_str(), 35921); // grey (off)
break;
case 3: //CLIMATE_MODE_HEAT
disp1->set_component_text_printf(component.c_str(), "%s", "\uE237"); // mdi:fire
disp1->set_component_font_color(component.c_str(), 35921); // grey (off)
break;
case 4: //CLIMATE_MODE_FAN_ONLY
disp1->set_component_text_printf(component.c_str(), "%s", "\uE20F"); // mdi:fan
disp1->set_component_font_color(component.c_str(), 35921); // grey (off)
break;
case 5: //CLIMATE_MODE_DRY
disp1->set_component_text_printf(component.c_str(), "%s", "\uE58D"); // mdi:water-percent
disp1->set_component_font_color(component.c_str(), 35921); // grey (off)
break;
case 6: //CLIMATE_MODE_AUTO
disp1->set_component_text_printf(component.c_str(), "%s", "\uEE8D"); // mdi:calendar-sync
disp1->set_component_font_color(component.c_str(), 35921); // grey (off)
break;
}
break;
case 2: //CLIMATE_ACTION_COOLING
disp1->set_component_text_printf(component.c_str(), "%s", "\uE716"); // mdi:snowflake
disp1->set_component_font_color(component.c_str(), 1055); // blue
break;
case 3: //CLIMATE_ACTION_HEATING
disp1->set_component_text_printf(component.c_str(), "%s", "\uE237"); // mdi:fire
disp1->set_component_font_color(component.c_str(), 64164); // deep-orange
break;
case 4: //CLIMATE_ACTION_IDLE
disp1->set_component_text_printf(component.c_str(), "%s", "\uE50E"); // mdi:thermometer
disp1->set_component_font_color(component.c_str(), 35921); // grey (off)
break;
case 5: //CLIMATE_ACTION_DRYING
disp1->set_component_text_printf(component.c_str(), "%s", "\uE58D"); // mdi:water-percent
disp1->set_component_font_color(component.c_str(), 64704); // orange
break;
case 6: //CLIMATE_ACTION_FAN
disp1->set_component_text_printf(component.c_str(), "%s", "\uE20F"); // mdi:fan
disp1->set_component_font_color(component.c_str(), 1530); // cyan
break;
}
- id: watchdog
mode: restart
then:
- script.execute: refresh_relays
- lambda: |-
static const char *const TAG = "script.watchdog";
ESP_LOGV(TAG, "Starting");
if (id(is_uploading_tft)) {
ESP_LOGW(TAG, "TFT upload in progress");
} else {
// report Wi-Fi status
bool wifi_connected = wifi_component->is_connected();
if (wifi_connected) {
id(wifi_timeout) = ${wifi_timeout};
float rssi = wifi_rssi->state;
std::string rssi_status = "Unknown";
if (rssi > -50) rssi_status = "Excellent";
else if (rssi > -60) rssi_status = "Good";
else if (rssi > -70) rssi_status = "Fair";
else if (rssi > -80) rssi_status = "Weak";
else rssi_status = "Poor";
if (rssi > -70) ESP_LOGI(TAG, "Wi-Fi: %s (%.0f dBm)", rssi_status.c_str(), rssi);
else if (rssi > -80) ESP_LOGW(TAG, "Wi-Fi: %s (%.0f dBm)", rssi_status.c_str(), rssi);
else ESP_LOGE(TAG, "Wi-Fi: %s (%.0f dBm)", rssi_status.c_str(), rssi);
}
else {
ESP_LOGW(TAG, "Wi-Fi: DISCONNECTED");
if (id(wifi_timeout) > 0) {
id(wifi_timeout)--;
ESP_LOGI(TAG, "Retrying Wi-Fi connection");
wifi_component->retry_connect();
} else {
ESP_LOGE(TAG, "Restarting ESP due to a Wi-Fi timeout...");
App.safe_reboot();
}
}
// report API status
bool api_connected = api_server->is_connected();
if (api_connected) {
ESP_LOGI(TAG, "API: Connected");
} else {
ESP_LOGW(TAG, "API: DISCONNECTED");
blueprint_status->publish_state(0);
if (current_page->state != "blank" and
current_page->state != "boot" and
current_page->state != "home" and
current_page->state != "screensaver" and
current_page->state != "settings" and
current_page->state != "qrcode") {
ESP_LOGI(TAG, "Fallback to page Home");
disp1->goto_page("home");
}
}
if (!wifi_connected or !api_connected) blueprint_status->publish_state(0);
// Report blueprint version
ESP_LOGI(TAG, "Blueprint:");
if (blueprint_status->state > 99) {
ESP_LOGI(TAG, " Version: %s", version_blueprint->state.c_str());
ESP_LOGI(TAG, " Init steps: %i (%0.1f%%)", int(blueprint_status->raw_state), blueprint_status->state);
} else {
ESP_LOGW(TAG, " Init steps: %i (%0.1f%%)", int(blueprint_status->raw_state), blueprint_status->state);
ESP_LOGW(TAG, " State: %s", (wifi_connected and api_connected) ? "Pending" : "DISCONNECTED");
ESP_LOGI(TAG, "Requesting blueprint settings");
auto ha_event = new esphome::api::CustomAPIDevice();
ha_event->fire_homeassistant_event("esphome.nspanel_ha_blueprint",
{
{"type", "boot"},
{"step", "timeout"}
});
}
// Report ESPHome
ESP_LOGI(TAG, "ESPHome:");
ESP_LOGI(TAG, " Version: ${version}");
// Report framework
#ifdef ARDUINO
size_t total_heap_size = ESP.getHeapSize();
size_t free_heap_size = ESP.getFreeHeap();
#elif defined(USE_ESP_IDF)
size_t total_heap_size = heap_caps_get_total_size(MALLOC_CAP_DEFAULT);
size_t free_heap_size = esp_get_free_heap_size();
#endif
if (total_heap_size != 0)
ESP_LOGI(TAG, " Heap: %zu bytes (%d%%)", free_heap_size,
int(round(((float)free_heap_size / total_heap_size) * 100.0f)));
ESP_LOGI(TAG, " Framework: %s", id(framework) == 1 ? "Arduino" :
(id(framework) == 2 ? "ESP-IDF" : "Unknown")); // ESPHome framework
// Report UART
ESP_LOGI(TAG, "UART:");
ESP_LOGI(TAG, " Baud rate: %" PRIu32 " bps", tf_uart->get_baud_rate());
ESP_LOGI(TAG, " Queue size: %d", tf_uart->available());
// Report Nextion status
nextion_init->publish_state(nextion_init->state and disp1->is_setup());
ESP_LOGI(TAG, "Nextion:");
ESP_LOGI(TAG, " Queue size: %d", disp1->queue_size());
if (disp1->is_setup())
ESP_LOGI(TAG, " Is setup: True");
else {
ESP_LOGW(TAG, " Is setup: False");
ESP_LOGW(TAG, " Is detected: %s", YESNO(disp1->is_detected()));
//exit_reparse->execute();
}
if (nextion_init->state) {
ESP_LOGI(TAG, " Init: True");
} else
ESP_LOGW(TAG, " Init: False");
if (version_tft->state.empty())
ESP_LOGW(TAG, " TFT: UNKNOWN");
else
ESP_LOGI(TAG, " TFT: %s", version_tft->state.c_str());
}
refresh_wifi_icon->execute();
ESP_LOGV(TAG, "Finished");
...
and no modifications at .nspanel_esphome_addon_upload_tft.yaml however remoring that one from the config doesn't help, I tried using another panel.
I could duplicate this memory slope on both esp-idf and Arduino. Will look for a way to improve it.
in case you still want to know, a reboot seems to happen when the heapsize < ~60KB
but reset reason it "Software Reset CPU" which is the same as after a manual restart.
removing tft upload from config doesn't help.
the free size decreases exactly every 60 seconds, but that can also be because esphome only measures every minute.
the scripts with mode: queueddo
not containt max_runs
https://esphome.io/guides/automations.html#script-component
which potentially can queue infinite runs.
not saying this is happening, but I don't see much other which can result in a memory leak. ofc the issue can also be in esphome core. in that case I expect other projects to have similar issue reported.
Nice findings!
I believe the memory leak was in the watchdog routine, so I've rebuilt that in a different way, but this point about the queued
scripts is very valid. I've limited that also.
I will have to monitor now, but I think the leak was resolved, or at least significantly reduced.
I will close this for now, to make easier managing my backlog, but please feel free to keep the discussion here and we can always reopen it if the problem persists after the v4.3 release.
did removing the watchdog https://github.com/Blackymas/NSPanel_HA_Blueprint/commit/692e145162e670a8b9c2694fc4feecfcd3034cf4#diff-45d6684fd336fc57bdd08e19302f4a3b120284bd43b34eea5b17e31f7f4af4c5 eventually solve the issue? and can I just go ahead and remove the watchdog for v 4.2.6. or is it better to wait for v4.3? also, are there any plans to reintroduce the watchdog again?
in my case I had the feeling that udp wasn't working if it was executed at the exact same moment the watchdog was running. my feeling was based on the log. but if I am able to just remove the watchdog without any consequences this would help me debug this issue.
sorry for spamming you with additional questions.
For the memory leak, I've removed the watchdog and a bunch of logs that are not really adding anything. The watchdog was recently added and apart of logs, it was restarting the device if the wifi was out for more than some time. That was replaced by ESPHome native function.
It's safe to remove the watchdog, however you will have to remove all references to that, which could also be in the TFT upload and the climate base.
thnx, only removing watchdog doesn't do the trick I tested on 2 devices, I will wait for 4.3 release or start using the dev branch for a while, but that takes time to plan, as I'm always in a stuggle uploading a new tft and need time to struggle with it.
Just to add my results, uptime 3 days & 3 hours.
to confirm updating to 4.3dev4 fixes the issue for me
Still happening for me with 4.3.1 :(
Still happening for me with 4.3.1 :(
Could you please report as a new bug and share your yaml there? Also, please give a bit more details... What still happening, the memory leak, the reboots or both?
did removing the watchdog 692e145#diff-45d6684fd336fc57bdd08e19302f4a3b120284bd43b34eea5b17e31f7f4af4c5 eventually solve the issue? and can I just go ahead and remove the watchdog for v 4.2.6. or is it better to wait for v4.3? also, are there any plans to reintroduce the watchdog again?
in my case I had the feeling that udp wasn't working if it was executed at the exact same moment the watchdog was running. my feeling was based on the log. but if I am able to just remove the watchdog without any consequences this would help me debug this issue.
sorry for spamming you with additional questions.
@bkbartk, on v4.3.3 I'm trying to return with the watchdog, but this time with no memory leak. It would be nice if you can give it a try and let me know if you have issues with the UDP based component you use. By the way, we have introduced PSRAM on v4.3.3. This is also available for Arduino, but probably would require some tunning to be able to run more things on that framework. If you wanna give it a try, I will be happy to support.
@edwardtfn I was not able to give it a try before the release, I just installed v 4.3.4 on one of my panels, now updating the other once. so far nothing critical. UDP works as expected. tft upload works for 80 to 90% on arduino and the udp component, so for that I switch over to esp-idf. I noticed that the webserver stopped working on esp-idf (on all 3 of my devices) but on arduino it seems to work.
not sure what the benefit is of PSRAM at this moment. I know, more RAM but I don't think it's used at the moment? but it gives me a lot of yellow lines during arduino compiling. I don't think this is an issue, so then it's just informative.
I will let you know if the Heap-size decreases, for now it's just to short to have reliable measurements.
Specially with esp-idf we could move some things to psram without having to work in the code, but looks like arduino cannot take advantage of that (or might need some special settings). My plan is to start moving some of the variables to psram, which will enable caching some info and with this improve performance. I haven't started this direction yet as I wanna see the impact (for good and for bad) of psram alone, but that certainly will open space for future improvement.
About the warnings, I was aware of that before the release. It happens only with Arduino and it is saying the psram pins are being overwritten (intentionality, as Sonoff chose non-standard pins for this). There's a way to hide those warnings, but that will hide any other warning, and we probably don't wanna that. 😉
Heap-free seems to be stable on arduino, including UDP
If you wanna give it a try with transfer buffer (it is just a small chunk, but it's probably better than nothing), add this to your panel's yaml:
external_components:
- source:
type: git
url: https://github.com/edwardtfn/esphome
ref: nextion-23
components:
- nextion
- psram
refresh: 1s
Please let me know your results.
cool, I just tested this and I'm able to upload the TFT even with the UDP component active
<html><body>
<!--StartFragment-->
19:33:15 | [D] | [nextion.upload.arduino:131] | Uploaded 99.70%, remaining 22404 bytes, free heap: 50564 (DRAM) + 2081303 (PSRAM) bytes
-- | -- | -- | --
19:33:15 | [D] | [nextion.upload.arduino:131] | Uploaded 99.76%, remaining 18308 bytes, free heap: 48736 (DRAM) + 2081303 (PSRAM) bytes
19:33:15 | [D] | [nextion.upload.arduino:131] | Uploaded 99.81%, remaining 14212 bytes, free heap: 50564 (DRAM) + 2081303 (PSRAM) bytes
19:33:15 | [D] | [nextion.upload.arduino:131] | Uploaded 99.87%, remaining 10116 bytes, free heap: 57740 (DRAM) + 2085951 (PSRAM) bytes
19:33:15 | [D] | [nextion.upload.arduino:131] | Uploaded 99.92%, remaining 6020 bytes, free heap: 57740 (DRAM) + 2085951 (PSRAM) bytes
19:33:15 | [D] | [nextion.upload.arduino:131] | Uploaded 99.97%, remaining 1924 bytes, free heap: 57740 (DRAM) + 2085951 (PSRAM) bytes
19:33:15 | [D] | [nextion.upload.arduino:131] | Uploaded 100.00%, remaining 0 bytes, free heap: 55908 (DRAM) + 2085951 (PSRAM) bytes
19:33:15 | [D] | [nextion.upload.arduino:357] | Successfully uploaded TFT to Nextion!
19:33:15 | [D] | [nextion.upload.arduino:359] | Close HTTP connection
19:33:15 | [D] | [nextion.upload.arduino:359] | Close HTTP connection
19:33:15 | [D] | [nextion.upload:104] | Nextion TFT upload finished: Upload successful
19:33:15 | [D] | [nextion.upload:115] | Restarting ESPHome
<!--EndFragment-->
</body>
</html>
This probably would also benefit people using BLE.
Still I hope one day I can use UDP with ESP-ESF But I checked other sync components and none of them support this yet.
Still I hope one day I can use UDP with ESP-ESF
I'm not an expert on UDP, but that shouldn't be hard to implement/adapt.
There is a new UDP component coming with ESPHome 2024.9.0 (which just started beta). Have you seen that?
yes I have, I haven't had the time to try it out and the configuration at the moment is not fully clear, I need to have a better look at how this config works, I think it will work in my case, still I have to check the configuration
TFT Version
4.2.6
ESPHome Version
4.2.6
Blueprint Version
4.2.6
Panel Model
EU
What is the bug?
Two NSPanel EU units reboot randomly
Steps to Reproduce
Running ESPhome 2023.12.9 on HA.
HA Versions: Core 2024.2.2 Supervisor 2024.02.0 Operating System 11.5 Frontend 20240207.1
Noticed spikes in the temperature graphs for both panels, sometimes around 3am where no heating was running or no large temperature changes expected, Diving deeper into things, both panels are now randomly rebooting, something which wasn't present on the previous, and fairly old (6-months?) version that I was running. The panel sitting infront of my computer has just rebooted before my eyes. Uptime duration: 29hours, 34hours, 6hours
Your Panel's YAML
ESPHome Logs
s6-rc: info: service legacy-cont-init successfully started s6-rc: info: service init-nginx: starting s6-rc: info: service esphome: starting s6-rc: info: service esphome successfully started s6-rc: info: service init-nginx successfully started s6-rc: info: service nginx: starting s6-rc: info: service nginx successfully started s6-rc: info: service discovery: starting [13:22:13] INFO: Waiting for ESPHome dashboard to come up... [13:22:13] INFO: Starting ESPHome dashboard... 2024-02-22 13:22:16,430 INFO Starting dashboard web server on unix socket /var/run/esphome.sock and configuration dir /config/esphome... [13:22:16] INFO: Starting NGINX... [13:22:17] INFO: Successfully send discovery information to Home Assistant. s6-rc: info: service discovery successfully started s6-rc: info: service legacy-services: starting s6-rc: info: service legacy-services successfully started 2024-02-22 13:25:07,302 INFO 200 GET /devices (0.0.0.0) 3.06ms 2024-02-22 13:30:08,854 INFO 200 GET /devices (0.0.0.0) 3.41ms 2024-02-22 13:35:08,856 INFO 200 GET /devices (0.0.0.0) 3.96ms 2024-02-22 13:40:08,853 INFO 200 GET /devices (0.0.0.0) 4.57ms 2024-02-22 13:45:08,848 INFO 200 GET /devices (0.0.0.0) 2.62ms 2024-02-22 13:50:08,925 INFO 200 GET /devices (0.0.0.0) 2.60ms 2024-02-22 13:55:08,853 INFO 200 GET /devices (0.0.0.0) 3.54ms 2024-02-22 14:00:08,854 INFO 200 GET /devices (0.0.0.0) 4.91ms 2024-02-22 14:05:09,266 INFO 200 GET /devices (0.0.0.0) 3.41ms 2024-02-22 14:10:08,852 INFO 200 GET /devices (0.0.0.0) 4.42ms 2024-02-22 14:15:08,857 INFO 200 GET /devices (0.0.0.0) 2.31ms 2024-02-22 14:20:08,853 INFO 200 GET /devices (0.0.0.0) 3.32ms 2024-02-22 14:25:08,852 INFO 200 GET /devices (0.0.0.0) 3.93ms 2024-02-22 14:30:08,856 INFO 200 GET /devices (0.0.0.0) 4.86ms 2024-02-22 14:35:08,853 INFO 200 GET /devices (0.0.0.0) 3.97ms 2024-02-22 14:40:09,230 INFO 200 GET /devices (0.0.0.0) 2.34ms 2024-02-22 14:45:08,852 INFO 200 GET /devices (0.0.0.0) 3.14ms 2024-02-22 14:50:08,851 INFO 200 GET /devices (0.0.0.0) 3.15ms 2024-02-22 14:55:08,860 INFO 200 GET /devices (0.0.0.0) 2.65ms 2024-02-22 15:00:08,849 INFO 200 GET /devices (0.0.0.0) 3.00ms 2024-02-22 15:05:08,849 INFO 200 GET /devices (0.0.0.0) 3.53ms 2024-02-22 15:10:09,082 INFO 200 GET /devices (0.0.0.0) 2.31ms 2024-02-22 15:15:09,233 INFO 200 GET /devices (0.0.0.0) 3.33ms 2024-02-22 15:20:08,853 INFO 200 GET /devices (0.0.0.0) 3.85ms 2024-02-22 15:25:08,852 INFO 200 GET /devices (0.0.0.0) 3.16ms 2024-02-22 15:30:08,900 INFO 200 GET /devices (0.0.0.0) 2.14ms 2024-02-22 15:35:08,852 INFO 200 GET /devices (0.0.0.0) 2.74ms 2024-02-22 15:40:08,852 INFO 200 GET /devices (0.0.0.0) 3.17ms 2024-02-22 15:45:08,853 INFO 200 GET /devices (0.0.0.0) 3.82ms 2024-02-22 15:50:08,852 INFO 200 GET /devices (0.0.0.0) 3.39ms 2024-02-22 15:55:08,855 INFO 200 GET /devices (0.0.0.0) 5.17ms 2024-02-22 16:00:08,849 INFO 200 GET /devices (0.0.0.0) 2.65ms 2024-02-22 16:05:08,853 INFO 200 GET /devices (0.0.0.0) 4.14ms 2024-02-22 16:10:08,856 INFO 200 GET /devices (0.0.0.0) 2.78ms 2024-02-22 16:15:08,853 INFO 200 GET /devices (0.0.0.0) 4.23ms 2024-02-22 16:20:08,854 INFO 200 GET /devices (0.0.0.0) 4.72ms 2024-02-22 16:25:08,855 INFO 200 GET /devices (0.0.0.0) 4.72ms 2024-02-22 16:30:08,849 INFO 200 GET /devices (0.0.0.0) 2.72ms 2024-02-22 16:35:08,854 INFO 200 GET /devices (0.0.0.0) 4.39ms 2024-02-22 16:40:08,853 INFO 200 GET /devices (0.0.0.0) 4.21ms 2024-02-22 16:45:08,850 INFO 200 GET /devices (0.0.0.0) 3.36ms 2024-02-22 16:50:08,851 INFO 200 GET /devices (0.0.0.0) 3.02ms 2024-02-22 16:55:08,852 INFO 200 GET /devices (0.0.0.0) 4.42ms 2024-02-22 17:00:08,853 INFO 200 GET /devices (0.0.0.0) 3.81ms 2024-02-22 17:05:08,852 INFO 200 GET /devices (0.0.0.0) 3.69ms 2024-02-22 17:10:09,032 INFO 200 GET /devices (0.0.0.0) 4.03ms 2024-02-22 17:15:08,853 INFO 200 GET /devices (0.0.0.0) 4.26ms 2024-02-22 17:20:08,851 INFO 200 GET /devices (0.0.0.0) 3.83ms 2024-02-22 17:25:09,170 INFO 200 GET /devices (0.0.0.0) 3.58ms 2024-02-22 17:30:09,415 INFO 200 GET /devices (0.0.0.0) 3.70ms 2024-02-22 17:35:08,855 INFO 200 GET /devices (0.0.0.0) 5.67ms 2024-02-22 17:40:08,850 INFO 200 GET /devices (0.0.0.0) 3.27ms 2024-02-22 17:45:08,850 INFO 200 GET /devices (0.0.0.0) 2.75ms 2024-02-22 17:50:08,853 INFO 200 GET /devices (0.0.0.0) 4.31ms 2024-02-22 17:55:08,995 INFO 200 GET /devices (0.0.0.0) 3.74ms 2024-02-22 18:00:09,253 INFO 200 GET /devices (0.0.0.0) 3.87ms 2024-02-22 18:05:08,850 INFO 200 GET /devices (0.0.0.0) 3.03ms 2024-02-22 18:10:08,854 INFO 200 GET /devices (0.0.0.0) 3.62ms 2024-02-22 18:15:08,853 INFO 200 GET /devices (0.0.0.0) 3.84ms 2024-02-22 18:20:08,850 INFO 200 GET /devices (0.0.0.0) 3.08ms 2024-02-22 18:25:08,852 INFO 200 GET /devices (0.0.0.0) 3.80ms 2024-02-22 18:30:08,892 INFO 200 GET /devices (0.0.0.0) 4.75ms 2024-02-22 18:35:09,410 INFO 200 GET /devices (0.0.0.0) 3.59ms 2024-02-22 18:40:08,857 INFO 200 GET /devices (0.0.0.0) 4.56ms 2024-02-22 18:45:09,335 INFO 200 GET /devices (0.0.0.0) 2.25ms 2024-02-22 18:50:08,850 INFO 200 GET /devices (0.0.0.0) 2.66ms 2024-02-22 18:55:08,854 INFO 200 GET /devices (0.0.0.0) 4.57ms 2024-02-22 19:00:08,849 INFO 200 GET /devices (0.0.0.0) 2.81ms 2024-02-22 19:05:08,850 INFO 200 GET /devices (0.0.0.0) 3.18ms 2024-02-22 19:10:09,315 INFO 200 GET /devices (0.0.0.0) 3.69ms 2024-02-22 19:15:08,849 INFO 200 GET /devices (0.0.0.0) 2.76ms 2024-02-22 19:20:08,848 INFO 200 GET /devices (0.0.0.0) 2.40ms 2024-02-22 19:25:08,852 INFO 200 GET /devices (0.0.0.0) 3.18ms 2024-02-22 19:30:08,852 INFO 200 GET /devices (0.0.0.0) 2.99ms 2024-02-22 19:35:08,849 INFO 200 GET /devices (0.0.0.0) 2.90ms 2024-02-22 19:40:09,009 INFO 200 GET /devices (0.0.0.0) 3.08ms 2024-02-22 19:45:09,189 INFO 200 GET /devices (0.0.0.0) 2.59ms 2024-02-22 19:50:08,852 INFO 200 GET /devices (0.0.0.0) 4.42ms 2024-02-22 19:55:08,849 INFO 200 GET /devices (0.0.0.0) 2.87ms 2024-02-22 20:00:08,854 INFO 200 GET /devices (0.0.0.0) 4.58ms 2024-02-22 20:05:08,854 INFO 200 GET /devices (0.0.0.0) 3.89ms 2024-02-22 20:10:08,854 INFO 200 GET /devices (0.0.0.0) 4.44ms 2024-02-22 20:15:08,852 INFO 200 GET /devices (0.0.0.0) 3.44ms 2024-02-22 20:20:08,851 INFO 200 GET /devices (0.0.0.0) 3.24ms
Home Assistant Logs
Logger: homeassistant.components.automation.nspanel_configuration Source: helpers/script.py:485 Integration: Automation (documentation, issues) First occurred: 20:12:58 (5 occurrences) Last logged: 20:12:58
nspanel Configuration: Main choices: Home page - Values: Repeat at step 2: If at step 1: If at step 3: Error executing script. Unexpected error for call_service at pos 2: Authenticated connection not ready yet for nspanel @ 192.168.0.222; current state is ConnectionState.HANDSHAKE_COMPLETE! nspanel Configuration: Main choices: Home page - Values: Repeat at step 2: If at step 1: Error executing script. Unexpected error for if at pos 3: Authenticated connection not ready yet for nspanel @ 192.168.0.222; current state is ConnectionState.HANDSHAKE_COMPLETE! nspanel Configuration: Main choices: Home page - Values: Repeat at step 2: Error executing script. Unexpected error for if at pos 1: Authenticated connection not ready yet for nspanel @ 192.168.0.222; current state is ConnectionState.HANDSHAKE_COMPLETE! nspanel Configuration: Main choices: Home page - Values: Error executing script. Unexpected error for repeat at pos 2: Authenticated connection not ready yet for nspanel @ 192.168.0.222; current state is ConnectionState.HANDSHAKE_COMPLETE! nspanel Configuration: Error executing script. Unexpected error for choose at pos 2: Authenticated connection not ready yet for nspanel @ 192.168.0.222; current state is ConnectionState.HANDSHAKE_COMPLETE! Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 485, in _async_step await getattr(self, handler)() File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 723, in _async_call_service_step response_data = await self._async_run_long_action( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 685, in _async_run_long_action return long_task.result() ^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/core.py", line 2279, in async_call response_data = await coro ^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/core.py", line 2316, in _execute_service return await target(service_call) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/components/esphome/manager.py", line 719, in execute_service await entry_data.client.execute_service(service, call.data) File "/usr/local/lib/python3.12/site-packages/aioesphomeapi/client.py", line 1193, in execute_service self._get_connection().send_message(req) ^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/site-packages/aioesphomeapi/client.py", line 372, in _get_connection raise APIConnectionError( aioesphomeapi.core.APIConnectionError: Authenticated connection not ready yet for nspanel @ 192.168.0.222; current state is ConnectionState.HANDSHAKE_COMPLETE!
Logger: homeassistant.components.automation.nspanel_configuration Source: components/automation/init.py:666 Integration: Automation (documentation, issues) First occurred: 20:12:58 (1 occurrences) Last logged: 20:12:58
While executing automation automation.nspanel_configuration Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/components/automation/init.py", line 666, in async_trigger return await self.action_script.async_run( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1600, in async_run return await asyncio.shield(run.async_run()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 435, in async_run await self._async_step(log_exceptions=False) File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 487, in _async_step self._handle_exception( File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 512, in _handle_exception raise exception File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 485, in _async_step await getattr(self, handler)() File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 943, in _async_choose_step await self._async_run_script(script) File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1100, in _async_run_script result = await self._async_run_long_action( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 685, in _async_run_long_action return long_task.result() ^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1600, in async_run return await asyncio.shield(run.async_run()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 435, in async_run await self._async_step(log_exceptions=False) File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 487, in _async_step self._handle_exception( File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 512, in _handle_exception raise exception File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 485, in _async_step await getattr(self, handler)() File "/usr/src/homeassistant/homeassistant/helpers/trace.py", line 283, in async_wrapper await func(*args) File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 891, in _async_repeat_step await async_run_sequence(iteration, extra_msg) File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 842, in async_run_sequence await self._async_run_script(script) File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1100, in _async_run_script result = await self._async_run_long_action( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 685, in _async_run_long_action return long_task.result() ^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1600, in async_run return await asyncio.shield(run.async_run()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 435, in async_run await self._async_step(log_exceptions=False) File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 487, in _async_step self._handle_exception( File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 512, in _handle_exception raise exception File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 485, in _async_step await getattr(self, handler)() File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 970, in _async_if_step await self._async_run_script(if_data["if_then"]) File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1100, in _async_run_script result = await self._async_run_long_action( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 685, in _async_run_long_action return long_task.result() ^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1600, in async_run return await asyncio.shield(run.async_run()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 435, in async_run await self._async_step(log_exceptions=False) File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 487, in _async_step self._handle_exception( File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 512, in _handle_exception raise exception File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 485, in _async_step await getattr(self, handler)() File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 970, in _async_if_step await self._async_run_script(if_data["if_then"]) File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1100, in _async_run_script result = await self._async_run_long_action( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 685, in _async_run_long_action return long_task.result() ^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1600, in async_run return await asyncio.shield(run.async_run()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 435, in async_run await self._async_step(log_exceptions=False) File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 487, in _async_step self._handle_exception( File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 535, in _handle_exception raise exception File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 485, in _async_step await getattr(self, handler)() File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 723, in _async_call_service_step response_data = await self._async_run_long_action( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 685, in _async_run_long_action return long_task.result() ^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/core.py", line 2279, in async_call response_data = await coro ^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/core.py", line 2316, in _execute_service return await target(service_call) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/components/esphome/manager.py", line 719, in execute_service await entry_data.client.execute_service(service, call.data) File "/usr/local/lib/python3.12/site-packages/aioesphomeapi/client.py", line 1193, in execute_service self._get_connection().send_message(req) ^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/site-packages/aioesphomeapi/client.py", line 372, in _get_connection raise APIConnectionError( aioesphomeapi.core.APIConnectionError: Authenticated connection not ready yet for nspanel @ 192.168.0.222; current state is ConnectionState.HANDSHAKE_COMPLETE!