Skip to content

Commit

Permalink
Tidy up
Browse files Browse the repository at this point in the history
  • Loading branch information
cdpuk committed Jan 20, 2024
1 parent 07c4fd2 commit 172411c
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 125 deletions.
9 changes: 0 additions & 9 deletions custom_components/bestway/bestway/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,11 @@
from dataclasses import dataclass
from enum import Enum, IntEnum, auto
from logging import getLogger
from time import time

from typing import Any

_LOGGER = getLogger(__name__)

# How old the latest update can be before a spa is considered offline
_CONNECTIVITY_TIMEOUT = 1000


class BestwayDeviceType(Enum):
"""Bestway device types."""
Expand Down Expand Up @@ -132,11 +128,6 @@ class BestwayDeviceStatus:
timestamp: int
attrs: dict[str, Any]

@property
def online(self) -> bool:
"""Determine whether the device is online based on the age of the latest update."""
return self.timestamp > (time() - _CONNECTIVITY_TIMEOUT)


@dataclass
class BestwayUserToken:
Expand Down
81 changes: 43 additions & 38 deletions custom_components/bestway/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
name="Spa Connected",
)

_SPA_ERRORS_SENSOR_DESCRIPTION = BinarySensorEntityDescription(
_AIRJET_SPA_ERRORS_SENSOR_DESCRIPTION = BinarySensorEntityDescription(
key="spa_has_error",
name="Spa Errors",
device_class=BinarySensorDeviceClass.PROBLEM,
Expand Down Expand Up @@ -66,15 +66,49 @@ async def async_setup_entry(
if device.device_type == BestwayDeviceType.AIRJET_SPA:
entities.extend(
[
SpaConnectivitySensor(coordinator, config_entry, device_id),
DeviceConnectivitySensor(
coordinator,
config_entry,
device_id,
_SPA_CONNECTIVITY_SENSOR_DESCRIPTION,
),
AirjetSpaErrorsSensor(coordinator, config_entry, device_id),
]
)

if device.device_type == BestwayDeviceType.AIRJET_V01_SPA:
entities.extend(
[
DeviceConnectivitySensor(
coordinator,
config_entry,
device_id,
_SPA_CONNECTIVITY_SENSOR_DESCRIPTION,
)
]
)

if device.device_type == BestwayDeviceType.HYDROJET_PRO_SPA:
entities.extend(
[
DeviceConnectivitySensor(
coordinator,
config_entry,
device_id,
_SPA_CONNECTIVITY_SENSOR_DESCRIPTION,
)
]
)

if device.device_type == BestwayDeviceType.POOL_FILTER:
entities.extend(
[
PoolFilterConnectivitySensor(coordinator, config_entry, device_id),
DeviceConnectivitySensor(
coordinator,
config_entry,
device_id,
_POOL_FILTER_CONNECTIVITY_SENSOR_DESCRIPTION,
),
PoolFilterChangeRequiredSensor(
coordinator, config_entry, device_id
),
Expand All @@ -85,17 +119,18 @@ async def async_setup_entry(
async_add_entities(entities)


class SpaConnectivitySensor(BestwayEntity, BinarySensorEntity):
"""Sensor to indicate whether a spa is currently online."""
class DeviceConnectivitySensor(BestwayEntity, BinarySensorEntity):
"""Sensor to indicate whether a device is currently online."""

def __init__(
self,
coordinator: BestwayUpdateCoordinator,
config_entry: ConfigEntry,
device_id: str,
entity_description: BinarySensorEntityDescription,
) -> None:
"""Initialize sensor."""
self.entity_description = _SPA_CONNECTIVITY_SENSOR_DESCRIPTION
self.entity_description = entity_description
self._attr_entity_category = EntityCategory.DIAGNOSTIC
self._attr_unique_id = f"{device_id}_{self.entity_description.key}"
super().__init__(
Expand All @@ -107,7 +142,7 @@ def __init__(
@property
def is_on(self) -> bool | None:
"""Return True if the spa is online."""
return self.status is not None and self.status.online
return self.bestway_device is not None and self.bestway_device.is_online

@property
def available(self) -> bool:
Expand All @@ -125,7 +160,7 @@ def __init__(
device_id: str,
) -> None:
"""Initialize sensor."""
self.entity_description = _SPA_ERRORS_SENSOR_DESCRIPTION
self.entity_description = _AIRJET_SPA_ERRORS_SENSOR_DESCRIPTION
self._attr_entity_category = EntityCategory.DIAGNOSTIC
self._attr_unique_id = f"{device_id}_{self.entity_description.key}"
super().__init__(
Expand Down Expand Up @@ -167,36 +202,6 @@ def extra_state_attributes(self) -> Mapping[str, Any] | None:
}


class PoolFilterConnectivitySensor(BestwayEntity, BinarySensorEntity):
"""Sensor to indicate whether a pool filter is currently online."""

def __init__(
self,
coordinator: BestwayUpdateCoordinator,
config_entry: ConfigEntry,
device_id: str,
) -> None:
"""Initialize sensor."""
self.entity_description = _POOL_FILTER_CONNECTIVITY_SENSOR_DESCRIPTION
self._attr_entity_category = EntityCategory.DIAGNOSTIC
self._attr_unique_id = f"{device_id}_{self.entity_description.key}"
super().__init__(
coordinator,
config_entry,
device_id,
)

@property
def is_on(self) -> bool | None:
"""Return True if the pool filter is online."""
return self.status is not None and self.status.online

@property
def available(self) -> bool:
"""Return True, as the connectivity sensor is always available."""
return True


class PoolFilterChangeRequiredSensor(BestwayEntity, BinarySensorEntity):
"""Sensor to indicate whether a pool filter requires a change."""

Expand Down
43 changes: 33 additions & 10 deletions custom_components/bestway/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
from .const import DOMAIN
from .entity import BestwayEntity

_SPA_MIN_TEMP_C = 20
_SPA_MIN_TEMP_F = 68
_SPA_MAX_TEMP_C = 40
_SPA_MAX_TEMP_F = 104


async def async_setup_entry(
hass: HomeAssistant,
Expand All @@ -30,16 +35,18 @@ async def async_setup_entry(
if device.device_type == BestwayDeviceType.AIRJET_SPA:
entities.append(AirjetSpaThermostat(coordinator, config_entry, device_id))
if device.device_type in [
BestwayDeviceType.HYDROJET_PRO_SPA,
BestwayDeviceType.AIRJET_V01_SPA,
BestwayDeviceType.HYDROJET_PRO_SPA,
]:
entities.append(HydrojetSpaThermostat(coordinator, config_entry, device_id))
entities.append(
AirjetV01HydrojetSpaThermostat(coordinator, config_entry, device_id)
)

async_add_entities(entities)


class AirjetSpaThermostat(BestwayEntity, ClimateEntity):
"""The main thermostat entity for a spa."""
"""A thermostat that works for Airjet spa devices."""

_attr_name = "Spa Thermostat"
_attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE
Expand Down Expand Up @@ -104,7 +111,11 @@ def min_temp(self) -> float:
As the Spa can be switched between temperature units, this needs to be dynamic.
"""
return 20 if self.temperature_unit == UnitOfTemperature.CELSIUS else 68
return (
_SPA_MIN_TEMP_C
if self.temperature_unit == UnitOfTemperature.CELSIUS
else _SPA_MIN_TEMP_F
)

@property
def max_temp(self) -> float:
Expand All @@ -113,7 +124,11 @@ def max_temp(self) -> float:
As the Spa can be switched between temperature units, this needs to be dynamic.
"""
return 40 if self.temperature_unit == UnitOfTemperature.CELSIUS else 104
return (
_SPA_MAX_TEMP_C
if self.temperature_unit == UnitOfTemperature.CELSIUS
else _SPA_MAX_TEMP_F
)

async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set new target hvac mode."""
Expand All @@ -137,8 +152,8 @@ async def async_set_temperature(self, **kwargs: Any) -> None:
await self.coordinator.async_refresh()


class HydrojetSpaThermostat(BestwayEntity, ClimateEntity):
"""The main thermostat entity for a spa."""
class AirjetV01HydrojetSpaThermostat(BestwayEntity, ClimateEntity):
"""A thermostat that works for Airjet_V01 and Hydrojet devices."""

_attr_name = "Spa Thermostat"
_attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE
Expand Down Expand Up @@ -168,7 +183,7 @@ def hvac_action(self) -> HVACAction | str | None:
"""Return the current running action (HEATING or IDLE)."""
if not self.status:
return None
heat_on = self.status.attrs["heat"] == 3
heat_on = self.status.attrs["heat"] == HydrojetHeat.ON
target_reached = self.status.attrs["word3"] == 1
return (
HVACAction.HEATING if (heat_on and not target_reached) else HVACAction.IDLE
Expand Down Expand Up @@ -203,7 +218,11 @@ def min_temp(self) -> float:
As the Spa can be switched between temperature units, this needs to be dynamic.
"""
return 20 if self.temperature_unit == UnitOfTemperature.CELSIUS else 68
return (
_SPA_MIN_TEMP_C
if self.temperature_unit == UnitOfTemperature.CELSIUS
else _SPA_MIN_TEMP_F
)

@property
def max_temp(self) -> float:
Expand All @@ -212,7 +231,11 @@ def max_temp(self) -> float:
As the Spa can be switched between temperature units, this needs to be dynamic.
"""
return 40 if self.temperature_unit == UnitOfTemperature.CELSIUS else 104
return (
_SPA_MAX_TEMP_C
if self.temperature_unit == UnitOfTemperature.CELSIUS
else _SPA_MAX_TEMP_F
)

async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set new target hvac mode."""
Expand Down
6 changes: 3 additions & 3 deletions custom_components/bestway/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ async def async_setup_entry(
for device_id, device in coordinator.api.devices.items():
if device.device_type == BestwayDeviceType.AIRJET_V01_SPA:
entities.append(
SpaBubblesSelect(
ThreeWaySpaBubblesSelect(
coordinator,
config_entry,
device_id,
Expand All @@ -82,7 +82,7 @@ async def async_setup_entry(

if device.device_type == BestwayDeviceType.HYDROJET_PRO_SPA:
entities.append(
SpaBubblesSelect(
ThreeWaySpaBubblesSelect(
coordinator,
config_entry,
device_id,
Expand All @@ -93,7 +93,7 @@ async def async_setup_entry(
async_add_entities(entities)


class SpaBubblesSelect(BestwayEntity, SelectEntity):
class ThreeWaySpaBubblesSelect(BestwayEntity, SelectEntity):
"""Bubbles selection for spa devices that support 3 levels."""

entity_description: BubblesSelectEntityDescription
Expand Down
Loading

0 comments on commit 172411c

Please sign in to comment.