[SOLVED] Garage Cover based on timer - no open/close state sensor

Hey guys,
I have upgraded my sliding garage door with a tasmota’ed sonoff basic switch.
The sonoff has a pulsetime set to 0.7s so it will just give the command to open/stop/close.
Unfortunatelly back when i was setting it up, i didnt think if hooking up a magnetic switch sensor or anything similar to read the position of my door and now the (somewhat old) box has been sealed with silicone. So im looking into a way to guess the state of the door without having to reopen the whole thing.

So i was thinking i could do it with a script or a template and try to guess the state depending on the time it has passed inbetween the on commands sent to the machine.

Im trying to do something like this:
Assuming the garage needs exactly 10s to fully open and that the starting state is closed
On first button press, have a template sensor (probably? or a couple of input booleans) indicate the garage state as opening.
If the second button press does not come within 10s, the state should change to open. if it comes before 10s, it should change to opening-stop.
The second button press should change the state accordingly to the previous and give different state depending on how soon it happened (compared to the 10s).
And so on and so on.

My thought was to have a percentage number to show the position of the door from 0-100%open by calculating the time it has worked.

Here is a first depiction of the code i tried to do in excel (maybe its wrong or stupid but im very new at coding and things :slight_smile:)
So i dont know if it makes any sense, or how the hell im going to turn that into code…

Has anyone written something similar?
Or can give me some tips on how to go about it?
Is there some smarter way to do it?

I know that I cannot include some factors like the door being stopped by its sensor but still… it will be smarter than it is now.

Ill start working on it but if anyone has some idea, you are free to stop me :slight_smile:
Thanks in advance

Edit: wrote a working code myself, you can check it out in the post below

You are saying you have no way of knowing the actual state of the garage door.

Instead of addressing that deficiency, you are creating a fake garage door sensor based on timing.

Here’s a metaphor:

  • Your doctor diagnoses you and prescribes treatment.
  • Your doctor never follows up with you to determine the treatment’s progress, efficacy, or success.
  • Instead, your doctor fakes a report about your condition based on timing.
    • Two days have passed, patient is feeling better.
    • Five days have passed, patient is almost fully recovered.
    • Eight days and patient is fully recovered.

I highly recommend you perform surgery on the sealed box and connect a magnetic switch to detect the door’s state.

BTW, I have used timing for a door’s state. If we forget to close the garage door after leaving, 5 minutes after our departure the door is automatically commanded to close. If it fails to close within 20 seconds, we receive an alert via text message.

It’s a 20-second watchdog timer. It counts down to 20 seconds, then sends the alert. However, if the door closes successfully, its door sensor cancels the watchdog timer. Without an actual door sensor, it would be pointless.

1 Like

If I’m understanding this correctly (you never said so, but I’m assuming that you’re using MQTT to control the sonoff), I believe you could use “optimistic: true” in your cover configuration to get what you want. It causes the cover to assume that the command that you gave to close/open the door will work. You wouldn’t get the wait time that you wanted between command and state change, but I don’t see what that gains you if you don’t know the actual state of the door anyway.

I appreciate the the metaphor man and i know that the correct way to fix it is to add a sensor.
Was just reaching out for help to avoid the surgery.

If my door needs say 10s to fully open, then by counting the time between two subsequent commands would help me assume the door’s state. That’s what im trying to do.

I understand your reticence and empathize with your predicament. No part of my home automation system relies on any form of wireless protocol; everything is hard-wired. So you can imagine the frustration when you realize, at some later date, “Nuts! I should’ve run one more pair to that location!”

You’re not obliged to perform surgery and can opt for something less invasive. For example, if you have an existing wireless transceiver (zwave, zigbee, 433MHz RF, etc) you can add a wireless contact sensor or minimally a tilt sensor.

I think your time is better spent installing a door sensor than cobbling together timers and code to fake the door’s state. The strategy is also fragile. If the command sent to open the door fails, your timers & code will cheerfully continue to lie about the door’s progress and closure.

Having said that, if your heart is set on building this thing, I wish you luck.

I am aware of that, unfortunatelly :frowning:

Will try to code it and see how it goes, if everyday use shows it is unreliable i will go ahead with the surgery and add a magnetic sensor to the sonoff i already have inside the machine.

Thanks :slight_smile:

If you don’t have any other way than MQTT then an easy and fairly inexpensive way to solve you problem is to use a NodeMCU with a ultrasonic sensor connected to it to measure the door position.

It’s what I use for one of my garage doors since I was tired of the unreliability of the MyQ cloud service.

Agreed, there are several ways.
In my case the best would be to just hook a sensor (ultrasonic or reed) on the sonoff i have inside the box.
Was just looking for something on the software side before i go do that :slight_smile:

