Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 49 additions & 7 deletions homeassistant/components/vallox/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,30 @@
from datetime import date
import ipaddress
import logging
from typing import Any, NamedTuple
from typing import Any, NamedTuple, cast
from uuid import UUID

from vallox_websocket_api import PROFILE as VALLOX_PROFILE, Vallox
from vallox_websocket_api.exceptions import ValloxApiException
from vallox_websocket_api.vallox import (
get_next_filter_change_date as calculate_next_filter_change_date,
get_uuid as calculate_uuid,
get_model as _api_get_model,
get_next_filter_change_date as _api_get_next_filter_change_date,
get_sw_version as _api_get_sw_version,
get_uuid as _api_get_uuid,
)
import voluptuous as vol

from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import CONF_HOST, CONF_NAME, Platform
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.typing import ConfigType, StateType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
UpdateFailed,
)

from .const import (
DEFAULT_FAN_SPEED_AWAY,
Expand Down Expand Up @@ -114,16 +121,32 @@ def get_metric(self, metric_key: str) -> StateType:

return value

def get_uuid(self) -> UUID | None:
@property
def model(self) -> str | None:
"""Return the model, if any."""
model = cast(str, _api_get_model(self.metric_cache))

if model == "Unknown":
return None

return model

@property
def sw_version(self) -> str:
"""Return the SW version."""
return cast(str, _api_get_sw_version(self.metric_cache))

@property
def uuid(self) -> UUID | None:
"""Return cached UUID value."""
uuid = calculate_uuid(self.metric_cache)
uuid = _api_get_uuid(self.metric_cache)
if not isinstance(uuid, UUID):
raise ValueError
return uuid

def get_next_filter_change_date(self) -> date | None:
"""Return the next filter change date."""
next_filter_change_date = calculate_next_filter_change_date(self.metric_cache)
next_filter_change_date = _api_get_next_filter_change_date(self.metric_cache)

if not isinstance(next_filter_change_date, date):
return None
Expand Down Expand Up @@ -291,3 +314,22 @@ async def async_handle(self, call: ServiceCall) -> None:
# be observed by all parties involved.
if result:
await self._coordinator.async_request_refresh()


class ValloxEntity(CoordinatorEntity[ValloxDataUpdateCoordinator]):
"""Representation of a Vallox entity."""

def __init__(self, name: str, coordinator: ValloxDataUpdateCoordinator) -> None:
"""Initialize a Vallox entity."""
super().__init__(coordinator)

self._device_uuid = self.coordinator.data.uuid
assert self.coordinator.config_entry is not None
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, str(self._device_uuid))},
manufacturer=DEFAULT_NAME,
model=self.coordinator.data.model,
name=name,
sw_version=self.coordinator.data.sw_version,
configuration_url=f"http://{self.coordinator.config_entry.data[CONF_HOST]}",
)
15 changes: 6 additions & 9 deletions homeassistant/components/vallox/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,18 @@
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from . import ValloxDataUpdateCoordinator
from . import ValloxDataUpdateCoordinator, ValloxEntity
from .const import DOMAIN


class ValloxBinarySensor(
CoordinatorEntity[ValloxDataUpdateCoordinator], BinarySensorEntity
):
class ValloxBinarySensor(ValloxEntity, BinarySensorEntity):
"""Representation of a Vallox binary sensor."""

entity_description: ValloxBinarySensorEntityDescription
_attr_entity_category = EntityCategory.DIAGNOSTIC

