From 44eeb2eb5efd7b60aa6cf4b7be6972f3eb2e7eb2 Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Wed, 27 Mar 2024 11:19:20 +0100 Subject: [PATCH] Allow Humidifier.current_humidity to be a float (#111297) * Allow Humidifier.current_humidity to be a float * Code review * Allow climate humidity values to be float * Update demo integration --- homeassistant/components/climate/__init__.py | 14 ++++++------ .../components/comelit/humidifier.py | 4 ++-- homeassistant/components/demo/climate.py | 12 +++++----- homeassistant/components/demo/humidifier.py | 8 +++---- .../components/generic_hygrostat/__init__.py | 6 ++--- .../generic_hygrostat/humidifier.py | 22 +++++++++---------- .../components/homekit_controller/climate.py | 4 ++-- .../components/humidifier/__init__.py | 20 ++++++++--------- pylint/plugins/hass_enforce_type_hints.py | 14 ++++++------ tests/components/demo/test_climate.py | 10 ++++----- tests/components/demo/test_humidifier.py | 10 ++++----- .../google_assistant/test_google_assistant.py | 8 +++---- 12 files changed, 66 insertions(+), 66 deletions(-) diff --git a/homeassistant/components/climate/__init__.py b/homeassistant/components/climate/__init__.py index d96dd163f41..87327945c68 100644 --- a/homeassistant/components/climate/__init__.py +++ b/homeassistant/components/climate/__init__.py @@ -292,9 +292,9 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_): _attr_hvac_mode: HVACMode | None _attr_hvac_modes: list[HVACMode] _attr_is_aux_heat: bool | None - _attr_max_humidity: int = DEFAULT_MAX_HUMIDITY + _attr_max_humidity: float = DEFAULT_MAX_HUMIDITY _attr_max_temp: float - _attr_min_humidity: int = DEFAULT_MIN_HUMIDITY + _attr_min_humidity: float = DEFAULT_MIN_HUMIDITY _attr_min_temp: float _attr_precision: float _attr_preset_mode: str | None @@ -302,7 +302,7 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_): _attr_supported_features: ClimateEntityFeature = ClimateEntityFeature(0) _attr_swing_mode: str | None _attr_swing_modes: list[str] | None - _attr_target_humidity: int | None = None + _attr_target_humidity: float | None = None _attr_target_temperature_high: float | None _attr_target_temperature_low: float | None _attr_target_temperature_step: float | None = None @@ -517,12 +517,12 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_): return self._attr_temperature_unit @cached_property - def current_humidity(self) -> int | None: + def current_humidity(self) -> float | None: """Return the current humidity.""" return self._attr_current_humidity @cached_property - def target_humidity(self) -> int | None: + def target_humidity(self) -> float | None: """Return the humidity we try to reach.""" return self._attr_target_humidity @@ -826,12 +826,12 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_): return self._attr_max_temp @cached_property - def min_humidity(self) -> int: + def min_humidity(self) -> float: """Return the minimum humidity.""" return self._attr_min_humidity @cached_property - def max_humidity(self) -> int: + def max_humidity(self) -> float: """Return the maximum humidity.""" return self._attr_max_humidity diff --git a/homeassistant/components/comelit/humidifier.py b/homeassistant/components/comelit/humidifier.py index 97cd3beb168..e7857535c78 100644 --- a/homeassistant/components/comelit/humidifier.py +++ b/homeassistant/components/comelit/humidifier.py @@ -148,12 +148,12 @@ class ComelitHumidifierEntity(CoordinatorEntity[ComelitSerialBridge], Humidifier return self._humidifier[3] == HumidifierComelitMode.AUTO @property - def target_humidity(self) -> int: + def target_humidity(self) -> float: """Set target humidity.""" return self._humidifier[4] / 10 @property - def current_humidity(self) -> int: + def current_humidity(self) -> float: """Return current humidity.""" return self._humidifier[0] / 10 diff --git a/homeassistant/components/demo/climate.py b/homeassistant/components/demo/climate.py index a7caede9b2d..ff0ed5746ca 100644 --- a/homeassistant/components/demo/climate.py +++ b/homeassistant/components/demo/climate.py @@ -57,8 +57,8 @@ async def async_setup_entry( preset=None, current_temperature=22, fan_mode="on_high", - target_humidity=67, - current_humidity=54, + target_humidity=67.4, + current_humidity=54.2, swing_mode="off", hvac_mode=HVACMode.COOL, hvac_action=HVACAction.COOLING, @@ -106,8 +106,8 @@ class DemoClimate(ClimateEntity): preset: str | None, current_temperature: float, fan_mode: str | None, - target_humidity: int | None, - current_humidity: int | None, + target_humidity: float | None, + current_humidity: float | None, swing_mode: str | None, hvac_mode: HVACMode, hvac_action: HVACAction | None, @@ -188,12 +188,12 @@ class DemoClimate(ClimateEntity): return self._target_temperature_low @property - def current_humidity(self) -> int | None: + def current_humidity(self) -> float | None: """Return the current humidity.""" return self._current_humidity @property - def target_humidity(self) -> int | None: + def target_humidity(self) -> float | None: """Return the humidity we try to reach.""" return self._target_humidity diff --git a/homeassistant/components/demo/humidifier.py b/homeassistant/components/demo/humidifier.py index 37c4f189f96..7245d96eaf0 100644 --- a/homeassistant/components/demo/humidifier.py +++ b/homeassistant/components/demo/humidifier.py @@ -36,8 +36,8 @@ async def async_setup_entry( DemoHumidifier( name="Dehumidifier", mode=None, - target_humidity=54, - current_humidity=59, + target_humidity=54.2, + current_humidity=59.4, action=HumidifierAction.DRYING, device_class=HumidifierDeviceClass.DEHUMIDIFIER, ), @@ -60,8 +60,8 @@ class DemoHumidifier(HumidifierEntity): self, name: str, mode: str | None, - target_humidity: int, - current_humidity: int | None = None, + target_humidity: float, + current_humidity: float | None = None, available_modes: list[str] | None = None, is_on: bool = True, action: HumidifierAction | None = None, diff --git a/homeassistant/components/generic_hygrostat/__init__.py b/homeassistant/components/generic_hygrostat/__init__.py index 3109e9bb563..467a9f0e0c5 100644 --- a/homeassistant/components/generic_hygrostat/__init__.py +++ b/homeassistant/components/generic_hygrostat/__init__.py @@ -36,13 +36,13 @@ HYGROSTAT_SCHEMA = vol.Schema( vol.Optional(CONF_DEVICE_CLASS): vol.In( [HumidifierDeviceClass.HUMIDIFIER, HumidifierDeviceClass.DEHUMIDIFIER] ), - vol.Optional(CONF_MAX_HUMIDITY): vol.Coerce(int), + vol.Optional(CONF_MAX_HUMIDITY): vol.Coerce(float), vol.Optional(CONF_MIN_DUR): vol.All(cv.time_period, cv.positive_timedelta), - vol.Optional(CONF_MIN_HUMIDITY): vol.Coerce(int), + vol.Optional(CONF_MIN_HUMIDITY): vol.Coerce(float), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_DRY_TOLERANCE, default=DEFAULT_TOLERANCE): vol.Coerce(float), vol.Optional(CONF_WET_TOLERANCE, default=DEFAULT_TOLERANCE): vol.Coerce(float), - vol.Optional(CONF_TARGET_HUMIDITY): vol.Coerce(int), + vol.Optional(CONF_TARGET_HUMIDITY): vol.Coerce(float), vol.Optional(CONF_KEEP_ALIVE): vol.All(cv.time_period, cv.positive_timedelta), vol.Optional(CONF_INITIAL_STATE): cv.boolean, vol.Optional(CONF_AWAY_HUMIDITY): vol.Coerce(int), diff --git a/homeassistant/components/generic_hygrostat/humidifier.py b/homeassistant/components/generic_hygrostat/humidifier.py index fea00d5cc8b..02641acccae 100644 --- a/homeassistant/components/generic_hygrostat/humidifier.py +++ b/homeassistant/components/generic_hygrostat/humidifier.py @@ -85,9 +85,9 @@ async def async_setup_platform( name: str = config[CONF_NAME] switch_entity_id: str = config[CONF_HUMIDIFIER] sensor_entity_id: str = config[CONF_SENSOR] - min_humidity: int | None = config.get(CONF_MIN_HUMIDITY) - max_humidity: int | None = config.get(CONF_MAX_HUMIDITY) - target_humidity: int | None = config.get(CONF_TARGET_HUMIDITY) + min_humidity: float | None = config.get(CONF_MIN_HUMIDITY) + max_humidity: float | None = config.get(CONF_MAX_HUMIDITY) + target_humidity: float | None = config.get(CONF_TARGET_HUMIDITY) device_class: HumidifierDeviceClass | None = config.get(CONF_DEVICE_CLASS) min_cycle_duration: timedelta | None = config.get(CONF_MIN_DUR) sensor_stale_duration: timedelta | None = config.get(CONF_STALE_DURATION) @@ -133,9 +133,9 @@ class GenericHygrostat(HumidifierEntity, RestoreEntity): name: str, switch_entity_id: str, sensor_entity_id: str, - min_humidity: int | None, - max_humidity: int | None, - target_humidity: int | None, + min_humidity: float | None, + max_humidity: float | None, + target_humidity: float | None, device_class: HumidifierDeviceClass | None, min_cycle_duration: timedelta | None, dry_tolerance: float, @@ -264,12 +264,12 @@ class GenericHygrostat(HumidifierEntity, RestoreEntity): return self._state @property - def current_humidity(self) -> int | None: + def current_humidity(self) -> float | None: """Return the measured humidity.""" - return int(self._cur_humidity) if self._cur_humidity is not None else None + return self._cur_humidity @property - def target_humidity(self) -> int | None: + def target_humidity(self) -> float | None: """Return the humidity we try to reach.""" return self._target_humidity @@ -326,7 +326,7 @@ class GenericHygrostat(HumidifierEntity, RestoreEntity): self.async_write_ha_state() @property - def min_humidity(self) -> int: + def min_humidity(self) -> float: """Return the minimum humidity.""" if self._min_humidity: return self._min_humidity @@ -335,7 +335,7 @@ class GenericHygrostat(HumidifierEntity, RestoreEntity): return super().min_humidity @property - def max_humidity(self) -> int: + def max_humidity(self) -> float: """Return the maximum humidity.""" if self._max_humidity: return self._max_humidity diff --git a/homeassistant/components/homekit_controller/climate.py b/homeassistant/components/homekit_controller/climate.py index dda181b31ff..49ae3bb4a42 100644 --- a/homeassistant/components/homekit_controller/climate.py +++ b/homeassistant/components/homekit_controller/climate.py @@ -637,7 +637,7 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity): return self.service.value(CharacteristicsTypes.RELATIVE_HUMIDITY_TARGET) @property - def min_humidity(self) -> int: + def min_humidity(self) -> float: """Return the minimum humidity.""" min_humidity = self.service[ CharacteristicsTypes.RELATIVE_HUMIDITY_TARGET @@ -647,7 +647,7 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity): return super().min_humidity @property - def max_humidity(self) -> int: + def max_humidity(self) -> float: """Return the maximum humidity.""" max_humidity = self.service[ CharacteristicsTypes.RELATIVE_HUMIDITY_TARGET diff --git a/homeassistant/components/humidifier/__init__.py b/homeassistant/components/humidifier/__init__.py index bf3ce16fa92..1af294d8640 100644 --- a/homeassistant/components/humidifier/__init__.py +++ b/homeassistant/components/humidifier/__init__.py @@ -165,18 +165,18 @@ class HumidifierEntity(ToggleEntity, cached_properties=CACHED_PROPERTIES_WITH_AT entity_description: HumidifierEntityDescription _attr_action: HumidifierAction | None = None _attr_available_modes: list[str] | None - _attr_current_humidity: int | None = None + _attr_current_humidity: float | None = None _attr_device_class: HumidifierDeviceClass | None - _attr_max_humidity: int = DEFAULT_MAX_HUMIDITY - _attr_min_humidity: int = DEFAULT_MIN_HUMIDITY + _attr_max_humidity: float = DEFAULT_MAX_HUMIDITY + _attr_min_humidity: float = DEFAULT_MIN_HUMIDITY _attr_mode: str | None _attr_supported_features: HumidifierEntityFeature = HumidifierEntityFeature(0) - _attr_target_humidity: int | None = None + _attr_target_humidity: float | None = None @property def capability_attributes(self) -> dict[str, Any]: """Return capability attributes.""" - data: dict[str, int | list[str] | None] = { + data: dict[str, Any] = { ATTR_MIN_HUMIDITY: self.min_humidity, ATTR_MAX_HUMIDITY: self.max_humidity, } @@ -199,7 +199,7 @@ class HumidifierEntity(ToggleEntity, cached_properties=CACHED_PROPERTIES_WITH_AT @property def state_attributes(self) -> dict[str, Any]: """Return the optional state attributes.""" - data: dict[str, int | str | None] = {} + data: dict[str, Any] = {} if self.action is not None: data[ATTR_ACTION] = self.action if self.is_on else HumidifierAction.OFF @@ -221,12 +221,12 @@ class HumidifierEntity(ToggleEntity, cached_properties=CACHED_PROPERTIES_WITH_AT return self._attr_action @cached_property - def current_humidity(self) -> int | None: + def current_humidity(self) -> float | None: """Return the current humidity.""" return self._attr_current_humidity @cached_property - def target_humidity(self) -> int | None: + def target_humidity(self) -> float | None: """Return the humidity we try to reach.""" return self._attr_target_humidity @@ -263,12 +263,12 @@ class HumidifierEntity(ToggleEntity, cached_properties=CACHED_PROPERTIES_WITH_AT await self.hass.async_add_executor_job(self.set_mode, mode) @cached_property - def min_humidity(self) -> int: + def min_humidity(self) -> float: """Return the minimum humidity.""" return self._attr_min_humidity @cached_property - def max_humidity(self) -> int: + def max_humidity(self) -> float: """Return the maximum humidity.""" return self._attr_max_humidity diff --git a/pylint/plugins/hass_enforce_type_hints.py b/pylint/plugins/hass_enforce_type_hints.py index 678cbb7a22a..4799a3a56fa 100644 --- a/pylint/plugins/hass_enforce_type_hints.py +++ b/pylint/plugins/hass_enforce_type_hints.py @@ -1025,11 +1025,11 @@ _INHERITANCE_MATCH: dict[str, list[ClassTypeHintMatch]] = { ), TypeHintMatch( function_name="current_humidity", - return_type=["int", None], + return_type=["float", None], ), TypeHintMatch( function_name="target_humidity", - return_type=["int", None], + return_type=["float", None], ), TypeHintMatch( function_name="hvac_mode", @@ -1171,11 +1171,11 @@ _INHERITANCE_MATCH: dict[str, list[ClassTypeHintMatch]] = { ), TypeHintMatch( function_name="min_humidity", - return_type="int", + return_type="float", ), TypeHintMatch( function_name="max_humidity", - return_type="int", + return_type="float", ), ], ), @@ -1549,11 +1549,11 @@ _INHERITANCE_MATCH: dict[str, list[ClassTypeHintMatch]] = { ), TypeHintMatch( function_name="min_humidity", - return_type=["int"], + return_type=["float"], ), TypeHintMatch( function_name="max_humidity", - return_type=["int"], + return_type=["float"], ), TypeHintMatch( function_name="mode", @@ -1565,7 +1565,7 @@ _INHERITANCE_MATCH: dict[str, list[ClassTypeHintMatch]] = { ), TypeHintMatch( function_name="target_humidity", - return_type=["int", None], + return_type=["float", None], ), TypeHintMatch( function_name="set_humidity", diff --git a/tests/components/demo/test_climate.py b/tests/components/demo/test_climate.py index dc2bdc3c720..ff18f9e6a4e 100644 --- a/tests/components/demo/test_climate.py +++ b/tests/components/demo/test_climate.py @@ -74,8 +74,8 @@ def test_setup_params(hass: HomeAssistant) -> None: assert state.attributes.get(ATTR_TEMPERATURE) == 21 assert state.attributes.get(ATTR_CURRENT_TEMPERATURE) == 22 assert state.attributes.get(ATTR_FAN_MODE) == "on_high" - assert state.attributes.get(ATTR_HUMIDITY) == 67 - assert state.attributes.get(ATTR_CURRENT_HUMIDITY) == 54 + assert state.attributes.get(ATTR_HUMIDITY) == 67.4 + assert state.attributes.get(ATTR_CURRENT_HUMIDITY) == 54.2 assert state.attributes.get(ATTR_SWING_MODE) == "off" assert state.attributes.get(ATTR_HVAC_MODES) == [ HVACMode.OFF, @@ -219,7 +219,7 @@ async def test_set_temp_with_hvac_mode(hass: HomeAssistant) -> None: async def test_set_target_humidity_bad_attr(hass: HomeAssistant) -> None: """Test setting the target humidity without required attribute.""" state = hass.states.get(ENTITY_CLIMATE) - assert state.attributes.get(ATTR_HUMIDITY) == 67 + assert state.attributes.get(ATTR_HUMIDITY) == 67.4 with pytest.raises(vol.Invalid): await hass.services.async_call( @@ -230,13 +230,13 @@ async def test_set_target_humidity_bad_attr(hass: HomeAssistant) -> None: ) state = hass.states.get(ENTITY_CLIMATE) - assert state.attributes.get(ATTR_HUMIDITY) == 67 + assert state.attributes.get(ATTR_HUMIDITY) == 67.4 async def test_set_target_humidity(hass: HomeAssistant) -> None: """Test the setting of the target humidity.""" state = hass.states.get(ENTITY_CLIMATE) - assert state.attributes.get(ATTR_HUMIDITY) == 67 + assert state.attributes.get(ATTR_HUMIDITY) == 67.4 await hass.services.async_call( DOMAIN, diff --git a/tests/components/demo/test_humidifier.py b/tests/components/demo/test_humidifier.py index 97647f0a90f..0f0fcaf43fd 100644 --- a/tests/components/demo/test_humidifier.py +++ b/tests/components/demo/test_humidifier.py @@ -57,8 +57,8 @@ def test_setup_params(hass: HomeAssistant) -> None: """Test the initial parameters.""" state = hass.states.get(ENTITY_DEHUMIDIFIER) assert state.state == STATE_ON - assert state.attributes.get(ATTR_HUMIDITY) == 54 - assert state.attributes.get(ATTR_CURRENT_HUMIDITY) == 59 + assert state.attributes.get(ATTR_HUMIDITY) == 54.2 + assert state.attributes.get(ATTR_CURRENT_HUMIDITY) == 59.4 assert state.attributes.get(ATTR_ACTION) == "drying" @@ -72,7 +72,7 @@ def test_default_setup_params(hass: HomeAssistant) -> None: async def test_set_target_humidity_bad_attr(hass: HomeAssistant) -> None: """Test setting the target humidity without required attribute.""" state = hass.states.get(ENTITY_DEHUMIDIFIER) - assert state.attributes.get(ATTR_HUMIDITY) == 54 + assert state.attributes.get(ATTR_HUMIDITY) == 54.2 with pytest.raises(vol.Invalid): await hass.services.async_call( @@ -84,13 +84,13 @@ async def test_set_target_humidity_bad_attr(hass: HomeAssistant) -> None: await hass.async_block_till_done() state = hass.states.get(ENTITY_DEHUMIDIFIER) - assert state.attributes.get(ATTR_HUMIDITY) == 54 + assert state.attributes.get(ATTR_HUMIDITY) == 54.2 async def test_set_target_humidity(hass: HomeAssistant) -> None: """Test the setting of the target humidity.""" state = hass.states.get(ENTITY_DEHUMIDIFIER) - assert state.attributes.get(ATTR_HUMIDITY) == 54 + assert state.attributes.get(ATTR_HUMIDITY) == 54.2 await hass.services.async_call( DOMAIN, diff --git a/tests/components/google_assistant/test_google_assistant.py b/tests/components/google_assistant/test_google_assistant.py index 94936eaaf3d..4198e648b53 100644 --- a/tests/components/google_assistant/test_google_assistant.py +++ b/tests/components/google_assistant/test_google_assistant.py @@ -254,7 +254,7 @@ async def test_query_climate_request( "thermostatTemperatureSetpoint": 21, "thermostatTemperatureAmbient": 22, "thermostatMode": "cool", - "thermostatHumidityAmbient": 54, + "thermostatHumidityAmbient": 54.2, "currentFanSpeedSetting": "on_high", } @@ -318,7 +318,7 @@ async def test_query_climate_request_f( "thermostatTemperatureSetpoint": -6.1, "thermostatTemperatureAmbient": -5.6, "thermostatMode": "cool", - "thermostatHumidityAmbient": 54, + "thermostatHumidityAmbient": 54.2, "currentFanSpeedSetting": "on_high", } hass_fixture.config.units.temperature_unit = UnitOfTemperature.CELSIUS @@ -363,8 +363,8 @@ async def test_query_humidifier_request( assert devices["humidifier.dehumidifier"] == { "on": True, "online": True, - "humiditySetpointPercent": 54, - "humidityAmbientPercent": 59, + "humiditySetpointPercent": 54.2, + "humidityAmbientPercent": 59.4, } assert devices["humidifier.hygrostat"] == { "on": True,