Change Honeywell somecomfort API to AIOSomecomfort API (#86102)

* Move to AIOSomecomfort

* Remove unused constant

* Improve test coverage to 100

* Update homeassistant/components/honeywell/__init__.py

remove "todo" from code

Co-authored-by: Erik Montnemery <erik@montnemery.com>

* Missing cannot_connect translation

* add asyncio errors
update devices per entity
rework retry login

Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
mkmer 2023-01-18 10:03:13 -05:00 committed by GitHub
parent f0ba7a3795
commit 5e6ba594aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 184 additions and 200 deletions

View File

@ -509,8 +509,8 @@ build.json @home-assistant/supervisor
/tests/components/homematic/ @pvizeli @danielperna84
/homeassistant/components/homewizard/ @DCSBL
/tests/components/homewizard/ @DCSBL
/homeassistant/components/honeywell/ @rdfurman
/tests/components/honeywell/ @rdfurman
/homeassistant/components/honeywell/ @rdfurman @mkmer
/tests/components/honeywell/ @rdfurman @mkmer
/homeassistant/components/http/ @home-assistant/core
/tests/components/http/ @home-assistant/core
/homeassistant/components/huawei_lte/ @scop @fphammerle

View File

@ -1,14 +1,13 @@
"""Support for Honeywell (US) Total Connect Comfort climate systems."""
import asyncio
from datetime import timedelta
import somecomfort
import AIOSomecomfort
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, Platform
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.util import Throttle
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import (
_LOGGER,
@ -20,7 +19,6 @@ from .const import (
)
UPDATE_LOOP_SLEEP_TIME = 5
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=300)
PLATFORMS = [Platform.CLIMATE, Platform.SENSOR]
MIGRATE_OPTIONS_KEYS = {CONF_COOL_AWAY_TEMPERATURE, CONF_HEAT_AWAY_TEMPERATURE}
@ -51,18 +49,33 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
username = config_entry.data[CONF_USERNAME]
password = config_entry.data[CONF_PASSWORD]
client = await hass.async_add_executor_job(
get_somecomfort_client, username, password
client = AIOSomecomfort.AIOSomeComfort(
username, password, session=async_get_clientsession(hass)
)
try:
await client.login()
await client.discover()
if client is None:
return False
except AIOSomecomfort.AuthError as ex:
raise ConfigEntryNotReady(
"Failed to initialize the Honeywell client: "
"Check your configuration (username, password), "
) from ex
except (
AIOSomecomfort.ConnectionError,
AIOSomecomfort.ConnectionTimeout,
asyncio.TimeoutError,
) as ex:
raise ConfigEntryNotReady(
"Failed to initialize the Honeywell client: "
"Connection error: maybe you have exceeded the API rate limit?"
) from ex
loc_id = config_entry.data.get(CONF_LOC_ID)
dev_id = config_entry.data.get(CONF_DEV_ID)
devices = {}
for location in client.locations_by_id.values():
if not loc_id or location.locationid == loc_id:
for device in location.devices_by_id.values():
@ -74,7 +87,6 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
return False
data = HoneywellData(hass, config_entry, client, username, password, devices)
await data.async_update()
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][config_entry.entry_id] = data
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
@ -99,21 +111,6 @@ async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) ->
return unload_ok
def get_somecomfort_client(username: str, password: str) -> somecomfort.SomeComfort:
"""Initialize the somecomfort client."""
try:
return somecomfort.SomeComfort(username, password)
except somecomfort.AuthError:
_LOGGER.error("Failed to login to honeywell account %s", username)
return None
except somecomfort.SomeComfortError as ex:
raise ConfigEntryNotReady(
"Failed to initialize the Honeywell client: "
"Check your configuration (username, password), "
"or maybe you have exceeded the API rate limit?"
) from ex
class HoneywellData:
"""Get the latest data and update."""
@ -121,10 +118,10 @@ class HoneywellData:
self,
hass: HomeAssistant,
config_entry: ConfigEntry,
client: somecomfort.SomeComfort,
client: AIOSomecomfort.AIOSomeComfort,
username: str,
password: str,
devices: dict[str, somecomfort.Device],
devices: dict[str, AIOSomecomfort.device.Device],
) -> None:
"""Initialize the data object."""
self._hass = hass
@ -134,73 +131,13 @@ class HoneywellData:
self._password = password
self.devices = devices
async def _retry(self) -> bool:
"""Recreate a new somecomfort client.
async def retry_login(self) -> bool:
"""Fire of a login retry."""
When we got an error, the best way to be sure that the next query
will succeed, is to recreate a new somecomfort client.
"""
self._client = await self._hass.async_add_executor_job(
get_somecomfort_client, self._username, self._password
)
if self._client is None:
return False
refreshed_devices = [
device
for location in self._client.locations_by_id.values()
for device in location.devices_by_id.values()
]
if len(refreshed_devices) == 0:
_LOGGER.error("Failed to find any devices after retry")
return False
for updated_device in refreshed_devices:
if updated_device.deviceid in self.devices:
self.devices[updated_device.deviceid] = updated_device
else:
_LOGGER.info(
"New device with ID %s detected, reload the honeywell integration"
" if you want to access it in Home Assistant"
)
await self._hass.config_entries.async_reload(self._config.entry_id)
return True
async def _refresh_devices(self):
"""Refresh each enabled device."""
for device in self.devices.values():
await self._hass.async_add_executor_job(device.refresh)
try:
await self._client.login()
except AIOSomecomfort.SomeComfortError:
await asyncio.sleep(UPDATE_LOOP_SLEEP_TIME)
return False
@Throttle(MIN_TIME_BETWEEN_UPDATES)
async def async_update(self) -> None:
"""Update the state."""
retries = 3
while retries > 0:
try:
await self._refresh_devices()
break
except (
somecomfort.client.APIRateLimited,
somecomfort.client.ConnectionError,
somecomfort.client.ConnectionTimeout,
OSError,
) as exp:
retries -= 1
if retries == 0:
_LOGGER.error(
"Ran out of retry attempts (3 attempts allocated). Error: %s",
exp,
)
raise exp
result = await self._retry()
if not result:
_LOGGER.error("Retry result was empty. Error: %s", exp)
raise exp
_LOGGER.info("SomeComfort update failed, retrying. Error: %s", exp)
return True

