Hi,
I have a Lilygo T547 V2.4 with S3 ESP, got it do compile with ESPHome and connected to HomeAssistant but still have som issue I want to fix. The case is, that this ePaper should mostly “sleep”, but if people want to get new informations, they should press a button on the display, the display updates thru HomeAssistant API (connect works), display newest things, and than people are able to press a touch button on the touch display. My problem now is that the “wakeup” takes quite some time, where the user does not see “anything” on the display. So my idea was to show “ASAP” a “Booting…” on the ePaper display, probable with a hint, how long the boot usually takes. As the blue LED goes on immediately, I was hoping to be “as fast” with writing on the ePaper, but I could not manage to do it. It takes about 10 seconds till the user sees something which are somehow “ages”.
(For wakign up from book I am using the RESET switch), as I had no luck with GPIO15 or GPIO16, which I ratherwould like to use. I could see both GPIO beeing triggered if the ESP is running, but I could not get it to make the ESP wake up.
My configuration is mainly form this setup.
I am using
on the board is printed V 2.4
Here is my ESPHome Yaml:
with this variable set:
rmgr_device_name: “${rmgr_device_name}”
and called via an include
So if anyone has an idea for any of those question, it would help me:
1.) Printing “Booting…” imemdiately on the Screen if the ESP gets power/awakes from deep_sleep
2.) Check on the board directly if the battery is charging (At the moment I assume charging if the volatage is increasing, which is computed on the HA)
3.) Awaking from deep_sleep thru an GPIO and not the used RESET
Many thanks
Juergen
# substitution fort ESPHome and recalculate in lambda for drawing
# rectangle (top_x, top_y, x_width, y_width) in the drawing
substitutions:
# Button Bottom Right
button_br_x1: "680"
button_br_y1: "425"
button_br_x2: "890"
button_br_y2: "500"
# Button Bottom Left
button_bl_x1: "420" # 680 - length - padding = 680 - (button_br_x2 + button_br_x1) - 50
button_bl_y1: "${button_br_y1}" # same height as br but used for clarity below
button_bl_x2: "630" # button_bl_x1 - (button_br_x2 + button_br_x1)
button_bl_y2: "${button_br_y2}" # same height as br
# Button Bottom sleep
button_bs_x1: "60" #
button_bs_y1: "${button_br_y1}" # same height as br but used for clarity below
button_bs_x2: "270" #
button_bs_y2: "${button_br_y2}" # same height as br
# MDI fonts
# https://materialdesignicons.com/
# WIFI
mdi_wifi: "\U000F05A9" # mdi-wifi
mdi_wifi_strength_4: "\U000F0928" # mdi-wifi-strength-4
mdi_wifi_strength_3: "\U000F0925" # mdi-wifi-strength-3
mdi_wifi_strength_2: "\U000F0922" # mdi-wifi-strength-2
mdi_wifi_strength_1: "\U000F091F" # mdi-wifi-strength-1
mdi_wifi_strength_alert_outline: "\U000F092B" # mdi-wifi-strength-alert-outline
mdi_access_point: "\U000F0003" # mdi-access-point
# battery
mdi_battery_80: "\U000F0081" # mdi-battery-80
mdi_battery_60: "\U000F007F" # mdi-battery-60
mdi_battery_40: "\U000F007D" # mdi-battery-40
mdi_battery_20: "\U000F007B" # mdi-battery-20
mdi_battery_10: "\U000F007A" # mdi-battery-10
mdi_battery_charging_80: "\U000F008A" # mdi-battery-charging-80
mdi_battery_charging_60: "\U000F0089" # mdi-battery-charging-60
mdi_battery_charging_40: "\U000F0088" # mdi-battery-charging-40
mdi_battery_charging_20: "\U000F0086" # mdi-battery-charging-20
mdi_battery_charging_10: "\U000F089C" # mdi-battery-charging-10
mdi_battery_unknown: "\U000F0091" # mdi-battery-unknown
# Misc
mdi_book_outline: "\U000F0B64" # mdi-book-outline
esphome:
name: "${rmgr_device_name}"
friendly_name: "${rmgr_device_name}"
platformio_options:
board_build.f_flash: 80000000L
board_build.flash_mode: qio
board_build.psram_type: opi
board_build.partitions: default_16MB.csv
board_build.arduino.memory_type: qio_opi
build_flags: # the first three defines are required for the screen library to function.
- "-DBOARD_HAS_PSRAM" #OK
- "-DARDUINO_USB_MODE=1" #OK
- "-DARDUINO_USB_CDC_ON_BOOT=1" #OK
libraries:
- SPI
on_boot:
- priority: -100
then:
- component.update: wifisignal
- component.update: battery_voltage
- priority: -800 # run as early as possible (must be <1000)
then:
- component.update: t5_display # show "Booting..." immediately
esp32:
board: esp32-s3-devkitc-1
framework:
type: arduino
variant: esp32s3
flash_size: 16MB
i2c:
- id: bus_a
sda: GPIO18
scl: GPIO17
frequency: 100khz
# There is some problems with i2c scan so turn scan off if problem appear on your board
scan: False
touchscreen:
platform: gt911
id: lilygo_touchscreen
interrupt_pin: GPIO47
address: 0x5D
i2c_id: bus_a
setup_priority: -100
transform:
# because we use the display widescreen, buttons on top we have to transfer the touch
mirror_x: false
mirror_y: true
swap_xy: true
on_update:
- lambda: |-
for (auto touch: touches) {
if (touch.state <= 2) {
ESP_LOGI("Touch points:", "id=%d x=%d, y=%d", touch.id, touch.x, touch.y);
}
}
# Have Buttons in HomeAssistant for actions
# defined above and substitutions used also in lambda for drawing the rectangle on screen !!!
binary_sensor:
- platform: touchscreen
name: "bottom left touch"
id: bl_touch
x_min: ${button_bl_x1}
y_min: ${button_bl_y1}
x_max: ${button_bl_x2}
y_max: ${button_bl_y2}
- platform: touchscreen
name: "bottom right touch"
id: br_touch
x_min: ${button_br_x1}
y_min: ${button_br_y1}
x_max: ${button_br_x2}
y_max: ${button_br_y2}
- platform: touchscreen
name: "bottom sleep touch"
id: bs_touch
x_min: ${button_bs_x1}
y_min: ${button_bs_y1}
x_max: ${button_bs_x2}
y_max: ${button_bs_y2}
- platform: gpio
pin:
number: GPIO21 # SENS OP_VN
inverted: true
name: "Button 1"
on_press:
- logger.log: "GPIO21 pressed"
text_sensor:
- platform: homeassistant
name: "Charging Status"
id: ha_charging_status # internal here in ESPHome YAML
entity_id: sensor.${rmgr_device_name}_battery_charging_status # ID in HA
globals:
- id: sleep_duration
type: int
restore_value: no
initial_value: '10' # default sleep duration in seconds
- id: overlay_text
type: std::string
restore_value: no
initial_value: ""
- id: is_booting
type: bool
restore_value: no
initial_value: 'true'
# Enable logging
logger:
# we need time :-)
time:
- platform: homeassistant
id: ha_time
# Enable Home Assistant API
api:
encryption:
key: !secret api_encryption_key
services:
- service: set_sleep_duration
variables:
duration: int
then:
- lambda: |-
id(sleep_duration) = duration;
ESP_LOGI("Sleep", "Sleep duration set to %d seconds", duration);
on_client_connected:
then:
- logger.log: "Connected to HomeAssistant. -> booted"
- homeassistant.event:
event: esphome.${rmgr_device_name}.booted
- lambda: 'id(is_booting) = false;' # to not print "Booting..." a second time
- lambda: 'id(overlay_text) = "";' # to prevent the screen updated twice after wakeup from deep_sleep; having an extra boolean might be the better idea
- component.update: t5_display
# - logger.log: "simulate refresh to refresh the screen on first connect"
# - homeassistant.event:
# event: esphome.${rmgr_device_name}
switch:
- platform: template
name: "Trigger Sleep"
restore_mode: ALWAYS_OFF
turn_on_action:
- script.execute: go_to_sleep
# scripts for putting ESP into sleep and informing the User on ePaper
script:
# to print on screen until when we sleep
- id: go_to_sleep
mode: restart
then:
- lambda: |-
auto now = id(ha_time).now();
auto timestamp = now.timestamp + id(sleep_duration) - 10; // seems to have 10 sec offset
auto future = esphome::ESPTime::from_epoch_local(timestamp);
// Map day_of_week (0 = saturday) to 3-letter name
const char* days[] = {"SAT", "SUN", "MON", "TUE", "WED", "THU", "FRI" };
int dow = future.day_of_week % 7; // ensure it's in 0..6
const char* day_str = days[dow];
char wake_time[50];
snprintf(wake_time, sizeof(wake_time), "Sleeping until: [%02d:%s] %04d-%02d-%02d %02d:%02d:%02d",
dow,day_str,
future.year, future.month, future.day_of_month,
future.hour, future.minute, future.second);
id(overlay_text) = wake_time;
ESP_LOGI("sleep", "Device will sleep until: %s", wake_time);
- component.update: t5_display
# - delay: 3s
- script.execute: sleep_now
# to immediately put ESP into sleep
- id: sleep_now
then:
- lambda: |-
ESP.deepSleep(id(sleep_duration) * 1000000ULL);
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Not needed, as the API connect takes way longer than the WIFI connect
#
# fast_connect: true
# manual_ip:
# static_ip: 172.16.0.200
# gateway: 172.16.0.1
# subnet: 255.255.255.0
external_components:
- source: github://nickolay/esphome-lilygo-t547plus
components: ["t547"]
- source: github://kaeltis/esphome-lilygo-t547plus
components: ["lilygo_t5_47_battery"]
font:
- file: 'fonts/GothamRnd-Book.ttf'
id: font_medium_gotham
size: 30
- file: 'fonts/materialdesignicons-webfont.ttf'
id: font_mdi_medlarge
size: 35
glyphs:
- "${mdi_wifi}"
- "${mdi_wifi_strength_4}"
- "${mdi_wifi_strength_3}"
- "${mdi_wifi_strength_2}"
- "${mdi_wifi_strength_1}"
- "${mdi_wifi_strength_alert_outline}"
- "${mdi_book_outline}"
# battery
- "${mdi_battery_80}"
- "${mdi_battery_60}"
- "${mdi_battery_40}"
- "${mdi_battery_20}"
- "${mdi_battery_10}"
- "${mdi_battery_charging_80}"
- "${mdi_battery_charging_60}"
- "${mdi_battery_charging_40}"
- "${mdi_battery_charging_20}"
- "${mdi_battery_charging_10}"
- "${mdi_battery_unknown}"
display:
- platform: t547
id: t5_display
update_interval: never
lambda: |-
auto draw_rect_frame = [&](display::Display &it,
int x1, int y1, int x2, int y2,
int thickness,
std::string label = "",
esphome::font::Font* font = nullptr) {
int width = x2 - x1;
int height = y2 - y1;
// Draw borders
it.filled_rectangle(x1, y1, width, thickness); // top
it.filled_rectangle(x1, y2 - thickness, width, thickness); // bottom
it.filled_rectangle(x1, y1, thickness, height); // left
it.filled_rectangle(x2 - thickness, y1, thickness, height); // right
// Optional: draw label text centered inside
if (!label.empty() && font != nullptr) {
int cx = x1 + width / 2;
int cy = y1 + height / 2 + 5;
it.printf(cx, cy, font, TextAlign::CENTER, "%s", label.c_str());
}
};
auto draw_for_test = [&](display::Display &it) {
int x = it.get_width() / 2;
int y = it.get_height() / 2;
it.printf(x, y, id(font_medium_gotham), TextAlign::TOP_CENTER, "Waiting ...");
it.filled_circle(20, 32, 15);
it.circle(20, 42, 15);
it.filled_gauge(75, 75, 30, 20, 80);
it.filled_regular_polygon(170, 45, 20, EDGES_HEXAGON);
it.regular_polygon(340, 90, 40, EDGES_OCTAGON, VARIATION_FLAT_TOP);
it.printf(520,300, id(font_mdi_medlarge), "${mdi_book_outline}");
};
auto draw_wifi_icon = [&](display::Display &it) {
std::string wifi_symbol = "${mdi_access_point}"; // default if no state!
if (id(wifisignal).has_state()) {
float rssi = id(wifisignal).state;
if (rssi >= -50) {
wifi_symbol = "${mdi_wifi_strength_4}";
} else if (rssi >= -60) {
wifi_symbol = "${mdi_wifi_strength_3}";
} else if (rssi >= -67) {
wifi_symbol = "${mdi_wifi_strength_2}";
} else if (rssi >= -70) {
wifi_symbol = "${mdi_wifi_strength_1}";
} else {
wifi_symbol = "${mdi_wifi_strength_alert_outline}";
}
}
// soll neben die Buttons gedruckt werden über wifi
it.printf(${button_br_x2} + 15, ${button_br_y1} + (${button_br_y2} - ${button_br_y1}) / 2 , id(font_mdi_medlarge), TextAlign::TOP_LEFT, wifi_symbol.c_str());
};
auto draw_battery_icon = [&](display::Display &it) {
std::string batt_symbol = "${mdi_battery_unknown}"; // default if no state!
if (id(battery_voltage_voltage).has_state()) {
float batt = id(battery_voltage_voltage).state;
bool charging = id(ha_charging_status).has_state() && id(ha_charging_status).state == "charging";
if (charging) {
if (batt >= 4.43) {
batt_symbol = "${mdi_battery_charging_80}";
} else if (batt >= 4) {
batt_symbol = "${mdi_battery_charging_60}";
} else if (batt >= 3.9) {
batt_symbol = "${mdi_battery_charging_40}";
} else if (batt >= 3.8) {
batt_symbol = "${mdi_battery_charging_20}";
} else {
batt_symbol = "${mdi_battery_charging_10}";
}
} else {
if (batt >= 4.43) {
batt_symbol = "${mdi_battery_80}";
} else if (batt >= 4) {
batt_symbol = "${mdi_battery_60}";
} else if (batt >= 3.9) {
batt_symbol = "${mdi_battery_40}";
} else if (batt >= 3.8) {
batt_symbol = "${mdi_battery_20}";
} else {
batt_symbol = "${mdi_battery_10}";
}
}
}
// soll neben die Buttons gedruckt werden über wifi
it.printf(${button_br_x2} + 15, ${button_br_y1} + (${button_br_y2} - ${button_br_y1}) / 2 - 40, id(font_mdi_medlarge), TextAlign::TOP_LEFT, batt_symbol.c_str());
};
auto draw_sleep_overlay = [&](display::Display &it) {
it.printf(${button_br_x2}, ${button_br_y1} + (${button_br_y2} - ${button_br_y1}) / 2,
id(font_medium_gotham), TextAlign::CENTER_RIGHT,
id(overlay_text).c_str());
};
auto draw_buttons = [&](display::Display &it) {
// below draw empty rectangle frame
// draw_rect_frame(it, ${button_bl_x1}, ${button_bl_y1}, ${button_bl_x2}, ${button_bl_y2}, 8);
// below draw rectanle with text centered
draw_rect_frame(it, ${button_bl_x1}, ${button_bl_y1}, ${button_bl_x2}, ${button_bl_y2}, 12, "15 Min", id(font_medium_gotham));
draw_rect_frame(it, ${button_br_x1}, ${button_br_y1}, ${button_br_x2}, ${button_br_y2}, 12, "30 Min", id(font_medium_gotham));
draw_rect_frame(it, ${button_bs_x1}, ${button_bs_y1}, ${button_bs_x2}, ${button_bs_y2}, 12, "SLEEP", id(font_medium_gotham));
//it.filled_rectangle(${button_bl_x1}, ${button_bl_y1},
// ${button_bl_x2} - ${button_bl_x1}, ${button_bl_y2} - ${button_bl_y1});
};
// ##### below the drawing happens
// befor the "if" the stuff is always on screen
if (id(is_booting)) {
it.printf(it.get_width() / 2, it.get_height() / 2, id(font_medium_gotham), TextAlign::CENTER, "Booting...");
return;
} else {
draw_for_test(it);
draw_battery_icon(it);
if (id(overlay_text) != "") {
// Here we go to Sleep Mode
draw_sleep_overlay(it);
} else {
// Printe in NON Sleep Mode
draw_buttons(it);
draw_wifi_icon(it);
}
}
sensor:
- platform: lilygo_t5_47_battery
id: battery_voltage
update_interval: 600s # we sleep a lot, and call it during wakeup
voltage:
name: "Battery Voltage"
id: battery_voltage_voltage
- platform: wifi_signal
name: "WiFi Signal Strength"
id: "wifisignal"
unit_of_measurement: "dBm"
entity_category: "diagnostic"
# update not really needed due to deep_sleep
update_interval: never