mirror of https://github.com/simbaja/ha_gehome.git
Merge pull request #68 from alexanv1/coffeemaker
Updates to Coffee Maker support
This commit is contained in:
commit
54880b878b
|
@ -0,0 +1,33 @@
|
|||
"""GE Home Button Entities"""
|
||||
import async_timeout
|
||||
import logging
|
||||
from typing import Callable
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .const import DOMAIN
|
||||
from .entities import GeErdButton
|
||||
from .update_coordinator import GeHomeUpdateCoordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: Callable):
|
||||
"""GE Home buttons."""
|
||||
|
||||
coordinator: GeHomeUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||
|
||||
# This should be a NOP, but let's be safe
|
||||
with async_timeout.timeout(20):
|
||||
await coordinator.initialization_future
|
||||
|
||||
apis = coordinator.appliance_apis.values()
|
||||
_LOGGER.debug(f'Found {len(apis):d} appliance APIs')
|
||||
entities = [
|
||||
entity
|
||||
for api in apis
|
||||
for entity in api.entities
|
||||
if isinstance(entity, GeErdButton)
|
||||
]
|
||||
_LOGGER.debug(f'Found {len(entities):d} buttons ')
|
||||
async_add_entities(entities)
|
|
@ -1,5 +1,4 @@
|
|||
"""Constants for the gehome integration."""
|
||||
from gehomesdk.clients.const import LOGIN_URL
|
||||
|
||||
DOMAIN = "ge_home"
|
||||
|
||||
|
|
|
@ -121,10 +121,10 @@ class ApplianceApi:
|
|||
|
||||
def build_entities_list(self) -> None:
|
||||
"""Build the entities list, adding anything new."""
|
||||
from ..entities import GeErdEntity
|
||||
from ..entities import GeErdEntity, GeErdButton
|
||||
entities = [
|
||||
e for e in self.get_all_entities()
|
||||
if not isinstance(e, GeErdEntity) or e.erd_code in self.appliance.known_properties
|
||||
if not isinstance(e, GeErdEntity) or isinstance(e, GeErdButton) or e.erd_code in self.appliance.known_properties
|
||||
]
|
||||
|
||||
for entity in entities:
|
||||
|
|
|
@ -3,16 +3,23 @@ from typing import List
|
|||
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from gehomesdk import (
|
||||
GeAppliance,
|
||||
ErdCode,
|
||||
ErdApplianceType
|
||||
ErdApplianceType,
|
||||
ErdCcmBrewSettings
|
||||
)
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
from .base import ApplianceApi
|
||||
from ..entities import (
|
||||
GeCcmPotNotPresentBinarySensor,
|
||||
GeErdSensor,
|
||||
GeErdBinarySensor,
|
||||
GeCcm
|
||||
GeErdButton,
|
||||
GeCcmBrewStrengthSelect,
|
||||
GeCcmBrewTemperatureNumber,
|
||||
GeCcmBrewCupsNumber,
|
||||
GeCcmBrewSettingsButton
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -22,23 +29,38 @@ class CcmApi(ApplianceApi):
|
|||
"""API class for Cafe Coffee Maker objects"""
|
||||
APPLIANCE_TYPE = ErdApplianceType.CAFE_COFFEE_MAKER
|
||||
|
||||
def __init__(self, coordinator: DataUpdateCoordinator, appliance: GeAppliance):
|
||||
super().__init__(coordinator, appliance)
|
||||
|
||||
self._brew_strengh_entity = GeCcmBrewStrengthSelect(self)
|
||||
self._brew_temperature_entity = GeCcmBrewTemperatureNumber(self)
|
||||
self._brew_cups_entity = GeCcmBrewCupsNumber(self)
|
||||
|
||||
def get_all_entities(self) -> List[Entity]:
|
||||
base_entities = super().get_all_entities()
|
||||
|
||||
units = self.hass.config.units
|
||||
|
||||
ccm_entities = [
|
||||
GeErdBinarySensor(self, ErdCode.CCM_IS_BREWING, device_class_override="heat"),
|
||||
GeErdBinarySensor(self, ErdCode.CCM_IS_BREWING),
|
||||
GeErdBinarySensor(self, ErdCode.CCM_IS_DESCALING),
|
||||
GeErdSensor(self, ErdCode.CCM_BREW_STRENGTH),
|
||||
GeErdSensor(self, ErdCode.CCM_BREW_CUPS),
|
||||
GeErdSensor(self, ErdCode.CCM_BREW_TEMPERATURE),
|
||||
GeCcmBrewSettingsButton(self),
|
||||
GeErdButton(self, ErdCode.CCM_CANCEL_DESCALING),
|
||||
GeErdButton(self, ErdCode.CCM_START_DESCALING),
|
||||
GeErdButton(self, ErdCode.CCM_CANCEL_BREWING),
|
||||
self._brew_strengh_entity,
|
||||
self._brew_temperature_entity,
|
||||
self._brew_cups_entity,
|
||||
GeErdSensor(self, ErdCode.CCM_CURRENT_WATER_TEMPERATURE),
|
||||
GeErdBinarySensor(self, ErdCode.CCM_OUT_OF_WATER, device_class_override="problem"),
|
||||
GeCcmPotNotPresentBinarySensor(self, ErdCode.CCM_POT_PRESENT, device_class_override="problem"),
|
||||
GeCcm(self, units)
|
||||
GeCcmPotNotPresentBinarySensor(self, ErdCode.CCM_POT_PRESENT, device_class_override="problem")
|
||||
]
|
||||
|
||||
entities = base_entities + ccm_entities
|
||||
return entities
|
||||
|
||||
async def start_brewing(self) -> None:
|
||||
"""Aggregate brew settings and start brewing."""
|
||||
|
||||
new_mode = ErdCcmBrewSettings(self._brew_cups_entity.value,
|
||||
self._brew_strengh_entity.brew_strength,
|
||||
self._brew_temperature_entity.brew_temperature)
|
||||
await self.appliance.async_set_erd_value(ErdCode.CCM_BREW_SETTINGS, new_mode)
|
|
@ -1,2 +1,5 @@
|
|||
from .ge_ccm_pot_not_present_binary_sensor import GeCcmPotNotPresentBinarySensor
|
||||
from .ge_ccm import GeCcm
|
||||
from .ge_ccm_brew_strength import GeCcmBrewStrengthSelect
|
||||
from .ge_ccm_brew_temperature import GeCcmBrewTemperatureNumber
|
||||
from .ge_ccm_brew_cups import GeCcmBrewCupsNumber
|
||||
from .ge_ccm_brew_settings import GeCcmBrewSettingsButton
|
|
@ -1,8 +0,0 @@
|
|||
from homeassistant.components.water_heater import (
|
||||
SUPPORT_OPERATION_MODE,
|
||||
SUPPORT_TARGET_TEMPERATURE
|
||||
)
|
||||
|
||||
GE_CCM = SUPPORT_OPERATION_MODE | SUPPORT_TARGET_TEMPERATURE
|
||||
MAX_CUPS = 10
|
||||
MIN_CUPS = 2
|
|
@ -1,150 +0,0 @@
|
|||
"""GE Home Sensor Entities - Advantium"""
|
||||
import logging
|
||||
from typing import Any, Dict, List, Mapping, Optional, Set
|
||||
from random import randrange
|
||||
|
||||
from gehomesdk import (
|
||||
ErdCode,
|
||||
ErdUnitType,
|
||||
ErdCcmBrewSettings,
|
||||
ErdCcmBrewStrength
|
||||
)
|
||||
|
||||
from homeassistant.const import ATTR_TEMPERATURE
|
||||
from homeassistant.util.unit_system import UnitSystem
|
||||
|
||||
from ...const import DOMAIN
|
||||
from ...devices import ApplianceApi
|
||||
from ..common import GeWaterHeater
|
||||
from .const import *
|
||||
from .ge_ccm_options import CcmBrewOptionsConverter
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
class GeCcm(GeWaterHeater):
|
||||
"""GE Appliance Cafe Coffee Maker"""
|
||||
|
||||
icon = "mdi:coffee-maker"
|
||||
|
||||
def __init__(self, api: ApplianceApi, units: UnitSystem):
|
||||
super().__init__(api)
|
||||
self._options = CcmBrewOptionsConverter(units)
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
return GE_CCM
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
return f"{DOMAIN}_{self.serial_number}"
|
||||
|
||||
@property
|
||||
def name(self) -> Optional[str]:
|
||||
return f"{self.serial_number} Coffee Maker"
|
||||
|
||||
@property
|
||||
def unit_type(self) -> Optional[ErdUnitType]:
|
||||
try:
|
||||
return self.appliance.get_erd_value(ErdCode.UNIT_TYPE)
|
||||
except:
|
||||
return None
|
||||
|
||||
@property
|
||||
def current_temperature(self) -> Optional[int]:
|
||||
return self.appliance.get_erd_value(ErdCode.CCM_CURRENT_WATER_TEMPERATURE)
|
||||
|
||||
@property
|
||||
def is_brewing(self) -> bool:
|
||||
return self.appliance.get_erd_value(ErdCode.CCM_IS_BREWING)
|
||||
|
||||
@property
|
||||
def is_descaling(self) -> bool:
|
||||
return self.appliance.get_erd_value(ErdCode.CCM_IS_DESCALING)
|
||||
|
||||
@property
|
||||
def current_operation(self) -> Optional[str]:
|
||||
try:
|
||||
settings: ErdCcmBrewSettings = self.appliance.get_erd_value(ErdCode.CCM_BREW_SETTINGS)
|
||||
if self.is_descaling:
|
||||
return "Descale"
|
||||
if not self.is_brewing:
|
||||
return "Off"
|
||||
return self._options.to_option_string(settings)
|
||||
except:
|
||||
return None
|
||||
|
||||
@property
|
||||
def operation_list(self) -> List[str]:
|
||||
return self._options.options
|
||||
|
||||
@property
|
||||
def current_brew_setting(self) -> ErdCcmBrewSettings:
|
||||
"""Get the current brew setting."""
|
||||
return self.appliance.get_erd_value(ErdCode.CCM_BREW_SETTINGS)
|
||||
|
||||
@property
|
||||
def target_temperature(self) -> Optional[int]:
|
||||
"""Return the temperature we try to reach."""
|
||||
try:
|
||||
return self.appliance.get_erd_value(ErdCode.CCM_BREW_TEMPERATURE)
|
||||
except:
|
||||
pass
|
||||
return None
|
||||
|
||||
@property
|
||||
def min_temp(self) -> int:
|
||||
"""Return the minimum temperature."""
|
||||
min_temp, _, _ = self.appliance.get_erd_value(ErdCode.CCM_BREW_TEMPERATURE_RANGE)
|
||||
return min_temp
|
||||
|
||||
@property
|
||||
def max_temp(self) -> int:
|
||||
"""Return the maximum temperature."""
|
||||
_, max_temp, _ = self.appliance.get_erd_value(ErdCode.CCM_BREW_TEMPERATURE_RANGE)
|
||||
return max_temp
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> Optional[Mapping[str, Any]]:
|
||||
data = {}
|
||||
|
||||
data["unit_type"] = self._stringify(self.unit_type)
|
||||
|
||||
return data
|
||||
|
||||
@property
|
||||
def can_set_temperature(self) -> bool:
|
||||
"""Indicates whether we can set the temperature based on the current mode"""
|
||||
return not self.is_descaling
|
||||
|
||||
async def async_set_operation_mode(self, operation_mode: str):
|
||||
"""Set the operation mode."""
|
||||
|
||||
#try to get the mode/setting for the selection
|
||||
try:
|
||||
if operation_mode not in ["Off","Descale"]:
|
||||
new_mode = self._options.from_option_string(operation_mode)
|
||||
new_mode = ErdCcmBrewSettings(new_mode.number_of_cups, new_mode.brew_strength, self.target_temperature)
|
||||
|
||||
await self.appliance.async_set_erd_value(ErdCode.CCM_BREW_SETTINGS, new_mode)
|
||||
elif operation_mode == "Off":
|
||||
await self.appliance.async_set_erd_value(ErdCode.CCM_CANCEL_BREWING, True)
|
||||
await self.appliance.async_set_erd_value(ErdCode.CCM_CANCEL_DESCALING, True)
|
||||
elif operation_mode == "Descale":
|
||||
await self.appliance.async_set_erd_value(ErdCode.CCM_START_DESCALING, True)
|
||||
except:
|
||||
_LOGGER.error(f"Error Attempting to set mode to {operation_mode}.", exc_info=True)
|
||||
|
||||
async def async_set_temperature(self, **kwargs):
|
||||
"""Set the brew temperature"""
|
||||
|
||||
target_temp = kwargs.get(ATTR_TEMPERATURE)
|
||||
if target_temp is None:
|
||||
return
|
||||
|
||||
# get the current strength/cups
|
||||
strength: ErdCcmBrewStrength = self.appliance.get_erd_value(ErdCode.CCM_BREW_STRENGTH)
|
||||
cups: int = self.appliance.get_erd_value(ErdCode.CCM_BREW_CUPS)
|
||||
new_mode = ErdCcmBrewSettings(cups, strength, target_temp)
|
||||
|
||||
await self.appliance.async_set_erd_value(ErdCode.CCM_BREW_SETTINGS, new_mode)
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
from gehomesdk import ErdCode
|
||||
from ...devices import ApplianceApi
|
||||
from ..common import GeErdNumber
|
||||
from .ge_ccm_cached_value import GeCcmCachedValue
|
||||
|
||||
class GeCcmBrewCupsNumber(GeErdNumber, GeCcmCachedValue):
|
||||
def __init__(self, api: ApplianceApi):
|
||||
GeErdNumber.__init__(self, api = api, erd_code = ErdCode.CCM_BREW_CUPS, min_value=1, max_value=10, mode="box")
|
||||
GeCcmCachedValue.__init__(self)
|
||||
|
||||
self._set_value = None
|
||||
|
||||
async def async_set_value(self, value):
|
||||
GeCcmCachedValue.set_value(self, value)
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self.get_value(device_value = super().value)
|
|
@ -0,0 +1,13 @@
|
|||
from gehomesdk import ErdCode
|
||||
from ...devices import ApplianceApi
|
||||
from ..common import GeErdButton
|
||||
|
||||
class GeCcmBrewSettingsButton(GeErdButton):
|
||||
def __init__(self, api: ApplianceApi):
|
||||
super().__init__(api, erd_code=ErdCode.CCM_BREW_SETTINGS)
|
||||
|
||||
async def async_press(self) -> None:
|
||||
"""Handle the button press."""
|
||||
|
||||
# Forward the call up to the Coffee Maker device to handle
|
||||
await self.api.start_brewing()
|
|
@ -0,0 +1,47 @@
|
|||
import logging
|
||||
from typing import List, Any, Optional
|
||||
|
||||
from gehomesdk import ErdCode, ErdCcmBrewStrength
|
||||
from ...devices import ApplianceApi
|
||||
from ..common import GeErdSelect, OptionsConverter
|
||||
from .ge_ccm_cached_value import GeCcmCachedValue
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
class GeCcmBrewStrengthOptionsConverter(OptionsConverter):
|
||||
def __init__(self):
|
||||
self._default = ErdCcmBrewStrength.MEDIUM
|
||||
|
||||
@property
|
||||
def options(self) -> List[str]:
|
||||
return [i.stringify() for i in [ErdCcmBrewStrength.LIGHT, ErdCcmBrewStrength.MEDIUM, ErdCcmBrewStrength.BOLD, ErdCcmBrewStrength.GOLD]]
|
||||
|
||||
def from_option_string(self, value: str) -> Any:
|
||||
try:
|
||||
return ErdCcmBrewStrength[value.upper()]
|
||||
except:
|
||||
_LOGGER.warn(f"Could not set brew strength to {value.upper()}")
|
||||
return self._default
|
||||
|
||||
def to_option_string(self, value: ErdCcmBrewStrength) -> Optional[str]:
|
||||
try:
|
||||
return value.stringify()
|
||||
except:
|
||||
return self._default.stringify()
|
||||
|
||||
class GeCcmBrewStrengthSelect(GeErdSelect, GeCcmCachedValue):
|
||||
def __init__(self, api: ApplianceApi):
|
||||
GeErdSelect.__init__(self, api = api, erd_code = ErdCode.CCM_BREW_STRENGTH, converter = GeCcmBrewStrengthOptionsConverter())
|
||||
GeCcmCachedValue.__init__(self)
|
||||
|
||||
@property
|
||||
def brew_strength(self) -> ErdCcmBrewStrength:
|
||||
return self._converter.from_option_string(self.current_option)
|
||||
|
||||
async def async_select_option(self, value):
|
||||
GeCcmCachedValue.set_value(self, value)
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def current_option(self):
|
||||
return self.get_value(device_value = super().current_option)
|
|
@ -0,0 +1,22 @@
|
|||
from gehomesdk import ErdCode
|
||||
from ...devices import ApplianceApi
|
||||
from ..common import GeErdNumber
|
||||
from .ge_ccm_cached_value import GeCcmCachedValue
|
||||
|
||||
class GeCcmBrewTemperatureNumber(GeErdNumber, GeCcmCachedValue):
|
||||
def __init__(self, api: ApplianceApi):
|
||||
min_temp, max_temp, _ = api.appliance.get_erd_value(ErdCode.CCM_BREW_TEMPERATURE_RANGE)
|
||||
GeErdNumber.__init__(self, api = api, erd_code = ErdCode.CCM_BREW_TEMPERATURE, min_value=min_temp, max_value=max_temp, mode="slider")
|
||||
GeCcmCachedValue.__init__(self)
|
||||
|
||||
async def async_set_value(self, value):
|
||||
GeCcmCachedValue.set_value(self, value)
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return int(self.get_value(device_value = super().value))
|
||||
|
||||
@property
|
||||
def brew_temperature(self) -> int:
|
||||
return self.value
|
|
@ -0,0 +1,20 @@
|
|||
class GeCcmCachedValue():
|
||||
def __init__(self):
|
||||
self._set_value = None
|
||||
self._last_device_value = None
|
||||
|
||||
def get_value(self, device_value):
|
||||
|
||||
# If the last device value is different from the current one, return the device value which overrides the set value
|
||||
if self._last_device_value != device_value:
|
||||
self._last_device_value = device_value
|
||||
self._set_value = None
|
||||
return device_value
|
||||
|
||||
if self._set_value is not None:
|
||||
return self._set_value
|
||||
|
||||
return device_value
|
||||
|
||||
def set_value(self, set_value):
|
||||
self._set_value = set_value
|
|
@ -1,61 +0,0 @@
|
|||
import logging
|
||||
from typing import List, Any, NamedTuple, Optional
|
||||
|
||||
from gehomesdk import ErdCcmBrewStrength, ErdCcmBrewSettings
|
||||
from homeassistant.const import TEMP_FAHRENHEIT
|
||||
from homeassistant.util.unit_system import UnitSystem
|
||||
|
||||
from custom_components.ge_home.entities.ccm.const import MAX_CUPS, MIN_CUPS
|
||||
from ..common import OptionsConverter
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
class CcmBrewOption(NamedTuple):
|
||||
strength: ErdCcmBrewStrength
|
||||
cups: int
|
||||
|
||||
def stringify(self):
|
||||
return f"{self.strength.stringify()} -- {self.cups} cups"
|
||||
|
||||
class CcmBrewOptionsConverter(OptionsConverter):
|
||||
def __init__(self, units: UnitSystem):
|
||||
super().__init__()
|
||||
self._units = units
|
||||
self._options = self._build_options()
|
||||
|
||||
@property
|
||||
def options(self) -> List[str]:
|
||||
options = ["Off"]
|
||||
options.extend([i.stringify() for i in self._options])
|
||||
options.extend(["Descale"])
|
||||
|
||||
return options
|
||||
|
||||
def from_option_string(self, value: str) -> Optional[ErdCcmBrewSettings]:
|
||||
try:
|
||||
if value in ["Off","Descale"]:
|
||||
return None
|
||||
s = value.split(" -- ")[0].upper()
|
||||
c = value.split(" -- ")[1].replace(" cups","")
|
||||
return ErdCcmBrewSettings(int(c), ErdCcmBrewStrength[s], 200)
|
||||
except:
|
||||
_LOGGER.error(f"Could not convert brew options '{value}'", exc_info=True)
|
||||
|
||||
#return a default if we can't interpret it
|
||||
return ErdCcmBrewSettings(4, ErdCcmBrewStrength.MEDIUM, 200)
|
||||
|
||||
def to_option_string(self, value: ErdCcmBrewSettings) -> Optional[str]:
|
||||
try:
|
||||
o = CcmBrewOption(value.brew_strength, value.number_of_cups)
|
||||
return o.stringify()
|
||||
except:
|
||||
#return a default if we can't interpret it
|
||||
return CcmBrewOption(ErdCcmBrewStrength.MEDIUM, 4)
|
||||
|
||||
def _build_options(self) -> List[CcmBrewOption]:
|
||||
options = []
|
||||
for s in filter(lambda x: x != ErdCcmBrewStrength.UNKNOWN, ErdCcmBrewStrength):
|
||||
for c in range(MIN_CUPS, MAX_CUPS, 2):
|
||||
options.append(CcmBrewOption(s, c))
|
||||
|
||||
return options
|
|
@ -9,6 +9,8 @@ from .ge_erd_light import GeErdLight
|
|||
from .ge_erd_timer_sensor import GeErdTimerSensor
|
||||
from .ge_erd_property_sensor import GeErdPropertySensor
|
||||
from .ge_erd_switch import GeErdSwitch
|
||||
from .ge_erd_button import GeErdButton
|
||||
from .ge_erd_number import GeErdNumber
|
||||
from .ge_water_heater import GeWaterHeater
|
||||
from .ge_erd_select import GeErdSelect
|
||||
from .ge_climate import GeClimate
|
|
@ -0,0 +1,17 @@
|
|||
from typing import Optional
|
||||
|
||||
from homeassistant.components.button import ButtonEntity
|
||||
|
||||
from gehomesdk import ErdCodeType
|
||||
from ...devices import ApplianceApi
|
||||
from .ge_erd_entity import GeErdEntity
|
||||
|
||||
|
||||
class GeErdButton(GeErdEntity, ButtonEntity):
|
||||
def __init__(self, api: ApplianceApi, erd_code: ErdCodeType, erd_override: str = None):
|
||||
super().__init__(api, erd_code, erd_override=erd_override)
|
||||
|
||||
"""GE Entity for buttons"""
|
||||
async def async_press(self) -> None:
|
||||
"""Handle the button press."""
|
||||
await self.appliance.async_set_erd_value(self.erd_code, True)
|
|
@ -83,7 +83,7 @@ class GeErdEntity(GeEntity):
|
|||
try:
|
||||
value = self.appliance.get_erd_value(ErdCode.TEMPERATURE_UNIT)
|
||||
except KeyError:
|
||||
return None
|
||||
return ErdMeasurementUnits.Imperial
|
||||
return value
|
||||
|
||||
def _get_icon(self):
|
||||
|
@ -143,5 +143,7 @@ class GeErdEntity(GeEntity):
|
|||
return "mdi:snowflake"
|
||||
if self.erd_code_class == ErdCodeClass.WATERSOFTENER_SENSOR:
|
||||
return "mdi:water"
|
||||
if self.erd_code_class == ErdCodeClass.CCM_SENSOR:
|
||||
return "mdi:coffee-maker"
|
||||
|
||||
return None
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
import logging
|
||||
from typing import Optional
|
||||
from gehomesdk.erd.erd_data_type import ErdDataType
|
||||
from homeassistant.components.number import NumberEntity
|
||||
|
||||
from homeassistant.const import (
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
TEMP_FAHRENHEIT,
|
||||
)
|
||||
from gehomesdk import ErdCodeType, ErdCodeClass
|
||||
from .ge_erd_entity import GeErdEntity
|
||||
from ...devices import ApplianceApi
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
class GeErdNumber(GeErdEntity, NumberEntity):
|
||||
"""GE Entity for numbers"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
api: ApplianceApi,
|
||||
erd_code: ErdCodeType,
|
||||
erd_override: str = None,
|
||||
icon_override: str = None,
|
||||
device_class_override: str = None,
|
||||
uom_override: str = None,
|
||||
data_type_override: ErdDataType = None,
|
||||
min_value: float = 1,
|
||||
max_value: float = 100,
|
||||
step_value: float = 1,
|
||||
mode: str = "auto"
|
||||
):
|
||||
super().__init__(api, erd_code, erd_override, icon_override, device_class_override)
|
||||
self._uom_override = uom_override
|
||||
self._data_type_override = data_type_override
|
||||
self._min_value = min_value
|
||||
self._max_value = max_value
|
||||
self._step_value = step_value
|
||||
self._mode = mode
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
try:
|
||||
value = self.appliance.get_erd_value(self.erd_code)
|
||||
return self._convert_value_from_device(value)
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self) -> Optional[str]:
|
||||
return self._get_uom()
|
||||
|
||||
@property
|
||||
def _data_type(self) -> ErdDataType:
|
||||
if self._data_type_override is not None:
|
||||
return self._data_type_override
|
||||
|
||||
return self.appliance.get_erd_code_data_type(self.erd_code)
|
||||
|
||||
@property
|
||||
def min_value(self) -> float:
|
||||
return self._convert_value_from_device(self._min_value)
|
||||
|
||||
@property
|
||||
def max_value(self) -> float:
|
||||
return self._convert_value_from_device(self._max_value)
|
||||
|
||||
@property
|
||||
def step(self) -> float:
|
||||
return self._step_value
|
||||
|
||||
@property
|
||||
def mode(self) -> float:
|
||||
return self._mode
|
||||
|
||||
def _convert_value_from_device(self, value):
|
||||
"""Convert to expected data type"""
|
||||
|
||||
if self._data_type == ErdDataType.INT:
|
||||
return int(round(value))
|
||||
else:
|
||||
return value
|
||||
|
||||
def _get_uom(self):
|
||||
"""Select appropriate units"""
|
||||
|
||||
#if we have an override, just use it
|
||||
if self._uom_override:
|
||||
return self._uom_override
|
||||
|
||||
if self.device_class == DEVICE_CLASS_TEMPERATURE:
|
||||
#NOTE: it appears that the API only sets temperature in Fahrenheit,
|
||||
#so we'll hard code this UOM instead of using the device configured
|
||||
#settings
|
||||
return TEMP_FAHRENHEIT
|
||||
|
||||
return None
|
||||
|
||||
def _get_device_class(self) -> Optional[str]:
|
||||
if self._device_class_override:
|
||||
return self._device_class_override
|
||||
|
||||
if self.erd_code_class in [
|
||||
ErdCodeClass.RAW_TEMPERATURE,
|
||||
ErdCodeClass.NON_ZERO_TEMPERATURE,
|
||||
]:
|
||||
return DEVICE_CLASS_TEMPERATURE
|
||||
|
||||
return None
|
||||
|
||||
def _get_icon(self):
|
||||
if self.erd_code_class == ErdCodeClass.DOOR:
|
||||
if self.state.lower().endswith("open"):
|
||||
return "mdi:door-open"
|
||||
if self.state.lower().endswith("closed"):
|
||||
return "mdi:door-closed"
|
||||
return super()._get_icon()
|
||||
|
||||
async def async_set_value(self, value):
|
||||
"""Sets the ERD value, assumes that the data type is correct"""
|
||||
|
||||
if self._data_type == ErdDataType.INT:
|
||||
value = int(round(value))
|
||||
|
||||
try:
|
||||
await self.appliance.async_set_erd_value(self.erd_code, value)
|
||||
except:
|
||||
_LOGGER.warning(f"Could not set {self.name} to {value}")
|
|
@ -9,11 +9,9 @@ from homeassistant.const import (
|
|||
DEVICE_CLASS_TEMPERATURE,
|
||||
DEVICE_CLASS_BATTERY,
|
||||
DEVICE_CLASS_POWER_FACTOR,
|
||||
DEVICE_CLASS_TIMESTAMP,
|
||||
TEMP_CELSIUS,
|
||||
TEMP_FAHRENHEIT,
|
||||
)
|
||||
from gehomesdk import ErdCode, ErdCodeType, ErdCodeClass, ErdMeasurementUnits
|
||||
from gehomesdk import ErdCodeType, ErdCodeClass
|
||||
from .ge_erd_entity import GeErdEntity
|
||||
from ...devices import ApplianceApi
|
||||
|
||||
|
@ -45,7 +43,7 @@ class GeErdSensor(GeErdEntity, SensorEntity):
|
|||
|
||||
# if it's a numeric data type, return it directly
|
||||
if self._data_type in [ErdDataType.INT, ErdDataType.FLOAT]:
|
||||
return value
|
||||
return self._convert_numeric_value_from_device(value)
|
||||
|
||||
# otherwise, return a stringified version
|
||||
# TODO: perhaps enhance so that there's a list of variables available
|
||||
|
@ -80,6 +78,14 @@ class GeErdSensor(GeErdEntity, SensorEntity):
|
|||
# return TEMP_CELSIUS
|
||||
#return TEMP_FAHRENHEIT
|
||||
|
||||
def _convert_numeric_value_from_device(self, value):
|
||||
"""Convert to expected data type"""
|
||||
|
||||
if self._data_type == ErdDataType.INT:
|
||||
return int(round(value))
|
||||
else:
|
||||
return value
|
||||
|
||||
def _get_uom(self):
|
||||
"""Select appropriate units"""
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "GE Home (SmartHQ)",
|
||||
"config_flow": true,
|
||||
"documentation": "https://github.com/simbaja/ha_gehome",
|
||||
"requirements": ["gehomesdk==0.4.21","magicattr==0.1.5"],
|
||||
"requirements": ["gehomesdk==0.4.22","magicattr==0.1.5","slixmpp==1.7.1"],
|
||||
"codeowners": ["@simbaja"],
|
||||
"version": "0.6.0"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
"""GE Home Number Entities"""
|
||||
import async_timeout
|
||||
import logging
|
||||
from typing import Callable
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .const import DOMAIN
|
||||
from .entities import GeErdNumber
|
||||
from .update_coordinator import GeHomeUpdateCoordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: Callable):
|
||||
"""GE Home numbers."""
|
||||
|
||||
coordinator: GeHomeUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||
|
||||
# This should be a NOP, but let's be safe
|
||||
with async_timeout.timeout(20):
|
||||
await coordinator.initialization_future
|
||||
|
||||
apis = coordinator.appliance_apis.values()
|
||||
_LOGGER.debug(f'Found {len(apis):d} appliance APIs')
|
||||
entities = [
|
||||
entity
|
||||
for api in apis
|
||||
for entity in api.entities
|
||||
if isinstance(entity, GeErdNumber)
|
||||
]
|
||||
_LOGGER.debug(f'Found {len(entities):d} numbers ')
|
||||
async_add_entities(entities)
|
|
@ -34,7 +34,7 @@ from .const import (
|
|||
)
|
||||
from .devices import ApplianceApi, get_appliance_api_type
|
||||
|
||||
PLATFORMS = ["binary_sensor", "sensor", "switch", "water_heater", "select", "climate", "light"]
|
||||
PLATFORMS = ["binary_sensor", "sensor", "switch", "water_heater", "select", "climate", "light", "button", "number"]
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -261,6 +261,7 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
|
|||
api = self.appliance_apis[appliance.mac_addr]
|
||||
except KeyError:
|
||||
return
|
||||
|
||||
for entity in api.entities:
|
||||
if entity.enabled:
|
||||
_LOGGER.debug(f"Updating {entity} ({entity.unique_id}, {entity.entity_id})")
|
||||
|
|
Loading…
Reference in New Issue