Add events on cloud connect and disconnect (#65215)

* Add events on cloud connect and disconnect

Signed-off-by: cgtobi <cgtobi@gmail.com>

* Use event capture helper

Signed-off-by: cgtobi <cgtobi@gmail.com>

* Provide listener method instead of public event

Signed-off-by: cgtobi <cgtobi@gmail.com>

* Add test for disconnect notification

Signed-off-by: cgtobi <cgtobi@gmail.com>

* Apply suggestions from code review

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Use Enum

Signed-off-by: cgtobi <cgtobi@gmail.com>

* Add module level api

Signed-off-by: cgtobi <cgtobi@gmail.com>

* Apply suggestions from code review

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Clean up dead code

Signed-off-by: cgtobi <cgtobi@gmail.com>

* Flake8

Signed-off-by: cgtobi <cgtobi@gmail.com>

* Clean up

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
pull/65443/head
Tobias Sauerwein 2022-02-02 18:11:06 +01:00 committed by GitHub
parent fda0fbd115
commit 81ad56b8ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 53 additions and 0 deletions

View File

@ -1,5 +1,7 @@
"""Component to integrate the Home Assistant cloud."""
import asyncio
from collections.abc import Callable
from enum import Enum
from hass_nabucasa import Cloud
import voluptuous as vol
@ -18,6 +20,10 @@ from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv, entityfilter
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.dispatcher import (
async_dispatcher_connect,
async_dispatcher_send,
)
from homeassistant.helpers.typing import ConfigType
from homeassistant.loader import bind_hass
from homeassistant.util.aiohttp import MockRequest
@ -52,6 +58,8 @@ DEFAULT_MODE = MODE_PROD
SERVICE_REMOTE_CONNECT = "remote_connect"
SERVICE_REMOTE_DISCONNECT = "remote_disconnect"
SIGNAL_CLOUD_CONNECTION_STATE = "CLOUD_CONNECTION_STATE"
ALEXA_ENTITY_SCHEMA = vol.Schema(
{
@ -118,6 +126,13 @@ class CloudNotConnected(CloudNotAvailable):
"""Raised when an action requires the cloud but it's not connected."""
class CloudConnectionState(Enum):
"""Cloud connection state."""
CLOUD_CONNECTED = "cloud_connected"
CLOUD_DISCONNECTED = "cloud_disconnected"
@bind_hass
@callback
def async_is_logged_in(hass: HomeAssistant) -> bool:
@ -135,6 +150,14 @@ def async_is_connected(hass: HomeAssistant) -> bool:
return DOMAIN in hass.data and hass.data[DOMAIN].iot.connected
@callback
def async_listen_connection_change(
hass: HomeAssistant, target: Callable[[CloudConnectionState], None]
) -> Callable[[], None]:
"""Notify on connection state changes."""
return async_dispatcher_connect(hass, SIGNAL_CLOUD_CONNECTION_STATE, target)
@bind_hass
@callback
def async_active_subscription(hass: HomeAssistant) -> bool:
@ -252,11 +275,22 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
Platform.TTS, DOMAIN, {}, config
)
async_dispatcher_send(
hass, SIGNAL_CLOUD_CONNECTION_STATE, CloudConnectionState.CLOUD_CONNECTED
)
async def _on_disconnect():
"""Handle cloud disconnect."""
async_dispatcher_send(
hass, SIGNAL_CLOUD_CONNECTION_STATE, CloudConnectionState.CLOUD_DISCONNECTED
)
async def _on_initialized():
"""Update preferences."""
await prefs.async_update(remote_domain=cloud.remote.instance_domain)
cloud.iot.register_on_connect(_on_connect)
cloud.iot.register_on_disconnect(_on_disconnect)
cloud.register_on_initialized(_on_initialized)
await cloud.initialize()

View File

@ -137,6 +137,14 @@ async def test_on_connect(hass, mock_cloud_fixture):
assert len(hass.states.async_entity_ids("binary_sensor")) == 0
cloud_states = []
def handle_state(cloud_state):
nonlocal cloud_states
cloud_states.append(cloud_state)
cloud.async_listen_connection_change(hass, handle_state)
assert "async_setup" in str(cl.iot._on_connect[-1])
await cl.iot._on_connect[-1]()
await hass.async_block_till_done()
@ -149,6 +157,17 @@ async def test_on_connect(hass, mock_cloud_fixture):
assert len(mock_load.mock_calls) == 0
assert len(cloud_states) == 1
assert cloud_states[-1] == cloud.CloudConnectionState.CLOUD_CONNECTED
assert len(cl.iot._on_disconnect) == 2
assert "async_setup" in str(cl.iot._on_disconnect[-1])
await cl.iot._on_disconnect[-1]()
await hass.async_block_till_done()
assert len(cloud_states) == 2
assert cloud_states[-1] == cloud.CloudConnectionState.CLOUD_DISCONNECTED
async def test_remote_ui_url(hass, mock_cloud_fixture):
"""Test getting remote ui url."""