From 0e132c4ef8b2ac4a68f462aac04b4c826f895987 Mon Sep 17 00:00:00 2001 From: Jamie Magee Date: Sat, 12 Sep 2026 11:06:01 -0700 Subject: [PATCH] Bump py-madvr2 to 1.9.1 (#181793) --- homeassistant/components/madvr/__init__.py | 3 +- homeassistant/components/madvr/config_flow.py | 51 +++++++++---------- homeassistant/components/madvr/coordinator.py | 4 +- homeassistant/components/madvr/manifest.json | 2 +- requirements_all.txt | 2 +- tests/components/madvr/conftest.py | 1 - tests/components/madvr/test_config_flow.py | 26 +++++++--- 7 files changed, 47 insertions(+), 42 deletions(-) diff --git a/homeassistant/components/madvr/__init__.py b/homeassistant/components/madvr/__init__.py index e55826b3b2ce..595505709258 100644 --- a/homeassistant/components/madvr/__init__.py +++ b/homeassistant/components/madvr/__init__.py @@ -2,7 +2,7 @@ import logging -from madvr.madvr import Madvr +from pymadvr.madvr import Madvr from homeassistant.const import CONF_HOST, CONF_PORT, EVENT_HOMEASSISTANT_STOP, Platform from homeassistant.core import Event, HomeAssistant @@ -18,7 +18,6 @@ async def async_handle_unload(coordinator: MadVRCoordinator) -> None: """Handle unload.""" _LOGGER.debug("Integration unloading") coordinator.client.stop() - await coordinator.client.async_cancel_tasks() _LOGGER.debug("Integration closing connection") await coordinator.client.close_connection() _LOGGER.debug("Unloaded") diff --git a/homeassistant/components/madvr/config_flow.py b/homeassistant/components/madvr/config_flow.py index ab05efaf4c7f..c908c74c9e83 100644 --- a/homeassistant/components/madvr/config_flow.py +++ b/homeassistant/components/madvr/config_flow.py @@ -4,8 +4,7 @@ import asyncio import logging from typing import Any, override -import aiohttp -from madvr.madvr import HeartBeatError, Madvr +from pymadvr.madvr import Madvr import voluptuous as vol from homeassistant.config_entries import ( @@ -102,40 +101,36 @@ async def test_connection(hass: HomeAssistant, host: str, port: int) -> str: """Test if we can connect to the device and grab the mac.""" madvr_client = Madvr(host=host, port=port, loop=hass.loop) _LOGGER.debug("Testing connection to madVR at %s:%s", host, port) - # try to connect try: - await asyncio.wait_for(madvr_client.open_connection(), timeout=15) - # connection can raise HeartBeatError if the device is not - # available or connection does not work - except (TimeoutError, aiohttp.ClientError, OSError, HeartBeatError) as err: - _LOGGER.error("Error connecting to madVR: %s", err) - raise CannotConnect from err + # try to connect + try: + await asyncio.wait_for(madvr_client.open_connection(), timeout=15) + except (TimeoutError, OSError) as err: + _LOGGER.error("Error connecting to madVR: %s", err) + raise CannotConnect from err - # check if we are connected - if not madvr_client.connected: - raise CannotConnect("Connection failed") + # check if we are connected + if not madvr_client.connected: + raise CannotConnect("Connection failed") - # background tasks needed to capture realtime info - await madvr_client.async_add_tasks() + # wait for client to capture device info + retry_time = 15 + while not madvr_client.mac_address and retry_time > 0: + await asyncio.sleep(RETRY_INTERVAL) + retry_time -= 1 - # wait for client to capture device info - retry_time = 15 - while not madvr_client.mac_address and retry_time > 0: - await asyncio.sleep(RETRY_INTERVAL) - retry_time -= 1 - - mac_address = madvr_client.mac_address - if mac_address: - _LOGGER.debug("Connected to madVR with MAC: %s", mac_address) - # close this connection because this client object will not be reused - await close_test_connection(madvr_client) - _LOGGER.debug("Connection test successful") - return mac_address + mac_address = madvr_client.mac_address + if mac_address: + _LOGGER.debug("Connected to madVR with MAC: %s", mac_address) + _LOGGER.debug("Connection test successful") + return mac_address + finally: + # close this connection because this client object will not be reused + await close_test_connection(madvr_client) async def close_test_connection(madvr_client: Madvr) -> None: """Close the test connection.""" _LOGGER.debug("Closing test connection") madvr_client.stop() - await madvr_client.async_cancel_tasks() await madvr_client.close_connection() diff --git a/homeassistant/components/madvr/coordinator.py b/homeassistant/components/madvr/coordinator.py index 7984c5a5b75a..8d89127d74ae 100644 --- a/homeassistant/components/madvr/coordinator.py +++ b/homeassistant/components/madvr/coordinator.py @@ -3,7 +3,7 @@ import logging from typing import Any -from madvr.madvr import Madvr +from pymadvr.madvr import Madvr from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant @@ -49,4 +49,4 @@ class MadVRCoordinator(DataUpdateCoordinator[dict[str, Any]]): _LOGGER.debug("Using loop: %s", self.client.loop) # tell the library to start background tasks await self.client.async_add_tasks() - _LOGGER.debug("Added %s tasks to client", len(self.client.tasks)) + _LOGGER.debug("Added background tasks to client") diff --git a/homeassistant/components/madvr/manifest.json b/homeassistant/components/madvr/manifest.json index e45a4c60f308..4b19d098bd20 100644 --- a/homeassistant/components/madvr/manifest.json +++ b/homeassistant/components/madvr/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/madvr", "integration_type": "device", "iot_class": "local_push", - "requirements": ["py-madvr2==1.6.40"] + "requirements": ["py-madvr2==1.9.1"] } diff --git a/requirements_all.txt b/requirements_all.txt index 1b4bc4d6022e..a1b01eef4d09 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1987,7 +1987,7 @@ py-dormakaba-dkey==1.0.6 py-improv-ble-client==2.0.1 # homeassistant.components.madvr -py-madvr2==1.6.40 +py-madvr2==1.9.1 # homeassistant.components.melissa py-melissa-climate==3.0.3 diff --git a/tests/components/madvr/conftest.py b/tests/components/madvr/conftest.py index 3136e04b06bc..61a907eb5c0a 100644 --- a/tests/components/madvr/conftest.py +++ b/tests/components/madvr/conftest.py @@ -39,7 +39,6 @@ def mock_madvr_client() -> Generator[AsyncMock]: client.connected.return_value = True client.is_device_connectable.return_value = True client.loop = AsyncMock() - client.tasks = AsyncMock() client.set_update_callback = MagicMock() # mock the property to be off on startup (which it is) diff --git a/tests/components/madvr/test_config_flow.py b/tests/components/madvr/test_config_flow.py index 966846ce3da5..f18cc8a02bb3 100644 --- a/tests/components/madvr/test_config_flow.py +++ b/tests/components/madvr/test_config_flow.py @@ -44,8 +44,9 @@ async def test_full_flow(hass: HomeAssistant, mock_madvr_client: AsyncMock) -> N } assert result["result"].unique_id == MOCK_MAC mock_madvr_client.open_connection.assert_called_once() - mock_madvr_client.async_add_tasks.assert_called_once() - mock_madvr_client.async_cancel_tasks.assert_called_once() + mock_madvr_client.async_add_tasks.assert_not_called() + mock_madvr_client.async_cancel_tasks.assert_not_called() + mock_madvr_client.close_connection.assert_called_once() @pytest.mark.usefixtures("mock_setup_entry") @@ -98,9 +99,9 @@ async def test_flow_errors(hass: HomeAssistant, mock_madvr_client: AsyncMock) -> # Verify method calls assert mock_madvr_client.open_connection.call_count == 4 - assert mock_madvr_client.async_add_tasks.call_count == 2 - # the first call will not call this due to timeout as expected - assert mock_madvr_client.async_cancel_tasks.call_count == 2 + assert mock_madvr_client.async_add_tasks.call_count == 0 + assert mock_madvr_client.async_cancel_tasks.call_count == 0 + assert mock_madvr_client.close_connection.call_count == 4 async def test_duplicate( @@ -126,6 +127,7 @@ async def test_reconfigure_flow( hass: HomeAssistant, mock_madvr_client: AsyncMock, mock_config_entry: MockConfigEntry, + mock_setup_entry: AsyncMock, ) -> None: """Test reconfigure flow.""" mock_config_entry.add_to_hass(hass) @@ -144,6 +146,7 @@ async def test_reconfigure_flow( result["flow_id"], {CONF_HOST: new_host, CONF_PORT: new_port}, ) + await hass.async_block_till_done() # should get the abort with success result assert result["type"] is FlowResultType.ABORT @@ -155,8 +158,10 @@ async def test_reconfigure_flow( # Verify that the connection was tested mock_madvr_client.open_connection.assert_called() - mock_madvr_client.async_add_tasks.assert_called() - mock_madvr_client.async_cancel_tasks.assert_called() + mock_madvr_client.async_add_tasks.assert_not_called() + mock_madvr_client.async_cancel_tasks.assert_not_called() + mock_madvr_client.close_connection.assert_called() + mock_setup_entry.assert_awaited_once() async def test_reconfigure_new_device( @@ -191,6 +196,7 @@ async def test_reconfigure_flow_errors( hass: HomeAssistant, mock_madvr_client: AsyncMock, mock_config_entry: MockConfigEntry, + mock_setup_entry: AsyncMock, ) -> None: """Test error handling in reconfigure flow.""" mock_config_entry.add_to_hass(hass) @@ -226,5 +232,11 @@ async def test_reconfigure_flow_errors( result["flow_id"], {CONF_HOST: "192.168.1.100", CONF_PORT: 44077}, ) + await hass.async_block_till_done() assert result["type"] is FlowResultType.ABORT assert result["reason"] == "reconfigure_successful" + assert mock_madvr_client.open_connection.call_count == 3 + assert mock_madvr_client.async_add_tasks.call_count == 0 + assert mock_madvr_client.async_cancel_tasks.call_count == 0 + assert mock_madvr_client.close_connection.call_count == 3 + mock_setup_entry.assert_awaited_once()