Update nexia climate platform to use newer standards (#64186)

This commit is contained in:
J. Nick Koston 2022-01-16 07:51:16 -10:00 committed by GitHub
parent 92b48cca7e
commit 187b4fad84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 74 additions and 102 deletions

View File

@ -731,6 +731,7 @@ omit =
homeassistant/components/netgear_lte/*
homeassistant/components/netio/switch.py
homeassistant/components/neurio_energy/sensor.py
homeassistant/components/nexia/entity.py
homeassistant/components/nexia/climate.py
homeassistant/components/nextcloud/*
homeassistant/components/nfandroidtv/__init__.py

View File

@ -1,4 +1,6 @@
"""Support for Nexia / Trane XL thermostats."""
from __future__ import annotations
from nexia.const import (
HOLD_PERMANENT,
HOLD_RESUME_SCHEDULE,
@ -9,17 +11,17 @@ from nexia.const import (
SYSTEM_STATUS_COOL,
SYSTEM_STATUS_HEAT,
SYSTEM_STATUS_IDLE,
UNIT_FAHRENHEIT,
)
from nexia.home import NexiaHome
from nexia.thermostat import NexiaThermostat
from nexia.util import find_humidity_setpoint
from nexia.zone import NexiaThermostatZone
import voluptuous as vol
from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import (
ATTR_HUMIDITY,
ATTR_HVAC_MODE,
ATTR_MAX_HUMIDITY,
ATTR_MIN_HUMIDITY,
ATTR_TARGET_TEMP_HIGH,
ATTR_TARGET_TEMP_LOW,
CURRENT_HVAC_COOL,
@ -43,7 +45,6 @@ from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_platform
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import dispatcher_send
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import (
@ -55,8 +56,6 @@ from .const import (
ATTR_RUN_MODE,
ATTR_ZONE_STATUS,
DOMAIN,
SIGNAL_THERMOSTAT_UPDATE,
SIGNAL_ZONE_UPDATE,
)
from .coordinator import NexiaDataUpdateCoordinator
from .entity import NexiaThermostatZoneEntity
@ -108,6 +107,21 @@ NEXIA_TO_HA_HVAC_MODE_MAP = {
value: key for key, value in HA_TO_NEXIA_HVAC_MODE_MAP.items()
}
HVAC_MODES = [
HVAC_MODE_OFF,
HVAC_MODE_AUTO,
HVAC_MODE_HEAT_COOL,
HVAC_MODE_HEAT,
HVAC_MODE_COOL,
]
NEXIA_SUPPORTED = (
SUPPORT_TARGET_TEMPERATURE_RANGE
| SUPPORT_TARGET_TEMPERATURE
| SUPPORT_FAN_MODE
| SUPPORT_PRESET_MODE
)
async def async_setup_entry(
hass: HomeAssistant,
@ -116,7 +130,7 @@ async def async_setup_entry(
) -> None:
"""Set up climate for a Nexia device."""
coordinator: NexiaDataUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]
nexia_home = coordinator.nexia_home
nexia_home: NexiaHome = coordinator.nexia_home
platform = entity_platform.async_get_current_platform()
@ -132,61 +146,57 @@ async def async_setup_entry(
SERVICE_SET_HVAC_RUN_MODE, SET_HVAC_RUN_MODE_SCHEMA, SERVICE_SET_HVAC_RUN_MODE
)
entities = []
entities: list[NexiaZone] = []
for thermostat_id in nexia_home.get_thermostat_ids():
thermostat = nexia_home.get_thermostat_by_id(thermostat_id)
thermostat: NexiaThermostat = nexia_home.get_thermostat_by_id(thermostat_id)
for zone_id in thermostat.get_zone_ids():
zone = thermostat.get_zone_by_id(zone_id)
zone: NexiaThermostatZone = thermostat.get_zone_by_id(zone_id)
entities.append(NexiaZone(coordinator, zone))
async_add_entities(entities, True)
async_add_entities(entities)
class NexiaZone(NexiaThermostatZoneEntity, ClimateEntity):
"""Provides Nexia Climate support."""
def __init__(self, coordinator, zone):
def __init__(
self, coordinator: NexiaDataUpdateCoordinator, zone: NexiaThermostatZone
) -> None:
"""Initialize the thermostat."""
super().__init__(
coordinator, zone, name=zone.get_name(), unique_id=zone.zone_id
)
self._undo_humidfy_dispatcher = None
self._undo_aircleaner_dispatcher = None
unit = self._thermostat.get_unit()
min_humidity, max_humidity = self._thermostat.get_humidity_setpoint_limits()
min_setpoint, max_setpoint = self._thermostat.get_setpoint_limits()
# The has_* calls are stable for the life of the device
# and do not do I/O
self._has_relative_humidity = self._thermostat.has_relative_humidity()
self._has_emergency_heat = self._thermostat.has_emergency_heat()
self._has_humidify_support = self._thermostat.has_humidify_support()
self._has_dehumidify_support = self._thermostat.has_dehumidify_support()
@property
def supported_features(self):
"""Return the list of supported features."""
supported = (
SUPPORT_TARGET_TEMPERATURE_RANGE
| SUPPORT_TARGET_TEMPERATURE
| SUPPORT_FAN_MODE
| SUPPORT_PRESET_MODE
)
supported = NEXIA_SUPPORTED
if self._has_humidify_support or self._has_dehumidify_support:
supported |= SUPPORT_TARGET_HUMIDITY
if self._has_emergency_heat:
supported |= SUPPORT_AUX_HEAT
return supported
self._attr_supported_features = supported
self._attr_preset_modes = self._zone.get_presets()
self._attr_fan_modes = self._thermostat.get_fan_modes()
self._attr_hvac_modes = HVAC_MODES
self._attr_min_humidity = percent_conv(min_humidity)
self._attr_max_humidity = percent_conv(max_humidity)
self._attr_min_temp = min_setpoint
self._attr_max_temp = max_setpoint
self._attr_temperature_unit = TEMP_CELSIUS if unit == "C" else TEMP_FAHRENHEIT
self._attr_target_temperature_step = 0.5 if unit == "C" else 1.0
self._attr_preset_modes = self._zone.get_presets()
@property
def is_fan_on(self):
"""Blower is on."""
return self._thermostat.is_blower_active()
@property
def temperature_unit(self):
"""Return the unit of measurement."""
return TEMP_CELSIUS if self._thermostat.get_unit() == "C" else TEMP_FAHRENHEIT
@property
def current_temperature(self):
"""Return the current temperature."""
@ -197,21 +207,6 @@ class NexiaZone(NexiaThermostatZoneEntity, ClimateEntity):
"""Return the fan setting."""
return self._thermostat.get_fan_mode()
@property
def fan_modes(self):
"""Return the list of available fan modes."""
return self._thermostat.get_fan_modes()
@property
def min_temp(self):
"""Minimum temp for the current setting."""
return (self._thermostat.get_setpoint_limits())[0]
@property
def max_temp(self):
"""Maximum temp for the current setting."""
return (self._thermostat.get_setpoint_limits())[1]
def set_fan_mode(self, fan_mode):
"""Set new target fan mode."""
self._thermostat.set_fan_mode(fan_mode)
@ -233,11 +228,6 @@ class NexiaZone(NexiaThermostatZoneEntity, ClimateEntity):
"""Preset that is active."""
return self._zone.get_preset()
@property
def preset_modes(self):
"""All presets."""
return self._zone.get_presets()
def set_humidity(self, humidity):
"""Dehumidify target."""
if self._thermostat.has_dehumidify_support():
@ -273,13 +263,6 @@ class NexiaZone(NexiaThermostatZoneEntity, ClimateEntity):
return self._zone.get_heating_setpoint()
return None
@property
def target_temperature_step(self):
"""Step size of temperature units."""
if self._thermostat.get_unit() == UNIT_FAHRENHEIT:
return 1.0
return 0.5
@property
def target_temperature_high(self):
"""Highest temperature we are trying to reach."""
@ -332,17 +315,6 @@ class NexiaZone(NexiaThermostatZoneEntity, ClimateEntity):
return NEXIA_TO_HA_HVAC_MODE_MAP[mode]
@property
def hvac_modes(self):
"""List of HVAC available modes."""
return [
HVAC_MODE_OFF,
HVAC_MODE_AUTO,
HVAC_MODE_HEAT_COOL,
HVAC_MODE_HEAT,
HVAC_MODE_COOL,
]
def set_temperature(self, **kwargs):
"""Set target temperature."""
new_heat_temp = kwargs.get(ATTR_TARGET_TEMP_LOW)
@ -397,12 +369,8 @@ class NexiaZone(NexiaThermostatZoneEntity, ClimateEntity):
if not self._has_relative_humidity:
return data
min_humidity = percent_conv(self._thermostat.get_humidity_setpoint_limits()[0])
max_humidity = percent_conv(self._thermostat.get_humidity_setpoint_limits()[1])
data.update(
{
ATTR_MIN_HUMIDITY: min_humidity,
ATTR_MAX_HUMIDITY: max_humidity,
ATTR_DEHUMIDIFY_SUPPORTED: self._has_dehumidify_support,
ATTR_HUMIDIFY_SUPPORTED: self._has_humidify_support,
}
@ -454,7 +422,7 @@ class NexiaZone(NexiaThermostatZoneEntity, ClimateEntity):
self._zone.call_permanent_hold()
self._zone.set_mode(mode=HA_TO_NEXIA_HVAC_MODE_MAP[hvac_mode])
self.schedule_update_ha_state()
self._signal_zone_update()
def set_aircleaner_mode(self, aircleaner_mode):
"""Set the aircleaner mode."""
@ -480,26 +448,3 @@ class NexiaZone(NexiaThermostatZoneEntity, ClimateEntity):
return
self._thermostat.set_dehumidify_setpoint(target_humidity)
self._signal_thermostat_update()
def _signal_thermostat_update(self):
"""Signal a thermostat update.
Whenever the underlying library does an action against
a thermostat, the data for the thermostat and all
connected zone is updated.
Update all the zones on the thermostat.
"""
dispatcher_send(
self.hass, f"{SIGNAL_THERMOSTAT_UPDATE}-{self._thermostat.thermostat_id}"
)
def _signal_zone_update(self):
"""Signal a zone update.
Whenever the underlying library does an action against
a zone, the data for the zone is updated.
Update a single zone.
"""
dispatcher_send(self.hass, f"{SIGNAL_ZONE_UPDATE}-{self._zone.zone_id}")

View File

@ -1,6 +1,9 @@
"""The nexia integration base entity."""
from nexia.thermostat import NexiaThermostat
from nexia.zone import NexiaThermostatZone
from homeassistant.const import ATTR_ATTRIBUTION
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.dispatcher import async_dispatcher_connect, dispatcher_send
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity
@ -47,7 +50,7 @@ class NexiaThermostatEntity(NexiaEntity):
def __init__(self, coordinator, thermostat, name, unique_id):
"""Initialize the entity."""
super().__init__(coordinator, name, unique_id)
self._thermostat = thermostat
self._thermostat: NexiaThermostat = thermostat
@property
def device_info(self) -> DeviceInfo:
@ -73,6 +76,19 @@ class NexiaThermostatEntity(NexiaEntity):
)
)
def _signal_thermostat_update(self):
"""Signal a thermostat update.
Whenever the underlying library does an action against
a thermostat, the data for the thermostat and all
connected zone is updated.
Update all the zones on the thermostat.
"""
dispatcher_send(
self.hass, f"{SIGNAL_THERMOSTAT_UPDATE}-{self._thermostat.thermostat_id}"
)
class NexiaThermostatZoneEntity(NexiaThermostatEntity):
"""Base class for nexia devices attached to a thermostat."""
@ -80,7 +96,7 @@ class NexiaThermostatZoneEntity(NexiaThermostatEntity):
def __init__(self, coordinator, zone, name, unique_id):
"""Initialize the entity."""
super().__init__(coordinator, zone.thermostat, name, unique_id)
self._zone = zone
self._zone: NexiaThermostatZone = zone
@property
def device_info(self):
@ -107,3 +123,13 @@ class NexiaThermostatZoneEntity(NexiaThermostatEntity):
self.async_write_ha_state,
)
)
def _signal_zone_update(self):
"""Signal a zone update.
Whenever the underlying library does an action against
a zone, the data for the zone is updated.
Update a single zone.
"""
dispatcher_send(self.hass, f"{SIGNAL_ZONE_UPDATE}-{self._zone.zone_id}")