esphome / feature-requests

ESPHome Feature Request Tracker
https://esphome.io/
417 stars 26 forks source link

Time-Based Cover - calculate interlock_wait_time to open/close duration + add max_duration #778

Open autox86 opened 4 years ago

autox86 commented 4 years ago

Describe the problem you have/What new integration you would like

Usage-Info: Time-Based Cover for roller shutter (Rolladen) is used. To prevent my roller shutter motors against blowing up, I implemented interlock + interlock_wait_time. As far as I understood from ESPHome docu, this is more or less taking care that the motor will not be feeded in both directions similutaniously.. Relevant config:

output:
  - platform: gpio
    pin: ${open_relay}
    name: "Relay #1"
    internal: true
    id: relay1
    interlock_wait_time: 350ms
    interlock: &interlock_group [relay1, relay2]
    restore_mode: always off

  - platform: gpio
    pin: ${close_relay}
    name: "Relay #2"
    internal: true
    id: relay2
    interlock_wait_time: 350ms
    interlock: *interlock_group
    restore_mode: always off`

Issues / Challenges:

Ideas / Feature Requests In regards to reduce the delay issue and have the position be more preciesly:

In terms of making sure that the roller shutter is always fully opening / closing, even if the calculated position is already reached, the max_duration entry from Endstop Cover would be helpful: So instead of stopping at 0% / 100% it will run until the time of max_duration is reached. Of course, this will only work if Build-In Endstops are avaialble, which is the case for most produced roller motors.

Example: max_duration (Optional, Time): The maximum duration the cover will opening or closing even if the time-based end-position based on close_duration / open_duration (0% / 100%) has been reached. !!!ONLY activate if your motor has build-in endstops!!!

Please describe your use case for this integration and alternatives you've tried:

I am having a house with 18 Roller Shutter (german: Rolladen). Looks like: Roller Shutter

I use a ESPHome flashed Tuya Modul "loratap sc500w" which is nothing more than a dual relay capable of having the 230v (momentary) switches to connect to.

I have two kinds of motors running the roller shutters: Mechanical and electronical with limit stop. The only difference is the collision detection of the electronical ones. (e.g. Somfy LT50 Somfy LT50 Mechanical or Becker E03 Electronical Both types of motors do have a user-saved end position, so fully open and fully closed where the motor stops driving.

If the "interlock_wait_time" and "move_delay" and "max_duration" is not an option to be implemented in the time-based-cover, I have some options left:

Any help is highly appreciated. Tried to find the time calculation in the sources my self, but I am unable to identify it. So, no clou if my ideas are easy or difficult to be transfered into code. :(

Additional context

Not sure if needed, but here is my complete config:

substitutions:
  device_name: rollstudio
  friendly_name: Studio Ost Rollade
  open_duration: 16.65sec
  close_duration: 15.90sec
  ledlinki: GPIO03
  open_switch: GPIO04
  close_switch: GPIO05
  close_relay: GPIO12
  reset_button: GPIO13
  open_relay: GPIO14

esphome:
  name: ${device_name}
  platform: ESP8266
  board: esp8285

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_pass
  power_save_mode: none
#  fast_connect: true

# Enable logging
logger:

# Enable Web server
web_server:
  port: 80

# Enable Home Assistant API
api:
  password: !secret api_pass
  reboot_timeout: 0s
ota:
  password: !secret api_pass

# Sync time with Home Assistant
time:
  - platform: homeassistant
    id: homeassistant_time

text_sensor:
  - platform: version
    name: "${friendly_name} Version"
    icon: mdi:information-outline
  - platform: wifi_info
    ip_address:
      name: "${friendly_name} IP"
      icon: mdi:ip-network-outline
    ssid:
      name: "${friendly_name} SSID"
      icon: mdi:signal-distance-variant
    bssid:
      name: "${friendly_name} BSSID"
      icon: mdi:signal-distance-variant

sensor:
  # Uptime sensor
  - platform: uptime
    name: "${friendly_name} Uptime"
    unit_of_measurement: days
    update_interval: 4h
    filters:
      - multiply: 0.000011574
  # WiFi Signal sensor
  - platform: wifi_signal
    name: "${friendly_name} WiFi"
    update_interval: 300s
    icon: mdi:signal-variant

binary_sensor:
  - platform: gpio
    pin: ${open_switch}
    name: "Switch #1"
    id: switch1
    internal: true
    on_press:
      then:
        - lambda: |
            if (id(rolladen).current_operation == COVER_OPERATION_IDLE) {
              // Cover is idle, check current state and open cover.
              id(rolladen).open();
            } 
            else {
              // Cover is opening/closing. Stop it.
              id(rolladen).stop();
            }
  #Reset Device
    on_multi_click:
    - timing:
      #six times short
        - ON for at most 1s
        - OFF for at most 1s
        - ON for at most 1s
        - OFF for at most 1s
        - ON for at most 1s
        - OFF for at most 1s
        - ON for at most 1s
        - OFF for at most 1s
        - ON for at most 1s
        - OFF for at least 0s
      then:
        - switch.toggle: reset

  - platform: gpio
    pin: ${close_switch}
    name: "Switch #2"
    id: switch2
    internal: true
    on_press:
      then:
        - lambda: |
            if (id(rolladen).current_operation == COVER_OPERATION_IDLE) {
              // Cover is idle, check current state and close cover.
              id(rolladen).close();
            } 
            else {
              // Cover is opening/closing. Stop it.
              id(rolladen).stop();
            }

  - platform: gpio
    pin: ${reset_button}
    id: reset_switch
    internal: true
    on_press:
      then:
        - switch.toggle: reset

switch:
# Switch to restart the shutter
  - platform: restart
    id: reset
    name: "${friendly_name} Restart"

  - platform: gpio
    pin: ${open_relay}
    name: "Relay #1"
    internal: true
    id: relay1
    interlock_wait_time: 350ms
    interlock: &interlock_group [relay1, relay2]
    restore_mode: always off

  - platform: gpio
    pin: ${close_relay}
    name: "Relay #2"
    internal: true
    id: relay2
    interlock_wait_time: 350ms
    interlock: *interlock_group
    restore_mode: always off

cover:
  - platform: time_based
    name: "${friendly_name}"
    id: rolladen

    open_action:
      - switch.turn_on: relay2
    open_duration: ${open_duration}

    close_action:
      - switch.turn_on: relay1
    close_duration: ${close_duration}
    #max_duration: 25sec
    stop_action:
      - switch.turn_off: relay2
      - switch.turn_off: relay1
gio-dot commented 4 years ago

Hi, software interlock can't never be a safe and smart solution. Best way is to use an electrical interlock. Take a look here: https://github.com/Gio-dot/Six-shutters-ESP32-controller

autox86 commented 4 years ago

Hi Gio-dot,

First of all, many thanks for that drawing. GREAT!!! I am currently changing my livingroom, kitchen, dineroom to be one big room. Therfore I will take care that all cables will be put into a "Smart Cage" with sufficient room to put in my Quinled deca and 16 times relay board. There I will stick to you drawing to have an electrical interlock, which will work as I have enough room to place the hardware.

In regards to my other rooms, I am a bit limited. I only have a deep installation box where I can put the devices behind the momentary switch. (looks like this

Neither Shelly 2.5 or Loratap SC500w do have the pins available to for NC/NO. So, I decided to have a software interlock + interlock_wait_time for extra safety.

@OttoWinter: What are your thoughts about it?

glmnet commented 4 years ago

As I understand it, your motor will run while you keep your button pressed, and will stop when you release the button or when the cover reaches the limit.

try this

cover:
  - platform: time_based
    name: "${friendly_name}"
    id: rolladen
    has_built_in_endstop: true

    open_action:
      - switch.turn_on: relay2
      - delay: 25s
      - switch.turn_off: relay2

    open_duration: ${open_duration}

    close_action:
      - switch.turn_on: relay1
      - delay: 25s
      - switch.turn_off: relay1

    close_duration: ${close_duration}
    #max_duration: 25sec
    stop_action:
      - switch.turn_off: relay2
      - switch.turn_off: relay1

edit: added the has_built_in_endstop

glmnet commented 4 years ago

I agree we can have a time configuration to discard some time between the command is sent to the motor and the cover actually starts moving, this might make sense if you start stop your cover many times in mid position may be.

autox86 commented 4 years ago

Hi, In my configuration above you can see I am using momentary switches, so more or less a button. 1x Click on the "button" for Up --> Moving UP 1x Click on button Up/Down (while still moving) --> Stop

Anyhow, I will check if your config will work, but I am afraid this will not change the behaviour as the time is also not taken into account, when stopping/starting the roller motor very often, at least this is my assumption. (Time calculation will start in "time-based cover", and the delay of the "switch" is not taken into account)

Honestly I could live with the time-issue (position issue), but "max_duration" would really be helpful... This would make sure my rollers are always completely open / closed, as the max_duration will be my "Start / Stop Time". Of course I could use "built-in-endstop" only, but this means my ESP8266 Relay will remain in status "ON".

See my example below for a better understanding:

My idea:

The parameter "has_built_in_endstop=true" and "max_duration=20s", which would cause the following:

1.) my blind is closed 2.) Either by HomeAssistant or by my momentary switch I click UP 3.) My ESP8266 Relay will change to state ON 4.) My Motor starts moving up 5.) My built-in-endstop of the motor is reached, the movement stops 6.) My ESP8266 Relay Board is still in in state ON 7.) max_duration of 20s is reached, sending stop command, ESP8266 Relay will change to state off

Text for the ESPHome documentation could be: max_duration (Optional, Time): The maximum duration the cover will opening or closing even if the time-based end-position based on close_duration / open_duration (0% / 100%) has been reached. !!!ONLY activate if your motor has build-in endstops!!!

alfredopironti commented 2 years ago

Same issue here.

@glmnet it indeed would make sense to add a configuration to discard some time. Since this is mostly to account for interlock_wait_time, it could apply only when direction changes (i.e. close -> open; or open -> close). If you come from a stopped state, then you just count time as usual.

Likely, a user would configure the same value of interlock_wait_time, or even a bit more if you do have built-in endstops. (No point trying to infer this amount of time, since the cover open/close actions can actually be any code.) I also don't really want to enable the has_built_in_endstop option, as I don't like the idea of possibly keeping a relay on all the time.

Your idea in https://github.com/esphome/feature-requests/issues/778#issuecomment-653065254 is also tempting, but as you also seemed to hint, one may get some race conditions. E.g. I start closing the cover (some 25s timer_1 starts because of the delay action) and I stop the cover after 1s. Then I wait 20s, and I begin closing again. The cover would stop alone after 4s, because of timer_1, which is unexpected.

Would we have enough consensus to start looking into the implementation of the "discard time" option?


@Gio-dot

Hi, software interlock can't never be a safe and smart solution. Best way is to use an electrical interlock. Take a look here: https://github.com/Gio-dot/Six-shutters-ESP32-controller

As a note, this solves the interlock, but crucially not the interlock_wait_time. In your setup, when the on_cover relay is on, switching the dir_cover relay (e.g. switching from open to close) makes the shutter change direction instantaneously, and could blow a motor. (By the way, it also seems that switching from close to open has no effect, as the dir_cover relay is never turned off.)

In fact there's an alternative way of achieving physical interlock (see image below): send Line (220V) to the COM of relay_1, use NO of relay_1 for cover direction UP, join NC of relay_1 with NO of relay_2; use COM of relay_2 for cover direction DOWN. This makes programming straightforward as you get one relay per direction, and electrical interlock (but, again, no interlock_wait_time!) relay_interlock

autox86 commented 2 years ago

Somehow I am not able to reference the Pull Request here. :-( Anyone an idea how I need to do that?

@djwmarcx Add Current based cover #1439

I have seen you are maintaining "current based cover"

We have the issue that the cover is not closing / opening when we have wait time configured and we started and stopped the cover a lot between 0-100%.

Solution: 1.) For a indirect fix, would it be possible that you @djwmarcx helping us and adding the following to time based cover? 💯 max_duration as you did for current based cover? So we can avoid stopping the cover with has_built_in_endstop and make sure max_duration is performing the "stop_action" and relays get released.

2.) The real fix would be taking into account the wait time, but I am unsure if it is worth the amount of time to spend on that.

djwmarcx commented 2 years ago

Well, you are having the same kind of problems I have suffered in the past using the time-based cover component. Those are the reason I've ended up creating the current-based cover component and using Shelly's 2.5 for all my shutters/awnings

Specifically:

If you can, I recommend you buy Shelly 2.5 devices instead of the tuya ones. The Shelly 2.5 provides current measurement in every channel. Along with the current-based component, your shutters will be re-calibrated every time open or closed positions are requested (every night maybe?). The integration will just leave the relay close until the motor stops consuming current. Also, you will get a more safe software interlocking (based on the current consumption). With the basic one, you can't know if a relay is welded. And... it happens. Hardware interlocking is the safest, that's true.... but devices with that kind of relays are pretty uncommon, and fitting something custom in a wall is a little bit sketchy.

That said, if you are tied to the time-based:

autox86 commented 2 years ago

@djwmarcx Thanks a lot for your reply. I was already afraid, I am the only one having that issue 😉

Okay, let me try to cover all aspects of your answer. 1.) I agree totally, time based cover with the basic tuya devices I use, is dangerous as the relays can get welded and burn my motors.

2.) Time based cover is a best guess only, as there is no re-calibration happening due to a miss of measurement (current)

3.) I have seen your current based cover and I was more than happy that you have a) implemented what I misses with time based cover (calibration, max-duration) b) sort of safety against disfunction.

4.) I have seen your current based cover component and bought sonoff dual r3, which should work same as the shelly ones. Why the sonoff and not the Shelly's? They are based on esp32 and I can use the BLE for plenty of other sensors, which is just fine for me. Sonoff is given with 1a inductive current, while I have not seen that for shelly.

In my eyes I am really concerned about the heat a shelly is producing, which is more or less based on the formfactor.

So yes, I will replace all my tuya devices with a sonoff and being happy that I can use your component 😀

The downside, the case of the sonoff is around 2mm to big to fit in a standard underwall case, which are standard here But as I have a dedicated underwall case next to each of my windows, it still fits into them.

So now you may wonder why I am asking you if you would like to implement the feature "max-duration" to the time based cover...?! I have learned from my previous mistakes 😉 Currently I am renovating our living room / kitchen and I have planned a central place for all wires.

This provides me the possibility to control 5 additional motors by simply using this one here: https://www.aliexpress.com/item/1005003319135693.html

With this board I can implement a hardware interlock. So no need for a wait time anymore.

Nevertheless, cover will change the length due to thermal differences (summer/winter), so there is always a kind of difference when it is fully closed/ opened by time. Btw the winter mode of my motors is optionally. When activated it always stops short before reaching the upper end. Every third full opening it will drive to the end for calibration, another reason why a sort of max duration is helpful.

So, adding a delay off when the cover is requested to 0% and 100% --》 Not sure if this is working. I still have my physical switches (buttons) in use, so when I press it, you never know if I press again to stop it half the way. But yes, either adding a delay or a sort of max duration is fine.

What do you think about a name like: relay_off_wait_time Or delay_relay_off

I am not a very good dev, but I could help maintain the documentation and of course I can help testing.

Just let me know.

bkbartk commented 1 year ago

I have the exact some issue but Reduce the interlocking wait-time to 200ms: This is enough and it will reduce the calibration drift almost to half. Once I do that, the issue seems to be fully gone, for now it's ok, but I like to be able to set this to 1second or something