mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Add Automate Pulse Hub v2 support (#39501)
Co-authored-by: Franck Nijhof <frenck@frenck.nl> Co-authored-by: Sillyfrog <sillyfrog@users.noreply.github.com>
This commit is contained in:
parent
f009b1442f
commit
d3e77e00e1
@ -75,6 +75,12 @@ omit =
|
||||
homeassistant/components/asuswrt/router.py
|
||||
homeassistant/components/aten_pe/*
|
||||
homeassistant/components/atome/*
|
||||
homeassistant/components/automate/__init__.py
|
||||
homeassistant/components/automate/base.py
|
||||
homeassistant/components/automate/const.py
|
||||
homeassistant/components/automate/cover.py
|
||||
homeassistant/components/automate/helpers.py
|
||||
homeassistant/components/automate/hub.py
|
||||
homeassistant/components/aurora/__init__.py
|
||||
homeassistant/components/aurora/binary_sensor.py
|
||||
homeassistant/components/aurora/const.py
|
||||
|
@ -56,6 +56,7 @@ homeassistant/components/august/* @bdraco
|
||||
homeassistant/components/aurora/* @djtimca
|
||||
homeassistant/components/aurora_abb_powerone/* @davet2001
|
||||
homeassistant/components/auth/* @home-assistant/core
|
||||
homeassistant/components/automate/* @sillyfrog
|
||||
homeassistant/components/automation/* @home-assistant/core
|
||||
homeassistant/components/avea/* @pattyland
|
||||
homeassistant/components/awair/* @ahayworth @danielsjf
|
||||
|
36
homeassistant/components/automate/__init__.py
Normal file
36
homeassistant/components/automate/__init__.py
Normal file
@ -0,0 +1,36 @@
|
||||
"""The Automate Pulse Hub v2 integration."""
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .const import DOMAIN
|
||||
from .hub import PulseHub
|
||||
|
||||
PLATFORMS = ["cover"]
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up Automate Pulse Hub v2 from a config entry."""
|
||||
hub = PulseHub(hass, entry)
|
||||
|
||||
if not await hub.async_setup():
|
||||
return False
|
||||
|
||||
hass.data.setdefault(DOMAIN, {})
|
||||
hass.data[DOMAIN][entry.entry_id] = hub
|
||||
|
||||
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
hub = hass.data[DOMAIN][entry.entry_id]
|
||||
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
if unload_ok:
|
||||
if not await hub.async_reset():
|
||||
return False
|
||||
hass.data[DOMAIN].pop(entry.entry_id)
|
||||
|
||||
return unload_ok
|
93
homeassistant/components/automate/base.py
Normal file
93
homeassistant/components/automate/base.py
Normal file
@ -0,0 +1,93 @@
|
||||
"""Base class for Automate Roller Blinds."""
|
||||
import logging
|
||||
|
||||
import aiopulse2
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers import entity
|
||||
from homeassistant.helpers.device_registry import async_get_registry as get_dev_reg
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_registry import async_get_registry as get_ent_reg
|
||||
|
||||
from .const import AUTOMATE_ENTITY_REMOVE, DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AutomateBase(entity.Entity):
|
||||
"""Base representation of an Automate roller."""
|
||||
|
||||
def __init__(self, roller: aiopulse2.Roller) -> None:
|
||||
"""Initialize the roller."""
|
||||
self.roller = roller
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return True if roller and hub is available."""
|
||||
return self.roller.online and self.roller.hub.connected
|
||||
|
||||
async def async_remove_and_unregister(self):
|
||||
"""Unregister from entity and device registry and call entity remove function."""
|
||||
_LOGGER.info("Removing %s %s", self.__class__.__name__, self.unique_id)
|
||||
|
||||
ent_registry = await get_ent_reg(self.hass)
|
||||
if self.entity_id in ent_registry.entities:
|
||||
ent_registry.async_remove(self.entity_id)
|
||||
|
||||
dev_registry = await get_dev_reg(self.hass)
|
||||
device = dev_registry.async_get_device(
|
||||
identifiers={(DOMAIN, self.unique_id)}, connections=set()
|
||||
)
|
||||
if device is not None:
|
||||
dev_registry.async_update_device(
|
||||
device.id, remove_config_entry_id=self.registry_entry.config_entry_id
|
||||
)
|
||||
|
||||
await self.async_remove()
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Entity has been added to hass."""
|
||||
self.roller.callback_subscribe(self.notify_update)
|
||||
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
AUTOMATE_ENTITY_REMOVE.format(self.roller.id),
|
||||
self.async_remove_and_unregister,
|
||||
)
|
||||
)
|
||||
|
||||
async def async_will_remove_from_hass(self):
|
||||
"""Entity being removed from hass."""
|
||||
self.roller.callback_unsubscribe(self.notify_update)
|
||||
|
||||
@callback
|
||||
def notify_update(self, roller: aiopulse2.Roller):
|
||||
"""Write updated device state information."""
|
||||
_LOGGER.debug(
|
||||
"Device update notification received: %s (%r)", roller.id, roller.name
|
||||
)
|
||||
self.async_write_ha_state()
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Report that Automate entities do not need polling."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return the unique ID of this roller."""
|
||||
return self.roller.id
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of roller."""
|
||||
return self.roller.name
|
||||
|
||||
@property
|
||||
def device_info(self):
|
||||
"""Return the device info."""
|
||||
attrs = {
|
||||
"identifiers": {(DOMAIN, self.roller.id)},
|
||||
}
|
||||
return attrs
|
37
homeassistant/components/automate/config_flow.py
Normal file
37
homeassistant/components/automate/config_flow.py
Normal file
@ -0,0 +1,37 @@
|
||||
"""Config flow for Automate Pulse Hub v2 integration."""
|
||||
import logging
|
||||
|
||||
import aiopulse2
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DATA_SCHEMA = vol.Schema({vol.Required("host"): str})
|
||||
|
||||
|
||||
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for Automate Pulse Hub v2."""
|
||||
|
||||
VERSION = 1
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Handle the initial step once we have info from the user."""
|
||||
if user_input is not None:
|
||||
try:
|
||||
hub = aiopulse2.Hub(user_input["host"])
|
||||
await hub.test()
|
||||
title = hub.name
|
||||
except Exception: # pylint: disable=broad-except
|
||||
return self.async_show_form(
|
||||
step_id="user",
|
||||
data_schema=DATA_SCHEMA,
|
||||
errors={"base": "cannot_connect"},
|
||||
)
|
||||
|
||||
return self.async_create_entry(title=title, data=user_input)
|
||||
|
||||
return self.async_show_form(step_id="user", data_schema=DATA_SCHEMA)
|
6
homeassistant/components/automate/const.py
Normal file
6
homeassistant/components/automate/const.py
Normal file
@ -0,0 +1,6 @@
|
||||
"""Constants for the Automate Pulse Hub v2 integration."""
|
||||
|
||||
DOMAIN = "automate"
|
||||
|
||||
AUTOMATE_HUB_UPDATE = "automate_hub_update_{}"
|
||||
AUTOMATE_ENTITY_REMOVE = "automate_entity_remove_{}"
|
147
homeassistant/components/automate/cover.py
Normal file
147
homeassistant/components/automate/cover.py
Normal file
@ -0,0 +1,147 @@
|
||||
"""Support for Automate Roller Blinds."""
|
||||
import aiopulse2
|
||||
|
||||
from homeassistant.components.cover import (
|
||||
ATTR_POSITION,
|
||||
DEVICE_CLASS_SHADE,
|
||||
SUPPORT_CLOSE,
|
||||
SUPPORT_CLOSE_TILT,
|
||||
SUPPORT_OPEN,
|
||||
SUPPORT_OPEN_TILT,
|
||||
SUPPORT_SET_POSITION,
|
||||
SUPPORT_SET_TILT_POSITION,
|
||||
SUPPORT_STOP,
|
||||
SUPPORT_STOP_TILT,
|
||||
CoverEntity,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
|
||||
from .base import AutomateBase
|
||||
from .const import AUTOMATE_HUB_UPDATE, DOMAIN
|
||||
from .helpers import async_add_automate_entities
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
"""Set up the Automate Rollers from a config entry."""
|
||||
hub = hass.data[DOMAIN][config_entry.entry_id]
|
||||
|
||||
current = set()
|
||||
|
||||
@callback
|
||||
def async_add_automate_covers():
|
||||
async_add_automate_entities(
|
||||
hass, AutomateCover, config_entry, current, async_add_entities
|
||||
)
|
||||
|
||||
hub.cleanup_callbacks.append(
|
||||
async_dispatcher_connect(
|
||||
hass,
|
||||
AUTOMATE_HUB_UPDATE.format(config_entry.entry_id),
|
||||
async_add_automate_covers,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class AutomateCover(AutomateBase, CoverEntity):
|
||||
"""Representation of a Automate cover device."""
|
||||
|
||||
@property
|
||||
def current_cover_position(self):
|
||||
"""Return the current position of the roller blind.
|
||||
|
||||
None is unknown, 0 is closed, 100 is fully open.
|
||||
"""
|
||||
position = None
|
||||
if self.roller.closed_percent is not None:
|
||||
position = 100 - self.roller.closed_percent
|
||||
return position
|
||||
|
||||
@property
|
||||
def current_cover_tilt_position(self):
|
||||
"""Return the current tilt of the roller blind.
|
||||
|
||||
None is unknown, 0 is closed, 100 is fully open.
|
||||
"""
|
||||
return None
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Flag supported features."""
|
||||
supported_features = 0
|
||||
if self.current_cover_position is not None:
|
||||
supported_features |= (
|
||||
SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_STOP | SUPPORT_SET_POSITION
|
||||
)
|
||||
if self.current_cover_tilt_position is not None:
|
||||
supported_features |= (
|
||||
SUPPORT_OPEN_TILT
|
||||
| SUPPORT_CLOSE_TILT
|
||||
| SUPPORT_STOP_TILT
|
||||
| SUPPORT_SET_TILT_POSITION
|
||||
)
|
||||
|
||||
return supported_features
|
||||
|
||||
@property
|
||||
def device_info(self):
|
||||
"""Return the device info."""
|
||||
attrs = super().device_info
|
||||
attrs["manufacturer"] = "Automate"
|
||||
attrs["model"] = self.roller.devicetype
|
||||
attrs["sw_version"] = self.roller.version
|
||||
attrs["via_device"] = (DOMAIN, self.roller.hub.id)
|
||||
attrs["name"] = self.name
|
||||
return attrs
|
||||
|
||||
@property
|
||||
def device_class(self):
|
||||
"""Class of the cover, a shade."""
|
||||
return DEVICE_CLASS_SHADE
|
||||
|
||||
@property
|
||||
def is_opening(self):
|
||||
"""Is cover opening/moving up."""
|
||||
return self.roller.action == aiopulse2.MovingAction.up
|
||||
|
||||
@property
|
||||
def is_closing(self):
|
||||
"""Is cover closing/moving down."""
|
||||
return self.roller.action == aiopulse2.MovingAction.down
|
||||
|
||||
@property
|
||||
def is_closed(self):
|
||||
"""Return if the cover is closed."""
|
||||
return self.roller.closed_percent == 100
|
||||
|
||||
async def async_close_cover(self, **kwargs):
|
||||
"""Close the roller."""
|
||||
await self.roller.move_down()
|
||||
|
||||
async def async_open_cover(self, **kwargs):
|
||||
"""Open the roller."""
|
||||
await self.roller.move_up()
|
||||
|
||||
async def async_stop_cover(self, **kwargs):
|
||||
"""Stop the roller."""
|
||||
await self.roller.move_stop()
|
||||
|
||||
async def async_set_cover_position(self, **kwargs):
|
||||
"""Move the roller shutter to a specific position."""
|
||||
await self.roller.move_to(100 - kwargs[ATTR_POSITION])
|
||||
|
||||
async def async_close_cover_tilt(self, **kwargs):
|
||||
"""Close the roller."""
|
||||
await self.roller.move_down()
|
||||
|
||||
async def async_open_cover_tilt(self, **kwargs):
|
||||
"""Open the roller."""
|
||||
await self.roller.move_up()
|
||||
|
||||
async def async_stop_cover_tilt(self, **kwargs):
|
||||
"""Stop the roller."""
|
||||
await self.roller.move_stop()
|
||||
|
||||
async def async_set_cover_tilt(self, **kwargs):
|
||||
"""Tilt the roller shutter to a specific position."""
|
||||
await self.roller.move_to(100 - kwargs[ATTR_POSITION])
|
46
homeassistant/components/automate/helpers.py
Normal file
46
homeassistant/components/automate/helpers.py
Normal file
@ -0,0 +1,46 @@
|
||||
"""Helper functions for Automate Pulse."""
|
||||
import logging
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.device_registry import async_get_registry as get_dev_reg
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@callback
|
||||
def async_add_automate_entities(
|
||||
hass, entity_class, config_entry, current, async_add_entities
|
||||
):
|
||||
"""Add any new entities."""
|
||||
hub = hass.data[DOMAIN][config_entry.entry_id]
|
||||
_LOGGER.debug("Looking for new %s on: %s", entity_class.__name__, hub.host)
|
||||
|
||||
api = hub.api.rollers
|
||||
|
||||
new_items = []
|
||||
for unique_id, roller in api.items():
|
||||
if unique_id not in current:
|
||||
_LOGGER.debug("New %s %s", entity_class.__name__, unique_id)
|
||||
new_item = entity_class(roller)
|
||||
current.add(unique_id)
|
||||
new_items.append(new_item)
|
||||
|
||||
async_add_entities(new_items)
|
||||
|
||||
|
||||
async def update_devices(hass, config_entry, api):
|
||||
"""Tell hass that device info has been updated."""
|
||||
dev_registry = await get_dev_reg(hass)
|
||||
|
||||
for api_item in api.values():
|
||||
# Update Device name
|
||||
device = dev_registry.async_get_device(
|
||||
identifiers={(DOMAIN, api_item.id)}, connections=set()
|
||||
)
|
||||
if device is not None:
|
||||
dev_registry.async_update_device(
|
||||
device.id,
|
||||
name=api_item.name,
|
||||
)
|
89
homeassistant/components/automate/hub.py
Normal file
89
homeassistant/components/automate/hub.py
Normal file
@ -0,0 +1,89 @@
|
||||
"""Code to handle a Pulse Hub."""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
import aiopulse2
|
||||
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
|
||||
from .const import AUTOMATE_ENTITY_REMOVE, AUTOMATE_HUB_UPDATE
|
||||
from .helpers import update_devices
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PulseHub:
|
||||
"""Manages a single Pulse Hub."""
|
||||
|
||||
def __init__(self, hass, config_entry):
|
||||
"""Initialize the system."""
|
||||
self.config_entry = config_entry
|
||||
self.hass = hass
|
||||
self.api: aiopulse2.Hub | None = None
|
||||
self.tasks = []
|
||||
self.current_rollers = {}
|
||||
self.cleanup_callbacks = []
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
"""Return the title of the hub shown in the integrations list."""
|
||||
return f"{self.api.name} ({self.api.host})"
|
||||
|
||||
@property
|
||||
def host(self):
|
||||
"""Return the host of this hub."""
|
||||
return self.config_entry.data["host"]
|
||||
|
||||
async def async_setup(self):
|
||||
"""Set up a hub based on host parameter."""
|
||||
host = self.host
|
||||
|
||||
hub = aiopulse2.Hub(host, propagate_callbacks=True)
|
||||
|
||||
self.api = hub
|
||||
|
||||
hub.callback_subscribe(self.async_notify_update)
|
||||
self.tasks.append(asyncio.create_task(hub.run()))
|
||||
|
||||
_LOGGER.debug("Hub setup complete")
|
||||
return True
|
||||
|
||||
async def async_reset(self):
|
||||
"""Reset this hub to default state."""
|
||||
for cleanup_callback in self.cleanup_callbacks:
|
||||
cleanup_callback()
|
||||
|
||||
# If not setup
|
||||
if self.api is None:
|
||||
return False
|
||||
|
||||
self.api.callback_unsubscribe(self.async_notify_update)
|
||||
await self.api.stop()
|
||||
del self.api
|
||||
self.api = None
|
||||
|
||||
# Wait for any running tasks to complete
|
||||
await asyncio.wait(self.tasks)
|
||||
|
||||
return True
|
||||
|
||||
async def async_notify_update(self, hub=None):
|
||||
"""Evaluate entities when hub reports that update has occurred."""
|
||||
_LOGGER.debug("Hub {self.title} updated")
|
||||
|
||||
await update_devices(self.hass, self.config_entry, self.api.rollers)
|
||||
self.hass.config_entries.async_update_entry(self.config_entry, title=self.title)
|
||||
|
||||
async_dispatcher_send(
|
||||
self.hass, AUTOMATE_HUB_UPDATE.format(self.config_entry.entry_id)
|
||||
)
|
||||
|
||||
for unique_id in list(self.current_rollers):
|
||||
if unique_id not in self.api.rollers:
|
||||
_LOGGER.debug("Notifying remove of %s", unique_id)
|
||||
self.current_rollers.pop(unique_id)
|
||||
async_dispatcher_send(
|
||||
self.hass, AUTOMATE_ENTITY_REMOVE.format(unique_id)
|
||||
)
|
13
homeassistant/components/automate/manifest.json
Normal file
13
homeassistant/components/automate/manifest.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"domain": "automate",
|
||||
"name": "Automate Pulse Hub v2",
|
||||
"config_flow": true,
|
||||
"iot_class": "local_push",
|
||||
"documentation": "https://www.home-assistant.io/integrations/automate",
|
||||
"requirements": [
|
||||
"aiopulse2==0.6.0"
|
||||
],
|
||||
"codeowners": [
|
||||
"@sillyfrog"
|
||||
]
|
||||
}
|
19
homeassistant/components/automate/strings.json
Normal file
19
homeassistant/components/automate/strings.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"host": "[%key:common::config_flow::data::host%]"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||
}
|
||||
}
|
||||
}
|
19
homeassistant/components/automate/translations/en.json
Normal file
19
homeassistant/components/automate/translations/en.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Device is already configured"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Failed to connect",
|
||||
"invalid_auth": "Invalid authentication",
|
||||
"unknown": "Unexpected error"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"host": "Host"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -28,6 +28,7 @@ FLOWS = [
|
||||
"atag",
|
||||
"august",
|
||||
"aurora",
|
||||
"automate",
|
||||
"awair",
|
||||
"axis",
|
||||
"azure_devops",
|
||||
|
@ -220,6 +220,9 @@ aionotify==0.2.0
|
||||
# homeassistant.components.notion
|
||||
aionotion==1.1.0
|
||||
|
||||
# homeassistant.components.automate
|
||||
aiopulse2==0.6.0
|
||||
|
||||
# homeassistant.components.acmeda
|
||||
aiopulse==0.4.2
|
||||
|
||||
|
@ -142,6 +142,9 @@ aiomusiccast==0.8.0
|
||||
# homeassistant.components.notion
|
||||
aionotion==1.1.0
|
||||
|
||||
# homeassistant.components.automate
|
||||
aiopulse2==0.6.0
|
||||
|
||||
# homeassistant.components.acmeda
|
||||
aiopulse==0.4.2
|
||||
|
||||
|
1
tests/components/automate/__init__.py
Normal file
1
tests/components/automate/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""Tests for the Automate Pulse Hub v2 integration."""
|
69
tests/components/automate/test_config_flow.py
Normal file
69
tests/components/automate/test_config_flow.py
Normal file
@ -0,0 +1,69 @@
|
||||
"""Test the Automate Pulse Hub v2 config flow."""
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from homeassistant import config_entries, setup
|
||||
from homeassistant.components.automate.const import DOMAIN
|
||||
|
||||
|
||||
def mock_hub(testfunc=None):
|
||||
"""Mock aiopulse2.Hub."""
|
||||
Hub = Mock()
|
||||
Hub.name = "Name of the device"
|
||||
|
||||
async def hub_test():
|
||||
if testfunc:
|
||||
testfunc()
|
||||
|
||||
Hub.test = hub_test
|
||||
|
||||
return Hub
|
||||
|
||||
|
||||
async def test_form(hass):
|
||||
"""Test we get the form."""
|
||||
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
assert result["errors"] is None
|
||||
|
||||
with patch("aiopulse2.Hub", return_value=mock_hub()), patch(
|
||||
"homeassistant.components.automate.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry:
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
"host": "1.1.1.1",
|
||||
},
|
||||
)
|
||||
|
||||
assert result2["type"] == "create_entry"
|
||||
assert result2["title"] == "Name of the device"
|
||||
assert result2["data"] == {
|
||||
"host": "1.1.1.1",
|
||||
}
|
||||
await hass.async_block_till_done()
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_form_cannot_connect(hass):
|
||||
"""Test we handle cannot connect error."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
def raise_error():
|
||||
raise ConnectionRefusedError
|
||||
|
||||
with patch("aiopulse2.Hub", return_value=mock_hub(raise_error)):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
"host": "1.1.1.1",
|
||||
},
|
||||
)
|
||||
|
||||
assert result2["type"] == "form"
|
||||
assert result2["errors"] == {"base": "cannot_connect"}
|
Loading…
x
Reference in New Issue
Block a user