Closed boojew closed 11 months ago
I took the same config and put it on another nspanel and I have the same issue. Unfortunately, I cant try an earlier version of esphome... but I assume based on reviewing the 4.0 release notes that this has to do with the change to enable local control
I have one panel controlling two lights, so using both relay 1 and relay 2. I do not have this issue. I just checked and confirm that both lights come on when I turn on/off each button. I also have local fallback enabled for both relays in the blueprint. I am non ESPHome 2023.9 and latest 4.0.2
Does the relay work without a blueprint setup?
No- it doesn’t. But I’m wondering if part of the issue is the new esphome yaml.
Also relevant- I’m using the North American model.
I moved back to an older version of the esphome yaml and it didnt fix it.. so indeed.. So I guess, if anything, this is an esphome bug. I am tempted to say the hardware died.. but 2 panels seems... unlikey.
Could you please share your settings (yaml) from both ESPHome and also your automation in Home Assistant? Please make sure to remove private info before sharing.
Automation:
- id: '1674838074099'
alias: nspanel-laundryroom
description: ''
use_blueprint:
path: Blackymas/nspanel_blueprint.yaml
input:
nspanel_name: 769880a636906af65ce4c1b29d2753f7
right_button_entity: switch.laundry_room_nspanel_relay_2
entity01: cover.right_garage_door
entity01_name: Right Garage Door
weather: AccuWeather
weather_entity: weather.home_2
button_page01_label: TESTPAGE
left_button_name: Garage Light
right_button_name: Side Light
entity_page01_label: ENTITY PAGE ONE
entities_entity01: cover.right_garage_door
entity02: cover.left_garage_door
entity02_name: Left Garage Door
chip01: binary_sensor.garage_door_new
chip02: binary_sensor.garage_door_old
chip01_icon: mdi:garage-open
chip02_icon: mdi:garage-open
relay_2_local_fallback: true
relay_1_local_fallback: true
left_button_hold_select: Default
Esphome:
#####################################################################################################
##### NSPANEL ESPHOME created by Blackymas - https://github.com/Blackymas/NSPanel_HA_Blueprint #####
##### ADVANCED CONFIG + FULL ESPHOME CODE! #####
##### 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:
##### DON'T CHANGE THIS #####
version: "4.0.2"
#############################
device_name: "laundry_room_nspanel"
wifi_ssid: babelfish
wifi_password: XXXXXXX
nextion_update_url: "http://192.168.0.229:83/nspanel_us.tft" # URL to local tft File
baud_rate: "115200" # requires 115200 if tft is installed but can be changed to 9600 if tft upload fails and nextion switches to 9600
##### WIFI SETUP #####
wifi:
networks:
- id: wifi_default
ssid: ${wifi_ssid}
password: ${wifi_password}
power_save_mode: none
ap:
ssid: "${device_name}"
password: ${wifi_password}
##### ESPHOME CONFIGURATION #####
esphome:
name: ${device_name}
min_version: 2023.5.0
##### TYPE OF ESP BOARD #####
esp32:
board: esp32dev
captive_portal:
web_server:
id: web_server_std
port: 80
auth:
username: admin
password: ${wifi_password}
##### OTA PASSWORD #####
ota:
id: ota_std
password: ${wifi_password}
safe_mode: true
reboot_timeout: 3min
num_attempts: 3
##### LOGGER #####
logger:
id: logger_std
##### ENABLE RINGTONE MUSIC SUPPORT #####
rtttl:
id: buzzer
output: buzzer_out
##### CONFIGURE INTERNAL BUZZER #####
output:
##### BUZZER FOR PLAYING RINGTONES #####
- platform: ledc
id: buzzer_out
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:
id: refresh_datetime
on_time_sync:
then:
- component.update: api_timestamp
- component.update: device_timestamp
- logger.log: "System clock synchronized"
- script.execute:
id: refresh_datetime
##### START - BUTTON CONFIGURATION #####
button:
###### REBOOT BUTTON #####
- name: ${device_name} Restart
platform: restart
id: restart_nspanel
##### UPDATE TFT DISPLAY #####
- name: ${device_name} Update TFT display
platform: template
icon: mdi:file-sync
id: tft_update
entity_category: config
on_press:
- logger.log: "Button pressed: Update TFT display"
- binary_sensor.template.publish:
id: nextion_init
state: false
- delay: 16ms
- lambda: id(disp1).upload_tft();
##### EXIT REPARSE TFT DISPLAY #####
- name: ${device_name} Exit reparse
platform: template
icon: mdi:file-sync
id: tft_reparse_off
entity_category: config
on_press:
- logger.log: "Button pressed: Exit reparse"
- uart.write:
id: tf_uart
data: "DRAKJHSUYDGBNCJHGJKSHBDN"
- uart.write:
id: tf_uart
data: [0xFF, 0xFF, 0xFF]
##### START - API CONFIGURATION #####
api:
id: api_server
reboot_timeout: 0s
services:
##### SERVICE TO UPDATE THE HMI FILE ##############
- service: upload_tft
then:
- logger.log: "Service: upload_tft"
- binary_sensor.template.publish:
id: nextion_init
state: false
- lambda: 'id(disp1)->upload_tft();'
##### SERVICE TO UPDATE THE TFT FILE from URL #####
- service: upload_tft_url
variables:
url: string
then:
- logger.log: "Service: upload_tft_url"
- binary_sensor.template.publish:
id: nextion_init
state: false
- lambda: 'id(disp1)->set_tft_url(url.c_str());'
- lambda: 'id(disp1)->upload_tft();'
##### Service to send a command "printf" directly to the display #####
- service: send_command_printf
variables:
cmd: string
then:
- lambda: 'id(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: 'id(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
message: int
then:
- lambda: 'id(disp1).set_component_value(component.c_str(), message);'
##### Service to send a command "hide componente" directly to the display #####
- service: send_command_hide ### unused ###
variables:
component: string
then:
- lambda: 'id(disp1).hide_component(component.c_str());'
##### Service to send a command "show componente" directly to the display #####
- service: send_command_show ### unused ###
variables:
component: string
then:
- lambda: 'id(disp1).show_component(component.c_str());'
##### Service to send a command "show ALL componente" directly to the display #####
- service: send_command_show_all ### unused ###
then:
- lambda: id(disp1).show_component("255");
##### Service to send a command "font color" directly to the display #####
- service: set_component_color
variables:
component: string
foreground: int[]
background: int[]
then:
- lambda: id(set_component_color).execute(component, foreground, background);
##### Service to show a notification-message on the screen #####
- service: notification_show
variables:
label: string
text: string
then:
- lambda: |-
ESP_LOGV("service.notification_show", "Starting");
id(disp1).send_command_printf("is_notification=1");
id(disp1).goto_page("notification");
id(disp1).set_component_text_printf("notification.notifi_label", "%s", label.c_str());
id(display_wrapped_text).execute("notification.notifi_text01", text.c_str(), id(display_mode) == 2 ? 23 : 32);
id(notification_label).publish_state(label.c_str());
id(notification_text).publish_state(text.c_str());
id(timer_reset_all).execute(id(current_page).state.c_str());
- switch.turn_on: notification_unread
- if:
condition:
- switch.is_on: notification_sound
then:
- rtttl.play: "two short:d=4,o=5,b=100:16e6,16e6"
##### Service to clear the notification #####
- service: notification_clear
then:
- logger.log: "Service: notification_clear"
- ¬ification_clear
lambda: |-
id(disp1).send_command_printf("is_notification=0");
id(notification_label).publish_state("");
id(notification_text).publish_state("");
- switch.turn_off: notification_unread
##### 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:
- lambda: |-
id(entity_id) = entity;
std::string cmd_page = std::string("page ") + page.c_str();
id(disp1).send_command_printf(cmd_page.c_str());
id(disp1).set_component_text_printf("page_label", "%s", page_label.c_str());
id(disp1).set_component_text_printf("back_page", "%s", back_page.c_str());
if (page == "climate")
{
if (entity == "embedded_climate") id(addon_climate_set_climate_friendly_name).execute(page_label.c_str());
id(disp1).set_component_value("embedded", (entity == "embedded_climate") ? 1 : 0);
}
else
{
if ((page_icon.c_str() != std::string()) and (page_icon.c_str() != ""))
id(disp1).set_component_text_printf("icon_state", "%s", page_icon.c_str());
id(set_component_color).execute("icon_state", page_icon_color, {});
}
##### 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 show a QR code on the display (ex. for WiFi password)
- service: qrcode
variables:
title: string
qrcode: string
show: bool
then:
- lambda: |-
id(disp1).set_component_text_printf("qrcode.qrcode_label", "%s", title.c_str());
id(disp1).set_component_text_printf("qrcode.qrcode_value", "%s", qrcode.c_str());
if (show) id(disp1).goto_page("qrcode");
#### Service to set climate state ####
- service: set_climate
variables:
current_temp: float
target_temp: float
temp_step: int
total_steps: int
temp_offset: int
climate_icon: string
embedded_climate: bool
entity: string
then:
- lambda: |-
if (id(current_page).state == "climate") id(entity_id) = entity;
- script.execute:
id: set_climate
current_temp: !lambda "return current_temp;"
target_temp: !lambda "return target_temp;"
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:
btn_id: string
btn_pic: int
btn_bg: int[]
btn_icon_font: int[]
btn_txt_font: int[]
btn_bri_font: int[]
btn_icon: string
btn_label: string
btn_bri_txt: string
then:
- lambda: |-
std::string btnicon = btn_id.c_str() + std::string("icon");
std::string btntext = btn_id.c_str() + std::string("text");
std::string btnbri = btn_id.c_str() + std::string("bri");
id(disp1).send_command_printf("%spic.pic=%i", btn_id.c_str(), btn_pic);
id(set_component_color).execute(btnicon.c_str(), btn_icon_font, btn_bg);
id(set_component_color).execute(btntext.c_str(), btn_txt_font, btn_bg);
id(set_component_color).execute(btnbri.c_str(), btn_bri_font, btn_bg);
id(disp1).set_component_text_printf(btnicon.c_str(), "%s", btn_icon.c_str());
id(display_wrapped_text).execute(btntext.c_str(), btn_label.c_str(), 10);
if (strcmp(btn_bri_txt.c_str(), "0") != 0)
id(disp1).set_component_text_printf(btnbri.c_str(), "%s", btn_bri_txt.c_str());
else
id(disp1).set_component_text_printf(btnbri.c_str(), " ");
##### SERVICE TO WAKE UP THE DISPLAY #####
- service: wake_up
variables:
reset_timer: bool
then:
- lambda: |-
if (id(current_page).state == "screensaver") id(disp1).goto_page(id(wakeup_page_name).state.c_str());
if (reset_timer)
id(timer_reset_all).execute(id(wakeup_page_name).state.c_str());
else
{
id(timer_sleep).execute(id(wakeup_page_name).state.c_str(), int(id(timeout_sleep).state));
id(timer_dim).execute(id(wakeup_page_name).state.c_str(), int(id(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: |-
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();
id(disp1).set_component_text_printf(enticon.c_str(), "%s", ent_icon.c_str());
if (strcmp(ent_icon.c_str(), "0") != 0) id(disp1).set_component_text_printf(enticon.c_str(), "%s", ent_icon.c_str());
id(disp1).set_component_text_printf(entlabel.c_str(), "%s", ent_label.c_str());
id(disp1).set_component_text_printf(ent_id.c_str(), "%s", ent_value.c_str());
if (strcmp(ent_value_xcen.c_str(), "0") != 0) id(disp1).send_command_printf("%s", entxcen.c_str());
##### Service for transferring global settings from the blueprint to ESPHome #####
- service: global_settings
variables:
blueprint_version: string
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
date_color: int
time_format: string
time_color: int
embedded_climate: bool
embedded_indoor_temperature: bool
temperature_unit_is_fahrenheit: bool
mui_please_confirm: string
then:
- lambda: |-
// Blueprint version
id(version_blueprint) = blueprint_version;
id(check_versions).execute();
// Relays
id(relay1_local).publish_state(relay1_local_control);
id(relay2_local).publish_state(relay2_local_control);
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;
id(relay_1_fallback) = relay1_fallback;
id(relay_2_fallback) = relay2_fallback;
// Localization
id(mui_time_format) = time_format;
// Date/Time colors
id(home_date_color) = date_color;
id(home_time_color) = time_color;
// Embedded thermostat
id(is_embedded_thermostat) = embedded_climate;
// Indoor temperature
id(embedded_indoor_temp) = embedded_indoor_temperature;
id(temp_unit_fahrenheit) = temperature_unit_is_fahrenheit;
id(display_embedded_temp).execute();
// Confirm page
id(display_wrapped_text).execute("confirm.title", mui_please_confirm.c_str(), 15);
// Refresh colors of global components
id(disp1).set_component_font_color("home.date", id(home_date_color));
id(disp1).set_component_font_color("home.time", id(home_time_color));
id(disp1).set_component_font_color("home.icon_top_01", id(home_relay1_icon_color));
id(disp1).set_component_font_color("home.icon_top_02", id(home_relay2_icon_color));
// Update home page
id(update_page_home).execute();
- if:
condition:
- text_sensor.state: # Is boot page visible?
id: current_page
state: 'boot'
then:
- lambda: |-
id(disp1).set_component_text_printf("boot.bluep_version", "%s", blueprint_version.c_str());
- 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:
- if:
condition:
switch.is_on: notification_sound
then:
- rtttl.play:
rtttl: 'two short:d=4,o=5,b=100:16e6,16e6'
- lambda: |-
ESP_LOGD("service.global_settings", "Jump to wake-up page: %s", id(wakeup_page_name).state.c_str());
id(disp1).goto_page(id(wakeup_page_name).state.c_str());
id(timer_reset_all).execute(id(wakeup_page_name).state.c_str());
#### Service to populate the page Home #####
- service: page_home
variables:
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[]
alarm_state: string
then:
- lambda: |-
// Notification button
id(disp1).send_command_printf("is_notification=%i", (id(notification_text).state.empty() and id(notification_label).state.empty()) ? 0 : 1);
id(disp1).set_component_text_printf("home.bt_notific", "%s", notification_icon.c_str());
id(set_component_color).execute("home.bt_notific", id(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
id(disp1).send_command_printf("is_qrcode=%i", (qrcode) ? 1 : 0);
id(disp1).set_component_text_printf("home.bt_qrcode", "%s", qrcode_icon.c_str());
id(set_component_color).execute("home.bt_qrcode", qrcode_icon_color, {});
// Entities pages button
id(disp1).send_command_printf("is_entities=%i", (entities_pages) ? 1 : 0);
id(disp1).set_component_text_printf("home.bt_entities", "%s", entities_pages_icon.c_str());
id(set_component_color).execute("home.bt_entities", entities_pages_icon_color, {});
// Alarm button
id(disp1).send_command_printf("is_alarm=%i", (alarm_state=="" or alarm_state.empty()) ? 0 : 1);
id(update_alarm_icon).execute("home.bt_alarm", alarm_state.c_str());
#### Service to populate the page Settings #####
- service: page_settings
variables:
reboot: string
#sleep_mode: string
brightness: string
bright: string
dim: string
then:
- lambda: |-
if (not reboot.empty()) id(disp1).set_component_text_printf("settings.lbl_reboot", " %s", reboot.c_str());
id(disp1).set_component_text_printf("settings.lbl_brightness", " %s", brightness.c_str());
id(display_wrapped_text).execute("settings.lbl_bright", bright.c_str(), id(display_mode) == 2 ? 25 : 10);
id(display_wrapped_text).execute("settings.lbl_dim", dim.c_str(), id(display_mode) == 2 ? 25 : 10);
#### 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[] #std::vector<std::string> #std::map
then:
- lambda: |-
// set alarm icon on home page
id(disp1).send_command_printf("is_alarm=%i", (state=="" or state.empty()) ? 0 : 1);
id(update_alarm_icon).execute("home.bt_alarm", state.c_str());
// Is page Alarm visible?
if (id(current_page).state=="alarm")
{ // Update alarm page
id(entity_id) = entity;
// Alarm page - Header
id(update_alarm_icon).execute("icon_state", state.c_str());
id(disp1).set_component_text_printf("page_label", "%s", page_title.c_str());
id(disp1).set_component_text_printf("code_format", "%s", code_format.c_str());
if (code_arm_required) id(disp1).set_component_text_printf("code_arm_req", "1"); else id(disp1).set_component_text_printf("code_arm_req", "0");
// Alarm page - Button's icons
id(disp1).set_component_text_printf("bt_home_icon", "\uE689"); //mdi:shield-home
id(disp1).set_component_text_printf("bt_away_icon", "\uE99C"); //mdi:shield-lock
id(disp1).set_component_text_printf("bt_night_icon", "\uF827"); //mdi:shield-moon
id(disp1).set_component_text_printf("bt_vacat_icon", "\uE6BA"); //mdi:shield-airplane
id(disp1).set_component_text_printf("bt_bypass_icon", "\uE77F"); //mdi:shield-half-full
id(disp1).set_component_text_printf("bt_disarm_icon", "\uE99D"); //mdi:shield-off
// Alarm page - Button's text
id(display_wrapped_text).execute("bt_home_text", mui_alarm[0].c_str(), 10);
id(display_wrapped_text).execute("bt_away_text", mui_alarm[1].c_str(), 10);
id(display_wrapped_text).execute("bt_night_text", mui_alarm[2].c_str(), 10);
id(display_wrapped_text).execute("bt_vacat_text", mui_alarm[3].c_str(), 10);
id(display_wrapped_text).execute("bt_bypass_text", mui_alarm[4].c_str(), 10);
id(display_wrapped_text).execute("bt_disarm_text", mui_alarm[5].c_str(), 10);
// Alarm page - Buttons
if (supported_features & 1) // Alarm - Button - Home
{
id(disp1).send_command_printf("bt_home_pic.pic=%i", (state=="armed_home") ? 43 : 42);
id(disp1).set_component_background_color("bt_home_text", (state=="armed_home") ? 19818 : 52857);
id(disp1).set_component_background_color("bt_home_icon", (state=="armed_home") ? 19818 : 52857);
id(disp1).set_component_font_color("bt_home_text", (state=="armed_home") ? 65535 : 0);
id(disp1).set_component_font_color("bt_home_icon", (state=="armed_home") ? 65535 : 0);
if (state=="armed_home") id(disp1).hide_component("bt_home"); else id(disp1).show_component("bt_home");
}
if (supported_features & 2) // Alarm - Button - Away
{
id(disp1).send_command_printf("bt_away_pic.pic=%i", (state=="armed_away") ? 43 : 42);
id(disp1).set_component_background_color("bt_away_text", (state=="armed_away") ? 19818 : 52857);
id(disp1).set_component_background_color("bt_away_icon", (state=="armed_away") ? 19818 : 52857);
id(disp1).set_component_font_color("bt_away_text", (state=="armed_away") ? 65535 : 0);
id(disp1).set_component_font_color("bt_away_icon", (state=="armed_away") ? 65535 : 0);
if (state=="armed_away") id(disp1).hide_component("bt_away"); else id(disp1).show_component("bt_away");
}
if (supported_features & 4) // Alarm - Button - Night
{
id(disp1).send_command_printf("bt_night_pic.pic=%i", (state=="armed_night") ? 43 : 42);
id(disp1).set_component_background_color("bt_night_text", (state=="armed_night") ? 19818 : 52857);
id(disp1).set_component_background_color("bt_night_icon", (state=="armed_night") ? 19818 : 52857);
id(disp1).set_component_font_color("bt_night_text", (state=="armed_night") ? 65535 : 0);
id(disp1).set_component_font_color("bt_night_icon", (state=="armed_night") ? 65535 : 0);
if (state=="armed_night") id(disp1).hide_component("bt_night"); else id(disp1).show_component("bt_night");
}
if (supported_features & 32) // Alarm - Button - Vacation
{
id(disp1).send_command_printf("bt_vacat_pic.pic=%i", (state=="armed_vacation") ? 43 : 42);
id(disp1).set_component_background_color("bt_vacat_text", (state=="armed_vacation") ? 19818 : 52857);
id(disp1).set_component_background_color("bt_vacat_icon", (state=="armed_vacation") ? 19818 : 52857);
id(disp1).set_component_font_color("bt_vacat_text", (state=="armed_vacation") ? 65535 : 0);
id(disp1).set_component_font_color("bt_vacat_icon", (state=="armed_vacation") ? 65535 : 0);
if (state=="armed_vacation") id(disp1).hide_component("bt_vacat"); else id(disp1).show_component("bt_vacat");
}
if (supported_features & 16) // Alarm - Button - Custom bypass
{
id(disp1).send_command_printf("bt_bypass_pic.pic=%i", (state=="armed_bypass") ? 43 : 42);
id(disp1).set_component_background_color("bt_bypass_text", (state=="armed_bypass") ? 19818 : 52857);
id(disp1).set_component_background_color("bt_bypass_icon", (state=="armed_bypass") ? 19818 : 52857);
id(disp1).set_component_font_color("bt_bypass_text", (state=="armed_bypass") ? 65535 : 0);
id(disp1).set_component_font_color("bt_bypass_icon", (state=="armed_bypass") ? 65535 : 0);
if (state=="armed_bypass") id(disp1).hide_component("bt_bypass"); else id(disp1).show_component("bt_bypass");
}
if ( true ) // Alarm - Button - Disarm
{
id(disp1).send_command_printf("bt_disarm_pic.pic=%i", (state=="disarmed") ? 43 : 42);
id(disp1).set_component_background_color("bt_disarm_text", (state=="disarmed") ? 19818 : 52857);
id(disp1).set_component_background_color("bt_disarm_icon", (state=="disarmed") ? 19818 : 52857);
id(disp1).set_component_font_color("bt_disarm_text", (state=="disarmed") ? 65535 : 0);
id(disp1).set_component_font_color("bt_disarm_icon", (state=="disarmed") ? 65535 : 0);
if (state=="disarmed") id(disp1).hide_component("bt_disarm"); else id(disp1).show_component("bt_disarm");
}
}
#### 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 (id(current_page).state == "media_player")
{
id(entity_id) = entity;
id(disp1).set_component_text_printf("page_label", "%s", friendly_name.c_str());
id(display_wrapped_text).execute("track", media_title.c_str(), id(display_mode) == 2 ? 16 : 27);
id(display_wrapped_text).execute("artist", media_artist.c_str(), id(display_mode) == 2 ? 26 : 40);
// on/off button
if (supported_features & 128 and state == "off") //TURN_ON
{
id(set_component_color).execute("bt_on_off", { 65535 }, {} );
id(disp1).show_component("bt_on_off");
}
else if (supported_features & 256 and state != "off") //TURN_OFF
{
id(set_component_color).execute("bt_on_off", { 10597 }, {} );
id(disp1).show_component("bt_on_off");
}
else id(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
{
id(disp1).set_component_text_printf("bt_play_pause", "%s", "\uE409"); // mdi:play
id(disp1).show_component("bt_play_pause");
}
else if (supported_features & 1 and state == "playing" ) //PAUSE
{
id(disp1).set_component_text_printf("bt_play_pause", "%s", "\uE3E3"); // mdi:pause
id(disp1).show_component("bt_play_pause");
}
else id(disp1).hide_component("bt_play_pause");
// bt_prev button - PREVIOUS_TRACK
if (supported_features & 16 and state != "off") id(disp1).show_component("bt_prev"); else id(disp1).hide_component("bt_prev");
// bt_next button - NEXT_TRACK
if (supported_features & 32 and state != "off") id(disp1).show_component("bt_next"); else id(disp1).hide_component("bt_next");
// Stop button - STOP
//if (supported_features & 4096 and (state == "playing" or state == "paused")) id(disp1).show_component("bt_stop"); else id(disp1).hide_component("bt_stop");
// mute/unmute button - VOLUME_MUTE
id(disp1).set_component_value("is_muted", (is_volume_muted) ? 1 : 0);
if (supported_features & 8 and is_volume_muted) // unmute
{
id(disp1).set_component_text_printf("bt_mute", "%s", "\uEE07"); // mdi:volume-variant-off
id(disp1).show_component("bt_mute");
}
else if (supported_features & 8) // mute
{
id(disp1).set_component_text_printf("bt_mute", "%s", "\uE57E"); // mdi:volume-low
id(disp1).show_component("bt_mute");
}
else id(disp1).hide_component("bt_mute");
// VOLUME_SET
if (supported_features & 4)
{
if (volume_level != id(last_volume_level))
{
id(last_volume_level) = volume_level;
id(disp1).set_component_text_printf("vol_text", "%i%%", volume_level);
id(disp1).set_component_value("vol_slider", volume_level);
}
id(disp1).show_component("vol_slider");
id(disp1).show_component("bt_vol_down");
id(disp1).show_component("bt_vol_up");
id(disp1).show_component("vol_text");
}
else
{
id(disp1).hide_component("vol_slider");
id(disp1).hide_component("bt_vol_down");
id(disp1).hide_component("bt_vol_up");
id(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;
id(disp1).set_component_value("prg_current", int(round(min(media_position + media_position_delta, media_duration))));
}
id(disp1).set_component_value("prg_total", int(round(media_duration)));
id(disp1).send_command_printf("prg_timer.en=%i", (state == "playing") ? 1 : 0);
id(disp1).show_component("time_current");
id(disp1).show_component("time_total");
id(disp1).show_component("time_progress");
}
else
{
id(disp1).send_command_printf("prg_timer.en=0");
id(disp1).hide_component("time_current");
id(disp1).hide_component("time_total");
id(disp1).hide_component("time_progress");
}
}
##### START - GLOBALS CONFIGURATION #####
globals:
###### Last volume level from Home Assistant ######
- id: last_volume_level
type: int
restore_value: false
initial_value: '-1'
###### Last duration from Home Assistant ######
- id: last_media_duration
type: int
restore_value: false
initial_value: '-1'
###### Last duration from Home Assistant ######
- id: last_media_position
type: int
restore_value: false
initial_value: '-1'
###### 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'
##### Display mode (1 = EU, 2 = US, 3 = US Landscape)
- id: display_mode
type: int
restore_value: true
initial_value: '0'
##### Is dimmed #####
- id: is_dim_brightness
type: bool
restore_value: false
initial_value: 'false'
##### Entity Id of the entity displayed on the detailed pages
- id: entity_id
type: std::string
restore_value: no
initial_value: ''
##### 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: int
restore_value: true
initial_value: '100'
##### Save Display DIM Brightness for NSPanel reboot
- id: display_dim_brightness_global
type: int
restore_value: true
initial_value: '10'
##### Temperature unit #####
##### Is embedded sensor used for indoor temperature? #####
- id: embedded_indoor_temp
type: bool
restore_value: true
initial_value: 'false'
- id: temp_unit_fahrenheit
type: bool
restore_value: true
initial_value: 'false'
##### Date/time formats #####
#- id: mui_date_format
# type: std::string
# restore_value: no
# initial_value: '"%A, %d.%m"'
- id: home_date_color
type: int
restore_value: true
initial_value: '65535'
- id: mui_time_format
type: std::string
restore_value: no
initial_value: '"%H:%M"'
- id: home_time_color
type: int
restore_value: true
initial_value: '65535'
##### Relay icons #####
- id: home_relay1_icon
type: std::string
restore_value: false
initial_value: ''
- id: home_relay1_icon_color
type: int
restore_value: true
initial_value: '65535'
- id: home_relay2_icon
type: std::string
restore_value: false
initial_value: ''
- id: home_relay2_icon_color
type: int
restore_value: true
initial_value: '65535'
- id: home_notify_icon_color_normal
type: std::vector<int>
restore_value: false
- id: home_notify_icon_color_unread
type: std::vector<int>
restore_value: false
##### Versions #####
- id: version_blueprint
type: std::string
restore_value: false
initial_value: ''
- id: version_tft
type: std::string
restore_value: false
initial_value: ''
##### START - BINARY SENSOR CONFIGURATION #####
binary_sensor:
###### LEFT BUTTON BELOW DISPLAY TO TOGGLE RELAY#####
- name: ${device_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
then:
- logger.log: "Left button - Long click"
- script.execute:
id: ha_button
page: !lambda return id(current_page).state;
component: "hw_bt_left"
command: "long_click"
- timing: &short_click-timing
- ON for at most 0.8s
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 id(current_page).state;
component: "hw_bt_left"
command: "short_click"
##### RIGHT BUTTON BELOW DISPLAY TO TOGGLE RELAY #####
- name: ${device_name} Right Button
platform: gpio
id: right_button
pin:
number: 27
inverted: true
on_multi_click:
- timing: *long_click-timing
then:
- logger.log: "Right button - Long click"
- script.execute:
id: ha_button
page: !lambda return id(current_page).state;
component: "hw_bt_right"
command: "long_click"
- timing: *short_click-timing
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 id(current_page).state;
component: "hw_bt_right"
command: "short_click"
##### Restart NSPanel Button - Setting Page #####
- name: ${device_name} Restart
platform: nextion
page_id: 7
component_id: 9
internal: true
on_click:
- button.press: restart_nspanel
##### Restart NSPanel Button - Boot Page #####
- name: ${device_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: ${device_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: ${device_name} Status
platform: status
id: api_status
on_state:
then:
- script.execute:
id: refresh_wifi_icon
##### START - SENSOR CONFIGURATION #####
sensor:
##### touchevent sensor, Reset the page timeout #####
- id: touchevent
platform: nextion
nextion_id: disp1
component_name: touchevent
internal: true
on_value:
then:
- lambda: |-
id(timer_reset_all).execute(id(current_page).state.c_str());
##### Uptime Sensors #####
- name: ${device_name} Uptime seconds
id: uptime_sec
platform: uptime
internal: true
- name: ${device_name} API uptime
id: api_timestamp
platform: template
lambda: 'return id(time_provider).now().timestamp;'
internal: false
device_class: timestamp
entity_category: diagnostic
accuracy_decimals: 0
update_interval: never
- name: ${device_name} Device uptime
id: device_timestamp
platform: template
lambda: 'return (id(time_provider).now().timestamp - id(uptime_sec).state);'
internal: false
device_class: timestamp
entity_category: diagnostic
accuracy_decimals: 0
update_interval: never
##### WIFI Signal stregth
- name: ${device_name} RSSI
platform: wifi_signal
update_interval: 60s
on_value:
- script.execute:
id: refresh_wifi_icon
##### 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) #####
- name: ${device_name} Temperature
platform: ntc
id: temp_nspanel
sensor: resistance_sensor
calibration:
b_constant: 3950
reference_temperature: 25°C
reference_resistance: 10kOhm
filters:
- lambda: return x + id(temperature_correction).state;
on_value:
then:
# Show panel's temperature if API or Wi-Fi are out
- lambda: id(display_embedded_temp).execute();
###### Display Brightness GET VALUE FROM NSPanel SLIDER #####
- name: ${device_name} brightness Slider
platform: nextion
id: brightslider
variable_name: brightslider
internal: true
on_value:
then:
- number.set:
id: display_brightness
value: !lambda 'return int(x);'
- lambda: |-
id(timer_reset_all).execute("settings");
###### Display DIM Brightness GET VALUE FROM NSPanel SLIDER #####
- name: ${device_name} dim brightness slider
platform: nextion
id: dimslider
variable_name: dimslider
internal: true
on_value:
then:
- number.set:
id: display_dim_brightness
value: !lambda 'return int(x);'
- lambda: |-
id(timer_reset_all).execute("settings");
##### START - TEXT SENSOR CONFIGURATION #####
text_sensor:
##### Current page name #####
- name: ${device_name} Current page
id: current_page
platform: template
#platform: nextion
#nextion_id: disp1
#component_name: currentpage
internal: false
disabled_by_default: false
on_value:
then:
- lambda: |-
if (x != "climate" and x != "cover" and x != "fan" and x != "light" and x != "media_player" and x != "confirm" and x != "keyb_num") id(entity_id) = "";
if (x != "media_player")
{
id(last_volume_level) = -1;
id(last_media_duration) = -1;
id(last_media_position) = -1;
}
ESP_LOGD("text_sensor.current_page", "New page: %s", x.c_str());
if (!id(entity_id).empty()) ESP_LOGD("text_sensor.current_page", "Entity shown: %s", id(entity_id).c_str());
id(timer_reset_all).execute(x.c_str());
##### ESPhome version used to compile the app #####
- name: ${device_name} ESPhome Version
platform: version
disabled_by_default: true
- platform: wifi_info
ip_address:
name: ${device_name} IP
disabled_by_default: true
id: ip_address
ssid:
name: ${device_name} SSID
disabled_by_default: true
bssid:
name: ${device_name} BSSID
disabled_by_default: true
- name: ${device_name} Notification Label
platform: template
id: notification_label
- name: ${device_name} Notification Text
platform: template
id: notification_text
##### NSPanel event sensor, the main action sensor - push to HA #####
- name: ${device_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: |-
ESP_LOGV("text_sensor.nspanelevent", "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"))) id(timer_reset_all).execute(page.c_str());
std::string value = doc["value"];
std::string entity = id(entity_id); //doc["entity"];
ESP_LOGV("text_sensor.nspanelevent", "page: %s", page.c_str());
ESP_LOGV("text_sensor.nspanelevent", "component: %s", component.c_str());
ESP_LOGV("text_sensor.nspanelevent", "value: %s", value.c_str());
ESP_LOGV("text_sensor.nspanelevent", "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}
});
if (component=="currentpage")
{
ESP_LOGV("text_sensor.nspanelevent", "New page: %s", page.c_str());
ESP_LOGV("text_sensor.nspanelevent", "Trigger HA event");
ha_event->fire_homeassistant_event("esphome.nspanel_ha_blueprint",
{
{"type", "page_changed"},
{"page", page},
{"entity", entity}
});
ESP_LOGV("text_sensor.nspanelevent", "Call add-ons scripts for new page");
id(addon_climate_set_climate).execute(page=="climate" and entity == "embedded_climate");
ESP_LOGV("text_sensor.nspanelevent", "Publish current_page sensor");
id(current_page).publish_state(page);
ESP_LOGV("text_sensor.nspanelevent", "Construct new page");
if (page=="home")
{
ESP_LOGV("text_sensor.nspanelevent", "Construct home page");
id(update_page_home).execute();
}
else if (page=="screensaver")
{
ESP_LOGV("text_sensor.nspanelevent", "Construct screensaver page");
id(update_page_screensaver).execute();
}
else if (page=="climate")
{
ESP_LOGV("text_sensor.nspanelevent", "Construct climate page");
id(disp1).set_component_text_printf("climate.button01_icon", "%s", "\uEE8D"); //mdi:calendar-sync
id(disp1).set_component_text_printf("climate.button02_icon", "%s", "\uE069"); //mdi:autorenew
id(disp1).set_component_text_printf("climate.button03_icon", "%s", "\uE237"); //mdi:fire
id(disp1).set_component_text_printf("climate.button04_icon", "%s", "\uE716"); //mdi:snowflake
id(disp1).set_component_text_printf("climate.button05_icon", "%s", "\uE58D"); //mdi:water-percent
id(disp1).set_component_text_printf("climate.button06_icon", "%s", "\uE20F"); //mdi:fan
id(disp1).set_component_text_printf("climate.button07_icon", "%s", "\uE424"); //mdi:power
id(addon_climate_update_page_climate).execute();
}
else if (page=="cover")
{
ESP_LOGV("text_sensor.nspanelevent", "Construct cover page");
id(disp1).set_component_text_printf("cover.cover_stop", "%s", "\uE666"); //mdi:stop-circle-outline
// In the future this will be dynamically contructed based on the device_class
id(disp1).set_component_text_printf("cover.cover_open", "%s", "\uF11D"); //mdi:window-shutter-open
id(disp1).set_component_text_printf("cover.cover_close", "%s", "\uF11B"); //mdi:window-shutter
}
else if (page=="fan")
{
ESP_LOGV("text_sensor.nspanelevent", "Construct fan page");
id(disp1).set_component_text_printf("fan.button_on", "%s", "\uE20F"); //mdi:fan
id(disp1).set_component_text_printf("fan.button_off", "%s", "\uE81C"); //mdi:fan-off
id(disp1).set_component_text_printf("fan.button_up", "%s", "\uF46D"); //mdi:fan-chevron-up
id(disp1).set_component_text_printf("fan.button_down", "%s", "\uF46C"); //mdi:fan-chevron-down
}
else if (page=="keyb_num")
{
ESP_LOGV("text_sensor.nspanelevent", "Construct keyb_num page");
id(disp1).set_component_text_printf("keyb_num.bview", "%s", "\uE207"); //mdi:eye
id(disp1).set_component_text_printf("keyb_num.bclose", "%s", "\uE158"); //mdi:close-circle
id(disp1).set_component_text_printf("keyb_num.bclear", "%s", "\uE641"); //mdi:eraser-variant
id(disp1).set_component_text_printf("keyb_num.benter", "%s", "\uE12B"); //mdi:check
}
else if (page=="weather01") id(disp1).set_component_text_printf("page_index", "%s", "\uE764\uE765\uE765\uE765\uE765"); // 1/5
else if (page=="weather02") id(disp1).set_component_text_printf("page_index", "%s", "\uE765\uE764\uE765\uE765\uE765"); // 2/5
else if (page=="weather03") id(disp1).set_component_text_printf("page_index", "%s", "\uE765\uE765\uE764\uE765\uE765"); // 3/5
else if (page=="weather04") id(disp1).set_component_text_printf("page_index", "%s", "\uE765\uE765\uE765\uE764\uE765"); // 4/5
else if (page=="weather05") id(disp1).set_component_text_printf("page_index", "%s", "\uE765\uE765\uE765\uE765\uE764"); // 5/5
else if (page=="buttonpage01" or page=="entitypage01") id(disp1).set_component_text_printf("page_index", "%s", "\uE764\uE765\uE765\uE765"); // 1/4
else if (page=="buttonpage02" or page=="entitypage02") id(disp1).set_component_text_printf("page_index", "%s", "\uE765\uE764\uE765\uE765"); // 2/4
else if (page=="buttonpage03" or page=="entitypage03") id(disp1).set_component_text_printf("page_index", "%s", "\uE765\uE765\uE764\uE765"); // 3/4
else if (page=="buttonpage04" or page=="entitypage04") id(disp1).set_component_text_printf("page_index", "%s", "\uE765\uE765\uE765\uE764"); // 4/4
else if (page=="settings")
{
//id(disp1).set_component_text_printf("bt_sleep", "%s", (id(sleep_mode).state) ? "\uEA19" : "\uEA18"); //mdi:toggle-switch-outline or mdi:toggle-switch-off-outline
id(disp1).hide_component("lbl_sleep");
id(disp1).hide_component("bt_sleep");
}
else if (page=="notification")
{
id(disp1).set_component_text_printf("notification.notifi_label", "%s", id(notification_label).state.c_str());
id(display_wrapped_text).execute("notification.notifi_text01", id(notification_text).state.c_str(), id(display_mode) == 2 ? 23 : 32);
}
else if (page=="media_player")
{
ESP_LOGV("text_sensor.nspanelevent", "Construct media_player page");
id(disp1).set_component_text_printf("bt_on_off", "%s", "\uE424"); //mdi:power
id(disp1).set_component_text_printf("bt_prev", "%s", "\uE4AD"); //mdi:skip-previous
id(disp1).set_component_text_printf("bt_next", "%s", "\uE4AC"); //mdi:skip-next
id(disp1).set_component_text_printf("bt_play_pause", "%s", "\uE40D"); //mdi:play-pause
//id(disp1).set_component_text_printf("bt_stop", "%s", "\uE4DA"); //mdi:stop
id(disp1).set_component_text_printf("bt_mute", "%s", "\uE75E"); //mdi:volume-mute
id(disp1).set_component_text_printf("bt_vol_down", "%s", "\uE75D"); //mdi:volume-minus
id(disp1).set_component_text_printf("bt_vol_up", "%s", "\uE75C"); //mdi:volume-plus
}
}
##### NSPanel event - Execute actions from ESPHome - NO push to HA #####
- name: ${device_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: |-
DynamicJsonDocument doc(1024);
deserializeJson(doc, x);
std::string page = doc["page"];
std::string event = doc["event"];
if (not (event == "pagechanged" and (page == "screensaver" or page == "home"))) id(timer_reset_all).execute(page.c_str());
std::string component = doc["component"];
std::string key = doc["key"];
std::string value = doc["value"];
std::string entity = id(entity_id); //doc["entity"];
int embedded = doc["embedded"];
std::string service = "";
// send event to Home Assistant
auto ha_event = new esphome::api::CustomAPIDevice();
if (event=="pagechanged")
{
ESP_LOGV("text_sensor.localevent", "New page: %s", page.c_str());
ESP_LOGV("text_sensor.localevent", "Trigger HA event");
ha_event->fire_homeassistant_event("esphome.nspanel_ha_blueprint",
{
{"type", "page_changed"},
{"page", page},
{"entity", entity}
});
ESP_LOGV("text_sensor.localevent", "Call add-ons scripts for new page");
id(addon_climate_set_climate).execute(page=="climate" and id(entity_id) == "embedded_climate");
ESP_LOGV("text_sensor.localevent", "Publish current_page sensor");
id(current_page).publish_state(page);
ESP_LOGV("text_sensor.localevent", "Construct new page");
}
else if (event=="short_click" or event=="long_click") id(ha_button).execute(page.c_str(), component.c_str(), event.c_str());
else if (event=="click")
{
if (page == "home" and component == "climate")
{
id(entity_id) = (id(is_embedded_thermostat)) ? "embedded_climate" : "";
id(disp1).set_component_value("climate.embedded", (id(is_embedded_thermostat)) ? 1 : 0);
}
id(disp1).goto_page("climate");
}
else if (page == "light" or page == "climate" or page == "notification")// Generic event
{
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"))
{
id(disp1).goto_page("keyb_num");
id(disp1).set_component_value("keyb_num.page_id", 23); //Calling from Alarm page
id(disp1).set_component_text_printf("keyb_num.domain", "%s", page.c_str());
id(disp1).set_component_text_printf("keyb_num.key", "%s", key.c_str());
id(disp1).set_component_text_printf("keyb_num.value", "%s", value.c_str());
id(disp1).set_component_text_printf("keyb_num.entity", "%s", entity.c_str());
id(disp1).set_component_text_printf("keyb_num.title", "%s", title.c_str());
}
else id(service_call_alarm_control_panel).execute(entity.c_str(), key.c_str(), code_format.c_str(), "");
}
else if (page=="boot")
{
// Detect display mode
if (doc.containsKey("display_mode"))
{
std::string display_mode_str = doc["display_mode"];
ESP_LOGD("text_sensor.localevent", "display_mode: %s", display_mode_str.c_str());
float display_mode_float = stof(display_mode_str);
if (display_mode_float > 0) id(display_mode) = int(display_mode_float);
}
// Detect TFT version
if (doc.containsKey("version"))
{
std::string version_tmp = doc["version"];
id(version_tft) = version_tmp;
}
id(check_versions).execute();
// Detect timeout
if (event=="timeout")
{
ha_event->fire_homeassistant_event("esphome.nspanel_ha_blueprint",
{
{"type", "boot"},
{"step", "timeout"},
{"value", value}
});
if (stof(value) >= 5)
id(disp1).goto_page(id(wakeup_page_name).state.c_str());
}
}
else if (page == "climate") id(service_call_climate).execute(entity.c_str(), key.c_str(), value.c_str(), (embedded==1));
else if (page == "cover")
{
if (key == "position") id(ha_call_service).execute("cover.set_cover_position", key.c_str(), value.c_str(), entity.c_str());
else id(ha_call_service).execute((std::string("cover.") + key.c_str()), "", "", entity.c_str());
}
else if (page == "fan")
{
if (key == "stop" or value == "0") id(ha_call_service).execute("fan.turn_off", "", "", entity.c_str());
else id(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"];
id(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";
id(disp1).goto_page(base_domain.c_str());
}
else if (page == "light") id(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") id(ha_call_service).execute("media_player.volume_mute", "is_volume_muted", value.c_str(), entity.c_str());
else if (key == "volume_set") id(ha_call_service).execute("media_player.volume_set", "volume_level", to_string(stof(value) / 100), entity.c_str());
else if (not key.empty()) id(ha_call_service).execute((std::string("media_player.") + key.c_str()), "", "", entity.c_str());
}
##### START - SWITCH CONFIGURATION #####
switch:
##### Notification unread #####
- name: ${device_name} Notification unread
platform: template
id: notification_unread
entity_category: config
optimistic: true
restore_mode: ALWAYS_OFF
on_turn_on:
- lambda: id(set_component_color).execute("home.bt_notific", id(home_notify_icon_color_unread), {});
on_turn_off:
- lambda: id(set_component_color).execute("home.bt_notific", id(home_notify_icon_color_normal), {});
##### Notification sound #####
- name: ${device_name} Notification sound
platform: template
id: notification_sound
entity_category: config
optimistic: true
restore_mode: RESTORE_DEFAULT_OFF
##### PHYSICAL SWITCH 1 #####
- name: ${device_name} Relay 1
platform: gpio
id: relay_1
pin:
number: 22
restore_mode: RESTORE_DEFAULT_OFF
on_turn_on:
then:
- script.execute:
id: refresh_relays
on_turn_off:
then:
- script.execute:
id: refresh_relays
##### PHYSICAL SWITCH 2 ######
- name: ${device_name} Relay 2
platform: gpio
id: relay_2
pin:
number: 19
restore_mode: RESTORE_DEFAULT_OFF
on_turn_on:
then:
- script.execute:
id: refresh_relays
on_turn_off:
then:
- script.execute:
id: refresh_relays
##### DISPLAY ALWAYS ON #####
- name: ${device_name} Screen Power
platform: gpio
id: screen_power
entity_category: config
pin:
number: 4
inverted: true
restore_mode: ALWAYS_ON
internal: true
##### Relay Local control #####
- name: ${device_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: ${device_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 - NUMBER CONFIGURATION #####
number:
##### SCREEN BRIGHTNESS #####
- name: ${device_name} Display Brightness
id: display_brightness
platform: template
entity_category: config
unit_of_measurement: '%'
min_value: 1
max_value: 100
step: 1
restore_value: true
optimistic: true
set_action:
then:
- lambda: |-
id(display_brightness_global) = int(x);
id(disp1).send_command_printf("brightness=%i", int(x));
id(disp1).send_command_printf("settings.brightslider.val=%i", int(x));
if (id(current_page).state != "screensaver")
{
id(disp1).set_backlight_brightness(x/100);
id(timer_dim).execute(id(current_page).state.c_str(), int(id(timeout_dim).state));
id(timer_sleep).execute(id(current_page).state.c_str(), int(id(timeout_sleep).state));
if (id(current_page).state == "settings") id(disp1).set_component_text_printf("bright_text", "%i%%", int(x));
}
##### SCREEN BRIGHTNESS DIMMED DOWN #####
- name: ${device_name} Display Brightness Dimdown
id: display_dim_brightness
platform: template
entity_category: config
unit_of_measurement: '%'
min_value: 1
max_value: 100
step: 1
restore_value: true
optimistic: true
set_action:
then:
- lambda: |-
id(display_dim_brightness_global) = int(x);
id(disp1).send_command_printf("brightness_dim=%i", int(x));
id(disp1).send_command_printf("settings.dimslider.val=%i", int(x));
if (id(current_page).state != "screensaver" and id(is_dim_brightness))
{
id(disp1).set_backlight_brightness(x/100);
id(timer_sleep).execute(id(current_page).state.c_str(), int(id(timeout_sleep).state));
if (id(current_page).state == "settings") id(disp1).set_component_text_printf("dim_text", "%i%%", int(x));
}
##### Temperature Correction #####
- name: ${device_name} Temperature Correction
platform: template
id: temperature_correction
entity_category: config
unit_of_measurement: '°C'
initial_value: 0
min_value: -10
max_value: 10
step: 0.1
restore_value: true
internal: false
optimistic: true
set_action:
- logger.log: Temperature correction changed.
- delay: 1s
- lambda: id(temp_nspanel).publish_state(id(temp_nspanel).raw_state);
##### Timers settings #####
- name: ${device_name} Timeout Page
platform: template
id: timeout_page
entity_category: config
min_value: 0
max_value: 300
initial_value: 15
step: 1
restore_value: true
optimistic: true
icon: mdi:timer
unit_of_measurement: "s"
set_action:
- lambda: id(timer_page).execute(id(current_page).state.c_str(), int(x));
- name: ${device_name} Timeout Dimming
platform: template
id: timeout_dim
entity_category: config
min_value: 0
max_value: 300
initial_value: 30
step: 1
restore_value: true
optimistic: true
icon: mdi:timer
unit_of_measurement: "s"
set_action:
- lambda: id(timer_dim).execute(id(current_page).state.c_str(), int(x));
- name: ${device_name} Timeout Sleep
platform: template
id: timeout_sleep
entity_category: config
min_value: 0
max_value: 300
initial_value: 60
step: 1
restore_value: true
optimistic: true
icon: mdi:timer
unit_of_measurement: "s"
set_action:
- lambda: |-
id(timer_dim).execute(id(current_page).state.c_str(), int(id(timeout_dim).state));
id(timer_sleep).execute(id(current_page).state.c_str(), int(x));
##### START - SELECT CONFIGURATION #####
select:
- id: wakeup_page_name
name: ${device_name} Wake-up page
platform: template
options:
- home
- buttonpage01
- buttonpage02
- buttonpage03
- buttonpage04
- entitypage01
- entitypage02
- entitypage03
- entitypage04
- qrcode
- alarm
initial_option: home
optimistic: true
restore_value: true
internal: false
entity_category: config
icon: mdi:page-next-outline
set_action:
- script.execute: update_page_screensaver
##### START - DISPLAY START CONFIGURATION #####
display:
- id: disp1
platform: nextion
uart_id: tf_uart
tft_url: ${nextion_update_url}
on_page: # I couldn't make this trigger to work, so used text_sensor nspanelevent and localevent instead
- lambda: ESP_LOGW("display.disp1", "NEXTION PAGE CHANGED");
on_setup:
then:
- lambda: |-
id(disp1).goto_page("boot");
id(disp1).set_component_text_printf("boot.esph_version", "%s", "${version}"); // ### esphome-version ###
id(disp1).show_component("bt_reboot");
id(timer_reset_all).execute("boot");
- wait_until:
api.connected
- lambda: |-
id(disp1).set_component_text_printf("boot.ip_addr", "%s", id(ip_address).state.c_str());
auto ha_event = new esphome::api::CustomAPIDevice();
ha_event->fire_homeassistant_event("esphome.nspanel_ha_blueprint",
{
{"type", "boot"},
{"step", "start"}
});
- delay: 1s
- lambda: |-
// Set dimming values
id(display_brightness).publish_state(id(display_brightness_global));
id(display_dim_brightness).publish_state(id(display_dim_brightness_global));
id(disp1).send_command_printf("brightness=%i", id(display_brightness_global));
id(disp1).send_command_printf("settings.brightslider.val=%i", id(display_brightness_global));
id(disp1).send_command_printf("brightness_dim=%i", id(display_dim_brightness_global));
id(disp1).send_command_printf("settings.dimslider.val=%i", id(display_dim_brightness_global));
id(nextion_init).publish_state(true);
auto ha_event = new esphome::api::CustomAPIDevice();
ha_event->fire_homeassistant_event("esphome.nspanel_ha_blueprint",
{
{"type", "boot"},
{"step", "nextion_init"}
});
id(home_relay1_icon) = "\uE3A5";
id(home_relay1_icon) = "\uE3A8";
id(timer_reset_all).execute("boot");
- *notification_clear
- switch.turn_off: notification_unread
- logger.log: "Nextion start - Done!"
### Scripts ######
script:
###### Timers ######
## Global timer reset - Triggered with a touch on the screen
- id: timer_reset_all
mode: restart
parameters:
page: string
then:
- lambda: |-
ESP_LOGV("script.timer_reset_all", "Reset timers");
id(timer_page).execute(page.c_str(), int(id(timeout_page).state));
id(timer_dim).execute(page.c_str(), int(id(timeout_dim).state));
id(timer_sleep).execute(page.c_str(), int(id(timeout_sleep).state));
- id: timer_page # Handle the fallback to home page after a timeout
mode: restart
parameters:
page: string
timeout: int
then:
- lambda: |-
ESP_LOGV("script.timer_page", "Reset timer: %is", timeout);
- if:
condition:
- lambda: |-
return (page != "screensaver" and page != "boot" and page != "home" and timeout >= 1);
then:
- delay: !lambda return (timeout *1000);
- lambda: |-
ESP_LOGD("script.timer_page", "Timed out on page: %s", id(current_page).state.c_str());
if (id(current_page).state != "screensaver" and id(current_page).state != "boot" and id(current_page).state != "home" and timeout >= 1)
{
ESP_LOGD("script.timer_page", "Fallback to page Home");
id(disp1).goto_page("home");
}
- id: timer_dim # Handle the brightness dimming after a timeout
mode: restart
parameters:
page: string
timeout: int
then:
- lambda: |-
ESP_LOGV("script.timer_dim", "Reset timer: %is", timeout);
if (id(is_dim_brightness))
{
if (page != "screensaver" and page != "boot")
{
ESP_LOGD("script.timer_dim", "Waking up on page: %s", page.c_str());
id(disp1).send_command_printf("wakeup_timer.en=1");
}
id(is_dim_brightness) = false;
}
- if:
condition:
- lambda: !lambda return (timeout >= 1);
then:
- delay: !lambda return (timeout *1000);
- lambda: |-
if (id(current_page).state != "screensaver" and id(current_page).state != "boot" and timeout >= 1)
{
ESP_LOGD("script.timer_dim", "Dimming the display to %i%%", id(display_dim_brightness_global));
id(disp1).send_command_printf("dim=%i", id(display_dim_brightness_global));
id(is_dim_brightness) = true;
}
- id: timer_sleep # Handle the sleep (go to screensaver page) after a timeout
mode: restart
parameters:
page: string
timeout: int
then:
- lambda: |-
ESP_LOGV("script.timer_sleep", "Reset timer: %is", timeout);
- if:
condition:
- lambda: !lambda return (timeout >= 1);
then:
- delay: !lambda return (timeout *1000);
- lambda: |-
if (id(current_page).state != "screensaver" and id(current_page).state != "boot" and timeout >= 1)
{
ESP_LOGD("script.timer_sleep", "Going to sleep");
id(disp1).goto_page("screensaver");
id(is_dim_brightness) = true;
}
- id: set_climate
mode: restart
parameters:
current_temp: float
target_temp: float
temp_step: int
total_steps: int
temp_offset: int
climate_icon: string
embedded_climate: bool
then:
- if:
condition:
- text_sensor.state: # Is climate page visible?
id: current_page
state: 'climate'
then:
- lambda: |-
id(addon_climate_set_climate).execute(embedded_climate);
id(disp1).send_command_printf("climateslider.maxval=%i", total_steps);
id(disp1).set_component_value("temp_offset", temp_offset);
id(disp1).set_component_value("temp_step", temp_step);
id(disp1).set_component_text_printf("current_temp", "%.1f°", current_temp);
id(disp1).show_component("current_temp");
id(disp1).show_component("current_icon");
if (target_temp > -999)
{
float slider_val = round(((10*target_temp) - temp_offset) / temp_step);
id(disp1).set_component_value("climateslider", slider_val);
id(disp1).set_component_text_printf("target_temp", "%.1f°", target_temp);
id(disp1).set_component_text_printf("target_icon", "%s", climate_icon.c_str());
id(disp1).show_component("target_icon");
id(disp1).show_component("target_temp");
id(disp1).show_component("climateslider");
id(disp1).show_component("decrease_temp");
id(disp1).show_component("increase_temp");
}
else
{
id(disp1).hide_component("target_icon");
id(disp1).hide_component("target_temp");
id(disp1).hide_component("climateslider");
id(disp1).hide_component("decrease_temp");
id(disp1).hide_component("increase_temp");
}
id(disp1).set_component_value("embedded", (embedded_climate) ? 1 : 0);
- id: refresh_datetime
mode: restart
then:
- lambda: |-
std::string time_format_str = id(mui_time_format);
if (time_format_str.find("%p") != std::string::npos)
{
std::string meridiem_text = id(time_provider).now().strftime("%p");
id(disp1).set_component_text_printf("home.meridiem", "%s", meridiem_text.c_str());
}
else { id(disp1).set_component_text_printf("home.meridiem", " "); }
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 time_text = id(time_provider).now().strftime(time_format_str);
id(disp1).set_component_text_printf("home.time", "%s", time_text.c_str());
- id: refresh_relays
mode: restart
then:
- lambda: |-
// Chips - Relays
if (id(relay_1).state) id(disp1).set_component_text_printf("home.icon_top_01", "%s", id(home_relay1_icon).c_str());
else id(disp1).set_component_text_printf("icon_top_01", "\uFFFF");
if (id(relay_2).state) id(disp1).set_component_text_printf("home.icon_top_02", "%s", id(home_relay2_icon).c_str());
else id(disp1).set_component_text_printf("home.icon_top_02", "\uFFFF");
// Hardware buttons - Fallback mode
if (id(relay_1).state and id(relay1_local).state) id(disp1).send_command_printf("home.left_bt_pic.val=%i", (id(relay_1).state) ? 1 : 0);
if (id(relay_2).state and id(relay2_local).state) id(disp1).send_command_printf("home.right_bt_pic.val=%i", (id(relay_2).state) ? 1 : 0);
- id: refresh_wifi_icon
mode: restart
then:
- if:
condition:
- binary_sensor.is_on: nextion_init
then:
# Update Wi-Fi icon
- if:
condition:
wifi.connected:
then:
- if:
condition:
api.connected:
then:
- lambda: id(disp1).send_command_printf("api=1");
- lambda: id(disp1).set_component_text_printf("home.wifi_icon", "%s", "\uE5A8");
- lambda: id(disp1).set_component_font_color("home.wifi_icon", 33808);
else:
- lambda: id(disp1).send_command_printf("api=0");
- lambda: id(disp1).set_component_text_printf("home.wifi_icon", "%s", "\uF256");
- lambda: id(disp1).set_component_font_color("home.wifi_icon", 63488);
else:
- lambda: id(disp1).send_command_printf("api=0");
- lambda: id(disp1).set_component_text_printf("home.wifi_icon", "%s", "\uE5A9");
- lambda: id(disp1).set_component_font_color("home.wifi_icon", 63488);
- id: update_page_home
mode: restart
then:
- if:
condition:
- text_sensor.state: # Is home page visible?
id: current_page
state: 'home'
then:
- script.execute: refresh_relays
- script.execute: refresh_wifi_icon
- lambda: |-
id(disp1).send_command_printf("is_notification=%i", (id(notification_text).state.empty() and id(notification_label).state.empty()) ? 0 : 1);
id(set_component_color).execute("home.bt_notific", id(notification_unread).state ? id(home_notify_icon_color_unread) : id(home_notify_icon_color_normal), {});
- script.execute: refresh_datetime
- script.execute: addon_climate_update_page_home
- 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);
}
id(api_server).send_homeassistant_service_call(resp);
}
- id: service_call_climate
mode: restart
parameters:
entity: string
key: string
value: string
embedded: bool
then:
- lambda: |-
if (embedded)
id(addon_climate_service_call).execute(key.c_str(), value.c_str());
else if (key == "set_temperature")
id(ha_call_service).execute("climate.set_temperature", "temperature", to_string(stof(value) / 10), entity.c_str());
else if (key == "hvac_mode")
id(ha_call_service).execute("climate.set_hvac_mode", key.c_str(), value.c_str(), entity.c_str());
- id: ha_call_service
mode: restart
parameters:
service: string
key: string
value: string
entity: string
then:
- lambda: |-
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}
});
}
- id: ha_button
mode: parallel
parameters:
page: string
component: string
command: string
then:
- lambda: |-
id(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: update_alarm_icon
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;
}
id(disp1).set_component_text_printf(component.c_str(), alarm_icon.c_str());
id(disp1).set_component_font_color(component.c_str(), alarm_color);
- id: update_climate_icon
mode: restart
parameters:
component: string
action: int
mode: int
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
id(disp1).set_component_text_printf(component.c_str(), "%s", "\uFFFF"); // (E424) Don't show icon when off
id(disp1).set_component_font_color(component.c_str(), 35921); // grey (off)
break;
case 1: //CLIMATE_MODE_HEAT_COOL
id(disp1).set_component_text_printf(component.c_str(), "%s", "\uE069"); // mdi:autorenew
id(disp1).set_component_font_color(component.c_str(), 35921); // grey (off)
break;
case 2: //CLIMATE_MODE_COOL
id(disp1).set_component_text_printf(component.c_str(), "%s", "\uE716"); // mdi:snowflake
id(disp1).set_component_font_color(component.c_str(), 35921); // grey (off)
break;
case 3: //CLIMATE_MODE_HEAT
id(disp1).set_component_text_printf(component.c_str(), "%s", "\uE237"); // mdi:fire
id(disp1).set_component_font_color(component.c_str(), 35921); // grey (off)
break;
case 4: //CLIMATE_MODE_FAN_ONLY
id(disp1).set_component_text_printf(component.c_str(), "%s", "\uE20F"); // mdi:fan
id(disp1).set_component_font_color(component.c_str(), 35921); // grey (off)
break;
case 5: //CLIMATE_MODE_DRY
id(disp1).set_component_text_printf(component.c_str(), "%s", "\uE58D"); // mdi:water-percent
id(disp1).set_component_font_color(component.c_str(), 35921); // grey (off)
break;
case 6: //CLIMATE_MODE_AUTO
id(disp1).set_component_text_printf(component.c_str(), "%s", "\uEE8D"); // mdi:calendar-sync
id(disp1).set_component_font_color(component.c_str(), 35921); // grey (off)
break;
}
break;
case 2: //CLIMATE_ACTION_COOLING
id(disp1).set_component_text_printf(component.c_str(), "%s", "\uE716"); // mdi:snowflake
id(disp1).set_component_font_color(component.c_str(), 1055); // blue
break;
case 3: //CLIMATE_ACTION_HEATING
id(disp1).set_component_text_printf(component.c_str(), "%s", "\uE237"); // mdi:fire
id(disp1).set_component_font_color(component.c_str(), 64164); // deep-orange
break;
case 4: //CLIMATE_ACTION_IDLE
id(disp1).set_component_text_printf(component.c_str(), "%s", "\uE50E"); // mdi:thermometer
id(disp1).set_component_font_color(component.c_str(), 35921); // grey (off)
break;
case 5: //CLIMATE_ACTION_DRYING
id(disp1).set_component_text_printf(component.c_str(), "%s", "\uE58D"); // mdi:water-percent
id(disp1).set_component_font_color(component.c_str(), 64704); // orange
break;
case 6: //CLIMATE_ACTION_FAN
id(disp1).set_component_text_printf(component.c_str(), "%s", "\uE20F"); // mdi:fan
id(disp1).set_component_font_color(component.c_str(), 1530); // cyan
break;
}
- id: set_component_color
mode: queued
parameters:
component: string
foreground: int[]
background: int[]
then:
- lambda: |-
int fg565 = -1;
int bg565 = -1;
// Foreground
if (foreground.size() == 3) fg565 = ((foreground[0] & 0b11111000) << 8) | ((foreground[1] & 0b11111100) << 3) | (foreground[2] >> 3);
else if (foreground.size() == 1) fg565 = foreground[0];
if (fg565 >= 0) id(disp1).set_component_font_color(component.c_str(), fg565);
// Background
if (background.size() == 3) bg565 = ((background[0] & 0b11111000) << 8) | ((background[1] & 0b11111100) << 3) | (background[2] >> 3);
else if (background.size() == 1) bg565 = background[0];
if (bg565 >= 0) id(disp1).set_component_background_color(component.c_str(), bg565);
- id: display_wrapped_text
mode: queued
parameters:
component: string
text: string
line_length_limit: int
then:
- lambda: |-
int startPos = 0;
int endPos = 0;
std::string wrappedText = "";
while (startPos < text.length()) {
while (text[startPos] == ' ' and startPos < text.length()) { startPos++; }
int endPos = startPos + line_length_limit;
if (endPos >= text.length()) endPos = text.length();
else
{
while (endPos > startPos && text[endPos] != ' ') { endPos--; }
if (endPos == startPos) endPos = startPos + line_length_limit; // Handle case of long word
}
wrappedText += text.substr(startPos, endPos-startPos);
if (endPos < text.length())
{
while (text[endPos] == ' ') { endPos--; }
if (endPos >= startPos) wrappedText += "\\r";
}
startPos = endPos + 1; // Skip the space
while (text[startPos] == ' ' and startPos < text.length()) { startPos++; }
}
id(disp1).set_component_text_printf(component.c_str(), "%s", wrappedText.c_str());
- id: display_embedded_temp
mode: restart
then:
- if:
condition:
- or:
- lambda: return id(embedded_indoor_temp);
- not:
- api.connected:
- not:
- wifi.connected:
then:
- lambda: |-
if (id(temp_unit_fahrenheit)) id(disp1).set_component_text_printf("home.current_temp", "%.0f°F", ((id(temp_nspanel).state * 9.0 / 5.0) + 32.0)); // °F = (°C × 9/5) + 32
else id(disp1).set_component_text_printf("home.current_temp", "%.1f°C", id(temp_nspanel).state);
- 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}", id(version_tft).c_str()) and compareVersions("${version}", id(version_blueprint).c_str()));
#- lambda: !lambda 'return (id(version_tft) == "${version}");'
#- lambda: !lambda 'return (id(version_blueprint) == "${version}");'
timeout: 60s
- 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);
};
ESP_LOGD("script.check_versions", "ESPHome version: ${version}");
ESP_LOGD("script.check_versions", "TFT version: %s", id(version_tft).c_str());
if (not compareVersions("${version}", id(version_tft).c_str())) ESP_LOGE("script.check_versions", "TFT version mismatch!");
ESP_LOGD("script.check_versions", "Blueprint version: %s", id(version_blueprint).c_str());
if (not compareVersions("${version}", id(version_blueprint).c_str())) ESP_LOGE("script.check_versions", "Blueprint version mismatch!");
auto ha_event = new esphome::api::CustomAPIDevice();
ha_event->fire_homeassistant_event("esphome.nspanel_ha_blueprint",
{
{"type", "version"},
{"tft", id(version_tft).c_str()},
{"esphome", "${version}"},
{"blueprint", id(version_blueprint).c_str()}
});
- id: update_page_screensaver
mode: restart
then:
- if:
condition:
text_sensor.state:
id: current_page
state: screensaver
then:
- lambda: |-
int wakeup_page_id = 0;
if (id(wakeup_page_name).state == "buttonpage01") wakeup_page_id = 12;
else if (id(wakeup_page_name).state == "buttonpage02") wakeup_page_id = 13;
else if (id(wakeup_page_name).state == "buttonpage03") wakeup_page_id = 14;
else if (id(wakeup_page_name).state == "buttonpage04") wakeup_page_id = 15;
else if (id(wakeup_page_name).state == "entitypage01") wakeup_page_id = 18;
else if (id(wakeup_page_name).state == "entitypage02") wakeup_page_id = 19;
else if (id(wakeup_page_name).state == "entitypage03") wakeup_page_id = 20;
else if (id(wakeup_page_name).state == "entitypage04") wakeup_page_id = 21;
else if (id(wakeup_page_name).state == "qrcode") wakeup_page_id = 17;
else if (id(wakeup_page_name).state == "alarm") wakeup_page_id = 23;
id(disp1).set_component_value("orign", wakeup_page_id);
##### ADD-ONS ############################################################
##### Add-on - Climate #####
- id: addon_climate_service_call
mode: restart
parameters:
key: string
value: string
then:
# Reserved for Add-on Climate
- lambda: |-
ESP_LOGV("script.addon_climate_service_call", "Check for addon_climate");
- id: addon_climate_update_page_home
mode: restart
then:
# Reserved for Add-on Climate
- lambda: |-
ESP_LOGV("script.addon_climate_update_page_home", "Check for addon_climate");
- id: addon_climate_set_climate
mode: restart
parameters:
embedded_climate: bool
then:
# Reserved for Add-on Climate
- lambda: |-
ESP_LOGV("script.addon_climate_set_climate", "Check for addon_climate");
ESP_LOGV("script.addon_climate_set_climate", "embedded_climate: %i", (embedded_climate) ? 1 : 0);
- id: addon_climate_update_page_climate
mode: restart
then:
# Reserved for Add-on Climate
- lambda: |-
ESP_LOGV("script.addon_climate_update_page_climate", "Check for addon_climate");
- id: addon_climate_set_climate_friendly_name
mode: restart
parameters:
friendly_name: string
then:
# Reserved for Add-on Climate
- lambda: |-
ESP_LOGV("script.addon_climate_set_climate_friendly_name", "Check for addon_climate");
ESP_LOGV("script.addon_climate_set_climate_friendly_name", "friendly_name: %s", friendly_name.c_str());
On your automation yaml, I don't see anything attached to relay 1. I understand it is using fallback, but coukt you please try setting the switch related to relay 1 to the left button and try again? Please let me know the results.
About ESPHome, is there a reason you are using the full ESPHome yaml instead of referencing like in the examples from GitHub? Are you making any customization to that?
On your automation yaml, I don't see anything attached to relay 1. I understand it is using fallback, but coukt you please try setting the switch related to relay 1 to the left button and try again? Please let me know the results.
About ESPHome, is there a reason you are using the full ESPHome yaml instead of referencing like in the examples from GitHub? Are you making any customization to that?
Sure! Done
- id: '1674838074099'
alias: nspanel-laundryroom
description: ''
use_blueprint:
path: Blackymas/nspanel_blueprint.yaml
input:
nspanel_name: 769880a636906af65ce4c1b29d2753f7
right_button_entity: switch.laundry_room_nspanel_relay_2
entity01: cover.right_garage_door
entity01_name: Right Garage Door
weather: AccuWeather
weather_entity: weather.home_2
button_page01_label: TESTPAGE
left_button_name: Garage Light
right_button_name: Side Light
entity_page01_label: ENTITY PAGE ONE
entities_entity01: cover.right_garage_door
entity02: cover.left_garage_door
entity02_name: Left Garage Door
chip01: binary_sensor.garage_door_new
chip02: binary_sensor.garage_door_old
chip01_icon: mdi:garage-open
chip02_icon: mdi:garage-open
relay_2_local_fallback: true
relay_1_local_fallback: true
left_button_hold_select: Default
left_button_entity: switch.laundry_room_nspanel_relay_1
No customization. Originally when I was setting this up, I was having some issues flashing and I moved it to all local to fix it.... then I forgot and never went back.. It is now
substitutions:
###### CHANGE ME START ######
device_name: "laundry_room_nspanel"
wifi_ssid: babelfish
wifi_password: XXX
nextion_update_url: "http://192.168.0.229:83/nspanel_us.tft"
##### addon-configuration #####
## addon_climate ##
# addon_climate_heater_relay: "1" # possible values: 1/2
##### CHANGE ME END #####
packages:
remote_package:
url: https://github.com/Blackymas/NSPanel_HA_Blueprint
ref: main
files:
- nspanel_esphome.yaml # Core package
# - nspanel_esphome_advanced.yaml # activate advanced (legacy) elements - can be useful for troubleshooting
# - nspanel_esphome_addon_climate_cool.yaml # activate for local climate (cooling) control
# - nspanel_esphome_addon_climate_heat.yaml # activate for local climate (heater) control
refresh: 300s
##### My customization - Start #####
##### My customization - End #####
Sure! Done
Is relay 1 working after this change or still the same issue as before?
No customization. Originally when I was setting this up, I was having some issues flashing and I moved it to all local to fix it.... then I forgot and never went back.. It is now
Not a problem if you wanna use the big file locally. I just wanna know about any customization.
It's probably easier for you to use the preference to GitHub, but if you have issues again or wanna keep more control, I would suggest you copy the entire file to a subfolder and then change the link in packages
like in the example here: https://github.com/Blackymas/NSPanel_HA_Blueprint/wiki/(EN)-First-Steps---Installation-and-Setup#3-advanced-configuration-for-all-esphome-and-home-assistant-professionals
@boojew When you turn on/off the Relay from Home Assistant, does the relay icon in NSPanel (square icon with 1 in top left) turn on/off too?
When you tried a 2nd panel, was the relay working fine before you flashed? At what point did the relay stop working? Have you tried a completely new minimal default configuration and blueprint using a different name for nspanel other than laundry_room_nspanel? Maybe something old in HA may be conflicting with the entity name.
So, yes, when I press the button in HA and locally, the UI updates both the line above the switch as well as toggles the "1" to the top left corner; however, in no cases can I get the relay to actually toggle and it remains open.
In terms of when does it break with a new nspanel. Great question and I will need to do more testing
Hi, I'm having the same problem, with both relays. Nspanel is on the latest versions of ESPHome (2023.9.3) and Blueprint (4.0.2). Stopped working after updating to these versions. When pressing the physical buttons, nothing happens (no sound of the relay), when pressing from the entity in HA, the relay does toggle (also hear the relay sound). The entity that is configured to toggle doesnt toggle either (also not when pressing the nspanel relay entity from HA).
@pvi25 is the entity in blueprint set to the entity of the relays? You are saying that both the relays toggle from HA entity but then right after say they don’t?!?
@pvi25 is the entity in blueprint set to the entity of the relays? You are saying that both the relays toggle from HA entity but then right after say they don’t?!?
I meant the entity that is supposed to be triggered in the Hardware Buttons config is not (never) triggered.
This is my Blueprint config for hardwarre buttons:
When pressing a physical button on the NSPanel, the switch 'Bureau Bureau' is supposed to be triggered, but when pressing the physical button on the NSPanel nothing at all happens (I do not even hear the relay click).
This is the ESPHome config for the NSPanel:
When toggling the relay switch from here, I do hear the relay click (and the little '1' icon appears on the NSPanel display), but still the 'Bureau Bureau' switch doesnt get triggered (thats what I meant with 'The entity that is configured to toggle doesnt toggle either').
When toggling 'Bureau Bureau' direcly, it does work:
Holy crap. I found my issue. Seems one of the pins between the screen and the relay module was VERY minorly misaligned. I honestly had checked before quickly but didnt see it. The tilt on the pin was very minor, but I guess enough to make a difference
Very sorry for the noise and the time that was spent here .. and HUGE thank you
Good to hear you found the issue. 🙂
I am on 4.02 for TFT, esphome-nspanel code, and Blueprint as well as on esphome 2023.9.3. Suddenly, a few days ago, I noticed my relay 1 button was not working. Relay 2 continues to work properly. At the time, I was on 4.0.0. Upgrading didnt solve it.
I SUSPECT, an esphome update is what broke this, but I dont know for sure. The blueprint is configured to let the panel control the relay directly. I also tested through the esphome UI toggling the relay and nothing. No relay clicking noise, nada. Clicking button 2 properly triggers local relay 2.
Logs dont show anything very interesting..
The "Nextion reported variable name invalid!" warning happens on both relays, so I assume it is normal