Last active
February 11, 2017 22:40
-
-
Save JerryWorkman/1a7e6a2d5b4d631866d19ec7f6633de6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Tilt switch. | |
Documentation: https://gist.github.com/JerryWorkman/f301c2f5b2e2e2741995280d32858da0#file-cover-tilt-md | |
Jerry Workman <jerry.workman@gmail.com> | |
License: MIT | |
5 Nov 2016 | |
Last Revised: 15 Dec 2016 | |
Combines a tilt sensor and a relay switch to control a garage door opener or | |
motorized gate. When this switch is turned on it will toggle the relay to | |
activate the garage door if it is not already open. The reverse will happen | |
when it is turned off. | |
The status is not reported while the door is opening or closing based on the | |
run_time parameter. | |
My Hardware: | |
Ecolink Intelligent Technology Z-Wave Garage Door Tilt Sensor: | |
http://amzn.to/2ebYPgU | |
GoControl Z-Wave Isolated Contact Fixture Module - FS20Z-1: | |
http://amzn.to/2ec29bK | |
Copy this file to <config_dir>/cover/tilt.py | |
Add the following to your configuration.yaml: | |
cover tilt: | |
platform: tilt | |
switches: | |
front_garage_door: | |
tilt_sensor: binary_sensor.my_tilt_switch | |
switch: switch.my_relay_switch | |
#optional on time for switch to simulate button press. default 1 second | |
contact_delay: 1 | |
#optional run time for the opener. default: 10 seconds | |
run_time: 10 | |
""" | |
from threading import Timer | |
import logging | |
import voluptuous as vol | |
import homeassistant.helpers.config_validation as cv | |
from homeassistant.components.cover import CoverDevice | |
from homeassistant.components.cover import PLATFORM_SCHEMA | |
from homeassistant.components import switch | |
from homeassistant.const import (STATE_OPEN, STATE_CLOSED, STATE_ON, | |
STATE_UNKNOWN) | |
_LOGGER = logging.getLogger(__name__) | |
CONF_TILT_SENSOR = 'tilt_sensor' | |
CONF_SWITCH = 'switch' | |
CONF_CONTACT_DELAY = 'contact_delay' | |
CONF_CONTACT_RUN_TIME = 'run_time' | |
DEFAULT_CONTACT_DELAY = 1 # momentary contact relay switch on time (sec) | |
DEFAULT_RUN_TIME = 10 # seconds required for door to open or close | |
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ | |
vol.Required(CONF_TILT_SENSOR, default=None): cv.string, | |
vol.Required(CONF_SWITCH, default=None): cv.string, | |
vol.Optional(CONF_CONTACT_DELAY, | |
default=DEFAULT_CONTACT_DELAY): cv.positive_int, | |
vol.Optional(CONF_CONTACT_RUN_TIME, | |
default=DEFAULT_RUN_TIME): cv.positive_int, | |
}) | |
# pylint: disable=unused-argument | |
def setup_platform(hass, config, add_entities, discovery_info=None): | |
"""Add all tilt sensors.""" | |
covers = config.get('covers', {}) | |
devices = [] | |
for dev_name, properties in covers.items(): | |
_LOGGER.debug("Adding cover %s: %s, %s", dev_name, | |
properties.get(CONF_TILT_SENSOR), | |
properties.get(CONF_SWITCH)) | |
devices.append( | |
TiltCover( | |
hass, | |
dev_name, | |
properties.get(CONF_TILT_SENSOR), | |
properties.get(CONF_SWITCH), | |
properties.get(CONF_CONTACT_DELAY, DEFAULT_CONTACT_DELAY), | |
properties.get(CONF_CONTACT_RUN_TIME, DEFAULT_RUN_TIME)), | |
) | |
if not devices: | |
_LOGGER.error("No covers added") | |
return False | |
add_entities(devices) | |
class TiltCover(CoverDevice): | |
""" | |
Tilt sensor and (toggle) switch to control a garage door opener or | |
motorized gate. | |
""" | |
def __init__(self, hass, dev_name, tilt_sensor_id, switch_id, | |
contact_delay=DEFAULT_CONTACT_DELAY, | |
run_time=DEFAULT_RUN_TIME): | |
"""init the class""" | |
self._name = dev_name | |
self._hass = hass | |
self._tilt_sensor = tilt_sensor_id | |
self._switch = switch_id | |
self._contact_delay = contact_delay | |
self._run_time = run_time | |
self._state = STATE_UNKNOWN | |
self._running = False # is door in the process of opening or closing | |
self._delay_timer = None | |
self._run_timer = None | |
@property | |
def name(self): | |
"""Return sensor name.""" | |
return self._name | |
@property | |
def is_closed(self): | |
return self._state == STATE_CLOSED | |
def open_cover(self, **kwargs): | |
"""Open garage door.""" | |
if self.is_closed: | |
self._toggle() | |
self._state = STATE_OPEN | |
self.schedule_update_ha_state() | |
def close_cover(self, **kwargs): | |
"""Close garage door.""" | |
if not self.is_closed: | |
self._toggle() | |
self._state = STATE_CLOSED | |
self.schedule_update_ha_state() | |
def _insure_relay_is_off(self): | |
""" | |
Just in case the relay is stuck on (closed) turn it off. | |
If the relay is stuck in the on (closed) position then the garage | |
door opener will not work manually or via remote. | |
""" | |
switch.turn_off(self.hass, self._switch) | |
def _toggle(self): | |
"""Simulate a momentary contact button press.""" | |
def _stop_delay_timer(): | |
"""Open momentary relay switch""" | |
switch.turn_off(self.hass, self._switch) | |
def _stop_run_timer(): | |
"""The door should be open/closed by now""" | |
self._running = False | |
self._insure_relay_is_off() | |
switch.turn_on(self.hass, self._switch) | |
self._running = True | |
self._delay_timer = Timer(self._contact_delay, _stop_delay_timer) | |
self._delay_timer.start() | |
self._run_timer = Timer(self._run_time, _stop_run_timer) | |
self._run_timer.start() | |
@property | |
def state(self): | |
return self._state | |
def update(self): | |
"""Copy state of tilt sensor state of device.""" | |
if self._running: | |
_LOGGER.debug('tilt switch %s running, assumed state is %s', | |
self._name, self._state) | |
else: | |
tilt = self._hass.states.get(self._tilt_sensor) | |
self._state = STATE_OPEN if tilt and tilt.state == STATE_ON \ | |
else STATE_CLOSED |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment