diff --git a/homeassistant/components/wallbox/const.py b/homeassistant/components/wallbox/const.py index 5aa659a0527..34d17e52275 100644 --- a/homeassistant/components/wallbox/const.py +++ b/homeassistant/components/wallbox/const.py @@ -3,7 +3,7 @@ from enum import StrEnum DOMAIN = "wallbox" -UPDATE_INTERVAL = 30 +UPDATE_INTERVAL = 60 BIDIRECTIONAL_MODEL_PREFIXES = ["QS"] diff --git a/homeassistant/components/wallbox/coordinator.py b/homeassistant/components/wallbox/coordinator.py index 8276ee14eaf..598bfa7429a 100644 --- a/homeassistant/components/wallbox/coordinator.py +++ b/homeassistant/components/wallbox/coordinator.py @@ -90,7 +90,9 @@ def _require_authentication[_WallboxCoordinatorT: WallboxCoordinator, **_P]( except requests.exceptions.HTTPError as wallbox_connection_error: if wallbox_connection_error.response.status_code == HTTPStatus.FORBIDDEN: raise ConfigEntryAuthFailed from wallbox_connection_error - raise ConnectionError from wallbox_connection_error + raise HomeAssistantError( + translation_domain=DOMAIN, translation_key="api_failed" + ) from wallbox_connection_error return require_authentication @@ -137,56 +139,65 @@ class WallboxCoordinator(DataUpdateCoordinator[dict[str, Any]]): @_require_authentication def _get_data(self) -> dict[str, Any]: """Get new sensor data for Wallbox component.""" - data: dict[str, Any] = self._wallbox.getChargerStatus(self._station) - data[CHARGER_MAX_CHARGING_CURRENT_KEY] = data[CHARGER_DATA_KEY][ - CHARGER_MAX_CHARGING_CURRENT_KEY - ] - data[CHARGER_LOCKED_UNLOCKED_KEY] = data[CHARGER_DATA_KEY][ - CHARGER_LOCKED_UNLOCKED_KEY - ] - data[CHARGER_ENERGY_PRICE_KEY] = data[CHARGER_DATA_KEY][ - CHARGER_ENERGY_PRICE_KEY - ] - # Only show max_icp_current if power_boost is available in the wallbox unit: - if ( - data[CHARGER_DATA_KEY].get(CHARGER_MAX_ICP_CURRENT_KEY, 0) > 0 - and CHARGER_POWER_BOOST_KEY - in data[CHARGER_DATA_KEY][CHARGER_PLAN_KEY][CHARGER_FEATURES_KEY] - ): - data[CHARGER_MAX_ICP_CURRENT_KEY] = data[CHARGER_DATA_KEY][ - CHARGER_MAX_ICP_CURRENT_KEY + try: + data: dict[str, Any] = self._wallbox.getChargerStatus(self._station) + data[CHARGER_MAX_CHARGING_CURRENT_KEY] = data[CHARGER_DATA_KEY][ + CHARGER_MAX_CHARGING_CURRENT_KEY ] + data[CHARGER_LOCKED_UNLOCKED_KEY] = data[CHARGER_DATA_KEY][ + CHARGER_LOCKED_UNLOCKED_KEY + ] + data[CHARGER_ENERGY_PRICE_KEY] = data[CHARGER_DATA_KEY][ + CHARGER_ENERGY_PRICE_KEY + ] + # Only show max_icp_current if power_boost is available in the wallbox unit: + if ( + data[CHARGER_DATA_KEY].get(CHARGER_MAX_ICP_CURRENT_KEY, 0) > 0 + and CHARGER_POWER_BOOST_KEY + in data[CHARGER_DATA_KEY][CHARGER_PLAN_KEY][CHARGER_FEATURES_KEY] + ): + data[CHARGER_MAX_ICP_CURRENT_KEY] = data[CHARGER_DATA_KEY][ + CHARGER_MAX_ICP_CURRENT_KEY + ] - data[CHARGER_CURRENCY_KEY] = ( - f"{data[CHARGER_DATA_KEY][CHARGER_CURRENCY_KEY][CODE_KEY]}/kWh" - ) + data[CHARGER_CURRENCY_KEY] = ( + f"{data[CHARGER_DATA_KEY][CHARGER_CURRENCY_KEY][CODE_KEY]}/kWh" + ) - data[CHARGER_STATUS_DESCRIPTION_KEY] = CHARGER_STATUS.get( - data[CHARGER_STATUS_ID_KEY], ChargerStatus.UNKNOWN - ) + data[CHARGER_STATUS_DESCRIPTION_KEY] = CHARGER_STATUS.get( + data[CHARGER_STATUS_ID_KEY], ChargerStatus.UNKNOWN + ) - # Set current solar charging mode - eco_smart_enabled = ( - data[CHARGER_DATA_KEY] - .get(CHARGER_ECO_SMART_KEY, {}) - .get(CHARGER_ECO_SMART_STATUS_KEY) - ) + # Set current solar charging mode + eco_smart_enabled = ( + data[CHARGER_DATA_KEY] + .get(CHARGER_ECO_SMART_KEY, {}) + .get(CHARGER_ECO_SMART_STATUS_KEY) + ) - eco_smart_mode = ( - data[CHARGER_DATA_KEY] - .get(CHARGER_ECO_SMART_KEY, {}) - .get(CHARGER_ECO_SMART_MODE_KEY) - ) - if eco_smart_mode is None: - data[CHARGER_ECO_SMART_KEY] = EcoSmartMode.DISABLED - elif eco_smart_enabled is False: - data[CHARGER_ECO_SMART_KEY] = EcoSmartMode.OFF - elif eco_smart_mode == 0: - data[CHARGER_ECO_SMART_KEY] = EcoSmartMode.ECO_MODE - elif eco_smart_mode == 1: - data[CHARGER_ECO_SMART_KEY] = EcoSmartMode.FULL_SOLAR + eco_smart_mode = ( + data[CHARGER_DATA_KEY] + .get(CHARGER_ECO_SMART_KEY, {}) + .get(CHARGER_ECO_SMART_MODE_KEY) + ) + if eco_smart_mode is None: + data[CHARGER_ECO_SMART_KEY] = EcoSmartMode.DISABLED + elif eco_smart_enabled is False: + data[CHARGER_ECO_SMART_KEY] = EcoSmartMode.OFF + elif eco_smart_mode == 0: + data[CHARGER_ECO_SMART_KEY] = EcoSmartMode.ECO_MODE + elif eco_smart_mode == 1: + data[CHARGER_ECO_SMART_KEY] = EcoSmartMode.FULL_SOLAR - return data + return data # noqa: TRY300 + except requests.exceptions.HTTPError as wallbox_connection_error: + if wallbox_connection_error.response.status_code == 429: + raise HomeAssistantError( + translation_domain=DOMAIN, translation_key="too_many_requests" + ) from wallbox_connection_error + raise HomeAssistantError( + translation_domain=DOMAIN, translation_key="api_failed" + ) from wallbox_connection_error async def _async_update_data(self) -> dict[str, Any]: """Get new sensor data for Wallbox component.""" @@ -200,7 +211,13 @@ class WallboxCoordinator(DataUpdateCoordinator[dict[str, Any]]): except requests.exceptions.HTTPError as wallbox_connection_error: if wallbox_connection_error.response.status_code == 403: raise InvalidAuth from wallbox_connection_error - raise + if wallbox_connection_error.response.status_code == 429: + raise HomeAssistantError( + translation_domain=DOMAIN, translation_key="too_many_requests" + ) from wallbox_connection_error + raise HomeAssistantError( + translation_domain=DOMAIN, translation_key="api_failed" + ) from wallbox_connection_error async def async_set_charging_current(self, charging_current: float) -> None: """Set maximum charging current for Wallbox.""" @@ -217,7 +234,13 @@ class WallboxCoordinator(DataUpdateCoordinator[dict[str, Any]]): except requests.exceptions.HTTPError as wallbox_connection_error: if wallbox_connection_error.response.status_code == 403: raise InvalidAuth from wallbox_connection_error - raise + if wallbox_connection_error.response.status_code == 429: + raise HomeAssistantError( + translation_domain=DOMAIN, translation_key="too_many_requests" + ) from wallbox_connection_error + raise HomeAssistantError( + translation_domain=DOMAIN, translation_key="api_failed" + ) from wallbox_connection_error async def async_set_icp_current(self, icp_current: float) -> None: """Set maximum icp current for Wallbox.""" @@ -227,8 +250,16 @@ class WallboxCoordinator(DataUpdateCoordinator[dict[str, Any]]): @_require_authentication def _set_energy_cost(self, energy_cost: float) -> None: """Set energy cost for Wallbox.""" - - self._wallbox.setEnergyCost(self._station, energy_cost) + try: + self._wallbox.setEnergyCost(self._station, energy_cost) + except requests.exceptions.HTTPError as wallbox_connection_error: + if wallbox_connection_error.response.status_code == 429: + raise HomeAssistantError( + translation_domain=DOMAIN, translation_key="too_many_requests" + ) from wallbox_connection_error + raise HomeAssistantError( + translation_domain=DOMAIN, translation_key="api_failed" + ) from wallbox_connection_error async def async_set_energy_cost(self, energy_cost: float) -> None: """Set energy cost for Wallbox.""" @@ -246,7 +277,13 @@ class WallboxCoordinator(DataUpdateCoordinator[dict[str, Any]]): except requests.exceptions.HTTPError as wallbox_connection_error: if wallbox_connection_error.response.status_code == 403: raise InvalidAuth from wallbox_connection_error - raise + if wallbox_connection_error.response.status_code == 429: + raise HomeAssistantError( + translation_domain=DOMAIN, translation_key="too_many_requests" + ) from wallbox_connection_error + raise HomeAssistantError( + translation_domain=DOMAIN, translation_key="api_failed" + ) from wallbox_connection_error async def async_set_lock_unlock(self, lock: bool) -> None: """Set wallbox to locked or unlocked.""" @@ -256,11 +293,19 @@ class WallboxCoordinator(DataUpdateCoordinator[dict[str, Any]]): @_require_authentication def _pause_charger(self, pause: bool) -> None: """Set wallbox to pause or resume.""" - - if pause: - self._wallbox.pauseChargingSession(self._station) - else: - self._wallbox.resumeChargingSession(self._station) + try: + if pause: + self._wallbox.pauseChargingSession(self._station) + else: + self._wallbox.resumeChargingSession(self._station) + except requests.exceptions.HTTPError as wallbox_connection_error: + if wallbox_connection_error.response.status_code == 429: + raise HomeAssistantError( + translation_domain=DOMAIN, translation_key="too_many_requests" + ) from wallbox_connection_error + raise HomeAssistantError( + translation_domain=DOMAIN, translation_key="api_failed" + ) from wallbox_connection_error async def async_pause_charger(self, pause: bool) -> None: """Set wallbox to pause or resume.""" @@ -270,13 +315,21 @@ class WallboxCoordinator(DataUpdateCoordinator[dict[str, Any]]): @_require_authentication def _set_eco_smart(self, option: str) -> None: """Set wallbox solar charging mode.""" - - if option == EcoSmartMode.ECO_MODE: - self._wallbox.enableEcoSmart(self._station, 0) - elif option == EcoSmartMode.FULL_SOLAR: - self._wallbox.enableEcoSmart(self._station, 1) - else: - self._wallbox.disableEcoSmart(self._station) + try: + if option == EcoSmartMode.ECO_MODE: + self._wallbox.enableEcoSmart(self._station, 0) + elif option == EcoSmartMode.FULL_SOLAR: + self._wallbox.enableEcoSmart(self._station, 1) + else: + self._wallbox.disableEcoSmart(self._station) + except requests.exceptions.HTTPError as wallbox_connection_error: + if wallbox_connection_error.response.status_code == 429: + raise HomeAssistantError( + translation_domain=DOMAIN, translation_key="too_many_requests" + ) from wallbox_connection_error + raise HomeAssistantError( + translation_domain=DOMAIN, translation_key="api_failed" + ) from wallbox_connection_error async def async_set_eco_smart(self, option: str) -> None: """Set wallbox solar charging mode.""" diff --git a/homeassistant/components/wallbox/lock.py b/homeassistant/components/wallbox/lock.py index ef35734ed7e..7acc56f67f2 100644 --- a/homeassistant/components/wallbox/lock.py +++ b/homeassistant/components/wallbox/lock.py @@ -7,7 +7,7 @@ from typing import Any from homeassistant.components.lock import LockEntity, LockEntityDescription from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant -from homeassistant.exceptions import PlatformNotReady +from homeassistant.exceptions import HomeAssistantError, PlatformNotReady from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from .const import ( @@ -41,7 +41,7 @@ async def async_setup_entry( ) except InvalidAuth: return - except ConnectionError as exc: + except HomeAssistantError as exc: raise PlatformNotReady from exc async_add_entities( diff --git a/homeassistant/components/wallbox/number.py b/homeassistant/components/wallbox/number.py index a5880f6e0f7..80773478582 100644 --- a/homeassistant/components/wallbox/number.py +++ b/homeassistant/components/wallbox/number.py @@ -12,7 +12,7 @@ from typing import cast from homeassistant.components.number import NumberEntity, NumberEntityDescription from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant -from homeassistant.exceptions import PlatformNotReady +from homeassistant.exceptions import HomeAssistantError, PlatformNotReady from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from .const import ( @@ -93,7 +93,7 @@ async def async_setup_entry( ) except InvalidAuth: return - except ConnectionError as exc: + except HomeAssistantError as exc: raise PlatformNotReady from exc async_add_entities( diff --git a/homeassistant/components/wallbox/sensor.py b/homeassistant/components/wallbox/sensor.py index 4b0ec8175e3..e19fc2b936a 100644 --- a/homeassistant/components/wallbox/sensor.py +++ b/homeassistant/components/wallbox/sensor.py @@ -3,7 +3,6 @@ from __future__ import annotations from dataclasses import dataclass -import logging from typing import cast from homeassistant.components.sensor import ( @@ -49,11 +48,6 @@ from .const import ( from .coordinator import WallboxCoordinator from .entity import WallboxEntity -CHARGER_STATION = "station" -UPDATE_INTERVAL = 30 - -_LOGGER = logging.getLogger(__name__) - @dataclass(frozen=True) class WallboxSensorEntityDescription(SensorEntityDescription): diff --git a/homeassistant/components/wallbox/strings.json b/homeassistant/components/wallbox/strings.json index 68602a960c2..ee98a4855e3 100644 --- a/homeassistant/components/wallbox/strings.json +++ b/homeassistant/components/wallbox/strings.json @@ -112,6 +112,9 @@ "exceptions": { "api_failed": { "message": "Error communicating with Wallbox API" + }, + "too_many_requests": { + "message": "Error communicating with Wallbox API, too many requests" } } } diff --git a/tests/components/wallbox/__init__.py b/tests/components/wallbox/__init__.py index 83e39d2f602..37e7d5059f0 100644 --- a/tests/components/wallbox/__init__.py +++ b/tests/components/wallbox/__init__.py @@ -162,6 +162,9 @@ test_response_no_power_boost = { http_404_error = requests.exceptions.HTTPError() http_404_error.response = requests.Response() http_404_error.response.status_code = HTTPStatus.NOT_FOUND +http_429_error = requests.exceptions.HTTPError() +http_429_error.response = requests.Response() +http_429_error.response.status_code = HTTPStatus.TOO_MANY_REQUESTS authorisation_response = { "data": { @@ -192,6 +195,24 @@ authorisation_response_unauthorised = { } } +invalid_reauth_response = { + "jwt": "fakekeyhere", + "refresh_token": "refresh_fakekeyhere", + "user_id": 12345, + "ttl": 145656758, + "refresh_token_ttl": 145756758, + "error": False, + "status": 200, +} + +http_403_error = requests.exceptions.HTTPError() +http_403_error.response = requests.Response() +http_403_error.response.status_code = HTTPStatus.FORBIDDEN + +http_404_error = requests.exceptions.HTTPError() +http_404_error.response = requests.Response() +http_404_error.response.status_code = HTTPStatus.NOT_FOUND + async def setup_integration(hass: HomeAssistant, entry: MockConfigEntry) -> None: """Test wallbox sensor class setup.""" diff --git a/tests/components/wallbox/test_config_flow.py b/tests/components/wallbox/test_config_flow.py index 467e20c51c1..bdfb4cad18d 100644 --- a/tests/components/wallbox/test_config_flow.py +++ b/tests/components/wallbox/test_config_flow.py @@ -1,9 +1,6 @@ """Test the Wallbox config flow.""" -from http import HTTPStatus -import json - -import requests_mock +from unittest.mock import Mock, patch from homeassistant import config_entries from homeassistant.components.wallbox import config_flow @@ -24,23 +21,21 @@ from homeassistant.data_entry_flow import FlowResultType from . import ( authorisation_response, authorisation_response_unauthorised, + http_403_error, + http_404_error, setup_integration, ) from tests.common import MockConfigEntry -test_response = json.loads( - json.dumps( - { - CHARGER_CHARGING_POWER_KEY: 0, - CHARGER_MAX_AVAILABLE_POWER_KEY: "xx", - CHARGER_CHARGING_SPEED_KEY: 0, - CHARGER_ADDED_RANGE_KEY: "xx", - CHARGER_ADDED_ENERGY_KEY: "44.697", - CHARGER_DATA_KEY: {CHARGER_MAX_CHARGING_CURRENT_KEY: 24}, - } - ) -) +test_response = { + CHARGER_CHARGING_POWER_KEY: 0, + CHARGER_MAX_AVAILABLE_POWER_KEY: "xx", + CHARGER_CHARGING_SPEED_KEY: 0, + CHARGER_ADDED_RANGE_KEY: "xx", + CHARGER_ADDED_ENERGY_KEY: "44.697", + CHARGER_DATA_KEY: {CHARGER_MAX_CHARGING_CURRENT_KEY: 24}, +} async def test_show_set_form(hass: HomeAssistant) -> None: @@ -59,17 +54,16 @@ async def test_form_cannot_authenticate(hass: HomeAssistant) -> None: DOMAIN, context={"source": config_entries.SOURCE_USER} ) - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=HTTPStatus.FORBIDDEN, - ) - mock_request.get( - "https://api.wall-box.com/chargers/status/12345", - json=test_response, - status_code=HTTPStatus.FORBIDDEN, - ) + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(side_effect=http_403_error), + ), + patch( + "homeassistant.components.wallbox.Wallbox.pauseChargingSession", + new=Mock(side_effect=http_403_error), + ), + ): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], { @@ -89,17 +83,16 @@ async def test_form_cannot_connect(hass: HomeAssistant) -> None: DOMAIN, context={"source": config_entries.SOURCE_USER} ) - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response_unauthorised, - status_code=HTTPStatus.NOT_FOUND, - ) - mock_request.get( - "https://api.wall-box.com/chargers/status/12345", - json=test_response, - status_code=HTTPStatus.NOT_FOUND, - ) + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(side_effect=http_404_error), + ), + patch( + "homeassistant.components.wallbox.Wallbox.pauseChargingSession", + new=Mock(side_effect=http_404_error), + ), + ): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], { @@ -119,17 +112,16 @@ async def test_form_validate_input(hass: HomeAssistant) -> None: DOMAIN, context={"source": config_entries.SOURCE_USER} ) - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=HTTPStatus.OK, - ) - mock_request.get( - "https://api.wall-box.com/chargers/status/12345", - json=test_response, - status_code=HTTPStatus.OK, - ) + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.getChargerStatus", + new=Mock(return_value=test_response), + ), + ): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], { @@ -148,18 +140,16 @@ async def test_form_reauth(hass: HomeAssistant, entry: MockConfigEntry) -> None: await setup_integration(hass, entry) assert entry.state is ConfigEntryState.LOADED - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=200, - ) - mock_request.get( - "https://api.wall-box.com/chargers/status/12345", - json=test_response, - status_code=200, - ) - + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response_unauthorised), + ), + patch( + "homeassistant.components.wallbox.Wallbox.getChargerStatus", + new=Mock(return_value=test_response), + ), + ): result = await entry.start_reauth_flow(hass) result2 = await hass.config_entries.flow.async_configure( @@ -183,26 +173,16 @@ async def test_form_reauth_invalid(hass: HomeAssistant, entry: MockConfigEntry) await setup_integration(hass, entry) assert entry.state is ConfigEntryState.LOADED - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json={ - "jwt": "fakekeyhere", - "refresh_token": "refresh_fakekeyhere", - "user_id": 12345, - "ttl": 145656758, - "refresh_token_ttl": 145756758, - "error": False, - "status": 200, - }, - status_code=200, - ) - mock_request.get( - "https://api.wall-box.com/chargers/status/12345", - json=test_response, - status_code=200, - ) - + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response_unauthorised), + ), + patch( + "homeassistant.components.wallbox.Wallbox.getChargerStatus", + new=Mock(return_value=test_response), + ), + ): result = await entry.start_reauth_flow(hass) result2 = await hass.config_entries.flow.async_configure( diff --git a/tests/components/wallbox/test_init.py b/tests/components/wallbox/test_init.py index 6d6a5cd1417..5048385aaf6 100644 --- a/tests/components/wallbox/test_init.py +++ b/tests/components/wallbox/test_init.py @@ -1,16 +1,15 @@ """Test Wallbox Init Component.""" -import requests_mock +from unittest.mock import Mock, patch -from homeassistant.components.wallbox.const import ( - CHARGER_MAX_CHARGING_CURRENT_KEY, - DOMAIN, -) +from homeassistant.components.wallbox.const import DOMAIN from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant from . import ( authorisation_response, + http_403_error, + http_429_error, setup_integration, setup_integration_connection_error, setup_integration_no_eco_mode, @@ -53,18 +52,16 @@ async def test_wallbox_refresh_failed_connection_error_auth( await setup_integration(hass, entry) assert entry.state is ConfigEntryState.LOADED - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=404, - ) - mock_request.get( - "https://api.wall-box.com/chargers/status/12345", - json=test_response, - status_code=200, - ) - + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(side_effect=http_429_error), + ), + patch( + "homeassistant.components.wallbox.Wallbox.pauseChargingSession", + new=Mock(return_value=test_response), + ), + ): wallbox = hass.data[DOMAIN][entry.entry_id] await wallbox.async_refresh() @@ -81,18 +78,68 @@ async def test_wallbox_refresh_failed_invalid_auth( await setup_integration(hass, entry) assert entry.state is ConfigEntryState.LOADED - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=403, - ) - mock_request.put( - "https://api.wall-box.com/v2/charger/12345", - json={CHARGER_MAX_CHARGING_CURRENT_KEY: 20}, - status_code=403, - ) + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(side_effect=http_403_error), + ), + patch( + "homeassistant.components.wallbox.Wallbox.pauseChargingSession", + new=Mock(side_effect=http_403_error), + ), + ): + wallbox = hass.data[DOMAIN][entry.entry_id] + await wallbox.async_refresh() + + assert await hass.config_entries.async_unload(entry.entry_id) + assert entry.state is ConfigEntryState.NOT_LOADED + + +async def test_wallbox_refresh_failed_http_error( + hass: HomeAssistant, entry: MockConfigEntry +) -> None: + """Test Wallbox setup with authentication error.""" + + await setup_integration(hass, entry) + assert entry.state is ConfigEntryState.LOADED + + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.getChargerStatus", + new=Mock(side_effect=http_403_error), + ), + ): + wallbox = hass.data[DOMAIN][entry.entry_id] + + await wallbox.async_refresh() + + assert await hass.config_entries.async_unload(entry.entry_id) + assert entry.state is ConfigEntryState.NOT_LOADED + + +async def test_wallbox_refresh_failed_too_many_requests( + hass: HomeAssistant, entry: MockConfigEntry +) -> None: + """Test Wallbox setup with authentication error.""" + + await setup_integration(hass, entry) + assert entry.state is ConfigEntryState.LOADED + + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.getChargerStatus", + new=Mock(side_effect=http_429_error), + ), + ): wallbox = hass.data[DOMAIN][entry.entry_id] await wallbox.async_refresh() @@ -109,18 +156,16 @@ async def test_wallbox_refresh_failed_connection_error( await setup_integration(hass, entry) assert entry.state is ConfigEntryState.LOADED - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=200, - ) - mock_request.get( - "https://api.wall-box.com/chargers/status/12345", - json=test_response, - status_code=403, - ) - + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.pauseChargingSession", + new=Mock(side_effect=http_403_error), + ), + ): wallbox = hass.data[DOMAIN][entry.entry_id] await wallbox.async_refresh() diff --git a/tests/components/wallbox/test_lock.py b/tests/components/wallbox/test_lock.py index 1d48e53b515..5842d708f11 100644 --- a/tests/components/wallbox/test_lock.py +++ b/tests/components/wallbox/test_lock.py @@ -1,15 +1,18 @@ """Test Wallbox Lock component.""" +from unittest.mock import Mock, patch + import pytest -import requests_mock from homeassistant.components.lock import SERVICE_LOCK, SERVICE_UNLOCK from homeassistant.components.wallbox.const import CHARGER_LOCKED_UNLOCKED_KEY from homeassistant.const import ATTR_ENTITY_ID from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError from . import ( authorisation_response, + http_429_error, setup_integration, setup_integration_platform_not_ready, setup_integration_read_only, @@ -28,18 +31,20 @@ async def test_wallbox_lock_class(hass: HomeAssistant, entry: MockConfigEntry) - assert state assert state.state == "unlocked" - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=200, - ) - mock_request.put( - "https://api.wall-box.com/v2/charger/12345", - json={CHARGER_LOCKED_UNLOCKED_KEY: False}, - status_code=200, - ) - + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.lockCharger", + new=Mock(return_value={CHARGER_LOCKED_UNLOCKED_KEY: False}), + ), + patch( + "homeassistant.components.wallbox.Wallbox.unlockCharger", + new=Mock(return_value={CHARGER_LOCKED_UNLOCKED_KEY: False}), + ), + ): await hass.services.async_call( "lock", SERVICE_LOCK, @@ -66,36 +71,73 @@ async def test_wallbox_lock_class_connection_error( await setup_integration(hass, entry) - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=200, - ) - mock_request.put( - "https://api.wall-box.com/v2/charger/12345", - json={CHARGER_LOCKED_UNLOCKED_KEY: False}, - status_code=404, + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.lockCharger", + new=Mock(side_effect=ConnectionError), + ), + pytest.raises(ConnectionError), + ): + await hass.services.async_call( + "lock", + SERVICE_LOCK, + { + ATTR_ENTITY_ID: MOCK_LOCK_ENTITY_ID, + }, + blocking=True, ) - with pytest.raises(ConnectionError): - await hass.services.async_call( - "lock", - SERVICE_LOCK, - { - ATTR_ENTITY_ID: MOCK_LOCK_ENTITY_ID, - }, - blocking=True, - ) - with pytest.raises(ConnectionError): - await hass.services.async_call( - "lock", - SERVICE_UNLOCK, - { - ATTR_ENTITY_ID: MOCK_LOCK_ENTITY_ID, - }, - blocking=True, - ) + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.lockCharger", + new=Mock(side_effect=ConnectionError), + ), + patch( + "homeassistant.components.wallbox.Wallbox.unlockCharger", + new=Mock(side_effect=ConnectionError), + ), + pytest.raises(ConnectionError), + ): + await hass.services.async_call( + "lock", + SERVICE_UNLOCK, + { + ATTR_ENTITY_ID: MOCK_LOCK_ENTITY_ID, + }, + blocking=True, + ) + + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.lockCharger", + new=Mock(side_effect=http_429_error), + ), + patch( + "homeassistant.components.wallbox.Wallbox.unlockCharger", + new=Mock(side_effect=http_429_error), + ), + pytest.raises(HomeAssistantError), + ): + await hass.services.async_call( + "lock", + SERVICE_UNLOCK, + { + ATTR_ENTITY_ID: MOCK_LOCK_ENTITY_ID, + }, + blocking=True, + ) async def test_wallbox_lock_class_authentication_error( diff --git a/tests/components/wallbox/test_number.py b/tests/components/wallbox/test_number.py index c319668c161..c603ae24106 100644 --- a/tests/components/wallbox/test_number.py +++ b/tests/components/wallbox/test_number.py @@ -1,22 +1,26 @@ """Test Wallbox Switch component.""" +from unittest.mock import Mock, patch + import pytest -import requests_mock from homeassistant.components.input_number import ATTR_VALUE, SERVICE_SET_VALUE from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN -from homeassistant.components.wallbox import InvalidAuth from homeassistant.components.wallbox.const import ( CHARGER_ENERGY_PRICE_KEY, CHARGER_MAX_CHARGING_CURRENT_KEY, CHARGER_MAX_ICP_CURRENT_KEY, ) +from homeassistant.components.wallbox.coordinator import InvalidAuth from homeassistant.const import ATTR_ENTITY_ID from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryAuthFailed +from homeassistant.exceptions import HomeAssistantError from . import ( authorisation_response, + http_403_error, + http_404_error, + http_429_error, setup_integration, setup_integration_bidir, setup_integration_platform_not_ready, @@ -29,6 +33,14 @@ from .const import ( from tests.common import MockConfigEntry +mock_wallbox = Mock() +mock_wallbox.authenticate = Mock(return_value=authorisation_response) +mock_wallbox.setEnergyCost = Mock(return_value={CHARGER_ENERGY_PRICE_KEY: 1.1}) +mock_wallbox.setMaxChargingCurrent = Mock( + return_value={CHARGER_MAX_CHARGING_CURRENT_KEY: 20} +) +mock_wallbox.setIcpMaxCurrent = Mock(return_value={CHARGER_MAX_ICP_CURRENT_KEY: 10}) + async def test_wallbox_number_class( hass: HomeAssistant, entry: MockConfigEntry @@ -37,17 +49,16 @@ async def test_wallbox_number_class( await setup_integration(hass, entry) - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=200, - ) - mock_request.put( - "https://api.wall-box.com/v2/charger/12345", - json={CHARGER_MAX_CHARGING_CURRENT_KEY: 20}, - status_code=200, - ) + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.setMaxChargingCurrent", + new=Mock(return_value={CHARGER_MAX_CHARGING_CURRENT_KEY: 20}), + ), + ): state = hass.states.get(MOCK_NUMBER_ENTITY_ID) assert state.attributes["min"] == 6 assert state.attributes["max"] == 25 @@ -82,19 +93,16 @@ async def test_wallbox_number_energy_class( await setup_integration(hass, entry) - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=200, - ) - - mock_request.post( - "https://api.wall-box.com/chargers/config/12345", - json={CHARGER_ENERGY_PRICE_KEY: 1.1}, - status_code=200, - ) - + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.setEnergyCost", + new=Mock(return_value={CHARGER_ENERGY_PRICE_KEY: 1.1}), + ), + ): await hass.services.async_call( "number", SERVICE_SET_VALUE, @@ -113,59 +121,113 @@ async def test_wallbox_number_class_connection_error( await setup_integration(hass, entry) - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=200, - ) - mock_request.put( - "https://api.wall-box.com/v2/charger/12345", - json={CHARGER_MAX_CHARGING_CURRENT_KEY: 20}, - status_code=404, + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.setMaxChargingCurrent", + new=Mock(side_effect=http_404_error), + ), + pytest.raises(HomeAssistantError), + ): + await hass.services.async_call( + "number", + SERVICE_SET_VALUE, + { + ATTR_ENTITY_ID: MOCK_NUMBER_ENTITY_ID, + ATTR_VALUE: 20, + }, + blocking=True, ) - with pytest.raises(ConnectionError): - await hass.services.async_call( - "number", - SERVICE_SET_VALUE, - { - ATTR_ENTITY_ID: MOCK_NUMBER_ENTITY_ID, - ATTR_VALUE: 20, - }, - blocking=True, - ) - -async def test_wallbox_number_class_energy_price_connection_error( +async def test_wallbox_number_class_too_many_requests( hass: HomeAssistant, entry: MockConfigEntry ) -> None: """Test wallbox sensor class.""" await setup_integration(hass, entry) - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=200, - ) - mock_request.post( - "https://api.wall-box.com/chargers/config/12345", - json={CHARGER_ENERGY_PRICE_KEY: 1.1}, - status_code=404, + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.setMaxChargingCurrent", + new=Mock(side_effect=http_429_error), + ), + pytest.raises(HomeAssistantError), + ): + await hass.services.async_call( + "number", + SERVICE_SET_VALUE, + { + ATTR_ENTITY_ID: MOCK_NUMBER_ENTITY_ID, + ATTR_VALUE: 20, + }, + blocking=True, ) - with pytest.raises(ConnectionError): - await hass.services.async_call( - "number", - SERVICE_SET_VALUE, - { - ATTR_ENTITY_ID: MOCK_NUMBER_ENTITY_ENERGY_PRICE_ID, - ATTR_VALUE: 1.1, - }, - blocking=True, - ) + +async def test_wallbox_number_class_energy_price_update_failed( + hass: HomeAssistant, entry: MockConfigEntry +) -> None: + """Test wallbox sensor class.""" + + await setup_integration(hass, entry) + + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.setEnergyCost", + new=Mock(side_effect=http_429_error), + ), + pytest.raises(HomeAssistantError), + ): + await hass.services.async_call( + "number", + SERVICE_SET_VALUE, + { + ATTR_ENTITY_ID: MOCK_NUMBER_ENTITY_ENERGY_PRICE_ID, + ATTR_VALUE: 1.1, + }, + blocking=True, + ) + + +async def test_wallbox_number_class_energy_price_update_connection_error( + hass: HomeAssistant, entry: MockConfigEntry +) -> None: + """Test wallbox sensor class.""" + + await setup_integration(hass, entry) + + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.setEnergyCost", + new=Mock(side_effect=http_404_error), + ), + pytest.raises(HomeAssistantError), + ): + await hass.services.async_call( + "number", + SERVICE_SET_VALUE, + { + ATTR_ENTITY_ID: MOCK_NUMBER_ENTITY_ENERGY_PRICE_ID, + ATTR_VALUE: 1.1, + }, + blocking=True, + ) async def test_wallbox_number_class_energy_price_auth_error( @@ -175,28 +237,26 @@ async def test_wallbox_number_class_energy_price_auth_error( await setup_integration(hass, entry) - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=200, + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.setEnergyCost", + new=Mock(side_effect=http_429_error), + ), + pytest.raises(HomeAssistantError), + ): + await hass.services.async_call( + "number", + SERVICE_SET_VALUE, + { + ATTR_ENTITY_ID: MOCK_NUMBER_ENTITY_ENERGY_PRICE_ID, + ATTR_VALUE: 1.1, + }, + blocking=True, ) - mock_request.post( - "https://api.wall-box.com/chargers/config/12345", - json={CHARGER_ENERGY_PRICE_KEY: 1.1}, - status_code=403, - ) - - with pytest.raises(ConfigEntryAuthFailed): - await hass.services.async_call( - "number", - SERVICE_SET_VALUE, - { - ATTR_ENTITY_ID: MOCK_NUMBER_ENTITY_ENERGY_PRICE_ID, - ATTR_VALUE: 1.1, - }, - blocking=True, - ) async def test_wallbox_number_class_platform_not_ready( @@ -218,19 +278,16 @@ async def test_wallbox_number_class_icp_energy( await setup_integration(hass, entry) - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=200, - ) - - mock_request.post( - "https://api.wall-box.com/chargers/config/12345", - json={CHARGER_MAX_ICP_CURRENT_KEY: 10}, - status_code=200, - ) - + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.setIcpMaxCurrent", + new=Mock(return_value={CHARGER_MAX_ICP_CURRENT_KEY: 10}), + ), + ): await hass.services.async_call( NUMBER_DOMAIN, SERVICE_SET_VALUE, @@ -249,28 +306,26 @@ async def test_wallbox_number_class_icp_energy_auth_error( await setup_integration(hass, entry) - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=200, + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.setIcpMaxCurrent", + new=Mock(side_effect=http_403_error), + ), + pytest.raises(InvalidAuth), + ): + await hass.services.async_call( + NUMBER_DOMAIN, + SERVICE_SET_VALUE, + { + ATTR_ENTITY_ID: MOCK_NUMBER_ENTITY_ICP_CURRENT_ID, + ATTR_VALUE: 10, + }, + blocking=True, ) - mock_request.post( - "https://api.wall-box.com/chargers/config/12345", - json={CHARGER_MAX_ICP_CURRENT_KEY: 10}, - status_code=403, - ) - - with pytest.raises(InvalidAuth): - await hass.services.async_call( - NUMBER_DOMAIN, - SERVICE_SET_VALUE, - { - ATTR_ENTITY_ID: MOCK_NUMBER_ENTITY_ICP_CURRENT_ID, - ATTR_VALUE: 10, - }, - blocking=True, - ) async def test_wallbox_number_class_icp_energy_connection_error( @@ -280,25 +335,52 @@ async def test_wallbox_number_class_icp_energy_connection_error( await setup_integration(hass, entry) - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=200, - ) - mock_request.post( - "https://api.wall-box.com/chargers/config/12345", - json={CHARGER_MAX_ICP_CURRENT_KEY: 10}, - status_code=404, + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.setIcpMaxCurrent", + new=Mock(side_effect=http_404_error), + ), + pytest.raises(HomeAssistantError), + ): + await hass.services.async_call( + NUMBER_DOMAIN, + SERVICE_SET_VALUE, + { + ATTR_ENTITY_ID: MOCK_NUMBER_ENTITY_ICP_CURRENT_ID, + ATTR_VALUE: 10, + }, + blocking=True, ) - with pytest.raises(ConnectionError): - await hass.services.async_call( - NUMBER_DOMAIN, - SERVICE_SET_VALUE, - { - ATTR_ENTITY_ID: MOCK_NUMBER_ENTITY_ICP_CURRENT_ID, - ATTR_VALUE: 10, - }, - blocking=True, - ) + +async def test_wallbox_number_class_icp_energy_too_many_request( + hass: HomeAssistant, entry: MockConfigEntry +) -> None: + """Test wallbox sensor class.""" + + await setup_integration(hass, entry) + + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.setIcpMaxCurrent", + new=Mock(side_effect=http_429_error), + ), + pytest.raises(HomeAssistantError), + ): + await hass.services.async_call( + NUMBER_DOMAIN, + SERVICE_SET_VALUE, + { + ATTR_ENTITY_ID: MOCK_NUMBER_ENTITY_ICP_CURRENT_ID, + ATTR_VALUE: 10, + }, + blocking=True, + ) diff --git a/tests/components/wallbox/test_select.py b/tests/components/wallbox/test_select.py index 516b1e87c27..f59a8367b41 100644 --- a/tests/components/wallbox/test_select.py +++ b/tests/components/wallbox/test_select.py @@ -16,6 +16,7 @@ from homeassistant.core import HomeAssistant, HomeAssistantError from . import ( authorisation_response, http_404_error, + http_429_error, setup_integration_select, test_response, test_response_eco_mode, @@ -109,7 +110,41 @@ async def test_wallbox_select_class_error( "homeassistant.components.wallbox.Wallbox.enableEcoSmart", new=Mock(side_effect=error), ), - pytest.raises(HomeAssistantError, match="Error communicating with Wallbox API"), + pytest.raises(HomeAssistantError), + ): + await hass.services.async_call( + SELECT_DOMAIN, + SERVICE_SELECT_OPTION, + { + ATTR_ENTITY_ID: MOCK_SELECT_ENTITY_ID, + ATTR_OPTION: mode, + }, + blocking=True, + ) + + +@pytest.mark.parametrize(("mode", "response"), TEST_OPTIONS) +async def test_wallbox_select_too_many_requests_error( + hass: HomeAssistant, + entry: MockConfigEntry, + mode, + response, + mock_authenticate, +) -> None: + """Test wallbox select class connection error.""" + + await setup_integration_select(hass, entry, response) + + with ( + patch( + "homeassistant.components.wallbox.Wallbox.disableEcoSmart", + new=Mock(side_effect=http_429_error), + ), + patch( + "homeassistant.components.wallbox.Wallbox.enableEcoSmart", + new=Mock(side_effect=http_429_error), + ), + pytest.raises(HomeAssistantError), ): await hass.services.async_call( SELECT_DOMAIN, diff --git a/tests/components/wallbox/test_switch.py b/tests/components/wallbox/test_switch.py index b7c3a81dc73..eb983ca44ce 100644 --- a/tests/components/wallbox/test_switch.py +++ b/tests/components/wallbox/test_switch.py @@ -1,15 +1,16 @@ """Test Wallbox Lock component.""" +from unittest.mock import Mock, patch + import pytest -import requests_mock from homeassistant.components.switch import SERVICE_TURN_OFF, SERVICE_TURN_ON from homeassistant.components.wallbox.const import CHARGER_STATUS_ID_KEY from homeassistant.const import ATTR_ENTITY_ID from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryAuthFailed +from homeassistant.exceptions import HomeAssistantError -from . import authorisation_response, setup_integration +from . import authorisation_response, http_404_error, http_429_error, setup_integration from .const import MOCK_SWITCH_ENTITY_ID from tests.common import MockConfigEntry @@ -26,18 +27,20 @@ async def test_wallbox_switch_class( assert state assert state.state == "on" - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=200, - ) - mock_request.post( - "https://api.wall-box.com/v3/chargers/12345/remote-action", - json={CHARGER_STATUS_ID_KEY: 193}, - status_code=200, - ) - + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.pauseChargingSession", + new=Mock(return_value={CHARGER_STATUS_ID_KEY: 193}), + ), + patch( + "homeassistant.components.wallbox.Wallbox.resumeChargingSession", + new=Mock(return_value={CHARGER_STATUS_ID_KEY: 193}), + ), + ): await hass.services.async_call( "switch", SERVICE_TURN_ON, @@ -64,72 +67,52 @@ async def test_wallbox_switch_class_connection_error( await setup_integration(hass, entry) - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=200, - ) - mock_request.post( - "https://api.wall-box.com/v3/chargers/12345/remote-action", - json={CHARGER_STATUS_ID_KEY: 193}, - status_code=404, + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.resumeChargingSession", + new=Mock(side_effect=http_404_error), + ), + pytest.raises(HomeAssistantError), + ): + # Test behavior when a connection error occurs + await hass.services.async_call( + "switch", + SERVICE_TURN_ON, + { + ATTR_ENTITY_ID: MOCK_SWITCH_ENTITY_ID, + }, + blocking=True, ) - with pytest.raises(ConnectionError): - await hass.services.async_call( - "switch", - SERVICE_TURN_ON, - { - ATTR_ENTITY_ID: MOCK_SWITCH_ENTITY_ID, - }, - blocking=True, - ) - with pytest.raises(ConnectionError): - await hass.services.async_call( - "switch", - SERVICE_TURN_OFF, - { - ATTR_ENTITY_ID: MOCK_SWITCH_ENTITY_ID, - }, - blocking=True, - ) - -async def test_wallbox_switch_class_authentication_error( +async def test_wallbox_switch_class_too_many_requests( hass: HomeAssistant, entry: MockConfigEntry ) -> None: """Test wallbox switch class connection error.""" await setup_integration(hass, entry) - with requests_mock.Mocker() as mock_request: - mock_request.get( - "https://user-api.wall-box.com/users/signin", - json=authorisation_response, - status_code=200, + with ( + patch( + "homeassistant.components.wallbox.Wallbox.authenticate", + new=Mock(return_value=authorisation_response), + ), + patch( + "homeassistant.components.wallbox.Wallbox.resumeChargingSession", + new=Mock(side_effect=http_429_error), + ), + pytest.raises(HomeAssistantError), + ): + # Test behavior when a connection error occurs + await hass.services.async_call( + "switch", + SERVICE_TURN_ON, + { + ATTR_ENTITY_ID: MOCK_SWITCH_ENTITY_ID, + }, + blocking=True, ) - mock_request.post( - "https://api.wall-box.com/v3/chargers/12345/remote-action", - json={CHARGER_STATUS_ID_KEY: 193}, - status_code=403, - ) - - with pytest.raises(ConfigEntryAuthFailed): - await hass.services.async_call( - "switch", - SERVICE_TURN_ON, - { - ATTR_ENTITY_ID: MOCK_SWITCH_ENTITY_ID, - }, - blocking=True, - ) - with pytest.raises(ConfigEntryAuthFailed): - await hass.services.async_call( - "switch", - SERVICE_TURN_OFF, - { - ATTR_ENTITY_ID: MOCK_SWITCH_ENTITY_ID, - }, - blocking=True, - )