Merge pull request #16 from bendavis/water-filter-support

Add Support for GE Water Filters
This commit is contained in:
simbaja 2021-07-08 14:58:36 -04:00 committed by GitHub
commit 459fc7f5cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 313 additions and 74 deletions

View File

@ -5,16 +5,16 @@ import voluptuous as vol
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from .const import (
DOMAIN
)
from .const import DOMAIN
from .update_coordinator import GeHomeUpdateCoordinator
CONFIG_SCHEMA = vol.Schema({DOMAIN: vol.Schema({})}, extra=vol.ALLOW_EXTRA)
async def async_setup(hass: HomeAssistant, config: dict):
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
"""Set up the ge_home component."""
hass.data.setdefault(DOMAIN, {})
@ -30,15 +30,17 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
"""Unload a config entry."""
coordinator: GeHomeUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
coordinator: GeHomeUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
ok = await coordinator.async_reset()
if ok:
hass.data[DOMAIN].pop(entry.entry_id)
return ok
async def async_update_options(hass, config_entry):
"""Update options."""
await hass.config_entries.async_reload(config_entry.entry_id)

View File

@ -10,9 +10,11 @@ from .dishwasher import DishwasherApi
from .washer import WasherApi
from .dryer import DryerApi
from .washer_dryer import WasherDryerApi
from .waterfilter import WaterFilterApi
_LOGGER = logging.getLogger(__name__)
def get_appliance_api_type(appliance_type: ErdApplianceType) -> Type:
_LOGGER.debug(f"Found device type: {appliance_type}")
"""Get the appropriate appliance type"""
@ -28,5 +30,8 @@ def get_appliance_api_type(appliance_type: ErdApplianceType) -> Type:
return DryerApi
if appliance_type == ErdApplianceType.COMBINATION_WASHER_DRYER:
return WasherDryerApi
if appliance_type == ErdApplianceType.POE_WATER_FILTER:
return WaterFilterApi
# Fallback
return ApplianceApi

View File

@ -48,4 +48,4 @@ class WasherApi(ApplianceApi):
if self.has_erd_code(ErdCode.LAUNDRY_WASHER_TANK_SELECTED):
washer_entities.extend([GeErdSensor(self, ErdCode.LAUNDRY_WASHER_TANK_SELECTED)])
return washer_entities
return washer_entities

View File

@ -0,0 +1,39 @@
from homeassistant.components.select import SelectEntity
import logging
from typing import List
from homeassistant.helpers.entity import Entity
from gehomesdk.erd import ErdCode, ErdApplianceType
from .base import ApplianceApi
from ..entities import (
GeErdSensor,
GeErdBinarySensor,
ErdFlowRateSensor,
ErdFilterLifeRemainingSensor,
ErdFilterPositionSelect,
)
_LOGGER = logging.getLogger(__name__)
class WaterFilterApi(ApplianceApi):
"""API class for water filter objects"""
APPLIANCE_TYPE = ErdApplianceType.POE_WATER_FILTER
def get_all_entities(self) -> List[Entity]:
base_entities = super().get_all_entities()
wf_entities = [
GeErdSensor(self, ErdCode.WH_FILTER_MODE),
GeErdSensor(self, ErdCode.WH_FILTER_VALVE_STATE),
ErdFilterPositionSelect(self, ErdCode.WH_FILTER_POSITION),
GeErdBinarySensor(self, ErdCode.WH_FILTER_MANUAL_MODE),
ErdFlowRateSensor(self, ErdCode.WH_FILTER_FLOW_RATE),
GeErdSensor(self, ErdCode.WH_FILTER_DAY_USAGE),
ErdFilterLifeRemainingSensor(self, ErdCode.WH_FILTER_LIFE_REMAINING),
GeErdBinarySensor(self, ErdCode.WH_FILTER_FLOW_ALERT),
]
entities = base_entities + wf_entities
return entities

View File

@ -2,3 +2,4 @@ from .common import *
from .dishwasher import *
from .fridge import *
from .oven import *
from .waterfilter import *