So, despites of everyone’s understandable disagreement, i think i’ve done it with code.
It’s not perfect but it works.
The main advantage is that i have an (unsafe) indication of where my garage doors are, in case i forget to close them when leaving the house.

Gonna share for comments and to, perhaps, help someone out.

notes:

  • the up part in naming is due to me having two doors, one is named up, the other dn, so you can ignore it
  • The only two things you need to change for this to work are the variable for total time the door takes to move from end to start ( garage_up_total_time) and the name of the switch that toggles your garage, in my case switch.sonoff_garage_2.
  • The switch could also be an RF transmitter

So here it is:

Please keep in mind that my door works with the simple way possible with only one signal input:

  • Signal while closed -> start opening.
  • Signal while opening -> stop (will start closing on next signal)
  • Signal while stopped in the middle -> start closing (depending on previous state)
  • Signal while closing -> stop (will start opening on next signal)
  • Signal while stopped in the middle -> start opening (depending on previous state)
  • Signal while open -> start closing.

Code:

  1. An input_select to state the 6 different states of the door:
    This should go in your configuration.yaml under input_select: or in your input_select.yaml if you have input_select: !include input_select.yaml already in your conf.
  garage_up_state:
    name: Garage UP State
    initial: Closed
    options:
      - Closed
      - Opening
      - Stopped Next Closing
      - Stopped Next Opening
      - Closing
      - Open
  1. I used this component to be able to store some variables (instead of input numbers and stuff)
    hass-variables
    With hass-variables, i created several variables to be able to track down times, the position of the door and the total time the door takes to open/close (starting from closed/open, respectively)
    This goes in configuration.yaml under variable: or in variables.yaml if you have variable: !include variables.yaml already in your conf.
  garage_up_total_time:
    value: 16 #change this value accordingly
  garage_up_position:
    value: 0
  garage_up_last_use:
    value: 0
  garage_up_prev_use:
    value: 0
  1. A script to run different scripts depending on the state of the input_select above
garage_up_operation:
  alias: "Garage Up Toggle"
  sequence:
    - service: variable.set_variable
      data:
        variable: "garage_up_prev_use"
        value_template: "{{(states.variable.garage_up_last_use.state)| int}}"
    - service: variable.set_variable
      data:
        variable: "garage_up_last_use"
        value_template: "{{(as_timestamp(now())| round(0))+(2*60*60)| int}}"
    - service: script.turn_on
      data_template:
        entity_id: >
          {% if is_state("input_select.garage_up_state", "Closed") %}
            script.garage_up_closed
          {% elif is_state("input_select.garage_up_state", "Opening") %}
            script.garage_up_opening
          {% elif is_state("input_select.garage_up_state", "Stopped Next Closing") %}
            script.garage_up_stopped_next_closing
          {% elif is_state("input_select.garage_up_state", "Stopped Next Opening") %}
            script.garage_up_stopped_next_opening
          {% elif is_state("input_select.garage_up_state", "Closing") %}
            script.garage_up_closing
          {% elif is_state("input_select.garage_up_state", "Open") %}
            script.garage_up_open
          {% endif %}

  1. And then some more scripts that would handle the operation switch and change the input_select according to where the door is.
garage_up_closed:
  alias: "When Garage Up Closed"
  sequence:
    - service: switch.turn_on
      entity_id: switch.sonoff_garage_2
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Opening"
        
    - delay:
        seconds: "{{(states.variable.garage_up_total_time.state)| int}}"
        
    - service: variable.set_variable
      data:
        variable: "garage_up_position"
        value_template: "{{(states.variable.garage_up_total_time.state)| int}}"
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Open"
        
        
        
garage_up_opening:
  alias: "When Garage Up Opening"
  sequence:
    - service: switch.turn_on
      entity_id: switch.sonoff_garage_2
    - service: script.turn_off
      entity_id: script.garage_up_closed, script.garage_up_stopped_next_opening 
    - service: variable.set_variable
      data:
        variable: "garage_up_position"
        value_template: "{{(states.variable.garage_up_position.state)| int +(states.variable.garage_up_last_use.state)| int-(states.variable.garage_up_prev_use.state)| int}}"
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Stopped Next Closing"



