Skip to content

Commit

Permalink
Merge pull request #24 from simbaja/dev
Browse files Browse the repository at this point in the history
Merge Dev into Master
  • Loading branch information
simbaja authored Aug 1, 2021
2 parents 7ac74cf + b22babe commit a62a9fd
Show file tree
Hide file tree
Showing 41 changed files with 961 additions and 180 deletions.
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

# GE Home Appliances (SmartHQ) Changelog

## 0.4.0

- Implemented Laundry Support (@warrenrees, @ssindsd)
- Implemented Water Filter Support (@bendavis, @tumtumsback, @rgabrielson11)
- Implemented Initial Advantium Support (@ssinsd)
- Bug fixes for ovens (@TKpizza)
- Additional authentication error handling (@rgabrielson11)
- Additional dishwasher functionality (@ssinsd)
- Introduced new select entity (@bendavis)
- Miscellaneous entity bug fixes/refinements
- Integrated new version of SDK

## 0.3.12

- Initial tracked version
45 changes: 43 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
# GE Home Appliances (SmartHQ)

## `ge_home`
Integration for GE WiFi-enabled appliances into Home Assistant. This integration currently contains fridge, oven, dishwasher, laundry washer, laundry dryer support.
[![GitHub Release][releases-shield]][releases]
[![GitHub Activity][commits-shield]][commits]
[![License][license-shield]](LICENSE)
[![hacs][hacsbadge]][hacs]

Integration for GE WiFi-enabled appliances into Home Assistant. This integration currently supports the following devices:

- Fridge
- Oven
- Dishwasher
- Laundry (Washer/Dryer)
- Whole Home Water Filter
- Advantium

**Forked from Andrew Mark's [repository](https://github.com/ajmarks/ha_components).**

## Home Assistant UI Examples
Entities card:

