Dev -> Main v0.6.9 (#226)

* - updated water heater naming

* - initial support for built-in AC units

* Add support for Built-In AC Unit

Built-In AC unit operation and function is similar to a WAC.
`gehomesdk` version bumped from 0.4.25 to 0.4.27 to include latest
ErdApplianceType enum.

* Update README.md

Update README.md to include Built-In AC as supported device

* - updated zero serial number detection (resolves #89)

* - updated version
- updated changelog

* - hopefully fixed recursion bug with numbers

* - added cooktop support

* - fixed circular reference

* Add support for fridges with reduced support for ERD codes (no turbo mode, no current temperature reporting, no temperature setpoint limit reporting, no door status reporting). This change has been tested on a Fisher & Paykel RF610AA.

* - added dual dishwasher support
- updated documentation
- version bumps

* - added water heater support

* - added basic espresso maker device

* - bugfixes

* - rewrote initialization (resolves #99)

* - added logic to prevent double registration of entities

* - added correct min/max temps for water heaters

* Fix CoffeeMaker after the NumberEntity refactoring

* - added fix for CGY366P2TS1 (#116) to try to get the cooktop status, but fail more gracefully if it isn't supported

* - fixed region setting in update coordinator

* - version bump
- doc update
- string fixes

* - updated the temperature conversion to use non-deprecated HASS methods

* - updated documentation (@gleepwurp)

* - more documentation updates

* - updated dishwasher for new functionality
- updated documentation

* updated uom for liquid volume per HA specifications

* - fixed typo in oven (#149)

* - updated change log
- fixed oven light control (#144)

* - fixed issues with dishwasher (#155)
- added oim descaling sensor (#154)
- version bump

* - updated change log

* updated dual dishwasher for changes to gehomesdk (#161)

Co-authored-by: na4ma4 <na4ma4@users.noreply.github.com>

* await disconnect when unloading (#169)

Fixes simbaja#164.

* Check for upper oven light when there is a lower oven (#174)

Resolves issue #121

* - added oven warming drawers
- simplified oven entity logic

* - fixed issues with the new oven initialization logic

* - fixed bad type import for warming drawer

* -added iot class (#181)

* - updated the gehomesdk version requirement

* - gehomesdk version bump

* - added dehumidifier (#114)

* - dehumidifier appliance type fix

* - added oven state sensors (#175)

* - updated change logs
- updated sdk version requirement

* - removed target select
- added dehumidifier entity
- sdk version bump

* - updated dehumidifier icon

* - added humidifier platform

* - fixed typos in humidifier class

* - fixed copy/paste error

* - sdk version requirement bump

* - sdk version bump

* - updated dehumidifier to handle target precision
- updated dehumidifier sensor value conversion

* - missed a commit

* - SDK version bump

* Set device class on day flow for water softeners (#207)

This should allow sensor to be added to the energy dashboard.

* - removed references to _hass in update coordinator
- removed hass attribute in ge_entity
- version bump

* bumped gehomesdk version requirement

* - added fridge/freezer controls

* - documentation updates

* - fixed error when reloading integration

* - added additional update error handling

* - fixed coordinator bug

* - added additional logic to handle non-standard ready conditions

* Set device class on day flow for water filters (#209)

* - bumped sdk version requirement

* added new style cooktop status support (#159)

* Update deprecated constants or remove unused ones (#219)

* - updated documentation

---------

Co-authored-by: Rob Schmidt <rwschmidt26@gmail.com>
Co-authored-by: Federico Sevilla <federico@sevilla.id.au>
Co-authored-by: alexanv1 <44785744+alexanv1@users.noreply.github.com>
Co-authored-by: na4ma4 <25967676+na4ma4@users.noreply.github.com>
Co-authored-by: na4ma4 <na4ma4@users.noreply.github.com>
Co-authored-by: Alex Peters <alex@peters.net>
Co-authored-by: Chris Petersen <154074+ex-nerd@users.noreply.github.com>
Co-authored-by: Nathan Fiscus <nathanfiscus@users.noreply.github.com>
Co-authored-by: Jason Foley <JTF195@hotmail.com>
Co-authored-by: myztillx <33730898+myztillx@users.noreply.github.com>
This commit is contained in:
simbaja 2024-01-28 10:07:52 -05:00 committed by GitHub
parent 3b6e657272
commit efe500fe9a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
42 changed files with 355 additions and 216 deletions

View File

@ -1,6 +1,12 @@
# GE Home Appliances (SmartHQ) Changelog
## 0.6.9
- Added additional fridge controls [#200]
- Bugfix: Additional auth stability improvements [#215, #211]
- Bugfix: Removed deprecated constants [#218]
## 0.6.8
- Added Dehumidifier [#114]

View File

@ -35,5 +35,13 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn
]
_LOGGER.debug(f'Found {len(entities):d} unregistered binary sensors')
async_add_entities(entities)
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered)
#if we're already initialized at this point, call device
#discovery directly, otherwise add a callback based on the
#ready signal
if coordinator.initialized:
async_devices_discovered(coordinator.appliance_apis.values())
else:
# add the ready signal and register the remove callback
coordinator.add_signal_remove_callback(
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered))

View File

@ -34,4 +34,12 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn
_LOGGER.debug(f'Found {len(entities):d} unregistered buttons ')
async_add_entities(entities)
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered)
#if we're already initialized at this point, call device
#discovery directly, otherwise add a callback based on the
#ready signal
if coordinator.initialized:
async_devices_discovered(coordinator.appliance_apis.values())
else:
# add the ready signal and register the remove callback
coordinator.add_signal_remove_callback(
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered))

View File

@ -36,4 +36,12 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn
_LOGGER.debug(f'Found {len(entities):d} unregistered climate entities')
async_add_entities(entities)
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered)
#if we're already initialized at this point, call device
#discovery directly, otherwise add a callback based on the
#ready signal
if coordinator.initialized:
async_devices_discovered(coordinator.appliance_apis.values())
else:
# add the ready signal and register the remove callback
coordinator.add_signal_remove_callback(
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered))

View File

@ -2,7 +2,7 @@ import logging
from typing import List
from gehomesdk.erd.erd_data_type import ErdDataType
from homeassistant.const import DEVICE_CLASS_POWER_FACTOR
from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.helpers.entity import Entity
from gehomesdk import (
ErdCode,
@ -44,7 +44,7 @@ class CooktopApi(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, data_type_override=ErdDataType.INT))
cooktop_entities.append(GeErdPropertySensor(self, ErdCode.COOKTOP_STATUS, prop+".power_pct", icon_override="mdi:fire", device_class_override=SensorDeviceClass.POWER_FACTOR, data_type_override=ErdDataType.INT))
return base_entities + cooktop_entities

View File

@ -1,5 +1,5 @@
from homeassistant.components.binary_sensor import DEVICE_CLASS_PROBLEM
from homeassistant.const import DEVICE_CLASS_TEMPERATURE
from homeassistant.components.sensor import SensorDeviceClass
import logging
from typing import List
@ -31,7 +31,8 @@ from ..entities import (
GeDispenser,
GeErdPropertySensor,
GeErdPropertyBinarySensor,
ConvertableDrawerModeOptionsConverter
ConvertableDrawerModeOptionsConverter,
GeFridgeIceControlSwitch
)
_LOGGER = logging.getLogger(__name__)
@ -61,7 +62,10 @@ class FridgeApi(ApplianceApi):
proximity_light: ErdOnOff = self.try_get_erd_value(ErdCode.PROXIMITY_LIGHT)
display_mode: ErdOnOff = self.try_get_erd_value(ErdCode.DISPLAY_MODE)
lockout_mode: ErdOnOff = self.try_get_erd_value(ErdCode.LOCKOUT_MODE)
turbo_cool: ErdOnOff = self.try_get_erd_value(ErdCode.TURBO_COOL_STATUS)
turbo_freeze: ErdOnOff = self.try_get_erd_value(ErdCode.TURBO_FREEZE_STATUS)
ice_boost: ErdOnOff = self.try_get_erd_value(ErdCode.FRIDGE_ICE_BOOST)
units = self.hass.config.units
# Common entities
@ -80,8 +84,11 @@ class FridgeApi(ApplianceApi):
GeErdPropertySensor(self, ErdCode.CURRENT_TEMPERATURE, "fridge"),
GeFridge(self),
])
if turbo_cool is not None:
fridge_entities.append(GeErdSwitch(self, ErdCode.FRIDGE_ICE_BOOST))
if(ice_maker_control and ice_maker_control.status_fridge != ErdOnOff.NA):
fridge_entities.append(GeErdPropertyBinarySensor(self, ErdCode.ICE_MAKER_CONTROL, "status_fridge"))
fridge_entities.append(GeFridgeIceControlSwitch(self, "fridge"))
if(water_filter and water_filter != ErdFilterStatus.NA):
fridge_entities.append(GeErdSensor(self, ErdCode.WATER_FILTER_STATUS))
if(air_filter and air_filter != ErdFilterStatus.NA):
@ -105,8 +112,13 @@ class FridgeApi(ApplianceApi):
GeErdPropertySensor(self, ErdCode.CURRENT_TEMPERATURE, "freezer"),
GeFreezer(self),
])
if turbo_freeze is not None:
freezer_entities.append(GeErdSwitch(self, ErdCode.TURBO_FREEZE_STATUS))
if ice_boost is not None:
freezer_entities.append(GeErdSwitch(self, ErdCode.FRIDGE_ICE_BOOST))
if(ice_maker_control and ice_maker_control.status_freezer != ErdOnOff.NA):
freezer_entities.append(GeErdPropertyBinarySensor(self, ErdCode.ICE_MAKER_CONTROL, "status_freezer"))
freezer_entities.append(GeFridgeIceControlSwitch(self, "freezer"))
if(ice_bucket_status and ice_bucket_status.is_present_freezer):
freezer_entities.append(GeErdPropertySensor(self, ErdCode.ICE_MAKER_BUCKET_STATUS, "state_full_freezer"))
@ -117,7 +129,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, data_type_override=ErdDataType.INT),
GeErdPropertySensor(self, ErdCode.HOT_WATER_STATUS, "current_temp", device_class_override=SensorDeviceClass.TEMPERATURE, data_type_override=ErdDataType.INT),
GeErdPropertyBinarySensor(self, ErdCode.HOT_WATER_STATUS, "faulted", device_class_override=DEVICE_CLASS_PROBLEM),
GeDispenser(self)
])

View File

@ -2,7 +2,7 @@ import logging
from typing import List
from gehomesdk.erd.erd_data_type import ErdDataType
from homeassistant.const import DEVICE_CLASS_POWER_FACTOR
from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.helpers.entity import Entity
from gehomesdk import (
ErdCode,
@ -100,18 +100,27 @@ class OvenApi(ApplianceApi):
if oven_config.has_warming_drawer and warm_drawer is not None:
oven_entities.append(GeErdSensor(self, ErdCode.WARMING_DRAWER_STATE))
if cooktop_config == ErdCooktopConfig.PRESENT:
if cooktop_config == ErdCooktopConfig.PRESENT:
# attempt to get the cooktop status using legacy status
cooktop_status_erd = ErdCode.COOKTOP_STATUS
cooktop_status: CooktopStatus = self.try_get_erd_value(ErdCode.COOKTOP_STATUS)
# if we didn't get it, try using the new version
if cooktop_status is None:
cooktop_status_erd = ErdCode.COOKTOP_STATUS_EXT
cooktop_status: CooktopStatus = self.try_get_erd_value(ErdCode.COOKTOP_STATUS_EXT)
# if we got a status through either mechanism, we can add the entities
if cooktop_status is not None:
cooktop_entities.append(GeErdBinarySensor(self, ErdCode.COOKTOP_STATUS))
cooktop_entities.append(GeErdBinarySensor(self, cooktop_status_erd))
for (k, v) in cooktop_status.burners.items():
if v.exists:
prop = self._camel_to_snake(k)
cooktop_entities.append(GeErdPropertyBinarySensor(self, ErdCode.COOKTOP_STATUS, prop+".on"))
cooktop_entities.append(GeErdPropertyBinarySensor(self, ErdCode.COOKTOP_STATUS, prop+".synchronized"))
cooktop_entities.append(GeErdPropertyBinarySensor(self, cooktop_status_erd, prop+".on"))
cooktop_entities.append(GeErdPropertyBinarySensor(self, cooktop_status_erd, 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, data_type_override=ErdDataType.INT))
cooktop_entities.append(GeErdPropertySensor(self, cooktop_status_erd, prop+".power_pct", icon_override="mdi:fire", device_class_override=SensorDeviceClass.POWER_FACTOR, data_type_override=ErdDataType.INT))
return base_entities + oven_entities + cooktop_entities

View File

@ -30,7 +30,7 @@ class WaterFilterApi(ApplianceApi):
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"),
GeErdPropertySensor(self, ErdCode.WH_FILTER_FLOW_RATE, "flow_rate"),
GeErdSensor(self, ErdCode.WH_FILTER_DAY_USAGE),
GeErdSensor(self, ErdCode.WH_FILTER_DAY_USAGE, device_class_override="water"),
GeErdPropertySensor(self, ErdCode.WH_FILTER_LIFE_REMAINING, "life_remaining"),
GeErdBinarySensor(self, ErdCode.WH_FILTER_FLOW_ALERT, device_class_override="moisture"),
]

View File

@ -27,7 +27,7 @@ class WaterSoftenerApi(ApplianceApi):
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_FILTER_DAY_USAGE, device_class_override="water"),
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"),

View File

@ -1,11 +1,6 @@
import logging
from typing import Any, List, Optional
from homeassistant.components.climate.const import (
HVAC_MODE_AUTO,
HVAC_MODE_COOL,
HVAC_MODE_FAN_ONLY,
)
from gehomesdk import ErdAcFanSetting
from ..common import OptionsConverter

View File

@ -1,11 +1,7 @@
import logging
from typing import Any, List, Optional
from homeassistant.components.climate.const import (
HVAC_MODE_AUTO,
HVAC_MODE_COOL,
HVAC_MODE_FAN_ONLY,
)
from homeassistant.components.climate import HVACMode
from gehomesdk import ErdAcOperationMode
from ...devices import ApplianceApi
from ..common import GeClimate, OptionsConverter
@ -16,13 +12,13 @@ _LOGGER = logging.getLogger(__name__)
class BiacHvacModeOptionsConverter(OptionsConverter):
@property
def options(self) -> List[str]:
return [HVAC_MODE_AUTO, HVAC_MODE_COOL, HVAC_MODE_FAN_ONLY]
return [HVACMode.AUTO, HVACMode.COOL, HVACMode.FAN_ONLY]
def from_option_string(self, value: str) -> Any:
try:
return {
HVAC_MODE_AUTO: ErdAcOperationMode.ENERGY_SAVER,
HVAC_MODE_COOL: ErdAcOperationMode.COOL,
HVAC_MODE_FAN_ONLY: ErdAcOperationMode.FAN_ONLY
HVACMode.AUTO: ErdAcOperationMode.ENERGY_SAVER,
HVACMode.COOL: ErdAcOperationMode.COOL,
HVACMode.FAN_ONLY: ErdAcOperationMode.FAN_ONLY
}.get(value)
except:
_LOGGER.warn(f"Could not set HVAC mode to {value.upper()}")
@ -30,14 +26,14 @@ class BiacHvacModeOptionsConverter(OptionsConverter):
def to_option_string(self, value: Any) -> Optional[str]:
try:
return {
ErdAcOperationMode.ENERGY_SAVER: HVAC_MODE_AUTO,
ErdAcOperationMode.AUTO: HVAC_MODE_AUTO,
ErdAcOperationMode.COOL: HVAC_MODE_COOL,
ErdAcOperationMode.FAN_ONLY: HVAC_MODE_FAN_ONLY
ErdAcOperationMode.ENERGY_SAVER: HVACMode.AUTO,
ErdAcOperationMode.AUTO: HVACMode.AUTO,
ErdAcOperationMode.COOL: HVACMode.COOL,
ErdAcOperationMode.FAN_ONLY: HVACMode.FAN_ONLY
}.get(value)
except:
_LOGGER.warn(f"Could not determine operation mode mapping for {value}")
return HVAC_MODE_COOL
return HVACMode.COOL
class GeBiacClimate(GeClimate):
"""Class for Built-In AC units"""

View File

@ -1,17 +1,7 @@
import logging
from typing import Any, List, Optional
from homeassistant.const import (
TEMP_FAHRENHEIT
)
from homeassistant.components.climate.const import (
HVAC_MODE_AUTO,
HVAC_MODE_COOL,
HVAC_MODE_DRY,
HVAC_MODE_FAN_ONLY,
HVAC_MODE_HEAT,
)
from homeassistant.components.climate import HVACMode
from gehomesdk import ErdCode, ErdAcOperationMode, ErdSacAvailableModes, ErdSacTargetTemperatureRange
from ...devices import ApplianceApi
from ..common import GeClimate, OptionsConverter
@ -25,19 +15,19 @@ class PacHvacModeOptionsConverter(OptionsConverter):
@property
def options(self) -> List[str]:
modes = [HVAC_MODE_COOL, HVAC_MODE_FAN_ONLY]
modes = [HVACMode.COOL, HVACMode.FAN_ONLY]
if self._available_modes and self._available_modes.has_heat:
modes.append(HVAC_MODE_HEAT)
modes.append(HVACMode.HEAT)
if self._available_modes and self._available_modes.has_dry:
modes.append(HVAC_MODE_DRY)
modes.append(HVACMode.DRY)
return modes
def from_option_string(self, value: str) -> Any:
try:
return {
HVAC_MODE_COOL: ErdAcOperationMode.COOL,
HVAC_MODE_HEAT: ErdAcOperationMode.HEAT,
HVAC_MODE_FAN_ONLY: ErdAcOperationMode.FAN_ONLY,
HVAC_MODE_DRY: ErdAcOperationMode.DRY
HVACMode.COOL: ErdAcOperationMode.COOL,
HVACMode.HEAT: ErdAcOperationMode.HEAT,
HVACMode.FAN_ONLY: ErdAcOperationMode.FAN_ONLY,
HVACMode.DRY: ErdAcOperationMode.DRY
}.get(value)
except:
_LOGGER.warn(f"Could not set HVAC mode to {value.upper()}")
@ -45,14 +35,14 @@ class PacHvacModeOptionsConverter(OptionsConverter):
def to_option_string(self, value: Any) -> Optional[str]:
try:
return {
ErdAcOperationMode.COOL: HVAC_MODE_COOL,
ErdAcOperationMode.HEAT: HVAC_MODE_HEAT,
ErdAcOperationMode.DRY: HVAC_MODE_DRY,
ErdAcOperationMode.FAN_ONLY: HVAC_MODE_FAN_ONLY
ErdAcOperationMode.COOL: HVACMode.COOL,
ErdAcOperationMode.HEAT: HVACMode.HEAT,
ErdAcOperationMode.DRY: HVACMode.DRY,
ErdAcOperationMode.FAN_ONLY: HVACMode.FAN_ONLY
}.get(value)
except:
_LOGGER.warn(f"Could not determine operation mode mapping for {value}")
return HVAC_MODE_COOL
return HVACMode.COOL
class GePacClimate(GeClimate):
"""Class for Portable AC units"""

View File

@ -1,16 +1,7 @@
import logging
from typing import Any, List, Optional
from homeassistant.const import (
TEMP_FAHRENHEIT
)
from homeassistant.components.climate.const import (
HVAC_MODE_AUTO,
HVAC_MODE_COOL,
HVAC_MODE_DRY,
HVAC_MODE_FAN_ONLY,
HVAC_MODE_HEAT,
)
from homeassistant.components.climate import HVACMode
from gehomesdk import ErdCode, ErdAcOperationMode, ErdSacAvailableModes, ErdSacTargetTemperatureRange
from ...devices import ApplianceApi
from ..common import GeClimate, OptionsConverter
@ -24,21 +15,21 @@ class SacHvacModeOptionsConverter(OptionsConverter):
@property
def options(self) -> List[str]:
modes = [HVAC_MODE_COOL, HVAC_MODE_FAN_ONLY]
modes = [HVACMode.COOL, HVACMode.FAN_ONLY]
if self._available_modes and self._available_modes.has_heat:
modes.append(HVAC_MODE_HEAT)
modes.append(HVAC_MODE_AUTO)
modes.append(HVACMode.HEAT)
modes.append(HVACMode.AUTO)
if self._available_modes and self._available_modes.has_dry:
modes.append(HVAC_MODE_DRY)
modes.append(HVACMode.DRY)
return modes
def from_option_string(self, value: str) -> Any:
try:
return {
HVAC_MODE_AUTO: ErdAcOperationMode.AUTO,
HVAC_MODE_COOL: ErdAcOperationMode.COOL,
HVAC_MODE_HEAT: ErdAcOperationMode.HEAT,
HVAC_MODE_FAN_ONLY: ErdAcOperationMode.FAN_ONLY,
HVAC_MODE_DRY: ErdAcOperationMode.DRY
HVACMode.AUTO: ErdAcOperationMode.AUTO,
HVACMode.COOL: ErdAcOperationMode.COOL,
HVACMode.HEAT: ErdAcOperationMode.HEAT,
HVACMode.FAN_ONLY: ErdAcOperationMode.FAN_ONLY,
HVACMode.DRY: ErdAcOperationMode.DRY
}.get(value)
except:
_LOGGER.warn(f"Could not set HVAC mode to {value.upper()}")
@ -46,16 +37,16 @@ class SacHvacModeOptionsConverter(OptionsConverter):
def to_option_string(self, value: Any) -> Optional[str]:
try:
return {
ErdAcOperationMode.ENERGY_SAVER: HVAC_MODE_AUTO,
ErdAcOperationMode.AUTO: HVAC_MODE_AUTO,
ErdAcOperationMode.COOL: HVAC_MODE_COOL,
ErdAcOperationMode.HEAT: HVAC_MODE_HEAT,
ErdAcOperationMode.DRY: HVAC_MODE_DRY,
ErdAcOperationMode.FAN_ONLY: HVAC_MODE_FAN_ONLY
ErdAcOperationMode.ENERGY_SAVER: HVACMode.AUTO,
ErdAcOperationMode.AUTO: HVACMode.AUTO,
ErdAcOperationMode.COOL: HVACMode.COOL,
ErdAcOperationMode.HEAT: HVACMode.HEAT,
ErdAcOperationMode.DRY: HVACMode.DRY,
ErdAcOperationMode.FAN_ONLY: HVACMode.FAN_ONLY
}.get(value)
except:
_LOGGER.warn(f"Could not determine operation mode mapping for {value}")
return HVAC_MODE_COOL
return HVACMode.COOL
class GeSacClimate(GeClimate):
"""Class for Split AC units"""

View File

@ -1,11 +1,7 @@
import logging
from typing import Any, List, Optional
from homeassistant.components.climate.const import (
HVAC_MODE_AUTO,
HVAC_MODE_COOL,
HVAC_MODE_FAN_ONLY,
)
from homeassistant.components.climate import HVACMode
from gehomesdk import ErdAcOperationMode
from ...devices import ApplianceApi
from ..common import GeClimate, OptionsConverter
@ -16,13 +12,13 @@ _LOGGER = logging.getLogger(__name__)
class WacHvacModeOptionsConverter(OptionsConverter):
@property
def options(self) -> List[str]:
return [HVAC_MODE_AUTO, HVAC_MODE_COOL, HVAC_MODE_FAN_ONLY]
return [HVACMode.AUTO, HVACMode.COOL, HVACMode.FAN_ONLY]
def from_option_string(self, value: str) -> Any:
try:
return {
HVAC_MODE_AUTO: ErdAcOperationMode.ENERGY_SAVER,
HVAC_MODE_COOL: ErdAcOperationMode.COOL,
HVAC_MODE_FAN_ONLY: ErdAcOperationMode.FAN_ONLY
HVACMode.AUTO: ErdAcOperationMode.ENERGY_SAVER,
HVACMode.COOL: ErdAcOperationMode.COOL,
HVACMode.FAN_ONLY: ErdAcOperationMode.FAN_ONLY
}.get(value)
except:
_LOGGER.warn(f"Could not set HVAC mode to {value.upper()}")
@ -30,14 +26,14 @@ class WacHvacModeOptionsConverter(OptionsConverter):
def to_option_string(self, value: Any) -> Optional[str]:
try:
return {
ErdAcOperationMode.ENERGY_SAVER: HVAC_MODE_AUTO,
ErdAcOperationMode.AUTO: HVAC_MODE_AUTO,
ErdAcOperationMode.COOL: HVAC_MODE_COOL,
ErdAcOperationMode.FAN_ONLY: HVAC_MODE_FAN_ONLY
ErdAcOperationMode.ENERGY_SAVER: HVACMode.AUTO,
ErdAcOperationMode.AUTO: HVACMode.AUTO,
ErdAcOperationMode.COOL: HVACMode.COOL,
ErdAcOperationMode.FAN_ONLY: HVACMode.FAN_ONLY
}.get(value)
except:
_LOGGER.warn(f"Could not determine operation mode mapping for {value}")
return HVAC_MODE_COOL
return HVACMode.COOL
class GeWacClimate(GeClimate):
"""Class for Window AC units"""

View File

@ -1,8 +1,5 @@
from homeassistant.components.water_heater import (
SUPPORT_OPERATION_MODE,
SUPPORT_TARGET_TEMPERATURE
)
from homeassistant.components.water_heater import WaterHeaterEntityFeature
SUPPORT_NONE = 0
GE_ADVANTIUM_WITH_TEMPERATURE = (SUPPORT_OPERATION_MODE | SUPPORT_TARGET_TEMPERATURE)
GE_ADVANTIUM = SUPPORT_OPERATION_MODE
GE_ADVANTIUM_WITH_TEMPERATURE = (WaterHeaterEntityFeature.OPERATION_MODE | WaterHeaterEntityFeature.TARGET_TEMPERATURE)
GE_ADVANTIUM = WaterHeaterEntityFeature.OPERATION_MODE

View File

@ -15,7 +15,8 @@ from gehomesdk import (
)
from gehomesdk.erd.values.advantium.advantium_enums import CookAction, CookMode
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.const import ATTR_TEMPERATURE
from ...const import DOMAIN
from ...devices import ApplianceApi
from ..common import GeAbstractWaterHeater
@ -272,7 +273,7 @@ class GeAdvantium(GeAbstractWaterHeater):
async def _convert_target_temperature(self, temp_120v: int, temp_240v: int):
unit_type = self.unit_type
target_temp_f = temp_240v if unit_type in [ErdUnitType.TYPE_240V_MONOGRAM, ErdUnitType.TYPE_240V_CAFE] else temp_120v
if self.temperature_unit == TEMP_FAHRENHEIT:
if self.temperature_unit == SensorDeviceClass.FAHRENHEIT:
return float(target_temp_f)
else:
return (target_temp_f - 32.0) * (5/9)

View File

@ -2,7 +2,6 @@ from gehomesdk import ErdCode
from ...devices import ApplianceApi
from ..common import GeErdNumber
from .ge_ccm_cached_value import GeCcmCachedValue
from homeassistant.const import TEMP_FAHRENHEIT
class GeCcmBrewTemperatureNumber(GeErdNumber, GeCcmCachedValue):
def __init__(self, api: ApplianceApi):

View File

@ -4,15 +4,10 @@ from typing import List, Optional
from homeassistant.components.climate import ClimateEntity
from homeassistant.const import (
ATTR_TEMPERATURE,
TEMP_FAHRENHEIT,
TEMP_CELSIUS,
)
from homeassistant.components.climate.const import (
HVAC_MODE_FAN_ONLY,
SUPPORT_TARGET_TEMPERATURE,
SUPPORT_FAN_MODE,
HVAC_MODE_OFF
UnitOfTemperature,
)
from homeassistant.components.climate import ClimateEntityFeature, HVACMode
from homeassistant.components.water_heater import WaterHeaterEntityFeature
from gehomesdk import ErdCode, ErdCodeType, ErdMeasurementUnits, ErdOnOff
from ...const import DOMAIN
from ...devices import ApplianceApi
@ -22,7 +17,7 @@ from .options_converter import OptionsConverter
_LOGGER = logging.getLogger(__name__)
#by default, we'll support target temp and fan mode (derived classes can override)
GE_CLIMATE_SUPPORT = SUPPORT_TARGET_TEMPERATURE | SUPPORT_FAN_MODE
GE_CLIMATE_SUPPORT = WaterHeaterEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE
class GeClimate(GeEntity, ClimateEntity):
"""GE Climate Base Entity (Window AC, Portable AC, etc)"""
@ -83,11 +78,11 @@ class GeClimate(GeEntity, ClimateEntity):
@property
def temperature_unit(self):
#appears to always be Fahrenheit internally, hardcode this
return TEMP_FAHRENHEIT
return UnitOfTemperature.FAHRENHEIT
#measurement_system = self.appliance.get_erd_value(ErdCode.TEMPERATURE_UNIT)
#if measurement_system == ErdMeasurementUnits.METRIC:
# return TEMP_CELSIUS
#return TEMP_FAHRENHEIT
# return UnitOfTemperature.CELSIUS
#return UnitOfTempterature.FAHRENHEIT
@property
def supported_features(self):
@ -116,30 +111,30 @@ class GeClimate(GeEntity, ClimateEntity):
@property
def hvac_mode(self):
if not self.is_on:
return HVAC_MODE_OFF
return HVACMode.OFF
return self._hvac_mode_converter.to_option_string(self.appliance.get_erd_value(self.hvac_mode_erd_code))
@property
def hvac_modes(self) -> List[str]:
return [HVAC_MODE_OFF] + self._hvac_mode_converter.options
return [HVACMode.OFF] + self._hvac_mode_converter.options
@property
def fan_mode(self):
if self.hvac_mode == HVAC_MODE_FAN_ONLY:
if self.hvac_mode == HVACMode.FAN_ONLY:
return self._fan_only_fan_mode_converter.to_option_string(self.appliance.get_erd_value(self.fan_mode_erd_code))
return self._fan_mode_converter.to_option_string(self.appliance.get_erd_value(self.fan_mode_erd_code))
@property
def fan_modes(self) -> List[str]:
if self.hvac_mode == HVAC_MODE_FAN_ONLY:
if self.hvac_mode == HVACMode.FAN_ONLY:
return self._fan_only_fan_mode_converter.options
return self._fan_mode_converter.options
async def async_set_hvac_mode(self, hvac_mode: str) -> None:
_LOGGER.debug(f"Setting HVAC mode from {self.hvac_mode} to {hvac_mode}")
if hvac_mode != self.hvac_mode:
if hvac_mode == HVAC_MODE_OFF:
if hvac_mode == HVACMode.OFF:
await self.appliance.async_set_erd_value(self.power_status_erd_code, ErdOnOff.OFF)
else:
#if it's not on, turn it on
@ -156,7 +151,7 @@ class GeClimate(GeEntity, ClimateEntity):
_LOGGER.debug(f"Setting Fan mode from {self.fan_mode} to {fan_mode}")
if fan_mode != self.fan_mode:
converter = (self._fan_only_fan_mode_converter
if self.hvac_mode == HVAC_MODE_FAN_ONLY
if self.hvac_mode == HVACMode.FAN_ONLY
else self._fan_mode_converter
)
@ -185,7 +180,7 @@ class GeClimate(GeEntity, ClimateEntity):
await self.appliance.async_set_erd_value(self.power_status_erd_code, ErdOnOff.OFF)
def _convert_temp(self, temperature_f: int):
if self.temperature_unit == TEMP_FAHRENHEIT:
if self.temperature_unit == UnitOfTemperature.FAHRENHEIT:
return float(temperature_f)
else:
return (temperature_f - 32.0) * (5/9)

View File

@ -10,7 +10,7 @@ class GeEntity:
def __init__(self, api: ApplianceApi):
self._api = api
self.hass = None
self._added = False
@property
def unique_id(self) -> str:
@ -56,6 +56,18 @@ class GeEntity:
def device_class(self) -> Optional[str]:
return self._get_device_class()
@property
def added(self) -> bool:
return self._added
async def async_added_to_hass(self) -> None:
"""Run when entity about to be added to hass."""
self._added = True
async def async_will_remove_from_hass(self) -> None:
"""Run when entity will be removed from hass."""
self._added = False
def _stringify(self, value: any, **kwargs) -> Optional[str]:
if isinstance(value, timedelta):
return str(value)[:-3] if value else ""

View File

@ -5,7 +5,7 @@ from homeassistant.components.number import (
NumberEntity,
NumberDeviceClass,
)
from homeassistant.const import TEMP_FAHRENHEIT
from homeassistant.const import UnitOfTemperature
from gehomesdk import ErdCodeType, ErdCodeClass
from .ge_erd_entity import GeErdEntity
from ...devices import ApplianceApi
@ -91,7 +91,7 @@ class GeErdNumber(GeErdEntity, NumberEntity):
#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 UnitOfTemperature.FAHRENHEIT
return None

View File

@ -1,17 +1,9 @@
import logging
from typing import Optional
from gehomesdk.erd.erd_data_type import ErdDataType
from homeassistant.components.sensor import SensorEntity, SensorStateClass
from homeassistant.components.sensor import SensorDeviceClass, SensorEntity, SensorStateClass
from homeassistant.const import (
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_POWER,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_POWER_FACTOR,
DEVICE_CLASS_HUMIDITY,
TEMP_FAHRENHEIT,
)
from homeassistant.const import UnitOfTemperature
from gehomesdk import ErdCodeType, ErdCodeClass
from .ge_erd_entity import GeErdEntity
from ...devices import ApplianceApi
@ -76,8 +68,8 @@ class GeErdSensor(GeErdEntity, SensorEntity):
return self.api.hass.config.units.temperature_unit
#if self._measurement_system == ErdMeasurementUnits.METRIC:
# return TEMP_CELSIUS
#return TEMP_FAHRENHEIT
# return UnitOfTemperature.CELSIUS
#return UnitOfTemperature.FAHRENHEIT
def _convert_numeric_value_from_device(self, value):
"""Convert to expected data type"""
@ -97,20 +89,20 @@ class GeErdSensor(GeErdEntity, SensorEntity):
if (
self.erd_code_class
in [ErdCodeClass.RAW_TEMPERATURE, ErdCodeClass.NON_ZERO_TEMPERATURE]
or self.device_class == DEVICE_CLASS_TEMPERATURE
or self.device_class == SensorDeviceClass.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 UnitOfTemperature.FAHRENHEIT
if (
self.erd_code_class == ErdCodeClass.BATTERY
or self.device_class == DEVICE_CLASS_BATTERY
or self.device_class == SensorDeviceClass.BATTERY
):
return "%"
if self.erd_code_class == ErdCodeClass.PERCENTAGE:
return "%"
if self.device_class == DEVICE_CLASS_POWER_FACTOR:
if self.device_class == SensorDeviceClass.POWER_FACTOR:
return "%"
if self.erd_code_class == ErdCodeClass.HUMIDITY:
return "%"
@ -131,15 +123,15 @@ class GeErdSensor(GeErdEntity, SensorEntity):
ErdCodeClass.RAW_TEMPERATURE,
ErdCodeClass.NON_ZERO_TEMPERATURE,
]:
return DEVICE_CLASS_TEMPERATURE
return SensorDeviceClass.TEMPERATURE
if self.erd_code_class == ErdCodeClass.BATTERY:
return DEVICE_CLASS_BATTERY
return SensorDeviceClass.BATTERY
if self.erd_code_class == ErdCodeClass.POWER:
return DEVICE_CLASS_POWER
return SensorDeviceClass.POWER
if self.erd_code_class == ErdCodeClass.ENERGY:
return DEVICE_CLASS_ENERGY
return SensorDeviceClass.ENERGY
if self.erd_code_class == ErdCodeClass.HUMIDITY:
return DEVICE_CLASS_HUMIDITY
return SensorDeviceClass.HUMIDITY
return None
@ -147,7 +139,7 @@ class GeErdSensor(GeErdEntity, SensorEntity):
if self._state_class_override:
return self._state_class_override
if self.device_class in [DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_ENERGY]:
if self.device_class in [SensorDeviceClass.TEMPERATURE, SensorDeviceClass.ENERGY]:
return SensorStateClass.MEASUREMENT
if self.erd_code_class in [ErdCodeClass.FLOW_RATE, ErdCodeClass.PERCENTAGE, ErdCodeClass.HUMIDITY]:
return SensorStateClass.MEASUREMENT

View File

@ -29,5 +29,5 @@ class GeErdSwitch(GeErdBinarySensor, SwitchEntity):
async def async_turn_off(self, **kwargs):
"""Turn the switch off."""
_LOGGER.debug(f"Turning on {self.unique_id}")
_LOGGER.debug(f"Turning off {self.unique_id}")
await self.appliance.async_set_erd_value(self.erd_code, self._converter.false_value())

View File

@ -3,10 +3,7 @@ import logging
from typing import Any, Dict, List, Optional
from homeassistant.components.water_heater import WaterHeaterEntity
from homeassistant.const import (
TEMP_FAHRENHEIT,
TEMP_CELSIUS
)
from homeassistant.const import UnitOfTemperature
from gehomesdk import ErdCode, ErdMeasurementUnits
from ...const import DOMAIN
from .ge_erd_entity import GeEntity
@ -37,8 +34,8 @@ class GeAbstractWaterHeater(GeEntity, WaterHeaterEntity, metaclass=abc.ABCMeta):
#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
# return UnitOfTemperature.CELSIUS
return UnitOfTemperature.FAHRENHEIT
@property
def supported_features(self):

View File

@ -1,4 +1,5 @@
from .ge_fridge import GeFridge
from .ge_freezer import GeFreezer
from .ge_dispenser import GeDispenser
from .convertable_drawer_mode_options import ConvertableDrawerModeOptionsConverter
from .convertable_drawer_mode_options import ConvertableDrawerModeOptionsConverter
from .ge_fridge_ice_control_switch import GeFridgeIceControlSwitch

View File

@ -1,10 +1,7 @@
from homeassistant.components.water_heater import (
SUPPORT_OPERATION_MODE,
SUPPORT_TARGET_TEMPERATURE
)
from homeassistant.components.water_heater import WaterHeaterEntityFeature
ATTR_DOOR_STATUS = "door_status"
GE_FRIDGE_SUPPORT = (SUPPORT_OPERATION_MODE | SUPPORT_TARGET_TEMPERATURE)
GE_FRIDGE_SUPPORT = (WaterHeaterEntityFeature.OPERATION_MODE | WaterHeaterEntityFeature.TARGET_TEMPERATURE)
HEATER_TYPE_FRIDGE = "fridge"
HEATER_TYPE_FREEZER = "freezer"

View File

@ -2,7 +2,7 @@ import logging
from typing import List, Any, Optional
from gehomesdk import ErdConvertableDrawerMode
from homeassistant.const import TEMP_FAHRENHEIT
from homeassistant.const import UnitOfTemperature
from homeassistant.util.unit_system import UnitSystem
from ..common import OptionsConverter
@ -43,7 +43,7 @@ class ConvertableDrawerModeOptionsConverter(OptionsConverter):
t = _TEMP_MAP.get(value, None)
if t and self._units.is_metric:
t = self._units.temperature(float(t), TEMP_FAHRENHEIT)
t = self._units.temperature(float(t), UnitOfTemperature.FAHRENHEIT)
t = round(t,1)
if t:

View File

@ -6,7 +6,7 @@ import abc
import logging
from typing import Any, Dict, List, Optional
from homeassistant.const import ATTR_TEMPERATURE, TEMP_FAHRENHEIT
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
from homeassistant.util.unit_conversion import TemperatureConverter
from gehomesdk import (
ErdCode,
@ -117,7 +117,7 @@ class GeAbstractFridge(GeAbstractWaterHeater):
return getattr(self.setpoint_limits, f"{self.heater_type}_min")
except:
_LOGGER.debug("No temperature setpoint limits available. Using hardcoded limits.")
return TemperatureConverter.convert(self.temp_limits[f"{self.heater_type}_min"], TEMP_FAHRENHEIT, self.temperature_unit)
return TemperatureConverter.convert(self.temp_limits[f"{self.heater_type}_min"], UnitOfTemperature.FAHRENHEIT, self.temperature_unit)
@property
def max_temp(self):
@ -126,7 +126,7 @@ class GeAbstractFridge(GeAbstractWaterHeater):
return getattr(self.setpoint_limits, f"{self.heater_type}_max")
except:
_LOGGER.debug("No temperature setpoint limits available. Using hardcoded limits.")
return TemperatureConverter.convert(self.temp_limits[f"{self.heater_type}_max"], TEMP_FAHRENHEIT, self.temperature_unit)
return TemperatureConverter.convert(self.temp_limits[f"{self.heater_type}_max"], UnitOfTemperature.FAHRENHEIT, self.temperature_unit)
@property
def current_operation(self) -> str:

View File

@ -3,7 +3,7 @@
import logging
from typing import List, Optional, Dict, Any
from homeassistant.const import ATTR_TEMPERATURE, TEMP_FAHRENHEIT
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
from homeassistant.util.unit_conversion import TemperatureConverter
from gehomesdk import (
@ -102,12 +102,12 @@ class GeDispenser(GeAbstractWaterHeater):
@property
def min_temp(self):
"""Return the minimum temperature."""
return TemperatureConverter.convert(self._min_temp, TEMP_FAHRENHEIT, self.temperature_unit)
return TemperatureConverter.convert(self._min_temp, UnitOfTemperature.FAHRENHEIT, self.temperature_unit)
@property
def max_temp(self):
"""Return the maximum temperature."""
return TemperatureConverter.convert(self._max_temp, TEMP_FAHRENHEIT, self.temperature_unit)
return TemperatureConverter.convert(self._max_temp, UnitOfTemperature.FAHRENHEIT, self.temperature_unit)
@property
def extra_state_attributes(self) -> Dict[str, Any]:

View File

@ -0,0 +1,47 @@
import logging
from gehomesdk import ErdCode, IceMakerControlStatus, ErdOnOff
from ...devices import ApplianceApi
from ..common import GeErdSwitch, BoolConverter
_LOGGER = logging.getLogger(__name__)
class GeFridgeIceControlSwitch(GeErdSwitch):
def __init__(self, api: ApplianceApi, control_type: str):
super().__init__(api, ErdCode.ICE_MAKER_CONTROL, BoolConverter())
self._control_type = control_type
@property
def control_status(self) -> IceMakerControlStatus:
return self.appliance.get_erd_value(ErdCode.ICE_MAKER_CONTROL)
@property
def is_on(self) -> bool:
if self._control_type == "fridge":
return self.control_status.status_fridge == ErdOnOff.ON
else:
return self.control_status.status_freezer == ErdOnOff.ON
async def async_turn_on(self, **kwargs):
"""Turn the switch on."""
_LOGGER.debug(f"Turning on {self.unique_id}")
old_status = self.control_status
if self._control_type == "fridge":
new_status = IceMakerControlStatus(ErdOnOff.ON, old_status.status_freezer)
else:
new_status = IceMakerControlStatus(old_status.status_fridge, ErdOnOff.ON)
await self.appliance.async_set_erd_value(self.erd_code, new_status)
async def async_turn_off(self, **kwargs):
"""Turn the switch off."""
_LOGGER.debug(f"Turning off {self.unique_id}")
old_status = self.control_status
if self._control_type == "fridge":
new_status = IceMakerControlStatus(ErdOnOff.OFF, old_status.status_freezer)
else:
new_status = IceMakerControlStatus(old_status.status_fridge, ErdOnOff.OFF)
await self.appliance.async_set_erd_value(self.erd_code, new_status)

View File

@ -1,13 +1,10 @@
import bidict
from homeassistant.components.water_heater import (
SUPPORT_OPERATION_MODE,
SUPPORT_TARGET_TEMPERATURE
)
from homeassistant.components.water_heater import WaterHeaterEntityFeature
from gehomesdk import ErdOvenCookMode
SUPPORT_NONE = 0
GE_OVEN_SUPPORT = (SUPPORT_OPERATION_MODE | SUPPORT_TARGET_TEMPERATURE)
GE_OVEN_SUPPORT = (WaterHeaterEntityFeature.OPERATION_MODE | WaterHeaterEntityFeature.TARGET_TEMPERATURE)
OP_MODE_OFF = "Off"
OP_MODE_BAKE = "Bake"

View File

@ -10,7 +10,7 @@ from gehomesdk import (
OvenCookSetting
)
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
from ...const import DOMAIN
from ...devices import ApplianceApi
from ..common import GeAbstractWaterHeater
@ -56,8 +56,8 @@ class GeOven(GeAbstractWaterHeater):
def temperature_unit(self):
measurement_system = self.appliance.get_erd_value(ErdCode.TEMPERATURE_UNIT)
if measurement_system == ErdMeasurementUnits.METRIC:
return TEMP_CELSIUS
return TEMP_FAHRENHEIT
return UnitOfTemperature.CELSIUS
return UnitOfTemperature.FAHRENHEIT
@property
def oven_select(self) -> str:
@ -155,7 +155,7 @@ class GeOven(GeAbstractWaterHeater):
target_temp = 0
elif self.target_temperature:
target_temp = self.target_temperature
elif self.temperature_unit == TEMP_FAHRENHEIT:
elif self.temperature_unit == UnitOfTemperature.FAHRENHEIT:
target_temp = 350
else:
target_temp = 177

View File

@ -7,12 +7,9 @@ from gehomesdk import (
ErdWaterHeaterMode
)
from homeassistant.components.water_heater import (
SUPPORT_OPERATION_MODE,
SUPPORT_TARGET_TEMPERATURE
)
from homeassistant.components.water_heater import WaterHeaterEntityFeature
from homeassistant.const import ATTR_TEMPERATURE, TEMP_FAHRENHEIT
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
from ...devices import ApplianceApi
from ..common import GeAbstractWaterHeater
from .heater_modes import WhHeaterModeConverter
@ -34,11 +31,11 @@ class GeWaterHeater(GeAbstractWaterHeater):
@property
def supported_features(self):
return (SUPPORT_OPERATION_MODE | SUPPORT_TARGET_TEMPERATURE)
return (WaterHeaterEntityFeature.OPERATION_MODE | WaterHeaterEntityFeature.TARGET_TEMPERATURE)
@property
def temperature_unit(self):
return TEMP_FAHRENHEIT
return UnitOfTemperature.FAHRENHEIT
@property
def current_temperature(self) -> Optional[int]:

View File

@ -33,4 +33,12 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn
_LOGGER.debug(f'Found {len(entities):d} unregistered humidifiers')
async_add_entities(entities)
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered)
#if we're already initialized at this point, call device
#discovery directly, otherwise add a callback based on the
#ready signal
if coordinator.initialized:
async_devices_discovered(coordinator.appliance_apis.values())
else:
# add the ready signal and register the remove callback
coordinator.add_signal_remove_callback(
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered))

View File

@ -37,4 +37,12 @@ async def async_setup_entry(
_LOGGER.debug(f"Found {len(entities):d} unregistered lights")
async_add_entities(entities)
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered)
#if we're already initialized at this point, call device
#discovery directly, otherwise add a callback based on the
#ready signal
if coordinator.initialized:
async_devices_discovered(coordinator.appliance_apis.values())
else:
# add the ready signal and register the remove callback
coordinator.add_signal_remove_callback(
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered))

View File

@ -5,7 +5,7 @@
"integration_type": "hub",
"iot_class": "cloud_push",
"documentation": "https://github.com/simbaja/ha_gehome",
"requirements": ["gehomesdk==0.5.23","magicattr==0.1.6","slixmpp==1.8.3"],
"requirements": ["gehomesdk==0.5.26","magicattr==0.1.6","slixmpp==1.8.3"],
"codeowners": ["@simbaja"],
"version": "0.6.8"
"version": "0.6.9"
}

View File

@ -34,4 +34,12 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn
_LOGGER.debug(f'Found {len(entities):d} unregisterd numbers')
async_add_entities(entities)
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered)
#if we're already initialized at this point, call device
#discovery directly, otherwise add a callback based on the
#ready signal
if coordinator.initialized:
async_devices_discovered(coordinator.appliance_apis.values())
else:
# add the ready signal and register the remove callback
coordinator.add_signal_remove_callback(
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered))

View File

@ -37,4 +37,12 @@ async def async_setup_entry(
_LOGGER.debug(f"Found {len(entities):d} unregistered selects")
async_add_entities(entities)
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered)
#if we're already initialized at this point, call device
#discovery directly, otherwise add a callback based on the
#ready signal
if coordinator.initialized:
async_devices_discovered(coordinator.appliance_apis.values())
else:
# add the ready signal and register the remove callback
coordinator.add_signal_remove_callback(
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered))

View File

@ -47,8 +47,16 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn
_LOGGER.debug(f'Found {len(entities):d} unregistered sensors')
async_add_entities(entities)
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered)
#if we're already initialized at this point, call device
#discovery directly, otherwise add a callback based on the
#ready signal
if coordinator.initialized:
async_devices_discovered(coordinator.appliance_apis.values())
else:
# add the ready signal and register the remove callback
coordinator.add_signal_remove_callback(
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered))
# register set_timer entity service
platform.async_register_entity_service(
SERVICE_SET_TIMER,

View File

@ -33,4 +33,12 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn
_LOGGER.debug(f'Found {len(entities):d} unregistered switches')
async_add_entities(entities)
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered)
#if we're already initialized at this point, call device
#discovery directly, otherwise add a callback based on the
#ready signal
if coordinator.initialized:
async_devices_discovered(coordinator.appliance_apis.values())
else:
# add the ready signal and register the remove callback
coordinator.add_signal_remove_callback(
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered))

