Wallbox Integration - Add repair action for insufficient rights (#148610)

Co-authored-by: Norbert Rittel <norbert@rittel.de>
This commit is contained in:
Hessel 2025-07-14 10:30:48 +02:00 committed by GitHub
parent 5e50c723a7
commit eae9f4f925
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 58 additions and 12 deletions

View File

@ -14,6 +14,7 @@ from wallbox import Wallbox
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, HomeAssistantError from homeassistant.exceptions import ConfigEntryAuthFailed, HomeAssistantError
from homeassistant.helpers import issue_registry as ir
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import ( from .const import (
@ -197,7 +198,6 @@ class WallboxCoordinator(DataUpdateCoordinator[dict[str, Any]]):
data[CHARGER_ECO_SMART_KEY] = EcoSmartMode.ECO_MODE data[CHARGER_ECO_SMART_KEY] = EcoSmartMode.ECO_MODE
elif eco_smart_mode == 1: elif eco_smart_mode == 1:
data[CHARGER_ECO_SMART_KEY] = EcoSmartMode.FULL_SOLAR data[CHARGER_ECO_SMART_KEY] = EcoSmartMode.FULL_SOLAR
return data # noqa: TRY300 return data # noqa: TRY300
except requests.exceptions.HTTPError as wallbox_connection_error: except requests.exceptions.HTTPError as wallbox_connection_error:
if wallbox_connection_error.response.status_code == 429: if wallbox_connection_error.response.status_code == 429:
@ -228,8 +228,10 @@ class WallboxCoordinator(DataUpdateCoordinator[dict[str, Any]]):
return data # noqa: TRY300 return data # noqa: TRY300
except requests.exceptions.HTTPError as wallbox_connection_error: except requests.exceptions.HTTPError as wallbox_connection_error:
if wallbox_connection_error.response.status_code == 403: if wallbox_connection_error.response.status_code == 403:
raise InvalidAuth( raise InsufficientRights(
translation_domain=DOMAIN, translation_key="invalid_auth" translation_domain=DOMAIN,
translation_key="insufficient_rights",
hass=self.hass,
) from wallbox_connection_error ) from wallbox_connection_error
if wallbox_connection_error.response.status_code == 429: if wallbox_connection_error.response.status_code == 429:
raise HomeAssistantError( raise HomeAssistantError(
@ -256,8 +258,10 @@ class WallboxCoordinator(DataUpdateCoordinator[dict[str, Any]]):
return data # noqa: TRY300 return data # noqa: TRY300
except requests.exceptions.HTTPError as wallbox_connection_error: except requests.exceptions.HTTPError as wallbox_connection_error:
if wallbox_connection_error.response.status_code == 403: if wallbox_connection_error.response.status_code == 403:
raise InvalidAuth( raise InsufficientRights(
translation_domain=DOMAIN, translation_key="invalid_auth" translation_domain=DOMAIN,
translation_key="insufficient_rights",
hass=self.hass,
) from wallbox_connection_error ) from wallbox_connection_error
if wallbox_connection_error.response.status_code == 429: if wallbox_connection_error.response.status_code == 429:
raise HomeAssistantError( raise HomeAssistantError(
@ -313,8 +317,10 @@ class WallboxCoordinator(DataUpdateCoordinator[dict[str, Any]]):
return data # noqa: TRY300 return data # noqa: TRY300
except requests.exceptions.HTTPError as wallbox_connection_error: except requests.exceptions.HTTPError as wallbox_connection_error:
if wallbox_connection_error.response.status_code == 403: if wallbox_connection_error.response.status_code == 403:
raise InvalidAuth( raise InsufficientRights(
translation_domain=DOMAIN, translation_key="invalid_auth" translation_domain=DOMAIN,
translation_key="insufficient_rights",
hass=self.hass,
) from wallbox_connection_error ) from wallbox_connection_error
if wallbox_connection_error.response.status_code == 429: if wallbox_connection_error.response.status_code == 429:
raise HomeAssistantError( raise HomeAssistantError(
@ -379,3 +385,34 @@ class WallboxCoordinator(DataUpdateCoordinator[dict[str, Any]]):
class InvalidAuth(HomeAssistantError): class InvalidAuth(HomeAssistantError):
"""Error to indicate there is invalid auth.""" """Error to indicate there is invalid auth."""
class InsufficientRights(HomeAssistantError):
"""Error to indicate there are insufficient right for the user."""
def __init__(
self,
*args: object,
translation_domain: str | None = None,
translation_key: str | None = None,
translation_placeholders: dict[str, str] | None = None,
hass: HomeAssistant,
) -> None:
"""Initialize exception."""
super().__init__(
self, *args, translation_domain, translation_key, translation_placeholders
)
self.hass = hass
self._create_insufficient_rights_issue()
def _create_insufficient_rights_issue(self) -> None:
"""Creates an issue for insufficient rights."""
ir.create_issue(
self.hass,
DOMAIN,
"insufficient_rights",
is_fixable=False,
severity=ir.IssueSeverity.ERROR,
learn_more_url="https://www.home-assistant.io/integrations/wallbox/#troubleshooting",
translation_key="insufficient_rights",
)

View File

@ -114,6 +114,12 @@
} }
} }
}, },
"issues": {
"insufficient_rights": {
"title": "The Wallbox account has insufficient rights.",
"description": "The Wallbox account has insufficient rights to lock/unlock and change the charging power. Please assign the user admin rights in the Wallbox portal."
}
},
"exceptions": { "exceptions": {
"api_failed": { "api_failed": {
"message": "Error communicating with Wallbox API" "message": "Error communicating with Wallbox API"
@ -123,6 +129,9 @@
}, },
"invalid_auth": { "invalid_auth": {
"message": "Invalid authentication" "message": "Invalid authentication"
},
"insufficient_rights": {
"message": "Insufficient rights for Wallbox user"
} }
} }
} }

View File

@ -5,7 +5,7 @@ from unittest.mock import patch
import pytest import pytest
from homeassistant.components.lock import SERVICE_LOCK, SERVICE_UNLOCK from homeassistant.components.lock import SERVICE_LOCK, SERVICE_UNLOCK
from homeassistant.components.wallbox.coordinator import InvalidAuth from homeassistant.components.wallbox.coordinator import InsufficientRights
from homeassistant.const import ATTR_ENTITY_ID from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
@ -96,7 +96,7 @@ async def test_wallbox_lock_class_error_handling(
with ( with (
patch.object(mock_wallbox, "lockCharger", side_effect=http_403_error), patch.object(mock_wallbox, "lockCharger", side_effect=http_403_error),
patch.object(mock_wallbox, "unlockCharger", side_effect=http_403_error), patch.object(mock_wallbox, "unlockCharger", side_effect=http_403_error),
pytest.raises(InvalidAuth), pytest.raises(InsufficientRights),
): ):
await hass.services.async_call( await hass.services.async_call(
"lock", "lock",

View File

@ -6,7 +6,7 @@ import pytest
from homeassistant.components.input_number import ATTR_VALUE, SERVICE_SET_VALUE from homeassistant.components.input_number import ATTR_VALUE, SERVICE_SET_VALUE
from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN
from homeassistant.components.wallbox.coordinator import InvalidAuth from homeassistant.components.wallbox.coordinator import InsufficientRights
from homeassistant.const import ATTR_ENTITY_ID from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
@ -130,7 +130,7 @@ async def test_wallbox_number_power_class_error_handling(
with ( with (
patch.object(mock_wallbox, "setMaxChargingCurrent", side_effect=http_403_error), patch.object(mock_wallbox, "setMaxChargingCurrent", side_effect=http_403_error),
pytest.raises(InvalidAuth), pytest.raises(InsufficientRights),
): ):
await hass.services.async_call( await hass.services.async_call(
NUMBER_DOMAIN, NUMBER_DOMAIN,
@ -202,7 +202,7 @@ async def test_wallbox_number_icp_power_class_error_handling(
with ( with (
patch.object(mock_wallbox, "setIcpMaxCurrent", side_effect=http_403_error), patch.object(mock_wallbox, "setIcpMaxCurrent", side_effect=http_403_error),
pytest.raises(InvalidAuth), pytest.raises(InsufficientRights),
): ):
await hass.services.async_call( await hass.services.async_call(
NUMBER_DOMAIN, NUMBER_DOMAIN,