From 8d49cb1195d9b3a0f1600cab2afacb4e66921d68 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Fri, 15 Aug 2025 13:57:11 +0200 Subject: [PATCH 01/33] Add pymodbus to package constraints (#150420) --- homeassistant/package_constraints.txt | 5 +++++ script/gen_requirements_all.py | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index cf29a29a246..601c0cf3238 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -216,3 +216,8 @@ rpds-py==0.24.0 # Constraint num2words to 0.5.14 as 0.5.15 and 0.5.16 were removed from PyPI num2words==0.5.14 + +# pymodbus does not follow SemVer, and it keeps getting +# downgraded or upgraded by custom components +# This ensures all use the same version +pymodbus==3.9.2 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index 779393d2c79..eb986fd8bb0 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -242,6 +242,11 @@ rpds-py==0.24.0 # Constraint num2words to 0.5.14 as 0.5.15 and 0.5.16 were removed from PyPI num2words==0.5.14 + +# pymodbus does not follow SemVer, and it keeps getting +# downgraded or upgraded by custom components +# This ensures all use the same version +pymodbus==3.9.2 """ GENERATED_MESSAGE = ( From 391c9a679ec1a0ee3580f05fd1b72aed3984e184 Mon Sep 17 00:00:00 2001 From: Arie Catsman <120491684+catsmanac@users.noreply.github.com> Date: Tue, 12 Aug 2025 11:55:43 +0200 Subject: [PATCH 02/33] Fix enphase_envoy non existing via device warning at first config. (#149010) Co-authored-by: Joost Lekkerkerker --- .../components/enphase_envoy/__init__.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/homeassistant/components/enphase_envoy/__init__.py b/homeassistant/components/enphase_envoy/__init__.py index e95ab1179e1..62d276b4224 100644 --- a/homeassistant/components/enphase_envoy/__init__.py +++ b/homeassistant/components/enphase_envoy/__init__.py @@ -2,6 +2,8 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from pyenphase import Envoy from homeassistant.const import CONF_HOST @@ -42,6 +44,21 @@ async def async_setup_entry(hass: HomeAssistant, entry: EnphaseConfigEntry) -> b }, ) + # register envoy before via_device is used + device_registry = dr.async_get(hass) + if TYPE_CHECKING: + assert envoy.serial_number + device_registry.async_get_or_create( + config_entry_id=entry.entry_id, + identifiers={(DOMAIN, envoy.serial_number)}, + manufacturer="Enphase", + name=coordinator.name, + model=envoy.envoy_model, + sw_version=str(envoy.firmware), + hw_version=envoy.part_number, + serial_number=envoy.serial_number, + ) + entry.runtime_data = coordinator await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) From b5bd61b20a1f9346f751a71bb1bb3f86b151efc2 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Mon, 11 Aug 2025 11:47:29 -0500 Subject: [PATCH 03/33] Handle non-streaming TTS case correctly (#150218) --- homeassistant/components/tts/__init__.py | 7 +- homeassistant/components/tts/entity.py | 12 +++ tests/components/tts/test_entity.py | 28 +++++++ tests/components/tts/test_init.py | 31 +++++++ .../wyoming/snapshots/test_tts.ambr | 80 ------------------- 5 files changed, 77 insertions(+), 81 deletions(-) diff --git a/homeassistant/components/tts/__init__.py b/homeassistant/components/tts/__init__.py index cf9099448df..629332d9d64 100644 --- a/homeassistant/components/tts/__init__.py +++ b/homeassistant/components/tts/__init__.py @@ -976,11 +976,15 @@ class SpeechManager: if engine_instance.name is None or engine_instance.name is UNDEFINED: raise HomeAssistantError("TTS engine name is not set.") - if isinstance(engine_instance, Provider): + if isinstance(engine_instance, Provider) or ( + not engine_instance.async_supports_streaming_input() + ): + # Non-streaming if isinstance(message_or_stream, str): message = message_or_stream else: message = "".join([chunk async for chunk in message_or_stream]) + extension, data = await engine_instance.async_internal_get_tts_audio( message, language, options ) @@ -996,6 +1000,7 @@ class SpeechManager: data_gen = make_data_generator(data) else: + # Streaming if isinstance(message_or_stream, str): async def gen_stream() -> AsyncGenerator[str]: diff --git a/homeassistant/components/tts/entity.py b/homeassistant/components/tts/entity.py index aea5be6d0da..77abaa26bab 100644 --- a/homeassistant/components/tts/entity.py +++ b/homeassistant/components/tts/entity.py @@ -191,6 +191,18 @@ class TextToSpeechEntity(RestoreEntity, cached_properties=CACHED_PROPERTIES_WITH """Load tts audio file from the engine.""" raise NotImplementedError + @final + async def async_internal_get_tts_audio( + self, message: str, language: str, options: dict[str, Any] + ) -> TtsAudioType: + """Load tts audio file from the engine and update state. + + Return a tuple of file extension and data as bytes. + """ + self.__last_tts_loaded = dt_util.utcnow().isoformat() + self.async_write_ha_state() + return await self.async_get_tts_audio(message, language, options=options) + async def async_get_tts_audio( self, message: str, language: str, options: dict[str, Any] ) -> TtsAudioType: diff --git a/tests/components/tts/test_entity.py b/tests/components/tts/test_entity.py index 8648ca95e93..308d3bb0fca 100644 --- a/tests/components/tts/test_entity.py +++ b/tests/components/tts/test_entity.py @@ -175,3 +175,31 @@ def test_streaming_supported() -> None: sync_non_streaming_entity = SyncNonStreamingEntity() assert sync_non_streaming_entity.async_supports_streaming_input() is False + + +async def test_internal_get_tts_audio_writes_state( + hass: HomeAssistant, + mock_tts_entity: MockTTSEntity, +) -> None: + """Test that only async_internal_get_tts_audio updates and writes the state.""" + + entity_id = f"{tts.DOMAIN}.{TEST_DOMAIN}" + + config_entry = await mock_config_entry_setup(hass, mock_tts_entity) + assert config_entry.state is ConfigEntryState.LOADED + state1 = hass.states.get(entity_id) + assert state1 is not None + + # State should *not* change with external method + await mock_tts_entity.async_get_tts_audio("test message", hass.config.language, {}) + state2 = hass.states.get(entity_id) + assert state2 is not None + assert state1.state == state2.state + + # State *should* change with internal method + await mock_tts_entity.async_internal_get_tts_audio( + "test message", hass.config.language, {} + ) + state3 = hass.states.get(entity_id) + assert state3 is not None + assert state1.state != state3.state diff --git a/tests/components/tts/test_init.py b/tests/components/tts/test_init.py index db42da5de0e..be155aae182 100644 --- a/tests/components/tts/test_init.py +++ b/tests/components/tts/test_init.py @@ -2032,3 +2032,34 @@ async def test_tts_cache() -> None: assert await consume_mid_data_task == b"012" with pytest.raises(ValueError): assert await consume_pre_data_loaded_task == b"012" + + +async def test_async_internal_get_tts_audio_called( + hass: HomeAssistant, + mock_tts_entity: MockTTSEntity, + hass_client: ClientSessionGenerator, +) -> None: + """Test that non-streaming entity has its async_internal_get_tts_audio method called.""" + + await mock_config_entry_setup(hass, mock_tts_entity) + + # Non-streaming + assert mock_tts_entity.async_supports_streaming_input() is False + + with patch( + "homeassistant.components.tts.entity.TextToSpeechEntity.async_internal_get_tts_audio" + ) as internal_get_tts_audio: + media_source_id = tts.generate_media_source_id( + hass, + "test message", + "tts.test", + "en_US", + cache=None, + ) + + url = await get_media_source_url(hass, media_source_id) + client = await hass_client() + await client.get(url) + + # async_internal_get_tts_audio is called + internal_get_tts_audio.assert_called_once_with("test message", "en_US", {}) diff --git a/tests/components/wyoming/snapshots/test_tts.ambr b/tests/components/wyoming/snapshots/test_tts.ambr index 67c9b24160c..53cc02eaacf 100644 --- a/tests/components/wyoming/snapshots/test_tts.ambr +++ b/tests/components/wyoming/snapshots/test_tts.ambr @@ -1,19 +1,6 @@ # serializer version: 1 # name: test_get_tts_audio list([ - dict({ - 'data': dict({ - }), - 'payload': None, - 'type': 'synthesize-start', - }), - dict({ - 'data': dict({ - 'text': 'Hello world', - }), - 'payload': None, - 'type': 'synthesize-chunk', - }), dict({ 'data': dict({ 'text': 'Hello world', @@ -21,29 +8,10 @@ 'payload': None, 'type': 'synthesize', }), - dict({ - 'data': dict({ - }), - 'payload': None, - 'type': 'synthesize-stop', - }), ]) # --- # name: test_get_tts_audio_different_formats list([ - dict({ - 'data': dict({ - }), - 'payload': None, - 'type': 'synthesize-start', - }), - dict({ - 'data': dict({ - 'text': 'Hello world', - }), - 'payload': None, - 'type': 'synthesize-chunk', - }), dict({ 'data': dict({ 'text': 'Hello world', @@ -51,29 +19,10 @@ 'payload': None, 'type': 'synthesize', }), - dict({ - 'data': dict({ - }), - 'payload': None, - 'type': 'synthesize-stop', - }), ]) # --- # name: test_get_tts_audio_different_formats.1 list([ - dict({ - 'data': dict({ - }), - 'payload': None, - 'type': 'synthesize-start', - }), - dict({ - 'data': dict({ - 'text': 'Hello world', - }), - 'payload': None, - 'type': 'synthesize-chunk', - }), dict({ 'data': dict({ 'text': 'Hello world', @@ -81,12 +30,6 @@ 'payload': None, 'type': 'synthesize', }), - dict({ - 'data': dict({ - }), - 'payload': None, - 'type': 'synthesize-stop', - }), ]) # --- # name: test_get_tts_audio_streaming @@ -128,23 +71,6 @@ # --- # name: test_voice_speaker list([ - dict({ - 'data': dict({ - 'voice': dict({ - 'name': 'voice1', - 'speaker': 'speaker1', - }), - }), - 'payload': None, - 'type': 'synthesize-start', - }), - dict({ - 'data': dict({ - 'text': 'Hello world', - }), - 'payload': None, - 'type': 'synthesize-chunk', - }), dict({ 'data': dict({ 'text': 'Hello world', @@ -156,11 +82,5 @@ 'payload': None, 'type': 'synthesize', }), - dict({ - 'data': dict({ - }), - 'payload': None, - 'type': 'synthesize-stop', - }), ]) # --- From e22e7f1bcf0c518419c67c3f2c11897bd2f60b25 Mon Sep 17 00:00:00 2001 From: HarvsG <11440490+HarvsG@users.noreply.github.com> Date: Wed, 13 Aug 2025 19:53:21 +0100 Subject: [PATCH 04/33] Pi_hole - Account for auth succeeding when it shouldn't (#150413) --- homeassistant/components/pi_hole/__init__.py | 7 +++++++ tests/components/pi_hole/__init__.py | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/pi_hole/__init__.py b/homeassistant/components/pi_hole/__init__.py index f73b7156d3e..ae51fe166c4 100644 --- a/homeassistant/components/pi_hole/__init__.py +++ b/homeassistant/components/pi_hole/__init__.py @@ -217,6 +217,13 @@ async def determine_api_version( _LOGGER.debug( "Connection to %s failed: %s, trying API version 5", holeV6.base_url, ex_v6 ) + else: + # It seems that occasionally the auth can succeed unexpectedly when there is a valid session + _LOGGER.warning( + "Authenticated with %s through v6 API, but succeeded with an incorrect password. This is a known bug", + holeV6.base_url, + ) + return 6 holeV5 = api_by_version(hass, entry, 5, password="wrong_token") try: await holeV5.get_data() diff --git a/tests/components/pi_hole/__init__.py b/tests/components/pi_hole/__init__.py index c20f22ac58d..c2edb51e066 100644 --- a/tests/components/pi_hole/__init__.py +++ b/tests/components/pi_hole/__init__.py @@ -221,12 +221,16 @@ def _create_mocked_hole( if wrong_host: raise HoleConnectionError("Cannot authenticate with Pi-hole: err") password = getattr(mocked_hole, "password", None) + if ( raise_exception or incorrect_app_password + or api_version == 5 or (api_version == 6 and password not in ["newkey", "apikey"]) ): - if api_version == 6: + if api_version == 6 and ( + incorrect_app_password or password not in ["newkey", "apikey"] + ): raise HoleError("Authentication failed: Invalid password") raise HoleConnectionError From 8b2fce9c339449f07b6a133fde8b06f0a93906e6 Mon Sep 17 00:00:00 2001 From: Manu <4445816+tr4nt0r@users.noreply.github.com> Date: Mon, 11 Aug 2025 15:51:22 +0200 Subject: [PATCH 05/33] Bump habiticalib to version 0.4.2 (#150417) --- homeassistant/components/habitica/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/habitica/manifest.json b/homeassistant/components/habitica/manifest.json index d890ed23676..e0c58383bcc 100644 --- a/homeassistant/components/habitica/manifest.json +++ b/homeassistant/components/habitica/manifest.json @@ -7,5 +7,5 @@ "iot_class": "cloud_polling", "loggers": ["habiticalib"], "quality_scale": "platinum", - "requirements": ["habiticalib==0.4.1"] + "requirements": ["habiticalib==0.4.2"] } diff --git a/requirements_all.txt b/requirements_all.txt index 65f10e07778..89373b70a07 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1127,7 +1127,7 @@ ha-philipsjs==3.2.2 ha-silabs-firmware-client==0.2.0 # homeassistant.components.habitica -habiticalib==0.4.1 +habiticalib==0.4.2 # homeassistant.components.bluetooth habluetooth==4.0.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index f92a78bf9d3..0b4c4cd0ce5 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -988,7 +988,7 @@ ha-philipsjs==3.2.2 ha-silabs-firmware-client==0.2.0 # homeassistant.components.habitica -habiticalib==0.4.1 +habiticalib==0.4.2 # homeassistant.components.bluetooth habluetooth==4.0.2 From 2ad470d1729e4ef09c864e02f4b04638aab87653 Mon Sep 17 00:00:00 2001 From: Petro31 <35082313+Petro31@users.noreply.github.com> Date: Fri, 15 Aug 2025 07:53:48 -0400 Subject: [PATCH 06/33] Fix optimistic set to false for template entities (#150421) --- homeassistant/components/template/entity.py | 10 ++-- .../components/template/template_entity.py | 2 +- .../template/test_alarm_control_panel.py | 32 +++++++++++++ tests/components/template/test_cover.py | 29 ++++++++++- tests/components/template/test_fan.py | 33 +++++++++++++ tests/components/template/test_light.py | 36 ++++++++++++++ tests/components/template/test_lock.py | 33 +++++++++++++ tests/components/template/test_number.py | 31 ++++++++++++ tests/components/template/test_select.py | 36 ++++++++++++++ tests/components/template/test_switch.py | 37 ++++++++++++++ tests/components/template/test_vacuum.py | 48 +++++++++++++++++++ 11 files changed, 322 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/template/entity.py b/homeassistant/components/template/entity.py index 03a93f50ec3..4901a7a7be8 100644 --- a/homeassistant/components/template/entity.py +++ b/homeassistant/components/template/entity.py @@ -34,16 +34,20 @@ class AbstractTemplateEntity(Entity): self._action_scripts: dict[str, Script] = {} if self._optimistic_entity: + optimistic = config.get(CONF_OPTIMISTIC) + self._template = config.get(CONF_STATE) - optimistic = self._template is None + assumed_optimistic = self._template is None if self._extra_optimistic_options: - optimistic = optimistic and all( + assumed_optimistic = assumed_optimistic and all( config.get(option) is None for option in self._extra_optimistic_options ) - self._attr_assumed_state = optimistic or config.get(CONF_OPTIMISTIC, False) + self._attr_assumed_state = optimistic or ( + optimistic is None and assumed_optimistic + ) if (object_id := config.get(CONF_OBJECT_ID)) is not None: self.entity_id = async_generate_entity_id( diff --git a/homeassistant/components/template/template_entity.py b/homeassistant/components/template/template_entity.py index 1bc49bceafd..3ba89cae1f4 100644 --- a/homeassistant/components/template/template_entity.py +++ b/homeassistant/components/template/template_entity.py @@ -102,7 +102,7 @@ TEMPLATE_ENTITY_COMMON_CONFIG_ENTRY_SCHEMA = vol.Schema( TEMPLATE_ENTITY_OPTIMISTIC_SCHEMA = { - vol.Optional(CONF_OPTIMISTIC, default=False): cv.boolean, + vol.Optional(CONF_OPTIMISTIC): cv.boolean, } diff --git a/tests/components/template/test_alarm_control_panel.py b/tests/components/template/test_alarm_control_panel.py index c1df654e328..319d02a1056 100644 --- a/tests/components/template/test_alarm_control_panel.py +++ b/tests/components/template/test_alarm_control_panel.py @@ -973,3 +973,35 @@ async def test_optimistic(hass: HomeAssistant) -> None: state = hass.states.get(TEST_ENTITY_ID) assert state.state == AlarmControlPanelState.ARMED_HOME + + +@pytest.mark.parametrize( + ("count", "panel_config"), + [ + ( + 1, + { + "name": TEST_OBJECT_ID, + "state": "{{ states('alarm_control_panel.test') }}", + **OPTIMISTIC_TEMPLATE_ALARM_CONFIG, + "optimistic": False, + }, + ) + ], +) +@pytest.mark.parametrize( + "style", + [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER], +) +@pytest.mark.usefixtures("setup_panel") +async def test_not_optimistic(hass: HomeAssistant) -> None: + """Test optimistic yaml option set to false.""" + await hass.services.async_call( + ALARM_DOMAIN, + "alarm_arm_away", + {"entity_id": TEST_ENTITY_ID, "code": "1234"}, + blocking=True, + ) + + state = hass.states.get(TEST_ENTITY_ID) + assert state.state == STATE_UNKNOWN diff --git a/tests/components/template/test_cover.py b/tests/components/template/test_cover.py index 692567c7aa8..2a83967b048 100644 --- a/tests/components/template/test_cover.py +++ b/tests/components/template/test_cover.py @@ -628,11 +628,38 @@ async def test_template_position( ], ) @pytest.mark.usefixtures("setup_cover") -async def test_template_not_optimistic(hass: HomeAssistant) -> None: +async def test_template_not_optimistic( + hass: HomeAssistant, + calls: list[ServiceCall], +) -> None: """Test the is_closed attribute.""" state = hass.states.get(TEST_ENTITY_ID) assert state.state == STATE_UNKNOWN + # Test to make sure optimistic is not set with only a position template. + await hass.services.async_call( + COVER_DOMAIN, + SERVICE_OPEN_COVER, + {ATTR_ENTITY_ID: TEST_ENTITY_ID}, + blocking=True, + ) + await hass.async_block_till_done() + + state = hass.states.get(TEST_ENTITY_ID) + assert state.state == STATE_UNKNOWN + + # Test to make sure optimistic is not set with only a position template. + await hass.services.async_call( + COVER_DOMAIN, + SERVICE_CLOSE_COVER, + {ATTR_ENTITY_ID: TEST_ENTITY_ID}, + blocking=True, + ) + await hass.async_block_till_done() + + state = hass.states.get(TEST_ENTITY_ID) + assert state.state == STATE_UNKNOWN + @pytest.mark.parametrize(("count", "state_template"), [(1, "{{ 1 == 1 }}")]) @pytest.mark.parametrize( diff --git a/tests/components/template/test_fan.py b/tests/components/template/test_fan.py index b9161edf61a..81486d75137 100644 --- a/tests/components/template/test_fan.py +++ b/tests/components/template/test_fan.py @@ -1885,6 +1885,39 @@ async def test_optimistic_option(hass: HomeAssistant) -> None: assert state.state == STATE_OFF +@pytest.mark.parametrize( + ("count", "fan_config"), + [ + ( + 1, + { + "name": TEST_OBJECT_ID, + "state": "{{ is_state('sensor.test_sensor', 'on') }}", + "turn_on": [], + "turn_off": [], + "optimistic": False, + }, + ) + ], +) +@pytest.mark.parametrize( + "style", + [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER], +) +@pytest.mark.usefixtures("setup_fan") +async def test_not_optimistic(hass: HomeAssistant) -> None: + """Test optimistic yaml option set to false.""" + await hass.services.async_call( + fan.DOMAIN, + "turn_on", + {"entity_id": TEST_ENTITY_ID}, + blocking=True, + ) + + state = hass.states.get(TEST_ENTITY_ID) + assert state.state == STATE_OFF + + async def test_setup_config_entry( hass: HomeAssistant, snapshot: SnapshotAssertion, diff --git a/tests/components/template/test_light.py b/tests/components/template/test_light.py index 0549f9981e7..e5d05cfa08f 100644 --- a/tests/components/template/test_light.py +++ b/tests/components/template/test_light.py @@ -2795,6 +2795,42 @@ async def test_optimistic_option(hass: HomeAssistant) -> None: assert state.state == STATE_OFF +@pytest.mark.parametrize( + ("count", "light_config"), + [ + ( + 1, + { + "name": TEST_OBJECT_ID, + "state": "{{ is_state('light.test_state', 'on') }}", + "turn_on": [], + "turn_off": [], + "optimistic": False, + }, + ) + ], +) +@pytest.mark.parametrize( + ("style", "expected"), + [ + (ConfigurationStyle.MODERN, STATE_OFF), + (ConfigurationStyle.TRIGGER, STATE_UNKNOWN), + ], +) +@pytest.mark.usefixtures("setup_light") +async def test_not_optimistic(hass: HomeAssistant, expected: str) -> None: + """Test optimistic yaml option set to false.""" + await hass.services.async_call( + light.DOMAIN, + "turn_on", + {"entity_id": TEST_ENTITY_ID}, + blocking=True, + ) + + state = hass.states.get(TEST_ENTITY_ID) + assert state.state == expected + + async def test_setup_config_entry( hass: HomeAssistant, snapshot: SnapshotAssertion, diff --git a/tests/components/template/test_lock.py b/tests/components/template/test_lock.py index 823306015bf..6a4164fb802 100644 --- a/tests/components/template/test_lock.py +++ b/tests/components/template/test_lock.py @@ -1190,6 +1190,39 @@ async def test_optimistic(hass: HomeAssistant) -> None: assert state.state == LockState.UNLOCKED +@pytest.mark.parametrize( + ("count", "lock_config"), + [ + ( + 1, + { + "name": TEST_OBJECT_ID, + "state": "{{ is_state('sensor.test_state', 'on') }}", + "lock": [], + "unlock": [], + "optimistic": False, + }, + ) + ], +) +@pytest.mark.parametrize( + "style", + [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER], +) +@pytest.mark.usefixtures("setup_lock") +async def test_not_optimistic(hass: HomeAssistant) -> None: + """Test optimistic yaml option set to false.""" + await hass.services.async_call( + lock.DOMAIN, + lock.SERVICE_LOCK, + {ATTR_ENTITY_ID: TEST_ENTITY_ID}, + blocking=True, + ) + + state = hass.states.get(TEST_ENTITY_ID) + assert state.state == LockState.UNLOCKED + + async def test_setup_config_entry( hass: HomeAssistant, snapshot: SnapshotAssertion, diff --git a/tests/components/template/test_number.py b/tests/components/template/test_number.py index 0ae98a23ae4..f10664e0d5f 100644 --- a/tests/components/template/test_number.py +++ b/tests/components/template/test_number.py @@ -605,6 +605,37 @@ async def test_optimistic(hass: HomeAssistant) -> None: assert float(state.state) == 2 +@pytest.mark.parametrize( + ("count", "number_config"), + [ + ( + 1, + { + "state": "{{ states('sensor.test_state') }}", + "optimistic": False, + "set_value": [], + }, + ) + ], +) +@pytest.mark.parametrize( + "style", + [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER], +) +@pytest.mark.usefixtures("setup_number") +async def test_not_optimistic(hass: HomeAssistant) -> None: + """Test optimistic yaml option set to false.""" + await hass.services.async_call( + number.DOMAIN, + number.SERVICE_SET_VALUE, + {ATTR_ENTITY_ID: _TEST_NUMBER, "value": 4}, + blocking=True, + ) + + state = hass.states.get(_TEST_NUMBER) + assert state.state == STATE_UNKNOWN + + @pytest.mark.parametrize( ("count", "number_config"), [ diff --git a/tests/components/template/test_select.py b/tests/components/template/test_select.py index f613fa865a6..eda27f18100 100644 --- a/tests/components/template/test_select.py +++ b/tests/components/template/test_select.py @@ -601,6 +601,42 @@ async def test_optimistic(hass: HomeAssistant) -> None: assert state.state == "yes" +@pytest.mark.parametrize( + ("count", "select_config"), + [ + ( + 1, + { + "state": "{{ states('select.test_state') }}", + "optimistic": False, + "options": "{{ ['test', 'yes', 'no'] }}", + "select_option": [], + }, + ) + ], +) +@pytest.mark.parametrize( + "style", + [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER], +) +@pytest.mark.usefixtures("setup_select") +async def test_not_optimistic(hass: HomeAssistant) -> None: + """Test optimistic yaml option set to false.""" + # Ensure Trigger template entities update the options list + hass.states.async_set(TEST_STATE_ENTITY_ID, "anything") + await hass.async_block_till_done() + + await hass.services.async_call( + select.DOMAIN, + select.SERVICE_SELECT_OPTION, + {ATTR_ENTITY_ID: _TEST_SELECT, "option": "test"}, + blocking=True, + ) + + state = hass.states.get(_TEST_SELECT) + assert state.state == STATE_UNKNOWN + + @pytest.mark.parametrize( ("count", "select_config"), [ diff --git a/tests/components/template/test_switch.py b/tests/components/template/test_switch.py index a32f1df4c76..5a884160fe8 100644 --- a/tests/components/template/test_switch.py +++ b/tests/components/template/test_switch.py @@ -14,6 +14,7 @@ from homeassistant.const import ( STATE_OFF, STATE_ON, STATE_UNAVAILABLE, + STATE_UNKNOWN, ) from homeassistant.core import CoreState, HomeAssistant, ServiceCall, State from homeassistant.helpers import device_registry as dr, entity_registry as er @@ -1267,3 +1268,39 @@ async def test_optimistic_option(hass: HomeAssistant) -> None: state = hass.states.get(TEST_ENTITY_ID) assert state.state == STATE_OFF + + +@pytest.mark.parametrize( + ("count", "switch_config"), + [ + ( + 1, + { + "name": TEST_OBJECT_ID, + "state": "{{ is_state('switch.test_state', 'on') }}", + "turn_on": [], + "turn_off": [], + "optimistic": False, + }, + ) + ], +) +@pytest.mark.parametrize( + ("style", "expected"), + [ + (ConfigurationStyle.MODERN, STATE_OFF), + (ConfigurationStyle.TRIGGER, STATE_UNKNOWN), + ], +) +@pytest.mark.usefixtures("setup_switch") +async def test_not_optimistic(hass: HomeAssistant, expected: str) -> None: + """Test optimistic yaml option set to false.""" + await hass.services.async_call( + switch.DOMAIN, + "turn_on", + {"entity_id": TEST_ENTITY_ID}, + blocking=True, + ) + + state = hass.states.get(TEST_ENTITY_ID) + assert state.state == expected diff --git a/tests/components/template/test_vacuum.py b/tests/components/template/test_vacuum.py index 8c2773956b2..21592718551 100644 --- a/tests/components/template/test_vacuum.py +++ b/tests/components/template/test_vacuum.py @@ -1299,6 +1299,54 @@ async def test_optimistic_option( assert state.state == VacuumActivity.DOCKED +@pytest.mark.parametrize( + ("count", "vacuum_config"), + [ + ( + 1, + { + "name": TEST_OBJECT_ID, + "state": "{{ states('sensor.test_state') }}", + "start": [], + **TEMPLATE_VACUUM_ACTIONS, + "optimistic": False, + }, + ) + ], +) +@pytest.mark.parametrize( + "style", + [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER], +) +@pytest.mark.parametrize( + "service", + [ + vacuum.SERVICE_START, + vacuum.SERVICE_PAUSE, + vacuum.SERVICE_STOP, + vacuum.SERVICE_RETURN_TO_BASE, + vacuum.SERVICE_CLEAN_SPOT, + ], +) +@pytest.mark.usefixtures("setup_vacuum") +async def test_not_optimistic( + hass: HomeAssistant, + service: str, + calls: list[ServiceCall], +) -> None: + """Test optimistic yaml option set to false.""" + await hass.services.async_call( + vacuum.DOMAIN, + service, + {"entity_id": TEST_ENTITY_ID}, + blocking=True, + ) + await hass.async_block_till_done() + + state = hass.states.get(TEST_ENTITY_ID) + assert state.state == STATE_UNKNOWN + + async def test_setup_config_entry( hass: HomeAssistant, snapshot: SnapshotAssertion, From ffbb7a2ab4e9314b854e861dbbf50046c2216938 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 12 Aug 2025 12:45:21 +0200 Subject: [PATCH 07/33] Fix error of the Powerfox integration in combination with the new Powerfox FLOW adapter (#150429) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- homeassistant/components/powerfox/__init__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/powerfox/__init__.py b/homeassistant/components/powerfox/__init__.py index 8e51985211d..c2f6830692c 100644 --- a/homeassistant/components/powerfox/__init__.py +++ b/homeassistant/components/powerfox/__init__.py @@ -4,7 +4,7 @@ from __future__ import annotations import asyncio -from powerfox import Powerfox, PowerfoxConnectionError +from powerfox import DeviceType, Powerfox, PowerfoxConnectionError from homeassistant.const import CONF_EMAIL, CONF_PASSWORD, Platform from homeassistant.core import HomeAssistant @@ -31,7 +31,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: PowerfoxConfigEntry) -> raise ConfigEntryNotReady from err coordinators: list[PowerfoxDataUpdateCoordinator] = [ - PowerfoxDataUpdateCoordinator(hass, entry, client, device) for device in devices + PowerfoxDataUpdateCoordinator(hass, entry, client, device) + for device in devices + # Filter out gas meter devices (Powerfox FLOW adapters) as they are not yet supported and cause integration failures + if device.type != DeviceType.GAS_METER ] await asyncio.gather( From c58a1881798d90c07ae02d9f34db8499315f0cc6 Mon Sep 17 00:00:00 2001 From: Kevin David Date: Mon, 11 Aug 2025 16:25:41 -0400 Subject: [PATCH 08/33] Bump python-snoo to 0.7.0 (#150434) --- homeassistant/components/snoo/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/snoo/manifest.json b/homeassistant/components/snoo/manifest.json index 2afec990e4b..b47947ab0e0 100644 --- a/homeassistant/components/snoo/manifest.json +++ b/homeassistant/components/snoo/manifest.json @@ -7,5 +7,5 @@ "iot_class": "cloud_push", "loggers": ["snoo"], "quality_scale": "bronze", - "requirements": ["python-snoo==0.6.6"] + "requirements": ["python-snoo==0.7.0"] } diff --git a/requirements_all.txt b/requirements_all.txt index 89373b70a07..3ebf11e4804 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2512,7 +2512,7 @@ python-roborock==2.18.2 python-smarttub==0.0.44 # homeassistant.components.snoo -python-snoo==0.6.6 +python-snoo==0.7.0 # homeassistant.components.songpal python-songpal==0.16.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 0b4c4cd0ce5..218ccd65cb2 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -2082,7 +2082,7 @@ python-roborock==2.18.2 python-smarttub==0.0.44 # homeassistant.components.snoo -python-snoo==0.6.6 +python-snoo==0.7.0 # homeassistant.components.songpal python-songpal==0.16.2 From bd1b81493c69fda5279c27666987bf10d88cf8cd Mon Sep 17 00:00:00 2001 From: wedsa5 Date: Tue, 12 Aug 2025 08:36:52 -0600 Subject: [PATCH 09/33] Fix brightness command not sent when in white color mode (#150439) Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> --- homeassistant/components/tuya/light.py | 7 +++- tests/components/tuya/test_light.py | 55 +++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/tuya/light.py b/homeassistant/components/tuya/light.py index 7b73e825900..1dc061520e3 100644 --- a/homeassistant/components/tuya/light.py +++ b/homeassistant/components/tuya/light.py @@ -665,8 +665,11 @@ class TuyaLightEntity(TuyaEntity, LightEntity): }, ] - elif ATTR_BRIGHTNESS in kwargs and self._brightness: - brightness = kwargs[ATTR_BRIGHTNESS] + elif self._brightness and (ATTR_BRIGHTNESS in kwargs or ATTR_WHITE in kwargs): + if ATTR_BRIGHTNESS in kwargs: + brightness = kwargs[ATTR_BRIGHTNESS] + else: + brightness = kwargs[ATTR_WHITE] # If there is a min/max value, the brightness is actually limited. # Meaning it is actually not on a 0-255 scale. diff --git a/tests/components/tuya/test_light.py b/tests/components/tuya/test_light.py index e3586613876..1c6b1138e4c 100644 --- a/tests/components/tuya/test_light.py +++ b/tests/components/tuya/test_light.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Any from unittest.mock import patch import pytest @@ -66,11 +67,58 @@ async def test_platform_setup_no_discovery( "mock_device_code", ["dj_mki13ie507rlry4r"], ) +@pytest.mark.parametrize( + ("turn_on_input", "expected_commands"), + [ + ( + { + "white": True, + }, + [ + {"code": "switch_led", "value": True}, + {"code": "work_mode", "value": "white"}, + {"code": "bright_value_v2", "value": 546}, + ], + ), + ( + { + "brightness": 150, + }, + [ + {"code": "switch_led", "value": True}, + {"code": "bright_value_v2", "value": 592}, + ], + ), + ( + { + "white": True, + "brightness": 150, + }, + [ + {"code": "switch_led", "value": True}, + {"code": "work_mode", "value": "white"}, + {"code": "bright_value_v2", "value": 592}, + ], + ), + ( + { + "white": 150, + }, + [ + {"code": "switch_led", "value": True}, + {"code": "work_mode", "value": "white"}, + {"code": "bright_value_v2", "value": 592}, + ], + ), + ], +) async def test_turn_on_white( hass: HomeAssistant, mock_manager: ManagerCompat, mock_config_entry: MockConfigEntry, mock_device: CustomerDevice, + turn_on_input: dict[str, Any], + expected_commands: list[dict[str, Any]], ) -> None: """Test turn_on service.""" entity_id = "light.garage_light" @@ -83,16 +131,13 @@ async def test_turn_on_white( SERVICE_TURN_ON, { "entity_id": entity_id, - "white": 150, + **turn_on_input, }, ) await hass.async_block_till_done() mock_manager.send_commands.assert_called_once_with( mock_device.id, - [ - {"code": "switch_led", "value": True}, - {"code": "work_mode", "value": "white"}, - ], + expected_commands, ) From 2725abf032a7103277756538c22c6ebe8e98e9cc Mon Sep 17 00:00:00 2001 From: Cyrill Raccaud Date: Tue, 12 Aug 2025 09:51:39 +0200 Subject: [PATCH 10/33] Bump cookidoo-api to 0.14.0 (#150450) --- homeassistant/components/cookidoo/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/cookidoo/manifest.json b/homeassistant/components/cookidoo/manifest.json index 5264e47a709..b4cf653f810 100644 --- a/homeassistant/components/cookidoo/manifest.json +++ b/homeassistant/components/cookidoo/manifest.json @@ -8,5 +8,5 @@ "iot_class": "cloud_polling", "loggers": ["cookidoo_api"], "quality_scale": "silver", - "requirements": ["cookidoo-api==0.12.2"] + "requirements": ["cookidoo-api==0.14.0"] } diff --git a/requirements_all.txt b/requirements_all.txt index 3ebf11e4804..b9a87f17c33 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -743,7 +743,7 @@ connect-box==0.3.1 construct==2.10.68 # homeassistant.components.cookidoo -cookidoo-api==0.12.2 +cookidoo-api==0.14.0 # homeassistant.components.backup # homeassistant.components.utility_meter diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 218ccd65cb2..3b0c118db55 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -646,7 +646,7 @@ colorthief==0.2.1 construct==2.10.68 # homeassistant.components.cookidoo -cookidoo-api==0.12.2 +cookidoo-api==0.14.0 # homeassistant.components.backup # homeassistant.components.utility_meter From fed6f19edfdbe12145e6ee142f4da9292297022c Mon Sep 17 00:00:00 2001 From: Matrix Date: Tue, 12 Aug 2025 16:42:40 +0800 Subject: [PATCH 11/33] Fix YoLink valve state when device running in class A mode (#150456) --- homeassistant/components/yolink/strings.json | 3 +++ homeassistant/components/yolink/valve.py | 14 ++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/yolink/strings.json b/homeassistant/components/yolink/strings.json index 0eb9de97469..4215031d904 100644 --- a/homeassistant/components/yolink/strings.json +++ b/homeassistant/components/yolink/strings.json @@ -47,6 +47,9 @@ "exceptions": { "invalid_config_entry": { "message": "Config entry not found or not loaded!" + }, + "valve_inoperable_currently": { + "message": "The Valve cannot be operated currently." } }, "entity": { diff --git a/homeassistant/components/yolink/valve.py b/homeassistant/components/yolink/valve.py index 06dee8af540..e63488194d0 100644 --- a/homeassistant/components/yolink/valve.py +++ b/homeassistant/components/yolink/valve.py @@ -21,6 +21,7 @@ from homeassistant.components.valve import ( ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from .const import DEV_MODEL_WATER_METER_YS5007, DOMAIN @@ -130,6 +131,13 @@ class YoLinkValveEntity(YoLinkEntity, ValveEntity): async def _async_invoke_device(self, state: str) -> None: """Call setState api to change valve state.""" + if ( + self.coordinator.device.is_support_mode_switching() + and self.coordinator.dev_net_type == ATTR_DEVICE_MODEL_A + ): + raise HomeAssistantError( + translation_domain=DOMAIN, translation_key="valve_inoperable_currently" + ) if ( self.coordinator.device.device_type == ATTR_DEVICE_MULTI_WATER_METER_CONTROLLER @@ -155,10 +163,4 @@ class YoLinkValveEntity(YoLinkEntity, ValveEntity): @property def available(self) -> bool: """Return true is device is available.""" - if ( - self.coordinator.device.is_support_mode_switching() - and self.coordinator.dev_net_type is not None - ): - # When the device operates in Class A mode, it cannot be controlled. - return self.coordinator.dev_net_type != ATTR_DEVICE_MODEL_A return super().available From 3d4d57fa3224d82ce8a1557a7714ab69a93b5c54 Mon Sep 17 00:00:00 2001 From: peteS-UK <64092177+peteS-UK@users.noreply.github.com> Date: Tue, 12 Aug 2025 10:55:21 +0100 Subject: [PATCH 12/33] Additional Fix error on startup when no Apps or Radio plugins are installed for Squeezebox (#150475) --- homeassistant/components/squeezebox/browse_media.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/squeezebox/browse_media.py b/homeassistant/components/squeezebox/browse_media.py index e14f1989cbe..cebd4fcb04f 100644 --- a/homeassistant/components/squeezebox/browse_media.py +++ b/homeassistant/components/squeezebox/browse_media.py @@ -157,7 +157,7 @@ class BrowseData: cmd = ["apps", 0, browse_limit] result = await player.async_query(*cmd) - if result["appss_loop"]: + if result and result.get("appss_loop"): for app in result["appss_loop"]: app_cmd = "app-" + app["cmd"] if app_cmd not in self.known_apps_radios: @@ -169,7 +169,7 @@ class BrowseData: ) cmd = ["radios", 0, browse_limit] result = await player.async_query(*cmd) - if result["radioss_loop"]: + if result and result.get("radioss_loop"): for app in result["radioss_loop"]: app_cmd = "app-" + app["cmd"] if app_cmd not in self.known_apps_radios: From b0ab3cddb844ee3ad30f69feb52944fb81241d9b Mon Sep 17 00:00:00 2001 From: Thomas D <11554546+thomasddn@users.noreply.github.com> Date: Fri, 15 Aug 2025 13:58:03 +0200 Subject: [PATCH 13/33] Fix re-auth flow for Volvo integration (#150478) --- homeassistant/components/volvo/config_flow.py | 6 +-- tests/components/volvo/test_config_flow.py | 49 ++++++++++++++++++- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/volvo/config_flow.py b/homeassistant/components/volvo/config_flow.py index f187d751a2d..0ae0e54077e 100644 --- a/homeassistant/components/volvo/config_flow.py +++ b/homeassistant/components/volvo/config_flow.py @@ -69,7 +69,7 @@ class VolvoOAuth2FlowHandler(AbstractOAuth2FlowHandler, domain=DOMAIN): async def async_oauth_create_entry(self, data: dict) -> ConfigFlowResult: """Create an entry for the flow.""" - self._config_data |= data + self._config_data |= (self.init_data or {}) | data return await self.async_step_api_key() async def async_step_reauth(self, _: Mapping[str, Any]) -> ConfigFlowResult: @@ -77,7 +77,7 @@ class VolvoOAuth2FlowHandler(AbstractOAuth2FlowHandler, domain=DOMAIN): return await self.async_step_reauth_confirm() async def async_step_reconfigure( - self, _: dict[str, Any] | None = None + self, data: dict[str, Any] | None = None ) -> ConfigFlowResult: """Reconfigure the entry.""" return await self.async_step_api_key() @@ -121,7 +121,7 @@ class VolvoOAuth2FlowHandler(AbstractOAuth2FlowHandler, domain=DOMAIN): if user_input is None: if self.source == SOURCE_REAUTH: - user_input = self._config_data = dict(self._get_reauth_entry().data) + user_input = self._config_data api = _create_volvo_cars_api( self.hass, self._config_data[CONF_TOKEN][CONF_ACCESS_TOKEN], diff --git a/tests/components/volvo/test_config_flow.py b/tests/components/volvo/test_config_flow.py index 91a7803dce5..3129b1383fe 100644 --- a/tests/components/volvo/test_config_flow.py +++ b/tests/components/volvo/test_config_flow.py @@ -13,7 +13,7 @@ from yarl import URL from homeassistant import config_entries from homeassistant.components.volvo.const import CONF_VIN, DOMAIN from homeassistant.config_entries import ConfigFlowResult -from homeassistant.const import CONF_API_KEY +from homeassistant.const import CONF_ACCESS_TOKEN, CONF_API_KEY, CONF_TOKEN from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType from homeassistant.helpers import config_entry_oauth2_flow @@ -117,6 +117,53 @@ async def test_reauth_flow( assert result["reason"] == "reauth_successful" +@pytest.mark.usefixtures("current_request_with_host") +async def test_reauth_no_stale_data( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + hass_client_no_auth: ClientSessionGenerator, + mock_config_flow_api: VolvoCarsApi, +) -> None: + """Test if reauthentication flow does not use stale data.""" + old_access_token = mock_config_entry.data[CONF_TOKEN][CONF_ACCESS_TOKEN] + + with patch( + "homeassistant.components.volvo.config_flow._create_volvo_cars_api", + return_value=mock_config_flow_api, + ) as mock_create_volvo_cars_api: + result = await mock_config_entry.start_reauth_flow(hass) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "reauth_confirm" + + result = await hass.config_entries.flow.async_configure(result["flow_id"], {}) + + state = config_entry_oauth2_flow._encode_jwt( + hass, + { + "flow_id": result["flow_id"], + "redirect_uri": REDIRECT_URI, + }, + ) + + client = await hass_client_no_auth() + resp = await client.get(f"/auth/external/callback?code=abcd&state={state}") + assert resp.status == 200 + assert resp.headers["content-type"] == "text/html; charset=utf-8" + + result = await _async_run_flow_to_completion( + hass, + result, + mock_config_flow_api, + has_vin_step=False, + is_reauth=True, + ) + + assert mock_create_volvo_cars_api.called + call = mock_create_volvo_cars_api.call_args_list[0] + access_token_arg = call.args[1] + assert old_access_token != access_token_arg + + async def test_reconfigure_flow( hass: HomeAssistant, mock_config_entry: MockConfigEntry, From 8f94657b0c65cbaf72dcb22bb44242a808a4c8b3 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Tue, 12 Aug 2025 13:47:11 +0200 Subject: [PATCH 14/33] Improve Z-Wave manual config flow step description (#150479) --- .../components/zwave_js/config_flow.py | 28 +++++++++++++++++-- .../components/zwave_js/strings.json | 8 ++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/zwave_js/config_flow.py b/homeassistant/components/zwave_js/config_flow.py index 6121bd00508..b72a71279ab 100644 --- a/homeassistant/components/zwave_js/config_flow.py +++ b/homeassistant/components/zwave_js/config_flow.py @@ -88,11 +88,16 @@ ADDON_USER_INPUT_MAP = { CONF_ADDON_LR_S2_AUTHENTICATED_KEY: CONF_LR_S2_AUTHENTICATED_KEY, } +EXAMPLE_SERVER_URL = "ws://localhost:3000" ON_SUPERVISOR_SCHEMA = vol.Schema({vol.Optional(CONF_USE_ADDON, default=True): bool}) MIN_MIGRATION_SDK_VERSION = AwesomeVersion("6.61") NETWORK_TYPE_NEW = "new" NETWORK_TYPE_EXISTING = "existing" +ZWAVE_JS_SERVER_INSTRUCTIONS = ( + "https://www.home-assistant.io/integrations/zwave_js/" + "#advanced-installation-instructions" +) ZWAVE_JS_UI_MIGRATION_INSTRUCTIONS = ( "https://www.home-assistant.io/integrations/zwave_js/" "#how-to-migrate-from-one-adapter-to-a-new-adapter-using-z-wave-js-ui" @@ -529,7 +534,12 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN): """Handle a manual configuration.""" if user_input is None: return self.async_show_form( - step_id="manual", data_schema=get_manual_schema({}) + step_id="manual", + data_schema=get_manual_schema({}), + description_placeholders={ + "example_server_url": EXAMPLE_SERVER_URL, + "server_instructions": ZWAVE_JS_SERVER_INSTRUCTIONS, + }, ) errors = {} @@ -558,7 +568,13 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN): return self._async_create_entry_from_vars() return self.async_show_form( - step_id="manual", data_schema=get_manual_schema(user_input), errors=errors + step_id="manual", + data_schema=get_manual_schema(user_input), + description_placeholders={ + "example_server_url": EXAMPLE_SERVER_URL, + "server_instructions": ZWAVE_JS_SERVER_INSTRUCTIONS, + }, + errors=errors, ) async def async_step_hassio( @@ -1016,6 +1032,10 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN): return self.async_show_form( step_id="manual_reconfigure", data_schema=get_manual_schema({CONF_URL: config_entry.data[CONF_URL]}), + description_placeholders={ + "example_server_url": EXAMPLE_SERVER_URL, + "server_instructions": ZWAVE_JS_SERVER_INSTRUCTIONS, + }, ) errors = {} @@ -1046,6 +1066,10 @@ class ZWaveJSConfigFlow(ConfigFlow, domain=DOMAIN): return self.async_show_form( step_id="manual_reconfigure", data_schema=get_manual_schema(user_input), + description_placeholders={ + "example_server_url": EXAMPLE_SERVER_URL, + "server_instructions": ZWAVE_JS_SERVER_INSTRUCTIONS, + }, errors=errors, ) diff --git a/homeassistant/components/zwave_js/strings.json b/homeassistant/components/zwave_js/strings.json index 8ac356a40b0..0ff635578ea 100644 --- a/homeassistant/components/zwave_js/strings.json +++ b/homeassistant/components/zwave_js/strings.json @@ -82,13 +82,21 @@ "title": "Installing add-on" }, "manual": { + "description": "The Z-Wave integration requires a running Z-Wave Server. If you don't already have that set up, please read the [instructions]({server_instructions}) in our documentation.\n\nWhen you have a Z-Wave Server running, enter its URL below to allow the integration to connect.", "data": { "url": "[%key:common::config_flow::data::url%]" + }, + "data_description": { + "url": "The URL of the Z-Wave Server WebSocket API, e.g. {example_server_url}" } }, "manual_reconfigure": { + "description": "[%key:component::zwave_js::config::step::manual::description%]", "data": { "url": "[%key:common::config_flow::data::url%]" + }, + "data_description": { + "url": "[%key:component::zwave_js::config::step::manual::data_description::url%]" } }, "on_supervisor": { From d9ebda49104c1ceb3f20beb3bb5eff7c3b983e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85ke=20Strandberg?= Date: Tue, 12 Aug 2025 13:58:38 +0200 Subject: [PATCH 15/33] Add missing boost2 code for Miele hobs (#150481) --- homeassistant/components/miele/const.py | 1 + homeassistant/components/miele/icons.json | 3 +- homeassistant/components/miele/strings.json | 3 +- .../miele/snapshots/test_sensor.ambr | 28 +++++++++++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/miele/const.py b/homeassistant/components/miele/const.py index e8b626af785..3b5b13398a5 100644 --- a/homeassistant/components/miele/const.py +++ b/homeassistant/components/miele/const.py @@ -1330,4 +1330,5 @@ class PlatePowerStep(MieleEnum): plate_step_17 = 17 plate_step_18 = 18 plate_step_boost = 117, 118, 218 + plate_step_boost_2 = 217 missing2none = -9999 diff --git a/homeassistant/components/miele/icons.json b/homeassistant/components/miele/icons.json index 77d94c49ffa..a5dbeb4ec2d 100644 --- a/homeassistant/components/miele/icons.json +++ b/homeassistant/components/miele/icons.json @@ -76,7 +76,8 @@ "plate_step_16": "mdi:circle-slice-7", "plate_step_17": "mdi:circle-slice-8", "plate_step_18": "mdi:circle-slice-8", - "plate_step_boost": "mdi:alpha-b-circle-outline" + "plate_step_boost": "mdi:alpha-b-circle-outline", + "plate_step_boost_2": "mdi:alpha-b-circle" } }, "program_type": { diff --git a/homeassistant/components/miele/strings.json b/homeassistant/components/miele/strings.json index 90689a3d9cc..cb9861e0246 100644 --- a/homeassistant/components/miele/strings.json +++ b/homeassistant/components/miele/strings.json @@ -223,7 +223,8 @@ "plate_step_16": "8\u2022", "plate_step_17": "9", "plate_step_18": "9\u2022", - "plate_step_boost": "Boost" + "plate_step_boost": "Boost", + "plate_step_boost_2": "Boost 2" } }, "drying_step": { diff --git a/tests/components/miele/snapshots/test_sensor.ambr b/tests/components/miele/snapshots/test_sensor.ambr index 2805a683077..5d941550f41 100644 --- a/tests/components/miele/snapshots/test_sensor.ambr +++ b/tests/components/miele/snapshots/test_sensor.ambr @@ -208,6 +208,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -266,6 +267,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -304,6 +306,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -362,6 +365,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -400,6 +404,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -458,6 +463,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -496,6 +502,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -554,6 +561,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -592,6 +600,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -650,6 +659,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -688,6 +698,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -746,6 +757,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -784,6 +796,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -842,6 +855,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -880,6 +894,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -938,6 +953,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -976,6 +992,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -1034,6 +1051,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -1457,6 +1475,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -1515,6 +1534,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -1553,6 +1573,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -1611,6 +1632,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -1649,6 +1671,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -1707,6 +1730,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -1745,6 +1769,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -1803,6 +1828,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -1841,6 +1867,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), @@ -1899,6 +1926,7 @@ 'plate_step_8', 'plate_step_9', 'plate_step_boost', + 'plate_step_boost_2', 'plate_step_warming', ]), }), From 82390f6f7b887582449763ee8950389f1d01ac40 Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 12 Aug 2025 19:27:27 +0200 Subject: [PATCH 16/33] Bump airOS to 0.2.8 (#150504) --- homeassistant/components/airos/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/airos/snapshots/test_diagnostics.ambr | 5 +++++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/airos/manifest.json b/homeassistant/components/airos/manifest.json index 84003c19b89..58f76abe577 100644 --- a/homeassistant/components/airos/manifest.json +++ b/homeassistant/components/airos/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/airos", "iot_class": "local_polling", "quality_scale": "bronze", - "requirements": ["airos==0.2.7"] + "requirements": ["airos==0.2.8"] } diff --git a/requirements_all.txt b/requirements_all.txt index b9a87f17c33..abc74ea56c0 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -453,7 +453,7 @@ airgradient==0.9.2 airly==1.1.0 # homeassistant.components.airos -airos==0.2.7 +airos==0.2.8 # homeassistant.components.airthings_ble airthings-ble==0.9.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 3b0c118db55..f9999b96e9a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -435,7 +435,7 @@ airgradient==0.9.2 airly==1.1.0 # homeassistant.components.airos -airos==0.2.7 +airos==0.2.8 # homeassistant.components.airthings_ble airthings-ble==0.9.2 diff --git a/tests/components/airos/snapshots/test_diagnostics.ambr b/tests/components/airos/snapshots/test_diagnostics.ambr index 574dbf68949..e3c4d74a5fd 100644 --- a/tests/components/airos/snapshots/test_diagnostics.ambr +++ b/tests/components/airos/snapshots/test_diagnostics.ambr @@ -28,9 +28,14 @@ }), 'genuine': '/images/genuine.png', 'gps': dict({ + 'alt': None, + 'dim': None, + 'dop': None, 'fix': 0, 'lat': '**REDACTED**', 'lon': '**REDACTED**', + 'sats': None, + 'time_synced': None, }), 'host': dict({ 'cpuload': 10.10101, From 56b4c554def44ba8cf83c8d7567f961bf450cda1 Mon Sep 17 00:00:00 2001 From: Shay Levy Date: Tue, 12 Aug 2025 22:53:56 +0300 Subject: [PATCH 17/33] Bump aiowebostv to 0.7.5 (#150514) --- homeassistant/components/webostv/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/webostv/manifest.json b/homeassistant/components/webostv/manifest.json index c3c3e9a564f..f8201fe3bef 100644 --- a/homeassistant/components/webostv/manifest.json +++ b/homeassistant/components/webostv/manifest.json @@ -6,7 +6,7 @@ "documentation": "https://www.home-assistant.io/integrations/webostv", "iot_class": "local_push", "loggers": ["aiowebostv"], - "requirements": ["aiowebostv==0.7.4"], + "requirements": ["aiowebostv==0.7.5"], "ssdp": [ { "st": "urn:lge-com:service:webos-second-screen:1" diff --git a/requirements_all.txt b/requirements_all.txt index abc74ea56c0..fb47514510d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -438,7 +438,7 @@ aiowatttime==0.1.1 aiowebdav2==0.4.6 # homeassistant.components.webostv -aiowebostv==0.7.4 +aiowebostv==0.7.5 # homeassistant.components.withings aiowithings==3.1.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index f9999b96e9a..700b04e8521 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -420,7 +420,7 @@ aiowatttime==0.1.1 aiowebdav2==0.4.6 # homeassistant.components.webostv -aiowebostv==0.7.4 +aiowebostv==0.7.5 # homeassistant.components.withings aiowithings==3.1.6 From 82907e5b882e39cfebd0430eb7ac231aa2dd5bb5 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 12 Aug 2025 13:49:43 -0500 Subject: [PATCH 18/33] Bump bleak-retry-connector to 4.0.1 (#150515) --- homeassistant/components/bluetooth/manifest.json | 2 +- homeassistant/package_constraints.txt | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/bluetooth/manifest.json b/homeassistant/components/bluetooth/manifest.json index ce5d98f8edb..d0d766862ff 100644 --- a/homeassistant/components/bluetooth/manifest.json +++ b/homeassistant/components/bluetooth/manifest.json @@ -16,7 +16,7 @@ "quality_scale": "internal", "requirements": [ "bleak==1.0.1", - "bleak-retry-connector==4.0.0", + "bleak-retry-connector==4.0.1", "bluetooth-adapters==2.0.0", "bluetooth-auto-recovery==1.5.2", "bluetooth-data-tools==1.28.2", diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 601c0cf3238..d1f5ec4fefc 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -20,7 +20,7 @@ audioop-lts==0.2.1 av==13.1.0 awesomeversion==25.5.0 bcrypt==4.3.0 -bleak-retry-connector==4.0.0 +bleak-retry-connector==4.0.1 bleak==1.0.1 bluetooth-adapters==2.0.0 bluetooth-auto-recovery==1.5.2 diff --git a/requirements_all.txt b/requirements_all.txt index fb47514510d..3a54f4e7fea 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -625,7 +625,7 @@ bizkaibus==0.1.1 bleak-esphome==3.1.0 # homeassistant.components.bluetooth -bleak-retry-connector==4.0.0 +bleak-retry-connector==4.0.1 # homeassistant.components.bluetooth bleak==1.0.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 700b04e8521..615ee3a6c8a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -559,7 +559,7 @@ bimmer-connected[china]==0.17.2 bleak-esphome==3.1.0 # homeassistant.components.bluetooth -bleak-retry-connector==4.0.0 +bleak-retry-connector==4.0.1 # homeassistant.components.bluetooth bleak==1.0.1 From 4213427b9c7f13f9925ba73f64ae925d6f7ed3b1 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 12 Aug 2025 15:07:25 -0500 Subject: [PATCH 19/33] Bump aiodhcpwatcher to 1.2.1 (#150519) --- homeassistant/components/dhcp/manifest.json | 2 +- homeassistant/package_constraints.txt | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/dhcp/manifest.json b/homeassistant/components/dhcp/manifest.json index 599e5ecae5b..32abe0684f7 100644 --- a/homeassistant/components/dhcp/manifest.json +++ b/homeassistant/components/dhcp/manifest.json @@ -15,7 +15,7 @@ ], "quality_scale": "internal", "requirements": [ - "aiodhcpwatcher==1.2.0", + "aiodhcpwatcher==1.2.1", "aiodiscover==2.7.1", "cached-ipaddress==0.10.0" ] diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index d1f5ec4fefc..750d024a872 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -1,6 +1,6 @@ # Automatically generated by gen_requirements_all.py, do not edit -aiodhcpwatcher==1.2.0 +aiodhcpwatcher==1.2.1 aiodiscover==2.7.1 aiodns==3.5.0 aiohasupervisor==0.3.1 diff --git a/requirements_all.txt b/requirements_all.txt index 3a54f4e7fea..95c150298df 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -220,7 +220,7 @@ aiobotocore==2.21.1 aiocomelit==0.12.3 # homeassistant.components.dhcp -aiodhcpwatcher==1.2.0 +aiodhcpwatcher==1.2.1 # homeassistant.components.dhcp aiodiscover==2.7.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 615ee3a6c8a..40f25865012 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -208,7 +208,7 @@ aiobotocore==2.21.1 aiocomelit==0.12.3 # homeassistant.components.dhcp -aiodhcpwatcher==1.2.0 +aiodhcpwatcher==1.2.1 # homeassistant.components.dhcp aiodiscover==2.7.1 From 776726a053c1134cce85430eb936daad343cd9c8 Mon Sep 17 00:00:00 2001 From: Luke Lashley Date: Wed, 13 Aug 2025 05:38:18 -0400 Subject: [PATCH 20/33] Bump python-snoo to 0.8.1 (#150530) --- homeassistant/components/snoo/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/snoo/const.py | 7 ++++++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/snoo/manifest.json b/homeassistant/components/snoo/manifest.json index b47947ab0e0..0db11c5b086 100644 --- a/homeassistant/components/snoo/manifest.json +++ b/homeassistant/components/snoo/manifest.json @@ -7,5 +7,5 @@ "iot_class": "cloud_push", "loggers": ["snoo"], "quality_scale": "bronze", - "requirements": ["python-snoo==0.7.0"] + "requirements": ["python-snoo==0.8.1"] } diff --git a/requirements_all.txt b/requirements_all.txt index 95c150298df..9cafe19d1e3 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2512,7 +2512,7 @@ python-roborock==2.18.2 python-smarttub==0.0.44 # homeassistant.components.snoo -python-snoo==0.7.0 +python-snoo==0.8.1 # homeassistant.components.songpal python-songpal==0.16.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 40f25865012..7648e174fb0 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -2082,7 +2082,7 @@ python-roborock==2.18.2 python-smarttub==0.0.44 # homeassistant.components.snoo -python-snoo==0.7.0 +python-snoo==0.8.1 # homeassistant.components.songpal python-songpal==0.16.2 diff --git a/tests/components/snoo/const.py b/tests/components/snoo/const.py index 2657048afb8..cd52679caf9 100644 --- a/tests/components/snoo/const.py +++ b/tests/components/snoo/const.py @@ -31,7 +31,12 @@ MOCK_SNOO_DEVICES = [ "name": "Test Snoo", "presence": {}, "presenceIoT": {}, - "awsIoT": {}, + "awsIoT": { + "awsRegion": "us-east-1", + "clientEndpoint": "z00023244d7fia4appr4b-ats.iot.us-east-1.amazonaws.com", + "clientReady": True, + "thingName": "676cbbe74529f85038b2e623_5831231335004715141_prod", + }, "lastSSID": {}, "provisionedAt": "random_time", } From 312d8aaff53cc38546a6bc43da764a423bfebc40 Mon Sep 17 00:00:00 2001 From: Robert Resch Date: Wed, 13 Aug 2025 09:45:54 +0200 Subject: [PATCH 21/33] Bump uv to 0.8.9 (#150542) --- Dockerfile | 2 +- homeassistant/package_constraints.txt | 2 +- pyproject.toml | 2 +- requirements.txt | 2 +- script/hassfest/docker/Dockerfile | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 549837ddef0..4a004c046e3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,7 +31,7 @@ RUN \ && go2rtc --version # Install uv -RUN pip3 install uv==0.7.1 +RUN pip3 install uv==0.8.9 WORKDIR /usr/src diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 750d024a872..8b38b7e6692 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -68,7 +68,7 @@ standard-telnetlib==3.13.0 typing-extensions>=4.14.0,<5.0 ulid-transform==1.4.0 urllib3>=2.0 -uv==0.7.1 +uv==0.8.9 voluptuous-openapi==0.1.0 voluptuous-serialize==2.6.0 voluptuous==0.15.2 diff --git a/pyproject.toml b/pyproject.toml index e869bd0d0cb..5757c965515 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ dependencies = [ "typing-extensions>=4.14.0,<5.0", "ulid-transform==1.4.0", "urllib3>=2.0", - "uv==0.7.1", + "uv==0.8.9", "voluptuous==0.15.2", "voluptuous-serialize==2.6.0", "voluptuous-openapi==0.1.0", diff --git a/requirements.txt b/requirements.txt index 7bd900a69ed..f0f49ac519b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -46,7 +46,7 @@ standard-telnetlib==3.13.0 typing-extensions>=4.14.0,<5.0 ulid-transform==1.4.0 urllib3>=2.0 -uv==0.7.1 +uv==0.8.9 voluptuous==0.15.2 voluptuous-serialize==2.6.0 voluptuous-openapi==0.1.0 diff --git a/script/hassfest/docker/Dockerfile b/script/hassfest/docker/Dockerfile index 5776f6dfe12..4b8aafce70f 100644 --- a/script/hassfest/docker/Dockerfile +++ b/script/hassfest/docker/Dockerfile @@ -14,7 +14,7 @@ WORKDIR "/github/workspace" COPY . /usr/src/homeassistant # Uv is only needed during build -RUN --mount=from=ghcr.io/astral-sh/uv:0.7.1,source=/uv,target=/bin/uv \ +RUN --mount=from=ghcr.io/astral-sh/uv:0.8.9,source=/uv,target=/bin/uv \ # Uv creates a lock file in /tmp --mount=type=tmpfs,target=/tmp \ # Required for PyTurboJPEG From 5a49007b86908cb71828545251f980faeeec1086 Mon Sep 17 00:00:00 2001 From: Luke Lashley Date: Wed, 13 Aug 2025 18:12:18 -0400 Subject: [PATCH 22/33] Bump python-snoo to 0.8.2 (#150569) --- homeassistant/components/snoo/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/snoo/manifest.json b/homeassistant/components/snoo/manifest.json index 0db11c5b086..0a2301c6fd8 100644 --- a/homeassistant/components/snoo/manifest.json +++ b/homeassistant/components/snoo/manifest.json @@ -7,5 +7,5 @@ "iot_class": "cloud_push", "loggers": ["snoo"], "quality_scale": "bronze", - "requirements": ["python-snoo==0.8.1"] + "requirements": ["python-snoo==0.8.2"] } diff --git a/requirements_all.txt b/requirements_all.txt index 9cafe19d1e3..75e8b9c36d4 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2512,7 +2512,7 @@ python-roborock==2.18.2 python-smarttub==0.0.44 # homeassistant.components.snoo -python-snoo==0.8.1 +python-snoo==0.8.2 # homeassistant.components.songpal python-songpal==0.16.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 7648e174fb0..4276eb83b31 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -2082,7 +2082,7 @@ python-roborock==2.18.2 python-smarttub==0.0.44 # homeassistant.components.snoo -python-snoo==0.8.1 +python-snoo==0.8.2 # homeassistant.components.songpal python-songpal==0.16.2 From 1643d5df67cdd59a4bac24b7f336cdd7829081c4 Mon Sep 17 00:00:00 2001 From: Luke Lashley Date: Wed, 13 Aug 2025 18:11:52 -0400 Subject: [PATCH 23/33] Change Snoo to use MQTT instead of PubNub (#150570) --- homeassistant/components/snoo/coordinator.py | 2 +- tests/components/snoo/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/snoo/coordinator.py b/homeassistant/components/snoo/coordinator.py index 8ce0db34621..43e717c2bc7 100644 --- a/homeassistant/components/snoo/coordinator.py +++ b/homeassistant/components/snoo/coordinator.py @@ -40,7 +40,7 @@ class SnooCoordinator(DataUpdateCoordinator[SnooData]): async def setup(self) -> None: """Perform setup needed on every coordintaor creation.""" - await self.snoo.subscribe(self.device, self.async_set_updated_data) + self.snoo.start_subscribe(self.device, self.async_set_updated_data) # After we subscribe - get the status so that we have something to start with. # We only need to do this once. The device will auto update otherwise. await self.snoo.get_status(self.device) diff --git a/tests/components/snoo/__init__.py b/tests/components/snoo/__init__.py index b4692e6f08b..417eb438143 100644 --- a/tests/components/snoo/__init__.py +++ b/tests/components/snoo/__init__.py @@ -48,7 +48,7 @@ def find_update_callback( mock: AsyncMock, serial_number: str ) -> Callable[[SnooData], Awaitable[None]]: """Find the update callback for a specific identifier.""" - for call in mock.subscribe.call_args_list: + for call in mock.start_subscribe.call_args_list: if call[0][0].serialNumber == serial_number: return call[0][1] pytest.fail(f"Callback for identifier {serial_number} not found") From 2c1407f159140da76a385f1facca4ec499b9d7dd Mon Sep 17 00:00:00 2001 From: Joakim Plate Date: Thu, 14 Aug 2025 09:30:47 +0200 Subject: [PATCH 24/33] Make sure we update the api version in philips_js discovery (#150604) --- homeassistant/components/philips_js/config_flow.py | 2 +- tests/components/philips_js/test_config_flow.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/philips_js/config_flow.py b/homeassistant/components/philips_js/config_flow.py index a568d51e5ea..779452b284b 100644 --- a/homeassistant/components/philips_js/config_flow.py +++ b/homeassistant/components/philips_js/config_flow.py @@ -82,7 +82,7 @@ class PhilipsJSConfigFlow(ConfigFlow, domain=DOMAIN): ) await hub.getSystem() - await hub.setTransport(hub.secured_transport) + await hub.setTransport(hub.secured_transport, hub.api_version_detected) if not hub.system or not hub.name: raise ConnectionFailure("System data or name is empty") diff --git a/tests/components/philips_js/test_config_flow.py b/tests/components/philips_js/test_config_flow.py index c4dcc44e619..77227fd0f63 100644 --- a/tests/components/philips_js/test_config_flow.py +++ b/tests/components/philips_js/test_config_flow.py @@ -125,7 +125,7 @@ async def test_pairing(hass: HomeAssistant, mock_tv_pairable, mock_setup_entry) assert result["type"] is FlowResultType.FORM assert result["errors"] == {} - mock_tv.setTransport.assert_called_with(True) + mock_tv.setTransport.assert_called_with(True, ANY) mock_tv.pairRequest.assert_called() result = await hass.config_entries.flow.async_configure( @@ -204,7 +204,7 @@ async def test_pair_grant_failed( assert result["type"] is FlowResultType.FORM assert result["errors"] == {} - mock_tv.setTransport.assert_called_with(True) + mock_tv.setTransport.assert_called_with(True, ANY) mock_tv.pairRequest.assert_called() # Test with invalid pin @@ -266,6 +266,7 @@ async def test_zeroconf_discovery( """Test we can setup from zeroconf discovery.""" mock_tv_pairable.secured_transport = secured_transport + mock_tv_pairable.api_version_detected = 6 result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_ZEROCONF}, @@ -291,7 +292,7 @@ async def test_zeroconf_discovery( assert result["type"] is FlowResultType.FORM assert result["errors"] == {} - mock_tv_pairable.setTransport.assert_called_with(secured_transport) + mock_tv_pairable.setTransport.assert_called_with(secured_transport, 6) mock_tv_pairable.pairRequest.assert_called() From 87a2d3e6d97605b46dfcf92aabce4949f0b5153c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85ke=20Strandberg?= Date: Thu, 7 Aug 2025 20:48:25 +0200 Subject: [PATCH 25/33] Bump pymiele to 0.5.3 (#150216) --- homeassistant/components/miele/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/miele/manifest.json b/homeassistant/components/miele/manifest.json index c9a20e977f9..b8ca0535c3e 100644 --- a/homeassistant/components/miele/manifest.json +++ b/homeassistant/components/miele/manifest.json @@ -8,7 +8,7 @@ "iot_class": "cloud_push", "loggers": ["pymiele"], "quality_scale": "bronze", - "requirements": ["pymiele==0.5.2"], + "requirements": ["pymiele==0.5.3"], "single_config_entry": true, "zeroconf": ["_mieleathome._tcp.local."] } diff --git a/requirements_all.txt b/requirements_all.txt index 75e8b9c36d4..6731133ffff 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2146,7 +2146,7 @@ pymeteoclimatic==0.1.0 pymicro-vad==1.0.1 # homeassistant.components.miele -pymiele==0.5.2 +pymiele==0.5.3 # homeassistant.components.xiaomi_tv pymitv==1.4.3 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 4276eb83b31..8ba254d87f4 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1788,7 +1788,7 @@ pymeteoclimatic==0.1.0 pymicro-vad==1.0.1 # homeassistant.components.miele -pymiele==0.5.2 +pymiele==0.5.3 # homeassistant.components.mochad pymochad==0.2.0 From 1a0b61c98ecac2d554b228afe7506c71f12980d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85ke=20Strandberg?= Date: Wed, 13 Aug 2025 23:42:47 +0200 Subject: [PATCH 26/33] Bump pymiele to 0.5.4 (#150605) --- homeassistant/components/miele/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/miele/manifest.json b/homeassistant/components/miele/manifest.json index b8ca0535c3e..63ace343dc8 100644 --- a/homeassistant/components/miele/manifest.json +++ b/homeassistant/components/miele/manifest.json @@ -8,7 +8,7 @@ "iot_class": "cloud_push", "loggers": ["pymiele"], "quality_scale": "bronze", - "requirements": ["pymiele==0.5.3"], + "requirements": ["pymiele==0.5.4"], "single_config_entry": true, "zeroconf": ["_mieleathome._tcp.local."] } diff --git a/requirements_all.txt b/requirements_all.txt index 6731133ffff..6080bb406c5 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2146,7 +2146,7 @@ pymeteoclimatic==0.1.0 pymicro-vad==1.0.1 # homeassistant.components.miele -pymiele==0.5.3 +pymiele==0.5.4 # homeassistant.components.xiaomi_tv pymitv==1.4.3 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 8ba254d87f4..7a610241b68 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1788,7 +1788,7 @@ pymeteoclimatic==0.1.0 pymicro-vad==1.0.1 # homeassistant.components.miele -pymiele==0.5.3 +pymiele==0.5.4 # homeassistant.components.mochad pymochad==0.2.0 From 0b337c7e2aef1a1f3719ae3467b7a057a1723f65 Mon Sep 17 00:00:00 2001 From: Tom Date: Thu, 14 Aug 2025 13:43:32 +0200 Subject: [PATCH 27/33] Bump airOS to 0.2.11 (#150627) --- homeassistant/components/airos/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/airos/manifest.json b/homeassistant/components/airos/manifest.json index 58f76abe577..16855d805c0 100644 --- a/homeassistant/components/airos/manifest.json +++ b/homeassistant/components/airos/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/airos", "iot_class": "local_polling", "quality_scale": "bronze", - "requirements": ["airos==0.2.8"] + "requirements": ["airos==0.2.11"] } diff --git a/requirements_all.txt b/requirements_all.txt index 6080bb406c5..271c0bc0407 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -453,7 +453,7 @@ airgradient==0.9.2 airly==1.1.0 # homeassistant.components.airos -airos==0.2.8 +airos==0.2.11 # homeassistant.components.airthings_ble airthings-ble==0.9.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 7a610241b68..ebc36f7557c 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -435,7 +435,7 @@ airgradient==0.9.2 airly==1.1.0 # homeassistant.components.airos -airos==0.2.8 +airos==0.2.11 # homeassistant.components.airthings_ble airthings-ble==0.9.2 From 837472c12d77f7a7ea29c1fc4c527ad4656874db Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 14 Aug 2025 16:16:04 -0500 Subject: [PATCH 28/33] Bump uiprotect to 7.21.1 (#150657) --- homeassistant/components/unifiprotect/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/unifiprotect/manifest.json b/homeassistant/components/unifiprotect/manifest.json index 8eee080abb4..50bdeec8572 100644 --- a/homeassistant/components/unifiprotect/manifest.json +++ b/homeassistant/components/unifiprotect/manifest.json @@ -40,7 +40,7 @@ "integration_type": "hub", "iot_class": "local_push", "loggers": ["uiprotect", "unifi_discovery"], - "requirements": ["uiprotect==7.20.0", "unifi-discovery==1.2.0"], + "requirements": ["uiprotect==7.21.1", "unifi-discovery==1.2.0"], "ssdp": [ { "manufacturer": "Ubiquiti Networks", diff --git a/requirements_all.txt b/requirements_all.txt index 271c0bc0407..556fde7839f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -3004,7 +3004,7 @@ typedmonarchmoney==0.4.4 uasiren==0.0.1 # homeassistant.components.unifiprotect -uiprotect==7.20.0 +uiprotect==7.21.1 # homeassistant.components.landisgyr_heat_meter ultraheat-api==0.5.7 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index ebc36f7557c..4277378445a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -2478,7 +2478,7 @@ typedmonarchmoney==0.4.4 uasiren==0.0.1 # homeassistant.components.unifiprotect -uiprotect==7.20.0 +uiprotect==7.21.1 # homeassistant.components.landisgyr_heat_meter ultraheat-api==0.5.7 From 83226ed01537319a05ed366ae8f6bb6d475c7e36 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 14 Aug 2025 22:49:31 -0500 Subject: [PATCH 29/33] Bump onvif-zeep-async to 4.0.3 (#150663) --- homeassistant/components/onvif/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/onvif/manifest.json b/homeassistant/components/onvif/manifest.json index fbb1454ec2a..787040d5691 100644 --- a/homeassistant/components/onvif/manifest.json +++ b/homeassistant/components/onvif/manifest.json @@ -8,5 +8,5 @@ "documentation": "https://www.home-assistant.io/integrations/onvif", "iot_class": "local_push", "loggers": ["onvif", "wsdiscovery", "zeep"], - "requirements": ["onvif-zeep-async==4.0.2", "WSDiscovery==2.1.2"] + "requirements": ["onvif-zeep-async==4.0.3", "WSDiscovery==2.1.2"] } diff --git a/requirements_all.txt b/requirements_all.txt index 556fde7839f..0af34048860 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1594,7 +1594,7 @@ ondilo==0.5.0 onedrive-personal-sdk==0.0.14 # homeassistant.components.onvif -onvif-zeep-async==4.0.2 +onvif-zeep-async==4.0.3 # homeassistant.components.opengarage open-garage==0.2.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 4277378445a..43a8d1135bd 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1362,7 +1362,7 @@ ondilo==0.5.0 onedrive-personal-sdk==0.0.14 # homeassistant.components.onvif -onvif-zeep-async==4.0.2 +onvif-zeep-async==4.0.3 # homeassistant.components.opengarage open-garage==0.2.0 From 06472224028470d5d7708de9227b7954f0e657ca Mon Sep 17 00:00:00 2001 From: Luke Lashley Date: Thu, 14 Aug 2025 23:46:59 -0400 Subject: [PATCH 30/33] Bump python-snoo to 0.8.3 (#150670) --- homeassistant/components/snoo/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/snoo/manifest.json b/homeassistant/components/snoo/manifest.json index 0a2301c6fd8..5a162a9e9d3 100644 --- a/homeassistant/components/snoo/manifest.json +++ b/homeassistant/components/snoo/manifest.json @@ -7,5 +7,5 @@ "iot_class": "cloud_push", "loggers": ["snoo"], "quality_scale": "bronze", - "requirements": ["python-snoo==0.8.2"] + "requirements": ["python-snoo==0.8.3"] } diff --git a/requirements_all.txt b/requirements_all.txt index 0af34048860..8543aaedeaa 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2512,7 +2512,7 @@ python-roborock==2.18.2 python-smarttub==0.0.44 # homeassistant.components.snoo -python-snoo==0.8.2 +python-snoo==0.8.3 # homeassistant.components.songpal python-songpal==0.16.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 43a8d1135bd..718f7794e56 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -2082,7 +2082,7 @@ python-roborock==2.18.2 python-smarttub==0.0.44 # homeassistant.components.snoo -python-snoo==0.8.2 +python-snoo==0.8.3 # homeassistant.components.songpal python-songpal==0.16.2 From 22e19e768ec51adec7b1ea8f371a8efcc1533453 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Fri, 15 Aug 2025 13:59:35 +0200 Subject: [PATCH 31/33] Fix missing labels for subdiv in workday (#150684) --- homeassistant/components/workday/config_flow.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/homeassistant/components/workday/config_flow.py b/homeassistant/components/workday/config_flow.py index 1d91e1d5ae3..20d9040e527 100644 --- a/homeassistant/components/workday/config_flow.py +++ b/homeassistant/components/workday/config_flow.py @@ -86,6 +86,9 @@ def add_province_and_language_to_schema( SelectOptionDict(value=k, label=", ".join(v)) for k, v in subdiv_aliases.items() ] + for option in province_options: + if option["label"] == "": + option["label"] = option["value"] else: province_options = provinces province_schema = { From c551a133c17eaaf09b15a28364391ba840bd64c4 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Fri, 15 Aug 2025 15:51:48 +0200 Subject: [PATCH 32/33] Improve handling decode errors in rest (#150699) --- homeassistant/components/rest/data.py | 16 ++++++-- tests/components/rest/test_data.py | 57 +++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/rest/data.py b/homeassistant/components/rest/data.py index 3341f296fb9..2964ef73d46 100644 --- a/homeassistant/components/rest/data.py +++ b/homeassistant/components/rest/data.py @@ -45,6 +45,7 @@ class RestData: self._method = method self._resource = resource self._encoding = encoding + self._force_use_set_encoding = False # Convert auth tuple to aiohttp.BasicAuth if needed if isinstance(auth, tuple) and len(auth) == 2: @@ -152,10 +153,19 @@ class RestData: # Read the response # Only use configured encoding if no charset in Content-Type header # If charset is present in Content-Type, let aiohttp use it - if response.charset: + if self._force_use_set_encoding is False and response.charset: # Let aiohttp use the charset from Content-Type header - self.data = await response.text() - else: + try: + self.data = await response.text() + except UnicodeDecodeError as ex: + self._force_use_set_encoding = True + _LOGGER.debug( + "Response charset came back as %s but could not be decoded, continue with configured encoding %s. %s", + response.charset, + self._encoding, + ex, + ) + if self._force_use_set_encoding or not response.charset: # Use configured encoding as fallback self.data = await response.text(encoding=self._encoding) self.headers = response.headers diff --git a/tests/components/rest/test_data.py b/tests/components/rest/test_data.py index 4d6bc000fac..01581c8ac68 100644 --- a/tests/components/rest/test_data.py +++ b/tests/components/rest/test_data.py @@ -1,13 +1,17 @@ """Test REST data module logging improvements.""" +from datetime import timedelta import logging +from unittest.mock import patch +from freezegun.api import FrozenDateTimeFactory import pytest from homeassistant.components.rest import DOMAIN from homeassistant.core import HomeAssistant from homeassistant.setup import async_setup_component +from tests.common import async_fire_time_changed from tests.test_util.aiohttp import AiohttpClientMocker @@ -89,6 +93,59 @@ async def test_rest_data_no_warning_on_200_with_wrong_content_type( ) +async def test_rest_data_with_incorrect_charset_in_header( + hass: HomeAssistant, + aioclient_mock: AiohttpClientMocker, + caplog: pytest.LogCaptureFixture, + freezer: FrozenDateTimeFactory, +) -> None: + """Test that we can handle sites which provides an incorrect charset.""" + aioclient_mock.get( + "http://example.com/api", + status=200, + text="

Some html

", + headers={"Content-Type": "text/html; charset=utf-8"}, + ) + + assert await async_setup_component( + hass, + DOMAIN, + { + DOMAIN: { + "resource": "http://example.com/api", + "method": "GET", + "encoding": "windows-1250", + "sensor": [ + { + "name": "test_sensor", + "value_template": "{{ value }}", + } + ], + } + }, + ) + await hass.async_block_till_done() + + with patch( + "tests.test_util.aiohttp.AiohttpClientMockResponse.text", + side_effect=UnicodeDecodeError("utf-8", b"", 1, 0, ""), + ): + freezer.tick(timedelta(minutes=1)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + log_text = "Response charset came back as utf-8 but could not be decoded, continue with configured encoding windows-1250." + assert log_text in caplog.text + + caplog.clear() + freezer.tick(timedelta(minutes=1)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + # Only log once as we only try once with automatic decoding + assert log_text not in caplog.text + + async def test_rest_data_no_warning_on_success_json( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, From 0bcc0f3fb93aeec096f4228e0afe25785b279cfd Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Fri, 15 Aug 2025 15:22:30 +0000 Subject: [PATCH 33/33] Bump version to 2025.8.2 --- homeassistant/const.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index c02668d6899..9ddbac360af 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -25,7 +25,7 @@ if TYPE_CHECKING: APPLICATION_NAME: Final = "HomeAssistant" MAJOR_VERSION: Final = 2025 MINOR_VERSION: Final = 8 -PATCH_VERSION: Final = "1" +PATCH_VERSION: Final = "2" __short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__: Final = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 13, 2) diff --git a/pyproject.toml b/pyproject.toml index 5757c965515..ced768ae63e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "homeassistant" -version = "2025.8.1" +version = "2025.8.2" license = "Apache-2.0" license-files = ["LICENSE*", "homeassistant/backports/LICENSE*"] description = "Open-source home automation platform running on Python 3."