garage_up_stopped_next_closing: #was Opening
  alias: "When Garage Up Stopped, next: Closing"
  sequence:
    - service: switch.turn_on
      entity_id: switch.sonoff_garage_2
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Closing"
        
    - delay:
        seconds: "{{(states.variable.garage_up_position.state)| int}}" 

    - service: variable.set_variable
      data:
        variable: "garage_up_position" 
        value: "0" # set position 0
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Closed"
        
        
garage_up_stopped_next_opening: #was Closing
  alias: "When Garage Up Stopped, next: Opening"
  sequence:
    - service: switch.turn_on
      entity_id: switch.sonoff_garage_2
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Opening"

    - delay:
        seconds: "{{(states.variable.garage_up_total_time.state)| int - (states.variable.garage_up_position.state)| int}}"

    - service: variable.set_variable
      data:
        variable: "garage_up_position"
        value_template: "{{(states.variable.garage_up_total_time.state)| int}}"  
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Open"
        
        
garage_up_closing:
  alias: "When Garage Up Closing"
  sequence:
    - service: switch.turn_on
      entity_id: switch.sonoff_garage_2
    - service: script.turn_off
      entity_id: script.garage_up_open, script.garage_up_stopped_next_closing
    - service: variable.set_variable
      data:
        variable: "garage_up_position"
        value_template: "{{(states.variable.garage_up_position.state)| int -((states.variable.garage_up_last_use.state)| int - (states.variable.garage_up_prev_use.state)| int)}}" 
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Stopped Next Opening"
        
        

garage_up_open:
  alias: "When Garage Up Open"
  sequence:
    - service: switch.turn_on
      entity_id: switch.sonoff_garage_2
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Closing"
        
    - delay:
        seconds: "{{(states.variable.garage_up_total_time.state)| int}}"
        
    - service: variable.set_variable
      data:
        variable: "garage_up_position"
        value: "0"
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Closed"

The code needs some refactoring and could probably be re-written in a much more smart way but, that’s what I came up with :slight_smile: - open to suggestions

  1. Lastly, for aesthetic reasons, i created a template_sensor to see the door state without being able to alter it. (I still keep the input_select editable in some other page of my frontend in case i need to manually reset the whole thing.)
    Inside sensors.yaml or under sensor: in configuration.yaml
      garage_up_state:
        friendly_name: "Γκαράζ Πάνω" #ignore my greek :)
        value_template: "{{ states.input_select.garage_up_state.state }}"
  1. And lastly v.2, a group to show them in my front-end:
  door_switches:
    control: hidden
    entities:
      - script.garage_up_operation
      - sensor.garage_up_state

I just wrote this up but it seems to be working. Will keep testing and come back with comments.

Main flaw is that im using unix timestamp to do my calculations which means im working with seconds, not fragments of seconds. It does not pose a great threat but if say you open and close the door several times without reaching the end point (using the switch while the door is moving) you get an inaccurate reading of the precise position of the door between the two ends (open/closed). Other than that, you still get accurate reading of the general state of the door.

Another flaw is that one of my doors is using a sensor when closing that will stop it if it finds an obstacle. This means it will change state (from closing to stopped) without HA knowing that. This needs to manually reset the input_select to the correct state afterwards.

Next step would be an automation to send me a notification if the door is not closed for xx time, using the states of my new template sensor.

edit: and here it is.

- id: '1542799053404'
  alias: Notify - Garage Up Open
  trigger:
  - entity_id: sensor.garage_up_state
    for: 00:01:00
    platform: state
    to: Stopped Next Closing
  - entity_id: sensor.garage_up_state
    for: 00:01:00
    platform: state
    to: Stopped Next Opening
  - entity_id: sensor.garage_up_state
    for: 00:01:00
    platform: state
    to: Open
  - entity_id: sensor.garage_dn_state
    for: 00:01:00
    platform: state
    to: Opening #this is probably unnecessary but i just put it there to be sure
  condition: []
  action:
  - data:
      message: Garage UP left Open
      title: Home Security
    service: notify.notify_html5

Hope this helps someone out who’s in the same need as me and doesnt want or cannot install additional sensors.
Now ill go grease the doors cause they screech like harpies :persevere:

k.

Now I think you’re trolling us! Main flaw is it’s απομίμηση. :slight_smile:

However, it has inspired me to write scripts to report color changes for light bulbs that have no color control. :wink:

1 Like

A more accurate term would be “ψεύτικο” but, i think i got your point.
Happy to inispire you, go code something to count the chickens in my backyard :wink:

1 Like

Is hass-variables correctly loaded for you in 0.84 release? Mine stopped working.

Hey there, cant’s really say, im still on 0.83.1
(although something is causing problems and im trying to figure it out right now, but i didnt update recently)

Just upgraded to 0.84.1 and im happy to say that it wont even boot :slight_smile:
Let’s do a clean install :frowning:

The guy released a new variables.py, you can get it from his github that fixed it on 0.84.1.
There’s no mention on his mainpage and the issue has been marked as closed so it’s tricky to spot.

1 Like

i know. I opened an issue on github. Works fine again.

1 Like

Is this still working? I’m new here and tried the code because I’m in the same situation.

I receive the following error:
Invalid config for [sensor]: required key not provided @ data['platform']. Got None. (See /config/configuration.yaml, line 12).

I think theres a problem with my script-file on line 11, because the scenes.yaml is empty.

11 script: !include scripts.yaml
12 scene: !include scenes.yaml
13 sensor: !include sensors.yaml

