Bump bimmer_connected to 0.16.4 (#129838)
parent
3a667bce8c
commit
8abbc4abbc
|
@ -7,7 +7,11 @@ from typing import Any
|
|||
|
||||
from bimmer_connected.api.authentication import MyBMWAuthentication
|
||||
from bimmer_connected.api.regions import get_region_from_name
|
||||
from bimmer_connected.models import MyBMWAPIError, MyBMWAuthError
|
||||
from bimmer_connected.models import (
|
||||
MyBMWAPIError,
|
||||
MyBMWAuthError,
|
||||
MyBMWCaptchaMissingError,
|
||||
)
|
||||
from httpx import RequestError
|
||||
import voluptuous as vol
|
||||
|
||||
|
@ -54,6 +58,8 @@ async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> dict[str,
|
|||
|
||||
try:
|
||||
await auth.login()
|
||||
except MyBMWCaptchaMissingError as ex:
|
||||
raise MissingCaptcha from ex
|
||||
except MyBMWAuthError as ex:
|
||||
raise InvalidAuth from ex
|
||||
except (MyBMWAPIError, RequestError) as ex:
|
||||
|
@ -98,6 +104,8 @@ class BMWConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||
CONF_REFRESH_TOKEN: info.get(CONF_REFRESH_TOKEN),
|
||||
CONF_GCID: info.get(CONF_GCID),
|
||||
}
|
||||
except MissingCaptcha:
|
||||
errors["base"] = "missing_captcha"
|
||||
except CannotConnect:
|
||||
errors["base"] = "cannot_connect"
|
||||
except InvalidAuth:
|
||||
|
@ -192,3 +200,7 @@ class CannotConnect(HomeAssistantError):
|
|||
|
||||
class InvalidAuth(HomeAssistantError):
|
||||
"""Error to indicate there is invalid auth."""
|
||||
|
||||
|
||||
class MissingCaptcha(HomeAssistantError):
|
||||
"""Error to indicate the captcha token is missing."""
|
||||
|
|
|
@ -7,7 +7,12 @@ import logging
|
|||
|
||||
from bimmer_connected.account import MyBMWAccount
|
||||
from bimmer_connected.api.regions import get_region_from_name
|
||||
from bimmer_connected.models import GPSPosition, MyBMWAPIError, MyBMWAuthError
|
||||
from bimmer_connected.models import (
|
||||
GPSPosition,
|
||||
MyBMWAPIError,
|
||||
MyBMWAuthError,
|
||||
MyBMWCaptchaMissingError,
|
||||
)
|
||||
from httpx import RequestError
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
@ -61,6 +66,12 @@ class BMWDataUpdateCoordinator(DataUpdateCoordinator[None]):
|
|||
|
||||
try:
|
||||
await self.account.get_vehicles()
|
||||
except MyBMWCaptchaMissingError as err:
|
||||
# If a captcha is required (user/password login flow), always trigger the reauth flow
|
||||
raise ConfigEntryAuthFailed(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="missing_captcha",
|
||||
) from err
|
||||
except MyBMWAuthError as err:
|
||||
# Allow one retry interval before raising AuthFailed to avoid flaky API issues
|
||||
if self.last_update_success:
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
"iot_class": "cloud_polling",
|
||||
"loggers": ["bimmer_connected"],
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["bimmer-connected[china]==0.16.3"]
|
||||
"requirements": ["bimmer-connected[china]==0.16.4"]
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
},
|
||||
"error": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]"
|
||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
||||
"missing_captcha": "Captcha validation missing"
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_account%]",
|
||||
|
@ -200,6 +201,9 @@
|
|||
"exceptions": {
|
||||
"invalid_poi": {
|
||||
"message": "Invalid data for point of interest: {poi_exception}"
|
||||
},
|
||||
"missing_captcha": {
|
||||
"message": "Login requires captcha validation"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -576,7 +576,7 @@ beautifulsoup4==4.12.3
|
|||
# beewi-smartclim==0.0.10
|
||||
|
||||
# homeassistant.components.bmw_connected_drive
|
||||
bimmer-connected[china]==0.16.3
|
||||
bimmer-connected[china]==0.16.4
|
||||
|
||||
# homeassistant.components.bizkaibus
|
||||
bizkaibus==0.1.1
|
||||
|
|
|
@ -510,7 +510,7 @@ base36==0.1.1
|
|||
beautifulsoup4==4.12.3
|
||||
|
||||
# homeassistant.components.bmw_connected_drive
|
||||
bimmer-connected[china]==0.16.3
|
||||
bimmer-connected[china]==0.16.4
|
||||
|
||||
# homeassistant.components.eq3btsmart
|
||||
# homeassistant.components.esphome
|
||||
|
|
|
@ -4,8 +4,13 @@ from copy import deepcopy
|
|||
from unittest.mock import patch
|
||||
|
||||
from bimmer_connected.api.authentication import MyBMWAuthentication
|
||||
from bimmer_connected.models import MyBMWAPIError, MyBMWAuthError
|
||||
from bimmer_connected.models import (
|
||||
MyBMWAPIError,
|
||||
MyBMWAuthError,
|
||||
MyBMWCaptchaMissingError,
|
||||
)
|
||||
from httpx import RequestError
|
||||
import pytest
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.bmw_connected_drive.config_flow import DOMAIN
|
||||
|
@ -311,3 +316,31 @@ async def test_reconfigure_unique_id_abort(hass: HomeAssistant) -> None:
|
|||
assert result2["type"] is FlowResultType.ABORT
|
||||
assert result2["reason"] == "account_mismatch"
|
||||
assert config_entry.data == FIXTURE_COMPLETE_ENTRY
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("bmw_fixture")
|
||||
async def test_captcha_flow_not_set(hass: HomeAssistant) -> None:
|
||||
"""Test the external flow with captcha failing once and succeeding the second time."""
|
||||
|
||||
TEST_REGION = "north_america"
|
||||
|
||||
# Start flow and open form
|
||||
# Start flow and open form
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "user"
|
||||
|
||||
# Add login data
|
||||
with patch(
|
||||
"bimmer_connected.api.authentication.MyBMWAuthentication._login_row_na",
|
||||
side_effect=MyBMWCaptchaMissingError(
|
||||
"Missing hCaptcha token for North America login"
|
||||
),
|
||||
):
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={**FIXTURE_USER_INPUT, CONF_REGION: TEST_REGION},
|
||||
)
|
||||
assert result["errors"]["base"] == "missing_captcha"
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
"""Test BMW coordinator."""
|
||||
|
||||
from copy import deepcopy
|
||||
from datetime import timedelta
|
||||
from unittest.mock import patch
|
||||
|
||||
from bimmer_connected.models import MyBMWAPIError, MyBMWAuthError
|
||||
from bimmer_connected.models import (
|
||||
MyBMWAPIError,
|
||||
MyBMWAuthError,
|
||||
MyBMWCaptchaMissingError,
|
||||
)
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.bmw_connected_drive import DOMAIN as BMW_DOMAIN
|
||||
from homeassistant.const import CONF_REGION
|
||||
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed
|
||||
from homeassistant.helpers import issue_registry as ir
|
||||
|
@ -122,3 +128,38 @@ async def test_init_reauth(
|
|||
f"config_entry_reauth_{BMW_DOMAIN}_{config_entry.entry_id}",
|
||||
)
|
||||
assert reauth_issue.active is True
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("bmw_fixture")
|
||||
async def test_captcha_reauth(
|
||||
hass: HomeAssistant,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test the reauth form."""
|
||||
TEST_REGION = "north_america"
|
||||
|
||||
config_entry_fixure = deepcopy(FIXTURE_CONFIG_ENTRY)
|
||||
config_entry_fixure["data"][CONF_REGION] = TEST_REGION
|
||||
config_entry = MockConfigEntry(**config_entry_fixure)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
coordinator = config_entry.runtime_data.coordinator
|
||||
|
||||
assert coordinator.last_update_success is True
|
||||
|
||||
freezer.tick(timedelta(minutes=10, seconds=1))
|
||||
with patch(
|
||||
"bimmer_connected.account.MyBMWAccount.get_vehicles",
|
||||
side_effect=MyBMWCaptchaMissingError(
|
||||
"Missing hCaptcha token for North America login"
|
||||
),
|
||||
):
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert coordinator.last_update_success is False
|
||||
assert isinstance(coordinator.last_exception, ConfigEntryAuthFailed) is True
|
||||
assert coordinator.last_exception.translation_key == "missing_captcha"
|
||||
|
|
Loading…
Reference in New Issue