View File

@ -3,7 +3,7 @@
import asyncio
import async_timeout
import logging
from typing import Any, Dict, Iterable, Optional, Tuple
from typing import Any, Callable, Dict, Iterable, Optional, Tuple, List
from gehomesdk import (
EVENT_APPLIANCE_INITIAL_UPDATE,
@ -22,6 +22,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, CONF_REGION
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import (
@ -55,17 +56,17 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None:
"""Set up the GeHomeUpdateCoordinator class."""
self._hass = hass
super().__init__(hass, _LOGGER, name=DOMAIN)
self._config_entry = config_entry
self._username = config_entry.data[CONF_USERNAME]
self._password = config_entry.data[CONF_PASSWORD]
self._region = config_entry.data[CONF_REGION]
self._appliance_apis = {} # type: Dict[str, ApplianceApi]
self._signal_remove_callbacks = [] # type: List[Callable]
self._reset_initialization()
super().__init__(hass, _LOGGER, name=DOMAIN)
def _reset_initialization(self):
self.client = None # type: Optional[GeWebsocketClient]
@ -111,7 +112,11 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
@property
def signal_ready(self) -> str:
"""Event specific per entry to signal readiness"""
return f"{DOMAIN}-ready-{self._config_entry.entry_id}"
return f"{DOMAIN}-ready-{self._config_entry.entry_id}"
@property
def initialized(self) -> bool:
return self._init_done
@property
def online(self) -> bool:
@ -150,6 +155,9 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
api = self.appliance_apis[mac_addr]
api.appliance = appliance
def add_signal_remove_callback(self, cb: Callable):
self._signal_remove_callbacks.append(cb)
async def get_client(self) -> GeWebsocketClient:
"""Get a new GE Websocket client."""
if self.client:
@ -161,8 +169,7 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
finally:
self._reset_initialization()
loop = self._hass.loop
self.client = self.create_ge_client(event_loop=loop)
self.client = self.create_ge_client(event_loop=self.hass.loop)
return self.client
async def async_setup(self):
@ -201,9 +208,9 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
async def async_begin_session(self):
"""Begins the ge_home 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)
fut = asyncio.ensure_future(self.client.async_run_client(), loop=self._hass.loop)
fut = asyncio.ensure_future(self.client.async_run_client(), loop=self.hass.loop)
_LOGGER.debug("Client running")
return fut
@ -211,6 +218,12 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
"""Resets the coordinator."""
_LOGGER.debug("resetting the coordinator")
entry = self._config_entry
# remove all the callbacks for this coordinator
for c in self._signal_remove_callbacks:
c()
self._signal_remove_callbacks.clear()
unload_ok = all(
await asyncio.gather(
*[
@ -263,7 +276,7 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
_LOGGER.info("ge_home shutting down")
if self.client:
self.client.clear_event_handlers()
self._hass.loop.create_task(self.client.disconnect())
self.hass.loop.create_task(self.client.disconnect())
async def on_device_update(self, data: Tuple[GeAppliance, Dict[ErdCodeType, Any]]):
"""Let HA know there's new state."""
@ -272,24 +285,34 @@ class GeHomeUpdateCoordinator(DataUpdateCoordinator):
try:
api = self.appliance_apis[appliance.mac_addr]
except KeyError:
_LOGGER.warn(f"Could not find appliance {appliance.mac_addr} in known device list.")
return
for entity in api.entities:
if entity.enabled:
_LOGGER.debug(f"Updating {entity} ({entity.unique_id}, {entity.entity_id})")
entity.async_write_ha_state()
self._update_entity_state(api.entities)
async def _refresh_ha_state(self):
entities = [
entity for api in self.appliance_apis.values() for entity in api.entities
]
self._update_entity_state(entities)
def _update_entity_state(self, entities: List[Entity]):
from .entities import GeEntity
for entity in entities:
# if this is a GeEntity, check if it's been added
#if not, don't try to refresh this entity
if isinstance(entity, GeEntity):
gee: GeEntity = entity
if not gee.added:
_LOGGER.debug(f"Entity {entity} ({entity.unique_id}, {entity.entity_id}) not yet added, skipping update...")
continue
if entity.enabled:
try:
_LOGGER.debug(f"Refreshing state for {entity} ({entity.unique_id}, {entity.entity_id}")
entity.async_write_ha_state()
except:
_LOGGER.debug(f"Could not refresh state for {entity} ({entity.unique_id}, {entity.entity_id}")
_LOGGER.warn(f"Could not refresh state for {entity} ({entity.unique_id}, {entity.entity_id}", exc_info=1)
@property
def all_appliances_updated(self) -> bool:

View File

@ -35,4 +35,12 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn
_LOGGER.debug(f'Found {len(entities):d} unregistered water heaters')
async_add_entities(entities)
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered)
#if we're already initialized at this point, call device
#discovery directly, otherwise add a callback based on the
#ready signal
if coordinator.initialized:
async_devices_discovered(coordinator.appliance_apis.values())
else:
# add the ready signal and register the remove callback
coordinator.add_signal_remove_callback(
async_dispatcher_connect(hass, coordinator.signal_ready, async_devices_discovered))

View File

@ -69,6 +69,10 @@ A/C Controls:
#### Features
{% if version_installed.split('.') | map('int') < '0.6.9'.split('.') | map('int') %}
- Added additional fridge controls (#200)
{% endif %}
{% if version_installed.split('.') | map('int') < '0.6.8'.split('.') | map('int') %}
- Added Dehumidifier (#114)
- Added oven drawer sensors
@ -123,6 +127,11 @@ A/C Controls:
#### Bugfixes
{% if version_installed.split('.') | map('int') < '0.6.9'.split('.') | map('int') %}
- Bugfix: Additional auth stability improvements (#215, #211)
- Bugfix: Removed deprecated constants (#218)
{% endif %}
{% if version_installed.split('.') | map('int') < '0.6.8'.split('.') | map('int') %}
- Bugfix: Fixed issue with oven lights (#174)
- Bugfix: Fixed issues with dual dishwasher (#161)