@GreyLinux thank you for taking the time to document your journey - you have helped me tremendously. I’ve been inspired to share my progress as well in case anyone would find it helpful for themselves.
I used the following esp32 device and display:
http://amazon.com/gp/product/B0B1M9S9V6
https://www.amazon.com/dp/B08D5ZD528
substitutions:
node_id: "master_bedroom_thermostat"
globals:
- id: temp_in_fahrenheit
restore_value: 'no'
type: float
- id: climate_mode
restore_value: 'no'
type: std::string
- id: active_climate_action
restore_value: 'no'
type: std::string
time:
- platform: homeassistant
id: my_time
on_time:
- seconds: 0
minutes: /1
then:
- component.update: tft_display
# i2c:
# - id: bus_a
# sda: 47 # minid1 - 21 # Blue
# scl: 48 # minid1 - 22 # Green
# scan: true
### >>>>>>>>>>>>> Text Sensors <<<<<<<<<<<<<<< ###
text_sensor:
# Last Rain - date time
- platform: homeassistant
name: outdoor_last_rain_sensor
id: outdoor_last_rain_sensor
entity_id: sensor.my_weather_station_last_rain
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
### >>>>>>>>>>>>> Sensors <<<<<<<<<<<<<<< ###
sensor:
- platform: uptime
id: ${node_id}_uptime
name: Uptime
- platform: homeassistant
name: temp_sensor_celsius
id: temp_sensor_celsius
entity_id: sensor.master_bedroom_mmwave_sensor_temp
internal: true
filters:
- lambda:
id(temp_in_fahrenheit) = x;
return (x - 32) * 5/9;
on_value:
then:
- component.update: tft_display
- platform: homeassistant
name: humidity_sensor
id: humidity_sensor
entity_id: sensor.master_bedroom_mmwave_sensor_humidity
internal: true
on_value:
then:
- component.update: tft_display
### >>>>>>>>>>>>> Weather Station Sensors <<<<<<<<<<<<<<< ###
# Temp
- platform: homeassistant
name: outdoor_temp_sensor
id: outdoor_temp_sensor
entity_id: sensor.my_weather_station_temp
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
# Humidity
- platform: homeassistant
name: outdoor_humidity_sensor
id: outdoor_humidity_sensor
entity_id: sensor.my_weather_station_humidity
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
# Feels Like Temp
- platform: homeassistant
name: outdoor_feels_like_temp_sensor
id: outdoor_feels_like_temp_sensor
entity_id: sensor.my_weather_station_feels_like
internal: true
on_value:
then:
- component.update: tft_display
# Absolute Pressure
- platform: homeassistant
name: outdoor_absolute_pressure_sensor
id: outdoor_absolute_pressure_sensor
entity_id: sensor.my_weather_station_abs_pressure
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
# Relative Pressure
- platform: homeassistant
name: outdoor_relative_pressure_sensor
id: outdoor_relative_pressure_sensor
entity_id: sensor.my_weather_station_rel_pressure
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
# Dew Point
- platform: homeassistant
name: outdoor_dew_point_sensor
id: outdoor_dew_point_sensor
entity_id: sensor.my_weather_station_dew_point
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
# Solar UV Index
- platform: homeassistant
name: outdoor_solar_uv_index_sensor
id: outdoor_solar_uv_index_sensor
entity_id: sensor.my_weather_station_uv_index
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
# Solar Rad W/m2
- platform: homeassistant
name: outdoor_solar_rad_watts_sensor
id: outdoor_solar_rad_watts_sensor
entity_id: sensor.my_weather_station_solar_rad
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
# Solar Rad Lux
- platform: homeassistant
name: outdoor_solar_rad_lux_sensor
id: outdoor_solar_rad_lux_sensor
entity_id: sensor.my_weather_station_solar_rad_lx
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
# Wind Speed
- platform: homeassistant
name: outdoor_wind_speed_sensor
id: outdoor_wind_speed_sensor
entity_id: sensor.my_weather_station_wind_speed
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
# Wind Direction
- platform: homeassistant
name: outdoor_wind_direction_sensor
id: outdoor_wind_direction_sensor
entity_id: sensor.my_weather_station_wind_dir
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
# Wind Gust
- platform: homeassistant
name: outdoor_wind_gust_sensor
id: outdoor_wind_gust_sensor
entity_id: sensor.my_weather_station_wind_gust
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
# Event Rain
- platform: homeassistant
name: outdoor_event_rain_sensor
id: outdoor_event_rain_sensor
entity_id: sensor.my_weather_station_event_rain
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
# Hourly Rate Rain
- platform: homeassistant
name: outdoor_hourly_rain_rate_sensor
id: outdoor_hourly_rain_rate_sensor
entity_id: sensor.my_weather_station_hourly_rain_rate
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
# Daily Rain
- platform: homeassistant
name: outdoor_daily_rain_sensor
id: outdoor_daily_rain_sensor
entity_id: sensor.my_weather_station_daily_rain
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
# Weekly Rain
- platform: homeassistant
name: outdoor_weekly_rain_sensor
id: outdoor_weekly_rain_sensor
entity_id: sensor.my_weather_station_weekly_rain
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
# Monthly Rain
- platform: homeassistant
name: outdoor_monthly_rain_sensor
id: outdoor_monthly_rain_sensor
entity_id: sensor.my_weather_station_monthly_rain
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
# Yearly Rain
- platform: homeassistant
name: outdoor_yearly_rain_sensor
id: outdoor_yearly_rain_sensor
entity_id: sensor.my_weather_station_yearly_rain
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
# Lifetime Rain
- platform: homeassistant
name: outdoor_lifetime_rain_sensor
id: outdoor_lifetime_rain_sensor
entity_id: sensor.my_weather_station_lifetime_rain
internal: true
on_value:
if:
condition:
- lambda: 'return id(tft_display).get_active_page() == id(weather_station_page);'
then:
- component.update: tft_display
### >>>>>>>>>>>>> BME280 SENSOR <<<<<<<<<<<<<<< ###
# - platform: bme280_i2c
# temperature:
# id: ${node_id}_temp_sensor
# name: BME280 Temp
# accuracy_decimals: 1
# oversampling: 16x
# pressure:
# id: ${node_id}_pressure
# name: BME280 Pressure
# oversampling: 2x
# humidity:
# id: ${node_id}_humidity
# name: BME280 Humidity
# accuracy_decimals: 1
# oversampling: 8x
# address: 0x76
# update_interval: 30s
### >>>>>>>>>>>>> Switches <<<<<<<<<<<<<<< ###
switch:
- platform: restart # Restart
name: Restart
id: ${node_id}_restart
icon: "mdi:restart"
- platform: shutdown # Shutdown
name: Shutdown
id: ${node_id}_shutdown
- platform: safe_mode # Safe Mode
name: Restart (Safe Mode)"
id: ${node_id}_safe_mode
- platform: template # HVAC Power - Source: https://community.home-assistant.io/t/switch-linked-to-homeassistant-switch/593354/3?u=bsell93
id: hvac_power
optimistic: true
turn_on_action:
- homeassistant.service:
service: switch.turn_on
data:
entity_id: switch.master_bedroom_hvac_power
- delay: 1s
- homeassistant.service:
service: climate.set_hvac_mode
data:
entity_id: climate.master_bedroom_hvac_climate
data_template:
hvac_mode: '{{ mode }}'
variables:
mode: |-
return id(climate_mode);
- delay: 1s
- homeassistant.service:
service: climate.set_temperature
data:
entity_id: climate.master_bedroom_hvac_climate
data_template:
temperature: '{{ target_temp }}'
variables:
target_temp: |-
if (id(${node_id}_climate).mode == CLIMATE_MODE_COOL)
{
return round(id(${node_id}_climate).target_temperature_high * (9.0/5.0) + 32.0) - 1;
}
return round(id(${node_id}_climate).target_temperature_low * (9.0/5.0) + 32.0) + 1;
turn_off_action:
- homeassistant.service:
service: switch.turn_off
data:
entity_id: switch.master_bedroom_hvac_power
### >>>>>>>>>>>>> Climate <<<<<<<<<<<<<<< ###
climate:
- platform: thermostat
name: "Thermostat"
id: ${node_id}_climate
sensor: temp_sensor_celsius
humidity_sensor: humidity_sensor
min_cooling_off_time: 1s # 300s
min_cooling_run_time: 1s # 300s
min_heating_off_time: 1s # 300s
min_heating_run_time: 1s # 300s
min_idle_time: 30s
visual:
temperature_step:
target_temperature: 1
current_temperature: 1
cool_action:
- lambda: |-
id(climate_mode) = "cool";
id(active_climate_action) = "cooling";
- switch.turn_on: hvac_power
heat_action:
- lambda: |-
id(climate_mode) = "heat";
id(active_climate_action) = "heating";
- switch.turn_on: hvac_power
idle_action:
- lambda: |-
id(active_climate_action) = "idle";
- switch.turn_off: hvac_power
on_state:
then:
if:
condition:
- lambda: |-
return id(active_climate_action) != "idle";
then:
- homeassistant.service:
service: climate.set_temperature
data:
entity_id: climate.master_bedroom_hvac_climate
data_template:
hvac_mode: '{{ hvac_mode }}'
temperature: '{{ target_temp }}'
variables:
hvac_mode: |-
auto mode = id(${node_id}_climate).mode;
if (mode == CLIMATE_MODE_COOL)
{
return "cool";
}
else if (mode == CLIMATE_MODE_HEAT)
{
return "heat";
}
return "off";
target_temp: |-
if (id(${node_id}_climate).mode == CLIMATE_MODE_COOL)
{
return round(id(${node_id}_climate).target_temperature_high * (9.0/5.0) + 32.0) - 1;
}
return round(id(${node_id}_climate).target_temperature_low * (9.0/5.0) + 32.0) + 1;
default_preset: Home
on_boot_restore_from: memory
preset:
- name: Home
mode: cool
default_target_temperature_low: 73 °F
default_target_temperature_high: 73 °F
- name: Sleep
mode: cool
default_target_temperature_low: 70 °F
default_target_temperature_high: 70 °F
- name: Away
mode: cool
default_target_temperature_low: 76 °F
default_target_temperature_high: 76 °F
### >>>>>>>>>>>>> Image <<<<<<<<<<<<<<< ###
image:
- file: mdi:close
id: close_icon
resize: 28x28
- file: mdi:power
id: power_icon
resize: 28x28
- file: mdi:fire
id: heat_icon
resize: 28x28
- file: mdi:snowflake
id: cool_icon
resize: 28x28
- file: mdi:minus
id: minus_icon
resize: 40x40
- file: mdi:plus
id: plus_icon
resize: 40x40
### >>>>>>>>>>>>> Font <<<<<<<<<<<<<<< ###
font:
# gfonts://family[@weight]
- file: "gfonts://Roboto"
id: roboto_48
size: 48
- file: "gfonts://Roboto"
id: roboto_24
size: 24
- file: "gfonts://Roboto"
id: roboto_16
size: 16
- file: "gfonts://Roboto"
id: roboto_10
size: 10
### >>>>>>>>>>>>> Color <<<<<<<<<<<<<<< ###
color:
- id: heat_red
hex: ec780f
- id: cool_blue
hex: 096dff
- id: off_green
hex: 08f26d
- id: grey
hex: D1D0CE
- id: dark_grey
hex: A0A0A0
### >>>>>>>>>>>>> SPI <<<<<<<<<<<<<<< ###
spi:
clk_pin: GPIO18 # minid1 - 18; esp32s3 - 11 # Brown
mosi_pin: GPIO23 # minid1 - 23; esp32s3 - 13 # Blue
miso_pin: GPIO19 # minid1 - 19; esp32s3 - 12 # Yellow
### >>>>>>>>>>>>> Display <<<<<<<<<<<<<<< ###
display:
- platform: ili9xxx
model: ILI9341
id: tft_display
dc_pin: GPIO21 # minid1 - 21; esp32s3 - 14 # Purple
cs_pin: GPIO33 # minid1 - 33; esp32s3 - 10 # White
reset_pin: GPIO26 # minid1 - 26; esp32s3 - 9 # Orange
dimensions:
height: 240
width: 320
update_interval: never
# auto_clear_enabled: false
data_rate: 40MHz
transform:
swap_xy: true
mirror_y: true
mirror_x: true
pages:
### >>>>>>>>>>>>> Home Page <<<<<<<<<<<<<<< ###
- id: home_page
lambda: |-
// alignment lines
// it.line(it.get_width()/2, 0, it.get_width()/2, it.get_height());
// it.line(0, it.get_height()/2, it.get_width(), it.get_height()/2);
// it.line(it.get_width()* 1/4, 0, it.get_width()* 1/4, it.get_height());
// it.line(it.get_width()* 3/4, 0, it.get_width()* 3/4, it.get_height());
// it.line(it.get_width()* 1/3, 0, it.get_width()* 1/3, it.get_height());
// it.line(it.get_width()* 2/3, 0, it.get_width()* 2/3, it.get_height());
// Show time
it.strftime(5, 5, id(roboto_16), "%I:%M %p", id(my_time).now());
// Show outdoor feels like temp and humidity
it.printf(it.get_width() - 5, 5, id(roboto_16), TextAlign::TOP_RIGHT, "%.0f°", id(outdoor_feels_like_temp_sensor).state);
// Set Current Humidity
it.printf(it.get_width()/2, (it.get_height()/2) - 50, id(roboto_16), TextAlign::CENTER, "%.0f%%", id(humidity_sensor).state);
// Set Current Temp
it.printf(it.get_width()/2, it.get_height()/2, id(roboto_48), TextAlign::CENTER, "%.0f°", id(temp_in_fahrenheit));
// Set Target Temp
auto current_mode = id(${node_id}_climate).mode;
auto target_temp = id(${node_id}_climate).target_temperature * (9.0/5.0) + 32.0; // Convert to Fahrenheit
auto current_mode_color = id(off_green);
auto active_mode_icon = id(power_icon); // mode icon
auto is_on = false;
if (current_mode == CLIMATE_MODE_HEAT)
{
target_temp = id(${node_id}_climate).target_temperature_low * (9.0/5.0) + 32.0;
current_mode_color = id(heat_red);
active_mode_icon = id(heat_icon);
is_on = true;
}
else if (current_mode == CLIMATE_MODE_COOL)
{
target_temp = id(${node_id}_climate).target_temperature_high * (9.0/5.0) + 32.0;
current_mode_color = id(cool_blue);
active_mode_icon = id(cool_icon);
is_on = true;
}
if (is_on)
{
// Plus/minus icons
it.image((it.get_width()* 1/3) - 20, it.get_height()/2 - 20, id(minus_icon));
it.image((it.get_width()* 2/3) - 20, it.get_height()/2 - 20, id(plus_icon));
// Target Temp
it.printf(it.get_width()/2, (it.get_height()/2) + 50, id(roboto_24), current_mode_color, TextAlign::CENTER, "%.0f°", target_temp);
// Draw rectangle around target temp to indicate button
it.rectangle((it.get_width()/2) - 25, (it.get_height()/2) + 32.5, 50, 37.5, current_mode_color);
}
// Mode icon
it.image(5, it.get_height() - 33, active_mode_icon);
### >>>>>>>>>>>>> Mode Page <<<<<<<<<<<<<<< ###
- id: mode_page
lambda: |-
// Show time
it.strftime(5, 5, id(roboto_16), "%I:%M %p", id(my_time).now());
// Show outdoor feels like temp and humidity
it.printf(it.get_width() - 5, 5, id(roboto_16), TextAlign::TOP_RIGHT, "%.0f°", id(outdoor_feels_like_temp_sensor).state);
auto current_mode = id(${node_id}_climate).mode;
auto heat_mode_color = id(dark_grey);
auto cool_mode_color = id(dark_grey);
auto power_mode_color = id(dark_grey);
if (current_mode == CLIMATE_MODE_HEAT)
{
heat_mode_color = id(heat_red);
}
else if (current_mode == CLIMATE_MODE_COOL)
{
cool_mode_color = id(cool_blue);
}
else
{
power_mode_color = id(off_green);
}
// Render Cool mode button
it.rectangle((it.get_width() * 1/4) - 30, (it.get_height()/2) - 25, 60, 55, cool_mode_color);
it.image((it.get_width() * 1/4) - 14, (it.get_height()/2) - 22, id(cool_icon), cool_mode_color);
it.print((it.get_width() * 1/4) - 25, it.get_height()/2, id(roboto_24), cool_mode_color, "Cool");
// Render Power mode button
it.rectangle((it.get_width()/2) - 30, (it.get_height()/2) - 25, 60, 55, power_mode_color);
it.image((it.get_width()/2) - 14, (it.get_height()/2) - 22, id(power_icon), power_mode_color);
it.print((it.get_width()/2) - 17, it.get_height()/2, id(roboto_24), power_mode_color, "Off");
// Render Heat mode button
it.rectangle((it.get_width() * 3/4) - 30, (it.get_height()/2) - 25, 60, 55, heat_mode_color);
it.image((it.get_width() * 3/4) - 14, (it.get_height()/2) - 22, id(heat_icon), heat_mode_color);
it.print((it.get_width() * 3/4) - 25, it.get_height()/2, id(roboto_24), heat_mode_color, "Heat");
### >>>>>>>>>>>>> Weather Station Page <<<<<<<<<<<<<<< ###
- id: weather_station_page
lambda: |-
// Show time
it.strftime(5, 5, id(roboto_16), "%I:%M %p", id(my_time).now());
// Show X - close button top right
it.image(it.get_width() - 5, 5, id(close_icon), ImageAlign::TOP_RIGHT);
// Temp
it.printf(5, it.get_height() * 1/10, id(roboto_10), "Temperature: %.0f°", id(outdoor_temp_sensor).state);
// Humidity
it.printf(5, it.get_height() * 2/10, id(roboto_10), "Humidity: %.0f%%", id(outdoor_humidity_sensor).state);
// Feels Like Temp
it.printf(5, it.get_height() * 3/10, id(roboto_10), "Feels Like: %.0f°", id(outdoor_feels_like_temp_sensor).state);
// Absolute Pressure
it.printf(5, it.get_height() * 4/10, id(roboto_10), "Abs Pressure: %.0finHg", id(outdoor_absolute_pressure_sensor).state);
// Relative Pressure
it.printf(5, it.get_height() * 5/10, id(roboto_10), "Rel Pressure: %.0finHg", id(outdoor_relative_pressure_sensor).state);
// Dew Point
it.printf(5, it.get_height() * 6/10, id(roboto_10), "Dew Point: %.0f°", id(outdoor_dew_point_sensor).state);
// Solar UV Index
it.printf(5, it.get_height() * 7/10, id(roboto_10), "Solar UV Index: %.0f", id(outdoor_solar_uv_index_sensor).state);
// Solar Rad W/m2 & Lux
it.printf(5, it.get_height() * 8/10, id(roboto_10), "Solar Rad: %.0fW/m2 (%.0f lux)", id(outdoor_solar_rad_watts_sensor).state, id(outdoor_solar_rad_lux_sensor).state);
// Wind Speed & Direction
it.printf(5, it.get_height() * 9/10, id(roboto_10), "Wind: %.0fmph (%.0f°)", id(outdoor_wind_speed_sensor).state, id(outdoor_wind_direction_sensor).state);
// Wind Gust
it.printf(it.get_width()/2, it.get_height() * 9/10, id(roboto_10), "Wind Gust: %.0fmph", id(outdoor_wind_gust_sensor).state);
// Event Rain
it.printf(it.get_width()/2, it.get_height() * 1/10, id(roboto_10), "Event Rain: %.0fin", id(outdoor_event_rain_sensor).state);
// Hourly Rain Rate
it.printf(it.get_width()/2, it.get_height() * 2/10, id(roboto_10), "Hourly Rain Rate: %.0fin", id(outdoor_hourly_rain_rate_sensor).state);
// Last Rain - date time
auto last_rain = id(outdoor_last_rain_sensor).state;
it.printf(it.get_width()/2, it.get_height() * 3/10, id(roboto_10), "Last Rain: %s %s", last_rain.substr(0,10).c_str(), last_rain.substr(11, 5).c_str());
// Daily Rain
it.printf(it.get_width()/2, it.get_height() * 4/10, id(roboto_10), "Daily Rain: %.0fin", id(outdoor_daily_rain_sensor).state);
// Weekly Rain
it.printf(it.get_width()/2, it.get_height() * 5/10, id(roboto_10), "Weekly Rain: %.0fin", id(outdoor_weekly_rain_sensor).state);
// Monthly Rain
it.printf(it.get_width()/2, it.get_height() * 6/10, id(roboto_10), "Monthly Rain: %.0fin", id(outdoor_monthly_rain_sensor).state);
// Yearly Rain
it.printf(it.get_width()/2, it.get_height() * 7/10, id(roboto_10), "Yearly Rain: %.0fin", id(outdoor_yearly_rain_sensor).state);
// Lifetime Rain
it.printf(it.get_width()/2, it.get_height() * 8/10, id(roboto_10), "Lifetime Rain: %.0fin", id(outdoor_lifetime_rain_sensor).state);
### >>>>>>>>>>>>> Touch Screen <<<<<<<<<<<<<<< ###
touchscreen:
platform: xpt2046
id: my_touchscreen
cs_pin: GPIO32 # White
update_interval: 50ms
threshold: 400
transform:
swap_xy: true
calibration:
x_min: 203
x_max: 3839
y_min: 340
y_max: 3849
on_touch:
- binary_sensor.template.publish:
id: touching
state: ON
- lambda: |-
ESP_LOGI("cal", "x=%d, y=%d, x_raw=%d, y_raw=%0d",
touch.x,
touch.y,
touch.x_raw,
touch.y_raw
);
on_release:
- binary_sensor.template.publish:
id: touching
state: OFF
### >>>>>>>>>>>>> Binary Sensors <<<<<<<<<<<<<<< ###
binary_sensor:
### >>>>>>>>>>>>> Home Page Touch Areas <<<<<<<<<<<<<<< ###
- platform: touchscreen
id: temp_down
x_min: 70
x_max: 130
y_min: 100
y_max: 150
page_id: home_page
on_press:
then:
- climate.control:
id: ${node_id}_climate
target_temperature_low: !lambda
auto current_mode = id(${node_id}_climate).mode;
if (current_mode == CLIMATE_MODE_HEAT)
{
auto target_temp_in_f = id(${node_id}_climate).target_temperature_low * (9.0/5.0) + 32.0;
return ((target_temp_in_f - 1) - 32) * 5/9;
}
auto lowest_temp = 50;
return ((lowest_temp) - 32) * 5/9; // Convert back to celsius
target_temperature_high: !lambda
auto current_mode = id(${node_id}_climate).mode;
if (current_mode == CLIMATE_MODE_COOL)
{
auto target_temp_in_f = id(${node_id}_climate).target_temperature_high * (9.0/5.0) + 32.0;
return ((target_temp_in_f - 1) - 32) * 5/9;
}
auto highest_temp = 86;
return ((highest_temp) - 32) * 5/9; // Convert back to celsius
- component.update: tft_display
- platform: touchscreen
id: temp_up
x_min: 205
x_max: 260
y_min: 100
y_max: 150
page_id: home_page
on_press:
then:
- climate.control:
id: ${node_id}_climate
target_temperature_low: !lambda
auto current_mode = id(${node_id}_climate).mode;
if (current_mode == CLIMATE_MODE_HEAT)
{
auto target_temp_in_f = id(${node_id}_climate).target_temperature_low * (9.0/5.0) + 32.0;
return ((target_temp_in_f + 1) - 32) * 5/9;
}
auto lowest_temp = 50;
return ((lowest_temp) - 32) * 5/9; // Convert back to celsius
target_temperature_high: !lambda
auto current_mode = id(${node_id}_climate).mode;
if (current_mode == CLIMATE_MODE_COOL)
{
auto target_temp_in_f = id(${node_id}_climate).target_temperature_high * (9.0/5.0) + 32.0;
return ((target_temp_in_f + 1) - 32) * 5/9;
}
auto highest_temp = 86;
return ((highest_temp) - 32) * 5/9; // Convert back to celsius
- component.update: tft_display
- platform: touchscreen
id: mode_select
x_min: 0
x_max: 55
y_min: 205
y_max: 240
page_id: home_page
on_press:
then:
- display.page.show: mode_page
- component.update: tft_display
- platform: touchscreen
id: open_weather_button
x_min: 270
x_max: 320
y_min: 0
y_max: 50
page_id: home_page
on_release:
then:
- display.page.show: weather_station_page
- component.update: tft_display
### >>>>>>>>>>>>> Mode Page Touch Areas <<<<<<<<<<<<<<< ###
- platform: touchscreen
id: set_cool_mode
x_min: 50
x_max: 115
y_min: 90
y_max: 150
page_id: mode_page
on_press:
then:
- climate.control:
id: ${node_id}_climate
mode: COOL
- display.page.show: home_page
- component.update: tft_display
- platform: touchscreen
id: set_off_mode
x_min: 135
x_max: 200
y_min: 90
y_max: 150
page_id: mode_page
on_press:
then:
- climate.control:
id: ${node_id}_climate
mode: "OFF"
- display.page.show: home_page
- component.update: tft_display
- platform: touchscreen
id: set_heat_mode
x_min: 220
x_max: 285
y_min: 90
y_max: 150
page_id: mode_page
on_press:
then:
- climate.control:
id: ${node_id}_climate
mode: "HEAT"
- display.page.show: home_page
- component.update: tft_display
### >>>>>>>>>>>>> Weather Page Touch Areas <<<<<<<<<<<<<<< ###
- platform: touchscreen
id: close_button
x_min: 270
x_max: 320
y_min: 0
y_max: 50
page_id: weather_station_page
on_release:
then:
- display.page.show: home_page
- component.update: tft_display
### >>>>>>>>>>>>> Backlight Binary Sensor <<<<<<<<<<<<<<< ###
- platform: template
id: touching
filters:
delayed_off: 20s
on_press:
- light.control:
id: back_light
brightness: 100%
on_release:
- light.control:
id: back_light
brightness: 35%
### >>>>>>>>>>>>> Backlight <<<<<<<<<<<<<<< ###
# Define a PWM output on the ESP32
output:
- platform: ledc
pin: 25
id: backlight_output
# Define a monochromatic, dimmable light for the backlight
light:
- platform: monochromatic
output: backlight_output
name: "Display Backlight"
id: back_light
restore_mode: RESTORE_DEFAULT_ON