mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 08:47:57 +00:00
Add KMTronic Integration (#41682)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
5cd022a683
commit
5c29adea3d
@ -243,6 +243,7 @@ homeassistant/components/keba/* @dannerph
|
||||
homeassistant/components/keenetic_ndms2/* @foxel
|
||||
homeassistant/components/kef/* @basnijholt
|
||||
homeassistant/components/keyboard_remote/* @bendavid
|
||||
homeassistant/components/kmtronic/* @dgomes
|
||||
homeassistant/components/knx/* @Julius2342 @farmio @marvin-w
|
||||
homeassistant/components/kodi/* @OnFreund @cgtobi
|
||||
homeassistant/components/konnected/* @heythisisnate @kit-klein
|
||||
|
104
homeassistant/components/kmtronic/__init__.py
Normal file
104
homeassistant/components/kmtronic/__init__.py
Normal file
@ -0,0 +1,104 @@
|
||||
"""The kmtronic integration."""
|
||||
import asyncio
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
import aiohttp
|
||||
import async_timeout
|
||||
from pykmtronic.auth import Auth
|
||||
from pykmtronic.hub import KMTronicHubAPI
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry, ConfigEntryNotReady
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import aiohttp_client
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
from .const import (
|
||||
CONF_HOSTNAME,
|
||||
CONF_PASSWORD,
|
||||
CONF_USERNAME,
|
||||
DATA_COORDINATOR,
|
||||
DATA_HOST,
|
||||
DATA_HUB,
|
||||
DOMAIN,
|
||||
MANUFACTURER,
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({DOMAIN: vol.Schema({})}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
PLATFORMS = ["switch"]
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: dict):
|
||||
"""Set up the kmtronic component."""
|
||||
hass.data[DOMAIN] = {}
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||
"""Set up kmtronic from a config entry."""
|
||||
|
||||
session = aiohttp_client.async_get_clientsession(hass)
|
||||
auth = Auth(
|
||||
session,
|
||||
f"http://{entry.data[CONF_HOSTNAME]}",
|
||||
entry.data[CONF_USERNAME],
|
||||
entry.data[CONF_PASSWORD],
|
||||
)
|
||||
hub = KMTronicHubAPI(auth)
|
||||
|
||||
async def async_update_data():
|
||||
try:
|
||||
async with async_timeout.timeout(10):
|
||||
await hub.async_update_relays()
|
||||
except aiohttp.client_exceptions.ClientResponseError as err:
|
||||
raise UpdateFailed(f"Wrong credentials: {err}") from err
|
||||
except (
|
||||
asyncio.TimeoutError,
|
||||
aiohttp.client_exceptions.ClientConnectorError,
|
||||
) as err:
|
||||
raise UpdateFailed(f"Error communicating with API: {err}") from err
|
||||
|
||||
coordinator = DataUpdateCoordinator(
|
||||
hass,
|
||||
_LOGGER,
|
||||
name=f"{MANUFACTURER} {hub.name}",
|
||||
update_method=async_update_data,
|
||||
update_interval=timedelta(seconds=30),
|
||||
)
|
||||
await coordinator.async_refresh()
|
||||
if not coordinator.last_update_success:
|
||||
raise ConfigEntryNotReady
|
||||
|
||||
hass.data[DOMAIN][entry.entry_id] = {
|
||||
DATA_HUB: hub,
|
||||
DATA_HOST: entry.data[DATA_HOST],
|
||||
DATA_COORDINATOR: coordinator,
|
||||
}
|
||||
|
||||
for component in PLATFORMS:
|
||||
hass.async_create_task(
|
||||
hass.config_entries.async_forward_entry_setup(entry, component)
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||
"""Unload a config entry."""
|
||||
unload_ok = all(
|
||||
await asyncio.gather(
|
||||
*[
|
||||
hass.config_entries.async_forward_entry_unload(entry, component)
|
||||
for component in PLATFORMS
|
||||
]
|
||||
)
|
||||
)
|
||||
if unload_ok:
|
||||
hass.data[DOMAIN].pop(entry.entry_id)
|
||||
|
||||
return unload_ok
|
74
homeassistant/components/kmtronic/config_flow.py
Normal file
74
homeassistant/components/kmtronic/config_flow.py
Normal file
@ -0,0 +1,74 @@
|
||||
"""Config flow for kmtronic integration."""
|
||||
import logging
|
||||
|
||||
import aiohttp
|
||||
from pykmtronic.auth import Auth
|
||||
from pykmtronic.hub import KMTronicHubAPI
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries, core, exceptions
|
||||
from homeassistant.helpers import aiohttp_client
|
||||
|
||||
from .const import CONF_HOSTNAME, CONF_PASSWORD, CONF_USERNAME
|
||||
from .const import DOMAIN # pylint:disable=unused-import
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DATA_SCHEMA = vol.Schema({CONF_HOSTNAME: str, CONF_USERNAME: str, CONF_PASSWORD: str})
|
||||
|
||||
|
||||
async def validate_input(hass: core.HomeAssistant, data):
|
||||
"""Validate the user input allows us to connect."""
|
||||
|
||||
session = aiohttp_client.async_get_clientsession(hass)
|
||||
auth = Auth(
|
||||
session,
|
||||
f"http://{data[CONF_HOSTNAME]}",
|
||||
data[CONF_USERNAME],
|
||||
data[CONF_PASSWORD],
|
||||
)
|
||||
hub = KMTronicHubAPI(auth)
|
||||
|
||||
try:
|
||||
await hub.async_get_status()
|
||||
except aiohttp.client_exceptions.ClientResponseError as err:
|
||||
raise InvalidAuth from err
|
||||
except aiohttp.client_exceptions.ClientConnectorError as err:
|
||||
raise CannotConnect from err
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for kmtronic."""
|
||||
|
||||
VERSION = 1
|
||||
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Handle the initial step."""
|
||||
errors = {}
|
||||
if user_input is not None:
|
||||
try:
|
||||
info = await validate_input(self.hass, user_input)
|
||||
|
||||
return self.async_create_entry(title=info["host"], data=user_input)
|
||||
except CannotConnect:
|
||||
errors["base"] = "cannot_connect"
|
||||
except InvalidAuth:
|
||||
errors["base"] = "invalid_auth"
|
||||
except Exception: # pylint: disable=broad-except
|
||||
_LOGGER.exception("Unexpected exception")
|
||||
errors["base"] = "unknown"
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="user", data_schema=DATA_SCHEMA, errors=errors
|
||||
)
|
||||
|
||||
|
||||
class CannotConnect(exceptions.HomeAssistantError):
|
||||
"""Error to indicate we cannot connect."""
|
||||
|
||||
|
||||
class InvalidAuth(exceptions.HomeAssistantError):
|
||||
"""Error to indicate there is invalid auth."""
|
16
homeassistant/components/kmtronic/const.py
Normal file
16
homeassistant/components/kmtronic/const.py
Normal file
@ -0,0 +1,16 @@
|
||||
"""Constants for the kmtronic integration."""
|
||||
|
||||
DOMAIN = "kmtronic"
|
||||
|
||||
CONF_HOSTNAME = "host"
|
||||
CONF_USERNAME = "username"
|
||||
CONF_PASSWORD = "password"
|
||||
|
||||
DATA_HUB = "hub"
|
||||
DATA_HOST = "host"
|
||||
DATA_COORDINATOR = "coordinator"
|
||||
|
||||
MANUFACTURER = "KMtronic"
|
||||
ATTR_MANUFACTURER = "manufacturer"
|
||||
ATTR_IDENTIFIERS = "identifiers"
|
||||
ATTR_NAME = "name"
|
8
homeassistant/components/kmtronic/manifest.json
Normal file
8
homeassistant/components/kmtronic/manifest.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"domain": "kmtronic",
|
||||
"name": "KMtronic",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/kmtronic",
|
||||
"requirements": ["pykmtronic==0.0.3"],
|
||||
"codeowners": ["@dgomes"]
|
||||
}
|
21
homeassistant/components/kmtronic/strings.json
Normal file
21
homeassistant/components/kmtronic/strings.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"host": "[%key:common::config_flow::data::host%]",
|
||||
"username": "[%key:common::config_flow::data::username%]",
|
||||
"password": "[%key:common::config_flow::data::password%]"
|
||||
}
|
||||
}
|
||||
},
|
||||
"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%]"
|
||||
}
|
||||
}
|
||||
}
|
67
homeassistant/components/kmtronic/switch.py
Normal file
67
homeassistant/components/kmtronic/switch.py
Normal file
@ -0,0 +1,67 @@
|
||||
"""KMtronic Switch integration."""
|
||||
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from .const import DATA_COORDINATOR, DATA_HOST, DATA_HUB, DOMAIN
|
||||
|
||||
|
||||
async def async_setup_entry(hass, entry, async_add_entities):
|
||||
"""Config entry example."""
|
||||
coordinator = hass.data[DOMAIN][entry.entry_id][DATA_COORDINATOR]
|
||||
hub = hass.data[DOMAIN][entry.entry_id][DATA_HUB]
|
||||
host = hass.data[DOMAIN][entry.entry_id][DATA_HOST]
|
||||
await hub.async_get_relays()
|
||||
|
||||
async_add_entities(
|
||||
[
|
||||
KMtronicSwitch(coordinator, host, relay, entry.unique_id)
|
||||
for relay in hub.relays
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class KMtronicSwitch(CoordinatorEntity, SwitchEntity):
|
||||
"""KMtronic Switch Entity."""
|
||||
|
||||
def __init__(self, coordinator, host, relay, config_entry_id):
|
||||
"""Pass coordinator to CoordinatorEntity."""
|
||||
super().__init__(coordinator)
|
||||
self._host = host
|
||||
self._relay = relay
|
||||
self._config_entry_id = config_entry_id
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return whether the entity is available."""
|
||||
return self.coordinator.last_update_success
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of the entity."""
|
||||
return f"Relay{self._relay.id}"
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return the unique ID of the entity."""
|
||||
return f"{self._config_entry_id}_relay{self._relay.id}"
|
||||
|
||||
@property
|
||||
def entity_registry_enabled_default(self) -> bool:
|
||||
"""Return if the entity should be enabled when first added to the entity registry."""
|
||||
return True
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return entity state."""
|
||||
return self._relay.is_on
|
||||
|
||||
async def async_turn_on(self, **kwargs) -> None:
|
||||
"""Turn the switch on."""
|
||||
await self._relay.turn_on()
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_turn_off(self, **kwargs) -> None:
|
||||
"""Turn the switch off."""
|
||||
await self._relay.turn_off()
|
||||
self.async_write_ha_state()
|
@ -115,6 +115,7 @@ FLOWS = [
|
||||
"izone",
|
||||
"juicenet",
|
||||
"keenetic_ndms2",
|
||||
"kmtronic",
|
||||
"kodi",
|
||||
"konnected",
|
||||
"kulersky",
|
||||
|
@ -1473,6 +1473,9 @@ pyitachip2ir==0.0.7
|
||||
# homeassistant.components.kira
|
||||
pykira==0.1.1
|
||||
|
||||
# homeassistant.components.kmtronic
|
||||
pykmtronic==0.0.3
|
||||
|
||||
# homeassistant.components.kodi
|
||||
pykodi==0.2.1
|
||||
|
||||
|
@ -775,6 +775,9 @@ pyisy==2.1.0
|
||||
# homeassistant.components.kira
|
||||
pykira==0.1.1
|
||||
|
||||
# homeassistant.components.kmtronic
|
||||
pykmtronic==0.0.3
|
||||
|
||||
# homeassistant.components.kodi
|
||||
pykodi==0.2.1
|
||||
|
||||
|
1
tests/components/kmtronic/__init__.py
Normal file
1
tests/components/kmtronic/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""Tests for the kmtronic integration."""
|
145
tests/components/kmtronic/test_config_flow.py
Normal file
145
tests/components/kmtronic/test_config_flow.py
Normal file
@ -0,0 +1,145 @@
|
||||
"""Test the kmtronic config flow."""
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from aiohttp import ClientConnectorError, ClientResponseError
|
||||
|
||||
from homeassistant import config_entries, setup
|
||||
from homeassistant.components.kmtronic.const import DOMAIN
|
||||
from homeassistant.config_entries import ENTRY_STATE_LOADED, ENTRY_STATE_NOT_LOADED
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
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"] == {}
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.kmtronic.config_flow.KMTronicHubAPI.async_get_status",
|
||||
return_value=[Mock()],
|
||||
), patch(
|
||||
"homeassistant.components.kmtronic.async_setup", return_value=True
|
||||
) as mock_setup, patch(
|
||||
"homeassistant.components.kmtronic.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",
|
||||
"username": "test-username",
|
||||
"password": "test-password",
|
||||
},
|
||||
)
|
||||
|
||||
assert result2["type"] == "create_entry"
|
||||
assert result2["title"] == "1.1.1.1"
|
||||
assert result2["data"] == {
|
||||
"host": "1.1.1.1",
|
||||
"username": "test-username",
|
||||
"password": "test-password",
|
||||
}
|
||||
await hass.async_block_till_done()
|
||||
assert len(mock_setup.mock_calls) == 1
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_form_invalid_auth(hass):
|
||||
"""Test we handle invalid auth."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.kmtronic.config_flow.KMTronicHubAPI.async_get_status",
|
||||
side_effect=ClientResponseError(None, None, status=401),
|
||||
):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
"host": "1.1.1.1",
|
||||
"username": "test-username",
|
||||
"password": "test-password",
|
||||
},
|
||||
)
|
||||
|
||||
assert result2["type"] == "form"
|
||||
assert result2["errors"] == {"base": "invalid_auth"}
|
||||
|
||||
|
||||
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}
|
||||
)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.kmtronic.config_flow.KMTronicHubAPI.async_get_status",
|
||||
side_effect=ClientConnectorError(None, Mock()),
|
||||
):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
"host": "1.1.1.1",
|
||||
"username": "test-username",
|
||||
"password": "test-password",
|
||||
},
|
||||
)
|
||||
|
||||
assert result2["type"] == "form"
|
||||
assert result2["errors"] == {"base": "cannot_connect"}
|
||||
|
||||
|
||||
async def test_form_unknown_error(hass):
|
||||
"""Test we handle unknown errors."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.kmtronic.config_flow.KMTronicHubAPI.async_get_status",
|
||||
side_effect=Exception(),
|
||||
):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
"host": "1.1.1.1",
|
||||
"username": "test-username",
|
||||
"password": "test-password",
|
||||
},
|
||||
)
|
||||
|
||||
assert result2["type"] == "form"
|
||||
assert result2["errors"] == {"base": "unknown"}
|
||||
|
||||
|
||||
async def test_unload_config_entry(hass, aioclient_mock):
|
||||
"""Test entry unloading."""
|
||||
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={"host": "1.1.1.1", "username": "admin", "password": "admin"},
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
aioclient_mock.get(
|
||||
"http://1.1.1.1/status.xml",
|
||||
text="<response><relay0>0</relay0><relay1>0</relay1></response>",
|
||||
)
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
config_entries = hass.config_entries.async_entries(DOMAIN)
|
||||
assert len(config_entries) == 1
|
||||
assert config_entries[0] is config_entry
|
||||
assert config_entry.state == ENTRY_STATE_LOADED
|
||||
|
||||
await hass.config_entries.async_unload(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert config_entry.state == ENTRY_STATE_NOT_LOADED
|
150
tests/components/kmtronic/test_switch.py
Normal file
150
tests/components/kmtronic/test_switch.py
Normal file
@ -0,0 +1,150 @@
|
||||
"""The tests for the KMtronic switch platform."""
|
||||
import asyncio
|
||||
from datetime import timedelta
|
||||
|
||||
from homeassistant.components.kmtronic.const import DOMAIN
|
||||
from homeassistant.config_entries import ENTRY_STATE_SETUP_RETRY
|
||||
from homeassistant.const import STATE_UNAVAILABLE
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||
|
||||
|
||||
async def test_relay_on_off(hass, aioclient_mock):
|
||||
"""Tests the relay turns on correctly."""
|
||||
|
||||
aioclient_mock.get(
|
||||
"http://1.1.1.1/status.xml",
|
||||
text="<response><relay0>0</relay0><relay1>0</relay1></response>",
|
||||
)
|
||||
|
||||
MockConfigEntry(
|
||||
domain=DOMAIN, data={"host": "1.1.1.1", "username": "foo", "password": "bar"}
|
||||
).add_to_hass(hass)
|
||||
assert await async_setup_component(hass, DOMAIN, {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Mocks the response for turning a relay1 on
|
||||
aioclient_mock.get(
|
||||
"http://1.1.1.1/FF0101",
|
||||
text="",
|
||||
)
|
||||
|
||||
state = hass.states.get("switch.relay1")
|
||||
assert state.state == "off"
|
||||
|
||||
await hass.services.async_call(
|
||||
"switch", "turn_on", {"entity_id": "switch.relay1"}, blocking=True
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("switch.relay1")
|
||||
assert state.state == "on"
|
||||
|
||||
# Mocks the response for turning a relay1 off
|
||||
aioclient_mock.get(
|
||||
"http://1.1.1.1/FF0100",
|
||||
text="",
|
||||
)
|
||||
|
||||
await hass.services.async_call(
|
||||
"switch", "turn_off", {"entity_id": "switch.relay1"}, blocking=True
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("switch.relay1")
|
||||
assert state.state == "off"
|
||||
|
||||
|
||||
async def test_update(hass, aioclient_mock):
|
||||
"""Tests switch refreshes status periodically."""
|
||||
now = dt_util.utcnow()
|
||||
future = now + timedelta(minutes=10)
|
||||
|
||||
aioclient_mock.get(
|
||||
"http://1.1.1.1/status.xml",
|
||||
text="<response><relay0>0</relay0><relay1>0</relay1></response>",
|
||||
)
|
||||
|
||||
MockConfigEntry(
|
||||
domain=DOMAIN, data={"host": "1.1.1.1", "username": "foo", "password": "bar"}
|
||||
).add_to_hass(hass)
|
||||
assert await async_setup_component(hass, DOMAIN, {})
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("switch.relay1")
|
||||
assert state.state == "off"
|
||||
|
||||
aioclient_mock.clear_requests()
|
||||
aioclient_mock.get(
|
||||
"http://1.1.1.1/status.xml",
|
||||
text="<response><relay0>1</relay0><relay1>1</relay1></response>",
|
||||
)
|
||||
async_fire_time_changed(hass, future)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("switch.relay1")
|
||||
assert state.state == "on"
|
||||
|
||||
|
||||
async def test_config_entry_not_ready(hass, aioclient_mock):
|
||||
"""Tests configuration entry not ready."""
|
||||
|
||||
aioclient_mock.get(
|
||||
"http://1.1.1.1/status.xml",
|
||||
exc=asyncio.TimeoutError(),
|
||||
)
|
||||
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data={"host": "1.1.1.1", "username": "foo", "password": "bar"}
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert config_entry.state == ENTRY_STATE_SETUP_RETRY
|
||||
|
||||
|
||||
async def test_failed_update(hass, aioclient_mock):
|
||||
"""Tests coordinator update fails."""
|
||||
now = dt_util.utcnow()
|
||||
future = now + timedelta(minutes=10)
|
||||
|
||||
aioclient_mock.get(
|
||||
"http://1.1.1.1/status.xml",
|
||||
text="<response><relay0>0</relay0><relay1>0</relay1></response>",
|
||||
)
|
||||
|
||||
MockConfigEntry(
|
||||
domain=DOMAIN, data={"host": "1.1.1.1", "username": "foo", "password": "bar"}
|
||||
).add_to_hass(hass)
|
||||
assert await async_setup_component(hass, DOMAIN, {})
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("switch.relay1")
|
||||
assert state.state == "off"
|
||||
|
||||
aioclient_mock.clear_requests()
|
||||
aioclient_mock.get(
|
||||
"http://1.1.1.1/status.xml",
|
||||
text="401 Unauthorized: Password required",
|
||||
status=401,
|
||||
)
|
||||
async_fire_time_changed(hass, future)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("switch.relay1")
|
||||
assert state.state == STATE_UNAVAILABLE
|
||||
|
||||
future += timedelta(minutes=10)
|
||||
aioclient_mock.clear_requests()
|
||||
aioclient_mock.get(
|
||||
"http://1.1.1.1/status.xml",
|
||||
exc=asyncio.TimeoutError(),
|
||||
)
|
||||
async_fire_time_changed(hass, future)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("switch.relay1")
|
||||
assert state.state == STATE_UNAVAILABLE
|
Loading…
x
Reference in New Issue
Block a user