View File

@ -5,4 +5,5 @@ from .ge_erd_property_binary_sensor import GeErdPropertyBinarySensor
from .ge_erd_sensor import GeErdSensor
from .ge_erd_property_sensor import GeErdPropertySensor
from .ge_erd_switch import GeErdSwitch
from .ge_water_heater import GeWaterHeater
from .ge_water_heater import GeWaterHeater
from .ge_erd_select import GeErdSelect

View File

@ -11,7 +11,15 @@ from .ge_entity import GeEntity
class GeErdEntity(GeEntity):
"""Parent class for GE entities tied to a specific ERD"""
def __init__(self, api: ApplianceApi, erd_code: ErdCodeType, erd_override: str = None, icon_override: str = None, device_class_override: str = None):
def __init__(
self,
api: ApplianceApi,
erd_code: ErdCodeType,
erd_override: str = None,
icon_override: str = None,
device_class_override: str = None,
):
super().__init__(api)
self._erd_code = api.appliance.translate_erd_code(erd_code)
self._erd_code_class = api.appliance.get_erd_code_class(self._erd_code)
@ -21,11 +29,11 @@ class GeErdEntity(GeEntity):
if not self._erd_code_class:
self._erd_code_class = ErdCodeClass.GENERAL
@property
def erd_code(self) -> ErdCodeType:
return self._erd_code
@property
def erd_code_class(self) -> ErdCodeClass:
return self._erd_code_class
@ -40,8 +48,8 @@ class GeErdEntity(GeEntity):
@property
def name(self) -> Optional[str]:
erd_string = self.erd_string
#override the name if specified
# override the name if specified
if self._erd_override != None:
erd_string = self._erd_override
@ -53,10 +61,10 @@ class GeErdEntity(GeEntity):
return f"{DOMAIN}_{self.serial_number}_{self.erd_string.lower()}"
def _stringify(self, value: any, **kwargs) -> Optional[str]:
""" Stringify a value """
"""Stringify a value"""
# perform special processing before passing over to the default method
if self.erd_code == ErdCode.CLOCK_TIME:
return value.strftime("%H:%M:%S") if value else None
return value.strftime("%H:%M:%S") if value else None
if self.erd_code_class == ErdCodeClass.RAW_TEMPERATURE:
return f"{value}"
if self.erd_code_class == ErdCodeClass.NON_ZERO_TEMPERATURE:
@ -106,5 +114,7 @@ class GeErdEntity(GeEntity):
return "mdi:cup-water"
if self.erd_code_class == ErdCodeClass.DISHWASHER_SENSOR:
return "mdi:dishwasher"
if self.erd_code_class == ErdCodeClass.WATERFILTER_SENSOR:
return "mdi:water"
return None

View File

@ -0,0 +1,11 @@
import logging
from homeassistant.components.select import SelectEntity
_LOGGER = logging.getLogger(__name__)
class GeErdSelect(SelectEntity):
"""Switches for boolean ERD codes."""
device_class = "select"

View File

