Nice, i am looking forward to it…
Here is my current layout. i removed the gif on the first page and show there some other useful stuff. The bottom section i have setup to my preferences.
I really like it and use it on my night desk. With HA i set the background light from the display to 30% in the night and 70% at day.
To have a nice view i printed the following:
The stand i have designed
That is my latest code for the ESP32-2432S028:
esphome:
name: cyd
friendly_name: CYD Schlafzimmer
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "secret"
ota:
- platform: esphome
password: "secret"
wifi:
ssid: "secret"
password: "secret"
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Cyd Fallback Hotspot"
password: "LEMTsad123"
captive_portal:
globals:
- id: show_return_page
type: bool
restore_value: yes
initial_value: "false"
# Setup a pin to control the backlight and the LED
output:
- platform: ledc
pin: GPIO21
id: backlight_pwm
- platform: ledc
id: output_red
pin: GPIO4
inverted: true
- platform: ledc
id: output_green
pin: GPIO16
inverted: true
- platform: ledc
id: output_blue
pin: GPIO17
inverted: true
light:
- platform: monochromatic
output: backlight_pwm
name: Display Backlight
id: backlight
restore_mode: ALWAYS_ON
- platform: rgb
name: LED
red: output_red
id: led
green: output_green
blue: output_blue
restore_mode: ALWAYS_OFF
# Setup SPI for the display. The ESP32-2432S028R uses separate SPI buses for display and touch
spi:
- id: tft
clk_pin: GPIO14
mosi_pin: GPIO13
miso_pin: GPIO12
- id: touch
clk_pin: GPIO25
mosi_pin: GPIO32
miso_pin: GPIO39
touchscreen:
platform: xpt2046
spi_id: touch
cs_pin: GPIO33
interrupt_pin: GPIO36
update_interval: 50ms
threshold: 400
calibration:
x_min: 3860
x_max: 280
y_min: 340
y_max: 3860
transform:
swap_xy: false
# Create a font to use, add and remove glyphs as needed.
# Crea las fuente que quieres utilizar, añade o quita los caracteres que necesites.
font:
- file: "gfonts://Itim"
id: fecha
size: 15
- file: "gfonts://Itim"
id: fetcha
size: 17
- file: "gfonts://Kanit"
id: hora
size: 60
- file: "gfonts://Roboto"
id: info
size: 15
- file: "gfonts://Roboto"
id: botones
size: 11
# Create the colors you want to use.
# Crea los colores que quieres utilizar.
color:
- id: black
hex: '000000'
- id: orange
hex: 'eb9c17'
- id: red
hex: 'b20b23'
- id: green
hex: '148e23'
- id: grey
hex: '464646'
# Create the icons you want to use.
# Crea los iconos que quieres utilizar.
image:
- file: mdi:home-thermometer
id: hometemperature
resize: 40x40
- file: mdi:weather-partly-cloudy
id: weather
resize: 40x40
- file: mdi:solar-power-variant
id: finance
resize: 40x40
- file: mdi:transmission-tower
id: health
resize: 40x40
- file: mdi:page-previous
id: back
resize: 40x40
- file: mdi:lightbulb-group-off-outline
id: fan
resize: 40x40
- file: mdi:floor-lamp-torchiere
id: thermostat
resize: 40x40
- file: mdi:mirror-rectangle
id: vacuum
resize: 40x40
- file: mdi:led-strip-variant
id: desk
resize: 40x40
- file: mdi:desk-lamp
id: printer
resize: 40x40
- file: mdi:lightbulb
id: printer3d
resize: 40x40
- file: mdi:home-assistant
id: habbit
resize: 40x40
# Replace the home gif as you want.
# Reemplaza el gif the inicio como quieras.
#animation:
# - file: "habbit.gif"
# id: ha
# resize: 70x70
# type: TRANSPARENT_BINARY
# This will fetch time from Home Assistant
time:
- platform: homeassistant
id: esptime
# Create sensors from HA you want to use and show.
# Crea los sensores de HA que quieres utilizar y mostrar.
sensor:
- platform: homeassistant
id: temperatura
entity_id: sensor.wandthermostat_jan_temperatur
internal: true
- platform: homeassistant
id: humedad
entity_id: sensor.wandthermostat_jan_luftfeuchtigkeit
internal: true
- platform: homeassistant
id: tempexterior
entity_id: sensor.aussentemperatur_temperatur
internal: true
- platform: homeassistant
id: problluvia
entity_id: sensor.aussentemperatur_luftfeuchtigkeit
internal: true
- platform: homeassistant
id: solarkwh
entity_id: sensor.homestation_solar_total_energie_heute
internal: true
- platform: homeassistant
id: netzeinsp
entity_id: sensor.solar_netzeinspeisung_kwh_taglich
internal: true
- platform: homeassistant
id: weight
entity_id: sensor.stromverbrauch_taglich
internal: true
- platform: homeassistant
id: distancia
entity_id: sensor.stromverbrauch_gesamt_kwh
internal: true
- platform: homeassistant
id: totalstrom
entity_id: sensor.total_power_nur_verbrauch
internal: true
text_sensor:
- platform: homeassistant
id: aireacondicionado
entity_id: scene.lichtgruppe_wohnzimmer_aus
internal: true
- platform: homeassistant
id: calefaccion
entity_id: light.schlafzimmerlicht
internal: true
- platform: homeassistant
id: aspirador
entity_id: switch.bad_spiegellicht
internal: true
- platform: homeassistant
id: escritorio
entity_id: light.wandlicht
internal: true
- platform: homeassistant
id: impresora
entity_id: switch.pc_led_pv_led
internal: true
- platform: homeassistant
id: impresora3d
entity_id: light.couchlicht
internal: true
# Assigns a function to each button, by calling the corresponding service in HA.
# Asigna una función a cada botón, llamando al servicio correspondiente en HA.
binary_sensor:
- platform: touchscreen
name: Button 1
x_min: 0
x_max: 140
y_min: 0
y_max: 65
on_press:
then:
- if:
condition:
lambda: 'return !id(show_return_page);'
then:
- globals.set:
id: show_return_page
value: !lambda "return !id(show_return_page);"
else:
- homeassistant.service:
service: scene.toggle
data:
entity_id: scene.lichtgruppe_wohnzimmer_aus
- platform: touchscreen
name: Button 2
x_min: 140
x_max: 280
y_min: 0
y_max: 65
on_press:
then:
- if:
condition:
lambda: 'return !id(show_return_page);'
then:
- globals.set:
id: show_return_page
value: !lambda "return !id(show_return_page);"
else:
- homeassistant.service:
service: light.toggle
data:
entity_id: light.schlafzimmerlicht
- platform: touchscreen
name: Button 3
x_min: 0
x_max: 140
y_min: 65
y_max: 130
on_press:
then:
- if:
condition:
lambda: 'return !id(show_return_page);'
then:
- globals.set:
id: show_return_page
value: !lambda "return !id(show_return_page);"
else:
- homeassistant.service:
service: switch.toggle
data:
entity_id: switch.bad_spiegellicht
- platform: touchscreen
name: Button 4
x_min: 140
x_max: 280
y_min: 65
y_max: 130
on_press:
then:
- if:
condition:
lambda: 'return !id(show_return_page);'
then:
- globals.set:
id: show_return_page
value: !lambda "return !id(show_return_page);"
else:
- homeassistant.service:
service: light.toggle
data:
entity_id: light.wandlicht
- platform: touchscreen
name: Button 5
x_min: 0
x_max: 140
y_min: 130
y_max: 195
on_press:
then:
- if:
condition:
lambda: 'return !id(show_return_page);'
then:
- globals.set:
id: show_return_page
value: !lambda "return !id(show_return_page);"
else:
- homeassistant.service:
service: switch.toggle
data:
entity_id: switch.pc_led_pv_led
- platform: touchscreen
name: Button 6
x_min: 140
x_max: 280
y_min: 130
y_max: 195
on_press:
then:
- if:
condition:
lambda: 'return !id(show_return_page);'
then:
- globals.set:
id: show_return_page
value: !lambda "return !id(show_return_page);"
else:
- homeassistant.service:
service: light.toggle
data:
entity_id: light.couchlicht
- platform: touchscreen
name: Button 7
x_min: 0
x_max: 140
y_min: 195
y_max: 260
on_press:
then:
- if:
condition:
lambda: 'return !id(show_return_page);'
then:
- globals.set:
id: show_return_page
value: !lambda "return !id(show_return_page);"
- platform: touchscreen
name: Button 8
x_min: 140
x_max: 280
y_min: 195
y_max: 260
on_press:
then:
- globals.set:
id: show_return_page
value: !lambda "return !id(show_return_page);"
# Setup the ili9xxx platform
# Display is used as 240x320 by default so we rotate it to 90° model: ili9342 changed to model: ili9341
display:
- platform: ili9xxx
id: esp_display
model: ili9341
spi_id: tft
cs_pin: GPIO15
dc_pin: GPIO2
rotation: 0
invert_colors: false
lambda: |-
if (id(show_return_page)) {
int button_width = 100;
int button_height = 65;
int x_start = 15;
int y_start = 15;
int x_padding = 10;
int y_padding = 10;
// Define los textos para los botones
const char* button_texts[] = {
"Wohnzimmer",
"Schlafzimmer",
"Badlicht",
"Wandlicht",
"PC-Licht",
"Couchlicht",
"Free",
"Start"
};
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 2; col++) {
int button_index = row * 2 + col;
int x = x_start + col * (button_width + x_padding);
int y = y_start + row * (button_height + y_padding);
it.rectangle(x, y, button_width, button_height, id(grey));
int text_width = strlen(button_texts[button_index]) * 5.5;
int text_height = 16;
it.print(x + (button_width - text_width) / 2, y + (button_height - text_height) / 2 + 20, id(botones), button_texts[button_index]);
}
}
if (id(aireacondicionado).state == "on") {
it.image(45, 20, id(fan), id(orange));
} else {
it.image(45, 20, id(fan), id(grey));
}
if (id(calefaccion).state == "on") {
it.image(155, 20, id(thermostat), id(orange));
} else {
it.image(155, 20, id(thermostat), id(grey));
}
if (id(aspirador).state == "on") {
it.image(45, 95, id(vacuum), id(orange));
} else {
it.image(45, 95, id(vacuum), id(grey));
}
if (id(escritorio).state == "on") {
it.image(155, 95, id(desk), id(orange));
} else {
it.image(155, 95, id(desk), id(grey));
}
if (id(impresora).state == "on") {
it.image(45, 170, id(printer), id(orange));
} else {
it.image(45, 170, id(printer), id(grey));
}
if (id(impresora3d).state == "on") {
it.image(155, 170, id(printer3d), id(orange));
} else {
it.image(155, 170, id(printer3d), id(grey));
}
it.image(45, 245, id(habbit), id(grey));
it.image(155, 245, id(back), id(green));
} else {
static int y = 182;
static int y_direction = 4; // Velocidad del movimiento
const int y_min = 180;
const int y_max = 187;
it.fill(id(black));
it.strftime(120, 55, id(fecha), TextAlign::CENTER, "%d/%m/%Y", id(esptime).now());
it.strftime(120, 92, id(hora), TextAlign::CENTER, "%H:%M", id(esptime).now());
it.printf(120, 135, id(fetcha), TextAlign::CENTER, "Aussentemp %.1f C", id(tempexterior).state);
it.line(50, 150, 190, 150);
it.printf(120, 163, id(fetcha), TextAlign::CENTER, "Hausstr %.1f W", id(totalstrom).state);
static int current_text_index = 0;
static float text_timer = 0;
const float text_interval = 4.0; // Intervalo para cambiar el texto en segundos
text_timer += 1.0;
if (text_timer >= text_interval) {
text_timer = 0;
current_text_index = (current_text_index + 1) % 4; // Alternar entre cuatro textos
}
if (current_text_index == 0) {
it.image(15, 260, id(hometemperature), id(orange));
it.print(70, 260, id(info), "Temperatur");
it.printf(175, 260, id(info), "%.1f C", id(temperatura).state);
it.print(70, 280, id(info), "Luftfeuchte");
it.printf(175, 280, id(info), "%.1f %%", id(humedad).state);
} else if (current_text_index == 1) {
it.image(15, 260, id(weather), id(orange));
it.print(70, 260, id(info), "Temperatur");
it.printf(175, 260, id(info), "%.1f C", id(tempexterior).state);
it.print(70, 280, id(info), "Au Luftfeuchte");
it.printf(175, 280, id(info), "%.1f %%", id(problluvia).state);
} else if (current_text_index == 2) {
it.image(15, 260, id(finance), id(green));
it.print(70, 260, id(info), "Solarertrag");
it.printf(175, 260, id(info), "%.1f kWh", id(solarkwh).state);
it.print(70, 280, id(info), "Einspeisung");
it.printf(175, 280, id(info), "%.1f kWh", id(netzeinsp).state);
} else if (current_text_index == 3) {
it.image(15, 260, id(health), id(red));
it.print(70, 260, id(info), "Strom heute");
it.printf(175, 260, id(info), "%.1f kWh", id(weight).state);
it.print(70, 280, id(info), "Strom total");
it.printf(175, 280, id(info), "%.1f kWh", id(distancia).state);
}
}