mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 17:27:52 +00:00
Add config flow to venstar (#58152)
This commit is contained in:
parent
2d6fa5c453
commit
dad5d19a35
@ -1168,6 +1168,7 @@ omit =
|
||||
homeassistant/components/velbus/sensor.py
|
||||
homeassistant/components/velbus/switch.py
|
||||
homeassistant/components/velux/*
|
||||
homeassistant/components/venstar/__init__.py
|
||||
homeassistant/components/venstar/climate.py
|
||||
homeassistant/components/verisure/__init__.py
|
||||
homeassistant/components/verisure/alarm_control_panel.py
|
||||
|
@ -563,6 +563,7 @@ homeassistant/components/utility_meter/* @dgomes
|
||||
homeassistant/components/vallox/* @andre-richter
|
||||
homeassistant/components/velbus/* @Cereal2nd @brefra
|
||||
homeassistant/components/velux/* @Julius2342
|
||||
homeassistant/components/venstar/* @garbled1
|
||||
homeassistant/components/vera/* @pavoni
|
||||
homeassistant/components/verisure/* @frenck
|
||||
homeassistant/components/versasense/* @flamm3blemuff1n
|
||||
|
@ -1 +1,109 @@
|
||||
"""The venstar component."""
|
||||
import asyncio
|
||||
|
||||
from requests import RequestException
|
||||
from venstarcolortouch import VenstarColorTouch
|
||||
|
||||
from homeassistant.const import (
|
||||
CONF_HOST,
|
||||
CONF_PASSWORD,
|
||||
CONF_PIN,
|
||||
CONF_SSL,
|
||||
CONF_USERNAME,
|
||||
)
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from .const import _LOGGER, DOMAIN, VENSTAR_TIMEOUT
|
||||
|
||||
PLATFORMS = ["climate"]
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config):
|
||||
"""Set up the Venstar thermostat."""
|
||||
username = config.data.get(CONF_USERNAME)
|
||||
password = config.data.get(CONF_PASSWORD)
|
||||
pin = config.data.get(CONF_PIN)
|
||||
host = config.data[CONF_HOST]
|
||||
timeout = VENSTAR_TIMEOUT
|
||||
protocol = "https" if config.data[CONF_SSL] else "http"
|
||||
|
||||
client = VenstarColorTouch(
|
||||
addr=host,
|
||||
timeout=timeout,
|
||||
user=username,
|
||||
password=password,
|
||||
pin=pin,
|
||||
proto=protocol,
|
||||
)
|
||||
|
||||
try:
|
||||
await hass.async_add_executor_job(client.update_info)
|
||||
except (OSError, RequestException) as ex:
|
||||
raise ConfigEntryNotReady(f"Unable to connect to the thermostat: {ex}") from ex
|
||||
hass.data.setdefault(DOMAIN, {})[config.entry_id] = client
|
||||
hass.config_entries.async_setup_platforms(config, PLATFORMS)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass, config):
|
||||
"""Unload the config config and platforms."""
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(config, PLATFORMS)
|
||||
if unload_ok:
|
||||
hass.data[DOMAIN].pop(config.entry_id)
|
||||
return unload_ok
|
||||
|
||||
|
||||
class VenstarEntity(Entity):
|
||||
"""Get the latest data and update."""
|
||||
|
||||
def __init__(self, config, client):
|
||||
"""Initialize the data object."""
|
||||
self._config = config
|
||||
self._client = client
|
||||
|
||||
async def async_update(self):
|
||||
"""Update the state."""
|
||||
try:
|
||||
info_success = await self.hass.async_add_executor_job(
|
||||
self._client.update_info
|
||||
)
|
||||
except (OSError, RequestException) as ex:
|
||||
_LOGGER.error("Exception during info update: %s", ex)
|
||||
|
||||
# older venstars sometimes cannot handle rapid sequential connections
|
||||
await asyncio.sleep(3)
|
||||
|
||||
try:
|
||||
sensor_success = await self.hass.async_add_executor_job(
|
||||
self._client.update_sensors
|
||||
)
|
||||
except (OSError, RequestException) as ex:
|
||||
_LOGGER.error("Exception during sensor update: %s", ex)
|
||||
|
||||
if not info_success or not sensor_success:
|
||||
_LOGGER.error("Failed to update data")
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the thermostat."""
|
||||
return self._client.name
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Set unique_id for this entity."""
|
||||
return f"{self._config.entry_id}"
|
||||
|
||||
@property
|
||||
def device_info(self):
|
||||
"""Return the device information for this entity."""
|
||||
return {
|
||||
"identifiers": {(DOMAIN, self._config.entry_id)},
|
||||
"name": self._client.name,
|
||||
"manufacturer": "Venstar",
|
||||
# pylint: disable=protected-access
|
||||
"model": f"{self._client.model}-{self._client._type}",
|
||||
# pylint: disable=protected-access
|
||||
"sw_version": self._client._api_ver,
|
||||
}
|
||||
|
@ -1,7 +1,4 @@
|
||||
"""Support for Venstar WiFi Thermostats."""
|
||||
import logging
|
||||
|
||||
from venstarcolortouch import VenstarColorTouch
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.climate import PLATFORM_SCHEMA, ClimateEntity
|
||||
@ -27,6 +24,7 @@ from homeassistant.components.climate.const import (
|
||||
SUPPORT_TARGET_TEMPERATURE,
|
||||
SUPPORT_TARGET_TEMPERATURE_RANGE,
|
||||
)
|
||||
from homeassistant.config_entries import SOURCE_IMPORT
|
||||
from homeassistant.const import (
|
||||
ATTR_TEMPERATURE,
|
||||
CONF_HOST,
|
||||
@ -42,20 +40,18 @@ from homeassistant.const import (
|
||||
)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ATTR_FAN_STATE = "fan_state"
|
||||
ATTR_HVAC_STATE = "hvac_mode"
|
||||
|
||||
CONF_HUMIDIFIER = "humidifier"
|
||||
|
||||
DEFAULT_SSL = False
|
||||
|
||||
VALID_FAN_STATES = [STATE_ON, HVAC_MODE_AUTO]
|
||||
VALID_THERMOSTAT_MODES = [HVAC_MODE_HEAT, HVAC_MODE_COOL, HVAC_MODE_OFF, HVAC_MODE_AUTO]
|
||||
|
||||
HOLD_MODE_OFF = "off"
|
||||
HOLD_MODE_TEMPERATURE = "temperature"
|
||||
from . import VenstarEntity
|
||||
from .const import (
|
||||
_LOGGER,
|
||||
ATTR_FAN_STATE,
|
||||
ATTR_HVAC_STATE,
|
||||
CONF_HUMIDIFIER,
|
||||
DEFAULT_SSL,
|
||||
DOMAIN,
|
||||
HOLD_MODE_TEMPERATURE,
|
||||
VALID_FAN_STATES,
|
||||
VALID_THERMOSTAT_MODES,
|
||||
)
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
@ -72,50 +68,42 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||
)
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
"""Set up the Venstar thermostat."""
|
||||
client = hass.data[DOMAIN][config_entry.entry_id]
|
||||
async_add_entities([VenstarThermostat(config_entry, client)], True)
|
||||
|
||||
username = config.get(CONF_USERNAME)
|
||||
password = config.get(CONF_PASSWORD)
|
||||
pin = config.get(CONF_PIN)
|
||||
host = config.get(CONF_HOST)
|
||||
timeout = config.get(CONF_TIMEOUT)
|
||||
humidifier = config.get(CONF_HUMIDIFIER)
|
||||
|
||||
protocol = "https" if config[CONF_SSL] else "http"
|
||||
async def async_setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Venstar thermostat platform.
|
||||
|
||||
client = VenstarColorTouch(
|
||||
addr=host,
|
||||
timeout=timeout,
|
||||
user=username,
|
||||
password=password,
|
||||
pin=pin,
|
||||
proto=protocol,
|
||||
Venstar uses config flow for configuration now. If an entry exists in
|
||||
configuration.yaml, the import flow will attempt to import it and create
|
||||
a config entry.
|
||||
"""
|
||||
_LOGGER.warning(
|
||||
"Loading venstar via platform config is deprecated; The configuration"
|
||||
" has been migrated to a config entry and can be safely removed"
|
||||
)
|
||||
|
||||
add_entities([VenstarThermostat(client, humidifier)], True)
|
||||
# No config entry exists and configuration.yaml config exists, trigger the import flow.
|
||||
if not hass.config_entries.async_entries(DOMAIN):
|
||||
await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_IMPORT}, data=config
|
||||
)
|
||||
|
||||
|
||||
class VenstarThermostat(ClimateEntity):
|
||||
class VenstarThermostat(VenstarEntity, ClimateEntity):
|
||||
"""Representation of a Venstar thermostat."""
|
||||
|
||||
def __init__(self, client, humidifier):
|
||||
def __init__(self, config, client):
|
||||
"""Initialize the thermostat."""
|
||||
self._client = client
|
||||
self._humidifier = humidifier
|
||||
super().__init__(config, client)
|
||||
self._mode_map = {
|
||||
HVAC_MODE_HEAT: self._client.MODE_HEAT,
|
||||
HVAC_MODE_COOL: self._client.MODE_COOL,
|
||||
HVAC_MODE_AUTO: self._client.MODE_AUTO,
|
||||
}
|
||||
|
||||
def update(self):
|
||||
"""Update the data from the thermostat."""
|
||||
info_success = self._client.update_info()
|
||||
sensor_success = self._client.update_sensors()
|
||||
if not info_success or not sensor_success:
|
||||
_LOGGER.error("Failed to update data")
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Return the list of supported features."""
|
||||
@ -124,16 +112,11 @@ class VenstarThermostat(ClimateEntity):
|
||||
if self._client.mode == self._client.MODE_AUTO:
|
||||
features |= SUPPORT_TARGET_TEMPERATURE_RANGE
|
||||
|
||||
if self._humidifier and self._client.hum_setpoint is not None:
|
||||
if self._client.hum_setpoint is not None:
|
||||
features |= SUPPORT_TARGET_HUMIDITY
|
||||
|
||||
return features
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the thermostat."""
|
||||
return self._client.name
|
||||
|
||||
@property
|
||||
def precision(self):
|
||||
"""Return the precision of the system.
|
||||
|
96
homeassistant/components/venstar/config_flow.py
Normal file
96
homeassistant/components/venstar/config_flow.py
Normal file
@ -0,0 +1,96 @@
|
||||
"""Config flow to configure the Venstar integration."""
|
||||
from venstarcolortouch import VenstarColorTouch
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries, core, exceptions
|
||||
from homeassistant.const import (
|
||||
CONF_HOST,
|
||||
CONF_PASSWORD,
|
||||
CONF_PIN,
|
||||
CONF_SSL,
|
||||
CONF_USERNAME,
|
||||
)
|
||||
|
||||
from .const import _LOGGER, DOMAIN, VENSTAR_TIMEOUT
|
||||
|
||||
DATA_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_HOST): str,
|
||||
vol.Optional(CONF_USERNAME): str,
|
||||
vol.Optional(CONF_PASSWORD): str,
|
||||
vol.Optional(CONF_PIN): str,
|
||||
vol.Optional(CONF_SSL, default=False): bool,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def validate_input(hass: core.HomeAssistant, data):
|
||||
"""Validate the user input allows us to connect."""
|
||||
username = data.get(CONF_USERNAME)
|
||||
password = data.get(CONF_PASSWORD)
|
||||
pin = data.get(CONF_PIN)
|
||||
host = data[CONF_HOST]
|
||||
timeout = VENSTAR_TIMEOUT
|
||||
protocol = "https" if data[CONF_SSL] else "http"
|
||||
|
||||
client = VenstarColorTouch(
|
||||
addr=host,
|
||||
timeout=timeout,
|
||||
user=username,
|
||||
password=password,
|
||||
pin=pin,
|
||||
proto=protocol,
|
||||
)
|
||||
|
||||
# perform a full info pull, because this calls login also.
|
||||
|
||||
info_success = await hass.async_add_executor_job(client.update_info)
|
||||
if not info_success:
|
||||
raise CannotConnect
|
||||
|
||||
return {"title": client.name}
|
||||
|
||||
|
||||
class VenstarConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a venstar config flow."""
|
||||
|
||||
VERSION = 1
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Create config entry. Show the setup form to the user."""
|
||||
errors = {}
|
||||
info = {}
|
||||
|
||||
if user_input is not None:
|
||||
self._async_abort_entries_match({CONF_HOST: user_input[CONF_HOST]})
|
||||
|
||||
try:
|
||||
info = await validate_input(self.hass, user_input)
|
||||
except CannotConnect:
|
||||
errors["base"] = "cannot_connect"
|
||||
except Exception: # pylint: disable=broad-except
|
||||
_LOGGER.exception("Unexpected exception")
|
||||
errors["base"] = "unknown"
|
||||
else:
|
||||
return self.async_create_entry(title=info["title"], data=user_input)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="user", data_schema=DATA_SCHEMA, errors=errors
|
||||
)
|
||||
|
||||
async def async_step_import(self, import_data):
|
||||
"""Import entry from configuration.yaml."""
|
||||
self._async_abort_entries_match({CONF_HOST: import_data[CONF_HOST]})
|
||||
return await self.async_step_user(
|
||||
{
|
||||
CONF_HOST: import_data[CONF_HOST],
|
||||
CONF_USERNAME: import_data.get(CONF_USERNAME),
|
||||
CONF_PASSWORD: import_data.get(CONF_PASSWORD),
|
||||
CONF_PIN: import_data.get(CONF_PIN),
|
||||
CONF_SSL: import_data[CONF_SSL],
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class CannotConnect(exceptions.HomeAssistantError):
|
||||
"""Error to indicate we cannot connect."""
|
29
homeassistant/components/venstar/const.py
Normal file
29
homeassistant/components/venstar/const.py
Normal file
@ -0,0 +1,29 @@
|
||||
"""The venstar component."""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.climate.const import (
|
||||
HVAC_MODE_AUTO,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_OFF,
|
||||
)
|
||||
from homeassistant.const import STATE_ON
|
||||
|
||||
DOMAIN = "venstar"
|
||||
|
||||
ATTR_FAN_STATE = "fan_state"
|
||||
ATTR_HVAC_STATE = "hvac_mode"
|
||||
|
||||
CONF_HUMIDIFIER = "humidifier"
|
||||
|
||||
DEFAULT_SSL = False
|
||||
|
||||
VALID_FAN_STATES = [STATE_ON, HVAC_MODE_AUTO]
|
||||
VALID_THERMOSTAT_MODES = [HVAC_MODE_HEAT, HVAC_MODE_COOL, HVAC_MODE_OFF, HVAC_MODE_AUTO]
|
||||
|
||||
HOLD_MODE_OFF = "off"
|
||||
HOLD_MODE_TEMPERATURE = "temperature"
|
||||
|
||||
VENSTAR_TIMEOUT = 5
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
@ -1,8 +1,11 @@
|
||||
{
|
||||
"domain": "venstar",
|
||||
"name": "Venstar",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/venstar",
|
||||
"requirements": ["venstarcolortouch==0.14"],
|
||||
"codeowners": [],
|
||||
"requirements": [
|
||||
"venstarcolortouch==0.14"
|
||||
],
|
||||
"codeowners": ["@garbled1"],
|
||||
"iot_class": "local_polling"
|
||||
}
|
||||
|
23
homeassistant/components/venstar/strings.json
Normal file
23
homeassistant/components/venstar/strings.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Connect to the Venstar Thermostat",
|
||||
"data": {
|
||||
"host": "[%key:common::config_flow::data::host%]",
|
||||
"username": "[%key:common::config_flow::data::username%]",
|
||||
"password": "[%key:common::config_flow::data::password%]",
|
||||
"pin": "[%key:common::config_flow::data::pin%]",
|
||||
"ssl": "[%key:common::config_flow::data::ssl%]"
|
||||
}
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||
}
|
||||
}
|
||||
}
|
20
homeassistant/components/venstar/translations/en.json
Normal file
20
homeassistant/components/venstar/translations/en.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Connect to the Venstar Thermostat",
|
||||
"data": {
|
||||
"host": "Hostname or IP",
|
||||
"username": "Username for thermostat (optional)",
|
||||
"password": "Password for thermostat (optional)",
|
||||
"pin": "Pin for Lockscreen (required if lock screen enabled)",
|
||||
"ssl": "Whether to use SSL or not when communicating"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Unable to connect to thermostat, please validate username/password if supplied, hostname/ip, and that LOCAL API is enabled on the thermostat.",
|
||||
"unknown": "An unknown error has occurred."
|
||||
}
|
||||
}
|
||||
}
|
@ -306,6 +306,7 @@ FLOWS = [
|
||||
"upnp",
|
||||
"uptimerobot",
|
||||
"velbus",
|
||||
"venstar",
|
||||
"vera",
|
||||
"verisure",
|
||||
"vesync",
|
||||
|
@ -1 +1,62 @@
|
||||
"""Tests for the venstar integration."""
|
||||
from requests import RequestException
|
||||
|
||||
|
||||
class VenstarColorTouchMock:
|
||||
"""Mock Venstar Library."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
addr,
|
||||
timeout,
|
||||
user=None,
|
||||
password=None,
|
||||
pin=None,
|
||||
proto="http",
|
||||
SSLCert=False,
|
||||
):
|
||||
"""Initialize the Venstar library."""
|
||||
self.status = {}
|
||||
self.model = "COLORTOUCH"
|
||||
self._api_ver = 5
|
||||
self.name = "TestVenstar"
|
||||
self._info = {}
|
||||
self._sensors = {}
|
||||
self.alerts = {}
|
||||
self.MODE_OFF = 0
|
||||
self.MODE_HEAT = 1
|
||||
self.MODE_COOL = 2
|
||||
self.MODE_AUTO = 3
|
||||
self._type = "residential"
|
||||
|
||||
def login(self):
|
||||
"""Mock login."""
|
||||
return True
|
||||
|
||||
def _request(self, path, data=None):
|
||||
"""Mock request."""
|
||||
self.status = {}
|
||||
|
||||
def update(self):
|
||||
"""Mock update."""
|
||||
return True
|
||||
|
||||
def update_info(self):
|
||||
"""Mock update_info."""
|
||||
return True
|
||||
|
||||
def broken_update_info(self):
|
||||
"""Mock a update_info that raises Exception."""
|
||||
raise RequestException
|
||||
|
||||
def update_sensors(self):
|
||||
"""Mock update_sensors."""
|
||||
return True
|
||||
|
||||
def update_runtimes(self):
|
||||
"""Mock update_runtimes."""
|
||||
return True
|
||||
|
||||
def update_alerts(self):
|
||||
"""Mock update_alerts."""
|
||||
return True
|
||||
|
128
tests/components/venstar/test_config_flow.py
Normal file
128
tests/components/venstar/test_config_flow.py
Normal file
@ -0,0 +1,128 @@
|
||||
"""Test the Venstar config flow."""
|
||||
import logging
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.venstar.const import DOMAIN
|
||||
from homeassistant.config_entries import SOURCE_USER
|
||||
from homeassistant.const import (
|
||||
CONF_HOST,
|
||||
CONF_PASSWORD,
|
||||
CONF_PIN,
|
||||
CONF_SSL,
|
||||
CONF_USERNAME,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import (
|
||||
RESULT_TYPE_ABORT,
|
||||
RESULT_TYPE_CREATE_ENTRY,
|
||||
RESULT_TYPE_FORM,
|
||||
)
|
||||
|
||||
from . import VenstarColorTouchMock
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
TEST_DATA = {
|
||||
CONF_HOST: "1.1.1.1",
|
||||
CONF_USERNAME: "test-username",
|
||||
CONF_PASSWORD: "test-password",
|
||||
CONF_PIN: "test-pin",
|
||||
CONF_SSL: False,
|
||||
}
|
||||
TEST_ID = "VenstarUniqueID"
|
||||
|
||||
|
||||
async def test_form(hass: HomeAssistant) -> None:
|
||||
"""Test we get the form."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert result["errors"] == {}
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.venstar.config_flow.VenstarColorTouch.update_info",
|
||||
new=VenstarColorTouchMock.update_info,
|
||||
), patch(
|
||||
"homeassistant.components.venstar.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry:
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
TEST_DATA,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||
assert result2["data"] == TEST_DATA
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_form_cannot_connect(hass: HomeAssistant) -> None:
|
||||
"""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.venstar.config_flow.VenstarColorTouch.update_info",
|
||||
return_value=False,
|
||||
):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
TEST_DATA,
|
||||
)
|
||||
|
||||
assert result2["type"] == RESULT_TYPE_FORM
|
||||
assert result2["errors"] == {"base": "cannot_connect"}
|
||||
|
||||
|
||||
async def test_unknown_error(hass: HomeAssistant) -> None:
|
||||
"""Test we handle unknown error."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.venstar.config_flow.VenstarColorTouch.update_info",
|
||||
side_effect=Exception,
|
||||
):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
TEST_DATA,
|
||||
)
|
||||
|
||||
assert result2["type"] == RESULT_TYPE_FORM
|
||||
assert result2["errors"] == {"base": "unknown"}
|
||||
|
||||
|
||||
async def test_already_configured(hass: HomeAssistant) -> None:
|
||||
"""Test when provided credentials are already configured."""
|
||||
MockConfigEntry(domain=DOMAIN, data=TEST_DATA, unique_id=TEST_ID).add_to_hass(hass)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert result["step_id"] == SOURCE_USER
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.venstar.VenstarColorTouch.update_info",
|
||||
new=VenstarColorTouchMock.update_info,
|
||||
), patch(
|
||||
"homeassistant.components.venstar.async_setup_entry",
|
||||
return_value=True,
|
||||
):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
TEST_DATA,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] == RESULT_TYPE_ABORT
|
||||
assert result2["reason"] == "already_configured"
|
71
tests/components/venstar/test_init.py
Normal file
71
tests/components/venstar/test_init.py
Normal file
@ -0,0 +1,71 @@
|
||||
"""Tests of the initialization of the venstar integration."""
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.venstar.const import DOMAIN as VENSTAR_DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import CONF_HOST, CONF_SSL
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import VenstarColorTouchMock
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
TEST_HOST = "venstartest.localdomain"
|
||||
|
||||
|
||||
async def test_setup_entry(hass: HomeAssistant):
|
||||
"""Validate that setup entry also configure the client."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=VENSTAR_DOMAIN,
|
||||
data={
|
||||
CONF_HOST: TEST_HOST,
|
||||
CONF_SSL: False,
|
||||
},
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.venstar.VenstarColorTouch._request",
|
||||
new=VenstarColorTouchMock._request,
|
||||
), patch(
|
||||
"homeassistant.components.venstar.VenstarColorTouch.update_sensors",
|
||||
new=VenstarColorTouchMock.update_sensors,
|
||||
), patch(
|
||||
"homeassistant.components.venstar.VenstarColorTouch.update_info",
|
||||
new=VenstarColorTouchMock.update_info,
|
||||
):
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert config_entry.state == ConfigEntryState.LOADED
|
||||
|
||||
await hass.config_entries.async_unload(config_entry.entry_id)
|
||||
|
||||
assert config_entry.state == ConfigEntryState.NOT_LOADED
|
||||
|
||||
|
||||
async def test_setup_entry_exception(hass: HomeAssistant):
|
||||
"""Validate that setup entry also configure the client."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=VENSTAR_DOMAIN,
|
||||
data={
|
||||
CONF_HOST: TEST_HOST,
|
||||
CONF_SSL: False,
|
||||
},
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.venstar.VenstarColorTouch._request",
|
||||
new=VenstarColorTouchMock._request,
|
||||
), patch(
|
||||
"homeassistant.components.venstar.VenstarColorTouch.update_sensors",
|
||||
new=VenstarColorTouchMock.update_sensors,
|
||||
), patch(
|
||||
"homeassistant.components.venstar.VenstarColorTouch.update_info",
|
||||
new=VenstarColorTouchMock.broken_update_info,
|
||||
):
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert config_entry.state == ConfigEntryState.SETUP_RETRY
|
Loading…
x
Reference in New Issue
Block a user