Sure thing! Although, about half of the entities from my screenshot above come from “boilerplate yaml” that is included with every ESPHome device (highly recommended). You’ll see the line device_base: !include common/device_base_esp8266.yaml
which points at more files to build up the boilerplate. I’ve included all the important files at the bottom. I’m not including my wifi.yaml
because it has some customizations in it but it’s only the wifi:
block.
This build is using:
- HC-SR04 ultrasonic distance sensor
- AM2302 temperature and humidity sensor
- ADS1115 analog-to-digital sensor for analog illuminance/co2
- TEMT6000 light sensor
- MQ-7 carbon monoxide sensor (if I remember correctly)
- Reed switches (I didn’t buy from this vendor but these are the style)
- Wemos D1 Mini
Here’s the big one: raygarage.yaml
substitutions:
node_name: raygarage
friendly_name: Ray's Garage
board: d1_mini
restore_from_flash: 'False'
log_level: NONE
library_priority: '0'
garage_priority: '1'
packages:
wifi: !include common/wifi.yaml
device_base: !include common/device_base_esp8266.yaml
i2c:
scl: D2
sda: D4
scan: True
ads1115:
- address: 0x48
globals:
- id: performing_last_movement
type: boolean
restore_value: no
initial_value: 'false'
sensor:
- platform: ultrasonic
update_interval: 5s
timeout: 4.0m
trigger_pin: D0
echo_pin: D7
name: Ray's Bay Distance
id: ray_s_bay_distance
filters:
- median:
window_size: 5
send_every: 5
send_first_at: 3
# Use D3 for DHT22 and I don't need an external pull-up
- platform: dht
update_interval: 5s
pin: D3
model: AM2302
temperature:
name: "Garage Temperature"
filters:
- lambda: return x * (9.0/5.0) + 32.0;
- median:
window_size: 31
send_every: 6
send_first_at: 2
unit_of_measurement: "°F"
humidity:
name: "Garage Humidity"
filters:
- median:
window_size: 31
send_every: 6
send_first_at: 2
- platform: ads1115
update_interval: 6s
multiplexer: 'A0_GND'
gain: 6.144
name: "Garage Illuminance"
icon: mdi:candle
# Added device_class to customize icon.
device_class: ""
accuracy_decimals: 0
filters:
- lambda: return (x / 10000.0) * 2000000.0;
- median:
window_size: 15
send_every: 10
send_first_at: 3
unit_of_measurement: 'lx'
- platform: ads1115
update_interval: 6s
multiplexer: 'A1_GND'
gain: 6.144
name: "Garage CO Content"
icon: mdi:molecule-co
# Added device_class to customize icon.
device_class: ""
accuracy_decimals: 2
unit_of_measurement: 'V'
filters:
- median:
window_size: 15
send_every: 10
send_first_at: 9
switch:
- platform: gpio
id: ray_button
internal: true
pin:
number: D1
mode: OUTPUT
restore_mode: ALWAYS_OFF
on_turn_on:
- delay: 1500ms
- switch.turn_off: ray_button
cover:
- platform: template
name: Ray's Garage Door
id: ray_s_garage_door
device_class: garage
lambda: |-
if (id(closed_endstop).state) //Door at closed endstop
{
if (id(ray_s_garage_door).current_operation == esphome::cover::COVER_OPERATION_OPENING) //We should be opening
{
if (!id(performing_last_movement)) //Make sure we don't trigger this logic twice otherwise it will do unwanted things
{
delay(1000); //Wait for door to stop in case reed is triggered too early
id(ray_button).turn_on(); //Press button again
id(performing_last_movement) = true; //Set flag to indicate we madeknow where the door is
}
}
else if (id(ray_s_garage_door).current_operation == esphome::cover::COVER_OPERATION_CLOSING)
{
//We should be closing, so all is good
id(performing_last_movement) = false;
id(ray_s_garage_door).current_operation = esphome::cover::COVER_OPERATION_IDLE;
id(ray_s_garage_door).position = COVER_CLOSED;
id(ray_s_garage_door).publish_state();
return COVER_CLOSED;
}
else
{
//No operation in progress, just send state
id(performing_last_movement) = false;
if (!id(ray_s_garage_door).position == esphome::cover::COVER_CLOSED)
{
id(ray_s_garage_door).position = COVER_CLOSED;
id(ray_s_garage_door).publish_state();
return COVER_CLOSED;
}
}
}
else if (id(open_endstop).state) //Door at open endstop
{
if (id(ray_s_garage_door).current_operation == esphome::cover::COVER_OPERATION_CLOSING) //We should be closing
{
if (!id(performing_last_movement)) //Make sure we don't trigger this logic twice otherwise it will do unwanted things
{
delay(1000); //Wait for door to stop in case reed is triggered too early
id(ray_button).turn_on(); //Press button again
id(performing_last_movement) = true; //Set flag to indicate we madeknow where the door is
}
}
else if (id(ray_s_garage_door).current_operation == esphome::cover::COVER_OPERATION_OPENING)
{
//We should be opening, so all is good
id(performing_last_movement) = false;
id(ray_s_garage_door).current_operation = esphome::cover::COVER_OPERATION_IDLE;
id(ray_s_garage_door).position = COVER_OPEN;
id(ray_s_garage_door).publish_state();
return COVER_OPEN;
}
else //Door not at any endstop
{
//No operation in progress, just send state
id(performing_last_movement) = false;
if (id(ray_s_garage_door).position != esphome::cover::COVER_OPEN)
{
id(ray_s_garage_door).position = COVER_OPEN;
id(ray_s_garage_door).publish_state();
return COVER_OPEN;
}
}
}
else
{
//The door is halfway open, so set it to OPEN
if (id(ray_s_garage_door).position != esphome::cover::COVER_OPEN)
{
id(ray_s_garage_door).position = COVER_OPEN;
id(ray_s_garage_door).publish_state();
return COVER_OPEN;
}
}
return {};
open_action:
- lambda: |-
id(ray_s_garage_door).current_operation = esphome::cover::COVER_OPERATION_OPENING;
if (!id(open_endstop).state) {
id(ray_button).turn_on();
if (id(closed_endstop).state) {
id(performing_last_movement) = true; //Set flag to indicate we know where the door is
}
}
close_action:
- lambda: |-
id(ray_s_garage_door).current_operation = esphome::cover::COVER_OPERATION_CLOSING;
if (!id(closed_endstop).state) {
id(ray_button).turn_on();
if (id(open_endstop).state) {
id(performing_last_movement) = true; //Set flag to indicate we know where the door is
}
}
stop_action:
- lambda: |-
if (id(ray_s_garage_door).current_operation == esphome::cover::COVER_OPERATION_CLOSING || id(ray_s_garage_door).current_operation == esphome::cover::COVER_OPERATION_OPENING )
{
id(ray_s_garage_door).current_operation = esphome::cover::COVER_OPERATION_IDLE;
//Stop the door if it is moving
id(performing_last_movement) = false;
id(ray_button).turn_on();
}
binary_sensor:
- platform: template
name: Ray's Car Presence
lambda: |-
if (id(ray_s_bay_distance).state < 1.3) {
return true;
} else {
return false;
}
# D5 will need an external pull down, and reed switch goes to 3.3V
- platform: gpio
pin: D5
device_class: opening
id: open_endstop
internal: True
filters:
- delayed_on_off: 500ms
# D6 will need an external pull down, and reed switch goes to 3.3V
- platform: gpio
pin: D6
device_class: opening
id: closed_endstop
internal: True
filters:
- delayed_on_off: 500ms
Here are the boilerplate files.
common/device_base_esp8266.yaml
:
esphome:
name: ${node_name}
platform: ESP8266
board: ${board}
esp8266_restore_from_flash: ${restore_from_flash}
build_path: ./build/${node_name}
captive_portal:
logger:
level: ${log_level}
api:
password: ${api_password}
ota:
password: ${ota_password}
id: ${node_name}_ota
<<: !include common.button.yaml
<<: !include common.binary_sensor.yaml
<<: !include common.sensor.yaml
<<: !include common.text_sensor.yaml
common/common.button.yaml
:
button:
- platform: restart
name: ${friendly_name} Restart
- platform: template
name: ${friendly_name} Reset WiFi
on_press:
then:
- lambda: |-
WiFi.disconnect();
WiFi.begin();
common/common.binary_sensor.yaml
:
binary_sensor:
- platform: status
name: ${friendly_name} Status
common/common.sensor.yaml
:
sensor:
- platform: uptime
name: ${friendly_name} Uptime Raw
id: ${node_name}_uptime_raw
internal: true
update_interval: 30s
- platform: wifi_signal
name: ${friendly_name} WiFi Signal Strength
update_interval: 600s
common/common.text_sensor.yaml
:
text_sensor:
- platform: version
name: ${friendly_name} ESPHome Version
hide_timestamp: True
- platform: wifi_info
ip_address:
name: ${friendly_name} IP Address
icon: mdi:ip
ssid:
name: ${friendly_name} SSID
icon: mdi:access-point-network
mac_address:
name: ${friendly_name} MAC
icon: mdi:folder-key-network
- platform: template
name: ${friendly_name} Uptime
lambda: |-
int seconds = (id(${node_name}_uptime_raw).state);
int days = seconds / (24 * 3600);
seconds = seconds % (24 * 3600);
int hours = seconds / 3600;
seconds = seconds % 3600;
int minutes = seconds / 60;
seconds = seconds % 60;
if ( days > 3650 ) {
return { "Starting up" };
} else if ( days ) {
return { (String(days) +"d " + String(hours) +"h " + String(minutes) +"m "+ String(seconds) +"s").c_str() };
} else if ( hours ) {
return { (String(hours) +"h " + String(minutes) +"m "+ String(seconds) +"s").c_str() };
} else if ( minutes ) {
return { (String(minutes) +"m "+ String(seconds) +"s").c_str() };
} else {
return { (String(seconds) +"s").c_str() };
}
icon: mdi:clock-start
update_interval: 600s
BTW, my other garage door openers both include PIR motion sensors. That’s why this one doesn’t have them, it was intentionally designed this way because of my garage shape. If you only have one garage door opener DEFINITELY include a PIR sensor so you can see if something moves in the garage. Having that detection and reporting in HA is VERY nice.
Good luck!