Skip to content

Commit e78a19a

Browse files
authored
Reolink translate key (#140821)
* Add firmware exception translations * Add test * Much nicer syntax * Check if translation key is present in string.json * fix tests * fix typo
1 parent 07bce88 commit e78a19a

File tree

5 files changed

+53
-14
lines changed

5 files changed

+53
-14
lines changed

homeassistant/components/reolink/strings.json

+6
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,12 @@
103103
},
104104
"config_entry_not_ready": {
105105
"message": "Error while trying to set up {host}: {err}"
106+
},
107+
"update_already_running": {
108+
"message": "Reolink firmware update already running, wait on completion before starting another"
109+
},
110+
"firmware_rate_limit": {
111+
"message": "Reolink firmware update server reached hourly rate limit: updating can be tried again in 1 hour"
106112
}
107113
},
108114
"issues": {

homeassistant/components/reolink/update.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
ReolinkHostCoordinatorEntity,
3232
ReolinkHostEntityDescription,
3333
)
34-
from .util import ReolinkConfigEntry, ReolinkData
34+
from .util import ReolinkConfigEntry, ReolinkData, raise_translated_error
3535

3636
PARALLEL_UPDATES = 0
3737
RESUME_AFTER_INSTALL = 15
@@ -184,6 +184,7 @@ async def async_release_notes(self) -> str | None:
184184
f"## Release notes\n\n{new_firmware.release_notes}"
185185
)
186186