View File

@ -4,7 +4,7 @@ from __future__ import annotations
import datetime
from typing import Any
import somecomfort
import AIOSomecomfort
from homeassistant.components.climate import (
ATTR_TARGET_TEMP_HIGH,
@ -70,7 +70,7 @@ HW_FAN_MODE_TO_HA = {
"follow schedule": FAN_AUTO,
}
PARALLEL_UPDATES = 1
SCAN_INTERVAL = datetime.timedelta(seconds=10)
async def async_setup_entry(
@ -230,7 +230,7 @@ class HoneywellUSThermostat(ClimateEntity):
cool_status = self._device.raw_ui_data.get("StatusCool", 0)
return heat_status == 2 or cool_status == 2
def _set_temperature(self, **kwargs) -> None:
async def _set_temperature(self, **kwargs) -> None:
"""Set new target temperature."""
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None:
return
@ -246,35 +246,43 @@ class HoneywellUSThermostat(ClimateEntity):
# Get next period time
hour, minute = divmod(next_period * 15, 60)
# Set hold time
setattr(self._device, f"hold_{mode}", datetime.time(hour, minute))
if mode == HVACMode.COOL:
await self._device.set_hold_cool(datetime.time(hour, minute))
elif mode == HVACMode.HEAT:
await self._device.set_hold_heat(datetime.time(hour, minute))
# Set temperature
setattr(self._device, f"setpoint_{mode}", temperature)
except somecomfort.SomeComfortError:
if mode == HVACMode.COOL:
await self._device.set_setpoint_cool(temperature)
elif mode == HVACMode.HEAT:
await self._device.set_setpoint_heat(temperature)
except AIOSomecomfort.SomeComfortError:
_LOGGER.error("Temperature %.1f out of range", temperature)
def set_temperature(self, **kwargs: Any) -> None:
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature."""
if {HVACMode.COOL, HVACMode.HEAT} & set(self._hvac_mode_map):
self._set_temperature(**kwargs)
await self._set_temperature(**kwargs)
try:
if HVACMode.HEAT_COOL in self._hvac_mode_map:
if temperature := kwargs.get(ATTR_TARGET_TEMP_HIGH):
self._device.setpoint_cool = temperature
await self._device.set_setpoint_cool(temperature)
if temperature := kwargs.get(ATTR_TARGET_TEMP_LOW):
self._device.setpoint_heat = temperature
except somecomfort.SomeComfortError as err:
await self._device.set_setpoint_heat(temperature)
except AIOSomecomfort.SomeComfortError as err:
_LOGGER.error("Invalid temperature %s: %s", temperature, err)
def set_fan_mode(self, fan_mode: str) -> None:
async def async_set_fan_mode(self, fan_mode: str) -> None:
"""Set new target fan mode."""
self._device.fan_mode = self._fan_mode_map[fan_mode]
await self._device.set_fan_mode(self._fan_mode_map[fan_mode])
def set_hvac_mode(self, hvac_mode: HVACMode) -> None:
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set new target hvac mode."""
self._device.system_mode = self._hvac_mode_map[hvac_mode]
await self._device.set_system_mode(self._hvac_mode_map[hvac_mode])
def _turn_away_mode_on(self) -> None:
async def _turn_away_mode_on(self) -> None:
"""Turn away on.
Somecomfort does have a proprietary away mode, but it doesn't really
@ -285,73 +293,87 @@ class HoneywellUSThermostat(ClimateEntity):
try:
# Get current mode
mode = self._device.system_mode
except somecomfort.SomeComfortError:
except AIOSomecomfort.SomeComfortError:
_LOGGER.error("Can not get system mode")
return
try:
# Set permanent hold
setattr(self._device, f"hold_{mode}", True)
# Set temperature
setattr(
self._device,
f"setpoint_{mode}",
getattr(self, f"_{mode}_away_temp"),
)
except somecomfort.SomeComfortError:
# and Set temperature
away_temp = getattr(self, f"_{mode}_away_temp")
if mode == HVACMode.COOL:
self._device.set_hold_cool(True)
self._device.set_setpoint_cool(away_temp)
elif mode == HVACMode.HEAT:
self._device.set_hold_heat(True)
self._device.set_setpoint_heat(away_temp)
except AIOSomecomfort.SomeComfortError:
_LOGGER.error(
"Temperature %.1f out of range", getattr(self, f"_{mode}_away_temp")
)
def _turn_hold_mode_on(self) -> None:
async def _turn_hold_mode_on(self) -> None:
"""Turn permanent hold on."""
try:
# Get current mode
mode = self._device.system_mode
except somecomfort.SomeComfortError:
except AIOSomecomfort.SomeComfortError:
_LOGGER.error("Can not get system mode")
return
# Check that we got a valid mode back
if mode in HW_MODE_TO_HVAC_MODE:
try:
# Set permanent hold
setattr(self._device, f"hold_{mode}", True)
except somecomfort.SomeComfortError:
if mode == HVACMode.COOL:
await self._device.set_hold_cool(True)
elif mode == HVACMode.HEAT:
await self._device.set_hold_heat(True)
except AIOSomecomfort.SomeComfortError:
_LOGGER.error("Couldn't set permanent hold")
else:
_LOGGER.error("Invalid system mode returned: %s", mode)
def _turn_away_mode_off(self) -> None:
async def _turn_away_mode_off(self) -> None:
"""Turn away/hold off."""
self._away = False
try:
# Disabling all hold modes
self._device.hold_cool = False
self._device.hold_heat = False
except somecomfort.SomeComfortError:
await self._device.set_hold_cool(False)
await self._device.set_hold_heat(False)
except AIOSomecomfort.SomeComfortError:
_LOGGER.error("Can not stop hold mode")
def set_preset_mode(self, preset_mode: str) -> None:
async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set new preset mode."""
if preset_mode == PRESET_AWAY:
self._turn_away_mode_on()
await self._turn_away_mode_on()
elif preset_mode == PRESET_HOLD:
self._away = False
self._turn_hold_mode_on()
await self._turn_hold_mode_on()
else:
self._turn_away_mode_off()
await self._turn_away_mode_off()
def turn_aux_heat_on(self) -> None:
async def async_turn_aux_heat_on(self) -> None:
"""Turn auxiliary heater on."""
self._device.system_mode = "emheat"
await self._device.system_mode("emheat")
def turn_aux_heat_off(self) -> None:
async def async_turn_aux_heat_off(self) -> None:
"""Turn auxiliary heater off."""
if HVACMode.HEAT in self.hvac_modes:
self.set_hvac_mode(HVACMode.HEAT)
await self.async_set_hvac_mode(HVACMode.HEAT)
else:
self.set_hvac_mode(HVACMode.OFF)
await self.async_set_hvac_mode(HVACMode.OFF)
async def async_update(self) -> None:
"""Get the latest state from the service."""
await self._data.async_update()
try:
await self._device.refresh()
except (
AIOSomecomfort.device.APIRateLimited,
AIOSomecomfort.device.ConnectionError,
AIOSomecomfort.device.ConnectionTimeout,
OSError,
):
await self._data.retry_login()

View File

@ -1,13 +1,17 @@
"""Config flow to configure the honeywell integration."""
from __future__ import annotations
import asyncio
import AIOSomecomfort
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from . import get_somecomfort_client
from .const import (
CONF_COOL_AWAY_TEMPERATURE,
CONF_HEAT_AWAY_TEMPERATURE,
@ -22,20 +26,28 @@ class HoneywellConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
VERSION = 1
async def async_step_user(self, user_input=None):
async def async_step_user(self, user_input=None) -> FlowResult:
"""Create config entry. Show the setup form to the user."""
errors = {}
valid = False
if user_input is not None:
valid = await self.is_valid(**user_input)
try:
valid = await self.is_valid(**user_input)
except AIOSomecomfort.AuthError:
errors["base"] = "invalid_auth"
except (
AIOSomecomfort.ConnectionError,
AIOSomecomfort.ConnectionTimeout,
asyncio.TimeoutError,
):
errors["base"] = "cannot_connect"
if valid:
return self.async_create_entry(
title=DOMAIN,
data=user_input,
)
errors["base"] = "invalid_auth"
data_schema = {
vol.Required(CONF_USERNAME): str,
vol.Required(CONF_PASSWORD): str,
@ -46,11 +58,14 @@ class HoneywellConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def is_valid(self, **kwargs) -> bool:
"""Check if login credentials are valid."""
client = await self.hass.async_add_executor_job(
get_somecomfort_client, kwargs[CONF_USERNAME], kwargs[CONF_PASSWORD]
client = AIOSomecomfort.AIOSomeComfort(
kwargs[CONF_USERNAME],
kwargs[CONF_PASSWORD],
session=async_get_clientsession(self.hass),
)
return client is not None
await client.login()
return True
@staticmethod
@callback
@ -68,7 +83,7 @@ class HoneywellOptionsFlowHandler(config_entries.OptionsFlow):
"""Initialize Honeywell options flow."""
self.config_entry = entry
async def async_step_init(self, user_input=None):
async def async_step_init(self, user_input=None) -> FlowResult:
"""Manage the options."""
if user_input is not None:
return self.async_create_entry(title=DOMAIN, data=user_input)

View File

@ -3,8 +3,8 @@
"name": "Honeywell Total Connect Comfort (US)",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/honeywell",
"requirements": ["somecomfort==0.8.0"],
"codeowners": ["@rdfurman"],
"requirements": ["aiosomecomfort==0.0.2"],
"codeowners": ["@rdfurman", "@mkmer"],
"iot_class": "cloud_polling",
"loggers": ["somecomfort"]
}

View File

@ -5,7 +5,7 @@ from collections.abc import Callable
from dataclasses import dataclass
from typing import Any
from somecomfort import Device
from AIOSomecomfort.device import Device
from homeassistant.components.sensor import (
SensorDeviceClass,

View File

@ -10,7 +10,8 @@
}
},
"error": {
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]"
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
}
},
"options": {

View File

@ -278,6 +278,9 @@ aioskybell==22.7.0
# homeassistant.components.slimproto
aioslimproto==2.1.1
# homeassistant.components.honeywell
aiosomecomfort==0.0.2
# homeassistant.components.steamist
aiosteamist==0.3.2
@ -2362,9 +2365,6 @@ solaredge==0.0.2
# homeassistant.components.solax
solax==0.3.0
# homeassistant.components.honeywell
somecomfort==0.8.0
# homeassistant.components.somfy_mylink
somfy-mylink-synergy==1.0.6

View File

@ -256,6 +256,9 @@ aioskybell==22.7.0
# homeassistant.components.slimproto
aioslimproto==2.1.1
# homeassistant.components.honeywell
aiosomecomfort==0.0.2
# homeassistant.components.steamist
aiosteamist==0.3.2
@ -1659,9 +1662,6 @@ solaredge==0.0.2
# homeassistant.components.solax
solax==0.3.0
# homeassistant.components.honeywell
somecomfort==0.8.0
# homeassistant.components.somfy_mylink
somfy-mylink-synergy==1.0.6

View File

@ -1,9 +1,9 @@
"""Fixtures for honeywell tests."""
from unittest.mock import create_autospec, patch
from unittest.mock import AsyncMock, create_autospec, patch
import AIOSomecomfort
import pytest
import somecomfort
from homeassistant.components.honeywell.const import DOMAIN
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
@ -30,7 +30,7 @@ def config_entry(config_data):
@pytest.fixture
def device():
"""Mock a somecomfort.Device."""
mock_device = create_autospec(somecomfort.Device, instance=True)
mock_device = create_autospec(AIOSomecomfort.device.Device, instance=True)
mock_device.deviceid = 1234567
mock_device._data = {
"canControlHumidification": False,
@ -48,7 +48,7 @@ def device():
@pytest.fixture
def device_with_outdoor_sensor():
"""Mock a somecomfort.Device."""
mock_device = create_autospec(somecomfort.Device, instance=True)
mock_device = create_autospec(AIOSomecomfort.device.Device, instance=True)
mock_device.deviceid = 1234567
mock_device._data = {
"canControlHumidification": False,
@ -67,7 +67,7 @@ def device_with_outdoor_sensor():
@pytest.fixture
def another_device():
"""Mock a somecomfort.Device."""
mock_device = create_autospec(somecomfort.Device, instance=True)
mock_device = create_autospec(AIOSomecomfort.device.Device, instance=True)
mock_device.deviceid = 7654321
mock_device._data = {
"canControlHumidification": False,
@ -85,7 +85,7 @@ def another_device():
@pytest.fixture
def location(device):
"""Mock a somecomfort.Location."""
mock_location = create_autospec(somecomfort.Location, instance=True)
mock_location = create_autospec(AIOSomecomfort.location.Location, instance=True)
mock_location.locationid.return_value = "location1"
mock_location.devices_by_id = {device.deviceid: device}
return mock_location
@ -94,11 +94,13 @@ def location(device):
@pytest.fixture(autouse=True)
def client(location):
"""Mock a somecomfort.SomeComfort client."""
client_mock = create_autospec(somecomfort.SomeComfort, instance=True)
client_mock = create_autospec(AIOSomecomfort.AIOSomeComfort, instance=True)
client_mock.locations_by_id = {location.locationid: location}
client_mock.login = AsyncMock(return_value=True)
client_mock.discover = AsyncMock()
with patch(
"homeassistant.components.honeywell.somecomfort.SomeComfort"
"homeassistant.components.honeywell.AIOSomecomfort.AIOSomeComfort"
) as sc_class_mock:
sc_class_mock.return_value = client_mock
yield client_mock

View File

@ -1,7 +1,7 @@
"""Tests for honeywell config flow."""
from unittest.mock import patch
from unittest.mock import MagicMock, patch
import somecomfort
import AIOSomecomfort
from homeassistant import data_entry_flow
from homeassistant.components.honeywell.const import (
@ -33,28 +33,32 @@ async def test_show_authenticate_form(hass: HomeAssistant) -> None:
assert result["step_id"] == "user"
async def test_connection_error(hass: HomeAssistant) -> None:
async def test_connection_error(hass: HomeAssistant, client: MagicMock) -> None:
"""Test that an error message is shown on connection fail."""
client.login.side_effect = AIOSomecomfort.ConnectionError
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=FAKE_CONFIG
)
assert result["errors"] == {"base": "cannot_connect"}
async def test_auth_error(hass: HomeAssistant, client: MagicMock) -> None:
"""Test that an error message is shown on login fail."""
with patch(
"somecomfort.SomeComfort",
side_effect=somecomfort.AuthError,
):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=FAKE_CONFIG
)
assert result["errors"] == {"base": "invalid_auth"}
client.login.side_effect = AIOSomecomfort.AuthError
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=FAKE_CONFIG
)
assert result["errors"] == {"base": "invalid_auth"}
async def test_create_entry(hass: HomeAssistant) -> None:
"""Test that the config entry is created."""
with patch(
"somecomfort.SomeComfort",
):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=FAKE_CONFIG
)
assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
assert result["data"] == FAKE_CONFIG
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=FAKE_CONFIG
)
assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
assert result["data"] == FAKE_CONFIG
@patch("homeassistant.components.honeywell.UPDATE_LOOP_SLEEP_TIME", 0)

View File

@ -2,7 +2,7 @@
from unittest.mock import create_autospec, patch
import somecomfort
import AIOSomecomfort
from homeassistant.components.honeywell.const import (
CONF_COOL_AWAY_TEMPERATURE,
@ -46,7 +46,7 @@ async def test_setup_multiple_thermostats_with_same_deviceid(
hass: HomeAssistant, caplog, config_entry: MockConfigEntry, device, client
) -> None:
"""Test Honeywell TCC API returning duplicate device IDs."""
mock_location2 = create_autospec(somecomfort.Location, instance=True)
mock_location2 = create_autospec(AIOSomecomfort.Location, instance=True)
mock_location2.locationid.return_value = "location2"
mock_location2.devices_by_id = {device.deviceid: device}
client.locations_by_id["location2"] = mock_location2
@ -71,13 +71,10 @@ async def test_away_temps_migration(hass: HomeAssistant) -> None:
options={},
)
with patch(
"homeassistant.components.honeywell.somecomfort.SomeComfort",
):
legacy_config.add_to_hass(hass)
await hass.config_entries.async_setup(legacy_config.entry_id)
await hass.async_block_till_done()
assert legacy_config.options == {
CONF_COOL_AWAY_TEMPERATURE: 1,
CONF_HEAT_AWAY_TEMPERATURE: 2,
}
legacy_config.add_to_hass(hass)
await hass.config_entries.async_setup(legacy_config.entry_id)
await hass.async_block_till_done()
assert legacy_config.options == {
CONF_COOL_AWAY_TEMPERATURE: 1,
CONF_HEAT_AWAY_TEMPERATURE: 2,
}

View File

@ -1,18 +1,24 @@
"""Test honeywell sensor."""
from somecomfort import Device, Location
from AIOSomecomfort.device import Device
from AIOSomecomfort.location import Location
import pytest
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
@pytest.mark.parametrize("unit,temp", [("C", "5"), ("F", "-15")])
async def test_outdoor_sensor(
hass: HomeAssistant,
config_entry: MockConfigEntry,
location: Location,
device_with_outdoor_sensor: Device,
unit,
temp,
):
"""Test outdoor temperature sensor."""
device_with_outdoor_sensor.temperature_unit = unit
location.devices_by_id[
device_with_outdoor_sensor.deviceid
] = device_with_outdoor_sensor
@ -25,5 +31,5 @@ async def test_outdoor_sensor(
assert temperature_state
assert humidity_state
assert temperature_state.state == "5"
assert temperature_state.state == temp
assert humidity_state.state == "25"