@ -1,19 +1,21 @@
from typing import Optional
from homeassistant.const import (
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_POWER_FACTOR,
TEMP_CELSIUS,
TEMP_FAHRENHEIT
TEMP_CELSIUS,
TEMP_FAHRENHEIT,
)
from homeassistant.helpers.entity import Entity
from gehomesdk import ErdCode, ErdCodeClass, ErdMeasurementUnits
from .ge_erd_entity import GeErdEntity
class GeErdSensor(GeErdEntity, Entity):
class GeErdSensor(GeErdEntity, Entity):
"""GE Entity for sensors"""
@property
def state(self) -> Optional[str]:
try:
@ -35,15 +37,19 @@ class GeErdSensor(GeErdEntity, Entity):
return TEMP_FAHRENHEIT
def _get_uom(self):
""" Select appropriate units """
"""Select appropriate units"""
if (
self.erd_code_class in [ErdCodeClass.RAW_TEMPERATURE,ErdCodeClass.NON_ZERO_TEMPERATURE] or
self.device_class == DEVICE_CLASS_TEMPERATURE
self.erd_code_class
in [ErdCodeClass.RAW_TEMPERATURE, ErdCodeClass.NON_ZERO_TEMPERATURE]
or self.device_class == DEVICE_CLASS_TEMPERATURE
):
if self._temp_measurement_system == ErdMeasurementUnits.METRIC:
return TEMP_CELSIUS
return TEMP_FAHRENHEIT
if self.erd_code_class == ErdCodeClass.BATTERY or self.device_class == DEVICE_CLASS_BATTERY:
if (
self.erd_code_class == ErdCodeClass.BATTERY
or self.device_class == DEVICE_CLASS_BATTERY
):
return "%"
if self.erd_code_class == ErdCodeClass.PERCENTAGE:
return "%"
@ -54,7 +60,10 @@ class GeErdSensor(GeErdEntity, Entity):
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]:
if self.erd_code_class in [
ErdCodeClass.RAW_TEMPERATURE,
ErdCodeClass.NON_ZERO_TEMPERATURE,
]:
return DEVICE_CLASS_TEMPERATURE
if self.erd_code_class == ErdCodeClass.BATTERY:
return DEVICE_CLASS_BATTERY

View File

@ -0,0 +1,3 @@
from .flow_rate_sensor import ErdFlowRateSensor
from .filter_life_remaining import ErdFilterLifeRemainingSensor
from .filter_position import ErdFilterPositionSelect

View File

@ -0,0 +1,19 @@
from gehomesdk import ErdCode, ErdOperatingMode
from gehomesdk.erd.values.common.erd_measurement_units import ErdMeasurementUnits
from typing import Optional
from ..common import GeErdSensor
class ErdFilterLifeRemainingSensor(GeErdSensor):
@property
def state(self) -> Optional[int]:
try:
value = self.appliance.get_erd_value(self.erd_code)
except KeyError:
return None
return value.life_remaining
@property
def unit_of_measurement(self) -> Optional[str]:
return "%"

View File

@ -0,0 +1,51 @@
from homeassistant.components.ge_home.entities.common.ge_erd_select import GeErdSelect
from homeassistant.components.ge_home.entities.common.ge_erd_entity import GeErdEntity
from homeassistant.components.ge_home.devices.base import ApplianceApi
import logging
from typing import Optional, Dict, Any
from gehomesdk import ErdCode, ErdCodeClass, ErdCodeType
from gehomesdk.erd.values.waterfilter.erd_waterfilter_position import (
ErdWaterFilterPosition,
)
from ...const import DOMAIN
_LOGGER = logging.getLogger(__name__)
class ErdFilterPositionSelect(GeErdEntity, GeErdSelect):
def __init__(
self,
api: ApplianceApi,
erd_code: ErdCodeType,
):
super().__init__(api=api, erd_code=erd_code)
self._attr_hass = api._hass
self.hass = api._hass
self._attr_unique_id = self.unique_id
self._attr_name = self.name
self._attr_current_option = ErdWaterFilterPosition.UNKNOWN.name
self._attr_icon = self.icon
self._attr_device_class = self.device_class
self._attr_options = [
ErdWaterFilterPosition.BYPASS.name,
ErdWaterFilterPosition.OFF.name,
ErdWaterFilterPosition.FILTERED.name,
ErdWaterFilterPosition.READY.name,
]
self._attr_device_info = self.device_info
async def async_select_option(self, option: str) -> None:
if (
option == ErdWaterFilterPosition.READY.name
or option == ErdWaterFilterPosition.UNKNOWN.name
):
return
await self.api.appliance.async_set_erd_value(
self.erd_code, ErdWaterFilterPosition[option]
)
@property
def icon(self) -> str:
return "mdi:water"

View File

