Skip to content

Instantly share code, notes, and snippets.

@InToSSH
Last active March 29, 2024 12:22
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save InToSSH/6f7eb0bd448d2060ca8f410d7a599b33 to your computer and use it in GitHub Desktop.
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 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