- Update to GE Home and use the gehomesdk

This commit is contained in:
Warren Rees 2021-05-20 11:15:49 -04:00
parent 5d520e5ac8
commit e399ff1652
46 changed files with 121 additions and 123 deletions

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2020 Andrew Marks Copyright (c) 2021
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -1,20 +1,19 @@
# GE Kitchen Appliances (SmartHQ) # GE Home Appliances (SmartHQ)
## `ge_kitchen` ## `ge_home`
Integration for GE WiFi-enabled kitchen appliances. So far, I've only done fridges and ovens (because that's what I Integration for GE WiFi-enabled appliances into Home Assistant. This integration currently contains fridge, oven, dishwasher, laundry washer, laundry dryer support.
have), but I hope to to dishwashers next. Because HA doesn't have Fridge or Oven platforms, both fridges and ovens are
primarily represented as water heater entities, which works surprisingly well. If anybody who has other GE appliances **Forked from Andrew Mark's [repository](https://github.com/ajmarks/ha_components).**
sees this and wants to pitch in, please shoot me a message or make a PR.
Entities card:
Entities card:
![Entities](https://raw.githubusercontent.com/simbaja/ha_components/master/img/appliance_entities.png)
![Entities](https://raw.githubusercontent.com/ajmarks/ha_components/master/img/appliance_entities.png)
Fridge Controls:
Fridge Controls:
![Fridge controls](https://raw.githubusercontent.com/simbaja/ha_components/master/img/fridge_control.png)
![Fridge controls](https://raw.githubusercontent.com/ajmarks/ha_components/master/img/fridge_control.png)
Oven Controls:
Oven Controls:
![Fridge controls](https://raw.githubusercontent.com/simbaja/ha_components/master/img/oven_controls.png)
![Fridge controls](https://raw.githubusercontent.com/ajmarks/ha_components/master/img/oven_controls.png)

View File

@ -1,4 +1,4 @@
"""The ge_kitchen integration.""" """The ge_home integration."""
from homeassistant.const import EVENT_HOMEASSISTANT_STOP from homeassistant.const import EVENT_HOMEASSISTANT_STOP
import voluptuous as vol import voluptuous as vol
@ -8,7 +8,7 @@ from homeassistant.core import HomeAssistant
from .const import ( from .const import (
DOMAIN DOMAIN
) )
from .update_coordinator import GeKitchenUpdateCoordinator from .update_coordinator import GeHomeUpdateCoordinator
CONFIG_SCHEMA = vol.Schema({DOMAIN: vol.Schema({})}, extra=vol.ALLOW_EXTRA) CONFIG_SCHEMA = vol.Schema({DOMAIN: vol.Schema({})}, extra=vol.ALLOW_EXTRA)
@ -16,11 +16,11 @@ async def async_setup(hass: HomeAssistant, config: dict):
return True return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
"""Set up the ge_kitchen component.""" """Set up the ge_home component."""
hass.data.setdefault(DOMAIN, {}) hass.data.setdefault(DOMAIN, {})
"""Set up ge_kitchen from a config entry.""" """Set up ge_home from a config entry."""
coordinator = GeKitchenUpdateCoordinator(hass, entry) coordinator = GeHomeUpdateCoordinator(hass, entry)
hass.data[DOMAIN][entry.entry_id] = coordinator hass.data[DOMAIN][entry.entry_id] = coordinator
if not await coordinator.async_setup(): if not await coordinator.async_setup():
@ -32,7 +32,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
"""Unload a config entry.""" """Unload a config entry."""
coordinator: GeKitchenUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] coordinator: GeHomeUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
ok = await coordinator.async_reset() ok = await coordinator.async_reset()
if ok: if ok:
hass.data[DOMAIN].pop(entry.entry_id) hass.data[DOMAIN].pop(entry.entry_id)

View File

@ -1,4 +1,4 @@
"""GE Kitchen Sensor Entities""" """GE Home Sensor Entities"""
import async_timeout import async_timeout
import logging import logging
from typing import Callable from typing import Callable
@ -9,14 +9,14 @@ from homeassistant.core import HomeAssistant
from .const import DOMAIN from .const import DOMAIN
from .entities import GeErdBinarySensor from .entities import GeErdBinarySensor
from .update_coordinator import GeKitchenUpdateCoordinator from .update_coordinator import GeHomeUpdateCoordinator
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: Callable): async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: Callable):
"""GE Kitchen sensors.""" """GE Home sensors."""
coordinator: GeKitchenUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id] coordinator: GeHomeUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]
# This should be a NOP, but let's be safe # This should be a NOP, but let's be safe
with async_timeout.timeout(20): with async_timeout.timeout(20):

View File

@ -1,4 +1,4 @@
"""Config flow for GE Kitchen integration.""" """Config flow for GE Home integration."""
import logging import logging
from typing import Dict, Optional from typing import Dict, Optional
@ -7,7 +7,7 @@ import aiohttp
import asyncio import asyncio
import async_timeout import async_timeout
from gekitchensdk import GeAuthFailedError, GeNotAuthenticatedError, GeGeneralServerError, async_get_oauth2_token from gehomesdk import GeAuthFailedError, GeNotAuthenticatedError, GeGeneralServerError, async_get_oauth2_token
import voluptuous as vol import voluptuous as vol
from homeassistant import config_entries, core from homeassistant import config_entries, core
@ -18,7 +18,7 @@ from .exceptions import HaAuthError, HaCannotConnect
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
GEKITCHEN_SCHEMA = vol.Schema( GEHOME_SCHEMA = vol.Schema(
{vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str} {vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str}
) )
@ -42,10 +42,10 @@ async def validate_input(hass: core.HomeAssistant, data):
raise HaCannotConnect('Unknown connection failure') raise HaCannotConnect('Unknown connection failure')
# Return info that you want to store in the config entry. # Return info that you want to store in the config entry.
return {"title": f"GE Kitchen ({data[CONF_USERNAME]:s})"} return {"title": f"GE Home ({data[CONF_USERNAME]:s})"}
class GeKitchenConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): class GeHomeConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for GE Kitchen.""" """Handle a config flow for GE Home."""
VERSION = 1 VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_PUSH CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_PUSH
@ -77,7 +77,7 @@ class GeKitchenConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
return self.async_create_entry(title=info["title"], data=user_input) return self.async_create_entry(title=info["title"], data=user_input)
return self.async_show_form( return self.async_show_form(
step_id="user", data_schema=GEKITCHEN_SCHEMA, errors=errors step_id="user", data_schema=GEHOME_SCHEMA, errors=errors
) )
async def async_step_reauth(self, user_input: Optional[dict] = None): async def async_step_reauth(self, user_input: Optional[dict] = None):
@ -100,5 +100,5 @@ class GeKitchenConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
return self.async_abort(reason=errors["base"]) return self.async_abort(reason=errors["base"])
return self.async_show_form( return self.async_show_form(
step_id="reauth", data_schema=GEKITCHEN_SCHEMA, errors=errors, step_id="reauth", data_schema=GEHOME_SCHEMA, errors=errors,
) )

View File

@ -1,7 +1,7 @@
"""Constants for the ge_kitchen integration.""" """Constants for the gehome integration."""
from gekitchensdk.clients.const import LOGIN_URL from gehomesdk.clients.const import LOGIN_URL
DOMAIN = "ge_kitchen" DOMAIN = "ge_home"
EVENT_ALL_APPLIANCES_READY = 'all_appliances_ready' EVENT_ALL_APPLIANCES_READY = 'all_appliances_ready'

View File

@ -1,7 +1,7 @@
import logging import logging
from typing import Type from typing import Type
from gekitchensdk.erd import ErdApplianceType from gehomesdk.erd import ErdApplianceType
from .base import ApplianceApi from .base import ApplianceApi
from .oven import OvenApi from .oven import OvenApi

View File

@ -2,8 +2,8 @@ import asyncio
import logging import logging
from typing import Dict, List, Optional from typing import Dict, List, Optional
from gekitchensdk import GeAppliance from gehomesdk import GeAppliance
from gekitchensdk.erd import ErdCode, ErdCodeType, ErdApplianceType from gehomesdk.erd import ErdCode, ErdCodeType, ErdApplianceType
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity

View File

@ -2,7 +2,7 @@ import logging
from typing import List from typing import List
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from gekitchensdk.erd import ErdCode, ErdApplianceType from gehomesdk.erd import ErdCode, ErdApplianceType
from .base import ApplianceApi from .base import ApplianceApi
from ..entities import GeErdSensor, GeDishwasherControlLockedSwitch from ..entities import GeErdSensor, GeDishwasherControlLockedSwitch
@ -28,4 +28,4 @@ class DishwasherApi(ApplianceApi):
] ]
entities = base_entities + dishwasher_entities entities = base_entities + dishwasher_entities
return entities return entities

View File

@ -2,7 +2,7 @@ import logging
from typing import List from typing import List
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from gekitchensdk.erd import ErdCode, ErdApplianceType from gehomesdk.erd import ErdCode, ErdApplianceType
from .base import ApplianceApi from .base import ApplianceApi
from ..entities import GeErdSensor, GeDishwasherControlLockedSwitch from ..entities import GeErdSensor, GeDishwasherControlLockedSwitch

View File

@ -4,7 +4,7 @@ import logging
from typing import List from typing import List
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from gekitchensdk import ( from gehomesdk import (
ErdCode, ErdCode,
ErdApplianceType, ErdApplianceType,
ErdOnOff, ErdOnOff,

View File

@ -3,7 +3,7 @@ from typing import List
from homeassistant.const import DEVICE_CLASS_POWER_FACTOR from homeassistant.const import DEVICE_CLASS_POWER_FACTOR
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from gekitchensdk import ( from gehomesdk import (
ErdCode, ErdCode,
ErdApplianceType, ErdApplianceType,
OvenConfiguration, OvenConfiguration,

View File

@ -1,9 +1,9 @@
from custom_components.ge_kitchen.entities.common.ge_erd_binary_sensor import GeErdBinarySensor from custom_components.ge_home.entities.common.ge_erd_binary_sensor import GeErdBinarySensor
import logging import logging
from typing import List from typing import List
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from gekitchensdk.erd import ErdCode, ErdApplianceType from gehomesdk.erd import ErdCode, ErdApplianceType
from .base import ApplianceApi from .base import ApplianceApi
from ..entities import GeErdSensor, GeErdBinarySensor from ..entities import GeErdSensor, GeErdBinarySensor
@ -35,4 +35,4 @@ class WasherApi(ApplianceApi):
] ]
entities = base_entities + washer_entities entities = base_entities + washer_entities
return entities return entities

View File

@ -2,7 +2,7 @@ import logging
from typing import List from typing import List
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from gekitchensdk.erd import ErdCode, ErdApplianceType from gehomesdk.erd import ErdCode, ErdApplianceType
from .base import ApplianceApi from .base import ApplianceApi
from ..entities import GeErdSensor, GeErdBinarySensor from ..entities import GeErdSensor, GeErdBinarySensor
@ -38,4 +38,4 @@ class WasherDryerApi(ApplianceApi):
] ]
entities = base_entities + washer_entities + dryer_entities entities = base_entities + washer_entities + dryer_entities
return entities return entities

View File

@ -1,7 +1,7 @@
from datetime import timedelta from datetime import timedelta
from typing import Optional, Dict, Any from typing import Optional, Dict, Any
from gekitchensdk import GeAppliance from gehomesdk import GeAppliance
from ...devices import ApplianceApi from ...devices import ApplianceApi
class GeEntity: class GeEntity:
@ -62,4 +62,4 @@ class GeEntity:
return None return None
def _get_device_class(self) -> Optional[str]: def _get_device_class(self) -> Optional[str]:
return None return None

View File

@ -2,7 +2,7 @@ from typing import Optional
from homeassistant.components.binary_sensor import BinarySensorEntity from homeassistant.components.binary_sensor import BinarySensorEntity
from gekitchensdk import ErdCode, ErdCodeType, ErdCodeClass from gehomesdk import ErdCode, ErdCodeType, ErdCodeClass
from ...devices import ApplianceApi from ...devices import ApplianceApi
from .ge_erd_entity import GeErdEntity from .ge_erd_entity import GeErdEntity

View File

@ -2,7 +2,7 @@ from datetime import timedelta
from typing import Optional from typing import Optional
from homeassistant.const import DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT from homeassistant.const import DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
from gekitchensdk import ErdCode, ErdCodeType, ErdCodeClass, ErdMeasurementUnits from gehomesdk import ErdCode, ErdCodeType, ErdCodeClass, ErdMeasurementUnits
from ...const import DOMAIN from ...const import DOMAIN
from ...devices import ApplianceApi from ...devices import ApplianceApi

View File

@ -1,7 +1,7 @@
from typing import Optional from typing import Optional
import magicattr import magicattr
from gekitchensdk import ErdCodeType from gehomesdk import ErdCodeType
from ...devices import ApplianceApi from ...devices import ApplianceApi
from .ge_erd_binary_sensor import GeErdBinarySensor from .ge_erd_binary_sensor import GeErdBinarySensor

View File

@ -1,7 +1,7 @@
from typing import Optional from typing import Optional
import magicattr import magicattr
from gekitchensdk import ErdCode, ErdCodeType, ErdMeasurementUnits from gehomesdk import ErdCode, ErdCodeType, ErdMeasurementUnits
from ...devices import ApplianceApi from ...devices import ApplianceApi
from .ge_erd_sensor import GeErdSensor from .ge_erd_sensor import GeErdSensor

View File

@ -8,7 +8,7 @@ from homeassistant.const import (
TEMP_FAHRENHEIT TEMP_FAHRENHEIT
) )
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from gekitchensdk import ErdCode, ErdCodeClass, ErdMeasurementUnits from gehomesdk import ErdCode, ErdCodeClass, ErdMeasurementUnits
from .ge_erd_entity import GeErdEntity from .ge_erd_entity import GeErdEntity

View File

@ -7,7 +7,7 @@ from homeassistant.const import (
TEMP_FAHRENHEIT, TEMP_FAHRENHEIT,
TEMP_CELSIUS TEMP_CELSIUS
) )
from gekitchensdk import ErdCode, ErdMeasurementUnits from gehomesdk import ErdCode, ErdMeasurementUnits
from ...const import DOMAIN from ...const import DOMAIN
from .ge_erd_entity import GeEntity from .ge_erd_entity import GeEntity

View File

@ -1,4 +1,4 @@
from gekitchensdk import ErdCode, ErdOperatingMode from gehomesdk import ErdCode, ErdOperatingMode
from ..common import GeErdSwitch from ..common import GeErdSwitch
@ -9,4 +9,4 @@ class GeDishwasherControlLockedSwitch(GeErdSwitch):
def is_on(self) -> bool: def is_on(self) -> bool:
mode: ErdOperatingMode = self.appliance.get_erd_value(ErdCode.OPERATING_MODE) mode: ErdOperatingMode = self.appliance.get_erd_value(ErdCode.OPERATING_MODE)
return mode == ErdOperatingMode.CONTROL_LOCKED return mode == ErdOperatingMode.CONTROL_LOCKED

View File

@ -1,4 +1,4 @@
"""GE Kitchen Sensor Entities - Abstract Fridge""" """GE Home Sensor Entities - Abstract Fridge"""
import sys import sys
import os import os
import abc import abc
@ -7,7 +7,7 @@ from typing import Any, Dict, List, Optional
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
from gekitchensdk import ( from gehomesdk import (
ErdCode, ErdCode,
ErdOnOff, ErdOnOff,
ErdFullNotFull, ErdFullNotFull,

View File

@ -1,4 +1,4 @@
"""GE Kitchen Sensor Entities - Dispenser""" """GE Home Sensor Entities - Dispenser"""
import logging import logging
from typing import List, Optional, Dict, Any from typing import List, Optional, Dict, Any
@ -6,7 +6,7 @@ from typing import List, Optional, Dict, Any
from homeassistant.const import ATTR_TEMPERATURE, TEMP_FAHRENHEIT from homeassistant.const import ATTR_TEMPERATURE, TEMP_FAHRENHEIT
from homeassistant.util.temperature import convert as convert_temperature from homeassistant.util.temperature import convert as convert_temperature
from gekitchensdk import ( from gehomesdk import (
ErdCode, ErdCode,
ErdHotWaterStatus, ErdHotWaterStatus,
ErdPresent, ErdPresent,

View File

@ -1,8 +1,8 @@
"""GE Kitchen Sensor Entities - Freezer""" """GE Home Sensor Entities - Freezer"""
import logging import logging
from typing import Any, Dict, Optional from typing import Any, Dict, Optional
from gekitchensdk import ( from gehomesdk import (
ErdCode, ErdCode,
ErdDoorStatus ErdDoorStatus
) )

View File

@ -1,8 +1,8 @@
"""GE Kitchen Sensor Entities - Fridge""" """GE Home Sensor Entities - Fridge"""
import logging import logging
from typing import Any, Dict from typing import Any, Dict
from gekitchensdk import ( from gehomesdk import (
ErdCode, ErdCode,
ErdDoorStatus, ErdDoorStatus,
ErdFilterStatus ErdFilterStatus

View File

@ -4,7 +4,7 @@ from homeassistant.components.water_heater import (
SUPPORT_OPERATION_MODE, SUPPORT_OPERATION_MODE,
SUPPORT_TARGET_TEMPERATURE SUPPORT_TARGET_TEMPERATURE
) )
from gekitchensdk import ErdOvenCookMode from gehomesdk import ErdOvenCookMode
SUPPORT_NONE = 0 SUPPORT_NONE = 0
GE_OVEN_SUPPORT = (SUPPORT_OPERATION_MODE | SUPPORT_TARGET_TEMPERATURE) GE_OVEN_SUPPORT = (SUPPORT_OPERATION_MODE | SUPPORT_TARGET_TEMPERATURE)

View File

@ -1,8 +1,8 @@
"""GE Kitchen Sensor Entities - Oven""" """GE Home Sensor Entities - Oven"""
import logging import logging
from typing import Any, Dict, List, Optional, Set from typing import Any, Dict, List, Optional, Set
from gekitchensdk import ( from gehomesdk import (
ErdCode, ErdCode,
ErdMeasurementUnits, ErdMeasurementUnits,
ErdOvenCookMode, ErdOvenCookMode,

View File

@ -0,0 +1,9 @@
{
"domain": "ge_home",
"name": "GE Home",
"config_flow": true,
"documentation": "https://github.com/simbaja/ha_components",
"requirements": ["gehomesdk==0.3.12","magicattr==0.1.5"],
"codeowners": ["@simbaja"],
"version": "0.3.12"
}

View File

@ -1,4 +1,4 @@
"""GE Kitchen Sensor Entities""" """GE Home Sensor Entities"""
import async_timeout import async_timeout
import logging import logging
from typing import Callable from typing import Callable
@ -8,14 +8,14 @@ from homeassistant.core import HomeAssistant
from .const import DOMAIN from .const import DOMAIN
from .entities import GeErdSensor from .entities import GeErdSensor
from .update_coordinator import GeKitchenUpdateCoordinator from .update_coordinator import GeHomeUpdateCoordinator
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: Callable): async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: Callable):
"""GE Kitchen sensors.""" """GE Home sensors."""
_LOGGER.debug('Adding GE Kitchen sensors') _LOGGER.debug('Adding GE Home sensors')
coordinator: GeKitchenUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id] coordinator: GeHomeUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]
# This should be a NOP, but let's be safe # This should be a NOP, but let's be safe
with async_timeout.timeout(20): with async_timeout.timeout(20):

View File

@ -1,4 +1,4 @@
"""GE Kitchen Switch Entities""" """GE Home Switch Entities"""
import async_timeout import async_timeout
import logging import logging
from typing import Callable from typing import Callable
@ -8,14 +8,14 @@ from homeassistant.core import HomeAssistant
from .entities import GeErdSwitch from .entities import GeErdSwitch
from .const import DOMAIN from .const import DOMAIN
from .update_coordinator import GeKitchenUpdateCoordinator from .update_coordinator import GeHomeUpdateCoordinator
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: Callable): async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: Callable):
"""GE Kitchen sensors.""" """GE Home sensors."""
_LOGGER.debug('Adding GE Kitchen switches') _LOGGER.debug('Adding GE Home switches')
coordinator: GeKitchenUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id] coordinator: GeHomeUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]
# This should be a NOP, but let's be safe # This should be a NOP, but let's be safe
with async_timeout.timeout(20): with async_timeout.timeout(20):

View File

@ -1,5 +1,5 @@
{ {
"title": "GE Kitchen", "title": "GE Home",
"config": { "config": {
"step": { "step": {
"init": { "init": {
@ -24,4 +24,4 @@
"already_configured_account": "[%key:common::config_flow::abort::already_configured_account%]" "already_configured_account": "[%key:common::config_flow::abort::already_configured_account%]"
} }
} }
} }

View File

@ -1,11 +1,11 @@
"""Data update coordinator for GE Kitchen Appliances""" """Data update coordinator for GE Home Appliances"""
import asyncio import asyncio
import async_timeout import async_timeout
import logging import logging
from typing import Any, Dict, Iterable, Optional, Tuple from typing import Any, Dict, Iterable, Optional, Tuple
from gekitchensdk import ( from gehomesdk import (
EVENT_APPLIANCE_INITIAL_UPDATE, EVENT_APPLIANCE_INITIAL_UPDATE,
EVENT_APPLIANCE_UPDATE_RECEIVED, EVENT_APPLIANCE_UPDATE_RECEIVED,
EVENT_CONNECTED, EVENT_CONNECTED,
@ -15,7 +15,7 @@ from gekitchensdk import (
GeAppliance, GeAppliance,
GeWebsocketClient, GeWebsocketClient,
) )
from gekitchensdk import GeAuthFailedError, GeGeneralServerError, GeNotAuthenticatedError from gehomesdk import GeAuthFailedError, GeGeneralServerError, GeNotAuthenticatedError
from .exceptions import HaAuthError, HaCannotConnect from .exceptions import HaAuthError, HaCannotConnect
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
@ -37,11 +37,11 @@ from .devices import ApplianceApi, get_appliance_api_type
PLATFORMS = ["binary_sensor", "sensor", "switch", "water_heater"] PLATFORMS = ["binary_sensor", "sensor", "switch", "water_heater"]
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
class GeKitchenUpdateCoordinator(DataUpdateCoordinator): class GeHomeUpdateCoordinator(DataUpdateCoordinator):
"""Define a wrapper class to update GE Kitchen data.""" """Define a wrapper class to update GE Home data."""
def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None: def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None:
"""Set up the GeKitchenUpdateCoordinator class.""" """Set up the GeHomeUpdateCoordinator class."""
self._hass = hass self._hass = hass
self._config_entry = config_entry self._config_entry = config_entry
self._username = config_entry.data[CONF_USERNAME] self._username = config_entry.data[CONF_USERNAME]
@ -176,7 +176,7 @@ class GeKitchenUpdateCoordinator(DataUpdateCoordinator):
raise raise
async def async_begin_session(self): async def async_begin_session(self):
"""Begins the ge_kitchen session.""" """Begins the ge_home session."""
_LOGGER.debug("Beginning session") _LOGGER.debug("Beginning session")
session = self._hass.helpers.aiohttp_client.async_get_clientsession() session = self._hass.helpers.aiohttp_client.async_get_clientsession()
await self.client.async_get_credentials(session) await self.client.async_get_credentials(session)
@ -206,15 +206,15 @@ class GeKitchenUpdateCoordinator(DataUpdateCoordinator):
@callback @callback
def reconnect(self, log=False) -> None: def reconnect(self, log=False) -> None:
"""Prepare to reconnect ge_kitchen session.""" """Prepare to reconnect ge_home session."""
if log: if log:
_LOGGER.info("Will try to reconnect to ge_kitchen service") _LOGGER.info("Will try to reconnect to ge_home service")
self.hass.loop.create_task(self.async_reconnect()) self.hass.loop.create_task(self.async_reconnect())
async def async_reconnect(self) -> None: async def async_reconnect(self) -> None:
"""Try to reconnect ge_kitchen session.""" """Try to reconnect ge_home session."""
self._retry_count += 1 self._retry_count += 1
_LOGGER.info(f"attempting to reconnect to ge_kitchen service (attempt {self._retry_count})") _LOGGER.info(f"attempting to reconnect to ge_home service (attempt {self._retry_count})")
try: try:
with async_timeout.timeout(ASYNC_TIMEOUT): with async_timeout.timeout(ASYNC_TIMEOUT):
@ -233,7 +233,7 @@ class GeKitchenUpdateCoordinator(DataUpdateCoordinator):
"""Close the connection on shutdown. """Close the connection on shutdown.
Used as an argument to EventBus.async_listen_once. Used as an argument to EventBus.async_listen_once.
""" """
_LOGGER.info("ge_kitchen shutting down") _LOGGER.info("ge_home shutting down")
if self.client: if self.client:
self.client.clear_event_handlers() self.client.clear_event_handlers()
self.client.disconnect() self.client.disconnect()

View File

@ -1,4 +1,4 @@
"""GE Kitchen Sensor Entities""" """GE Home Sensor Entities"""
import async_timeout import async_timeout
import logging import logging
from typing import Callable from typing import Callable
@ -9,14 +9,14 @@ from homeassistant.core import HomeAssistant
from .entities import GeWaterHeater from .entities import GeWaterHeater
from .const import DOMAIN from .const import DOMAIN
from .update_coordinator import GeKitchenUpdateCoordinator from .update_coordinator import GeHomeUpdateCoordinator
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: Callable): async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: Callable):
"""GE Kitchen Water Heaters.""" """GE Home Water Heaters."""
_LOGGER.debug('Adding GE "Water Heaters"') _LOGGER.debug('Adding GE "Water Heaters"')
coordinator: GeKitchenUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id] coordinator: GeHomeUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]
# This should be a NOP, but let's be safe # This should be a NOP, but let's be safe
with async_timeout.timeout(20): with async_timeout.timeout(20):

View File

@ -1,9 +0,0 @@
{
"domain": "ge_kitchen",
"name": "GE Kitchen",
"config_flow": true,
"documentation": "https://github.com/simbaja/ha_components",
"requirements": ["gekitchensdk==0.3.11","magicattr==0.1.5"],
"codeowners": ["@simbaja"],
"version": "0.3.11"
}

View File

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

17
info.md
View File

@ -1,20 +1,19 @@
# GE Kitchen Appliances (SmartHQ) # GE Home Appliances (SmartHQ)
## `ge_kitchen` ## `ge_home`
Integration for GE WiFi-enabled kitchen appliances. So far, I've only done fridges and ovens (because that's what I Integration for GE WiFi-enabled appliances into Home Assistant. This integration currently contains fridge, oven, dishwasher, laundry washer, laundry dryer support.
have), but I hope to to dishwashers next. Because HA doesn't have Fridge or Oven platforms, both fridges and ovens are
primarily represented as water heater entities, which works surprisingly well. If anybody who has other GE appliances **Forked from Andrew Mark's [repository](https://github.com/ajmarks/ha_components).**
sees this and wants to pitch in, please shoot me a message or make a PR.
Entities card: Entities card:
![Entities](https://raw.githubusercontent.com/ajmarks/ha_components/master/img/appliance_entities.png) ![Entities](https://raw.githubusercontent.com/simbaja/ha_components/master/img/appliance_entities.png)
Fridge Controls: Fridge Controls:
![Fridge controls](https://raw.githubusercontent.com/ajmarks/ha_components/master/img/fridge_control.png) ![Fridge controls](https://raw.githubusercontent.com/simbaja/ha_components/master/img/fridge_control.png)
Oven Controls: Oven Controls:
![Fridge controls](https://raw.githubusercontent.com/ajmarks/ha_components/master/img/oven_controls.png) ![Fridge controls](https://raw.githubusercontent.com/simbaja/ha_components/master/img/oven_controls.png)