Last active
October 26, 2024 11:09
-
-
Save InToSSH/6f7eb0bd448d2060ca8f410d7a599b33 to your computer and use it in GitHub Desktop.
ESPHome - Venetian Blind example with time-based cover control and tilt with Shelly2.5
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
# This is an example yaml config file for ESPHome to control Venetian blinds with one motor, where turning on the motor in 'up' direction first fully tilts open the blind then starts moving up, and vice versa, in 'down' direction first tilts blind closed, then starts moving down. | |
# AUTHOR: InToSSH - github.com/InToSSH | |
substitutions: | |
device_name: Living Room Cover | |
esphome: | |
name: living_room_blind | |
platform: ESP8266 | |
board: esp01_1m | |
wifi: | |
ssid: !secret wifi_ssid | |
password: !secret wifi_pass | |
fast_connect: true | |
power_save_mode: none | |
manual_ip: | |
static_ip: 10.10.3.25 | |
gateway: 10.10.3.1 | |
subnet: 255.255.255.0 | |
# Enable fallback hotspot (captive portal) in case wifi connection fails | |
ap: | |
ssid: ${device_name} | |
password: !secret ap_pass | |
# Enable logging | |
logger: | |
level: WARN | |
esp8266_store_log_strings_in_flash: False | |
# Enable Home Assistant API | |
api: | |
password: !secret api_pass | |
ota: | |
password: !secret api_pass | |
i2c: | |
sda: GPIO12 | |
scl: GPIO14 | |
globals: | |
- id: cover_moving #This is for the HW buttons to determine if a press should stop the blind or start moving it (this could probably be done without this var by reading id(time_cover).current_operation) | |
type: bool | |
initial_value: "0" | |
cover: | |
- platform: time_based # Time based cover to track the position of the blind based on the time (unfortunatelly this doesn't support tilt) | |
name: ${device_name} - Time Cover | |
internal: True | |
id: time_cover | |
has_built_in_endstop: True # The controller in my blind automatically stops the motor in it's endpoints, this is set to True to be able to synchronize the zero position based on time with the actual position when the blind is either fully closed or open | |
# The power meter in the Shelly2.5 is then used to determine when the blind has stopped, sending a "cover.stop" action to this cover. | |
open_action: | |
- globals.set: | |
id: cover_moving | |
value: "true" | |
- script.execute: detect_endpoint | |
- switch.turn_off: motor_down | |
- switch.turn_on: motor_up | |
open_duration: 54sec # Set the correct time for your specific blind | |
close_action: | |
- globals.set: | |
id: cover_moving | |
value: "true" | |
- script.execute: detect_endpoint | |
- switch.turn_off: motor_up | |
- switch.turn_on: motor_down | |
close_duration: 53sec # Set the correct time for your specific blind | |
stop_action: | |
- globals.set: | |
id: cover_moving | |
value: "false" | |
- script.stop: detect_endpoint | |
- switch.turn_off: motor_up | |
- switch.turn_off: motor_down | |
- platform: template # Template cover which synchronizes position with the time_cover, but also supports tilt. | |
name: ${device_name} | |
id: template_cover | |
lambda: |- | |
if (id(template_cover).current_operation != id(time_cover).current_operation) | |
{ | |
id(template_cover).current_operation = id(time_cover).current_operation; | |
} | |
return id(time_cover).position; | |
has_position: true | |
assumed_state: True | |
open_action: | |
- cover.open: time_cover | |
close_action: | |
- cover.close: time_cover | |
stop_action: | |
- cover.stop: time_cover | |
position_action: | |
- cover.control: | |
id: time_cover | |
position: !lambda |- | |
return pos; | |
tilt_action: # This controls the tilt, since there is no feedback on the real position of the tilt we just sync it by either fully opening or closing and then moving to specified position | |
- lambda: |- | |
if (tilt == 1) { | |
auto call1 = id(time_cover).make_call(); | |
call1.set_command_open(); | |
call1.perform(); | |
delay(1000); // This is how much time it takes for my blind to tilt fully open/closed | |
auto call2 = id(time_cover).make_call(); | |
call2.set_command_stop(); | |
call2.perform(); | |
} else if (tilt == 0) { | |
auto call1 = id(time_cover).make_call(); | |
call1.set_command_close(); | |
call1.perform(); | |
delay(1000); // This is how much time it takes for my blind to tilt fully open/closed | |
auto call2 = id(time_cover).make_call(); | |
call2.set_command_stop(); | |
call2.perform(); | |
} else { | |
if (tilt > 0.5) { | |
auto call1 = id(time_cover).make_call(); | |
call1.set_command_open(); | |
call1.perform(); | |
delay(1000); // This is how much time it takes for my blind to tilt fully open/closed | |
auto call2 = id(time_cover).make_call(); | |
call2.set_command_stop(); | |
call2.perform(); | |
delay(500); | |
auto call3 = id(time_cover).make_call(); | |
call3.set_command_close(); | |
call3.perform(); | |
delay(1000 - (tilt*1000) + 50); | |
auto call4 = id(time_cover).make_call(); | |
call4.set_command_stop(); | |
call4.perform(); | |
} | |
if (tilt <= 0.5) { | |
auto call1 = id(time_cover).make_call(); | |
call1.set_command_close(); | |
call1.perform(); | |
delay(1000); // This is how much time it takes for my blind to tilt fully open/closed | |
auto call2 = id(time_cover).make_call(); | |
call2.set_command_stop(); | |
call2.perform(); | |
delay(500); | |
auto call3 = id(time_cover).make_call(); | |
call3.set_command_open(); | |
call3.perform(); | |
delay(tilt*1000 + 200); | |
auto call4 = id(time_cover).make_call(); | |
call4.set_command_stop(); | |
call4.perform(); | |
} | |
} | |
id(template_cover).tilt = tilt; | |
id(template_cover).publish_state(); | |
script: | |
- id: detect_endpoint # Used to detect the endpoint of the blind based on the power draw, the blind automatically stops in it's endpoints, this might not be needed, but I don't like the idea of leaving the relay on when "has_built_in_endstop" is used on the cover. | |
then: | |
- delay: 5sec | |
- wait_until: | |
sensor.in_range: | |
id: power_down | |
below: 20 | |
- wait_until: | |
sensor.in_range: | |
id: power_up | |
below: 20 | |
- cover.stop: template_cover | |
switch: | |
- platform: gpio | |
pin: 4 | |
name: ${device_name} - Motor UP | |
id: motor_up | |
interlock: [motor_down] | |
interlock_wait_time: 100ms | |
restore_mode: always off | |
- platform: gpio | |
pin: 15 | |
name: ${device_name} - Motor DOWN | |
id: motor_down | |
interlock: [motor_up] | |
interlock_wait_time: 100ms | |
restore_mode: always off | |
binary_sensor: | |
- platform: gpio # Physical button on the wall to move the blind UP | |
pin: 5 | |
name: ${device_name} - Button UP | |
on_press: | |
then: | |
- if: | |
condition: | |
lambda: 'return !id(cover_moving);' | |
then: | |
- cover.open: template_cover | |
on_click: | |
- min_length: 1ms | |
max_length: 999ms | |
then: | |
- cover.stop: template_cover | |
- platform: gpio # Physical button on the wall to move the blind DOWN | |
pin: 13 | |
name: ${device_name} - Button DOWN | |
on_press: | |
then: | |
- if: | |
condition: | |
lambda: 'return !id(cover_moving);' | |
then: | |
- cover.close: template_cover | |
on_click: | |
- min_length: 1ms | |
max_length: 999ms | |
then: | |
- cover.stop: template_cover | |
- platform: homeassistant | |
name: ${device_name} - HA UP | |
entity_id: input_boolean.momentary_up | |
on_press: | |
then: | |
- if: | |
condition: | |
lambda: 'return !id(cover_moving);' | |
then: | |
- cover.open: template_cover | |
on_click: | |
- min_length: 1ms | |
max_length: 999ms | |
then: | |
- cover.stop: template_cover | |
- platform: homeassistant | |
name: ${device_name} - HA DOWN | |
entity_id: input_boolean.momentary_down | |
on_press: | |
then: | |
- if: | |
condition: | |
lambda: 'return !id(cover_moving);' | |
then: | |
- cover.close: template_cover | |
on_click: | |
- min_length: 1ms | |
max_length: 999ms | |
then: | |
- cover.stop: template_cover | |
sensor: | |
- platform: ade7953 | |
voltage: | |
name: ${device_name} - Voltage | |
current_a: | |
name: ${device_name} - Current Down | |
internal: True | |
current_b: | |
name: ${device_name} - Current Up | |
internal: True | |
active_power_a: | |
name: ${device_name} - Power Down | |
id: power_down | |
active_power_b: | |
name: ${device_name} - Power Up | |
id: power_up | |
filters: | |
- multiply: -1 | |
update_interval: 5s |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment