Hi,
I have a ESP32 C6 with an 1.47 Inch LCD screen.
I use it to display the reading of two temperature sensors. It works great, except every night, exactly at 2:29 it freezes. Since it is always the same time, I assume it relates to Wifi router restarting (have to do that - different topic) or some other kind of nightly networking hiccup. Is there something I can do in my esphome config to avoid this? Here is my code:
# This sets the default values
substitutions:
friendly_name: "UNSET_FRIENDLY_NAME"
device_id: "UNSET_DEVICE_ID"
description: "UNSET DESCRIPTION"
area: "UNSET AREA"
is_esp_32: "true"
logger: "INFO"
inside_temp_sensor_id: sensor.climate_temperature_2
inside_temp_name: "OFFICE"
outside_temp_sensor_id: sensor.climate_temperature
outside_temp_name: "OUTSIDE"
i2c:
- id: bus_a
sda: GPIO1
scl: GPIO2
scan: False
#frequency: 400kHz # didn't change anything
spi:
clk_pin: GPIO7
miso_pin: GPIO5
mosi_pin: GPIO6
one_wire:
- pin: GPIO10
platform: gpio
esp32:
board: esp32-c6-devkitc-1
variant: esp32c6
flash_size: 4MB
framework:
type: esp-idf
version: 5.3.1
platform_version: 6.9.0
sdkconfig_options:
CONFIG_ESPTOOLPY_FLASHSIZE_DETECT: y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB: y
CONFIG_OPENTHREAD_ENABLED: n
CONFIG_USE_MINIMAL_MDNS: y
# Memory optimization
COMPILER_OPTIMIZATION_SIZE: y
COMPILER_OPTIMIZATION_LEVEL_RELEASE: y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE: y
CONFIG_HEAP_POISONING_DISABLED: y
esphome:
friendly_name: $friendly_name
name: $device_id
name_add_mac_suffix: false
comment: "${description}"
area: $area
includes:
- ./common/yaml/functions.h
project:
name: "Waveshare.ESP32-C6-LCD-1-47in"
version: "v"
platformio_options:
board_build.flash_mode: dio
build_flags:
- "-DI2C_NUM_1=I2C_NUM_0"
- "-DBOARD_HAS_PSRAM"
- "-Wl,-Map,output.map"
board_build.arduino.memory_type: qio_opi
platform_packages:
- platformio/toolchain-xtensa-esp-elf @ 14.2.0+20241119
# binary_sensor:
# # https://esphome.io/components/binary_sensor/status.html
# # Reports if this device is Connected or not
# - platform: status
# name: "Status"
# id: "${device_id}_status"
# icon: mdi:check-network
# entity_category: diagnostic
light:
# RGB LED
- platform: esp32_rmt_led_strip
pin:
number: GPIO8
ignore_strapping_warning: true
name: "RGB LED"
id: rgb_led
chipset: ws2812
#rmt_channel: 0
num_leds: 1
rgb_order: RGB
# gamma_correct: 2.8
default_transition_length: 0s
restore_mode: RESTORE_DEFAULT_OFF
sensor:
- platform: uptime
type: timestamp
name: Uptime
entity_category: diagnostic
# WiFi Signal sensor
- platform: wifi_signal
name: WiFi Signal
id: wifi_signal_db
icon: mdi:wifi-strength-outline
entity_category: diagnostic
update_interval: 30s
disabled_by_default: True
- platform: copy
source_id: wifi_signal_db
name: "WiFi Signal Percent"
id: wifi_signal_percent
icon: mdi:wifi-strength-outline
unit_of_measurement: "%"
filters:
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
entity_category: "diagnostic"
device_class: ""
disabled_by_default: True
- platform: uptime
type: seconds
name: Uptime Sensor
entity_category: diagnostic
- platform: homeassistant
id: outside_temperature
entity_id: $outside_temp_sensor_id
- platform: homeassistant
id: inside_temperature
entity_id: $inside_temp_sensor_id
graph:
# auto-ranged graph
- id: inside_graph
duration: 48h
width: 320
height: 59
border: false
min_value: -10
max_value: 40
traces:
- sensor: inside_temperature
line_thickness: 3
line_type: SOLID
continuous: true
- id: outside_graph
duration: 48h
width: 320
height: 59
border: false
min_value: -10
max_value: 40
traces:
- sensor: outside_temperature
line_thickness: 3
line_type: SOLID
continuous: true
font:
- file: "common/fonts/8-bit-nintendo.ttf"
id: nes_1x
size: 7 # Pixel Perfect
- file: "common/fonts/8-bit-nintendo.ttf"
id: nes_2x
size: 14
- file: "common/fonts/8-bit-nintendo.ttf"
id: nes_25x
size: 18
- file: "common/fonts/8-bit-nintendo.ttf"
id: nes_3x
size: 21
- file: "common/fonts/8-bit-nintendo.ttf"
id: nes_4x
size: 32
# - file: "common/fonts/gotham-Light-webfont.ttf"
# id: gotham_lt
# size: 25
- file: "common/fonts/gotham-Medium-webfont.ttf"
id: gotham_16
size: 16
- file: "common/fonts/gotham-Medium-webfont.ttf"
id: gotham_40
size: 40
- file: "common/fonts/gotham-Medium-webfont.ttf"
id: gotham_md
size: 64
# - file: "common/fonts/gotham-Black-webfont.ttf"
# id: gotham_b
# size: 30
image:
# Home Assistant Logos
- file: mdi:home-assistant
id: home_assistant_logo_20
type: "BINARY"
resize: 20x20x
# WiFi
- file: mdi:signal-cellular-3
id: wifi_3_20
type: "BINARY"
resize: 20x20
- file: mdi:signal-cellular-2
id: wifi_2_20
type: "BINARY"
resize: 20x20
- file: mdi:signal-cellular-1
id: wifi_1_20
type: "BINARY"
resize: 20x20
- file: mdi:signal-cellular-outline
id: wifi_0_20
type: "BINARY"
resize: 20x20
- file: mdi:signal-off
id: wifi_off_20
resize: 20x20
type: "BINARY"
output:
- platform: ledc
pin: GPIO22
id: lcd_backlight
frequency: 1000 Hz
number:
- platform: template
name: "Display Brightness"
id: display_brightness
optimistic: true
min_value: 0
max_value: 100
step: 1
initial_value: 100
restore_value: true
mode: slider
on_value:
then:
- output.set_level:
id: lcd_backlight
level: !lambda "return x / 100.0;"
color:
- id: black
red_int: 0
green_int: 0
blue_int: 0
white_int: 0
- id: gray
red_int: 128
green_int: 128
blue_int: 128
white_int: 0
- id: gray_dark
red_int: 50
green_int: 50
blue_int: 50
white_int: 0
- id: red
red_int: 255
green_int: 0
blue_int: 0
white_int: 0
- id: orange
red_int: 255
green_int: 165
blue_int: 0
white_int: 0
- id: yellow
red_int: 255
green_int: 255
blue_int: 0
white_int: 0
- id: green
red_int: 0
green_int: 255
blue_int: 0
white_int: 0
- id: blue
red_int: 0
green_int: 0
blue_int: 255
white_int: 0
- id: hablue
red_int: 3
green_int: 169
blue_int: 244
white_int: 0
- id: white
red_int: 255
green_int: 255
blue_int: 255
white_int: 0
globals:
- id: screen_rotation
type: int
restore_value: yes
initial_value: "0"
- id: inside_temp_name
type: std::string
restore_value: yes
initial_value: '"${inside_temp_name}"'
- id: outside_temp_name
type: std::string
restore_value: yes
initial_value: '"${outside_temp_name}"'
# button:
# - platform: template
# name: "switch page"
# on_press:
# - display.page.show_next: tft_ha
# - component.update: tft_ha
switch:
- platform: template
name: "flip screen"
lambda: |-
// return true; if the switch should be reported as ON.
// return false; if the switch should be reported as OFF.
return id(screen_rotation) > 50;
turn_on_action:
- globals.set:
id: screen_rotation
value: "180"
turn_off_action:
- globals.set:
id: screen_rotation
value: "0"
# https://esphome.io/components/display/
# TFT Display (ST7789)
display:
- platform: st7789v
cs_pin: GPIO14
dc_pin:
number: GPIO15
ignore_strapping_warning: true
reset_pin: GPIO21
model: Waveshare 1.47in 172X320
id: tft_ha
rotation: 0
pages:
- id: page1
lambda: |-
// id(screen_rotation) is either 0 or 180
// we want it to be 90 or 270
// but then we also want to flip it, so that 270 => 90 and 90 => 270
auto current_rot = id(screen_rotation) + 90;
if (current_rot >= 100) {current_rot = 90;}
else {current_rot = 270;}
it.set_rotation(id(static_cast<DisplayRotation>(current_rot)));
auto cur_time = id(homeassistant_time).now();
if (cur_time.is_valid()) {
it.printf(it.get_width()/2, -12, id(nes_2x), TextAlign::TOP_CENTER, "%02d:%02d", cur_time.hour, cur_time.minute);
} else {}
// Home Assistant API Connection Status
if (!id(api_id).is_connected()) {
it.image(it.get_width()-2, 0, id(home_assistant_logo_20), ImageAlign::TOP_RIGHT, gray);
} else {
it.image(it.get_width()-2, 0, id(home_assistant_logo_20), ImageAlign::TOP_RIGHT, hablue);
}
// Determine the appropriate WiFi icon
if (!id(wifi_signal_percent).has_state()) {
it.image(5, 0, id(wifi_off_20), ImageAlign::TOP_LEFT, gray);
} else {
// WiFi Signal Strength Status
int wifi_strength = id(wifi_signal_percent).state;
if (wifi_strength >= 75) {
it.image(5, 0, id(wifi_3_20), ImageAlign::TOP_LEFT, green);
} else if (wifi_strength >= 50) {
it.image(5, 0, id(wifi_2_20), ImageAlign::TOP_LEFT, orange);
} else if (wifi_strength >= 25) {
it.image(5, 0, id(wifi_1_20), ImageAlign::TOP_LEFT, yellow);
} else {
it.image(5, 0, id(wifi_0_20), ImageAlign::TOP_LEFT, red);
}
}
it.line(0, 20, it.get_width(), 20, white);
auto width = it.get_width();
auto height = it.get_height();
auto header_height = 24;
auto space_under_header = height - header_height;
auto rect_width = width;
auto rect_height = 30;
auto rect_start_x = 0;
auto rect_end_x = width;
auto rect_vertical_center = header_height + (space_under_header / 2);
auto rect_start_y = rect_vertical_center - (rect_height / 2);
auto rect_end_y = rect_start_y + rect_height;
it.printf(it.get_width() / 2, header_height, id(gotham_md), gray_dark, TextAlign::TOP_CENTER, id(inside_temp_name).c_str());
it.printf(it.get_width() / 2, it.get_height() + 20, id(gotham_md), gray_dark, TextAlign::BOTTOM_CENTER, id(outside_temp_name).c_str());
#define DRAW_TEMP_COL(pixel_x) it.filled_rectangle(pixel_x, rect_start_y, 1, rect_height, TemperatureToColor(PixelToTemperature(pixel_x, -10,40,0,320)));
#define DRAW_LINE_VERTI(temp, clr) it.filled_rectangle(TemperatureToPixel(temp, -10,40,0,320), rect_start_y, 1, rect_height, clr);
// draw gradient
for (int i = rect_start_x; i <= rect_end_x; i++) {
DRAW_TEMP_COL(i);
}
// draw numbers on gradient
for (int i = 0; i <= 30; i+=10) {
it.printf(TemperatureToPixel(i,-10,40,0,320), rect_vertical_center+2, id(gotham_16), gray, TextAlign::CENTER, "%d", i);
}
// draw top graph
it.graph(0, header_height, id(inside_graph), yellow);
// draw bottom graph
it.graph(0, rect_end_y, id(outside_graph), yellow);
auto inside_temp = 0.0;
if (id(inside_temperature).has_state()){ inside_temp = id(inside_temperature).state; } else {}
auto inside_clr = TemperatureToColor(inside_temp);
auto inside_xpos = TemperatureToPixel(inside_temp,-10,40,0,320);
auto outside_temp = 0.0;
if (id(outside_temperature).has_state()){ outside_temp = id(outside_temperature).state; } else {}
auto outside_clr = TemperatureToColor(outside_temp);
auto outside_xpos = TemperatureToPixel(outside_temp,-10,40,0,320);
auto triangle_width = 25;
auto triangle_height = 25;
auto box_width = 108;
auto box_height = 40;
struct Point {
int x;
int y;
};
Point line_points[8];
line_points[0] = {inside_xpos, rect_vertical_center - 10}; // triangle tip
line_points[1] = {inside_xpos - (triangle_width/2), rect_vertical_center - triangle_height}; // triangle left corner
line_points[2] = {inside_xpos - (box_width/2), rect_vertical_center - triangle_height}; // box bottom left
line_points[3] = {inside_xpos - (box_width/2), rect_vertical_center - triangle_height - box_height}; // box top left
line_points[4] = {inside_xpos + (box_width/2), rect_vertical_center - triangle_height - box_height}; // box top right
line_points[5] = {inside_xpos + (box_width/2), rect_vertical_center - triangle_height}; // box bottom right
line_points[6] = {inside_xpos + (triangle_width/2), rect_vertical_center - triangle_height}; // triangle right corner
line_points[7] = {inside_xpos, rect_vertical_center - 10}; // triangle tip
it.filled_triangle(line_points[0].x,line_points[0].y, line_points[1].x,line_points[1].y, line_points[6].x,line_points[6].y, black);
it.filled_rectangle(line_points[3].x, line_points[3].y, box_width, box_height, black);
for(int i = 1; i < std::ssize(line_points); i++){ it.line(line_points[i-1].x, line_points[i-1].y, line_points[i].x, line_points[i].y, white);}
line_points[0] = {outside_xpos, rect_vertical_center + 10}; // triangle tip
line_points[1] = {outside_xpos - (triangle_width/2), rect_vertical_center + triangle_height}; // triangle left corner
line_points[2] = {outside_xpos - (box_width/2), rect_vertical_center + triangle_height}; // box bottom left
line_points[3] = {outside_xpos - (box_width/2), rect_vertical_center + triangle_height + box_height}; // box top left
line_points[4] = {outside_xpos + (box_width/2), rect_vertical_center + triangle_height + box_height}; // box top right
line_points[5] = {outside_xpos + (box_width/2), rect_vertical_center + triangle_height}; // box bottom right
line_points[6] = {outside_xpos + (triangle_width/2), rect_vertical_center + triangle_height}; // triangle right corner
line_points[7] = {outside_xpos, rect_vertical_center + 10}; // triangle tip
it.filled_triangle(line_points[0].x,line_points[0].y, line_points[1].x,line_points[1].y, line_points[6].x,line_points[6].y, black);
it.filled_rectangle(line_points[3].x, line_points[3].y, box_width, box_height, black);
for(int i = 1; i < std::ssize(line_points); i++){ it.line(line_points[i-1].x, line_points[i-1].y, line_points[i].x, line_points[i].y, white);}
it.printf(inside_xpos, rect_start_y+1, id(gotham_40), inside_clr, TextAlign::BOTTOM_CENTER, "%.1f°", inside_temp);
it.printf(outside_xpos, rect_end_y+12, id(gotham_40), outside_clr, TextAlign::TOP_CENTER, "%.1f°", outside_temp);
# Cycle through pages on a timer
# interval:
# - interval: 5s
# then:
# - display.page.show_next: tft_ha
# - component.update: tft_ha
When checking logs, I’m getting a warning:
[09:01:26][W][graph:118]: Graphing reducing y-scale to prevent too many gridlines
[09:01:26][W][graph:118]: Graphing reducing y-scale to prevent too many gridlines
[09:01:26][W][component:237]: Component display took a long time for an operation (290 ms).
[09:01:26][W][component:238]: Components should block for at most 30 ms.
I’m thankful for any input on this.