Bump py-aosmith to 1.0.6 (#107409)
parent
4ea8c174f5
commit
3f2170bd06
|
@ -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(
|
||||
|
|
|
@ -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",
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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"]
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
]
|
|
@ -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
|
||||
}
|
||||
}
|
||||
]
|
|
@ -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
|
||||
}
|
||||
}
|
||||
]
|
|
@ -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
|
||||
}
|
||||
}
|
||||
]
|
|
@ -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"
|
||||
}
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in New Issue