def __init__(
self,
Expand All @@ -30,14 +29,12 @@ def __init__(
description: ValloxBinarySensorEntityDescription,
) -> None:
"""Initialize the Vallox binary sensor."""
super().__init__(coordinator)
super().__init__(name, coordinator)

self.entity_description = description

self._attr_name = f"{name} {description.name}"

uuid = self.coordinator.data.get_uuid()
self._attr_unique_id = f"{uuid}-{description.key}"
self._attr_unique_id = f"{self._device_uuid}-{description.key}"

@property
def is_on(self) -> bool | None:
Expand Down
10 changes: 4 additions & 6 deletions homeassistant/components/vallox/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from . import ValloxDataUpdateCoordinator
from . import ValloxDataUpdateCoordinator, ValloxEntity
from .const import (
DOMAIN,
METRIC_KEY_MODE,
Expand Down Expand Up @@ -80,7 +79,7 @@ async def async_setup_entry(
async_add_entities([device])


class ValloxFan(CoordinatorEntity[ValloxDataUpdateCoordinator], FanEntity):
class ValloxFan(ValloxEntity, FanEntity):
"""Representation of the fan."""

def __init__(
Expand All @@ -90,13 +89,12 @@ def __init__(
coordinator: ValloxDataUpdateCoordinator,
) -> None:
"""Initialize the fan."""
super().__init__(coordinator)
super().__init__(name, coordinator)

self._client = client

self._attr_name = name

self._attr_unique_id = str(self.coordinator.data.get_uuid())
self._attr_unique_id = str(self._device_uuid)

@property
def supported_features(self) -> int:
Expand Down
13 changes: 6 additions & 7 deletions homeassistant/components/vallox/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
TEMP_CELSIUS,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util import dt

from . import ValloxDataUpdateCoordinator
from . import ValloxDataUpdateCoordinator, ValloxEntity
from .const import (
DOMAIN,
METRIC_KEY_MODE,
Expand All @@ -32,10 +32,11 @@
)


class ValloxSensor(CoordinatorEntity[ValloxDataUpdateCoordinator], SensorEntity):
class ValloxSensor(ValloxEntity, SensorEntity):
"""Representation of a Vallox sensor."""

entity_description: ValloxSensorEntityDescription
_attr_entity_category = EntityCategory.DIAGNOSTIC

def __init__(
self,
Expand All @@ -44,14 +45,12 @@ def __init__(
description: ValloxSensorEntityDescription,
) -> None:
"""Initialize the Vallox sensor."""
super().__init__(coordinator)
super().__init__(name, coordinator)

self.entity_description = description

self._attr_name = f"{name} {description.name}"

uuid = self.coordinator.data.get_uuid()
self._attr_unique_id = f"{uuid}-{description.key}"
self._attr_unique_id = f"{self._device_uuid}-{description.key}"

@property
def native_value(self) -> StateType | datetime:
Expand Down
24 changes: 22 additions & 2 deletions tests/components/vallox/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,31 @@ def patch_profile_home():
yield


@pytest.fixture(autouse=True)
def patch_model():
"""Patch the Vallox model response."""
with patch(
"homeassistant.components.vallox._api_get_model",
return_value="Vallox Testmodel",
):
yield


@pytest.fixture(autouse=True)
def patch_sw_version():
"""Patch the Vallox SW version response."""
with patch(
"homeassistant.components.vallox._api_get_sw_version",
return_value="0.1.2",
):
yield


@pytest.fixture(autouse=True)
def patch_uuid():
"""Patch the Vallox entity UUID."""
"""Patch the Vallox UUID response."""
with patch(
"homeassistant.components.vallox.calculate_uuid",
"homeassistant.components.vallox._api_get_uuid",
return_value=_random_uuid(),
):
yield
Expand Down
10 changes: 5 additions & 5 deletions tests/components/vallox/test_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ async def test_remaining_filter_returns_timestamp(
"""Test that the remaining time for filter sensor returns a timestamp."""
# Act
with patch(
"homeassistant.components.vallox.calculate_next_filter_change_date",
"homeassistant.components.vallox._api_get_next_filter_change_date",
return_value=dt.now().date(),
), patch_metrics(metrics={}):
await hass.config_entries.async_setup(mock_entry.entry_id)
Expand All @@ -68,7 +68,7 @@ async def test_remaining_time_for_filter_none_returned_from_vallox(
"""Test that the remaining time for filter sensor returns 'unknown' when Vallox returns None."""
# Act
with patch(
"homeassistant.components.vallox.calculate_next_filter_change_date",
"homeassistant.components.vallox._api_get_next_filter_change_date",
return_value=None,
), patch_metrics(metrics={}):
await hass.config_entries.async_setup(mock_entry.entry_id)
Expand Down Expand Up @@ -98,7 +98,7 @@ async def test_remaining_time_for_filter_in_the_future(

# Act
with patch(
"homeassistant.components.vallox.calculate_next_filter_change_date",
"homeassistant.components.vallox._api_get_next_filter_change_date",
return_value=mocked_filter_end_date,
), patch_metrics(metrics={}):
await hass.config_entries.async_setup(mock_entry.entry_id)
Expand All @@ -122,7 +122,7 @@ async def test_remaining_time_for_filter_today(

# Act
with patch(
"homeassistant.components.vallox.calculate_next_filter_change_date",
"homeassistant.components.vallox._api_get_next_filter_change_date",
return_value=mocked_filter_end_date,
), patch_metrics(metrics={}):
await hass.config_entries.async_setup(mock_entry.entry_id)
Expand All @@ -146,7 +146,7 @@ async def test_remaining_time_for_filter_in_the_past(

# Act
with patch(
"homeassistant.components.vallox.calculate_next_filter_change_date",
"homeassistant.components.vallox._api_get_next_filter_change_date",
return_value=mocked_filter_end_date,
), patch_metrics(metrics={}):
await hass.config_entries.async_setup(mock_entry.entry_id)
Expand Down