here’s my script.yaml:

garage_up_operation:
  alias: "Garage Up Toggle"
  sequence:
    - service: variable.set_variable
      data:
        variable: "garage_up_prev_use"
        value_template: "{{(states.variable.garage_up_last_use.state)| int}}"
    - service: variable.set_variable
      data:
        variable: "garage_up_last_use"
        value_template: "{{(as_timestamp(now())| round(0))+(2*60*60)| int}}"
    - service: script.turn_on
      data_template:
        entity_id: >
          {% if is_state("input_select.garage_up_state", "Closed") %}
            script.garage_up_closed
          {% elif is_state("input_select.garage_up_state", "Opening") %}
            script.garage_up_opening
          {% elif is_state("input_select.garage_up_state", "Stopped Next Closing") %}
            script.garage_up_stopped_next_closing
          {% elif is_state("input_select.garage_up_state", "Stopped Next Opening") %}
            script.garage_up_stopped_next_opening
          {% elif is_state("input_select.garage_up_state", "Closing") %}
            script.garage_up_closing
          {% elif is_state("input_select.garage_up_state", "Open") %}
            script.garage_up_open
          {% endif %}

garage_up_closed:
  alias: "When Garage Up Closed"
  sequence:
    - service: switch.turn_on
      entity_id: switch.shelly_garage_fm
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Opening"

    - delay:
        seconds: "{{(states.variable.garage_up_total_time.state)| int}}"

    - service: variable.set_variable
      data:
        variable: "garage_up_position"
        value_template: "{{(states.variable.garage_up_total_time.state)| int}}"
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Open"



garage_up_opening:
  alias: "When Garage Up Opening"
  sequence:
    - service: switch.turn_on
      entity_id: switch.shelly_garage_fm
    - service: script.turn_off
      entity_id: script.garage_up_closed, script.garage_up_stopped_next_opening
    - service: variable.set_variable
      data:
        variable: "garage_up_position"
        value_template: "{{(states.variable.garage_up_position.state)| int +(states.variable.garage_up_last_use.state)| int-(states.variable.garage_up_prev_use.state)| int}}"
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Stopped Next Closing"

garage_up_stopped_next_closing: #was Opening
  alias: "When Garage Up Stopped, next: Closing"
  sequence:
    - service: switch.turn_on
      entity_id: switch.shelly_garage_fm
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Closing"

    - delay:
        seconds: "{{(states.variable.garage_up_position.state)| int}}"

    - service: variable.set_variable
      data:
        variable: "garage_up_position"
        value: "0" # set position 0
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Closed"


garage_up_stopped_next_opening: #was Closing
  alias: "When Garage Up Stopped, next: Opening"
  sequence:
    - service: switch.turn_on
      entity_id: switch.shelly_garage_fm
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Opening"

    - delay:
        seconds: "{{(states.variable.garage_up_total_time.state)| int - (states.variable.garage_up_position.state)| int}}"

    - service: variable.set_variable
      data:
        variable: "garage_up_position"
        value_template: "{{(states.variable.garage_up_total_time.state)| int}}"
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Open"


garage_up_closing:
  alias: "When Garage Up Closing"
  sequence:
    - service: switch.turn_on
      entity_id: switch.shelly_garage_fm
    - service: script.turn_off
      entity_id: script.garage_up_open, script.garage_up_stopped_next_closing
    - service: variable.set_variable
      data:
        variable: "garage_up_position"
        value_template: "{{(states.variable.garage_up_position.state)| int -((states.variable.garage_up_last_use.state)| int - (states.variable.garage_up_prev_use.state)| int)}}"
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Stopped Next Opening"



garage_up_open:
  alias: "When Garage Up Open"
  sequence:
    - service: switch.turn_on
      entity_id: switch.shelly_garage_fm
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Closing"

    - delay:
        seconds: "{{(states.variable.garage_up_total_time.state)| int}}"

    - service: variable.set_variable
      data:
        variable: "garage_up_position"
        value: "0"
    - service: input_select.select_option
      data:
        entity_id: input_select.garage_up_state
        option: "Closed"

thanks for your help.

those three things are all referring to different things.

the error is for a sensor. It says it’s missing ‘platform’ check your sensor config.

Just because the error says “line 11” it doesn’t mean that the error is in scripts.yaml. Sometimes the config checker gets the lines wrong by a little bit. Again, check your sensor config.

There is no issue with having an empty scenes.yaml (unless you are expecting something to be there because you have created a scene).

And, besides, there is no correlation between the scripts.yaml and scenes.yaml. One has nothing to do with the other.

Fix the sensor config and recheck again.

Thanks! now it‘s working. I had to check the syntax in my sensor config.

Wow, I never would have thought to check that! :wink:

:laughing:

Glad you got it fixed.