diff --git a/homeassistant/components/aosmith/__init__.py b/homeassistant/components/aosmith/__init__.py index b75a4ad7295..4da390685ab 100644 --- a/homeassistant/components/aosmith/__init__.py +++ b/homeassistant/components/aosmith/__init__.py @@ -37,16 +37,16 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: await status_coordinator.async_config_entry_first_refresh() device_registry = dr.async_get(hass) - for junction_id, status_data in status_coordinator.data.items(): + for junction_id, aosmith_device in status_coordinator.data.items(): device_registry.async_get_or_create( config_entry_id=entry.entry_id, identifiers={(DOMAIN, junction_id)}, manufacturer="A. O. Smith", - name=status_data.get("name"), - model=status_data.get("model"), - serial_number=status_data.get("serial"), - suggested_area=status_data.get("install", {}).get("location"), - sw_version=status_data.get("data", {}).get("firmwareVersion"), + name=aosmith_device.name, + model=aosmith_device.model, + serial_number=aosmith_device.serial, + suggested_area=aosmith_device.install_location, + sw_version=aosmith_device.status.firmware_version, ) energy_coordinator = AOSmithEnergyCoordinator( diff --git a/homeassistant/components/aosmith/const.py b/homeassistant/components/aosmith/const.py index c0c693e0dac..ba9980293dc 100644 --- a/homeassistant/components/aosmith/const.py +++ b/homeassistant/components/aosmith/const.py @@ -4,11 +4,6 @@ from datetime import timedelta DOMAIN = "aosmith" -AOSMITH_MODE_ELECTRIC = "ELECTRIC" -AOSMITH_MODE_HEAT_PUMP = "HEAT_PUMP" -AOSMITH_MODE_HYBRID = "HYBRID" -AOSMITH_MODE_VACATION = "VACATION" - # Update interval to be used for normal background updates. REGULAR_INTERVAL = timedelta(seconds=30) @@ -17,9 +12,3 @@ FAST_INTERVAL = timedelta(seconds=1) # Update interval to be used for energy usage data. ENERGY_USAGE_INTERVAL = timedelta(minutes=10) - -HOT_WATER_STATUS_MAP = { - "LOW": "low", - "MEDIUM": "medium", - "HIGH": "high", -} diff --git a/homeassistant/components/aosmith/coordinator.py b/homeassistant/components/aosmith/coordinator.py index 7d6053cc86e..a0dd703b800 100644 --- a/homeassistant/components/aosmith/coordinator.py +++ b/homeassistant/components/aosmith/coordinator.py @@ -1,12 +1,12 @@ """The data update coordinator for the A. O. Smith integration.""" import logging -from typing import Any from py_aosmith import ( AOSmithAPIClient, AOSmithInvalidCredentialsException, AOSmithUnknownException, ) +from py_aosmith.models import Device as AOSmithDevice from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed @@ -17,7 +17,7 @@ from .const import DOMAIN, ENERGY_USAGE_INTERVAL, FAST_INTERVAL, REGULAR_INTERVA _LOGGER = logging.getLogger(__name__) -class AOSmithStatusCoordinator(DataUpdateCoordinator[dict[str, dict[str, Any]]]): +class AOSmithStatusCoordinator(DataUpdateCoordinator[dict[str, AOSmithDevice]]): """Coordinator for device status, updating with a frequent interval.""" def __init__(self, hass: HomeAssistant, client: AOSmithAPIClient) -> None: @@ -25,7 +25,7 @@ class AOSmithStatusCoordinator(DataUpdateCoordinator[dict[str, dict[str, Any]]]) super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=REGULAR_INTERVAL) self.client = client - async def _async_update_data(self) -> dict[str, dict[str, Any]]: + async def _async_update_data(self) -> dict[str, AOSmithDevice]: """Fetch latest data from the device status endpoint.""" try: devices = await self.client.get_devices() @@ -34,12 +34,9 @@ class AOSmithStatusCoordinator(DataUpdateCoordinator[dict[str, dict[str, Any]]]) except AOSmithUnknownException as err: raise UpdateFailed(f"Error communicating with API: {err}") from err - mode_pending = any( - device.get("data", {}).get("modePending") for device in devices - ) + mode_pending = any(device.status.mode_change_pending for device in devices) setpoint_pending = any( - device.get("data", {}).get("temperatureSetpointPending") - for device in devices + device.status.temperature_setpoint_pending for device in devices ) if mode_pending or setpoint_pending: @@ -47,7 +44,7 @@ class AOSmithStatusCoordinator(DataUpdateCoordinator[dict[str, dict[str, Any]]]) else: self.update_interval = REGULAR_INTERVAL - return {device.get("junctionId"): device for device in devices} + return {device.junction_id: device for device in devices} class AOSmithEnergyCoordinator(DataUpdateCoordinator[dict[str, float]]): @@ -78,6 +75,6 @@ class AOSmithEnergyCoordinator(DataUpdateCoordinator[dict[str, float]]): except AOSmithUnknownException as err: raise UpdateFailed(f"Error communicating with API: {err}") from err - energy_usage_by_junction_id[junction_id] = energy_usage.get("lifetimeKwh") + energy_usage_by_junction_id[junction_id] = energy_usage.lifetime_kwh return energy_usage_by_junction_id diff --git a/homeassistant/components/aosmith/entity.py b/homeassistant/components/aosmith/entity.py index 107e5d7e944..7407fbac3cb 100644 --- a/homeassistant/components/aosmith/entity.py +++ b/homeassistant/components/aosmith/entity.py @@ -2,6 +2,7 @@ from typing import TypeVar from py_aosmith import AOSmithAPIClient +from py_aosmith.models import Device as AOSmithDevice from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.update_coordinator import CoordinatorEntity @@ -37,26 +38,20 @@ class AOSmithStatusEntity(AOSmithEntity[AOSmithStatusCoordinator]): """Base entity for entities that use data from the status coordinator.""" @property - def device(self): - """Shortcut to get the device status from the coordinator data.""" - return self.coordinator.data.get(self.junction_id) - - @property - def device_data(self): - """Shortcut to get the device data within the device status.""" - device = self.device - return None if device is None else device.get("data", {}) + def device(self) -> AOSmithDevice: + """Shortcut to get the device from the coordinator data.""" + return self.coordinator.data[self.junction_id] @property def available(self) -> bool: """Return True if entity is available.""" - return super().available and self.device_data.get("isOnline") is True + return super().available and self.device.status.is_online class AOSmithEnergyEntity(AOSmithEntity[AOSmithEnergyCoordinator]): """Base entity for entities that use data from the energy coordinator.""" @property - def energy_usage(self) -> float | None: + def energy_usage(self) -> float: """Shortcut to get the energy usage from the coordinator data.""" - return self.coordinator.data.get(self.junction_id) + return self.coordinator.data[self.junction_id] diff --git a/homeassistant/components/aosmith/manifest.json b/homeassistant/components/aosmith/manifest.json index 7651086e138..436918ae772 100644 --- a/homeassistant/components/aosmith/manifest.json +++ b/homeassistant/components/aosmith/manifest.json @@ -5,5 +5,5 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/aosmith", "iot_class": "cloud_polling", - "requirements": ["py-aosmith==1.0.4"] + "requirements": ["py-aosmith==1.0.6"] } diff --git a/homeassistant/components/aosmith/sensor.py b/homeassistant/components/aosmith/sensor.py index b0606d2dca4..e4a99a340de 100644 --- a/homeassistant/components/aosmith/sensor.py +++ b/homeassistant/components/aosmith/sensor.py @@ -2,7 +2,8 @@ from collections.abc import Callable from dataclasses import dataclass -from typing import Any + +from py_aosmith.models import Device as AOSmithDevice, HotWaterStatus from homeassistant.components.sensor import ( SensorDeviceClass, @@ -16,7 +17,7 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import AOSmithData -from .const import DOMAIN, HOT_WATER_STATUS_MAP +from .const import DOMAIN from .coordinator import AOSmithEnergyCoordinator, AOSmithStatusCoordinator from .entity import AOSmithEnergyEntity, AOSmithStatusEntity @@ -25,7 +26,7 @@ from .entity import AOSmithEnergyEntity, AOSmithStatusEntity class AOSmithStatusSensorEntityDescription(SensorEntityDescription): """Entity description class for sensors using data from the status coordinator.""" - value_fn: Callable[[dict[str, Any]], str | int | None] + value_fn: Callable[[AOSmithDevice], str | int | None] STATUS_ENTITY_DESCRIPTIONS: tuple[AOSmithStatusSensorEntityDescription, ...] = ( @@ -36,11 +37,17 @@ STATUS_ENTITY_DESCRIPTIONS: tuple[AOSmithStatusSensorEntityDescription, ...] = ( device_class=SensorDeviceClass.ENUM, options=["low", "medium", "high"], value_fn=lambda device: HOT_WATER_STATUS_MAP.get( - device.get("data", {}).get("hotWaterStatus") + device.status.hot_water_status ), ), ) +HOT_WATER_STATUS_MAP: dict[HotWaterStatus, str] = { + HotWaterStatus.LOW: "low", + HotWaterStatus.MEDIUM: "medium", + HotWaterStatus.HIGH: "high", +} + async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback diff --git a/homeassistant/components/aosmith/water_heater.py b/homeassistant/components/aosmith/water_heater.py index 8c42048d439..9522d06e062 100644 --- a/homeassistant/components/aosmith/water_heater.py +++ b/homeassistant/components/aosmith/water_heater.py @@ -2,6 +2,8 @@ from typing import Any +from py_aosmith.models import OperationMode as AOSmithOperationMode + from homeassistant.components.water_heater import ( STATE_ECO, STATE_ELECTRIC, @@ -16,31 +18,25 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import AOSmithData -from .const import ( - AOSMITH_MODE_ELECTRIC, - AOSMITH_MODE_HEAT_PUMP, - AOSMITH_MODE_HYBRID, - AOSMITH_MODE_VACATION, - DOMAIN, -) +from .const import DOMAIN from .coordinator import AOSmithStatusCoordinator from .entity import AOSmithStatusEntity MODE_HA_TO_AOSMITH = { - STATE_OFF: AOSMITH_MODE_VACATION, - STATE_ECO: AOSMITH_MODE_HYBRID, - STATE_ELECTRIC: AOSMITH_MODE_ELECTRIC, - STATE_HEAT_PUMP: AOSMITH_MODE_HEAT_PUMP, + STATE_ECO: AOSmithOperationMode.HYBRID, + STATE_ELECTRIC: AOSmithOperationMode.ELECTRIC, + STATE_HEAT_PUMP: AOSmithOperationMode.HEAT_PUMP, + STATE_OFF: AOSmithOperationMode.VACATION, } MODE_AOSMITH_TO_HA = { - AOSMITH_MODE_ELECTRIC: STATE_ELECTRIC, - AOSMITH_MODE_HEAT_PUMP: STATE_HEAT_PUMP, - AOSMITH_MODE_HYBRID: STATE_ECO, - AOSMITH_MODE_VACATION: STATE_OFF, + AOSmithOperationMode.ELECTRIC: STATE_ELECTRIC, + AOSmithOperationMode.HEAT_PUMP: STATE_HEAT_PUMP, + AOSmithOperationMode.HYBRID: STATE_ECO, + AOSmithOperationMode.VACATION: STATE_OFF, } # Operation mode to use when exiting away mode -DEFAULT_OPERATION_MODE = AOSMITH_MODE_HYBRID +DEFAULT_OPERATION_MODE = AOSmithOperationMode.HYBRID DEFAULT_SUPPORT_FLAGS = ( WaterHeaterEntityFeature.TARGET_TEMPERATURE @@ -79,23 +75,22 @@ class AOSmithWaterHeaterEntity(AOSmithStatusEntity, WaterHeaterEntity): @property def operation_list(self) -> list[str]: """Return the list of supported operation modes.""" - op_modes = [] - for mode_dict in self.device_data.get("modes", []): - mode_name = mode_dict.get("mode") - ha_mode = MODE_AOSMITH_TO_HA.get(mode_name) + ha_modes = [] + for supported_mode in self.device.supported_modes: + ha_mode = MODE_AOSMITH_TO_HA.get(supported_mode.mode) # Filtering out STATE_OFF since it is handled by away mode if ha_mode is not None and ha_mode != STATE_OFF: - op_modes.append(ha_mode) + ha_modes.append(ha_mode) - return op_modes + return ha_modes @property def supported_features(self) -> WaterHeaterEntityFeature: """Return the list of supported features.""" supports_vacation_mode = any( - mode_dict.get("mode") == AOSMITH_MODE_VACATION - for mode_dict in self.device_data.get("modes", []) + supported_mode.mode == AOSmithOperationMode.VACATION + for supported_mode in self.device.supported_modes ) if supports_vacation_mode: @@ -106,22 +101,22 @@ class AOSmithWaterHeaterEntity(AOSmithStatusEntity, WaterHeaterEntity): @property def target_temperature(self) -> float | None: """Return the temperature we try to reach.""" - return self.device_data.get("temperatureSetpoint") + return self.device.status.temperature_setpoint @property def max_temp(self) -> float: """Return the maximum temperature.""" - return self.device_data.get("temperatureSetpointMaximum") + return self.device.status.temperature_setpoint_maximum @property def current_operation(self) -> str: """Return the current operation mode.""" - return MODE_AOSMITH_TO_HA.get(self.device_data.get("mode"), STATE_OFF) + return MODE_AOSMITH_TO_HA.get(self.device.status.current_mode, STATE_OFF) @property def is_away_mode_on(self): """Return True if away mode is on.""" - return self.device_data.get("mode") == AOSMITH_MODE_VACATION + return self.device.status.current_mode == AOSmithOperationMode.VACATION async def async_set_operation_mode(self, operation_mode: str) -> None: """Set new target operation mode.""" @@ -129,18 +124,19 @@ class AOSmithWaterHeaterEntity(AOSmithStatusEntity, WaterHeaterEntity): if aosmith_mode is not None: await self.client.update_mode(self.junction_id, aosmith_mode) - await self.coordinator.async_request_refresh() + await self.coordinator.async_request_refresh() async def async_set_temperature(self, **kwargs: Any) -> None: """Set new target temperature.""" temperature = kwargs.get("temperature") - await self.client.update_setpoint(self.junction_id, temperature) + if temperature is not None: + await self.client.update_setpoint(self.junction_id, temperature) - await self.coordinator.async_request_refresh() + await self.coordinator.async_request_refresh() async def async_turn_away_mode_on(self) -> None: """Turn away mode on.""" - await self.client.update_mode(self.junction_id, AOSMITH_MODE_VACATION) + await self.client.update_mode(self.junction_id, AOSmithOperationMode.VACATION) await self.coordinator.async_request_refresh() diff --git a/requirements_all.txt b/requirements_all.txt index cb331e8d9e0..1d9fb84075b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1554,7 +1554,7 @@ pushover_complete==1.1.1 pvo==2.1.1 # homeassistant.components.aosmith -py-aosmith==1.0.4 +py-aosmith==1.0.6 # homeassistant.components.canary py-canary==0.5.3 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 1929a2ceca4..14235bb399a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1201,7 +1201,7 @@ pushover_complete==1.1.1 pvo==2.1.1 # homeassistant.components.aosmith -py-aosmith==1.0.4 +py-aosmith==1.0.6 # homeassistant.components.canary py-canary==0.5.3 diff --git a/tests/components/aosmith/conftest.py b/tests/components/aosmith/conftest.py index f2c3ffc9c3c..157b58cb902 100644 --- a/tests/components/aosmith/conftest.py +++ b/tests/components/aosmith/conftest.py @@ -3,6 +3,16 @@ from collections.abc import Generator from unittest.mock import AsyncMock, MagicMock, patch from py_aosmith import AOSmithAPIClient +from py_aosmith.models import ( + Device, + DeviceStatus, + DeviceType, + EnergyUseData, + EnergyUseHistoryEntry, + HotWaterStatus, + OperationMode, + SupportedOperationModeInfo, +) import pytest from homeassistant.components.aosmith.const import DOMAIN @@ -10,11 +20,7 @@ from homeassistant.const import CONF_EMAIL, CONF_PASSWORD from homeassistant.core import HomeAssistant from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM -from tests.common import ( - MockConfigEntry, - load_json_array_fixture, - load_json_object_fixture, -) +from tests.common import MockConfigEntry, load_json_object_fixture FIXTURE_USER_INPUT = { CONF_EMAIL: "testemail@example.com", @@ -22,6 +28,80 @@ FIXTURE_USER_INPUT = { } +def build_device_fixture( + mode_pending: bool, setpoint_pending: bool, has_vacation_mode: bool +): + """Build a fixture for a device.""" + supported_modes: list[SupportedOperationModeInfo] = [ + SupportedOperationModeInfo( + mode=OperationMode.HYBRID, + original_name="HYBRID", + has_day_selection=False, + ), + SupportedOperationModeInfo( + mode=OperationMode.HEAT_PUMP, + original_name="HEAT_PUMP", + has_day_selection=False, + ), + SupportedOperationModeInfo( + mode=OperationMode.ELECTRIC, + original_name="ELECTRIC", + has_day_selection=True, + ), + ] + + if has_vacation_mode: + supported_modes.append( + SupportedOperationModeInfo( + mode=OperationMode.VACATION, + original_name="VACATION", + has_day_selection=True, + ) + ) + + return Device( + brand="aosmith", + model="HPTS-50 200 202172000", + device_type=DeviceType.NEXT_GEN_HEAT_PUMP, + dsn="dsn", + junction_id="junctionId", + name="My water heater", + serial="serial", + install_location="Basement", + supported_modes=supported_modes, + status=DeviceStatus( + firmware_version="2.14", + is_online=True, + current_mode=OperationMode.HEAT_PUMP, + mode_change_pending=mode_pending, + temperature_setpoint=130, + temperature_setpoint_pending=setpoint_pending, + temperature_setpoint_previous=130, + temperature_setpoint_maximum=130, + hot_water_status=HotWaterStatus.LOW, + ), + ) + + +ENERGY_USE_FIXTURE = EnergyUseData( + lifetime_kwh=132.825, + history=[ + EnergyUseHistoryEntry( + date="2023-10-30T04:00:00.000Z", + energy_use_kwh=2.01, + ), + EnergyUseHistoryEntry( + date="2023-10-31T04:00:00.000Z", + energy_use_kwh=1.542, + ), + EnergyUseHistoryEntry( + date="2023-11-01T04:00:00.000Z", + energy_use_kwh=1.908, + ), + ], +) + + @pytest.fixture def mock_config_entry() -> MockConfigEntry: """Return the default mocked config entry.""" @@ -42,25 +122,44 @@ def mock_setup_entry() -> Generator[AsyncMock, None, None]: @pytest.fixture -def get_devices_fixture() -> str: - """Return the name of the fixture to use for get_devices.""" - return "get_devices" +def get_devices_fixture_mode_pending() -> bool: + """Return whether to set mode_pending in the get_devices fixture.""" + return False @pytest.fixture -async def mock_client(get_devices_fixture: str) -> Generator[MagicMock, None, None]: +def get_devices_fixture_setpoint_pending() -> bool: + """Return whether to set setpoint_pending in the get_devices fixture.""" + return False + + +@pytest.fixture +def get_devices_fixture_has_vacation_mode() -> bool: + """Return whether to include vacation mode in the get_devices fixture.""" + return True + + +@pytest.fixture +async def mock_client( + get_devices_fixture_mode_pending: bool, + get_devices_fixture_setpoint_pending: bool, + get_devices_fixture_has_vacation_mode: bool, +) -> Generator[MagicMock, None, None]: """Return a mocked client.""" - get_devices_fixture = load_json_array_fixture(f"{get_devices_fixture}.json", DOMAIN) - get_energy_use_fixture = load_json_object_fixture( - "get_energy_use_data.json", DOMAIN - ) + get_devices_fixture = [ + build_device_fixture( + get_devices_fixture_mode_pending, + get_devices_fixture_setpoint_pending, + get_devices_fixture_has_vacation_mode, + ) + ] get_all_device_info_fixture = load_json_object_fixture( "get_all_device_info.json", DOMAIN ) client_mock = MagicMock(AOSmithAPIClient) client_mock.get_devices = AsyncMock(return_value=get_devices_fixture) - client_mock.get_energy_use_data = AsyncMock(return_value=get_energy_use_fixture) + client_mock.get_energy_use_data = AsyncMock(return_value=ENERGY_USE_FIXTURE) client_mock.get_all_device_info = AsyncMock( return_value=get_all_device_info_fixture ) diff --git a/tests/components/aosmith/fixtures/get_devices.json b/tests/components/aosmith/fixtures/get_devices.json deleted file mode 100644 index e34c50cd270..00000000000 --- a/tests/components/aosmith/fixtures/get_devices.json +++ /dev/null @@ -1,46 +0,0 @@ -[ - { - "brand": "aosmith", - "model": "HPTS-50 200 202172000", - "deviceType": "NEXT_GEN_HEAT_PUMP", - "dsn": "dsn", - "junctionId": "junctionId", - "name": "My water heater", - "serial": "serial", - "install": { - "location": "Basement" - }, - "data": { - "__typename": "NextGenHeatPump", - "temperatureSetpoint": 130, - "temperatureSetpointPending": false, - "temperatureSetpointPrevious": 130, - "temperatureSetpointMaximum": 130, - "modes": [ - { - "mode": "HYBRID", - "controls": null - }, - { - "mode": "HEAT_PUMP", - "controls": null - }, - { - "mode": "ELECTRIC", - "controls": "SELECT_DAYS" - }, - { - "mode": "VACATION", - "controls": "SELECT_DAYS" - } - ], - "isOnline": true, - "firmwareVersion": "2.14", - "hotWaterStatus": "LOW", - "mode": "HEAT_PUMP", - "modePending": false, - "vacationModeRemainingDays": 0, - "electricModeRemainingDays": 0 - } - } -] diff --git a/tests/components/aosmith/fixtures/get_devices_mode_pending.json b/tests/components/aosmith/fixtures/get_devices_mode_pending.json deleted file mode 100644 index a12f1d95f13..00000000000 --- a/tests/components/aosmith/fixtures/get_devices_mode_pending.json +++ /dev/null @@ -1,46 +0,0 @@ -[ - { - "brand": "aosmith", - "model": "HPTS-50 200 202172000", - "deviceType": "NEXT_GEN_HEAT_PUMP", - "dsn": "dsn", - "junctionId": "junctionId", - "name": "My water heater", - "serial": "serial", - "install": { - "location": "Basement" - }, - "data": { - "__typename": "NextGenHeatPump", - "temperatureSetpoint": 130, - "temperatureSetpointPending": false, - "temperatureSetpointPrevious": 130, - "temperatureSetpointMaximum": 130, - "modes": [ - { - "mode": "HYBRID", - "controls": null - }, - { - "mode": "HEAT_PUMP", - "controls": null - }, - { - "mode": "ELECTRIC", - "controls": "SELECT_DAYS" - }, - { - "mode": "VACATION", - "controls": "SELECT_DAYS" - } - ], - "isOnline": true, - "firmwareVersion": "2.14", - "hotWaterStatus": "LOW", - "mode": "HEAT_PUMP", - "modePending": true, - "vacationModeRemainingDays": 0, - "electricModeRemainingDays": 0 - } - } -] diff --git a/tests/components/aosmith/fixtures/get_devices_no_vacation_mode.json b/tests/components/aosmith/fixtures/get_devices_no_vacation_mode.json deleted file mode 100644 index 249024e1f1e..00000000000 --- a/tests/components/aosmith/fixtures/get_devices_no_vacation_mode.json +++ /dev/null @@ -1,42 +0,0 @@ -[ - { - "brand": "aosmith", - "model": "HPTS-50 200 202172000", - "deviceType": "NEXT_GEN_HEAT_PUMP", - "dsn": "dsn", - "junctionId": "junctionId", - "name": "My water heater", - "serial": "serial", - "install": { - "location": "Basement" - }, - "data": { - "__typename": "NextGenHeatPump", - "temperatureSetpoint": 130, - "temperatureSetpointPending": false, - "temperatureSetpointPrevious": 130, - "temperatureSetpointMaximum": 130, - "modes": [ - { - "mode": "HYBRID", - "controls": null - }, - { - "mode": "HEAT_PUMP", - "controls": null - }, - { - "mode": "ELECTRIC", - "controls": "SELECT_DAYS" - } - ], - "isOnline": true, - "firmwareVersion": "2.14", - "hotWaterStatus": "LOW", - "mode": "HEAT_PUMP", - "modePending": false, - "vacationModeRemainingDays": 0, - "electricModeRemainingDays": 0 - } - } -] diff --git a/tests/components/aosmith/fixtures/get_devices_setpoint_pending.json b/tests/components/aosmith/fixtures/get_devices_setpoint_pending.json deleted file mode 100644 index 4d6e7613cf2..00000000000 --- a/tests/components/aosmith/fixtures/get_devices_setpoint_pending.json +++ /dev/null @@ -1,46 +0,0 @@ -[ - { - "brand": "aosmith", - "model": "HPTS-50 200 202172000", - "deviceType": "NEXT_GEN_HEAT_PUMP", - "dsn": "dsn", - "junctionId": "junctionId", - "name": "My water heater", - "serial": "serial", - "install": { - "location": "Basement" - }, - "data": { - "__typename": "NextGenHeatPump", - "temperatureSetpoint": 130, - "temperatureSetpointPending": true, - "temperatureSetpointPrevious": 130, - "temperatureSetpointMaximum": 130, - "modes": [ - { - "mode": "HYBRID", - "controls": null - }, - { - "mode": "HEAT_PUMP", - "controls": null - }, - { - "mode": "ELECTRIC", - "controls": "SELECT_DAYS" - }, - { - "mode": "VACATION", - "controls": "SELECT_DAYS" - } - ], - "isOnline": true, - "firmwareVersion": "2.14", - "hotWaterStatus": "LOW", - "mode": "HEAT_PUMP", - "modePending": false, - "vacationModeRemainingDays": 0, - "electricModeRemainingDays": 0 - } - } -] diff --git a/tests/components/aosmith/fixtures/get_energy_use_data.json b/tests/components/aosmith/fixtures/get_energy_use_data.json deleted file mode 100644 index 989ddab5399..00000000000 --- a/tests/components/aosmith/fixtures/get_energy_use_data.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "average": 2.7552000000000003, - "graphData": [ - { - "date": "2023-10-30T04:00:00.000Z", - "kwh": 2.01 - }, - { - "date": "2023-10-31T04:00:00.000Z", - "kwh": 1.542 - }, - { - "date": "2023-11-01T04:00:00.000Z", - "kwh": 1.908 - } - ], - "lifetimeKwh": 132.825, - "startDate": "Oct 30" -} diff --git a/tests/components/aosmith/test_init.py b/tests/components/aosmith/test_init.py index 463932e930a..7ff75ce1105 100644 --- a/tests/components/aosmith/test_init.py +++ b/tests/components/aosmith/test_init.py @@ -15,11 +15,9 @@ from homeassistant.components.aosmith.const import ( from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant -from tests.common import ( - MockConfigEntry, - async_fire_time_changed, - load_json_array_fixture, -) +from .conftest import build_device_fixture + +from tests.common import MockConfigEntry, async_fire_time_changed async def test_config_entry_setup(init_integration: MockConfigEntry) -> None: @@ -52,7 +50,7 @@ async def test_config_entry_not_ready_get_energy_use_data_error( """Test the config entry not ready when get_energy_use_data fails.""" mock_config_entry.add_to_hass(hass) - get_devices_fixture = load_json_array_fixture("get_devices.json", DOMAIN) + get_devices_fixture = [build_device_fixture(False, False, True)] with patch( "homeassistant.components.aosmith.config_flow.AOSmithAPIClient.get_devices", @@ -68,12 +66,17 @@ async def test_config_entry_not_ready_get_energy_use_data_error( @pytest.mark.parametrize( - ("get_devices_fixture", "time_to_wait", "expected_call_count"), + ( + "get_devices_fixture_mode_pending", + "get_devices_fixture_setpoint_pending", + "time_to_wait", + "expected_call_count", + ), [ - ("get_devices", REGULAR_INTERVAL, 1), - ("get_devices", FAST_INTERVAL, 0), - ("get_devices_mode_pending", FAST_INTERVAL, 1), - ("get_devices_setpoint_pending", FAST_INTERVAL, 1), + (False, False, REGULAR_INTERVAL, 1), + (False, False, FAST_INTERVAL, 0), + (True, False, FAST_INTERVAL, 1), + (False, True, FAST_INTERVAL, 1), ], ) async def test_update( diff --git a/tests/components/aosmith/test_water_heater.py b/tests/components/aosmith/test_water_heater.py index 61cb159c82a..a66b5db35e6 100644 --- a/tests/components/aosmith/test_water_heater.py +++ b/tests/components/aosmith/test_water_heater.py @@ -2,15 +2,10 @@ from unittest.mock import MagicMock +from py_aosmith.models import OperationMode import pytest from syrupy.assertion import SnapshotAssertion -from homeassistant.components.aosmith.const import ( - AOSMITH_MODE_ELECTRIC, - AOSMITH_MODE_HEAT_PUMP, - AOSMITH_MODE_HYBRID, - AOSMITH_MODE_VACATION, -) from homeassistant.components.water_heater import ( ATTR_AWAY_MODE, ATTR_OPERATION_MODE, @@ -59,8 +54,8 @@ async def test_state( @pytest.mark.parametrize( - ("get_devices_fixture"), - ["get_devices_no_vacation_mode"], + ("get_devices_fixture_has_vacation_mode"), + [False], ) async def test_state_away_mode_unsupported( hass: HomeAssistant, init_integration: MockConfigEntry @@ -77,9 +72,9 @@ async def test_state_away_mode_unsupported( @pytest.mark.parametrize( ("hass_mode", "aosmith_mode"), [ - (STATE_HEAT_PUMP, AOSMITH_MODE_HEAT_PUMP), - (STATE_ECO, AOSMITH_MODE_HYBRID), - (STATE_ELECTRIC, AOSMITH_MODE_ELECTRIC), + (STATE_HEAT_PUMP, OperationMode.HEAT_PUMP), + (STATE_ECO, OperationMode.HYBRID), + (STATE_ELECTRIC, OperationMode.ELECTRIC), ], ) async def test_set_operation_mode( @@ -122,8 +117,8 @@ async def test_set_temperature( @pytest.mark.parametrize( ("hass_away_mode", "aosmith_mode"), [ - (True, AOSMITH_MODE_VACATION), - (False, AOSMITH_MODE_HYBRID), + (True, OperationMode.VACATION), + (False, OperationMode.HYBRID), ], ) async def test_away_mode(