Created
November 23, 2023 11:50
-
-
Save GuySie/3721b7851c6a2de644453f0570dab87c to your computer and use it in GitHub Desktop.
ESPHome CYD Thermostat example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ============================================================ | |
# Edit substitutions for your naming, devices and passwords here. | |
# | |
# This code assumes you have a climate thermostat entity and a separate temperature sensor. If you want to use the temperature sensor in your thermostat you need to change the code. | |
# thermostat_entity: Your climate entity that this device will control. | |
# temperature_entity: Your thermometer sensor that measures the current temperature in the room. Only used for graph and display. | |
substitutions: | |
name: cyd-thermostat | |
friendly_name: "CYD Thermostat Control" | |
thermostat_entity: climate.your-thermostat | |
temperature_entity: sensor.your-thermometer | |
api_key: !secret api_key | |
ota_password: !secret ota_password | |
ap_password: !secret ap_password | |
wifi_ssid: !secret wifi_ssid | |
wifi_password: !secret wifi_password | |
# ============================================================ | |
# ESPHome YAML start | |
# | |
esphome: | |
name: ${name} | |
friendly_name: ${friendly_name} | |
esp32: | |
board: esp32dev | |
framework: | |
type: arduino | |
# Enable logging | |
logger: | |
# Enable Home Assistant API | |
api: | |
encryption: | |
key: ${api_key} | |
ota: | |
password: ${ota_password} | |
wifi: | |
ssid: ${wifi_ssid} | |
password: ${wifi_password} | |
# Enable fallback hotspot (captive portal) in case wifi connection fails | |
ap: | |
ssid: "Cyd-Screen Fallback Hotspot" | |
password: ${ap_password} | |
captive_portal: | |
# ============================================================ | |
# ESPHome Display related setup | |
# | |
# Create a font to use, add and remove glyphs as needed. | |
font: | |
- file: 'fonts/Arimo-Regular.ttf' | |
id: arimo40 | |
size: 40 | |
glyphs: " .,°0123456789C+-OfNAna" | |
- file: 'fonts/Arimo-Regular.ttf' | |
id: arimo14 | |
size: 14 | |
glyphs: " .,0123456789NAna" | |
- file: 'fonts/Arimo-Regular.ttf' | |
id: arimo10 | |
size: 10 | |
glyphs: "CurentTagNA" | |
# Create color scheme | |
color: | |
- id: white | |
hex: ffffff | |
- id: ha_blue | |
hex: 18bcf2 | |
- id: ha_yellow | |
hex: ffd502 | |
# Define the graph | |
# TO DO: Weird behavior of target temperature line. Seems to not display until changed? Figure this out. | |
graph: | |
- id: tempgraph | |
duration: 1h | |
width: 260 | |
height: 100 | |
x_grid: 10min | |
y_grid: 2.5 | |
max_value: 25.0 | |
min_value: 15.0 | |
traces: | |
# Display current temperature as a solid blue line | |
- sensor: current_temperature | |
line_type: SOLID | |
line_thickness: 2 | |
color: ha_blue | |
# Display target temperature as a dashed yellow line | |
- sensor: target_temperature | |
line_type: DASHED | |
line_thickness: 2 | |
color: ha_yellow | |
# ============================================================ | |
# Home Assistant related setup | |
# | |
light: | |
# Set up display backlight | |
- platform: monochromatic | |
output: backlight_pwm | |
name: Display Backlight | |
id: backlight | |
restore_mode: ALWAYS_ON | |
# Set up LED on the back and turn it off by default | |
- platform: rgb | |
name: RGB | |
id: led | |
red: led_red | |
green: led_green | |
blue: led_blue | |
restore_mode: ALWAYS_OFF | |
# Set up sensors for thermostat state, current temperature, and target temperature | |
text_sensor: | |
- platform: homeassistant | |
id: thermostat | |
entity_id: ${thermostat_entity} | |
internal: true | |
sensor: | |
- platform: homeassistant | |
id: current_temperature | |
entity_id: ${temperature_entity} | |
internal: true | |
- platform: homeassistant | |
id: target_temperature | |
entity_id: ${thermostat_entity} | |
attribute: temperature | |
internal: true | |
# Set up sensor for LDR (light meter) | |
- platform: adc | |
pin: GPIO34 | |
id: board_ldr | |
name: "board_ldr" | |
update_interval: 10000ms | |
entity_category: "diagnostic" | |
# Reports the WiFi signal strength/RSSI in dB | |
- platform: wifi_signal | |
name: "WiFi Signal dB" | |
id: wifi_signal_db | |
update_interval: 60s | |
entity_category: "diagnostic" | |
# Reports the WiFi signal strength in % | |
- platform: copy | |
source_id: wifi_signal_db | |
name: "WiFi Signal Percent" | |
filters: | |
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0); | |
unit_of_measurement: "Signal %" | |
entity_category: "diagnostic" | |
# Reports the light brightness in % | |
# TO DO: If we smooth this out, we could use this to auto adjust brightness of backlight? | |
# TO DO: Assumes values of 0.075 for full brightness and 0.49 for pitch black, for now - proper values should be tested. | |
- platform: copy | |
source_id: board_ldr | |
name: "Light Percent" | |
filters: | |
- lambda: return min(max((100 - (((x - 0.075) / (0.49 - 0.075)) * 100)), 0.0), 100.0); | |
unit_of_measurement: "Light %" | |
# Setup binary sensors for the four areas for touch | |
# TO DO: Disable plus and minus areas when not in heating mode | |
binary_sensor: | |
# Minus button to lower target temperature | |
- platform: touchscreen | |
name: "Minus button" | |
x_min: 20 | |
x_max: 80 | |
y_min: 20 | |
y_max: 60 | |
on_press: | |
- homeassistant.service: | |
service: climate.set_temperature | |
data: | |
entity_id: ${thermostat_entity} | |
temperature: !lambda |- | |
auto target = id(target_temperature).state; | |
target -= 0.5; | |
return target; | |
# Plus button to raise target temperature | |
- platform: touchscreen | |
name: "Plus button" | |
x_min: 240 | |
x_max: 300 | |
y_min: 20 | |
y_max: 60 | |
on_press: | |
- homeassistant.service: | |
service: climate.set_temperature | |
data: | |
entity_id: ${thermostat_entity} | |
temperature: !lambda |- | |
auto target = id(target_temperature).state; | |
target += 0.5; | |
return target; | |
# Heat button to turn on heating mode | |
- platform: touchscreen | |
name: "Heat button" | |
x_min: 20 | |
x_max: 80 | |
y_min: 80 | |
y_max: 120 | |
on_press: | |
- homeassistant.service: | |
service: climate.turn_on | |
data: | |
entity_id: ${thermostat_entity} | |
# Off button to turn off heating mode | |
- platform: touchscreen | |
name: "Off button" | |
x_min: 240 | |
x_max: 300 | |
y_min: 80 | |
y_max: 120 | |
on_press: | |
- homeassistant.service: | |
service: climate.turn_off | |
data: | |
entity_id: ${thermostat_entity} | |
# ============================================================ | |
# Load images and icons | |
# TO DO: Load Tile-card style button images | |
image: | |
- file: mdi:fire | |
id: heat | |
resize: 34x34 | |
- file: mdi:power | |
id: "off" | |
resize: 34x34 | |
# ============================================================ | |
# Hardware related setup | |
# | |
# 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 | |
# Setup board power switches | |
switch: | |
- platform: restart | |
name: "$friendly_name restart" | |
- platform: shutdown | |
name: "$friendly_name shutdown" | |
- platform: safe_mode | |
name: "$friendly_name restart (Safe Mode)" | |
# Setup a pin to control the backlight | |
output: | |
- platform: ledc | |
pin: GPIO21 | |
id: backlight_pwm | |
# Setup channels for the red/green/blue of the LED on the back | |
- platform: ledc | |
pin: GPIO4 | |
id: led_red | |
inverted: true | |
- platform: ledc | |
pin: GPIO16 | |
id: led_green | |
inverted: true | |
- platform: ledc | |
pin: GPIO17 | |
id: led_blue | |
inverted: true | |
# Setup the ili9xxx platform | |
# | |
# Display is used as 240x320 by default so we rotate it to 90° | |
# | |
# We print date and time wth the strftime() function, see the ESPHome documentation to | |
# format date and atime to your locale. | |
display: | |
- platform: ili9xxx | |
model: ili9341 | |
spi_id: tft | |
cs_pin: GPIO15 | |
dc_pin: GPIO2 | |
rotation: 90 | |
# Draw interface for touchscreen button control, display of current and target temperature, and graphing of current temperature | |
# Only show target temperature and buttons if thermostat is in heating mode | |
# TO DO: Replace blue and yellow filled rectangles with button images | |
lambda: |- | |
it.fill(id(Color::BLACK)); | |
if (id(thermostat).state == "heat") { | |
it.filled_rectangle(20, 20, 60, 40, id(ha_blue)); | |
it.print(50, 40, id(arimo40), TextAlign::CENTER, "-"); | |
it.filled_rectangle(240, 20, 60, 40, id(ha_blue)); | |
it.print(270, 40, id(arimo40), TextAlign::CENTER, "+"); | |
} | |
if (id(thermostat).has_state()) { | |
if (id(thermostat).state == "heat") { | |
it.printf(160, 10, id(arimo10), TextAlign::TOP_CENTER, "Target"); | |
it.printf(160, 17, id(arimo40), TextAlign::TOP_CENTER, "%.1f °C", id(target_temperature).state); | |
} | |
else { | |
if (id(thermostat).state == "off") { | |
it.printf(160, 17, id(arimo40), TextAlign::TOP_CENTER, "Off"); | |
} | |
} | |
} | |
if (id(thermostat).state == "heat") { | |
it.filled_rectangle(20, 80, 60, 40, id(ha_yellow)); | |
it.image(33, 83, id(heat)); | |
} | |
else { | |
it.filled_rectangle(20, 80, 60, 40, id(ha_blue)); | |
it.image(33, 83, id(heat)); | |
} | |
if (id(thermostat).state == "off") { | |
it.filled_rectangle(240, 80, 60, 40, id(ha_yellow)); | |
it.image(253, 83, id(off)); | |
} | |
else { | |
it.filled_rectangle(240, 80, 60, 40, id(ha_blue)); | |
it.image(253, 83, id(off)); | |
} | |
it.printf(160, 70, id(arimo10), TextAlign::TOP_CENTER, "Current"); | |
if (id(current_temperature).has_state()) { | |
it.printf(160, 77, id(arimo40), TextAlign::TOP_CENTER, "%.1f °C", id(current_temperature).state); | |
} | |
it.print(10, 133, id(arimo14), TextAlign::CENTER_LEFT, "25"); | |
it.print(10, 155, id(arimo14), TextAlign::CENTER_LEFT, "22.5"); | |
it.print(10, 180, id(arimo14), TextAlign::CENTER_LEFT, "20"); | |
it.print(10, 205, id(arimo14), TextAlign::CENTER_LEFT, "17.5"); | |
it.print(10, 227, id(arimo14), TextAlign::CENTER_LEFT, "15"); | |
it.graph(50, 130, id(tempgraph)); | |
# Set up the xpt2046 touch platform | |
touchscreen: | |
platform: xpt2046 | |
spi_id: touch | |
cs_pin: GPIO33 | |
interrupt_pin: GPIO36 | |
update_interval: 50ms | |
report_interval: 1s | |
threshold: 400 | |
calibration_x_min: 3860 | |
calibration_x_max: 280 | |
calibration_y_min: 340 | |
calibration_y_max: 3860 | |
swap_x_y: false |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment