Skip to content

Instantly share code, notes, and snippets.

@jakesOneFourSeven
Last active February 1, 2026 14:47
Show Gist options
  • Select an option

  • Save jakesOneFourSeven/64620e6b8df7d24cad17ec803a0773e6 to your computer and use it in GitHub Desktop.

Select an option

Save jakesOneFourSeven/64620e6b8df7d24cad17ec803a0773e6 to your computer and use it in GitHub Desktop.
esphome:
name: esphome-web-41bcfc
friendly_name: 'CYD Pip-Boy'
min_version: 2024.11.0
name_add_mac_suffix: false
esp32:
variant: esp32
framework:
type: esp-idf
logger:
api:
ota:
- platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
spi:
- id: bus_display
clk_pin: GPIO14
mosi_pin: GPIO13
miso_pin: GPIO12
- id: bus_touch
clk_pin: GPIO25
mosi_pin: GPIO32
miso_pin: GPIO39
display:
- platform: ili9xxx
id: my_display
model: ILI9341
spi_id: bus_display
cs_pin: GPIO15
dc_pin: GPIO2
reset_pin: GPIO4
rotation: 180°
invert_colors: false
dimensions:
width: 320
height: 240
update_interval: never
auto_clear_enabled: false
touchscreen:
platform: xpt2046
id: ts
spi_id: bus_touch
cs_pin: GPIO33
interrupt_pin: GPIO36
calibration:
x_min: 221
x_max: 3748
y_min: 282
y_max: 3796
transform:
swap_xy: true
mirror_x: true
mirror_y: false
output:
- platform: ledc
pin: GPIO21
id: backlight_pwm
light:
- platform: monochromatic
output: backlight_pwm
id: backlight
name: "Display Backlight"
restore_mode: ALWAYS_ON
time:
- platform: homeassistant
id: ha_time
font:
- file: "gfonts://Roboto+Mono@700"
id: font_large
size: 24
- file: "gfonts://Roboto+Mono@400"
id: font_small
size: 14
- file: "gfonts://Material+Symbols+Outlined"
id: icon_font
size: 40
glyphs:
- "\U0000E80B" # Bolt
- "\U0000E1AF" # Flow
- "\U0000E2BE" # Battery
globals:
- id: pv_prod
type: float
initial_value: '0.0'
- id: house_load
type: float
initial_value: '0.0'
- id: batt_soc_val
type: float
initial_value: '0.0'
- id: inv_power
type: float
initial_value: '0.0'
- id: batt_power
type: float
initial_value: '0.0'
lvgl:
touchscreens:
- touchscreen_id: ts
buffer_size: 10%
style_definitions:
- id: pipboy_green_text
text_color: 0x00FF00
text_font: font_small
- id: pipboy_green_large
text_color: 0x00FF00
text_font: font_large
- id: pipboy_icons
text_color: 0x00FF00
text_font: icon_font
- id: page_style
bg_color: 0x000000
- id: header_style
bg_color: 0x001A00
border_width: 0
radius: 0
- id: bar_bg_style
bg_color: 0x001100
border_color: 0x00FF00
border_width: 1
- id: switch_base_style
bg_color: 0x000000
border_color: 0x00FF00
border_width: 2
radius: 4
- id: pivot_style
bg_color: 0x00FF00
radius: 10
pages:
- id: page_main
styles: page_style
widgets:
# Background click listener
- obj:
width: 100%
height: 100%
bg_opa: 0%
clickable: true
on_click:
then:
- lvgl.page.show: page_switches
# Header
- obj:
width: 310
height: 28
x: 5
y: 0
styles: header_style
widgets:
- label:
align: left_mid
pad_left: 5
text: "PIP-BOY 3000 MK V"
styles: pipboy_green_text
- label:
id: clock_label
align: right_mid
text: "00:00"
styles: pipboy_green_text
# Grid Lines
- obj: { width: 320, height: 1, y: 105, bg_color: 0x00FF00, bg_opa: 15% }
- obj: { width: 320, height: 1, y: 190, bg_color: 0x00FF00, bg_opa: 15% }
# Column 1: LOAD
- label:
x: 0
y: 40
width: 106
text_align: center
text: "\U0000E80B"
styles: pipboy_icons
- label:
x: 0
y: 120
width: 106
text_align: center
text: "VAULT LOAD"
styles: pipboy_green_text
- label:
id: house_value
x: 0
y: 145
width: 106
text_align: center
text: "0"
styles: pipboy_green_large
# Column 2: RADS (Ticks only)
- meter:
id: pv_meter
x: 115
y: 35
width: 90
height: 90
bg_opa: 0%
border_width: 0
scales:
- range_from: 0
range_to: 5000
angle_range: 240
rotation: 150
ticks:
count: 11
length: 6
width: 2
color: 0x004400
major:
stride: 2
length: 10
width: 3
color: 0x00FF00
indicators:
- line:
id: pv_needle
width: 5
color: 0x00FF00
r_mod: -12
# Pivot Dot for Needle
- obj:
x: 155
y: 75
width: 10
height: 10
styles: pivot_style
- label:
x: 106
y: 125
width: 108
text_align: center
text: "RADS"
styles: pipboy_green_text
- label:
id: pv_value
x: 106
y: 145
width: 108
text_align: center
text: "0"
styles: pipboy_green_large
# Column 3: FLOW
- label:
x: 214
y: 40
width: 106
text_align: center
text: "\U0000E1AF"
styles: pipboy_icons
- label:
x: 214
y: 120
width: 106
text_align: center
text: "FLOW"
styles: pipboy_green_text
- label:
id: inv_value
x: 214
y: 145
width: 106
text_align: center
text: "0"
styles: pipboy_green_large
# Battery Core
- bar:
id: battery_bar
width: 250
height: 18
x: 35
y: 215
styles: bar_bg_style
- label:
id: battery_label
x: 35
y: 195
text: "CORE: 0%"
styles: pipboy_green_text
- id: page_switches
styles: page_style
widgets:
- obj:
width: 310
height: 28
x: 5
y: 0
styles: header_style
clickable: true
on_click:
then:
- lvgl.page.show: page_main
widgets:
- label:
align: left_mid
pad_left: 5
text: "SYSTEM CONTROL"
styles: pipboy_green_text
- label:
id: clock_label_sw
align: right_mid
text: "00:00"
styles: pipboy_green_text
# Switch 1
- label:
x: 30
y: 60
text: "MAIN GEYSER"
styles: pipboy_green_text
- switch:
id: sw_widget_main
x: 210
y: 55
width: 60
height: 30
styles: switch_base_style
on_value:
then:
- if:
condition: { lambda: 'return x;' }
then: [switch.turn_on: main_geyser]
else: [switch.turn_off: main_geyser]
# Switch 2
- label:
x: 30
y: 110
text: "KITCHEN GEYSER"
styles: pipboy_green_text
- switch:
id: sw_widget_kitchen
x: 210
y: 105
width: 60
height: 30
styles: switch_base_style
on_value:
then:
- if:
condition: { lambda: 'return x;' }
then: [switch.turn_on: kitchen_geyser]
else: [switch.turn_off: kitchen_geyser]
# Switch 3
- label:
x: 30
y: 160
text: "POOL PUMP"
styles: pipboy_green_text
- switch:
id: sw_widget_pool
x: 210
y: 155
width: 60
height: 30
styles: switch_base_style
on_value:
then:
- if:
condition: { lambda: 'return x;' }
then: [switch.turn_on: pool_pump]
else: [switch.turn_off: pool_pump]
- button:
x: 105
y: 200
width: 110
height: 35
styles: switch_base_style
widgets:
- label:
align: center
text: "RETURN"
styles: pipboy_green_text
on_click:
then:
- lvgl.page.show: page_main
# HA Integration
switch:
- platform: homeassistant
id: main_geyser
entity_id: switch.sonoff_10025b0b5c
on_state:
then:
- lambda: |-
if (x) lv_obj_add_state(id(sw_widget_main), LV_STATE_CHECKED);
else lv_obj_clear_state(id(sw_widget_main), LV_STATE_CHECKED);
- platform: homeassistant
id: kitchen_geyser
entity_id: switch.sonoff_100258f71c_1
on_state:
then:
- lambda: |-
if (x) lv_obj_add_state(id(sw_widget_kitchen), LV_STATE_CHECKED);
else lv_obj_clear_state(id(sw_widget_kitchen), LV_STATE_CHECKED);
- platform: homeassistant
id: pool_pump
entity_id: switch.sonoff_100258f5d3_1
on_state:
then:
- lambda: |-
if (x) lv_obj_add_state(id(sw_widget_pool), LV_STATE_CHECKED);
else lv_obj_clear_state(id(sw_widget_pool), LV_STATE_CHECKED);
script:
- id: refresh_all
then:
- lambda: |-
char buf[32];
sprintf(buf, "%.0f W", id(pv_prod));
lv_label_set_text(id(pv_value), buf);
lv_meter_set_indicator_value(id(pv_meter), id(pv_needle), (int32_t)id(pv_prod));
sprintf(buf, "%.0f W", id(house_load));
lv_label_set_text(id(house_value), buf);
sprintf(buf, "%.0f W", id(inv_power));
lv_label_set_text(id(inv_value), buf);
lv_bar_set_value(id(battery_bar), (int)id(batt_soc_val), LV_ANIM_ON);
sprintf(buf, "CORE: %.0f%%", id(batt_soc_val));
lv_label_set_text(id(battery_label), buf);
sensor:
- platform: homeassistant
id: sensor_pv
entity_id: sensor.esphome_web_f3a4dc_inverterhoas_pv_average_power
on_value:
- globals.set: { id: pv_prod, value: !lambda "return x;" }
- script.execute: refresh_all
- platform: homeassistant
id: sensor_house
entity_id: sensor.electricity_energy_instant_power
on_value:
- globals.set: { id: house_load, value: !lambda "return x;" }
- script.execute: refresh_all
- platform: homeassistant
id: sensor_soc
entity_id: sensor.esphome_web_f3a4dc_inverterhoas_battery_state_of_charge
on_value:
- globals.set: { id: batt_soc_val, value: !lambda "return x;" }
- script.execute: refresh_all
- platform: homeassistant
id: sensor_inv
entity_id: sensor.esphome_web_f3a4dc_inverterhoas_average_inverter_power
on_value:
- globals.set: { id: inv_power, value: !lambda "return x;" }
- script.execute: refresh_all
interval:
- interval: 15s
then:
- lambda: |-
auto t = id(ha_time).now();
if (t.is_valid()) {
char clock_buf[8];
t.strftime(clock_buf, sizeof(clock_buf), "%H:%M");
lv_label_set_text(id(clock_label), clock_buf);
lv_label_set_text(id(clock_label_sw), clock_buf);
}
@jakesOneFourSeven
Copy link
Author

jakesOneFourSeven commented Jan 31, 2026

WhatsApp Image 2026-01-13 at 12 04 07
WhatsApp Image 2026-01-13 at 10 32 05

@low-streaming
Copy link

it looks nice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment