Hello,
I worked on the Sonoff Dual that I installed the firmware Sonoff-Tasmota. I’ve integrated it with Home-Assistant using MQTT commands.
You can set a Window Cover position from the Window Set Position
which is converted from 0-100 to 0-16. I’ve set the timer 2 seconds more (18 sec) in order to go fully down or up.
The Window Position
is the current position of the Window Cover that is changed with the MQTT Commands (ON/OFF). If all automations are working correctly, you don’t have to change this bar.
This is the result:
To make it work I had to count the time it takes my window cover to go up/down. For me, it was 18 seconds, so this is the configuration on Home Assistant:
Basic Config
configuration.yaml
timer:
window_1_up:
duration: '00:00:18'
window_1_down:
duration: '00:00:18'
input_number:
window_1_position:
name: "Window Position"
min: 0
max: 100
window_1_set_position:
name: "Window Set Position"
min: 0
max: 100
cover:
- platform: template
covers:
window_1_cover:
friendly_name: "Window 1 Cover"
position_template: "{{ (states.input_number.window_1_position.state | int) }}"
open_cover:
- service: mqtt.publish
data:
topic: 'cmnd/window_1/power2'
payload: 'OFF'
- service: mqtt.publish
data:
topic: 'cmnd/window_1/power1'
payload: 'ON'
close_cover:
- service: mqtt.publish
data:
topic: 'cmnd/window_1/power1'
payload: 'OFF'
- service: mqtt.publish
data:
topic: 'cmnd/window_1/power2'
payload: 'ON'
stop_cover:
- service: mqtt.publish
data:
topic: 'cmnd/window_1/power1'
payload: 'OFF'
- service: mqtt.publish
data:
topic: 'cmnd/window_1/power2'
payload: 'OFF'
automations.yaml
- id: '301'
alias: window_1 - MQTT Button1 OFF (up)
trigger:
- payload: 'OFF'
platform: mqtt
topic: stat/window_1/POWER1
action:
- service: timer.cancel
entity_id: timer.window_1_up
- service: input_number.set_value
data_template:
entity_id: input_number.window_1_set_position
value: >-
{{ states.input_number.window_1_position.state }}
- id: '302'
alias: window_1 - MQTT Button2 OFF (down)
trigger:
- payload: 'OFF'
platform: mqtt
topic: stat/window_1/POWER2
action:
- service: timer.cancel
entity_id: timer.window_1_down
- service: input_number.set_value
data_template:
entity_id: input_number.window_1_set_position
value: >-
{{ states.input_number.window_1_position.state }}
- id: '303'
alias: window_1 - Timer stopped
trigger:
- platform: event
event_type: timer.finished
event_data:
entity_id: timer.window_1_up
- platform: event
event_type: timer.finished
event_data:
entity_id: timer.window_1_down
action:
- service: cover.stop_cover
data:
entity_id: cover.window_1_cover
- id: '311'
alias: window_1 - MQTT Button1 ON (up)
trigger:
- payload: 'ON'
platform: mqtt
topic: stat/window_1/POWER1
condition:
condition: template
value_template: '{{ as_timestamp(now()) - as_timestamp(states.input_number.window_1_set_position.last_updated) > 3 }}'
action:
- service: timer.start
data:
duration: 00:00:16
entity_id: timer.window_1_up
- id: '312'
alias: window_1 - MQTT Button2 ON (down)
trigger:
- payload: 'ON'
platform: mqtt
topic: stat/window_1/POWER2
condition:
condition: template
value_template: '{{ as_timestamp(now()) - as_timestamp(states.input_number.window_1_set_position.last_updated) > 3 }}'
action:
- service: timer.start
data:
duration: 00:00:16
entity_id: timer.window_1_down
- id: '411'
alias: window_1 - Position UP
trigger:
platform: time_pattern
seconds: '/1'
condition:
condition: state
entity_id: timer.window_1_up
state: active
action:
- service: input_number.set_value
data_template:
entity_id: input_number.window_1_position
value: >-
{% set step=100/16 %}
{% if (states.input_number.window_1_position.state | float + step) < 100 %}
{{ states.input_number.window_1_position.state | float + step | int }}
{% else %}
100
{% endif %}
- id: '412'
alias: window_1 - Position Down
trigger:
platform: time_pattern
seconds: '/1'
condition:
condition: state
entity_id: timer.window_1_down
state: active
action:
- service: input_number.set_value
data_template:
entity_id: input_number.window_1_position
value: >-
{% set step=100/16 %}
{% if (states.input_number.window_1_position.state | float - step) > 0 %}
{{ states.input_number.window_1_position.state | float - step | int}}
{% else %}
0
{% endif %}
- id: '511'
alias: window_1 - Set Position Down
trigger:
platform: state
entity_id: input_number.window_1_set_position
condition:
condition: template
value_template: >-
{{ (states.input_number.window_1_position.state | int) >
(states.input_number.window_1_set_position.state | int) }}
action:
- service: timer.start
data_template:
entity_id: timer.window_1_down
duration: >-
{{ '00:00:%02d' | format(((
(states.input_number.window_1_position.state | int) -
(states.input_number.window_1_set_position.state | int)
) * 16 /100) | int | abs )
}}
- service: cover.close_cover
data:
entity_id: cover.window_1_cover
- id: '512'
alias: Window_1 - Set Position UP
trigger:
platform: state
entity_id: input_number.window_1_set_position
condition:
condition: template
value_template: >-
{{ (states.input_number.window_1_position.state | int) <
(states.input_number.window_1_set_position.state | int) }}
action:
- service: timer.start
data_template:
entity_id: timer.window_1_up
duration: >-
{{ '00:00:%02d' | format(((
(states.input_number.window_1_position.state | int) -
(states.input_number.window_1_set_position.state | int)
) * 16 /100) | int | abs )
}}
- service: cover.open_cover
data:
entity_id: cover.window_1_cover
UI Config
lovlace.yaml
entities:
- entity: cover.window_cover
- entity: input_number.window_set_position
name: Set Position
- entity: input_number.window_position
name: Current Position
show_header_toggle: false
title: Window Cover
type: entities
groups.yaml
window_cover:
name: Window Cover
entities:
- cover.window_cover
- input_number.window_set_position
- input_number.window_position
- timer.window_up
- timer.window_down
API Call
Set position:
http://[home-assistant-url]:8123/api/services/input_number/set_value?api_password=password
{ "entity_id": "input_number.window_set_position", "value": 50 }
IFTTT
Home Asssistant Automations:
- id: ifttt_window_set
alias: IFTTT Window Set
trigger:
platform: event
event_type: ifttt_webhook_received
event_data:
action: window_set
action:
service_template: '{{ trigger.event.data.service }}'
data_template:
entity_id: '{{ trigger.event.data.entity_id }}'
- id: ifttt_window_position
alias: IFTTT Window Position
trigger:
platform: event
event_type: ifttt_webhook_received
event_data:
action: window_position
action:
service_template: '{{ trigger.event.data.service }}'
data_template:
entity_id: '{{ trigger.event.data.entity_id }}'
value: '{{ trigger.event.data.value }}'
IFTT WebHook POST Reqest for close:
{"action": "window_set", "service": "cover.close_cover", "entity_id": "cover.window_cover" }
IFTT WebHook POST Reqest for set position:
{"action": "window_position", "service": "input_number.set_value", "entity_id": "input_number.window_set_position", "value": "{{NumberField}}"}
Alternative option
If you are using ESPHome, then this can be used instead, which automatically integrates with home-assistant.
esphome:
name: myroom_window
platform: ESP8266
board: esp01_1m
wifi:
ssid: 'myssid'
password: 'mypass'
api:
logger:
ota:
binary_sensor:
- platform: gpio
pin:
number: GPIO09
mode: INPUT_PULLUP
inverted: True
id: ph_button3
on_press:
- cover.open: my_cover
on_release:
- cover.stop: my_cover
- platform: gpio
pin:
number: GPIO00
mode: INPUT_PULLUP
inverted: True
id: ph_button4
on_press:
- cover.close: my_cover
on_release:
- cover.stop: my_cover
switch:
- platform: gpio
pin: GPIO12
interlock: &interlock [open_cover, close_cover]
id: open_cover
- platform: gpio
pin: GPIO5
interlock: *interlock
id: close_cover
cover:
- platform: time_based
name: "myroom_window"
id: my_cover
open_action:
- switch.turn_on: open_cover
open_duration: 18s
close_action:
- switch.turn_on: close_cover
close_duration: 18s
stop_action:
- switch.turn_off: open_cover
- switch.turn_off: close_cover
FAQ
- Use record on configuration.conf to save the state of the cover and sliders after a restart.
- On Sonoff Tashoma Firmware there is the SetOption14 to interlock the 2 relays, though I haven’t tested it. It could help have fewer automations.
- Physical switch connection diagram: here
- Physical switch Sonoff configuration (GPIO0 - 09 switch 1, GPIO9 - 10 switch 2)
- Allow Cover arrows to be always enabled: On configuration.yaml on cover section set “optimistic: true”
- Save the automation on a separate file. Add this line on configuration.yaml: automation old: !include_dir_merge_list automation/
- Easily add another window sensor by changing all the window_1 to something else.
- Split configuration: Instead of writing the whole configuration on configuration.yaml, you could create a package.yaml file by following the official doc about packages here.
I hope it helps!