187+
@raise_translated_error
187188
async def async_install(
188189
self, version: str | None, backup: bool, **kwargs: Any
189190
) -> None:
@@ -196,6 +197,8 @@ async def async_install(
196197
try:
197198
await self._host.api.update_firmware(self._channel)
198199
except ReolinkError as err:
200+
if err.translation_key:
201+
raise
199202
raise HomeAssistantError(
200203
translation_domain=DOMAIN,
201204
translation_key="firmware_install_error",

homeassistant/components/reolink/util.py

+23-12
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
2828
from homeassistant.helpers import device_registry as dr
2929
from homeassistant.helpers.storage import Store
30+
from homeassistant.helpers.translation import async_get_exception_message
3031
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
3132

3233
from .const import DOMAIN
@@ -97,6 +98,16 @@ def get_device_uid_and_ch(
9798
return (device_uid, ch, is_chime)
9899

99100

101+
def check_translation_key(err: ReolinkError) -> str | None:
102+
"""Check if the translation key from the upstream library is present."""
103+
if not err.translation_key:
104+
return None
105+
if async_get_exception_message(DOMAIN, err.translation_key) == err.translation_key:
106+
# translation key not found in strings.json
107+
return None
108+
return err.translation_key
109+
110+
100111
# Decorators
101112
def raise_translated_error[**P, R](
102113
func: Callable[P, Awaitable[R]],
@@ -110,73 +121,73 @@ async def decorator_raise_translated_error(*args: P.args, **kwargs: P.kwargs) ->
110121
except InvalidParameterError as err:
111122
raise ServiceValidationError(
112123
translation_domain=DOMAIN,
113-
translation_key="invalid_parameter",
124+
translation_key=check_translation_key(err) or "invalid_parameter",
114125
translation_placeholders={"err": str(err)},
115126
) from err
116127
except ApiError as err:
117128
raise HomeAssistantError(
118129
translation_domain=DOMAIN,
119-
translation_key="api_error",
130+
translation_key=check_translation_key(err) or "api_error",
120131
translation_placeholders={"err": str(err)},
121132
) from err
122133
except InvalidContentTypeError as err:
123134
raise HomeAssistantError(
124135
translation_domain=DOMAIN,
125-
translation_key="invalid_content_type",
136+
translation_key=check_translation_key(err) or "invalid_content_type",
126137
translation_placeholders={"err": str(err)},
127138
) from err
128139
except CredentialsInvalidError as err:
129140
raise HomeAssistantError(
130141
translation_domain=DOMAIN,
131-
translation_key="invalid_credentials",
142+
translation_key=check_translation_key(err) or "invalid_credentials",
132143
translation_placeholders={"err": str(err)},
133144
) from err
134145
except LoginError as err:
135146
raise HomeAssistantError(
136147
translation_domain=DOMAIN,
137-
translation_key="login_error",
148+
translation_key=check_translation_key(err) or "login_error",
138149
translation_placeholders={"err": str(err)},
139150
) from err
140151
except NoDataError as err:
141152
raise HomeAssistantError(
142153
translation_domain=DOMAIN,
143-
translation_key="no_data",
154+
translation_key=check_translation_key(err) or "no_data",
144155
translation_placeholders={"err": str(err)},
145156
) from err
146157
except UnexpectedDataError as err:
147158
raise HomeAssistantError(
148159
translation_domain=DOMAIN,
149-
translation_key="unexpected_data",
160+
translation_key=check_translation_key(err) or "unexpected_data",
150161
translation_placeholders={"err": str(err)},
151162
) from err
152163
except NotSupportedError as err:
153164
raise HomeAssistantError(
154165
translation_domain=DOMAIN,
155-
translation_key="not_supported",
166+
translation_key=check_translation_key(err) or "not_supported",
156167
translation_placeholders={"err": str(err)},
157168
) from err
158169
except SubscriptionError as err:
159170
raise HomeAssistantError(
160171
translation_domain=DOMAIN,
161-
translation_key="subscription_error",
172+
translation_key=check_translation_key(err) or "subscription_error",
162173
translation_placeholders={"err": str(err)},
163174
) from err
164175
except ReolinkConnectionError as err:
165176
raise HomeAssistantError(
166177
translation_domain=DOMAIN,
167-
translation_key="connection_error",
178+
translation_key=check_translation_key(err) or "connection_error",
168179
translation_placeholders={"err": str(err)},
169180
) from err
170181
except ReolinkTimeoutError as err:
171182
raise HomeAssistantError(
172183
translation_domain=DOMAIN,
173-
translation_key="timeout",
184+
translation_key=check_translation_key(err) or "timeout",
174185
translation_placeholders={"err": str(err)},
175186
) from err
176187
except ReolinkError as err:
177188
raise HomeAssistantError(
178189
translation_domain=DOMAIN,
179-
translation_key="unexpected",
190+
translation_key=check_translation_key(err) or "unexpected",
180191
translation_placeholders={"err": str(err)},
181192
) from err
182193

tests/components/reolink/test_update.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from freezegun.api import FrozenDateTimeFactory
88
import pytest
9-
from reolink_aio.exceptions import ReolinkError
9+
from reolink_aio.exceptions import ApiError, ReolinkError
1010
from reolink_aio.software_version import NewSoftwareVersion
1111

1212
from homeassistant.components.reolink.update import POLL_AFTER_INSTALL, POLL_PROGRESS
@@ -144,6 +144,17 @@ async def test_update_firm(
144144
blocking=True,
145145
)
146146

147+
reolink_connect.update_firmware.side_effect = ApiError(
148+
"Test error", translation_key="firmware_rate_limit"
149+
)
150+
with pytest.raises(HomeAssistantError):
151+
await hass.services.async_call(
152+
UPDATE_DOMAIN,
153+
SERVICE_INSTALL,
154+
{ATTR_ENTITY_ID: entity_id},
155+
blocking=True,
156+
)
157+
147158
# test _async_update_future
148159
reolink_connect.camera_sw_version.return_value = "v3.3.0.226_23031644"
149160
reolink_connect.firmware_update_available.return_value = False

tests/components/reolink/test_util.py

+8
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@
4040
ApiError("Test error"),
4141
HomeAssistantError,
4242
),
43+
(
44+
ApiError("Test error", translation_key="firmware_rate_limit"),
45+
HomeAssistantError,
46+
),
47+
(
48+
ApiError("Test error", translation_key="not_in_strings.json"),
49+
HomeAssistantError,
50+
),
4351
(
4452
CredentialsInvalidError("Test error"),
4553
HomeAssistantError,

0 commit comments

Comments
 (0)