Binary Sensor for Remote UI & Fix timezone (#22076)

* Binary Sensor for Remote UI

* Fix lint

* Revert make hass public

* Add tests
This commit is contained in:
Pascal Vizeli 2019-03-15 18:39:53 +01:00 committed by Paulus Schoutsen
parent 9520d38288
commit 17ba33004c
7 changed files with 124 additions and 6 deletions

View file

@ -24,7 +24,7 @@ from .const import (
CONF_USER_POOL_ID, DOMAIN, MODE_DEV, MODE_PROD)
from .prefs import CloudPreferences
REQUIREMENTS = ['hass-nabucasa==0.5']
REQUIREMENTS = ['hass-nabucasa==0.7']
DEPENDENCIES = ['http']
_LOGGER = logging.getLogger(__name__)
@ -193,4 +193,6 @@ async def async_setup(hass, config):
DOMAIN, SERVICE_REMOTE_DISCONNECT, _service_handler)
await http_api.async_setup(hass)
hass.async_create_task(hass.helpers.discovery.async_load_platform(
'binary_sensor', DOMAIN, {}, config))
return True

View file

@ -0,0 +1,73 @@
"""Support for Home Assistant Cloud binary sensors."""
from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from .const import DISPATCHER_REMOTE_UPDATE, DOMAIN
DEPENDENCIES = ['cloud']
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None):
"""Set up the cloud binary sensors."""
if discovery_info is None:
return
cloud = hass.data[DOMAIN]
async_add_entities([CloudRemoteBinary(cloud)])
class CloudRemoteBinary(BinarySensorDevice):
"""Representation of an Cloud Remote UI Connection binary sensor."""
def __init__(self, cloud):
"""Initialize the binary sensor."""
self.cloud = cloud
self._unsub_dispatcher = None
@property
def name(self) -> str:
"""Return the name of the binary sensor, if any."""
return "Remote UI"
@property
def unique_id(self) -> str:
"""Return a unique ID."""
return "cloud-remote-ui-connectivity"
@property
def is_on(self) -> bool:
"""Return true if the binary sensor is on."""
return self.cloud.remote.is_connected
@property
def device_class(self) -> str:
"""Return the class of this device, from component DEVICE_CLASSES."""
return 'connectivity'
@property
def available(self) -> bool:
"""Return True if entity is available."""
return self.cloud.remote.certificate is not None
@property
def should_poll(self) -> bool:
"""Return True if entity has to be polled for state."""
return False
async def async_added_to_hass(self):
"""Register update dispatcher."""
@callback
def async_state_update(data):
"""Update callback."""
self.async_write_ha_state()
self._unsub_dispatcher = async_dispatcher_connect(
self.hass, DISPATCHER_REMOTE_UPDATE, async_state_update)
async def async_will_remove_from_hass(self):
"""Register update dispatcher."""
if self._unsub_dispatcher is not None:
self._unsub_dispatcher()
self._unsub_dispatcher = None

View file

@ -6,15 +6,18 @@ from typing import Any, Dict
import aiohttp
from hass_nabucasa.client import CloudClient as Interface
from homeassistant.core import callback
from homeassistant.components.alexa import smart_home as alexa_sh
from homeassistant.components.google_assistant import (
helpers as ga_h, smart_home as ga)
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES
from homeassistant.helpers.typing import HomeAssistantType
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.util.aiohttp import MockRequest
from . import utils
from .const import CONF_ENTITY_CONFIG, CONF_FILTER, DOMAIN
from .const import (
CONF_ENTITY_CONFIG, CONF_FILTER, DOMAIN, DISPATCHER_REMOTE_UPDATE)
from .prefs import CloudPreferences
@ -115,13 +118,19 @@ class CloudClient(Interface):
self._alexa_config = None
self._google_config = None
async def async_user_message(
self, identifier: str, title: str, message: str) -> None:
@callback
def user_message(self, identifier: str, title: str, message: str) -> None:
"""Create a message for user to UI."""
self._hass.components.persistent_notification.async_create(
message, title, identifier
)
@callback
def dispatcher_message(self, identifier: str, data: Any = None) -> None:
"""Match cloud notification to dispatcher."""
if identifier.startwith("remote_"):
async_dispatcher_send(self._hass, DISPATCHER_REMOTE_UPDATE, data)
async def async_alexa_message(
self, payload: Dict[Any, Any]) -> Dict[Any, Any]:
"""Process cloud alexa message to client."""

View file

@ -25,3 +25,5 @@ CONF_ACME_DIRECTORY_SERVER = 'acme_directory_server'
MODE_DEV = "development"
MODE_PROD = "production"
DISPATCHER_REMOTE_UPDATE = 'cloud_remote_update'

View file

@ -524,7 +524,7 @@ habitipy==0.2.0
hangups==0.4.6
# homeassistant.components.cloud
hass-nabucasa==0.5
hass-nabucasa==0.7
# homeassistant.components.mqtt.server
hbmqtt==0.9.4

View file

@ -114,7 +114,7 @@ ha-ffmpeg==1.11
hangups==0.4.6
# homeassistant.components.cloud
hass-nabucasa==0.5
hass-nabucasa==0.7
# homeassistant.components.mqtt.server
hbmqtt==0.9.4

View file

@ -0,0 +1,32 @@
"""Tests for the cloud binary sensor."""
from unittest.mock import Mock
from homeassistant.setup import async_setup_component
from homeassistant.components.cloud.const import DISPATCHER_REMOTE_UPDATE
async def test_remote_connection_sensor(hass):
"""Test the remote connection sensor."""
assert await async_setup_component(hass, 'cloud', {'cloud': {}})
cloud = hass.data['cloud'] = Mock()
cloud.remote.certificate = None
await hass.async_block_till_done()
state = hass.states.get('binary_sensor.remote_ui')
assert state is not None
assert state.state == 'unavailable'
cloud.remote.is_connected = False
cloud.remote.certificate = object()
hass.helpers.dispatcher.async_dispatcher_send(DISPATCHER_REMOTE_UPDATE, {})
await hass.async_block_till_done()
state = hass.states.get('binary_sensor.remote_ui')
assert state.state == 'off'
cloud.remote.is_connected = True
hass.helpers.dispatcher.async_dispatcher_send(DISPATCHER_REMOTE_UPDATE, {})
await hass.async_block_till_done()
state = hass.states.get('binary_sensor.remote_ui')
assert state.state == 'on'