Skip to content

Commit

Permalink
Binary Sensor for Remote UI & Fix timezone (#22076)
Browse files Browse the repository at this point in the history
* Binary Sensor for Remote UI

* Fix lint

* Revert make hass public

* Add tests
  • Loading branch information
pvizeli authored and balloob committed Mar 15, 2019
1 parent 3ec8b5a commit ac1aeb3
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 6 deletions.
4 changes: 3 additions & 1 deletion homeassistant/components/cloud/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
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__)
Expand Down Expand Up @@ -193,4 +193,6 @@ async def _service_handler(service):
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
73 changes: 73 additions & 0 deletions homeassistant/components/cloud/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -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
15 changes: 12 additions & 3 deletions homeassistant/components/cloud/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@
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


Expand Down Expand Up @@ -115,13 +118,19 @@ async def cleanups(self) -> None:
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."""
Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/cloud/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@

MODE_DEV = "development"
MODE_PROD = "production"

DISPATCHER_REMOTE_UPDATE = 'cloud_remote_update'
2 changes: 1 addition & 1 deletion requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
32 changes: 32 additions & 0 deletions tests/components/cloud/test_binary_sensor.py
Original file line number Diff line number Diff line change
@@ -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'

0 comments on commit ac1aeb3

Please sign in to comment.