@ -0,0 +1,21 @@
from gehomesdk import ErdCode, ErdOperatingMode
from gehomesdk.erd.values.common.erd_measurement_units import ErdMeasurementUnits
from typing import Optional
from ..common import GeErdSensor
class ErdFlowRateSensor(GeErdSensor):
@property
def state(self) -> Optional[float]:
try:
value = self.appliance.get_erd_value(self.erd_code)
except KeyError:
return None
return value.flow_rate
@property
def unit_of_measurement(self) -> Optional[str]:
if self._temp_measurement_system == ErdMeasurementUnits.METRIC:
return "lpm"
return "gpm"

View File

@ -0,0 +1,38 @@
"""GE Home Sensor 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 GeErdSelect
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 selects."""
_LOGGER.debug("Adding GE Home selects")
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
_LOGGER.debug("Coordinator init future finished")
apis = list(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, GeErdSelect)
and entity.erd_code in api.appliance._property_cache
]
_LOGGER.debug(f"Found {len(entities):d} selectors")
async_add_entities(entities)

View File

@ -24,19 +24,20 @@ from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import (
DOMAIN,
EVENT_ALL_APPLIANCES_READY,
UPDATE_INTERVAL,
MIN_RETRY_DELAY,
MAX_RETRY_DELAY,
DOMAIN,
EVENT_ALL_APPLIANCES_READY,
UPDATE_INTERVAL,
MIN_RETRY_DELAY,
MAX_RETRY_DELAY,
RETRY_OFFLINE_COUNT,
ASYNC_TIMEOUT
ASYNC_TIMEOUT,
)
from .devices import ApplianceApi, get_appliance_api_type
PLATFORMS = ["binary_sensor", "sensor", "switch", "water_heater"]
PLATFORMS = ["binary_sensor", "sensor", "switch", "water_heater", "select"]
_LOGGER = logging.getLogger(__name__)
class GeHomeUpdateCoordinator(DataUpdateCoordinator):
"""Define a wrapper class to update GE Home data."""
@ -65,15 +66,23 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
self._retry_count = 0
self.initialization_future = asyncio.Future()
def create_ge_client(self, event_loop: Optional[asyncio.AbstractEventLoop]) -> GeWebsocketClient:
def create_ge_client(
self, event_loop: Optional[asyncio.AbstractEventLoop]
) -> GeWebsocketClient:
"""
Create a new GeClient object with some helpful callbacks.
:param event_loop: Event loop
:return: GeWebsocketClient
"""
client = GeWebsocketClient(self._username, self._password, event_loop=event_loop, )
client.add_event_handler(EVENT_APPLIANCE_INITIAL_UPDATE, self.on_device_initial_update)
client = GeWebsocketClient(
self._username,
self._password,
event_loop=event_loop,
)
client.add_event_handler(
EVENT_APPLIANCE_INITIAL_UPDATE, self.on_device_initial_update
)
client.add_event_handler(EVENT_APPLIANCE_UPDATE_RECEIVED, self.on_device_update)
client.add_event_handler(EVENT_GOT_APPLIANCE_LIST, self.on_appliance_list)
client.add_event_handler(EVENT_DISCONNECTED, self.on_disconnect)
@ -87,10 +96,10 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
@property
def appliance_apis(self) -> Dict[str, ApplianceApi]:
return self._appliance_apis
@property
def online(self) -> bool:
"""
"""
Indicates whether the services is online. If it's retried several times, it's assumed
that it's offline for some reason
"""
@ -116,15 +125,17 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
def maybe_add_appliance_api(self, appliance: GeAppliance):
mac_addr = appliance.mac_addr
if mac_addr not in self.appliance_apis:
_LOGGER.debug(f"Adding appliance api for appliance {mac_addr} ({appliance.appliance_type})")
_LOGGER.debug(
f"Adding appliance api for appliance {mac_addr} ({appliance.appliance_type})"
)
api = self._get_appliance_api(appliance)
api.build_entities_list()
self.appliance_apis[mac_addr] = api
else:
#if we already have the API, switch out its appliance reference for this one
# if we already have the API, switch out its appliance reference for this one
api = self.appliance_apis[mac_addr]
api.appliance = appliance
api.appliance = appliance
async def get_client(self) -> GeWebsocketClient:
"""Get a new GE Websocket client."""
if self.client:
@ -132,10 +143,10 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
self.client.clear_event_handlers()
await self.client.disconnect()
except Exception as err:
_LOGGER.warn(f'exception while disconnecting client {err}')
_LOGGER.warn(f"exception while disconnecting client {err}")
finally:
self._reset_initialization()
loop = self._hass.loop
self.client = self.create_ge_client(event_loop=loop)
return self.client
@ -146,44 +157,48 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
for component in PLATFORMS:
self.hass.async_create_task(
self.hass.config_entries.async_forward_entry_setup(self._config_entry, component)
self.hass.config_entries.async_forward_entry_setup(
self._config_entry, component
)
)
try:
await self.async_start_client()
except (GeNotAuthenticatedError, GeAuthFailedError):
raise HaAuthError('Authentication failure')
raise HaAuthError("Authentication failure")
except GeGeneralServerError:
raise HaCannotConnect('Cannot connect (server error)')
raise HaCannotConnect("Cannot connect (server error)")
except Exception:
raise HaCannotConnect('Unknown connection failure')
raise HaCannotConnect("Unknown connection failure")
try:
with async_timeout.timeout(ASYNC_TIMEOUT):
await self.initialization_future
except (asyncio.CancelledError, asyncio.TimeoutError):
raise HaCannotConnect('Initialization timed out')
raise HaCannotConnect("Initialization timed out")
return True
async def async_start_client(self):
"""Start a new GeClient in the HASS event loop."""
try:
_LOGGER.debug('Creating and starting client')
_LOGGER.debug("Creating and starting client")
await self.get_client()
await self.async_begin_session()
except:
_LOGGER.debug('could not start the client')
_LOGGER.debug("could not start the client")
self.client = None
raise
async def async_begin_session(self):
"""Begins the ge_home session."""
_LOGGER.debug("Beginning session")
session = self._hass.helpers.aiohttp_client.async_get_clientsession()
await self.client.async_get_credentials(session)
fut = asyncio.ensure_future(self.client.async_run_client(), loop=self._hass.loop)
_LOGGER.debug('Client running')
fut = asyncio.ensure_future(
self.client.async_run_client(), loop=self._hass.loop
)
_LOGGER.debug("Client running")
return fut
async def async_reset(self):
@ -193,17 +208,19 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
unload_ok = all(
await asyncio.gather(
*[
self.hass.config_entries.async_forward_entry_unload(entry, component)
self.hass.config_entries.async_forward_entry_unload(
entry, component
)
for component in PLATFORMS
]
)
)
return unload_ok
return unload_ok
async def _kill_client(self):
"""Kill the client. Leaving this in for testing purposes."""
await asyncio.sleep(30)
_LOGGER.critical('Killing the connection. Popcorn time.')
_LOGGER.critical("Killing the connection. Popcorn time.")
await self.client.disconnect()
@callback
@ -216,13 +233,17 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
async def async_reconnect(self) -> None:
"""Try to reconnect ge_home session."""
self._retry_count += 1
_LOGGER.info(f"attempting to reconnect to ge_home service (attempt {self._retry_count})")
_LOGGER.info(
f"attempting to reconnect to ge_home service (attempt {self._retry_count})"
)
try:
with async_timeout.timeout(ASYNC_TIMEOUT):
await self.async_start_client()
except Exception as err:
_LOGGER.warn(f"could not reconnect: {err}, will retry in {self._get_retry_delay()} seconds")
_LOGGER.warn(
f"could not reconnect: {err}, will retry in {self._get_retry_delay()} seconds"
)
self.hass.loop.call_later(self._get_retry_delay(), self.reconnect)
_LOGGER.debug("forcing a state refresh while disconnected")
try:
@ -249,21 +270,23 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
except KeyError:
return
for entity in api.entities:
_LOGGER.debug(f'Updating {entity} ({entity.unique_id}, {entity.entity_id})')
_LOGGER.debug(f"Updating {entity} ({entity.unique_id}, {entity.entity_id})")
entity.async_write_ha_state()
async def _refresh_ha_state(self):
entities = [
entity
for api in self.appliance_apis.values()
for entity in api.entities
entity for api in self.appliance_apis.values() for entity in api.entities
]
for entity in entities:
try:
_LOGGER.debug(f'Refreshing state for {entity} ({entity.unique_id}, {entity.entity_id}')
_LOGGER.debug(
f"Refreshing state for {entity} ({entity.unique_id}, {entity.entity_id}"
)
entity.async_write_ha_state()
except:
_LOGGER.debug(f'Could not refresh state for {entity} ({entity.unique_id}, {entity.entity_id}')
_LOGGER.debug(
f"Could not refresh state for {entity} ({entity.unique_id}, {entity.entity_id}"
)
@property
def all_appliances_updated(self) -> bool:
@ -272,31 +295,35 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
async def on_appliance_list(self, _):
"""When we get an appliance list, mark it and maybe trigger all ready."""
_LOGGER.debug('Got roster update')
_LOGGER.debug("Got roster update")
self.last_update_success = True
if not self._got_roster:
self._got_roster = True
#TODO: Probably should have a better way of confirming we're good to go...
await asyncio.sleep(5) # After the initial roster update, wait a bit and hit go
# TODO: Probably should have a better way of confirming we're good to go...
await asyncio.sleep(
5
) # After the initial roster update, wait a bit and hit go
await self.async_maybe_trigger_all_ready()
async def on_device_initial_update(self, appliance: GeAppliance):
"""When an appliance first becomes ready, let the system know and schedule periodic updates."""
_LOGGER.debug(f'Got initial update for {appliance.mac_addr}')
_LOGGER.debug(f"Got initial update for {appliance.mac_addr}")
self.last_update_success = True
self.maybe_add_appliance_api(appliance)
await self.async_maybe_trigger_all_ready()
_LOGGER.debug(f'Requesting updates for {appliance.mac_addr}')
_LOGGER.debug(f"Requesting updates for {appliance.mac_addr}")
while self.connected:
await asyncio.sleep(UPDATE_INTERVAL)
if self.connected and self.client.available:
await appliance.async_request_update()
_LOGGER.debug(f'No longer requesting updates for {appliance.mac_addr}')
_LOGGER.debug(f"No longer requesting updates for {appliance.mac_addr}")
async def on_disconnect(self, _):
"""Handle disconnection."""
_LOGGER.debug(f"Disconnected. Attempting to reconnect in {MIN_RETRY_DELAY} seconds")
_LOGGER.debug(
f"Disconnected. Attempting to reconnect in {MIN_RETRY_DELAY} seconds"
)
self.last_update_success = False
self.hass.loop.call_later(MIN_RETRY_DELAY, self.reconnect, True)
@ -311,7 +338,9 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
# Been here, done this
return
if self._got_roster and self.all_appliances_updated:
_LOGGER.debug('Ready to go. Waiting 2 seconds and setting init future result.')
_LOGGER.debug(
"Ready to go. Waiting 2 seconds and setting init future result."
)
# The the flag and wait to prevent two different fun race conditions
self._init_done = True
await asyncio.sleep(2)
@ -320,4 +349,4 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
def _get_retry_delay(self) -> int:
delay = MIN_RETRY_DELAY * 2 ** (self._retry_count - 1)
return min(delay, MAX_RETRY_DELAY)
return min(delay, MAX_RETRY_DELAY)

View File

@ -1,6 +1,6 @@
{
"name": "GE Appliances (SmartHQ)",
"homeassistant": "2021.1.5",
"domains": ["binary_sensor", "sensor", "switch", "water_heater"],
"domains": ["binary_sensor", "sensor", "switch", "water_heater", "select"],
"iot_class": "Cloud Polling"
}