As a followup on this for future searchers, I eventually opted for using a Duty Cycle sensor and Pulse Counter sensor in ESPHome then used a value_template and icon_template to decode the various permutations of signals that my garage door opener outputs. Cover status can only be Open/Close but by using icon_template I’m able to provide some more meaningful feedback via the Lovelace UI (eg, power cut, open, closed, operating/partially open, unavailable).
For reference, the door opener is a very common unit sold in the New Zealand and Australian markets by various door companies. The brand and model are: Automatic Technology GDO-6v4 EasyRoller.
I intercepted the signals by connecting my ESP8266 to the GDO’s Aux socket giving me 5v supply and a common ground. By soldering pigtails carefully to the “high” side of open/close surface mount LEDs I’m able to sense the status of the doors operation. a 2v voltage drop across the LEDs is perfect to drive the GPIOs on the 3.3v ESP8266. Finally a relay connects across the OCS/GND pins to “press the button”.
Decoding the LEDs is made a little complex because they are lit solid, flash individually and together to represent open, opening, closed, closing, partially open and a power outage (why they bother to indicate this is beyond me!). Therefore it became a bit of an exercise to decipher into the simple status’ of open/closed that a Cover supports.
For my cover I have treated the LEDs/sensor connections as follows:
Bottom LED sensor:
Type: Duty Cycle. UoM: %
Sample: 3s
States:
- Door closed = duty cycle of 100% (ie, sensor detects high)
- Door partially open = bottom sensor detects pulses at 1Hz AND top sensor detects pulses at 1Hz (< 100 pulses / minute)
- Door open = duty cycle of 0% (ie, sensor detects low) AND top sensor is on continuously (pulse counter = 0)
Top LED sensor:
Type: Pulse Counter. UoM: pulses/minute
Sample: 3s
States:
- Door partially open = LED pulses at 1Hz (< 100 pulses / minute)
- Power outage = sensor detects pulses at 2Hz (> 100 pulses / minute)
Note: approximations are used when comparing pulse/duty values as the sample period is 3s to keep the UI feedback responsive. In practise and testing it works very nicely.
Heres my cover config:
cover:
- platform: template
covers:
garage_door:
device_class: garage
friendly_name: Garage Door
value_template: >
{% if is_state('sensor.garage_door_top', 'unavailable') and s_state('sensor.garage_door_bottom', 'unavailable') %}
Closed
{% elif states('sensor.garage_door_top') | int > 100 %}
Closed
{% elif states('sensor.garage_door_bottom') | int == 100 %}
Closed
{% elif states('sensor.garage_door_bottom') | int == 0 and states('sensor.garage_door_top') | int == 0 %}
Open
{% elif states('sensor.garage_door_closed') | int < 100 and states('sensor.garage_door_top') | int < 100 %}
Open
{% else %}
Closed
{% endif %}
open_cover:
service: switch.turn_on
data:
entity_id: switch.garage_door
close_cover:
service: switch.turn_on
data:
entity_id: switch.garage_door
icon_template: >-
{% if is_state('sensor.garage_door_top', 'unavailable') and s_state('sensor.garage_door_bottom', 'unavailable') %}
mdi:help-box
{% elif states('sensor.garage_door_top') | int > 100 %}
mdi:power-plug-off
{% elif states('sensor.garage_door_bottom') | int == 100 %}
mdi:garage
{% elif states('sensor.garage_door_bottom') | int == 0 and states('sensor.garage_door_top') | int == 0 %}
mdi:garage-open
{% elif states('sensor.garage_door_bottom') | int < 100 and states('sensor.garage_door_top') | int < 100 %}
mdi:garage-alert
{% else %}
mdi:garage
{% endif %}
I’m pretty chuffed at how this turned out. My wife is happy and now pushing me to detect her driving up the road so the door opens automatically. If I can manage this then its likely my home automation plans will take off at pace!