mirror of
https://github.com/home-assistant/core.git
synced 2026-09-24 15:31:52 -05:00
Use platform entity attribute enums for reads in HomeKit (#180016)
This commit is contained in:
@@ -9,15 +9,8 @@ from pyhap.const import CATEGORY_THERMOSTAT
|
||||
from pyhap.service import Service
|
||||
|
||||
from homeassistant.components.climate import (
|
||||
ATTR_CURRENT_TEMPERATURE,
|
||||
ATTR_FAN_MODE,
|
||||
ATTR_FAN_MODES,
|
||||
ATTR_HVAC_ACTION,
|
||||
ATTR_HVAC_MODES,
|
||||
ATTR_MAX_TEMP,
|
||||
ATTR_MIN_TEMP,
|
||||
ATTR_SWING_MODE,
|
||||
ATTR_SWING_MODES,
|
||||
ATTR_TARGET_TEMP_HIGH,
|
||||
ATTR_TARGET_TEMP_LOW,
|
||||
DEFAULT_MAX_TEMP,
|
||||
@@ -29,7 +22,9 @@ from homeassistant.components.climate import (
|
||||
SERVICE_SET_FAN_MODE,
|
||||
SERVICE_SET_SWING_MODE,
|
||||
SWING_OFF,
|
||||
ClimateEntityCapabilityAttribute,
|
||||
ClimateEntityFeature,
|
||||
ClimateEntityStateAttribute,
|
||||
HVACAction,
|
||||
HVACMode,
|
||||
)
|
||||
@@ -141,11 +136,11 @@ class HomeKitClimateAccessory(HomeAccessory):
|
||||
# reload the accessory when any of them change.
|
||||
self._reload_on_change_attrs.extend(
|
||||
(
|
||||
ATTR_MIN_TEMP,
|
||||
ATTR_MAX_TEMP,
|
||||
ATTR_FAN_MODES,
|
||||
ATTR_SWING_MODES,
|
||||
ATTR_HVAC_MODES,
|
||||
ClimateEntityCapabilityAttribute.MIN_TEMP,
|
||||
ClimateEntityCapabilityAttribute.MAX_TEMP,
|
||||
ClimateEntityCapabilityAttribute.FAN_MODES,
|
||||
ClimateEntityCapabilityAttribute.SWING_MODES,
|
||||
ClimateEntityCapabilityAttribute.HVAC_MODES,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -204,7 +199,9 @@ class HomeKitClimateAccessory(HomeAccessory):
|
||||
def _update_current_temperature_char(self, state: State) -> None:
|
||||
"""Update the current temperature characteristic from the entity state."""
|
||||
self._update_temperature_char(
|
||||
self.char_current_temp, state, ATTR_CURRENT_TEMPERATURE
|
||||
self.char_current_temp,
|
||||
state,
|
||||
ClimateEntityStateAttribute.CURRENT_TEMPERATURE,
|
||||
)
|
||||
|
||||
def _dual_setpoint_params(
|
||||
@@ -275,7 +272,8 @@ class HomeKitClimateAccessory(HomeAccessory):
|
||||
self.ordered_fan_speeds
|
||||
and (
|
||||
speed := fan_mode_to_speed(
|
||||
self.ordered_fan_speeds, attributes.get(ATTR_FAN_MODE)
|
||||
self.ordered_fan_speeds,
|
||||
attributes.get(ClimateEntityStateAttribute.FAN_MODE),
|
||||
)
|
||||
)
|
||||
is not None
|
||||
@@ -286,7 +284,7 @@ class HomeKitClimateAccessory(HomeAccessory):
|
||||
"""Update the swing characteristic from the current swing mode."""
|
||||
# An absent swing mode keeps the last value; there is nothing to show.
|
||||
if self.swing_on_mode is not None and (
|
||||
swing_mode := attributes.get(ATTR_SWING_MODE)
|
||||
swing_mode := attributes.get(ClimateEntityStateAttribute.SWING_MODE)
|
||||
):
|
||||
self.char_swing.set_value(1 if is_swing_on(swing_mode) else 0)
|
||||
|
||||
@@ -363,13 +361,13 @@ class HomeKitClimateAccessory(HomeAccessory):
|
||||
self._update_swing_char(attributes)
|
||||
self._update_fan_speed_char(attributes)
|
||||
|
||||
fan_mode = attributes.get(ATTR_FAN_MODE)
|
||||
fan_mode = attributes.get(ClimateEntityStateAttribute.FAN_MODE)
|
||||
fan_mode_lower = fan_mode.lower() if isinstance(fan_mode, str) else None
|
||||
if CHAR_TARGET_FAN_STATE in self.fan_chars:
|
||||
self.char_target_fan_state.set_value(1 if fan_mode_lower == FAN_AUTO else 0)
|
||||
|
||||
if CHAR_CURRENT_FAN_STATE in self.fan_chars and (
|
||||
hvac_action := attributes.get(ATTR_HVAC_ACTION)
|
||||
hvac_action := attributes.get(ClimateEntityStateAttribute.HVAC_ACTION)
|
||||
):
|
||||
self.char_current_fan_state.set_value(
|
||||
HC_HASS_TO_HOMEKIT_FAN_STATE[hvac_action]
|
||||
|
||||
@@ -5,10 +5,6 @@ import math
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.climate import (
|
||||
ATTR_FAN_MODES,
|
||||
ATTR_MAX_TEMP,
|
||||
ATTR_MIN_TEMP,
|
||||
ATTR_SWING_MODES,
|
||||
FAN_HIGH,
|
||||
FAN_LOW,
|
||||
FAN_MEDIUM,
|
||||
@@ -18,6 +14,7 @@ from homeassistant.components.climate import (
|
||||
SWING_OFF,
|
||||
SWING_ON,
|
||||
SWING_VERTICAL,
|
||||
ClimateEntityCapabilityAttribute,
|
||||
)
|
||||
from homeassistant.core import State
|
||||
from homeassistant.util.percentage import (
|
||||
@@ -51,7 +48,9 @@ def get_fan_modes_and_speeds(
|
||||
exposes, in HomeKit rotation-speed order; it is empty when the entity only
|
||||
advertises custom fan mode names.
|
||||
"""
|
||||
fan_modes = _lower_to_original(attributes.get(ATTR_FAN_MODES) or [])
|
||||
fan_modes = _lower_to_original(
|
||||
attributes.get(ClimateEntityCapabilityAttribute.FAN_MODES) or []
|
||||
)
|
||||
ordered_fan_speeds: list[str] = []
|
||||
if PRE_DEFINED_FAN_MODES.intersection(fan_modes):
|
||||
ordered_fan_speeds = [
|
||||
@@ -67,7 +66,9 @@ def get_swing_on_mode(attributes: dict[str, Any]) -> str | None:
|
||||
returned so it can be sent back to the service. Returns ``None`` when the
|
||||
entity exposes no predefined swing modes.
|
||||
"""
|
||||
if not (swing_modes := attributes.get(ATTR_SWING_MODES)):
|
||||
if not (
|
||||
swing_modes := attributes.get(ClimateEntityCapabilityAttribute.SWING_MODES)
|
||||
):
|
||||
return None
|
||||
lower_to_original = _lower_to_original(swing_modes)
|
||||
return next(
|
||||
@@ -82,13 +83,13 @@ def get_swing_on_mode(attributes: dict[str, Any]) -> str | None:
|
||||
|
||||
def get_swing_off_mode(attributes: dict[str, Any]) -> str:
|
||||
"""Return the entity's off swing mode, preserving its original casing."""
|
||||
swing_modes = attributes.get(ATTR_SWING_MODES) or []
|
||||
swing_modes = attributes.get(ClimateEntityCapabilityAttribute.SWING_MODES) or []
|
||||
return _lower_to_original(swing_modes).get(SWING_OFF, SWING_OFF)
|
||||
|
||||
|
||||
def has_swing_off_mode(attributes: dict[str, Any]) -> bool:
|
||||
"""Return whether the entity advertises a swing off mode."""
|
||||
swing_modes = attributes.get(ATTR_SWING_MODES) or []
|
||||
swing_modes = attributes.get(ClimateEntityCapabilityAttribute.SWING_MODES) or []
|
||||
return SWING_OFF in _lower_to_original(swing_modes)
|
||||
|
||||
|
||||
@@ -131,12 +132,16 @@ def get_temperature_range_from_state(
|
||||
defaults are already Celsius and used as-is. The minimum is clamped to zero
|
||||
because the Home app crashes on negative bounds.
|
||||
"""
|
||||
if (min_temp := state.attributes.get(ATTR_MIN_TEMP)) is not None:
|
||||
if (
|
||||
min_temp := state.attributes.get(ClimateEntityCapabilityAttribute.MIN_TEMP)
|
||||
) is not None:
|
||||
min_temp = temperature_to_homekit(min_temp, unit)
|
||||
else:
|
||||
min_temp = default_min
|
||||
|
||||
if (max_temp := state.attributes.get(ATTR_MAX_TEMP)) is not None:
|
||||
if (
|
||||
max_temp := state.attributes.get(ClimateEntityCapabilityAttribute.MAX_TEMP)
|
||||
) is not None:
|
||||
max_temp = temperature_to_homekit(max_temp, unit)
|
||||
else:
|
||||
max_temp = default_max
|
||||
|
||||
@@ -8,6 +8,7 @@ from pyhap.const import CATEGORY_AIR_PURIFIER
|
||||
from pyhap.service import Service
|
||||
from pyhap.util import callback as pyhap_callback
|
||||
|
||||
from homeassistant.components.fan import FanEntityStateAttribute
|
||||
from homeassistant.const import (
|
||||
STATE_ON,
|
||||
STATE_UNAVAILABLE,
|
||||
@@ -48,7 +49,7 @@ from .const import (
|
||||
SERV_TEMPERATURE_SENSOR,
|
||||
THRESHOLD_FILTER_CHANGE_NEEDED,
|
||||
)
|
||||
from .type_fans import ATTR_PRESET_MODE, CHAR_ROTATION_SPEED, Fan
|
||||
from .type_fans import CHAR_ROTATION_SPEED, Fan
|
||||
from .util import (
|
||||
cleanup_name_for_homekit,
|
||||
convert_to_float,
|
||||
@@ -468,8 +469,8 @@ class AirPurifier(Fan):
|
||||
|
||||
# Automatic mode is represented in HASS by a preset called Auto or auto
|
||||
attributes = new_state.attributes
|
||||
if ATTR_PRESET_MODE in attributes:
|
||||
current_preset_mode = attributes.get(ATTR_PRESET_MODE)
|
||||
if FanEntityStateAttribute.PRESET_MODE in attributes:
|
||||
current_preset_mode = attributes.get(FanEntityStateAttribute.PRESET_MODE)
|
||||
self.char_target_air_purifier_state.set_value(
|
||||
TARGET_STATE_AUTO
|
||||
if current_preset_mode and current_preset_mode.lower() == "auto"
|
||||
|
||||
@@ -13,12 +13,11 @@ from pyhap.service import Service
|
||||
from pyhap.util import callback as pyhap_callback
|
||||
|
||||
from homeassistant.components.cover import (
|
||||
ATTR_CURRENT_POSITION,
|
||||
ATTR_CURRENT_TILT_POSITION,
|
||||
ATTR_POSITION,
|
||||
ATTR_TILT_POSITION,
|
||||
DOMAIN as COVER_DOMAIN,
|
||||
CoverEntityFeature,
|
||||
CoverEntityStateAttribute,
|
||||
CoverState,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
@@ -273,7 +272,9 @@ class OpeningDeviceBase(HomeAccessory):
|
||||
# update tilt
|
||||
if not self._supports_tilt:
|
||||
return
|
||||
current_tilt = new_state.attributes.get(ATTR_CURRENT_TILT_POSITION)
|
||||
current_tilt = new_state.attributes.get(
|
||||
CoverEntityStateAttribute.CURRENT_TILT_POSITION
|
||||
)
|
||||
if not isinstance(current_tilt, (float, int)):
|
||||
return
|
||||
# HomeKit sends values between -90 and 90.
|
||||
@@ -332,7 +333,9 @@ class OpeningDevice(OpeningDeviceBase, HomeAccessory):
|
||||
@override
|
||||
def async_update_state(self, new_state: State) -> None:
|
||||
"""Update cover position and tilt after state changed."""
|
||||
current_position = new_state.attributes.get(ATTR_CURRENT_POSITION)
|
||||
current_position = new_state.attributes.get(
|
||||
CoverEntityStateAttribute.CURRENT_POSITION
|
||||
)
|
||||
if isinstance(current_position, (float, int)):
|
||||
current_position = int(current_position)
|
||||
self.char_current_position.set_value(current_position)
|
||||
|
||||
@@ -10,9 +10,7 @@ from homeassistant.components.fan import (
|
||||
ATTR_DIRECTION,
|
||||
ATTR_OSCILLATING,
|
||||
ATTR_PERCENTAGE,
|
||||
ATTR_PERCENTAGE_STEP,
|
||||
ATTR_PRESET_MODE,
|
||||
ATTR_PRESET_MODES,
|
||||
DIRECTION_FORWARD,
|
||||
DIRECTION_REVERSE,
|
||||
DOMAIN as FAN_DOMAIN,
|
||||
@@ -20,7 +18,9 @@ from homeassistant.components.fan import (
|
||||
SERVICE_SET_DIRECTION,
|
||||
SERVICE_SET_PERCENTAGE,
|
||||
SERVICE_SET_PRESET_MODE,
|
||||
FanEntityCapabilityAttribute,
|
||||
FanEntityFeature,
|
||||
FanEntityStateAttribute,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
@@ -66,14 +66,18 @@ class Fan(HomeAccessory):
|
||||
assert state
|
||||
self._reload_on_change_attrs.extend(
|
||||
(
|
||||
ATTR_PERCENTAGE_STEP,
|
||||
ATTR_PRESET_MODES,
|
||||
FanEntityStateAttribute.PERCENTAGE_STEP,
|
||||
FanEntityCapabilityAttribute.PRESET_MODES,
|
||||
)
|
||||
)
|
||||
|
||||
features = state.attributes.get(EntityStateAttribute.SUPPORTED_FEATURES, 0)
|
||||
percentage_step = state.attributes.get(ATTR_PERCENTAGE_STEP, 1)
|
||||
self.preset_modes: list[str] | None = state.attributes.get(ATTR_PRESET_MODES)
|
||||
percentage_step = state.attributes.get(
|
||||
FanEntityStateAttribute.PERCENTAGE_STEP, 1
|
||||
)
|
||||
self.preset_modes: list[str] | None = state.attributes.get(
|
||||
FanEntityCapabilityAttribute.PRESET_MODES
|
||||
)
|
||||
|
||||
if features & FanEntityFeature.DIRECTION:
|
||||
self.chars.append(CHAR_ROTATION_DIRECTION)
|
||||
@@ -210,7 +214,9 @@ class Fan(HomeAccessory):
|
||||
params[ATTR_PRESET_MODE] = self.preset_modes[0]
|
||||
self.async_call_service(FAN_DOMAIN, SERVICE_SET_PRESET_MODE, params)
|
||||
elif current_state := self.hass.states.get(self.entity_id):
|
||||
percentage: float = current_state.attributes.get(ATTR_PERCENTAGE) or 50.0
|
||||
percentage: float = (
|
||||
current_state.attributes.get(FanEntityStateAttribute.PERCENTAGE) or 50.0
|
||||
)
|
||||
params[ATTR_PERCENTAGE] = percentage
|
||||
_LOGGER.debug("%s: Set auto to 0", self.entity_id)
|
||||
self.async_call_service(FAN_DOMAIN, SERVICE_TURN_ON, params)
|
||||
@@ -267,7 +273,7 @@ class Fan(HomeAccessory):
|
||||
|
||||
# Handle Direction
|
||||
if self.char_direction is not None:
|
||||
direction = new_state.attributes.get(ATTR_DIRECTION)
|
||||
direction = new_state.attributes.get(FanEntityStateAttribute.DIRECTION)
|
||||
if direction in (DIRECTION_FORWARD, DIRECTION_REVERSE):
|
||||
hk_direction = 1 if direction == DIRECTION_REVERSE else 0
|
||||
self.char_direction.set_value(hk_direction)
|
||||
@@ -276,7 +282,7 @@ class Fan(HomeAccessory):
|
||||
if self.char_speed is not None and state != STATE_OFF:
|
||||
# We do not change the homekit speed when turning off
|
||||
# as it will clear the restore state
|
||||
percentage = attributes.get(ATTR_PERCENTAGE)
|
||||
percentage = attributes.get(FanEntityStateAttribute.PERCENTAGE)
|
||||
# If the homeassistant component reports its speed as the first entry
|
||||
# in its speed list but is not off, the hk_speed_value is 0. But 0
|
||||
# is a special value in homekit. When you turn on a homekit accessory
|
||||
@@ -295,12 +301,12 @@ class Fan(HomeAccessory):
|
||||
|
||||
# Handle Oscillating
|
||||
if self.char_swing is not None:
|
||||
oscillating = attributes.get(ATTR_OSCILLATING)
|
||||
oscillating = attributes.get(FanEntityStateAttribute.OSCILLATING)
|
||||
if isinstance(oscillating, bool):
|
||||
hk_oscillating = 1 if oscillating else 0
|
||||
self.char_swing.set_value(hk_oscillating)
|
||||
|
||||
current_preset_mode = attributes.get(ATTR_PRESET_MODE)
|
||||
current_preset_mode = attributes.get(FanEntityStateAttribute.PRESET_MODE)
|
||||
if self.char_target_fan_state is not None:
|
||||
# Handle single preset mode
|
||||
self.char_target_fan_state.set_value(int(current_preset_mode is not None))
|
||||
|
||||
@@ -10,11 +10,7 @@ from pyhap.characteristic import Characteristic
|
||||
from pyhap.const import CATEGORY_AIR_CONDITIONER, CATEGORY_HEATER
|
||||
|
||||
from homeassistant.components.climate import (
|
||||
ATTR_CURRENT_HUMIDITY,
|
||||
ATTR_CURRENT_TEMPERATURE,
|
||||
ATTR_HVAC_ACTION,
|
||||
ATTR_HVAC_MODE,
|
||||
ATTR_HVAC_MODES,
|
||||
ATTR_TARGET_TEMP_HIGH,
|
||||
ATTR_TARGET_TEMP_LOW,
|
||||
ATTR_TEMPERATURE,
|
||||
@@ -25,7 +21,9 @@ from homeassistant.components.climate import (
|
||||
SERVICE_SET_HVAC_MODE,
|
||||
SERVICE_SET_SWING_MODE,
|
||||
SERVICE_SET_TEMPERATURE,
|
||||
ClimateEntityCapabilityAttribute,
|
||||
ClimateEntityFeature,
|
||||
ClimateEntityStateAttribute,
|
||||
HVACAction,
|
||||
HVACMode,
|
||||
)
|
||||
@@ -151,7 +149,7 @@ class HeaterCooler(HomeKitClimateAccessory):
|
||||
)
|
||||
)
|
||||
|
||||
hvac_modes = attributes.get(ATTR_HVAC_MODES, [])
|
||||
hvac_modes = attributes.get(ClimateEntityCapabilityAttribute.HVAC_MODES, [])
|
||||
current_mode = try_parse_enum(HVACMode, state.state)
|
||||
|
||||
self._supports_off = HVACMode.OFF in hvac_modes
|
||||
@@ -229,7 +227,7 @@ class HeaterCooler(HomeKitClimateAccessory):
|
||||
self.fan_chars.append(CHAR_TARGET_FAN_STATE)
|
||||
if self.ordered_fan_speeds:
|
||||
self.fan_chars.append(CHAR_ROTATION_SPEED)
|
||||
if attributes.get(ATTR_HVAC_ACTION) is not None:
|
||||
if attributes.get(ClimateEntityStateAttribute.HVAC_ACTION) is not None:
|
||||
self.fan_chars.append(CHAR_CURRENT_FAN_STATE)
|
||||
|
||||
# Fan/swing modes are detected in the base class; only advertise the
|
||||
@@ -304,7 +302,7 @@ class HeaterCooler(HomeKitClimateAccessory):
|
||||
# Thermostat, this is decided once at setup and not a reload attribute:
|
||||
# current humidity changes on every update, so reloading on it would
|
||||
# thrash the accessory.
|
||||
self._has_humidity = ATTR_CURRENT_HUMIDITY in attributes
|
||||
self._has_humidity = ClimateEntityStateAttribute.CURRENT_HUMIDITY in attributes
|
||||
if self._has_humidity:
|
||||
humidity_serv = self.add_preload_service(SERV_HUMIDITY_SENSOR, CHAR_NAME)
|
||||
serv.add_linked_service(humidity_serv)
|
||||
@@ -534,10 +532,13 @@ class HeaterCooler(HomeKitClimateAccessory):
|
||||
self._has_cool_threshold
|
||||
and self._has_heat_threshold
|
||||
and (
|
||||
ATTR_TARGET_TEMP_HIGH in attributes
|
||||
or ATTR_TARGET_TEMP_LOW in attributes
|
||||
ClimateEntityStateAttribute.TARGET_TEMP_HIGH in attributes
|
||||
or ClimateEntityStateAttribute.TARGET_TEMP_LOW in attributes
|
||||
)
|
||||
and (
|
||||
effective_mode in RANGE_MODES
|
||||
or ClimateEntityStateAttribute.TARGET_TEMPERATURE not in attributes
|
||||
)
|
||||
and (effective_mode in RANGE_MODES or ATTR_TEMPERATURE not in attributes)
|
||||
)
|
||||
|
||||
if use_range:
|
||||
@@ -584,7 +585,9 @@ class HeaterCooler(HomeKitClimateAccessory):
|
||||
# Pick whichever threshold moved further from the entity's existing
|
||||
# target setpoint. The thresholds are in HomeKit units, so convert
|
||||
# the target setpoint before comparing.
|
||||
target_temp = current_state.attributes.get(ATTR_TEMPERATURE)
|
||||
target_temp = current_state.attributes.get(
|
||||
ClimateEntityStateAttribute.TARGET_TEMPERATURE
|
||||
)
|
||||
if target_temp is None:
|
||||
selected_temp = heating_temp
|
||||
else:
|
||||
@@ -643,9 +646,9 @@ class HeaterCooler(HomeKitClimateAccessory):
|
||||
self.char_current_state.set_value(HC_INACTIVE)
|
||||
else:
|
||||
self.char_active.set_value(1)
|
||||
action = attributes.get(ATTR_HVAC_ACTION) or self._derive_action(
|
||||
new_state, current_mode
|
||||
)
|
||||
action = attributes.get(
|
||||
ClimateEntityStateAttribute.HVAC_ACTION
|
||||
) or self._derive_action(new_state, current_mode)
|
||||
self.char_current_state.set_value(
|
||||
HC_HASS_TO_HOMEKIT_ACTION.get(action, HC_INACTIVE)
|
||||
)
|
||||
@@ -653,7 +656,8 @@ class HeaterCooler(HomeKitClimateAccessory):
|
||||
self._update_current_temperature_char(new_state)
|
||||
self._update_temperature_thresholds(new_state)
|
||||
if self._has_humidity and isinstance(
|
||||
(humidity := attributes.get(ATTR_CURRENT_HUMIDITY)), (int, float)
|
||||
(humidity := attributes.get(ClimateEntityStateAttribute.CURRENT_HUMIDITY)),
|
||||
(int, float),
|
||||
):
|
||||
self.char_current_humidity.set_value(humidity)
|
||||
if self.fan_chars:
|
||||
@@ -671,8 +675,8 @@ class HeaterCooler(HomeKitClimateAccessory):
|
||||
# Dual capable entities publish the range keys even in single
|
||||
# setpoint modes, so only values decide what is displayed.
|
||||
supports_dual_temp = (
|
||||
attributes.get(ATTR_TARGET_TEMP_HIGH) is not None
|
||||
or attributes.get(ATTR_TARGET_TEMP_LOW) is not None
|
||||
attributes.get(ClimateEntityStateAttribute.TARGET_TEMP_HIGH) is not None
|
||||
or attributes.get(ClimateEntityStateAttribute.TARGET_TEMP_LOW) is not None
|
||||
)
|
||||
|
||||
if supports_dual_temp:
|
||||
@@ -686,7 +690,7 @@ class HeaterCooler(HomeKitClimateAccessory):
|
||||
)
|
||||
elif (
|
||||
target_temp := temperature_attribute_to_homekit(
|
||||
state, ATTR_TEMPERATURE, self._unit
|
||||
state, ClimateEntityStateAttribute.TARGET_TEMPERATURE, self._unit
|
||||
)
|
||||
) is not None:
|
||||
if self._has_cool_threshold:
|
||||
@@ -697,7 +701,7 @@ class HeaterCooler(HomeKitClimateAccessory):
|
||||
def _derive_action(self, state: State, mode: HVACMode | None) -> HVACAction:
|
||||
"""Infer heating / cooling when integration omits hvac_action."""
|
||||
attributes = state.attributes
|
||||
cur = attributes.get(ATTR_CURRENT_TEMPERATURE)
|
||||
cur = attributes.get(ClimateEntityStateAttribute.CURRENT_TEMPERATURE)
|
||||
if cur is None or mode is None:
|
||||
return HVACAction.IDLE
|
||||
|
||||
@@ -705,17 +709,19 @@ class HeaterCooler(HomeKitClimateAccessory):
|
||||
# Range modes have independent thresholds; single-target modes only
|
||||
# drive one side. Any other mode (e.g. dry, fan_only) stays idle.
|
||||
if mode in RANGE_MODES:
|
||||
cool_above = attributes.get(ATTR_TARGET_TEMP_HIGH)
|
||||
heat_below = attributes.get(ATTR_TARGET_TEMP_LOW)
|
||||
cool_above = attributes.get(ClimateEntityStateAttribute.TARGET_TEMP_HIGH)
|
||||
heat_below = attributes.get(ClimateEntityStateAttribute.TARGET_TEMP_LOW)
|
||||
if cool_above is None and heat_below is None:
|
||||
# Some integrations run auto from a single setpoint.
|
||||
cool_above = heat_below = attributes.get(ATTR_TEMPERATURE)
|
||||
cool_above = heat_below = attributes.get(
|
||||
ClimateEntityStateAttribute.TARGET_TEMPERATURE
|
||||
)
|
||||
elif mode == HVACMode.COOL:
|
||||
cool_above = attributes.get(ATTR_TEMPERATURE)
|
||||
cool_above = attributes.get(ClimateEntityStateAttribute.TARGET_TEMPERATURE)
|
||||
heat_below = None
|
||||
elif mode == HVACMode.HEAT:
|
||||
cool_above = None
|
||||
heat_below = attributes.get(ATTR_TEMPERATURE)
|
||||
heat_below = attributes.get(ClimateEntityStateAttribute.TARGET_TEMPERATURE)
|
||||
else:
|
||||
return HVACAction.IDLE
|
||||
|
||||
|
||||
@@ -7,15 +7,14 @@ from pyhap.const import CATEGORY_HUMIDIFIER
|
||||
from pyhap.util import callback as pyhap_callback
|
||||
|
||||
from homeassistant.components.humidifier import (
|
||||
ATTR_CURRENT_HUMIDITY,
|
||||
ATTR_HUMIDITY,
|
||||
ATTR_MAX_HUMIDITY,
|
||||
ATTR_MIN_HUMIDITY,
|
||||
DEFAULT_MAX_HUMIDITY,
|
||||
DEFAULT_MIN_HUMIDITY,
|
||||
DOMAIN as HUMIDIFIER_DOMAIN,
|
||||
SERVICE_SET_HUMIDITY,
|
||||
HumidifierDeviceClass,
|
||||
HumidifierEntityCapabilityAttribute,
|
||||
HumidifierEntityStateAttribute,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
@@ -101,8 +100,8 @@ class HumidifierDehumidifier(HomeAccessory):
|
||||
super().__init__(*args, category=CATEGORY_HUMIDIFIER)
|
||||
self._reload_on_change_attrs.extend(
|
||||
(
|
||||
ATTR_MAX_HUMIDITY,
|
||||
ATTR_MIN_HUMIDITY,
|
||||
HumidifierEntityCapabilityAttribute.MAX_HUMIDITY,
|
||||
HumidifierEntityCapabilityAttribute.MIN_HUMIDITY,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -287,10 +286,22 @@ class HumidifierDehumidifier(HomeAccessory):
|
||||
"""Return min and max humidity range."""
|
||||
attributes = state.attributes
|
||||
min_humidity = max(
|
||||
round(attributes.get(ATTR_MIN_HUMIDITY, DEFAULT_MIN_HUMIDITY)), 0
|
||||
round(
|
||||
attributes.get(
|
||||
HumidifierEntityCapabilityAttribute.MIN_HUMIDITY,
|
||||
DEFAULT_MIN_HUMIDITY,
|
||||
)
|
||||
),
|
||||
0,
|
||||
)
|
||||
max_humidity = min(
|
||||
round(attributes.get(ATTR_MAX_HUMIDITY, DEFAULT_MAX_HUMIDITY)), 100
|
||||
round(
|
||||
attributes.get(
|
||||
HumidifierEntityCapabilityAttribute.MAX_HUMIDITY,
|
||||
DEFAULT_MAX_HUMIDITY,
|
||||
)
|
||||
),
|
||||
100,
|
||||
)
|
||||
return min_humidity, max_humidity
|
||||
|
||||
@@ -315,9 +326,11 @@ class HumidifierDehumidifier(HomeAccessory):
|
||||
self.char_current_humidifier_dehumidifier.set_value(current_state)
|
||||
|
||||
# Update target humidity
|
||||
target_humidity = attributes.get(ATTR_HUMIDITY)
|
||||
target_humidity = attributes.get(HumidifierEntityStateAttribute.HUMIDITY)
|
||||
if isinstance(target_humidity, (int, float)):
|
||||
self.char_target_humidity.set_value(target_humidity)
|
||||
current_humidity = attributes.get(ATTR_CURRENT_HUMIDITY)
|
||||
current_humidity = attributes.get(
|
||||
HumidifierEntityStateAttribute.CURRENT_HUMIDITY
|
||||
)
|
||||
if isinstance(current_humidity, (int, float)):
|
||||
self.char_current_humidity.set_value(current_humidity)
|
||||
|
||||
@@ -7,19 +7,16 @@ from typing import Any, override
|
||||
from pyhap.const import CATEGORY_LIGHTBULB
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_BRIGHTNESS_PCT,
|
||||
ATTR_COLOR_MODE,
|
||||
ATTR_COLOR_TEMP_KELVIN,
|
||||
ATTR_HS_COLOR,
|
||||
ATTR_MAX_COLOR_TEMP_KELVIN,
|
||||
ATTR_MIN_COLOR_TEMP_KELVIN,
|
||||
ATTR_RGBW_COLOR,
|
||||
ATTR_RGBWW_COLOR,
|
||||
ATTR_SUPPORTED_COLOR_MODES,
|
||||
ATTR_WHITE,
|
||||
DOMAIN as LIGHT_DOMAIN,
|
||||
ColorMode,
|
||||
LightEntityCapabilityAttribute,
|
||||
LightEntityStateAttribute,
|
||||
brightness_supported,
|
||||
color_supported,
|
||||
color_temp_supported,
|
||||
@@ -75,9 +72,9 @@ class Light(HomeAccessory):
|
||||
super().__init__(*args, category=CATEGORY_LIGHTBULB)
|
||||
self._reload_on_change_attrs.extend(
|
||||
(
|
||||
ATTR_SUPPORTED_COLOR_MODES,
|
||||
ATTR_MAX_COLOR_TEMP_KELVIN,
|
||||
ATTR_MIN_COLOR_TEMP_KELVIN,
|
||||
LightEntityCapabilityAttribute.SUPPORTED_COLOR_MODES,
|
||||
LightEntityCapabilityAttribute.MAX_COLOR_TEMP_KELVIN,
|
||||
LightEntityCapabilityAttribute.MIN_COLOR_TEMP_KELVIN,
|
||||
)
|
||||
)
|
||||
self.chars = []
|
||||
@@ -88,9 +85,9 @@ class Light(HomeAccessory):
|
||||
assert state
|
||||
attributes = state.attributes
|
||||
self.color_modes = color_modes = (
|
||||
attributes.get(ATTR_SUPPORTED_COLOR_MODES) or []
|
||||
attributes.get(LightEntityCapabilityAttribute.SUPPORTED_COLOR_MODES) or []
|
||||
)
|
||||
self._previous_color_mode = attributes.get(ATTR_COLOR_MODE)
|
||||
self._previous_color_mode = attributes.get(LightEntityStateAttribute.COLOR_MODE)
|
||||
self.color_supported = color_supported(color_modes)
|
||||
self.color_temp_supported = color_temp_supported(color_modes)
|
||||
self.rgbw_supported = ColorMode.RGBW in color_modes
|
||||
@@ -121,10 +118,16 @@ class Light(HomeAccessory):
|
||||
|
||||
if CHAR_COLOR_TEMPERATURE in self.chars:
|
||||
min_mireds = color_temperature_kelvin_to_mired(
|
||||
attributes.get(ATTR_MAX_COLOR_TEMP_KELVIN, DEFAULT_MAX_COLOR_TEMP)
|
||||
attributes.get(
|
||||
LightEntityCapabilityAttribute.MAX_COLOR_TEMP_KELVIN,
|
||||
DEFAULT_MAX_COLOR_TEMP,
|
||||
)
|
||||
)
|
||||
max_mireds = color_temperature_kelvin_to_mired(
|
||||
attributes.get(ATTR_MIN_COLOR_TEMP_KELVIN, DEFAULT_MIN_COLOR_TEMP)
|
||||
attributes.get(
|
||||
LightEntityCapabilityAttribute.MIN_COLOR_TEMP_KELVIN,
|
||||
DEFAULT_MIN_COLOR_TEMP,
|
||||
)
|
||||
)
|
||||
# Ensure min is less than max
|
||||
self.min_mireds, self.max_mireds = get_min_max(min_mireds, max_mireds)
|
||||
@@ -250,7 +253,7 @@ class Light(HomeAccessory):
|
||||
# Handle State
|
||||
state = new_state.state
|
||||
attributes = new_state.attributes
|
||||
color_mode = attributes.get(ATTR_COLOR_MODE)
|
||||
color_mode = attributes.get(LightEntityStateAttribute.COLOR_MODE)
|
||||
self.char_on.set_value(int(state == STATE_ON))
|
||||
color_mode_changed = self._previous_color_mode != color_mode
|
||||
self._previous_color_mode = color_mode
|
||||
@@ -258,7 +261,8 @@ class Light(HomeAccessory):
|
||||
# Handle Brightness
|
||||
if (
|
||||
self.brightness_supported
|
||||
and (brightness := attributes.get(ATTR_BRIGHTNESS)) is not None
|
||||
and (brightness := attributes.get(LightEntityStateAttribute.BRIGHTNESS))
|
||||
is not None
|
||||
and isinstance(brightness, (int, float))
|
||||
):
|
||||
brightness = round(brightness / 255 * 100, 0)
|
||||
@@ -281,12 +285,14 @@ class Light(HomeAccessory):
|
||||
# Handle Color - color must always be set before color temperature
|
||||
# or the iOS UI will not display it correctly.
|
||||
if self.color_supported:
|
||||
if color_temp := attributes.get(ATTR_COLOR_TEMP_KELVIN):
|
||||
if color_temp := attributes.get(
|
||||
LightEntityStateAttribute.COLOR_TEMP_KELVIN
|
||||
):
|
||||
hue, saturation = color_temperature_to_hs(color_temp)
|
||||
elif color_mode == ColorMode.WHITE:
|
||||
hue, saturation = 0, 0
|
||||
elif (
|
||||
(hue_sat := attributes.get(ATTR_HS_COLOR))
|
||||
(hue_sat := attributes.get(LightEntityStateAttribute.HS_COLOR))
|
||||
and isinstance(hue_sat, (list, tuple))
|
||||
and len(hue_sat) == 2
|
||||
):
|
||||
@@ -306,7 +312,9 @@ class Light(HomeAccessory):
|
||||
if CHAR_COLOR_TEMPERATURE in self.chars:
|
||||
color_temp = None
|
||||
if self.color_temp_supported:
|
||||
color_temp_kelvin = attributes.get(ATTR_COLOR_TEMP_KELVIN)
|
||||
color_temp_kelvin = attributes.get(
|
||||
LightEntityStateAttribute.COLOR_TEMP_KELVIN
|
||||
)
|
||||
if color_temp_kelvin is not None:
|
||||
color_temp = color_temperature_kelvin_to_mired(color_temp_kelvin)
|
||||
elif color_mode == ColorMode.WHITE:
|
||||
|
||||
@@ -8,12 +8,13 @@ from pyhap.const import CATEGORY_SWITCH
|
||||
|
||||
from homeassistant.components.media_player import (
|
||||
ATTR_INPUT_SOURCE,
|
||||
ATTR_INPUT_SOURCE_LIST,
|
||||
ATTR_MEDIA_VOLUME_LEVEL,
|
||||
ATTR_MEDIA_VOLUME_MUTED,
|
||||
DOMAIN as MEDIA_PLAYER_DOMAIN,
|
||||
SERVICE_SELECT_SOURCE,
|
||||
MediaPlayerEntityCapabilityAttribute,
|
||||
MediaPlayerEntityFeature,
|
||||
MediaPlayerEntityStateAttribute,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
@@ -242,7 +243,11 @@ class MediaPlayer(HomeAccessory):
|
||||
play_stop_char.set_value(hk_state)
|
||||
|
||||
if toggle_mute_char := self.chars[FEATURE_TOGGLE_MUTE]:
|
||||
mute_state = bool(new_state.attributes.get(ATTR_MEDIA_VOLUME_MUTED))
|
||||
mute_state = bool(
|
||||
new_state.attributes.get(
|
||||
MediaPlayerEntityStateAttribute.MEDIA_VOLUME_MUTED
|
||||
)
|
||||
)
|
||||
_LOGGER.debug(
|
||||
'%s: Set current state for "toggle_mute" to %s',
|
||||
self.entity_id,
|
||||
@@ -259,8 +264,8 @@ class TelevisionMediaPlayer(RemoteInputSelectAccessory):
|
||||
"""Initialize a Television Media Player accessory object."""
|
||||
super().__init__(
|
||||
MediaPlayerEntityFeature.SELECT_SOURCE,
|
||||
ATTR_INPUT_SOURCE,
|
||||
ATTR_INPUT_SOURCE_LIST,
|
||||
MediaPlayerEntityStateAttribute.INPUT_SOURCE,
|
||||
MediaPlayerEntityCapabilityAttribute.INPUT_SOURCE_LIST,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
@@ -394,7 +399,11 @@ class TelevisionMediaPlayer(RemoteInputSelectAccessory):
|
||||
|
||||
# Set mute state
|
||||
if CHAR_VOLUME_SELECTOR in self.chars_speaker:
|
||||
current_mute_state = bool(new_state.attributes.get(ATTR_MEDIA_VOLUME_MUTED))
|
||||
current_mute_state = bool(
|
||||
new_state.attributes.get(
|
||||
MediaPlayerEntityStateAttribute.MEDIA_VOLUME_MUTED
|
||||
)
|
||||
)
|
||||
_LOGGER.debug(
|
||||
"%s: Set current mute state to %s",
|
||||
self.entity_id,
|
||||
|
||||
@@ -8,10 +8,9 @@ from pyhap.const import CATEGORY_TELEVISION
|
||||
|
||||
from homeassistant.components.remote import (
|
||||
ATTR_ACTIVITY,
|
||||
ATTR_ACTIVITY_LIST,
|
||||
ATTR_CURRENT_ACTIVITY,
|
||||
DOMAIN as REMOTE_DOMAIN,
|
||||
RemoteEntityFeature,
|
||||
RemoteEntityStateAttribute,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
@@ -224,8 +223,8 @@ class ActivityRemote(RemoteInputSelectAccessory):
|
||||
"""Initialize a Activity Remote accessory object."""
|
||||
super().__init__(
|
||||
RemoteEntityFeature.ACTIVITY,
|
||||
ATTR_CURRENT_ACTIVITY,
|
||||
ATTR_ACTIVITY_LIST,
|
||||
RemoteEntityStateAttribute.CURRENT_ACTIVITY,
|
||||
RemoteEntityStateAttribute.ACTIVITY_LIST,
|
||||
*args,
|
||||
)
|
||||
state = self.hass.states.get(self.entity_id)
|
||||
|
||||
@@ -23,13 +23,14 @@ from homeassistant.components.input_number import (
|
||||
DOMAIN as INPUT_NUMBER_DOMAIN,
|
||||
SERVICE_SET_VALUE as INPUT_NUMBER_SERVICE_SET_VALUE,
|
||||
)
|
||||
from homeassistant.components.input_select import ATTR_OPTIONS, SERVICE_SELECT_OPTION
|
||||
from homeassistant.components.input_select import SERVICE_SELECT_OPTION
|
||||
from homeassistant.components.lawn_mower import (
|
||||
DOMAIN as LAWN_MOWER_DOMAIN,
|
||||
SERVICE_DOCK,
|
||||
SERVICE_START_MOWING,
|
||||
LawnMowerActivity,
|
||||
)
|
||||
from homeassistant.components.select import SelectEntityCapabilityAttribute
|
||||
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||
from homeassistant.components.vacuum import (
|
||||
DOMAIN as VACUUM_DOMAIN,
|
||||
@@ -527,7 +528,7 @@ class SelectSwitch(HomeAccessory):
|
||||
assert state
|
||||
|
||||
self.select_chars: dict[str, Characteristic] = {}
|
||||
options = state.attributes[ATTR_OPTIONS]
|
||||
options = state.attributes[SelectEntityCapabilityAttribute.OPTIONS]
|
||||
for option in options:
|
||||
serv_option = self.add_preload_service(
|
||||
SERV_OUTLET,
|
||||
|
||||
@@ -6,16 +6,8 @@ from typing import Any, override
|
||||
from pyhap.const import CATEGORY_THERMOSTAT
|
||||
|
||||
from homeassistant.components.climate import (
|
||||
ATTR_CURRENT_HUMIDITY,
|
||||
ATTR_CURRENT_TEMPERATURE,
|
||||
ATTR_HUMIDITY,
|
||||
ATTR_HVAC_ACTION,
|
||||
ATTR_HVAC_MODE,
|
||||
ATTR_HVAC_MODES,
|
||||
ATTR_MAX_HUMIDITY,
|
||||
ATTR_MAX_TEMP,
|
||||
ATTR_MIN_HUMIDITY,
|
||||
ATTR_MIN_TEMP,
|
||||
ATTR_TARGET_TEMP_HIGH,
|
||||
ATTR_TARGET_TEMP_LOW,
|
||||
DEFAULT_MAX_HUMIDITY,
|
||||
@@ -26,17 +18,20 @@ from homeassistant.components.climate import (
|
||||
SERVICE_SET_HUMIDITY,
|
||||
SERVICE_SET_HVAC_MODE as SERVICE_SET_HVAC_MODE_THERMOSTAT,
|
||||
SERVICE_SET_TEMPERATURE as SERVICE_SET_TEMPERATURE_THERMOSTAT,
|
||||
ClimateEntityCapabilityAttribute,
|
||||
ClimateEntityFeature,
|
||||
ClimateEntityStateAttribute,
|
||||
HVACAction,
|
||||
HVACMode,
|
||||
)
|
||||
from homeassistant.components.water_heater import (
|
||||
ATTR_OPERATION_LIST,
|
||||
ATTR_OPERATION_MODE,
|
||||
DOMAIN as WATER_HEATER_DOMAIN,
|
||||
SERVICE_SET_OPERATION_MODE,
|
||||
SERVICE_SET_TEMPERATURE as SERVICE_SET_TEMPERATURE_WATER_HEATER,
|
||||
WaterHeaterCapabilityAttribute,
|
||||
WaterHeaterEntityFeature,
|
||||
WaterHeaterStateAttribute,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
@@ -162,15 +157,21 @@ class Thermostat(HomeKitClimateAccessory):
|
||||
assert state
|
||||
hc_min_temp, hc_max_temp = self.get_temperature_range(state)
|
||||
# The common climate reload attributes are added by the base class.
|
||||
self._reload_on_change_attrs.append(ATTR_MIN_HUMIDITY)
|
||||
self._reload_on_change_attrs.append(
|
||||
ClimateEntityCapabilityAttribute.MIN_HUMIDITY
|
||||
)
|
||||
|
||||
# Add additional characteristics if auto mode is supported
|
||||
self.chars: list[str] = []
|
||||
|
||||
attributes = state.attributes
|
||||
min_humidity, _ = get_min_max(
|
||||
attributes.get(ATTR_MIN_HUMIDITY, DEFAULT_MIN_HUMIDITY),
|
||||
attributes.get(ATTR_MAX_HUMIDITY, DEFAULT_MAX_HUMIDITY),
|
||||
attributes.get(
|
||||
ClimateEntityCapabilityAttribute.MIN_HUMIDITY, DEFAULT_MIN_HUMIDITY
|
||||
),
|
||||
attributes.get(
|
||||
ClimateEntityCapabilityAttribute.MAX_HUMIDITY, DEFAULT_MAX_HUMIDITY
|
||||
),
|
||||
)
|
||||
features = attributes.get(EntityStateAttribute.SUPPORTED_FEATURES, 0)
|
||||
|
||||
@@ -180,7 +181,7 @@ class Thermostat(HomeKitClimateAccessory):
|
||||
)
|
||||
|
||||
if (
|
||||
ATTR_CURRENT_HUMIDITY in attributes
|
||||
ClimateEntityStateAttribute.CURRENT_HUMIDITY in attributes
|
||||
or features & ClimateEntityFeature.TARGET_HUMIDITY
|
||||
):
|
||||
self.chars.append(CHAR_CURRENT_HUMIDITY)
|
||||
@@ -271,7 +272,7 @@ class Thermostat(HomeKitClimateAccessory):
|
||||
self.fan_chars.append(CHAR_SWING_MODE)
|
||||
|
||||
if self.fan_chars:
|
||||
if attributes.get(ATTR_HVAC_ACTION) is not None:
|
||||
if attributes.get(ClimateEntityStateAttribute.HVAC_ACTION) is not None:
|
||||
self.fan_chars.append(CHAR_CURRENT_FAN_STATE)
|
||||
self._configure_fan_service(serv_thermostat)
|
||||
|
||||
@@ -307,7 +308,9 @@ class Thermostat(HomeKitClimateAccessory):
|
||||
# and hope for the best.
|
||||
hc_target_temp = char_values.get(CHAR_TARGET_TEMPERATURE)
|
||||
hc_current_temp = temperature_attribute_to_homekit(
|
||||
state, ATTR_CURRENT_TEMPERATURE, self._unit
|
||||
state,
|
||||
ClimateEntityStateAttribute.CURRENT_TEMPERATURE,
|
||||
self._unit,
|
||||
)
|
||||
hc_fallback_order = HC_HEAT_COOL_PREFER_HEAT
|
||||
if (
|
||||
@@ -411,7 +414,10 @@ class Thermostat(HomeKitClimateAccessory):
|
||||
def _configure_hvac_modes(self, state: State) -> None:
|
||||
"""Configure target mode characteristics."""
|
||||
# This cannot be none OR an empty list
|
||||
hc_modes = state.attributes.get(ATTR_HVAC_MODES) or DEFAULT_HVAC_MODES
|
||||
hc_modes = (
|
||||
state.attributes.get(ClimateEntityCapabilityAttribute.HVAC_MODES)
|
||||
or DEFAULT_HVAC_MODES
|
||||
)
|
||||
# Determine available modes for this entity,
|
||||
# Prefer HEAT_COOL over AUTO and COOL over FAN_ONLY, DRY
|
||||
#
|
||||
@@ -466,7 +472,7 @@ class Thermostat(HomeKitClimateAccessory):
|
||||
)
|
||||
|
||||
# Set current operation mode for supported thermostats
|
||||
if hvac_action := attributes.get(ATTR_HVAC_ACTION):
|
||||
if hvac_action := attributes.get(ClimateEntityStateAttribute.HVAC_ACTION):
|
||||
self.char_current_heat_cool.set_value(
|
||||
HC_HASS_TO_HOMEKIT_ACTION.get(hvac_action, HC_HEAT_COOL_OFF)
|
||||
)
|
||||
@@ -476,14 +482,16 @@ class Thermostat(HomeKitClimateAccessory):
|
||||
# Update current humidity
|
||||
if CHAR_CURRENT_HUMIDITY in self.chars:
|
||||
assert self.char_current_humidity
|
||||
current_humdity = attributes.get(ATTR_CURRENT_HUMIDITY)
|
||||
current_humdity = attributes.get(
|
||||
ClimateEntityStateAttribute.CURRENT_HUMIDITY
|
||||
)
|
||||
if isinstance(current_humdity, (int, float)):
|
||||
self.char_current_humidity.set_value(current_humdity)
|
||||
|
||||
# Update target humidity
|
||||
if CHAR_TARGET_HUMIDITY in self.chars:
|
||||
assert self.char_target_humidity
|
||||
target_humdity = attributes.get(ATTR_HUMIDITY)
|
||||
target_humdity = attributes.get(ClimateEntityStateAttribute.TARGET_HUMIDITY)
|
||||
if isinstance(target_humdity, (int, float)):
|
||||
self.char_target_humidity.set_value(target_humdity)
|
||||
|
||||
@@ -499,7 +507,7 @@ class Thermostat(HomeKitClimateAccessory):
|
||||
|
||||
# Update target temperature
|
||||
target_temp = temperature_attribute_to_homekit(
|
||||
new_state, ATTR_TEMPERATURE, self._unit
|
||||
new_state, ClimateEntityStateAttribute.TARGET_TEMPERATURE, self._unit
|
||||
)
|
||||
if (
|
||||
target_temp is None
|
||||
@@ -509,11 +517,11 @@ class Thermostat(HomeKitClimateAccessory):
|
||||
# even if the device does not support it
|
||||
hc_hvac_mode = self.char_target_heat_cool.value
|
||||
if hc_hvac_mode == HC_HEAT_COOL_HEAT:
|
||||
temp_low = attributes.get(ATTR_TARGET_TEMP_LOW)
|
||||
temp_low = attributes.get(ClimateEntityStateAttribute.TARGET_TEMP_LOW)
|
||||
if isinstance(temp_low, (int, float)):
|
||||
target_temp = self._temperature_to_homekit(temp_low)
|
||||
elif hc_hvac_mode == HC_HEAT_COOL_COOL:
|
||||
temp_high = attributes.get(ATTR_TARGET_TEMP_HIGH)
|
||||
temp_high = attributes.get(ClimateEntityStateAttribute.TARGET_TEMP_HIGH)
|
||||
if isinstance(temp_high, (int, float)):
|
||||
target_temp = self._temperature_to_homekit(temp_high)
|
||||
if target_temp:
|
||||
@@ -537,9 +545,9 @@ class WaterHeater(HomeAccessory):
|
||||
super().__init__(*args, category=CATEGORY_THERMOSTAT)
|
||||
self._reload_on_change_attrs.extend(
|
||||
(
|
||||
ATTR_MAX_TEMP,
|
||||
ATTR_MIN_TEMP,
|
||||
ATTR_OPERATION_LIST,
|
||||
WaterHeaterCapabilityAttribute.MAX_TEMP,
|
||||
WaterHeaterCapabilityAttribute.MIN_TEMP,
|
||||
WaterHeaterCapabilityAttribute.OPERATION_LIST,
|
||||
)
|
||||
)
|
||||
self._unit = self.hass.config.units.temperature_unit
|
||||
@@ -548,7 +556,9 @@ class WaterHeater(HomeAccessory):
|
||||
min_temp, max_temp = self.get_temperature_range(state)
|
||||
|
||||
features = state.attributes.get(EntityStateAttribute.SUPPORTED_FEATURES, 0)
|
||||
operation_list = state.attributes.get(ATTR_OPERATION_LIST) or []
|
||||
operation_list = (
|
||||
state.attributes.get(WaterHeaterCapabilityAttribute.OPERATION_LIST) or []
|
||||
)
|
||||
self._supports_on_off = bool(features & WaterHeaterEntityFeature.ON_OFF)
|
||||
self._supports_operation_mode = bool(
|
||||
features & WaterHeaterEntityFeature.OPERATION_MODE
|
||||
@@ -629,11 +639,16 @@ class WaterHeater(HomeAccessory):
|
||||
state = self.hass.states.get(self.entity_id)
|
||||
if not state:
|
||||
return
|
||||
current_operation_mode = state.attributes.get(ATTR_OPERATION_MODE)
|
||||
current_operation_mode = state.attributes.get(
|
||||
WaterHeaterStateAttribute.OPERATION_MODE
|
||||
)
|
||||
if current_operation_mode and current_operation_mode != STATE_OFF:
|
||||
# Already in a non-off operation mode; do not change it.
|
||||
return
|
||||
operation_list = state.attributes.get(ATTR_OPERATION_LIST) or []
|
||||
operation_list = (
|
||||
state.attributes.get(WaterHeaterCapabilityAttribute.OPERATION_LIST)
|
||||
or []
|
||||
)
|
||||
for mode in operation_list:
|
||||
if mode != STATE_OFF:
|
||||
params[ATTR_OPERATION_MODE] = mode
|
||||
@@ -665,13 +680,13 @@ class WaterHeater(HomeAccessory):
|
||||
"""Update water_heater state after state change."""
|
||||
# Update current and target temperature
|
||||
target_temperature = temperature_attribute_to_homekit(
|
||||
new_state, ATTR_TEMPERATURE, self._unit
|
||||
new_state, WaterHeaterStateAttribute.TEMPERATURE, self._unit
|
||||
)
|
||||
if target_temperature is not None:
|
||||
self.char_target_temp.set_value(target_temperature)
|
||||
|
||||
current_temperature = temperature_attribute_to_homekit(
|
||||
new_state, ATTR_CURRENT_TEMPERATURE, self._unit
|
||||
new_state, WaterHeaterStateAttribute.CURRENT_TEMPERATURE, self._unit
|
||||
)
|
||||
if current_temperature is not None:
|
||||
self.char_current_temp.set_value(current_temperature)
|
||||
|
||||
Reference in New Issue
Block a user