![Entities](https://raw.githubusercontent.com/simbaja/ha_components/master/img/appliance_entities.png)
Expand All @@ -17,3 +29,32 @@ Oven Controls:

![Fridge controls](https://raw.githubusercontent.com/simbaja/ha_components/master/img/oven_controls.png)

## Installation (Manual)

1. Using the tool of choice open the directory (folder) for your HA configuration (where you find `configuration.yaml`).
2. If you do not have a `custom_components` directory (folder) there, you need to create it.
3. In the `custom_components` directory (folder) create a new folder called `ge_home`.
4. Download _all_ the files from the `custom_components/ge_home/` directory (folder) in this repository.
5. Place the files you downloaded in the new directory (folder) you created.
6. Restart Home Assistant
7. In the HA UI go to "Configuration" -> "Integrations" click "+" and search for "GE Home"

## Installation (HACS)

Please follow directions [here](https://hacs.xyz/docs/faq/custom_repositories/), and use https://github.com/simbaja/ha_gehome as the repository URL.
## Configuration

Configuration is done via the HA user interface.

## Change Log

Please click [here](CHANGELOG.md) for change information.

[commits-shield]: https://img.shields.io/github/commit-activity/y/simbaja/ha_gehome.svg?style=for-the-badge
[commits]: https://github.com/simbaja/ha_gehome/commits/master
[hacs]: https://github.com/custom-components/hacs
[hacsbadge]: https://img.shields.io/badge/HACS-Custom-orange.svg?style=for-the-badge
[license-shield]: https://img.shields.io/github/license/simbaja/ha_gehome.svg?style=for-the-badge
[maintenance-shield]: https://img.shields.io/badge/maintainer-Jack%20Simbach%20%40simbaja-blue.svg?style=for-the-badge
[releases-shield]: https://img.shields.io/github/release/simbaja/ha_gehome.svg?style=for-the-badge
[releases]: https://github.com/simbaja/ha_gehome/releases
14 changes: 8 additions & 6 deletions custom_components/ge_home/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@

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, {})
Expand All @@ -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)
10 changes: 9 additions & 1 deletion custom_components/ge_home/devices/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@
from .washer import WasherApi
from .dryer import DryerApi
from .washer_dryer import WasherDryerApi
from .water_filter import WaterFilterApi
from .advantium import AdvantiumApi

_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"""
_LOGGER.debug(f"Found device type: {appliance_type}")
if appliance_type == ErdApplianceType.OVEN:
return OvenApi
if appliance_type == ErdApplianceType.FRIDGE:
Expand All @@ -28,5 +31,10 @@ 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
if appliance_type == ErdApplianceType.ADVANTIUM:
return AdvantiumApi

# Fallback
return ApplianceApi
46 changes: 46 additions & 0 deletions custom_components/ge_home/devices/advantium.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from custom_components.ge_home.entities.advantium.ge_advantium import GeAdvantium
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, GeErdPropertySensor, GeErdPropertyBinarySensor, UPPER_OVEN

_LOGGER = logging.getLogger(__name__)

class AdvantiumApi(ApplianceApi):
"""API class for Advantium objects"""
APPLIANCE_TYPE = ErdApplianceType.ADVANTIUM

def get_all_entities(self) -> List[Entity]:
base_entities = super().get_all_entities()

advantium_entities = [
GeErdSensor(self, ErdCode.UNIT_TYPE),
GeErdBinarySensor(self, ErdCode.UPPER_OVEN_REMOTE_ENABLED, self._single_name(ErdCode.UPPER_OVEN_REMOTE_ENABLED)),
GeErdBinarySensor(self, ErdCode.MICROWAVE_REMOTE_ENABLE),
GeErdSensor(self, ErdCode.UPPER_OVEN_DISPLAY_TEMPERATURE, self._single_name(ErdCode.UPPER_OVEN_DISPLAY_TEMPERATURE)),
GeErdSensor(self, ErdCode.ADVANTIUM_KITCHEN_TIME_REMAINING),
GeErdSensor(self, ErdCode.ADVANTIUM_COOK_TIME_REMAINING),
GeAdvantium(self),

#Cook Status
GeErdPropertySensor(self, ErdCode.ADVANTIUM_COOK_STATUS, "cook_mode"),
GeErdPropertySensor(self, ErdCode.ADVANTIUM_COOK_STATUS, "termination_reason", icon_override="mdi:information-outline"),
GeErdPropertySensor(self, ErdCode.ADVANTIUM_COOK_STATUS, "preheat_status", icon_override="mdi:fire"),
GeErdPropertySensor(self, ErdCode.ADVANTIUM_COOK_STATUS, "temperature", icon_override="mdi:thermometer"),
GeErdPropertySensor(self, ErdCode.ADVANTIUM_COOK_STATUS, "power_level", icon_override="mdi:gauge"),
GeErdPropertySensor(self, ErdCode.ADVANTIUM_COOK_STATUS, "warm_status", icon_override="mdi:radiator"),
GeErdPropertyBinarySensor(self, ErdCode.ADVANTIUM_COOK_STATUS, "door_status", device_class_override="door"),
GeErdPropertyBinarySensor(self, ErdCode.ADVANTIUM_COOK_STATUS, "sensing_active", icon_on_override="mdi:flash-auto", icon_off_override="mdi:flash-off"),
GeErdPropertyBinarySensor(self, ErdCode.ADVANTIUM_COOK_STATUS, "cooling_fan_status", icon_on_override="mdi:fan", icon_off_override="mdi:fan-off"),
GeErdPropertyBinarySensor(self, ErdCode.ADVANTIUM_COOK_STATUS, "oven_light_status", icon_on_override="mdi:lightbulb-on", icon_off_override="mdi:lightbulb-off"),
]
entities = base_entities + advantium_entities
return entities

def _single_name(self, erd_code: ErdCode):
return erd_code.name.replace(UPPER_OVEN+"_","").replace("_", " ").title()

12 changes: 11 additions & 1 deletion custom_components/ge_home/devices/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,16 @@ def entities(self) -> List[Entity]:

def get_all_entities(self) -> List[Entity]:
"""Create Entities for this device."""
return self.get_base_entities()

def get_base_entities(self) -> List[Entity]:
"""Create base entities (i.e. common between all appliances)."""
from ..entities import GeErdSensor, GeErdSwitch
entities = [
GeErdSensor(self, ErdCode.CLOCK_TIME),
GeErdSwitch(self, ErdCode.SABBATH_MODE),
]
return entities
return entities

def build_entities_list(self) -> None:
"""Build the entities list, adding anything new."""
Expand All @@ -123,3 +127,9 @@ def try_get_erd_value(self, code: ErdCodeType):
except:
return None

def has_erd_code(self, code: ErdCodeType):
try:
self.appliance.get_erd_value(code)
return True
except:
return False
21 changes: 17 additions & 4 deletions custom_components/ge_home/devices/dishwasher.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,39 @@
from gehomesdk.erd import ErdCode, ErdApplianceType

from .base import ApplianceApi
from ..entities import GeErdSensor, GeDishwasherControlLockedSwitch
from ..entities import GeErdSensor, GeErdBinarySensor, GeErdPropertySensor

_LOGGER = logging.getLogger(__name__)


class DishwasherApi(ApplianceApi):
"""API class for dishwasher objects"""
APPLIANCE_TYPE = ErdApplianceType.WASHER
APPLIANCE_TYPE = ErdApplianceType.DISH_WASHER

def get_all_entities(self) -> List[Entity]:
base_entities = super().get_all_entities()

dishwasher_entities = [
#GeDishwasherControlLockedSwitch(self, ErdCode.USER_INTERFACE_LOCKED),
GeErdSensor(self, ErdCode.DISHWASHER_CYCLE_NAME),
GeErdSensor(self, ErdCode.DISHWASHER_CYCLE_STATE),
GeErdSensor(self, ErdCode.DISHWASHER_CYCLE_STATE, icon_override="mdi:state-machine"),
GeErdSensor(self, ErdCode.DISHWASHER_OPERATING_MODE),
GeErdSensor(self, ErdCode.DISHWASHER_PODS_REMAINING_VALUE),
GeErdSensor(self, ErdCode.DISHWASHER_PODS_REMAINING_VALUE, uom_override="pods"),
GeErdSensor(self, ErdCode.DISHWASHER_RINSE_AGENT, icon_override="mdi:sparkles"),
GeErdSensor(self, ErdCode.DISHWASHER_TIME_REMAINING),
GeErdBinarySensor(self, ErdCode.DISHWASHER_DOOR_STATUS),

#User Setttings
GeErdPropertySensor(self, ErdCode.DISHWASHER_USER_SETTING, "sound", icon_override="mdi:volume-high"),
GeErdPropertySensor(self, ErdCode.DISHWASHER_USER_SETTING, "lock_control", icon_override="mdi:lock"),
GeErdPropertySensor(self, ErdCode.DISHWASHER_USER_SETTING, "sabbath", icon_override="mdi:judaism"),
GeErdPropertySensor(self, ErdCode.DISHWASHER_USER_SETTING, "cycle_mode", icon_override="mdi:state-machine"),
GeErdPropertySensor(self, ErdCode.DISHWASHER_USER_SETTING, "presoak", icon_override="mdi:water"),
GeErdPropertySensor(self, ErdCode.DISHWASHER_USER_SETTING, "bottle_jet", icon_override="mdi:bottle-tonic-outline"),
GeErdPropertySensor(self, ErdCode.DISHWASHER_USER_SETTING, "wash_temp", icon_override="mdi:coolant-temperature"),
GeErdPropertySensor(self, ErdCode.DISHWASHER_USER_SETTING, "dry_option", icon_override="mdi:fan"),
GeErdPropertySensor(self, ErdCode.DISHWASHER_USER_SETTING, "wash_zone", icon_override="mdi:dock-top"),
GeErdPropertySensor(self, ErdCode.DISHWASHER_USER_SETTING, "delay_hours", icon_override="mdi:clock-fast")
]
entities = base_entities + dishwasher_entities
return entities
Expand Down
56 changes: 43 additions & 13 deletions custom_components/ge_home/devices/dryer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,64 @@
from typing import List

from homeassistant.helpers.entity import Entity
from gehomesdk.erd import ErdCode, ErdApplianceType
from gehomesdk import ErdCode, ErdApplianceType

from .base import ApplianceApi
from ..entities import GeErdSensor, GeErdBinarySensor

_LOGGER = logging.getLogger(__name__)


class DryerApi(ApplianceApi):
"""API class for dryer objects"""
APPLIANCE_TYPE = ErdApplianceType.DRYER

def get_all_entities(self) -> List[Entity]:
base_entities = super().get_all_entities()

dryer_entities = [
GeErdSensor(self, ErdCode.LAUNDRY_MACHINE_STATE),
GeErdSensor(self, ErdCode.LAUNDRY_MACHINE_SUBCYCLE),
GeErdBinarySensor(self, ErdCode.LAUNDRY_END_OF_CYCLE),
common_entities = [
GeErdSensor(self, ErdCode.LAUNDRY_MACHINE_STATE, icon_override="mdi:tumble-dryer"),
GeErdSensor(self, ErdCode.LAUNDRY_CYCLE, icon_override="mdi:state-machine"),
GeErdSensor(self, ErdCode.LAUNDRY_SUB_CYCLE, icon_override="mdi:state-machine"),
GeErdBinarySensor(self, ErdCode.LAUNDRY_END_OF_CYCLE, icon_override="mdi:tumble-dryer"),
GeErdSensor(self, ErdCode.LAUNDRY_TIME_REMAINING),
GeErdSensor(self, ErdCode.LAUNDRY_CYCLE),
GeErdSensor(self, ErdCode.LAUNDRY_DELAY_TIME_REMAINING),
GeErdSensor(self, ErdCode.LAUNDRY_DOOR),
GeErdSensor(self, ErdCode.LAUNDRY_DRYNESSNEW_LEVEL),
GeErdSensor(self, ErdCode.LAUNDRY_TEMPERATURENEW_OPTION),
GeErdBinarySensor(self, ErdCode.LAUNDRY_REMOTE_STATUS)

GeErdBinarySensor(self, ErdCode.LAUNDRY_DOOR),
GeErdBinarySensor(self, ErdCode.LAUNDRY_REMOTE_STATUS, icon_override="mdi:tumble-dryer"),
]
entities = base_entities + dryer_entities

dryer_entities = self.get_dryer_entities()

entities = base_entities + common_entities + dryer_entities
return entities

def get_dryer_entities(self):
#Not all options appear to exist on every dryer... we'll look for the presence of
#a code to figure out which sensors are applicable beyond the common ones.
dryer_entities = [
]

if self.has_erd_code(ErdCode.LAUNDRY_DRYER_DRYNESS_LEVEL):
dryer_entities.extend([GeErdSensor(self, ErdCode.LAUNDRY_DRYER_DRYNESS_LEVEL)])
if self.has_erd_code(ErdCode.LAUNDRY_DRYER_DRYNESSNEW_LEVEL):
dryer_entities.extend([GeErdSensor(self, ErdCode.LAUNDRY_DRYER_DRYNESSNEW_LEVEL)])
if self.has_erd_code(ErdCode.LAUNDRY_DRYER_TEMPERATURE_OPTION):
dryer_entities.extend([GeErdSensor(self, ErdCode.LAUNDRY_DRYER_TEMPERATURE_OPTION)])
if self.has_erd_code(ErdCode.LAUNDRY_DRYER_TEMPERATURENEW_OPTION):
dryer_entities.extend([GeErdSensor(self, ErdCode.LAUNDRY_DRYER_TEMPERATURENEW_OPTION)])
if self.has_erd_code(ErdCode.LAUNDRY_DRYER_TUMBLE_STATUS):
dryer_entities.extend([GeErdSensor(self, ErdCode.LAUNDRY_DRYER_TUMBLE_STATUS)])
if self.has_erd_code(ErdCode.LAUNDRY_DRYER_TUMBLENEW_STATUS):
dryer_entities.extend([GeErdSensor(self, ErdCode.LAUNDRY_DRYER_TUMBLENEW_STATUS)])
if self.has_erd_code(ErdCode.LAUNDRY_DRYER_WASHERLINK_STATUS):
dryer_entities.extend([GeErdBinarySensor(self, ErdCode.LAUNDRY_DRYER_WASHERLINK_STATUS)])
if self.has_erd_code(ErdCode.LAUNDRY_DRYER_LEVEL_SENSOR_DISABLED):
dryer_entities.extend([GeErdBinarySensor(self, ErdCode.LAUNDRY_DRYER_LEVEL_SENSOR_DISABLED)])
if self.has_erd_code(ErdCode.LAUNDRY_DRYER_SHEET_USAGE_CONFIGURATION):
dryer_entities.extend([GeErdSensor(self, ErdCode.LAUNDRY_DRYER_SHEET_USAGE_CONFIGURATION)])
if self.has_erd_code(ErdCode.LAUNDRY_DRYER_SHEET_INVENTORY):
dryer_entities.extend([GeErdSensor(self, ErdCode.LAUNDRY_DRYER_SHEET_INVENTORY, icon_override="mdi:tray-full", uom_override="sheets")])
if self.has_erd_code(ErdCode.LAUNDRY_DRYER_ECODRY_STATUS):
dryer_entities.extend([GeErdSensor(self, ErdCode.LAUNDRY_DRYER_ECODRY_STATUS)])

return dryer_entities

2 changes: 1 addition & 1 deletion custom_components/ge_home/devices/fridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def get_all_entities(self) -> List[Entity]:
dispenser_entities.extend([
GeErdBinarySensor(self, ErdCode.HOT_WATER_IN_USE),
GeErdSensor(self, ErdCode.HOT_WATER_SET_TEMP),
GeErdPropertySensor(self, ErdCode.HOT_WATER_STATUS, "status"),
GeErdPropertySensor(self, ErdCode.HOT_WATER_STATUS, "status", icon_override="mdi:information-outline"),
GeErdPropertySensor(self, ErdCode.HOT_WATER_STATUS, "time_until_ready", icon_override="mdi:timer-outline"),
GeErdPropertySensor(self, ErdCode.HOT_WATER_STATUS, "current_temp", device_class_override=DEVICE_CLASS_TEMPERATURE),
GeErdPropertyBinarySensor(self, ErdCode.HOT_WATER_STATUS, "faulted", device_class_override=DEVICE_CLASS_PROBLEM),
Expand Down
5 changes: 4 additions & 1 deletion custom_components/ge_home/devices/oven.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ class OvenApi(ApplianceApi):
def get_all_entities(self) -> List[Entity]:
base_entities = super().get_all_entities()
oven_config: OvenConfiguration = self.appliance.get_erd_value(ErdCode.OVEN_CONFIGURATION)
cooktop_config: ErdCooktopConfig = self.appliance.get_erd_value(ErdCode.COOKTOP_CONFIG)

cooktop_config = ErdCooktopConfig.NONE
if self.has_erd_code(ErdCode.COOKTOP_CONFIG):
cooktop_config: ErdCooktopConfig = self.appliance.get_erd_value(ErdCode.COOKTOP_CONFIG)

_LOGGER.debug(f"Oven Config: {oven_config}")
_LOGGER.debug(f"Cooktop Config: {cooktop_config}")
Expand Down
Loading

0 comments on commit a62a9fd

Please sign in to comment.