From da0a65be87d9138132c95efdf7258b7f086041ec Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Thu, 23 Jul 2026 17:15:51 -0400 Subject: [PATCH 1/8] Fix for ProxmoxVE compoenent failing authentication with realms containg upper case letters. (#176742) --- .../components/proxmoxve/__init__.py | 4 +- homeassistant/components/proxmoxve/common.py | 2 +- tests/components/proxmoxve/conftest.py | 8 +- .../components/proxmoxve/test_config_flow.py | 6 +- tests/components/proxmoxve/test_init.py | 208 ++++++++++++------ 5 files changed, 149 insertions(+), 79 deletions(-) diff --git a/homeassistant/components/proxmoxve/__init__.py b/homeassistant/components/proxmoxve/__init__.py index 2f969fae5bed..666394485c39 100644 --- a/homeassistant/components/proxmoxve/__init__.py +++ b/homeassistant/components/proxmoxve/__init__.py @@ -193,9 +193,9 @@ async def async_migrate_entry(hass: HomeAssistant, entry: ProxmoxConfigEntry) -> if "@" in data.get(CONF_USERNAME, ""): username, realm = data[CONF_USERNAME].split("@", 1) data[CONF_USERNAME] = username - data[CONF_REALM] = realm.lower() + data[CONF_REALM] = realm - realm = data[CONF_REALM].lower() + realm = data[CONF_REALM] # If the realm is one of the base providers, # set the provider to match the realm. diff --git a/homeassistant/components/proxmoxve/common.py b/homeassistant/components/proxmoxve/common.py index 73dee442372a..a32a38734e9d 100644 --- a/homeassistant/components/proxmoxve/common.py +++ b/homeassistant/components/proxmoxve/common.py @@ -16,7 +16,7 @@ def sanitize_config_entry(input_data: Mapping[str, Any]) -> dict[str, Any]: realm = provider.lower() if provider == AUTH_OTHER: - realm = data[CONF_REALM].lower() + realm = data[CONF_REALM] data[CONF_REALM] = realm data[CONF_USERNAME] = f"{username}@{realm}" diff --git a/tests/components/proxmoxve/conftest.py b/tests/components/proxmoxve/conftest.py index 1decc74ac46c..9ac0b312633b 100644 --- a/tests/components/proxmoxve/conftest.py +++ b/tests/components/proxmoxve/conftest.py @@ -64,8 +64,8 @@ MOCK_TEST_TOKEN_CONFIG = { MOCK_TEST_OTHER_CONFIG = { **MOCK_TEST_CONFIG, CONF_AUTH_METHOD: "other", - CONF_REALM: "test_realm", - CONF_USERNAME: "test_user@test_realm", + CONF_REALM: "Test_Realm", + CONF_USERNAME: "test_user@Test_Realm", } MOCK_TEST_TOKEN_OTHER_CONFIG = { @@ -74,8 +74,8 @@ MOCK_TEST_TOKEN_OTHER_CONFIG = { CONF_TOKEN_ID: "test_token_id", CONF_TOKEN_SECRET: "test_token_secret", CONF_AUTH_METHOD: "other", - CONF_REALM: "test_realm", - CONF_USERNAME: "test_user@test_realm", + CONF_REALM: "Test_Realm", + CONF_USERNAME: "test_user@Test_Realm", } diff --git a/tests/components/proxmoxve/test_config_flow.py b/tests/components/proxmoxve/test_config_flow.py index c6814ca95717..aaf4aa0dd5ec 100644 --- a/tests/components/proxmoxve/test_config_flow.py +++ b/tests/components/proxmoxve/test_config_flow.py @@ -75,7 +75,7 @@ MOCK_USER_STEP_OTHER = { MOCK_USER_AUTH_STEP_OTHER = { **MOCK_USER_AUTH_STEP_PASSWORD, - CONF_REALM: "test_realm", + CONF_REALM: "Test_Realm", } # Other authentication method with realm and token @@ -86,7 +86,7 @@ MOCK_USER_STEP_OTHER_TOKEN = { MOCK_USER_AUTH_STEP_OTHER_TOKEN = { **MOCK_USER_AUTH_STEP_TOKEN, - CONF_REALM: "test_realm", + CONF_REALM: "Test_Realm", } MOCK_USER_SETUP = {CONF_NODES: ["pve1"]} @@ -724,7 +724,7 @@ async def test_full_flow_reauth_token_other( result = await hass.config_entries.flow.async_configure( result["flow_id"], user_input={ - CONF_REALM: "test_realm", + CONF_REALM: "Test_Realm", CONF_TOKEN_ID: "test_token_id", CONF_TOKEN_SECRET: "new_token_secret", }, diff --git a/tests/components/proxmoxve/test_init.py b/tests/components/proxmoxve/test_init.py index 83c6a0a5139e..68ccca4f5916 100644 --- a/tests/components/proxmoxve/test_init.py +++ b/tests/components/proxmoxve/test_init.py @@ -9,6 +9,7 @@ import requests from requests.exceptions import ConnectTimeout, SSLError from homeassistant.components.proxmoxve.const import ( + AUTH_OTHER, AUTH_PAM, CONF_AUTH_METHOD, CONF_CONTAINERS, @@ -165,25 +166,56 @@ async def test_setup_exceptions( assert mock_config_entry.state is expected_state +@pytest.mark.parametrize( + ("mock_config_entry", "expected_auth_method", "expected_realm"), + [ + ( + MockConfigEntry( + domain=DOMAIN, + version=1, + unique_id="1", + data={ + CONF_HOST: "http://test_host", + CONF_PORT: 8006, + CONF_REALM: "pam", + CONF_USERNAME: "test_user@pam", + CONF_PASSWORD: "test_password", + CONF_VERIFY_SSL: True, + }, + ), + AUTH_PAM, + "pam", + ), + ( + MockConfigEntry( + domain=DOMAIN, + version=1, + unique_id="1", + data={ + CONF_HOST: "http://test_host", + CONF_PORT: 8006, + CONF_REALM: "Test_Realm", + CONF_USERNAME: "test_user@Test_Realm", + CONF_PASSWORD: "test_password", + CONF_VERIFY_SSL: True, + }, + ), + AUTH_OTHER, + "Test_Realm", + ), + ], +) async def test_migration_v1_to_v3( hass: HomeAssistant, entity_registry: er.EntityRegistry, device_registry: dr.DeviceRegistry, + mock_config_entry: MockConfigEntry, + expected_auth_method: str, + expected_realm: str, ) -> None: - """Test migration from version 1.""" - entry = MockConfigEntry( - domain=DOMAIN, - version=1, - unique_id="1", - data={ - CONF_HOST: "http://test_host", - CONF_PORT: 8006, - CONF_REALM: "pam", - CONF_USERNAME: "test_user@pam", - CONF_PASSWORD: "test_password", - CONF_VERIFY_SSL: True, - }, - ) + """Test migration from version 1 to 3.""" + entry = mock_config_entry + entry.add_to_hass(hass) assert entry.version == 1 @@ -227,6 +259,8 @@ async def test_migration_v1_to_v3( await hass.async_block_till_done() assert entry.version == 3 + assert entry.data[CONF_AUTH_METHOD] == expected_auth_method + assert entry.data[CONF_REALM] == expected_realm vm_entity_after = entity_registry.async_get(vm_entity.entity_id) container_entity_after = entity_registry.async_get(container_entity.entity_id) @@ -235,6 +269,97 @@ async def test_migration_v1_to_v3( assert container_entity_after.unique_id == f"{entry.entry_id}_200_status" +@pytest.mark.parametrize( + ("mock_config_entry", "expected_auth_method", "expected_realm"), + [ + ( + MockConfigEntry( + domain=DOMAIN, + version=2, + unique_id="1", + data={ + CONF_HOST: "http://test_host", + CONF_PORT: 8006, + CONF_REALM: "pam", + CONF_USERNAME: "test_user@pam", + CONF_PASSWORD: "test_password", + CONF_VERIFY_SSL: True, + }, + ), + AUTH_PAM, + "pam", + ), + ( + MockConfigEntry( + domain=DOMAIN, + version=2, + unique_id="1", + data={ + CONF_HOST: "http://test_host", + CONF_PORT: 8006, + CONF_REALM: "Test_Realm", + CONF_USERNAME: "test_user@Test_Realm", + CONF_PASSWORD: "test_password", + CONF_VERIFY_SSL: True, + }, + ), + AUTH_OTHER, + "Test_Realm", + ), + ( + MockConfigEntry( + domain=DOMAIN, + version=2, + unique_id="1", + data={ + CONF_HOST: "http://test_host", + CONF_PORT: 8006, + CONF_USERNAME: "test_user@pam", + CONF_PASSWORD: "test_password", + CONF_VERIFY_SSL: True, + }, + ), + AUTH_PAM, + "pam", + ), + ( + MockConfigEntry( + domain=DOMAIN, + version=2, + unique_id="1", + data={ + CONF_HOST: "http://test_host", + CONF_PORT: 8006, + CONF_USERNAME: "test_user@Test_Realm", + CONF_PASSWORD: "test_password", + CONF_VERIFY_SSL: True, + }, + ), + AUTH_OTHER, + "Test_Realm", + ), + ], +) +async def test_migration_v2_to_v3( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + expected_auth_method: str, + expected_realm: str, +) -> None: + """Test migration from version 2 to 3.""" + entry = mock_config_entry + + entry.add_to_hass(hass) + assert entry.version == 2 + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert entry.version == 3 + assert entry.data[CONF_AUTH_METHOD] == expected_auth_method + assert entry.data[CONF_REALM] == expected_realm + + async def test_offline_node( hass: HomeAssistant, mock_proxmox_client: MagicMock, @@ -253,61 +378,6 @@ async def test_offline_node( assert state.state == STATE_OFF -async def test_migration_v2_to_v3( - hass: HomeAssistant, -) -> None: - """Test migration from version 2 to 3.""" - entry = MockConfigEntry( - domain=DOMAIN, - version=2, - unique_id="1", - data={ - CONF_HOST: "http://test_host", - CONF_PORT: 8006, - CONF_REALM: "pam", - CONF_USERNAME: "test_user@pam", - CONF_PASSWORD: "test_password", - CONF_VERIFY_SSL: True, - }, - ) - entry.add_to_hass(hass) - assert entry.version == 2 - - await hass.config_entries.async_setup(entry.entry_id) - await hass.async_block_till_done() - - assert entry.version == 3 - assert entry.data[CONF_AUTH_METHOD] == AUTH_PAM - assert entry.data[CONF_REALM] == AUTH_PAM - - -async def test_migration_v2_to_v3_without_realm( - hass: HomeAssistant, -) -> None: - """Test migration from version 2 to 3.""" - entry = MockConfigEntry( - domain=DOMAIN, - version=2, - unique_id="1", - data={ - CONF_HOST: "http://test_host", - CONF_PORT: 8006, - CONF_USERNAME: "test_user@pam", - CONF_PASSWORD: "test_password", - CONF_VERIFY_SSL: True, - }, - ) - entry.add_to_hass(hass) - assert entry.version == 2 - - await hass.config_entries.async_setup(entry.entry_id) - await hass.async_block_till_done() - - assert entry.version == 3 - assert entry.data[CONF_AUTH_METHOD] == AUTH_PAM - assert entry.data[CONF_REALM] == AUTH_PAM - - async def test_new_vm_creates_entity( hass: HomeAssistant, mock_proxmox_client: MagicMock, From 0b0dd55e4d8db64173eeaed6ce98a87d2c8de8c5 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Tue, 21 Jul 2026 14:48:28 +0200 Subject: [PATCH 2/8] Bump yoto-api to 4.3.2 (#176987) --- homeassistant/components/yoto/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/yoto/manifest.json b/homeassistant/components/yoto/manifest.json index 14d96dfbd4f3..0d41784390be 100644 --- a/homeassistant/components/yoto/manifest.json +++ b/homeassistant/components/yoto/manifest.json @@ -10,5 +10,5 @@ "iot_class": "cloud_push", "loggers": ["yoto_api"], "quality_scale": "platinum", - "requirements": ["yoto-api==4.3.1"] + "requirements": ["yoto-api==4.3.2"] } diff --git a/requirements_all.txt b/requirements_all.txt index 01f89263081c..7d918c266af9 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -3414,7 +3414,7 @@ yeelightsunflower==0.0.10 yolink-api==0.6.5 # homeassistant.components.yoto -yoto-api==4.3.1 +yoto-api==4.3.2 # homeassistant.components.youless youless-api==2.2.0 From 0017266e77e9954e906500412931eee873568f94 Mon Sep 17 00:00:00 2001 From: Richard H <5207490+genestealer@users.noreply.github.com> Date: Wed, 22 Jul 2026 14:55:23 +0100 Subject: [PATCH 3/8] Fix Envoy diagnostics fixture download on non-UTF-8 responses (#177008) --- homeassistant/components/enphase_envoy/diagnostics.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/enphase_envoy/diagnostics.py b/homeassistant/components/enphase_envoy/diagnostics.py index 77d7c2a4dc97..d52c4c14e049 100644 --- a/homeassistant/components/enphase_envoy/diagnostics.py +++ b/homeassistant/components/enphase_envoy/diagnostics.py @@ -79,7 +79,9 @@ async def _get_fixture_collection(envoy: Envoy, serial: str) -> dict[str, Any]: try: response: ClientResponse = await envoy.request(end_point) fixture_data[end_point] = ( - (await response.text()).replace("\n", "").replace(serial, CLEAN_TEXT) + (await response.text(errors="replace")) + .replace("\n", "") + .replace(serial, CLEAN_TEXT) ) fixture_data[f"{end_point}_log"] = json_dumps( { From ec0f869c4ab7ca2739bae3e513de7bdafc2d8ac8 Mon Sep 17 00:00:00 2001 From: Artem Draft Date: Wed, 22 Jul 2026 20:31:28 +0300 Subject: [PATCH 4/8] Bump pybravia to 0.5.1 (#177076) --- homeassistant/components/braviatv/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/braviatv/manifest.json b/homeassistant/components/braviatv/manifest.json index 0c8f90ac3d7a..532ee681502a 100644 --- a/homeassistant/components/braviatv/manifest.json +++ b/homeassistant/components/braviatv/manifest.json @@ -8,7 +8,7 @@ "integration_type": "device", "iot_class": "local_polling", "loggers": ["pybravia"], - "requirements": ["pybravia==0.4.1"], + "requirements": ["pybravia==0.5.1"], "ssdp": [ { "manufacturer": "Sony Corporation", diff --git a/requirements_all.txt b/requirements_all.txt index 7d918c266af9..4096dd84f102 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2048,7 +2048,7 @@ pyblu==2.0.8 pybotvac==0.0.29 # homeassistant.components.braviatv -pybravia==0.4.1 +pybravia==0.5.1 # homeassistant.components.nissan_leaf pycarwings2==2.14 From 883659c0c69c39086cabeff1b0f9e775b2d96517 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 22 Jul 2026 13:32:56 -1000 Subject: [PATCH 5/8] Bump yarl to 1.24.5 (#177097) --- homeassistant/package_constraints.txt | 2 +- pyproject.toml | 2 +- requirements.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 50ee981adf9d..18332579d46a 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -75,7 +75,7 @@ voluptuous-openapi==0.4.1 voluptuous-serialize==2.7.0 voluptuous==0.15.2 webrtc-models==0.3.0 -yarl==1.24.2 +yarl==1.24.5 zeroconf==0.150.0 # Constrain pycryptodome to avoid vulnerability diff --git a/pyproject.toml b/pyproject.toml index 67982b512877..fea82603234c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,7 +78,7 @@ dependencies = [ "voluptuous==0.15.2", "voluptuous-serialize==2.7.0", "voluptuous-openapi==0.4.1", - "yarl==1.24.2", + "yarl==1.24.5", "webrtc-models==0.3.0", "zeroconf==0.150.0", ] diff --git a/requirements.txt b/requirements.txt index 6673d88bdedd..c66f214ecb19 100644 --- a/requirements.txt +++ b/requirements.txt @@ -60,5 +60,5 @@ voluptuous-openapi==0.4.1 voluptuous-serialize==2.7.0 voluptuous==0.15.2 webrtc-models==0.3.0 -yarl==1.24.2 +yarl==1.24.5 zeroconf==0.150.0 From 745db90e0ba0a6bd966579c743e9663d34bf4399 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 22 Jul 2026 17:02:27 -1000 Subject: [PATCH 6/8] Bump aiohttp to 3.14.3 (#177105) --- homeassistant/package_constraints.txt | 2 +- pyproject.toml | 2 +- requirements.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 18332579d46a..a844fc33446a 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -6,7 +6,7 @@ aiodns==4.0.4 aiogithubapi==26.0.0 aiohttp-asyncmdnsresolver==0.2.0 aiohttp-fast-zlib==0.3.0 -aiohttp==3.14.1 +aiohttp==3.14.3 aiohttp_cors==0.8.1 aiousbwatcher==1.1.2 aiozoneinfo==0.2.3 diff --git a/pyproject.toml b/pyproject.toml index fea82603234c..c057aa50686e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ dependencies = [ # module level in `bootstrap.py` and its requirements thus need to be in # requirements.txt to ensure they are always installed "aiogithubapi==26.0.0", - "aiohttp==3.14.1", + "aiohttp==3.14.3", "aiohttp_cors==0.8.1", "aiohttp-fast-zlib==0.3.0", "aiohttp-asyncmdnsresolver==0.2.0", diff --git a/requirements.txt b/requirements.txt index c66f214ecb19..bc15bb1849ce 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ aiodns==4.0.4 aiogithubapi==26.0.0 aiohttp-asyncmdnsresolver==0.2.0 aiohttp-fast-zlib==0.3.0 -aiohttp==3.14.1 +aiohttp==3.14.3 aiohttp_cors==0.8.1 aiozoneinfo==0.2.3 annotatedyaml==1.0.2 From 82ef9c0b8f75ac189c9ccab6e3fbf9b1d0b90406 Mon Sep 17 00:00:00 2001 From: Josef Zweck Date: Thu, 23 Jul 2026 22:25:52 +0200 Subject: [PATCH 7/8] Bump pylamarzocco to 2.4.3 (#177151) --- homeassistant/components/lamarzocco/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/lamarzocco/manifest.json b/homeassistant/components/lamarzocco/manifest.json index 0abd73db29a1..3976349c4673 100644 --- a/homeassistant/components/lamarzocco/manifest.json +++ b/homeassistant/components/lamarzocco/manifest.json @@ -37,5 +37,5 @@ "iot_class": "cloud_push", "loggers": ["pylamarzocco"], "quality_scale": "platinum", - "requirements": ["pylamarzocco==2.4.2"] + "requirements": ["pylamarzocco==2.4.3"] } diff --git a/requirements_all.txt b/requirements_all.txt index 4096dd84f102..0ce28e05d339 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2298,7 +2298,7 @@ pykwb==0.0.8 pylacrosse==0.4 # homeassistant.components.lamarzocco -pylamarzocco==2.4.2 +pylamarzocco==2.4.3 # homeassistant.components.lastfm pylast==5.1.0 From faf5ddddd107f37444ec49bb004a8847a1ad2976 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Fri, 24 Jul 2026 07:08:26 +0000 Subject: [PATCH 8/8] Bump version to 2026.7.4 --- 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 68f0ec1366cb..62bb20178da5 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -22,7 +22,7 @@ if TYPE_CHECKING: APPLICATION_NAME: Final = "HomeAssistant" MAJOR_VERSION: Final = 2026 MINOR_VERSION: Final = 7 -PATCH_VERSION: Final = "3" +PATCH_VERSION: Final = "4" __short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__: Final = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 14, 2) diff --git a/pyproject.toml b/pyproject.toml index c057aa50686e..d6e3e435c508 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "homeassistant" -version = "2026.7.3" +version = "2026.7.4" license = "Apache-2.0" license-files = ["LICENSE*", "homeassistant/backports/LICENSE*"] description = "Open-source home automation platform running on Python 3."