Skip to content
Snippets Groups Projects
Commit 2ec295a6 authored by Johan Bloemberg's avatar Johan Bloemberg Committed by Pascal Vizeli
Browse files

Add availability to Rflink entities. (#14977)

parent 4bd7a7ee
No related branches found
No related tags found
No related merge requests found
......@@ -20,6 +20,8 @@ from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.deprecation import get_deprecated
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.dispatcher import (
async_dispatcher_send, async_dispatcher_connect)
REQUIREMENTS = ['rflink==0.0.37']
......@@ -65,6 +67,8 @@ DOMAIN = 'rflink'
SERVICE_SEND_COMMAND = 'send_command'
SIGNAL_AVAILABILITY = 'rflink_device_available'
DEVICE_DEFAULTS_SCHEMA = vol.Schema({
vol.Optional(CONF_FIRE_EVENT, default=False): cv.boolean,
vol.Optional(CONF_SIGNAL_REPETITIONS,
......@@ -185,6 +189,8 @@ def async_setup(hass, config):
# Reset protocol binding before starting reconnect
RflinkCommand.set_rflink_protocol(None)
async_dispatcher_send(hass, SIGNAL_AVAILABILITY, False)
# If HA is not stopping, initiate new connection
if hass.state != CoreState.stopping:
_LOGGER.warning('disconnected from Rflink, reconnecting')
......@@ -219,9 +225,16 @@ def async_setup(hass, config):
_LOGGER.exception(
"Error connecting to Rflink, reconnecting in %s",
reconnect_interval)
# Connection to Rflink device is lost, make entities unavailable
async_dispatcher_send(hass, SIGNAL_AVAILABILITY, False)
hass.loop.call_later(reconnect_interval, reconnect, exc)
return
# There is a valid connection to a Rflink device now so
# mark entities as available
async_dispatcher_send(hass, SIGNAL_AVAILABILITY, True)
# Bind protocol to command class to allow entities to send commands
RflinkCommand.set_rflink_protocol(
protocol, config[DOMAIN][CONF_WAIT_FOR_ACK])
......@@ -244,6 +257,7 @@ class RflinkDevice(Entity):
platform = None
_state = STATE_UNKNOWN
_available = True
def __init__(self, device_id, hass, name=None, aliases=None, group=True,
group_aliases=None, nogroup_aliases=None, fire_event=False,
......@@ -305,6 +319,23 @@ class RflinkDevice(Entity):
"""Assume device state until first device event sets state."""
return self._state is STATE_UNKNOWN
@property
def available(self):
"""Return True if entity is available."""
return self._available
@callback
def set_availability(self, availability):
"""Update availability state."""
self._available = availability
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_added_to_hass(self):
"""Register update callback."""
async_dispatcher_connect(self.hass, SIGNAL_AVAILABILITY,
self.set_availability)
class RflinkCommand(RflinkDevice):
"""Singleton class to make Rflink command interface available to entities.
......
......@@ -8,6 +8,9 @@ automatic sensor creation.
import asyncio
from ..test_rflink import mock_rflink
from homeassistant.components.rflink import (
CONF_RECONNECT_INTERVAL)
from homeassistant.const import STATE_UNKNOWN
DOMAIN = 'sensor'
......@@ -32,7 +35,7 @@ CONFIG = {
def test_default_setup(hass, monkeypatch):
"""Test all basic functionality of the rflink sensor component."""
# setup mocking rflink module
event_callback, create, _, _ = yield from mock_rflink(
event_callback, create, _, disconnect_callback = yield from mock_rflink(
hass, CONFIG, DOMAIN, monkeypatch)
# make sure arguments are passed
......@@ -100,3 +103,38 @@ def test_disable_automatic_add(hass, monkeypatch):
# make sure new device is not added
assert not hass.states.get('sensor.test2')
@asyncio.coroutine
def test_entity_availability(hass, monkeypatch):
"""If Rflink device is disconnected, entities should become unavailable."""
# Make sure Rflink mock does not 'recover' to quickly from the
# disconnect or else the unavailability cannot be measured
config = CONFIG
failures = [True, True]
config[CONF_RECONNECT_INTERVAL] = 60
# Create platform and entities
event_callback, create, _, disconnect_callback = yield from mock_rflink(
hass, config, DOMAIN, monkeypatch, failures=failures)
# Entities are available by default
assert hass.states.get('sensor.test').state == STATE_UNKNOWN
# Mock a disconnect of the Rflink device
disconnect_callback()
# Wait for dispatch events to propagate
yield from hass.async_block_till_done()
# Entity should be unavailable
assert hass.states.get('sensor.test').state == 'unavailable'
# Reconnect the Rflink device
disconnect_callback()
# Wait for dispatch events to propagate
yield from hass.async_block_till_done()
# Entities should be available again
assert hass.states.get('sensor.test').state == STATE_UNKNOWN
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment