Hi, all. Here is a another project for esphome. This is a freezer monitor (Outdoor, garage, etc) that monitors the ambient temparture and turns on a heater (light bulb, etc) if the temperature hits the setpoint. The devices used includes dallas temperature sensors, a 5v 2-relay and a SSD1306 oled display.
substitutions:
name: "freezer-monitor"
type: ESP
esphome:
name: freezer-monitor
friendly_name: "freezer-monitor"
comment: Freezer temperature monitor. Freezer always on, heaters on below setpoint temperature.
esp32:
board: esp32dev
framework:
type: arduino
# === Global Variables ===
# Define global variables to store and manage device states.
globals:
- id: freezer_state # Tracks whether the freezer is active.
type: int
initial_value: '1'
- id: heater_state # Tracks whether the heater is active.
type: int
initial_value: '0'
- id: upper_threshold_value # Temperature hysteresis range to avoid frequent toggling.
type: float
initial_value: '45.0'
- id: lower_threshold_value # Temperature hysteresis range to avoid frequent toggling.
type: float
initial_value: '35.0'
# === Logging Configuration ===
# Enable logging to monitor the device's behavior.
logger:
# level: WARN
# === Remote Control and Updates ===
api:
encryption:
key: "xxxx"
# === Wi-Fi Configuration ===
# Setting up Wi-Fi connection details and a fallback hotspot.
ota:
platform: esphome
wifi:
ssid: !secret wifi_ssid2
password: !secret wifi_password2
ap:
ssid: "${name} Fallback Hotspot"
password: "password"
# === Captive Portal ===
# For fallback access when not connected to Wi-Fi.
captive_portal:
# === Web Server ===
# Local web interface for monitoring and control.
web_server:
version: 3
sorting_groups:
- id: relay_settings
name: "Relays"
sorting_weight: -30
- id: temperature_settings
name: "Temperature"
sorting_weight: -25
- id: set_point_settings
name: "Temperature SetPoints"
sorting_weight: -20
- id: humidity_settings
name: "Humidity"
sorting_weight: -15
- id: state_settings
name: "State"
sorting_weight: -10
# === Time Configuration ===
# Synchronize time using SNTP.
time:
- platform: sntp
id: sntp_time
timezone: America/New_York
servers:
- 0.pool.ntp.org
- 1.pool.ntp.org
- 2.pool.ntp.org
# === Number Component ===
# Adjustable temperature setpoint for controlling heaters.
number:
- platform: template
name: "SetPoint Temp"
id: setpoint_temp
unit_of_measurement: "°F"
icon: "mdi:temperature-fahrenheit"
optimistic: true
min_value: 35
max_value: 45
step: 1
initial_value: 45
restore_value: true
web_server:
sorting_group_id: set_point_settings
# === GPIO Outputs ===
# Configuring an LED output.
output:
- platform: gpio
pin:
number: 25
mode: output
id: LED
# === Text Sensors ===
# Providing network-related information.
text_sensor:
- platform: wifi_info
ip_address:
name: "IP Address"
icon: "mdi:ip"
ssid:
name: "Connected SSID"
icon: "mdi:wifi"
bssid:
name: "Connected BSSID"
icon: "mdi:wifi"
mac_address:
name: "Mac Wifi Address"
icon: "mdi:lan-connect"
dns_address:
name: "DNS Address"
icon: "mdi:ip"
# === Binary Sensors ===
# Status monitoring and heater state.
binary_sensor:
- platform: status
name: "${type} Status"
icon: "mdi:state-machine"
- platform: template
name: "Heater Status"
icon: "mdi:earth"
id: heater_state_value
lambda: |-
if (id(heater).state) {
return true;
} else {
return false;
}
web_server:
sorting_group_id: state_settings
- platform: template
name: "Freezer Power Status"
icon: "mdi:earth"
id: freezer_state_value
lambda: |-
if (id(freezer).state) {
return true;
} else {
return false;
}
web_server:
sorting_group_id: state_settings
# === Switches ===
# Configuring GPIO relays and a restart switch.
switch:
- platform: restart
icon: mdi:reload-alert
name: "${type} Restart"
- platform: gpio
name: "Freezer Power"
id: freezer
icon: "mdi:electric-switch"
restore_mode: ALWAYS_ON
pin:
number: 21
inverted: false
on_turn_on:
- logger.log: "Freezer Power Turned On!"
on_turn_off:
- logger.log: "Freezer Power Turned Off!"
web_server:
sorting_group_id: relay_settings
- platform: gpio
name: "Heater"
id: heater
icon: "mdi:electric-switch"
restore_mode: ALWAYS_OFF
pin:
number: 19
inverted: true
on_turn_on:
- logger.log: "Heater Turned On!"
on_turn_off:
- logger.log: "Heater Turned Off!"
web_server:
sorting_group_id: relay_settings
- platform: gpio
name: "Relay 3"
id: relay3
icon: "mdi:electric-switch"
pin:
number: 18
inverted: false
on_turn_on:
- logger.log: "Relay 3 Turned On!"
on_turn_off:
- logger.log: "Relay 3 Turned Off!"
internal: true
web_server:
sorting_group_id: relay_settings
- platform: gpio
name: "Relay 4"
id: relay4
icon: "mdi:electric-switch"
pin:
number: 5
inverted: false
on_turn_on:
- logger.log: "Relay 4 Turned On!"
on_turn_off:
- logger.log: "Relay 4 Turned Off!"
internal: true
web_server:
sorting_group_id: relay_settings
# === One-Wire Bus ===
# Setting up one-wire protocol for Dallas sensors.
one_wire:
- platform: gpio
pin: 02
id: dallas_1
# === Sensors ===
# Monitoring uptime, temperatures, and pressure.
sensor:
- platform: uptime
name: "Uptime" # Device uptime in seconds
- platform: internal_temperature
name: "Internal Temperature" # ESP32 internal temperature in °F
id: "internal_temperature_f"
unit_of_measurement: "°F"
icon: "mdi:temperature-fahrenheit"
accuracy_decimals: 0
device_class: "temperature"
state_class: "measurement"
filters:
- lambda: return x * (9.0/5.0) + 32.0; # Convert Celsius to Fahrenheit
- filter_out: nan
- platform: template
name: "Lower Threshold"
id: lower_threshold
unit_of_measurement: "°F"
icon: "mdi:temperature-fahrenheit"
accuracy_decimals: 0
lambda: "return id(setpoint_temp).state;"
update_interval: 5s
web_server:
sorting_group_id: state_settings
- platform: template
name: "Upper Threshold"
id: upper_threshold
unit_of_measurement: "°F"
icon: "mdi:temperature-fahrenheit"
accuracy_decimals: 0
lambda: "return id(setpoint_temp).state + 5;"
update_interval: 5s
web_server:
sorting_group_id: state_settings
- platform: dallas_temp
address: 0xd70313949761c028
one_wire_id: dallas_1
name: "Ambient Temperature"
id: ambient_temp
icon: "mdi:thermometer"
device_class: "temperature"
state_class: "measurement"
accuracy_decimals: 0
update_interval: 15s
resolution: 9
filters:
- throttle: 1s
- heartbeat: 5s
- debounce: 0.1s
- lambda: return x * (9.0/5.0) + 32.0;
- filter_out: nan
unit_of_measurement: "°F"
web_server:
sorting_group_id: temperature_settings
- platform: dallas_temp
address: 0x940309949743e728
one_wire_id: dallas_1
name: "Freezer Temperature"
id: freezer_temp
icon: "mdi:thermometer"
device_class: "temperature"
state_class: "measurement"
accuracy_decimals: 0
update_interval: 15s
resolution: 9
filters:
- throttle: 1s
- heartbeat: 5s
- debounce: 0.1s
- lambda: return x * (9.0/5.0) + 32.0;
- filter_out: nan
unit_of_measurement: "°F"
web_server:
sorting_group_id: temperature_settings
- platform: dallas_temp
address: 0xed031294973fff28
one_wire_id: dallas_1
name: "Compressor Temperature"
id: compressor_temp
icon: "mdi:thermometer"
device_class: "temperature"
state_class: "measurement"
accuracy_decimals: 0
update_interval: 15s
resolution: 9
filters:
- throttle: 1s
- heartbeat: 5s
- debounce: 0.1s
- lambda: return x * (9.0/5.0) + 32.0;
- filter_out: nan
unit_of_measurement: "°F"
web_server:
sorting_group_id: temperature_settings
# === i2c Sensors ===
# Configure temperature sensors for monitoring room, fins, and exterior temperatures.
i2c:
sda: 15
scl: 14
scan: true
id: bus_a
frequency: 400kHz
font:
- file: 'fonts/arial.ttf'
id: arial_medium
size: 14
- file: "fonts/OpenSans-Regular.ttf"
id: opensans_medium
size: 12
- file: "fonts/OpenSans-Regular.ttf"
id: opensans_small
size: 10
- file: "gfonts://Roboto" # gfonts://family[@weight]
id: roboto
size: 20
- file: "gfonts://Roboto"
id: roboto_medium
size: 15
- file: "gfonts://Roboto"
id: roboto_small
size: 12
- file: "gfonts://Roboto"
id: roboto_smallest
size: 10
- file: 'fonts/BebasNeue-Regular.ttf'
id: bebasneue_large
size: 48
- file: 'fonts/BebasNeue-Regular.ttf'
id: bebasneue_medium
size: 32
- file: 'fonts/Silkscreen-Regular.ttf'
id: silkscreen_medium
size: 10
- file: 'fonts/Silkscreen-Regular.ttf'
id: silkscreen_small
size: 8
- file: 'fonts/arial.ttf'
id: arial_large
size: 16
display:
- platform: ssd1306_i2c
model: "SSD1306 128x64"
address: 0x3C
i2c_id: bus_a
id: oled_display
auto_clear_enabled: True
show_test_card: true
update_interval: 5s
pages:
- id: page1
lambda: |-
// it.printf(X, Y,.. (X (Row) and Y (Column))
// Print "Freezer" in top center.
it.printf(it.get_width() / 2, 8, id(roboto_medium), TextAlign::TOP_CENTER, "Freezer");
// Print time in HH:MM format
it.strftime(0, 60, id(bebasneue_large), TextAlign::BASELINE_LEFT, "%H:%M", id(sntp_time).now());
// Print ROOM temperature
if (id(ambient_temp).has_state()) {
it.printf(127, 23, id(arial_medium), TextAlign::TOP_RIGHT, "%.1f°", id(ambient_temp).state);
}
// Print Freezer temperature
if (id(setpoint_temp).has_state()) {
it.printf(127, 60, id(arial_medium), TextAlign::BASELINE_RIGHT, "%.1f°", id(setpoint_temp).state);
}
- id: page2
lambda: |-
// Print "Currently Running" in the top center
it.printf(it.get_width() / 2, 8, id(roboto_medium), TextAlign::TOP_CENTER, "Currently Running");
// Determine the text to display
std::string status_text;
if (id(heater_state) == 1 && id(heater_state) == 1) {
status_text = "HEAT";
} else {
status_text = "NONE";
}
// Print the status text centered at the bottom
it.printf(it.get_width() / 2, it.get_height() - 4, id(bebasneue_large), TextAlign::BASELINE_CENTER, "%s", status_text.c_str());
- id: page3
lambda: |-
// Print "Target Temp" in top center.
it.printf(it.get_width() / 2, 8, id(roboto_medium), TextAlign::TOP_CENTER, "Target Temp");
// Print Target temperature
if (id(setpoint_temp).has_state()) {
it.printf(it.get_width() / 2, it.get_height() - 4, id(bebasneue_large), TextAlign::BASELINE_CENTER, "%.1f°", id(setpoint_temp).state);
}
- id: page4
lambda: |-
// Print "Ambient Temp" in top center.
it.printf(it.get_width() / 2, 8, id(roboto_medium), TextAlign::TOP_CENTER, "Ambient Temp");
// Print Ambient1 temperature
if (id(ambient_temp).has_state()) {
it.printf(it.get_width() / 2, it.get_height() - 4, id(bebasneue_large), TextAlign::BASELINE_CENTER, "%.1f°", id(ambient_temp).state);
}
- id: page5
lambda: |-
// Print "Freezer Temp" in top center.
it.printf(it.get_width() / 2, 8, id(roboto_medium), TextAlign::TOP_CENTER, "Freezer Temp");
// Print Freezer temperature
if (id(freezer_temp).has_state()) {
it.printf(it.get_width() / 2, it.get_height() - 4, id(bebasneue_large), TextAlign::BASELINE_CENTER, "%.1f°", id(freezer_temp).state);
}
- id: page6
lambda: |-
// Print "Compressor Temp" in top center.
it.printf(it.get_width() / 2, 8, id(roboto_medium), TextAlign::TOP_CENTER, "Compressor Temp");
// Print Compressor temperature
if (id(compressor_temp).has_state()) {
it.printf(it.get_width() / 2, it.get_height() - 4, id(bebasneue_large), TextAlign::BASELINE_CENTER, "%.1f°", id(compressor_temp).state);
}
- id: name
lambda: |-
it.print(64, 0, id(roboto), TextAlign::TOP_CENTER, "Pumphouse");
- id: startup
lambda: |-
// Draw a circle in the middle of the display
it.filled_circle(it.get_width() / 2, it.get_height() / 2, 20);
interval:
- interval: 20s
then:
- display.page.show: page1
- component.update: oled_display
- delay: 4s
- display.page.show: page2
- component.update: oled_display
- delay: 4s
- display.page.show: page3
- component.update: oled_display
- delay: 2s
- display.page.show: page4
- component.update: oled_display
- delay: 2s
- display.page.show: page5
- component.update: oled_display
- delay: 2s
- display.page.show: page6
- component.update: oled_display
- delay: 2s
- interval: 15s
then:
- lambda: |-
float upper_threshold = id(upper_threshold);
float lower_threshold = id(lower_threshold);
bool is_heating_active = id(heater_state);
bool is_freezer_active = id(freezer_state);
float is_ambient = id(ambient_temp).state;
float is_ambient_above_upper = id(ambient_temp).state > upper_threshold;
float is_ambient_below_lower = id(ambient_temp).state <= lower_threshold;
// Heater Control Logic
if (id(ambient_temp).state <= id(setpoint_temp).state) {
ESP_LOGW("logic", "Temperature above upper threshold; turning on heater.");
id(heater).turn_on();
id(heater_state) = 1;
} else if (id(ambient_temp).state > id(setpoint_temp).state + 5) {
ESP_LOGW("logic", "Temperature above target; ; turning off heater.");
id(heater).turn_off();
id(heater_state) = 0;
}