mirror of https://github.com/simbaja/ha_gehome.git
391 lines
12 KiB
Python
391 lines
12 KiB
Python
"""Define all of the entity types"""
|
|
|
|
__all__ = (
|
|
"DOOR_ERD_CODES",
|
|
"RAW_TEMPERATURE_ERD_CODES",
|
|
"NONZERO_TEMPERATURE_ERD_CODES",
|
|
"TEMPERATURE_ERD_CODES",
|
|
"TIMER_ERD_CODES",
|
|
"GeEntity",
|
|
"GeErdEntity",
|
|
"GeErdSensor",
|
|
"GeErdPropertySensor",
|
|
"GeErdBinarySensor",
|
|
"GeErdPropertyBinarySensor",
|
|
"GeErdSwitch",
|
|
)
|
|
|
|
import logging
|
|
from typing import Any, Dict, Optional, TYPE_CHECKING
|
|
|
|
from gekitchen import ErdCodeType, GeAppliance, translate_erd_code
|
|
from gekitchen.erd_types import *
|
|
from gekitchen.erd_constants import *
|
|
from homeassistant.components.binary_sensor import BinarySensorEntity
|
|
from homeassistant.components.switch import SwitchEntity
|
|
from homeassistant.const import DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers.entity import Entity
|
|
|
|
from .const import DOMAIN
|
|
from .erd_string_utils import *
|
|
|
|
if TYPE_CHECKING:
|
|
from .appliance_api import ApplianceApi
|
|
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
DOOR_ERD_CODES = {
|
|
ErdCode.DOOR_STATUS
|
|
}
|
|
RAW_TEMPERATURE_ERD_CODES = {
|
|
ErdCode.HOT_WATER_SET_TEMP,
|
|
ErdCode.LOWER_OVEN_RAW_TEMPERATURE,
|
|
ErdCode.LOWER_OVEN_USER_TEMP_OFFSET,
|
|
ErdCode.UPPER_OVEN_RAW_TEMPERATURE,
|
|
ErdCode.UPPER_OVEN_USER_TEMP_OFFSET,
|
|
ErdCode.CURRENT_TEMPERATURE,
|
|
ErdCode.TEMPERATURE_SETTING,
|
|
}
|
|
NONZERO_TEMPERATURE_ERD_CODES = {
|
|
ErdCode.LOWER_OVEN_DISPLAY_TEMPERATURE,
|
|
ErdCode.LOWER_OVEN_PROBE_DISPLAY_TEMP,
|
|
ErdCode.UPPER_OVEN_DISPLAY_TEMPERATURE,
|
|
ErdCode.UPPER_OVEN_PROBE_DISPLAY_TEMP,
|
|
}
|
|
TEMPERATURE_ERD_CODES = RAW_TEMPERATURE_ERD_CODES.union(NONZERO_TEMPERATURE_ERD_CODES)
|
|
TIMER_ERD_CODES = {
|
|
ErdCode.LOWER_OVEN_ELAPSED_COOK_TIME,
|
|
ErdCode.LOWER_OVEN_KITCHEN_TIMER,
|
|
ErdCode.LOWER_OVEN_DELAY_TIME_REMAINING,
|
|
ErdCode.LOWER_OVEN_COOK_TIME_REMAINING,
|
|
ErdCode.LOWER_OVEN_ELAPSED_COOK_TIME,
|
|
ErdCode.ELAPSED_ON_TIME,
|
|
ErdCode.TIME_REMAINING,
|
|
ErdCode.UPPER_OVEN_ELAPSED_COOK_TIME,
|
|
ErdCode.UPPER_OVEN_KITCHEN_TIMER,
|
|
ErdCode.UPPER_OVEN_DELAY_TIME_REMAINING,
|
|
ErdCode.UPPER_OVEN_ELAPSED_COOK_TIME,
|
|
ErdCode.UPPER_OVEN_COOK_TIME_REMAINING,
|
|
}
|
|
|
|
|
|
def boolify_erd_value(erd_code: ErdCodeType, value: Any) -> Optional[bool]:
|
|
"""
|
|
Convert an erd property value to a bool
|
|
|
|
:param erd_code: The ERD code for the property
|
|
:param value: The current value in its native format
|
|
:return: The value converted to a bool
|
|
"""
|
|
erd_code = translate_erd_code(erd_code)
|
|
if isinstance(value, ErdDoorStatus):
|
|
if value == ErdDoorStatus.NA:
|
|
return None
|
|
return value == ErdDoorStatus.OPEN
|
|
if value is None:
|
|
return None
|
|
return bool(value)
|
|
|
|
|
|
def stringify_erd_value(erd_code: ErdCodeType, value: Any, units: str) -> Optional[str]:
|
|
"""
|
|
Convert an erd property value to a nice string
|
|
|
|
:param erd_code: The ERD code for the property
|
|
:param value: The current value in its native format
|
|
:param units: Units to apply, if applicable
|
|
:return: The value converted to a string
|
|
"""
|
|
erd_code = translate_erd_code(erd_code)
|
|
|
|
if isinstance(value, ErdOvenState):
|
|
return oven_display_state_to_str(value)
|
|
if isinstance(value, OvenCookSetting):
|
|
return oven_cook_setting_to_str(value, units)
|
|
if isinstance(value, FridgeDoorStatus):
|
|
return value.status
|
|
if isinstance(value, FridgeIceBucketStatus):
|
|
return bucket_status_to_str(value)
|
|
if isinstance(value, ErdFilterStatus):
|
|
return value.name.capitalize()
|
|
if isinstance(value, HotWaterStatus):
|
|
return hot_water_status_str(value)
|
|
if isinstance(value, ErdDoorStatus):
|
|
return door_status_to_str(value)
|
|
|
|
if erd_code == ErdCode.CLOCK_TIME:
|
|
return value.strftime("%H:%M:%S") if value else None
|
|
if erd_code in RAW_TEMPERATURE_ERD_CODES:
|
|
return f"{value}"
|
|
if erd_code in NONZERO_TEMPERATURE_ERD_CODES:
|
|
return f"{value}" if value else ""
|
|
if erd_code in TIMER_ERD_CODES:
|
|
return str(value)[:-3] if value else ""
|
|
if erd_code == ErdCode.DOOR_STATUS:
|
|
return value.status
|
|
if value is None:
|
|
return None
|
|
return str(value)
|
|
|
|
|
|
def get_erd_units(erd_code: ErdCodeType, measurement_units: ErdMeasurementUnits):
|
|
"""Get the units for a sensor."""
|
|
erd_code = translate_erd_code(erd_code)
|
|
if not measurement_units:
|
|
return None
|
|
|
|
if erd_code in TEMPERATURE_ERD_CODES or erd_code in {ErdCode.LOWER_OVEN_COOK_MODE, ErdCode.UPPER_OVEN_COOK_MODE}:
|
|
if measurement_units == ErdMeasurementUnits.METRIC:
|
|
return TEMP_CELSIUS
|
|
return TEMP_FAHRENHEIT
|
|
return None
|
|
|
|
|
|
def get_erd_icon(erd_code: ErdCodeType, value: Any = None) -> Optional[str]:
|
|
"""Select an appropriate icon."""
|
|
erd_code = translate_erd_code(erd_code)
|
|
if not isinstance(erd_code, ErdCode):
|
|
return None
|
|
if erd_code in TIMER_ERD_CODES:
|
|
return "mdi:timer-outline"
|
|
if erd_code in {
|
|
ErdCode.LOWER_OVEN_COOK_MODE,
|
|
ErdCode.LOWER_OVEN_CURRENT_STATE,
|
|
ErdCode.LOWER_OVEN_WARMING_DRAWER_STATE,
|
|
ErdCode.UPPER_OVEN_COOK_MODE,
|
|
ErdCode.UPPER_OVEN_CURRENT_STATE,
|
|
ErdCode.UPPER_OVEN_WARMING_DRAWER_STATE,
|
|
ErdCode.WARMING_DRAWER_STATE,
|
|
}:
|
|
return "mdi:stove"
|
|
if erd_code in {
|
|
ErdCode.TURBO_COOL_STATUS,
|
|
ErdCode.TURBO_FREEZE_STATUS,
|
|
}:
|
|
return "mdi:snowflake"
|
|
if erd_code == ErdCode.SABBATH_MODE:
|
|
return "mdi:judaism"
|
|
|
|
# Let binary sensors assign their own. Might be worth passing
|
|
# the actual entity in if we want to do more of this.
|
|
if erd_code in DOOR_ERD_CODES and isinstance(value, str):
|
|
if "open" in value.lower():
|
|
return "mdi:door-open"
|
|
return "mdi:door-closed"
|
|
|
|
return None
|
|
|
|
|
|
class GeEntity:
|
|
"""Base class for all GE Entities"""
|
|
def __init__(self, api: "ApplianceApi"):
|
|
self._api = api
|
|
self.hass = None # type: Optional[HomeAssistant]
|
|
|
|
@property
|
|
def unique_id(self) -> str:
|
|
raise NotImplementedError
|
|
|
|
@property
|
|
def api(self) -> "ApplianceApi":
|
|
return self._api
|
|
|
|
@property
|
|
def device_info(self) -> Optional[Dict[str, Any]]:
|
|
return self.api.device_info
|
|
|
|
@property
|
|
def serial_number(self):
|
|
return self.api.serial_number
|
|
|
|
@property
|
|
def should_poll(self) -> bool:
|
|
"""Don"t poll."""
|
|
return False
|
|
|
|
@property
|
|
def available(self) -> bool:
|
|
return self.appliance.available
|
|
|
|
@property
|
|
def appliance(self) -> GeAppliance:
|
|
return self.api.appliance
|
|
|
|
@property
|
|
def name(self) -> Optional[str]:
|
|
raise NotImplementedError
|
|
|
|
|
|
class GeErdEntity(GeEntity):
|
|
"""Parent class for GE entities tied to a specific ERD"""
|
|
def __init__(self, api: "ApplianceApi", erd_code: ErdCodeType):
|
|
super().__init__(api)
|
|
self._erd_code = translate_erd_code(erd_code)
|
|
|
|
@property
|
|
def erd_code(self) -> ErdCodeType:
|
|
return self._erd_code
|
|
|
|
@property
|
|
def erd_string(self) -> str:
|
|
erd_code = self.erd_code
|
|
if isinstance(self.erd_code, ErdCode):
|
|
return erd_code.name
|
|
return erd_code
|
|
|
|
@property
|
|
def name(self) -> Optional[str]:
|
|
erd_string = self.erd_string
|
|
return " ".join(erd_string.split("_")).title()
|
|
|
|
@property
|
|
def unique_id(self) -> Optional[str]:
|
|
return f"{DOMAIN}_{self.serial_number}_{self.erd_string.lower()}"
|
|
|
|
@property
|
|
def icon(self) -> Optional[str]:
|
|
return get_erd_icon(self.erd_code)
|
|
|
|
|
|
class GeErdSensor(GeErdEntity, Entity):
|
|
"""GE Entity for sensors"""
|
|
@property
|
|
def state(self) -> Optional[str]:
|
|
try:
|
|
value = self.appliance.get_erd_value(self.erd_code)
|
|
except KeyError:
|
|
return None
|
|
return stringify_erd_value(self.erd_code, value, self.units)
|
|
|
|
@property
|
|
def measurement_system(self) -> Optional[ErdMeasurementUnits]:
|
|
return self.appliance.get_erd_value(ErdCode.TEMPERATURE_UNIT)
|
|
|
|
@property
|
|
def units(self) -> Optional[str]:
|
|
return get_erd_units(self.erd_code, self.measurement_system)
|
|
|
|
@property
|
|
def device_class(self) -> Optional[str]:
|
|
if self.erd_code in TEMPERATURE_ERD_CODES:
|
|
return DEVICE_CLASS_TEMPERATURE
|
|
return None
|
|
|
|
@property
|
|
def icon(self) -> Optional[str]:
|
|
return get_erd_icon(self.erd_code, self.state)
|
|
|
|
@property
|
|
def unit_of_measurement(self) -> Optional[str]:
|
|
if self.device_class == DEVICE_CLASS_TEMPERATURE:
|
|
return self.units
|
|
|
|
|
|
class GeErdPropertySensor(GeErdSensor):
|
|
"""GE Entity for sensors"""
|
|
def __init__(self, api: "ApplianceApi", erd_code: ErdCodeType, erd_property: str):
|
|
super().__init__(api, erd_code)
|
|
self.erd_property = erd_property
|
|
|
|
@property
|
|
def unique_id(self) -> Optional[str]:
|
|
return f"{super().unique_id}_{self.erd_property}"
|
|
|
|
@property
|
|
def name(self) -> Optional[str]:
|
|
base_string = super().name
|
|
property_name = self.erd_property.replace("_", " ").title()
|
|
return f"{base_string} {property_name}"
|
|
|
|
@property
|
|
def state(self) -> Optional[str]:
|
|
try:
|
|
value = getattr(self.appliance.get_erd_value(self.erd_code), self.erd_property)
|
|
except KeyError:
|
|
return None
|
|
return stringify_erd_value(self.erd_code, value, self.units)
|
|
|
|
@property
|
|
def measurement_system(self) -> Optional[ErdMeasurementUnits]:
|
|
return self.appliance.get_erd_value(ErdCode.TEMPERATURE_UNIT)
|
|
|
|
@property
|
|
def units(self) -> Optional[str]:
|
|
return get_erd_units(self.erd_code, self.measurement_system)
|
|
|
|
@property
|
|
def device_class(self) -> Optional[str]:
|
|
if self.erd_code in TEMPERATURE_ERD_CODES:
|
|
return "temperature"
|
|
return None
|
|
|
|
|
|
class GeErdBinarySensor(GeErdEntity, BinarySensorEntity):
|
|
"""GE Entity for binary sensors"""
|
|
@property
|
|
def is_on(self) -> bool:
|
|
"""Return True if entity is on."""
|
|
return bool(self.appliance.get_erd_value(self.erd_code))
|
|
|
|
@property
|
|
def icon(self) -> Optional[str]:
|
|
return get_erd_icon(self.erd_code, self.is_on)
|
|
|
|
@property
|
|
def device_class(self) -> Optional[str]:
|
|
if self.erd_code in DOOR_ERD_CODES:
|
|
return "door"
|
|
return None
|
|
|
|
|
|
class GeErdPropertyBinarySensor(GeErdBinarySensor):
|
|
"""GE Entity for property binary sensors"""
|
|
def __init__(self, api: "ApplianceApi", erd_code: ErdCodeType, erd_property: str):
|
|
super().__init__(api, erd_code)
|
|
self.erd_property = erd_property
|
|
|
|
@property
|
|
def is_on(self) -> Optional[bool]:
|
|
"""Return True if entity is on."""
|
|
try:
|
|
value = getattr(self.appliance.get_erd_value(self.erd_code), self.erd_property)
|
|
except KeyError:
|
|
return None
|
|
return boolify_erd_value(self.erd_code, value)
|
|
|
|
@property
|
|
def icon(self) -> Optional[str]:
|
|
return get_erd_icon(self.erd_code, self.is_on)
|
|
|
|
@property
|
|
def unique_id(self) -> Optional[str]:
|
|
return f"{super().unique_id}_{self.erd_property}"
|
|
|
|
@property
|
|
def name(self) -> Optional[str]:
|
|
base_string = super().name
|
|
property_name = self.erd_property.replace("_", " ").title()
|
|
return f"{base_string} {property_name}"
|
|
|
|
|
|
class GeErdSwitch(GeErdBinarySensor, SwitchEntity):
|
|
"""Switches for boolean ERD codes."""
|
|
device_class = "switch"
|
|
|
|
@property
|
|
def is_on(self) -> bool:
|
|
"""Return True if switch is on."""
|
|
return bool(self.appliance.get_erd_value(self.erd_code))
|
|
|
|
async def async_turn_on(self, **kwargs):
|
|
"""Turn the switch on."""
|
|
_LOGGER.debug(f"Turning on {self.unique_id}")
|
|
await self.appliance.async_set_erd_value(self.erd_code, True)
|
|
|
|
async def async_turn_off(self, **kwargs):
|
|
"""Turn the switch off."""
|
|
_LOGGER.debug(f"Turning on {self.unique_id}")
|
|
await self.appliance.async_set_erd_value(self.erd_code, False)
|