mirror of https://github.com/simbaja/ha_gehome.git
Merge pull request #75 from simbaja/dev
Merge 0.6.0 Changes into Master
This commit is contained in:
commit
64fe8e62bd
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -1,6 +1,18 @@
|
|||
|
||||
# GE Home Appliances (SmartHQ) Changelog
|
||||
|
||||
## 0.6.0
|
||||
|
||||
- Requires HA 2021.12.x or later
|
||||
- Enabled authentication to both US and EU regions
|
||||
- Changed the sensors to use native value/uom
|
||||
- Changed the temperatures to always be natively fahrenheit (API appears to always use this system) (@vignatyuk)
|
||||
- Initial support for Microwaves (@mbcomer, @mnestor)
|
||||
- Initial support for Water Softeners (@npentell, @drjeff)
|
||||
- Initial support for Opal Ice Makers (@mbcomer, @knobunc)
|
||||
- Initial support for Coffee Makers (@alexanv1)
|
||||
- Updated deprecated icons (@mjmeli, @schmittx)
|
||||
|
||||
## 0.5.0
|
||||
|
||||
- Initial support for oven hoods (@digitalbites)
|
||||
|
@ -9,7 +21,7 @@
|
|||
- Fixed device info when serial not present (@Xe138)
|
||||
- Fixed issue with ovens when raw temperature not available (@chadohalloran)
|
||||
- Fixed issue where Split A/C temperature sensors report UOM incorrectly (@RobertusIT)
|
||||
- Added convertable drawer mode, proximity light, and interior lights to fridge (@grotto27, @elwing00)
|
||||
- Added convertable drawer mode, proximity light, and interior lights to fridge (@groto27, @elwing00)
|
||||
## 0.4.3
|
||||
|
||||
- Enabled support for appliances without serial numbers
|
||||
|
|
|
@ -12,12 +12,18 @@ Integration for GE WiFi-enabled appliances into Home Assistant. This integratio
|
|||
- Dishwasher
|
||||
- Laundry (Washer/Dryer)
|
||||
- Whole Home Water Filter
|
||||
- Whole Home Water Softener
|
||||
- A/C (Portable, Split, Window)
|
||||
- Range Hoods
|
||||
- Range Hood
|
||||
- Advantium
|
||||
- Microwave
|
||||
- Opal Ice Maker
|
||||
- Coffee Maker
|
||||
|
||||
**Forked from Andrew Mark's [repository](https://github.com/ajmarks/ha_components).**
|
||||
## Updates
|
||||
|
||||
Unfortunately, I'm pretty much at the end of what I can do without assistance from others with these devices that can help provide logs. I'll do what I can to make updates if there's something broken, but I am not really able to add new functionality if I can't get a little help to do so.
|
||||
## Home Assistant UI Examples
|
||||
Entities card:
|
||||
|
||||
|
|
|
@ -1,19 +1,38 @@
|
|||
"""The ge_home integration."""
|
||||
|
||||
import logging
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.const import CONF_REGION
|
||||
from .const import DOMAIN
|
||||
from .update_coordinator import GeHomeUpdateCoordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
CONFIG_SCHEMA = vol.Schema({DOMAIN: vol.Schema({})}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: dict):
|
||||
return True
|
||||
|
||||
async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry):
|
||||
"""Migrate old entry."""
|
||||
_LOGGER.debug("Migrating from version %s", config_entry.version)
|
||||
|
||||
if config_entry.version == 1:
|
||||
|
||||
new = {**config_entry.data}
|
||||
new[CONF_REGION] = "US"
|
||||
|
||||
config_entry.version = 2
|
||||
hass.config_entries.async_update_entry(config_entry, data=new)
|
||||
|
||||
_LOGGER.info("Migration to version %s successful", config_entry.version)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||
"""Set up the ge_home component."""
|
||||
|
|
|
@ -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)
|
|
@ -7,11 +7,17 @@ import aiohttp
|
|||
import asyncio
|
||||
import async_timeout
|
||||
|
||||
from gehomesdk import GeAuthFailedError, GeNotAuthenticatedError, GeGeneralServerError, async_get_oauth2_token
|
||||
from gehomesdk import (
|
||||
GeAuthFailedError,
|
||||
GeNotAuthenticatedError,
|
||||
GeGeneralServerError,
|
||||
async_get_oauth2_token,
|
||||
LOGIN_REGIONS
|
||||
)
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries, core
|
||||
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
|
||||
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, CONF_REGION
|
||||
|
||||
from .const import DOMAIN # pylint:disable=unused-import
|
||||
from .exceptions import HaAuthError, HaCannotConnect, HaAlreadyConfigured
|
||||
|
@ -19,7 +25,11 @@ from .exceptions import HaAuthError, HaCannotConnect, HaAlreadyConfigured
|
|||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
GEHOME_SCHEMA = vol.Schema(
|
||||
{vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str}
|
||||
{
|
||||
vol.Required(CONF_USERNAME): str,
|
||||
vol.Required(CONF_PASSWORD): str,
|
||||
vol.Required(CONF_REGION): vol.In(LOGIN_REGIONS.keys())
|
||||
}
|
||||
)
|
||||
|
||||
async def validate_input(hass: core.HomeAssistant, data):
|
||||
|
@ -30,7 +40,7 @@ async def validate_input(hass: core.HomeAssistant, data):
|
|||
# noinspection PyBroadException
|
||||
try:
|
||||
with async_timeout.timeout(10):
|
||||
_ = await async_get_oauth2_token(session, data[CONF_USERNAME], data[CONF_PASSWORD])
|
||||
_ = await async_get_oauth2_token(session, data[CONF_USERNAME], data[CONF_PASSWORD], data[CONF_REGION])
|
||||
except (asyncio.TimeoutError, aiohttp.ClientError):
|
||||
raise HaCannotConnect('Connection failure')
|
||||
except (GeAuthFailedError, GeNotAuthenticatedError):
|
||||
|
@ -47,7 +57,7 @@ async def validate_input(hass: core.HomeAssistant, data):
|
|||
class GeHomeConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for GE Home."""
|
||||
|
||||
VERSION = 1
|
||||
VERSION = 2
|
||||
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_PUSH
|
||||
|
||||
async def _async_validate_input(self, user_input):
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
"""Constants for the gehome integration."""
|
||||
from gehomesdk.clients.const import LOGIN_URL
|
||||
|
||||
DOMAIN = "ge_home"
|
||||
|
||||
|
@ -13,4 +12,4 @@ RETRY_OFFLINE_COUNT = 5
|
|||
|
||||
SERVICE_SET_TIMER = "set_timer"
|
||||
SERVICE_CLEAR_TIMER = "clear_timer"
|
||||
SERVICE_SET_INT_VALUE = "set_int_value"
|
||||
SERVICE_SET_INT_VALUE = "set_int_value"
|
||||
|
|
|
@ -16,6 +16,10 @@ from .wac import WacApi
|
|||
from .sac import SacApi
|
||||
from .pac import PacApi
|
||||
from .hood import HoodApi
|
||||
from .microwave import MicrowaveApi
|
||||
from .water_softener import WaterSoftenerApi
|
||||
from .oim import OimApi
|
||||
from .coffee_maker import CcmApi
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -37,6 +41,8 @@ def get_appliance_api_type(appliance_type: ErdApplianceType) -> Type:
|
|||
return WasherDryerApi
|
||||
if appliance_type == ErdApplianceType.POE_WATER_FILTER:
|
||||
return WaterFilterApi
|
||||
if appliance_type == ErdApplianceType.WATER_SOFTENER:
|
||||
return WaterSoftenerApi
|
||||
if appliance_type == ErdApplianceType.ADVANTIUM:
|
||||
return AdvantiumApi
|
||||
if appliance_type == ErdApplianceType.AIR_CONDITIONER:
|
||||
|
@ -47,6 +53,12 @@ def get_appliance_api_type(appliance_type: ErdApplianceType) -> Type:
|
|||
return PacApi
|
||||
if appliance_type == ErdApplianceType.HOOD:
|
||||
return HoodApi
|
||||
if appliance_type == ErdApplianceType.MICROWAVE:
|
||||
return MicrowaveApi
|
||||
if appliance_type == ErdApplianceType.OPAL_ICE_MAKER:
|
||||
return OimApi
|
||||
if appliance_type == ErdApplianceType.CAFE_COFFEE_MAKER:
|
||||
return CcmApi
|
||||
|
||||
# Fallback
|
||||
return ApplianceApi
|
||||
|
|
|
@ -2,7 +2,7 @@ import logging
|
|||
from typing import List
|
||||
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from gehomesdk.erd import ErdCode, ErdApplianceType
|
||||
from gehomesdk.erd import ErdCode, ErdApplianceType, ErdDataType
|
||||
|
||||
from .base import ApplianceApi
|
||||
from ..entities import GeAdvantium, GeErdSensor, GeErdBinarySensor, GeErdPropertySensor, GeErdPropertyBinarySensor, UPPER_OVEN
|
||||
|
@ -29,8 +29,8 @@ class AdvantiumApi(ApplianceApi):
|
|||
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, "temperature", icon_override="mdi:thermometer", data_type_override=ErdDataType.INT),
|
||||
GeErdPropertySensor(self, ErdCode.ADVANTIUM_COOK_STATUS, "power_level", icon_override="mdi:gauge", data_type_override=ErdDataType.INT),
|
||||
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"),
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
import logging
|
||||
from typing import List
|
||||
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from gehomesdk import (
|
||||
GeAppliance,
|
||||
ErdCode,
|
||||
ErdApplianceType,
|
||||
ErdCcmBrewSettings
|
||||
)
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
from .base import ApplianceApi
|
||||
from ..entities import (
|
||||
GeCcmPotNotPresentBinarySensor,
|
||||
GeErdSensor,
|
||||
GeErdBinarySensor,
|
||||
GeErdButton,
|
||||
GeCcmBrewStrengthSelect,
|
||||
GeCcmBrewTemperatureNumber,
|
||||
GeCcmBrewCupsNumber,
|
||||
GeCcmBrewSettingsButton
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
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()
|
||||
|
||||
ccm_entities = [
|
||||
GeErdBinarySensor(self, ErdCode.CCM_IS_BREWING),
|
||||
GeErdBinarySensor(self, ErdCode.CCM_IS_DESCALING),
|
||||
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")
|
||||
]
|
||||
|
||||
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)
|
|
@ -23,14 +23,14 @@ class DishwasherApi(ApplianceApi):
|
|||
GeErdSensor(self, ErdCode.DISHWASHER_CYCLE_STATE, icon_override="mdi:state-machine"),
|
||||
GeErdSensor(self, ErdCode.DISHWASHER_OPERATING_MODE),
|
||||
GeErdSensor(self, ErdCode.DISHWASHER_PODS_REMAINING_VALUE, uom_override="pods"),
|
||||
GeErdSensor(self, ErdCode.DISHWASHER_RINSE_AGENT, icon_override="mdi:sparkles"),
|
||||
GeErdSensor(self, ErdCode.DISHWASHER_RINSE_AGENT, icon_override="mdi:shimmer"),
|
||||
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, "sabbath", icon_override="mdi:star-david"),
|
||||
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"),
|
||||
|
|
|
@ -14,7 +14,8 @@ from gehomesdk import (
|
|||
ErdFilterStatus,
|
||||
HotWaterStatus,
|
||||
FridgeModelInfo,
|
||||
ErdConvertableDrawerMode
|
||||
ErdConvertableDrawerMode,
|
||||
ErdDataType
|
||||
)
|
||||
|
||||
from .base import ApplianceApi
|
||||
|
@ -110,7 +111,7 @@ class FridgeApi(ApplianceApi):
|
|||
GeErdSensor(self, ErdCode.HOT_WATER_SET_TEMP),
|
||||
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),
|
||||
GeErdPropertySensor(self, ErdCode.HOT_WATER_STATUS, "current_temp", device_class_override=DEVICE_CLASS_TEMPERATURE, data_type_override=ErdDataType.INT),
|
||||
GeErdPropertyBinarySensor(self, ErdCode.HOT_WATER_STATUS, "faulted", device_class_override=DEVICE_CLASS_PROBLEM),
|
||||
GeDispenser(self)
|
||||
])
|
||||
|
|
|
@ -14,7 +14,7 @@ from .base import ApplianceApi
|
|||
from ..entities import (
|
||||
GeHoodLightLevelSelect,
|
||||
GeHoodFanSpeedSelect,
|
||||
GeErdSensor,
|
||||
GeErdTimerSensor,
|
||||
GeErdSwitch,
|
||||
ErdOnOffBoolConverter
|
||||
)
|
||||
|
@ -45,7 +45,7 @@ class HoodApi(ApplianceApi):
|
|||
if light_availability and light_availability.is_available:
|
||||
hood_entities.append(GeHoodLightLevelSelect(self, ErdCode.HOOD_LIGHT_LEVEL))
|
||||
if timer_availability == ErdOnOff.ON:
|
||||
hood_entities.append(GeErdSensor(self, ErdCode.HOOD_TIMER))
|
||||
hood_entities.append(GeErdTimerSensor(self, ErdCode.HOOD_TIMER))
|
||||
|
||||
entities = base_entities + hood_entities
|
||||
return entities
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
import logging
|
||||
from typing import List
|
||||
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from gehomesdk import (
|
||||
ErdCode,
|
||||
ErdApplianceType,
|
||||
ErdHoodFanSpeedAvailability,
|
||||
ErdHoodLightLevelAvailability,
|
||||
ErdOnOff
|
||||
)
|
||||
|
||||
from .base import ApplianceApi
|
||||
from ..entities import (
|
||||
GeHoodLightLevelSelect,
|
||||
GeHoodFanSpeedSelect,
|
||||
GeErdPropertySensor,
|
||||
GeErdPropertyBinarySensor,
|
||||
GeErdBinarySensor,
|
||||
GeErdTimerSensor
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MicrowaveApi(ApplianceApi):
|
||||
"""API class for Microwave objects"""
|
||||
APPLIANCE_TYPE = ErdApplianceType.MICROWAVE
|
||||
|
||||
def get_all_entities(self) -> List[Entity]:
|
||||
base_entities = super().get_all_entities()
|
||||
|
||||
#get the availabilities
|
||||
fan_availability: ErdHoodFanSpeedAvailability = self.try_get_erd_value(ErdCode.HOOD_FAN_SPEED_AVAILABILITY)
|
||||
light_availability: ErdHoodLightLevelAvailability = self.try_get_erd_value(ErdCode.HOOD_LIGHT_LEVEL_AVAILABILITY)
|
||||
|
||||
mwave_entities = [
|
||||
GeErdBinarySensor(self, ErdCode.MICROWAVE_REMOTE_ENABLE),
|
||||
GeErdPropertySensor(self, ErdCode.MICROWAVE_STATE, "status"),
|
||||
GeErdPropertyBinarySensor(self, ErdCode.MICROWAVE_STATE, "door_status", device_class_override="door"),
|
||||
GeErdPropertySensor(self, ErdCode.MICROWAVE_STATE, "cook_mode", icon_override="mdi:food-turkey"),
|
||||
GeErdPropertySensor(self, ErdCode.MICROWAVE_STATE, "power_level", icon_override="mdi:gauge"),
|
||||
GeErdPropertySensor(self, ErdCode.MICROWAVE_STATE, "temperature", icon_override="mdi:thermometer"),
|
||||
GeErdTimerSensor(self, ErdCode.MICROWAVE_COOK_TIMER),
|
||||
GeErdTimerSensor(self, ErdCode.MICROWAVE_KITCHEN_TIMER)
|
||||
]
|
||||
|
||||
if fan_availability and fan_availability.is_available:
|
||||
mwave_entities.append(GeHoodFanSpeedSelect(self, ErdCode.HOOD_FAN_SPEED))
|
||||
#for now, represent as a select
|
||||
if light_availability and light_availability.is_available:
|
||||
mwave_entities.append(GeHoodLightLevelSelect(self, ErdCode.HOOD_LIGHT_LEVEL))
|
||||
|
||||
entities = base_entities + mwave_entities
|
||||
return entities
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import logging
|
||||
from typing import List
|
||||
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from gehomesdk import (
|
||||
ErdCode,
|
||||
ErdApplianceType,
|
||||
ErdOnOff
|
||||
)
|
||||
|
||||
from .base import ApplianceApi
|
||||
from ..entities import (
|
||||
OimLightLevelOptionsConverter,
|
||||
GeErdSensor,
|
||||
GeErdBinarySensor,
|
||||
GeErdSelect,
|
||||
GeErdSwitch,
|
||||
ErdOnOffBoolConverter
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OimApi(ApplianceApi):
|
||||
"""API class for Oven Hood objects"""
|
||||
APPLIANCE_TYPE = ErdApplianceType.HOOD
|
||||
|
||||
def get_all_entities(self) -> List[Entity]:
|
||||
base_entities = super().get_all_entities()
|
||||
|
||||
oim_entities = [
|
||||
GeErdSensor(self, ErdCode.OIM_STATUS),
|
||||
GeErdBinarySensor(self, ErdCode.OIM_FILTER_STATUS, device_class_override="problem"),
|
||||
GeErdSelect(self, ErdCode.OIM_LIGHT_LEVEL, OimLightLevelOptionsConverter()),
|
||||
GeErdSwitch(self, ErdCode.OIM_POWER, bool_converter=ErdOnOffBoolConverter(), icon_on_override="mdi:power-on", icon_off_override="mdi:power-off"),
|
||||
]
|
||||
|
||||
entities = base_entities + oim_entities
|
||||
return entities
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import logging
|
||||
from typing import List
|
||||
from gehomesdk.erd.erd_data_type import ErdDataType
|
||||
|
||||
from homeassistant.const import DEVICE_CLASS_POWER_FACTOR
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
@ -8,7 +9,8 @@ from gehomesdk import (
|
|||
ErdApplianceType,
|
||||
OvenConfiguration,
|
||||
ErdCooktopConfig,
|
||||
CooktopStatus
|
||||
CooktopStatus,
|
||||
ErdOvenLightLevelAvailability
|
||||
)
|
||||
|
||||
from .base import ApplianceApi
|
||||
|
@ -19,6 +21,7 @@ from ..entities import (
|
|||
GeErdPropertySensor,
|
||||
GeErdPropertyBinarySensor,
|
||||
GeOven,
|
||||
GeOvenLightLevelSelect,
|
||||
UPPER_OVEN,
|
||||
LOWER_OVEN
|
||||
)
|
||||
|
@ -40,6 +43,9 @@ class OvenApi(ApplianceApi):
|
|||
has_upper_raw_temperature = self.has_erd_code(ErdCode.UPPER_OVEN_RAW_TEMPERATURE)
|
||||
has_lower_raw_temperature = self.has_erd_code(ErdCode.LOWER_OVEN_RAW_TEMPERATURE)
|
||||
|
||||
upper_light_availability: ErdOvenLightLevelAvailability = self.try_get_erd_value(ErdCode.UPPER_OVEN_LIGHT_AVAILABILITY)
|
||||
lower_light_availability: ErdOvenLightLevelAvailability = self.try_get_erd_value(ErdCode.LOWER_OVEN_LIGHT_AVAILABILITY)
|
||||
|
||||
_LOGGER.debug(f"Oven Config: {oven_config}")
|
||||
_LOGGER.debug(f"Cooktop Config: {cooktop_config}")
|
||||
oven_entities = []
|
||||
|
@ -68,6 +74,8 @@ class OvenApi(ApplianceApi):
|
|||
oven_entities.append(GeErdSensor(self, ErdCode.UPPER_OVEN_RAW_TEMPERATURE))
|
||||
if has_lower_raw_temperature:
|
||||
oven_entities.append(GeErdSensor(self, ErdCode.LOWER_OVEN_RAW_TEMPERATURE))
|
||||
if lower_light_availability is None or lower_light_availability.is_available:
|
||||
oven_entities.append(GeOvenLightLevelSelect(self, ErdCode.LOWER_OVEN_LIGHT))
|
||||
else:
|
||||
oven_entities.extend([
|
||||
GeErdSensor(self, ErdCode.UPPER_OVEN_COOK_MODE, self._single_name(ErdCode.UPPER_OVEN_COOK_MODE)),
|
||||
|
@ -80,6 +88,8 @@ class OvenApi(ApplianceApi):
|
|||
])
|
||||
if has_upper_raw_temperature:
|
||||
oven_entities.append(GeErdSensor(self, ErdCode.UPPER_OVEN_RAW_TEMPERATURE, self._single_name(ErdCode.UPPER_OVEN_RAW_TEMPERATURE)))
|
||||
if upper_light_availability is None or upper_light_availability.is_available:
|
||||
oven_entities.append(GeOvenLightLevelSelect(self, ErdCode.UPPER_OVEN_LIGHT, self._single_name(ErdCode.UPPER_OVEN_LIGHT)))
|
||||
|
||||
|
||||
if cooktop_config == ErdCooktopConfig.PRESENT:
|
||||
|
@ -92,7 +102,7 @@ class OvenApi(ApplianceApi):
|
|||
cooktop_entities.append(GeErdPropertyBinarySensor(self, ErdCode.COOKTOP_STATUS, prop+".on"))
|
||||
cooktop_entities.append(GeErdPropertyBinarySensor(self, ErdCode.COOKTOP_STATUS, prop+".synchronized"))
|
||||
if not v.on_off_only:
|
||||
cooktop_entities.append(GeErdPropertySensor(self, ErdCode.COOKTOP_STATUS, prop+".power_pct", icon_override="mdi:fire", device_class_override=DEVICE_CLASS_POWER_FACTOR))
|
||||
cooktop_entities.append(GeErdPropertySensor(self, ErdCode.COOKTOP_STATUS, prop+".power_pct", icon_override="mdi:fire", device_class_override=DEVICE_CLASS_POWER_FACTOR, data_type_override=ErdDataType.INT))
|
||||
|
||||
return base_entities + oven_entities + cooktop_entities
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ from homeassistant.helpers.entity import Entity
|
|||
from gehomesdk.erd import ErdCode, ErdApplianceType
|
||||
|
||||
from .base import ApplianceApi
|
||||
from ..entities import GeSacClimate, GeSacTemperatureSensor, GeErdSensor, GeErdSwitch, ErdOnOffBoolConverter
|
||||
from ..entities import GeSacClimate, GeErdSensor, GeErdSwitch, ErdOnOffBoolConverter
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -19,8 +19,8 @@ class SacApi(ApplianceApi):
|
|||
|
||||
sac_entities = [
|
||||
GeSacClimate(self),
|
||||
GeSacTemperatureSensor(self, ErdCode.AC_TARGET_TEMPERATURE),
|
||||
GeSacTemperatureSensor(self, ErdCode.AC_AMBIENT_TEMPERATURE),
|
||||
GeErdSensor(self, ErdCode.AC_TARGET_TEMPERATURE),
|
||||
GeErdSensor(self, ErdCode.AC_AMBIENT_TEMPERATURE),
|
||||
GeErdSensor(self, ErdCode.AC_FAN_SETTING, icon_override="mdi:fan"),
|
||||
GeErdSensor(self, ErdCode.AC_OPERATION_MODE),
|
||||
GeErdSwitch(self, ErdCode.AC_POWER_STATUS, bool_converter=ErdOnOffBoolConverter(), icon_on_override="mdi:power-on", icon_off_override="mdi:power-off"),
|
||||
|
|
|
@ -7,6 +7,7 @@ from gehomesdk import ErdCode, ErdApplianceType
|
|||
from .base import ApplianceApi
|
||||
from ..entities import (
|
||||
GeErdSensor,
|
||||
GeErdPropertySensor,
|
||||
GeErdBinarySensor,
|
||||
GeErdFilterPositionSelect,
|
||||
)
|
||||
|
@ -28,7 +29,7 @@ class WaterFilterApi(ApplianceApi):
|
|||
GeErdFilterPositionSelect(self, ErdCode.WH_FILTER_POSITION),
|
||||
GeErdBinarySensor(self, ErdCode.WH_FILTER_MANUAL_MODE, icon_on_override="mdi:human", icon_off_override="mdi:robot"),
|
||||
GeErdBinarySensor(self, ErdCode.WH_FILTER_LEAK_VALIDITY, device_class_override="moisture"),
|
||||
GeErdSensor(self, ErdCode.WH_FILTER_FLOW_RATE),
|
||||
GeErdPropertySensor(self, ErdCode.WH_FILTER_FLOW_RATE, "flow_rate"),
|
||||
GeErdSensor(self, ErdCode.WH_FILTER_DAY_USAGE),
|
||||
GeErdSensor(self, ErdCode.WH_FILTER_LIFE_REMAINING),
|
||||
GeErdBinarySensor(self, ErdCode.WH_FILTER_FLOW_ALERT, device_class_override="moisture"),
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
import logging
|
||||
from typing import List
|
||||
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from gehomesdk import ErdCode, ErdApplianceType
|
||||
|
||||
from .base import ApplianceApi
|
||||
from ..entities import (
|
||||
GeErdSensor,
|
||||
GeErdPropertySensor,
|
||||
GeErdBinarySensor,
|
||||
GeErdShutoffPositionSelect,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WaterSoftenerApi(ApplianceApi):
|
||||
"""API class for water softener objects"""
|
||||
|
||||
APPLIANCE_TYPE = ErdApplianceType.WATER_SOFTENER
|
||||
|
||||
def get_all_entities(self) -> List[Entity]:
|
||||
base_entities = super().get_all_entities()
|
||||
|
||||
ws_entities = [
|
||||
GeErdBinarySensor(self, ErdCode.WH_FILTER_MANUAL_MODE, icon_on_override="mdi:human", icon_off_override="mdi:robot"),
|
||||
GeErdPropertySensor(self, ErdCode.WH_FILTER_FLOW_RATE, "flow_rate"),
|
||||
GeErdBinarySensor(self, ErdCode.WH_FILTER_FLOW_ALERT, device_class_override="moisture"),
|
||||
GeErdSensor(self, ErdCode.WH_FILTER_DAY_USAGE),
|
||||
GeErdSensor(self, ErdCode.WH_SOFTENER_ERROR_CODE, icon_override="mdi:alert-circle"),
|
||||
GeErdBinarySensor(self, ErdCode.WH_SOFTENER_LOW_SALT, icon_on_override="mdi:alert", icon_off_override="mdi:grain"),
|
||||
GeErdSensor(self, ErdCode.WH_SOFTENER_SHUTOFF_VALVE_STATE, icon_override="mdi:state-machine"),
|
||||
GeErdSensor(self, ErdCode.WH_SOFTENER_SALT_LIFE_REMAINING, icon_override="mdi:calendar-clock"),
|
||||
GeErdShutoffPositionSelect(self, ErdCode.WH_SOFTENER_SHUTOFF_VALVE_CONTROL),
|
||||
]
|
||||
entities = base_entities + ws_entities
|
||||
return entities
|
|
@ -5,4 +5,7 @@ from .oven import *
|
|||
from .water_filter import *
|
||||
from .advantium import *
|
||||
from .ac import *
|
||||
from .hood import *
|
||||
from .hood import *
|
||||
from .water_softener import *
|
||||
from .opal_ice_maker import *
|
||||
from .ccm import *
|
|
@ -1,4 +1,3 @@
|
|||
from .ge_wac_climate import GeWacClimate
|
||||
from .ge_sac_climate import GeSacClimate
|
||||
from .ge_pac_climate import GePacClimate
|
||||
from .ge_sac_temperature_sensor import GeSacTemperatureSensor
|
||||
from .ge_pac_climate import GePacClimate
|
|
@ -66,11 +66,6 @@ class GePacClimate(GeClimate):
|
|||
#construct the converter based on the available modes
|
||||
self._hvac_mode_converter = PacHvacModeOptionsConverter(self._modes)
|
||||
|
||||
@property
|
||||
def temperature_unit(self):
|
||||
#SAC appears to be hard coded to use Fahrenheit internally, no matter what the display shows
|
||||
return TEMP_FAHRENHEIT
|
||||
|
||||
@property
|
||||
def min_temp(self) -> float:
|
||||
temp = 64
|
||||
|
|
|
@ -69,12 +69,6 @@ class GeSacClimate(GeClimate):
|
|||
#construct the converter based on the available modes
|
||||
self._hvac_mode_converter = SacHvacModeOptionsConverter(self._modes)
|
||||
|
||||
|
||||
@property
|
||||
def temperature_unit(self):
|
||||
#SAC appears to be hard coded to use Fahrenheit internally, no matter what the display shows
|
||||
return TEMP_FAHRENHEIT
|
||||
|
||||
@property
|
||||
def min_temp(self) -> float:
|
||||
temp = 60
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
import logging
|
||||
from typing import Any, List, Optional
|
||||
|
||||
from homeassistant.const import (
|
||||
TEMP_FAHRENHEIT
|
||||
)
|
||||
from ..common import GeErdSensor
|
||||
|
||||
class GeSacTemperatureSensor(GeErdSensor):
|
||||
"""Class for Split A/C temperature sensors"""
|
||||
|
||||
@property
|
||||
def _temp_units(self) -> Optional[str]:
|
||||
#SAC appears to be hard coded to use Fahrenheit internally, no matter what the display shows
|
||||
return TEMP_FAHRENHEIT
|
|
@ -0,0 +1,5 @@
|
|||
from .ge_ccm_pot_not_present_binary_sensor import GeCcmPotNotPresentBinarySensor
|
||||
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
|
|
@ -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
|
|
@ -0,0 +1,8 @@
|
|||
from ..common import GeErdBinarySensor
|
||||
|
||||
class GeCcmPotNotPresentBinarySensor(GeErdBinarySensor):
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return True if entity is not pot present."""
|
||||
return not self._boolify(self.appliance.get_erd_value(self.erd_code))
|
||||
|
|
@ -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
|
|
@ -82,10 +82,12 @@ class GeClimate(GeEntity, ClimateEntity):
|
|||
|
||||
@property
|
||||
def temperature_unit(self):
|
||||
measurement_system = self.appliance.get_erd_value(ErdCode.TEMPERATURE_UNIT)
|
||||
if measurement_system == ErdMeasurementUnits.METRIC:
|
||||
return TEMP_CELSIUS
|
||||
#appears to always be Fahrenheit internally, hardcode this
|
||||
return TEMP_FAHRENHEIT
|
||||
#measurement_system = self.appliance.get_erd_value(ErdCode.TEMPERATURE_UNIT)
|
||||
#if measurement_system == ErdMeasurementUnits.METRIC:
|
||||
# return TEMP_CELSIUS
|
||||
#return TEMP_FAHRENHEIT
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
|
|
|
@ -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):
|
||||
|
@ -104,7 +104,7 @@ class GeErdEntity(GeEntity):
|
|||
if self.erd_code_class == ErdCodeClass.LOCK_CONTROL:
|
||||
return "mdi:lock-outline"
|
||||
if self.erd_code_class == ErdCodeClass.SABBATH_CONTROL:
|
||||
return "mdi:judaism"
|
||||
return "mdi:star-david"
|
||||
if self.erd_code_class == ErdCodeClass.COOLING_CONTROL:
|
||||
return "mdi:snowflake"
|
||||
if self.erd_code_class == ErdCodeClass.OVEN_SENSOR:
|
||||
|
@ -138,6 +138,12 @@ class GeErdEntity(GeEntity):
|
|||
if self.erd_code_class == ErdCodeClass.FAN:
|
||||
return "mdi:fan"
|
||||
if self.erd_code_class == ErdCodeClass.LIGHT:
|
||||
return "mdi:lightbulb"
|
||||
return "mdi:lightbulb"
|
||||
if self.erd_code_class == ErdCodeClass.OIM_SENSOR:
|
||||
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}")
|
|
@ -1,7 +1,7 @@
|
|||
from typing import Optional
|
||||
|
||||
import magicattr
|
||||
from gehomesdk import ErdCode, ErdCodeType, ErdMeasurementUnits
|
||||
from gehomesdk import ErdCode, ErdCodeType, ErdMeasurementUnits, ErdDataType
|
||||
from ...devices import ApplianceApi
|
||||
from .ge_erd_sensor import GeErdSensor
|
||||
|
||||
|
@ -11,13 +11,14 @@ class GeErdPropertySensor(GeErdSensor):
|
|||
def __init__(
|
||||
self, api: ApplianceApi, erd_code: ErdCodeType, erd_property: str,
|
||||
erd_override: str = None, icon_override: str = None, device_class_override: str = None,
|
||||
state_class_override: str = None, uom_override: str = None
|
||||
state_class_override: str = None, uom_override: str = None, data_type_override: ErdDataType = None
|
||||
):
|
||||
super().__init__(
|
||||
api, erd_code, erd_override=erd_override,
|
||||
icon_override=icon_override, device_class_override=device_class_override,
|
||||
state_class_override=state_class_override,
|
||||
uom_override=uom_override
|
||||
uom_override=uom_override,
|
||||
data_type_override=data_type_override
|
||||
)
|
||||
self.erd_property = erd_property
|
||||
self._erd_property_cleansed = erd_property.replace(".","_").replace("[","_").replace("]","_")
|
||||
|
@ -33,9 +34,17 @@ class GeErdPropertySensor(GeErdSensor):
|
|||
return f"{base_string} {property_name}"
|
||||
|
||||
@property
|
||||
def state(self) -> Optional[str]:
|
||||
def native_value(self):
|
||||
try:
|
||||
value = magicattr.get(self.appliance.get_erd_value(self.erd_code), self.erd_property)
|
||||
|
||||
# if it's a numeric data type, return it directly
|
||||
if self._data_type in [ErdDataType.INT, ErdDataType.FLOAT]:
|
||||
return value
|
||||
|
||||
# otherwise, return a stringified version
|
||||
# TODO: perhaps enhance so that there's a list of variables available
|
||||
# for the stringify function to consume...
|
||||
return self._stringify(value, temp_units=self._temp_units)
|
||||
except KeyError:
|
||||
return None
|
||||
return self._stringify(value, temp_units=self._temp_units)
|
||||
return None
|
|
@ -1,6 +1,7 @@
|
|||
import logging
|
||||
from typing import Optional
|
||||
from homeassistant.components.sensor import STATE_CLASS_MEASUREMENT
|
||||
from gehomesdk.erd.erd_data_type import ErdDataType
|
||||
from homeassistant.components.sensor import SensorEntity, SensorStateClass
|
||||
|
||||
from homeassistant.const import (
|
||||
DEVICE_CLASS_ENERGY,
|
||||
|
@ -8,29 +9,15 @@ from homeassistant.const import (
|
|||
DEVICE_CLASS_TEMPERATURE,
|
||||
DEVICE_CLASS_BATTERY,
|
||||
DEVICE_CLASS_POWER_FACTOR,
|
||||
DEVICE_CLASS_TIMESTAMP,
|
||||
TEMP_CELSIUS,
|
||||
TEMP_FAHRENHEIT,
|
||||
)
|
||||
#from homeassistant.components.sensor import (
|
||||
# STATE_CLASS_MEASUREMENT,
|
||||
# STATE_CLASS_TOTAL_INCREASING
|
||||
#)
|
||||
# For now, let's not force the newer version, we'll use the same constants
|
||||
# but it'll be optional.
|
||||
# TODO: Force the usage of new HA
|
||||
STATE_CLASS_MEASUREMENT = "measurement"
|
||||
STATE_CLASS_TOTAL_INCREASING = 'total_increasing'
|
||||
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from gehomesdk import ErdCode, ErdCodeType, ErdCodeClass, ErdMeasurementUnits
|
||||
|
||||
from gehomesdk import ErdCodeType, ErdCodeClass
|
||||
from .ge_erd_entity import GeErdEntity
|
||||
from ...devices import ApplianceApi
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
class GeErdSensor(GeErdEntity, Entity):
|
||||
class GeErdSensor(GeErdEntity, SensorEntity):
|
||||
"""GE Entity for sensors"""
|
||||
|
||||
def __init__(
|
||||
|
@ -42,34 +29,62 @@ class GeErdSensor(GeErdEntity, Entity):
|
|||
device_class_override: str = None,
|
||||
state_class_override: str = None,
|
||||
uom_override: str = None,
|
||||
data_type_override: ErdDataType = None
|
||||
):
|
||||
super().__init__(api, erd_code, erd_override, icon_override, device_class_override)
|
||||
self._uom_override = uom_override
|
||||
self._state_class_override = state_class_override
|
||||
self._data_type_override = data_type_override
|
||||
|
||||
@property
|
||||
def state(self) -> Optional[str]:
|
||||
def native_value(self):
|
||||
try:
|
||||
value = self.appliance.get_erd_value(self.erd_code)
|
||||
|
||||
# if it's a numeric data type, return it directly
|
||||
if self._data_type in [ErdDataType.INT, ErdDataType.FLOAT]:
|
||||
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
|
||||
# for the stringify function to consume...
|
||||
return self._stringify(value, temp_units=self._temp_units)
|
||||
except KeyError:
|
||||
return None
|
||||
# TODO: perhaps enhance so that there's a list of variables available
|
||||
# for the stringify function to consume...
|
||||
return self._stringify(value, temp_units=self._temp_units)
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self) -> Optional[str]:
|
||||
def native_unit_of_measurement(self) -> Optional[str]:
|
||||
return self._get_uom()
|
||||
|
||||
@property
|
||||
def state_class(self) -> Optional[str]:
|
||||
return self._get_state_class()
|
||||
|
||||
@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 _temp_units(self) -> Optional[str]:
|
||||
if self._measurement_system == ErdMeasurementUnits.METRIC:
|
||||
return TEMP_CELSIUS
|
||||
return TEMP_FAHRENHEIT
|
||||
#based on testing, all API values are in Fahrenheit, so we'll redefine
|
||||
#this property to be the configured temperature unit and set the native
|
||||
#unit differently
|
||||
return self.api.hass.config.units.temperature_unit
|
||||
|
||||
#if self._measurement_system == ErdMeasurementUnits.METRIC:
|
||||
# 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"""
|
||||
|
@ -83,7 +98,10 @@ class GeErdSensor(GeErdEntity, Entity):
|
|||
in [ErdCodeClass.RAW_TEMPERATURE, ErdCodeClass.NON_ZERO_TEMPERATURE]
|
||||
or self.device_class == DEVICE_CLASS_TEMPERATURE
|
||||
):
|
||||
return self._temp_units
|
||||
#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
|
||||
if (
|
||||
self.erd_code_class == ErdCodeClass.BATTERY
|
||||
or self.device_class == DEVICE_CLASS_BATTERY
|
||||
|
@ -94,12 +112,12 @@ class GeErdSensor(GeErdEntity, Entity):
|
|||
if self.device_class == DEVICE_CLASS_POWER_FACTOR:
|
||||
return "%"
|
||||
if self.erd_code_class == ErdCodeClass.FLOW_RATE:
|
||||
if self._measurement_system == ErdMeasurementUnits.METRIC:
|
||||
return "lpm"
|
||||
#if self._measurement_system == ErdMeasurementUnits.METRIC:
|
||||
# return "lpm"
|
||||
return "gpm"
|
||||
if self.erd_code_class == ErdCodeClass.LIQUID_VOLUME:
|
||||
if self._measurement_system == ErdMeasurementUnits.METRIC:
|
||||
return "l"
|
||||
#if self._measurement_system == ErdMeasurementUnits.METRIC:
|
||||
# return "l"
|
||||
return "g"
|
||||
return None
|
||||
|
||||
|
@ -125,11 +143,11 @@ class GeErdSensor(GeErdEntity, Entity):
|
|||
return self._state_class_override
|
||||
|
||||
if self.device_class in [DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_ENERGY]:
|
||||
return STATE_CLASS_MEASUREMENT
|
||||
return SensorStateClass.MEASUREMENT
|
||||
if self.erd_code_class in [ErdCodeClass.FLOW_RATE, ErdCodeClass.PERCENTAGE]:
|
||||
return STATE_CLASS_MEASUREMENT
|
||||
return SensorStateClass.MEASUREMENT
|
||||
if self.erd_code_class in [ErdCodeClass.LIQUID_VOLUME]:
|
||||
return STATE_CLASS_TOTAL_INCREASING
|
||||
return SensorStateClass.TOTAL_INCREASING
|
||||
|
||||
return None
|
||||
|
||||
|
|
|
@ -34,9 +34,10 @@ class GeWaterHeater(GeEntity, WaterHeaterEntity, metaclass=abc.ABCMeta):
|
|||
|
||||
@property
|
||||
def temperature_unit(self):
|
||||
measurement_system = self.appliance.get_erd_value(ErdCode.TEMPERATURE_UNIT)
|
||||
if measurement_system == ErdMeasurementUnits.METRIC:
|
||||
return TEMP_CELSIUS
|
||||
#It appears that the GE API is alwasy Fehrenheit
|
||||
#measurement_system = self.appliance.get_erd_value(ErdCode.TEMPERATURE_UNIT)
|
||||
#if measurement_system == ErdMeasurementUnits.METRIC:
|
||||
# return TEMP_CELSIUS
|
||||
return TEMP_FAHRENHEIT
|
||||
|
||||
@property
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
from .oim_light_level_options import OimLightLevelOptionsConverter
|
|
@ -0,0 +1,26 @@
|
|||
import logging
|
||||
from typing import List, Any, Optional
|
||||
|
||||
from gehomesdk import ErdCodeType, ErdOimLightLevel, ErdCode
|
||||
from ...devices import ApplianceApi
|
||||
from ..common import GeErdSelect, OptionsConverter
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
class OimLightLevelOptionsConverter(OptionsConverter):
|
||||
@property
|
||||
def options(self) -> List[str]:
|
||||
return [i.stringify() for i in ErdOimLightLevel]
|
||||
def from_option_string(self, value: str) -> Any:
|
||||
try:
|
||||
return ErdOimLightLevel[value.upper()]
|
||||
except:
|
||||
_LOGGER.warn(f"Could not set hood light level to {value.upper()}")
|
||||
return ErdOimLightLevel.OFF
|
||||
def to_option_string(self, value: ErdOimLightLevel) -> Optional[str]:
|
||||
try:
|
||||
if value is not None:
|
||||
return value.stringify()
|
||||
except:
|
||||
pass
|
||||
return ErdOimLightLevel.OFF.stringify()
|
|
@ -1,2 +1,3 @@
|
|||
from .ge_oven import GeOven
|
||||
from .ge_oven_light_level_select import GeOvenLightLevelSelect
|
||||
from .const import UPPER_OVEN, LOWER_OVEN
|
|
@ -0,0 +1,66 @@
|
|||
import logging
|
||||
from typing import List, Any, Optional
|
||||
|
||||
from gehomesdk import ErdCodeType, ErdOvenLightLevelAvailability, ErdOvenLightLevel, ErdCode
|
||||
from ...devices import ApplianceApi
|
||||
from ..common import GeErdSelect, OptionsConverter
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
class OvenLightLevelOptionsConverter(OptionsConverter):
|
||||
def __init__(self, availability: ErdOvenLightLevelAvailability):
|
||||
super().__init__()
|
||||
self.availability = availability
|
||||
self.excluded_levels = [ErdOvenLightLevel.NOT_AVAILABLE]
|
||||
|
||||
if not availability or not availability.dim_available:
|
||||
self.excluded_levels.append(ErdOvenLightLevel.DIM)
|
||||
|
||||
@property
|
||||
def options(self) -> List[str]:
|
||||
return [i.stringify() for i in ErdOvenLightLevel if i not in self.excluded_levels]
|
||||
def from_option_string(self, value: str) -> Any:
|
||||
try:
|
||||
return ErdOvenLightLevel[value.upper()]
|
||||
except:
|
||||
_LOGGER.warn(f"Could not set Oven light level to {value.upper()}")
|
||||
return ErdOvenLightLevel.OFF
|
||||
def to_option_string(self, value: ErdOvenLightLevel) -> Optional[str]:
|
||||
try:
|
||||
if value is not None:
|
||||
return value.stringify()
|
||||
except:
|
||||
pass
|
||||
return ErdOvenLightLevel.OFF.stringify()
|
||||
|
||||
class GeOvenLightLevelSelect(GeErdSelect):
|
||||
|
||||
def __init__(self, api: ApplianceApi, erd_code: ErdCodeType, erd_override: str = None):
|
||||
self._availability: ErdOvenLightLevelAvailability = api.try_get_erd_value(ErdCode.LOWER_OVEN_LIGHT_AVAILABILITY)
|
||||
|
||||
#check to see if we have a status
|
||||
value: ErdOvenLightLevel = api.try_get_erd_value(erd_code)
|
||||
self._has_status = value is not None and value != ErdOvenLightLevel.NOT_AVAILABLE
|
||||
self._assumed_state = ErdOvenLightLevel.OFF
|
||||
|
||||
super().__init__(api, erd_code, OvenLightLevelOptionsConverter(self._availability), erd_override=erd_override)
|
||||
|
||||
@property
|
||||
def assumed_state(self) -> bool:
|
||||
return not self._has_status
|
||||
|
||||
@property
|
||||
def current_option(self):
|
||||
if self.assumed_state:
|
||||
return self._assumed_state
|
||||
|
||||
return self._converter.to_option_string(self.appliance.get_erd_value(self.erd_code))
|
||||
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
"""Change the selected option."""
|
||||
_LOGGER.debug(f"Setting select from {self.current_option} to {option}")
|
||||
|
||||
new_state = self._converter.from_option_string(option)
|
||||
await self.appliance.async_set_erd_value(self.erd_code, new_state)
|
||||
self._assumed_state = new_state
|
||||
|
|
@ -0,0 +1 @@
|
|||
from .shutoff_position import GeErdShutoffPositionSelect
|
|
@ -0,0 +1,65 @@
|
|||
import logging
|
||||
from typing import List, Any, Optional
|
||||
|
||||
from gehomesdk import ErdCodeType, ErdWaterSoftenerShutoffValveState, ErdCode
|
||||
from ...devices import ApplianceApi
|
||||
from ..common import GeErdSelect, OptionsConverter
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
class FilterPositionOptionsConverter(OptionsConverter):
|
||||
@property
|
||||
def options(self) -> List[str]:
|
||||
return [i.name.title()
|
||||
for i in ErdWaterSoftenerShutoffValveState
|
||||
if i not in [ErdWaterSoftenerShutoffValveState.UNKNOWN, ErdWaterSoftenerShutoffValveState.TRANSITION]]
|
||||
def from_option_string(self, value: str) -> Any:
|
||||
try:
|
||||
return ErdWaterSoftenerShutoffValveState[value.upper()]
|
||||
except:
|
||||
_LOGGER.warn(f"Could not set filter position to {value.upper()}")
|
||||
return ErdWaterSoftenerShutoffValveState.UNKNOWN
|
||||
def to_option_string(self, value: Any) -> Optional[str]:
|
||||
try:
|
||||
if value is not None:
|
||||
return value.name.title()
|
||||
except:
|
||||
pass
|
||||
return ErdWaterSoftenerShutoffValveState.UNKNOWN.name.title()
|
||||
|
||||
class GeErdShutoffPositionSelect(GeErdSelect):
|
||||
def __init__(self, api: ApplianceApi, erd_code: ErdCodeType):
|
||||
super().__init__(api, erd_code, FilterPositionOptionsConverter(), icon_override="mdi:valve")
|
||||
|
||||
@property
|
||||
def current_option(self):
|
||||
"""Return the current selected option"""
|
||||
|
||||
#if we're transitioning or don't know what the mode is, don't allow changes
|
||||
mode: ErdWaterSoftenerShutoffValveState = self.appliance.get_erd_value(ErdCode.WH_SOFTENER_SHUTOFF_VALVE_STATE)
|
||||
if mode in [ErdWaterSoftenerShutoffValveState.TRANSITION, ErdWaterSoftenerShutoffValveState.UNKNOWN]:
|
||||
return mode.name.title()
|
||||
|
||||
return self._converter.to_option_string(self.appliance.get_erd_value(self.erd_code))
|
||||
|
||||
@property
|
||||
def options(self) -> List[str]:
|
||||
"""Return a list of options"""
|
||||
|
||||
#if we're transitioning or don't know what the mode is, don't allow changes
|
||||
mode: ErdWaterSoftenerShutoffValveState = self.appliance.get_erd_value(ErdCode.WH_SOFTENER_SHUTOFF_VALVE_STATE)
|
||||
if mode in [ErdWaterSoftenerShutoffValveState.TRANSITION, ErdWaterSoftenerShutoffValveState.UNKNOWN]:
|
||||
return mode.name.title()
|
||||
|
||||
return self._converter.options
|
||||
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
value = self._converter.from_option_string(option)
|
||||
if value in [ErdWaterSoftenerShutoffValveState.UNKNOWN, ErdWaterSoftenerShutoffValveState.TRANSITION]:
|
||||
_LOGGER.debug("Cannot set position to transition/unknown")
|
||||
return
|
||||
if self.appliance.get_erd_value(ErdCode.WH_SOFTENER_SHUTOFF_VALVE_STATE) == ErdWaterSoftenerShutoffValveState.TRANSITION:
|
||||
_LOGGER.debug("Cannot set position if in transition")
|
||||
return
|
||||
|
||||
return await super().async_select_option(option)
|
|
@ -3,7 +3,7 @@
|
|||
"name": "GE Home (SmartHQ)",
|
||||
"config_flow": true,
|
||||
"documentation": "https://github.com/simbaja/ha_gehome",
|
||||
"requirements": ["gehomesdk==0.4.12","magicattr==0.1.5"],
|
||||
"requirements": ["gehomesdk==0.4.25","magicattr==0.1.5","slixmpp==1.7.1"],
|
||||
"codeowners": ["@simbaja"],
|
||||
"version": "0.5.0"
|
||||
"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})")
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "GE Home (SmartHQ)",
|
||||
"homeassistant": "2021.7.1",
|
||||
"domains": ["binary_sensor", "sensor", "switch", "water_heater", "select"],
|
||||
"homeassistant": "2021.12.0",
|
||||
"domains": ["binary_sensor", "sensor", "switch", "water_heater", "select", "button", "climate", "light", "number"],
|
||||
"iot_class": "Cloud Polling"
|
||||
}
|
||||
|
|
32
info.md
32
info.md
|
@ -2,15 +2,25 @@
|
|||
|
||||
Integration for GE WiFi-enabled appliances into Home Assistant. This integration currently support the following devices:
|
||||
|
||||
- Fridge
|
||||
- Fridge
|
||||
- Oven
|
||||
- Dishwasher
|
||||
- Laundry (Washer/Dryer)
|
||||
- Whole Home Water Filter
|
||||
- Whole Home Water Softener
|
||||
- A/C (Portable, Split, Window)
|
||||
- Range Hood
|
||||
- Advantium
|
||||
- Microwave
|
||||
- Opal Ice Maker
|
||||
- Coffee Maker
|
||||
|
||||
**Forked from Andrew Mark's [repository](https://github.com/ajmarks/ha_components).**
|
||||
|
||||
## Updates
|
||||
|
||||
Unfortunately, I'm pretty much at the end of what I can do without assistance from others with these devices that can help provide logs. I'll do what I can to make updates if there's something broken, but I am not really able to add new functionality if I can't get a little help to do so.
|
||||
|
||||
## Home Assistant UI Examples
|
||||
Entities card:
|
||||
|
||||
|
@ -34,6 +44,13 @@ A/C Controls:
|
|||
|
||||
#### Breaking Changes
|
||||
|
||||
{% if version_installed.split('.') | map('int') < '0.6.0'.split('.') | map('int') %}
|
||||
- Requires HA version 2021.12.0 or later
|
||||
- Enabled authentication to both US and EU regions (may require re-auth)
|
||||
- Changed the sensors to use native value/uom
|
||||
- Changed the temperatures to always be natively fahrenheit (API appears to always use this system) (@vignatyuk)
|
||||
{% endif %}
|
||||
|
||||
{% if version_installed.split('.') | map('int') < '0.4.0'.split('.') | map('int') %}
|
||||
- Laundry support changes will cause entity names to be different, you will need to fix in HA (uninstall, reboot, delete leftover entitites, install, reboot)
|
||||
{% endif %}
|
||||
|
@ -46,6 +63,13 @@ A/C Controls:
|
|||
|
||||
#### Features
|
||||
|
||||
{% if version_installed.split('.') | map('int') < '0.6.0'.split('.') | map('int') %}
|
||||
- Initial support for Water Softeners (@npentell, @drjeff)
|
||||
- Initial support for Opal Ice Makers (@mbcomer, @knobunc)
|
||||
- Initial support for Microwaves (@mbcomer, @mnestor)
|
||||
- Initial support for Coffee Makers (@alexanv1)
|
||||
{% endif %}
|
||||
|
||||
{% if version_installed.split('.') | map('int') < '0.5.0'.split('.') | map('int') %}
|
||||
- Support for Oven Hood units (@digitalbites)
|
||||
- Added extended mode support for ovens
|
||||
|
@ -67,12 +91,16 @@ A/C Controls:
|
|||
|
||||
#### Bugfixes
|
||||
|
||||
{% if version_installed.split('.') | map('int') < '0.6.0'.split('.') | map('int') %}
|
||||
- Updated deprecated icons (@mjmeli, @schmittx)
|
||||
{% endif %}
|
||||
|
||||
{% if version_installed.split('.') | map('int') < '0.5.0'.split('.') | map('int') %}
|
||||
- Advantium fixes (@willhayslett)
|
||||
- Fixed device info when serial not present (@Xe138)
|
||||
- Fixed issue with ovens when raw temperature not available (@chadohalloran)
|
||||
- Fixed issue where Split A/C temperature sensors report UOM incorrectly (@RobertusIT)
|
||||
- Added convertable drawer mode, proximity light, and interior lights to fridge (@grotto27, @elwing00)
|
||||
- Added convertable drawer mode, proximity light, and interior lights to fridge (@groto27, @elwing00)
|
||||
{% endif %}
|
||||
|
||||
{% if version_installed.split('.') | map('int') < '0.4.3'.split('.') | map('int') %}
|
||||
|
|
Loading…
Reference in New Issue