Repository: bimmerconnected/bimmer_connected (python)

Issue:
Distances in miles instead of km
I just upgraded to the latest verion of the library and now all my data comes back with mi instead of km in the units. How can I change it back to km?

_Originally posted by @th0mi in https://github.com/bimmerconnected/bimmer_connected/discussions/448_

Pull request:
Add bmw-unit-preferences
## Proposed change
<!--
  Describe the big picture of your changes here to communicate to the
  maintainers why we should accept this pull request. If it fixes a bug
  or resolves a feature request, be sure to link to that issue in the
  additional information section.
-->
Apparently, one has to give unit preferences when making API calls now.

- https://github.com/evcc-io/evcc/issues/3526
- #448

It is possible to change between metric/imperial units by:
- initializing `MyBMWAccount(..., use_metric_units=False)`
- calling `account.set_use_metric_units(False)` after init.

## Type of change
- [x] Bugfix (non-breaking change which fixes an issue)
- [ ] New feature (which adds functionality to this library)
- [ ] Breaking change (fix/feature causing existing functionality to break)
- [ ] Code quality improvements to existing code or addition of tests

## Additional information
<!--
  Details are important, and help maintainers processing your PR.
  Please be sure to fill out additional details, if applicable.
-->

- This PR fixes or closes issue: fixes #450 
- This PR is related to issue: 

## Checklist
<!--
  Put an `x` in the boxes that apply. You can also fill these out after
  creating the PR. If you're unsure about any of them, don't hesitate to ask.
  We're here to help! This is simply a reminder of what we are going to look
  for before merging your code.
-->

- [ ] The code change is tested and works locally.
- [ ] Tests have been added to verify that the new code works.


Patch:
diff --git a/bimmer_connected/account.py b/bimmer_connected/account.py
index 67e7774..5c5d2ca 100644
--- a/bimmer_connected/account.py
+++ b/bimmer_connected/account.py
@@ -12,9 +12,9 @@ from bimmer_connected.api.authentication import MyBMWAuthentication
 from bimmer_connected.api.client import MyBMWClient, MyBMWClientConfiguration
 from bimmer_connected.api.regions import Regions
 from bimmer_connected.const import VEHICLES_URL, CarBrands
+from bimmer_connected.models import GPSPosition
 from bimmer_connected.utils import deprecated
 from bimmer_connected.vehicle import MyBMWVehicle
-from bimmer_connected.vehicle.models import GPSPosition
 
 VALID_UNTIL_OFFSET = datetime.timedelta(seconds=10)
 
@@ -34,29 +34,34 @@ class MyBMWAccount:  # pylint: disable=too-many-instance-attributes
     region: Regions
     """Region of the account. See `api.Regions`."""
 
-    mybmw_client_config: MyBMWClientConfiguration = None  # type: ignore[assignment]
+    config: MyBMWClientConfiguration = None  # type: ignore[assignment]
     """Optional. If provided, username/password/region are ignored."""
 
     log_responses: InitVar[pathlib.Path] = None
     """Optional. If set, all responses from the server will be logged to this directory."""
 
-    observer_position: Optional[GPSPosition] = None
+    observer_position: InitVar[GPSPosition] = None
     """Optional. Required for getting a position on older cars."""
 
+    use_metric_units: InitVar[bool] = True
+    """Optional. Use metric units (km, l) by default. Use imperial units (mi, gal) if False."""
+
     vehicles: List[MyBMWVehicle] = field(default_factory=list, init=False)
 
-    def __post_init__(self, password, log_responses):
-        if self.mybmw_client_config is None:
-            self.mybmw_client_config = MyBMWClientConfiguration(
+    def __post_init__(self, password, log_responses, observer_position, use_metric_units):
+        if self.config is None:
+            self.config = MyBMWClientConfiguration(
                 MyBMWAuthentication(self.username, password, self.region),
                 log_response_path=log_responses,
+                observer_position=observer_position,
+                use_metric_units=use_metric_units,
             )
 
     async def get_vehicles(self) -> None:
         """Retrieve vehicle data from BMW servers."""
         _LOGGER.debug("Getting vehicle list")
 
-        async with MyBMWClient(self.mybmw_client_config) as client:
+        async with MyBMWClient(self.config) as client:
             vehicles_request_params = {
                 "apptimezone": self.utcdiff,
                 "appDateTime": int(datetime.datetime.now().timestamp() * 1000),
@@ -66,7 +71,7 @@ class MyBMWAccount:  # pylint: disable=too-many-instance-attributes
                 await client.get(
                     VEHICLES_URL,
                     params=vehicles_request_params,
-                    headers=client.generate_default_header(self.region, brand),
+                    headers=client.generate_default_header(brand),
                 )
                 for brand in CarBrands
             ]
@@ -94,11 +99,15 @@ class MyBMWAccount:  # pylint: disable=too-many-instance-attributes
 
     def set_observer_position(self, latitude: float, longitude: float) -> None:
         """Set the position of the observer for all vehicles."""
-        self.observer_position = GPSPosition(latitude=latitude, longitude=longitude)
+        self.config.observer_position = GPSPosition(latitude=latitude, longitude=longitude)
 
     def set_refresh_token(self, refresh_token: str) -> None:
         """Overwrite the current value of the MyBMW refresh token."""
-        self.mybmw_client_config.authentication.refresh_token = refresh_token
+        self.config.authentication.refresh_token = refresh_token
+
+    def set_use_metric_units(self, use_metric_units: bool) -> None:
+        """Change between using metric units (km, l) if True or imperial units (mi, gal) if False."""
+        self.config.use_metric_units = use_metric_units
 
     @property
     def timezone(self):
@@ -113,7 +122,7 @@ class MyBMWAccount:  # pylint: disable=too-many-instance-attributes
     @property
     def refresh_token(self) -> Optional[str]:
         """Returns the current refresh_token."""
-        return self.mybmw_client_config.authentication.refresh_token
+        return self.config.authentication.refresh_token
 
 
 @deprecated("MyBMWAccount")
diff --git a/bimmer_connected/api/client.py b/bimmer_connected/api/client.py
index 99b3315..ab7de8a 100644
--- a/bimmer_connected/api/client.py
+++ b/bimmer_connected/api/client.py
@@ -10,7 +10,8 @@ import httpx
 from bimmer_connected.api.authentication import MyBMWAuthentication
 from bimmer_connected.api.regions import get_server_url
 from bimmer_connected.api.utils import get_correlation_id, log_to_to_file
-from bimmer_connected.const import HTTPX_TIMEOUT, USER_AGENT, X_USER_AGENT, CarBrands, Regions
+from bimmer_connected.const import HTTPX_TIMEOUT, USER_AGENT, X_USER_AGENT, CarBrands
+from bimmer_connected.models import GPSPosition
 
 
 @dataclass
@@ -19,6 +20,8 @@ class MyBMWClientConfiguration:
 
     authentication: MyBMWAuthentication
     log_response_path: Optional[pathlib.Path] = None
+    observer_position: Optional[GPSPosition] = None
+    use_metric_units: Optional[bool] = True
 
 
 class MyBMWClient(httpx.AsyncClient):
@@ -35,7 +38,7 @@ class MyBMWClient(httpx.AsyncClient):
 
         # Set default values
         kwargs["base_url"] = kwargs.get("base_url") or get_server_url(config.authentication.region)
-        kwargs["headers"] = kwargs.get("headers") or self.generate_default_header(config.authentication.region, brand)
+        kwargs["headers"] = kwargs.get("headers") or self.generate_default_header(brand)
 
         # Register event hooks
         kwargs["event_hooks"] = defaultdict(list, **kwargs.get("event_hooks", {}))
@@ -64,13 +67,13 @@ class MyBMWClient(httpx.AsyncClient):
 
         super().__init__(*args, **kwargs)
 
-    @staticmethod
-    def generate_default_header(region: Regions, brand: CarBrands = None) -> Dict[str, str]:
+    def generate_default_header(self, brand: CarBrands = None) -> Dict[str, str]:
         """Generate a header for HTTP requests to the server."""
         return {
             "accept": "application/json",
             "accept-language": "en",
             "user-agent": USER_AGENT,
-            "x-user-agent": X_USER_AGENT.format((brand or CarBrands.BMW), region.value),
+            "x-user-agent": X_USER_AGENT.format((brand or CarBrands.BMW), self.config.authentication.region.value),
             **get_correlation_id(),
+            "bmw-units-preferences": "d=KM;v=L" if self.config.use_metric_units else "d=MI;v=G",
         }
diff --git a/bimmer_connected/cli.py b/bimmer_connected/cli.py
index 3757614..a6afbba 100644
--- a/bimmer_connected/cli.py
+++ b/bimmer_connected/cli.py
@@ -138,7 +138,7 @@ async def fingerprint(args) -> None:
     for vehicle in account.vehicles:
         if vehicle.drive_train in HV_BATTERY_DRIVE_TRAINS:
             print(f"Getting 'charging-sessions' for {vehicle.vin}")
-            async with MyBMWClient(account.mybmw_client_config, brand=vehicle.brand) as client:
+            async with MyBMWClient(account.config, brand=vehicle.brand) as client:
                 await client.post(
                     "/eadrax-chs/v1/charging-sessions",
                     params={"vin": vehicle.vin, "maxResults": 40, "include_date_picker": "true"},
diff --git a/bimmer_connected/vehicle/models.py b/bimmer_connected/models.py
similarity index 100%
rename from bimmer_connected/vehicle/models.py
rename to bimmer_connected/models.py
diff --git a/bimmer_connected/vehicle/charging_profile.py b/bimmer_connected/vehicle/charging_profile.py
index 0a72ab9..97d1b7d 100644
--- a/bimmer_connected/vehicle/charging_profile.py
+++ b/bimmer_connected/vehicle/charging_profile.py
@@ -5,7 +5,7 @@ import logging
 from dataclasses import dataclass
 from typing import Any, Dict, List, Optional
 
-from bimmer_connected.vehicle.models import StrEnum, VehicleDataBase
+from bimmer_connected.models import StrEnum, VehicleDataBase
 
 _LOGGER = logging.getLogger(__name__)
 
diff --git a/bimmer_connected/vehicle/doors_windows.py b/bimmer_connected/vehicle/doors_windows.py
index e9574b8..11118a9 100644
--- a/bimmer_connected/vehicle/doors_windows.py
+++ b/bimmer_connected/vehicle/doors_windows.py
@@ -4,7 +4,7 @@ import logging
 from dataclasses import dataclass, field
 from typing import Any, Dict, List
 
-from bimmer_connected.vehicle.models import StrEnum, VehicleDataBase
+from bimmer_connected.models import StrEnum, VehicleDataBase
 
 _LOGGER = logging.getLogger(__name__)
 
diff --git a/bimmer_connected/vehicle/fuel_and_battery.py b/bimmer_connected/vehicle/fuel_and_battery.py
index 065fc5a..f740f0a 100644
--- a/bimmer_connected/vehicle/fuel_and_battery.py
+++ b/bimmer_connected/vehicle/fuel_and_battery.py
@@ -6,7 +6,7 @@ import logging
 from dataclasses import dataclass
 from typing import Any, Dict, Optional
 
-from bimmer_connected.vehicle.models import StrEnum, ValueWithUnit, VehicleDataBase
+from bimmer_connected.models import StrEnum, ValueWithUnit, VehicleDataBase
 
 _LOGGER = logging.getLogger(__name__)
 
diff --git a/bimmer_connected/vehicle/location.py b/bimmer_connected/vehicle/location.py
index 2ba32ac..577ea4a 100644
--- a/bimmer_connected/vehicle/location.py
+++ b/bimmer_connected/vehicle/location.py
@@ -7,8 +7,8 @@ from typing import Any, Dict, Optional
 
 from bimmer_connected.const import Regions
 from bimmer_connected.coord_convert import gcj2wgs
+from bimmer_connected.models import GPSPosition, VehicleDataBase
 from bimmer_connected.utils import parse_datetime
-from bimmer_connected.vehicle.models import GPSPosition, VehicleDataBase
 
 _LOGGER = logging.getLogger(__name__)
 
diff --git a/bimmer_connected/vehicle/remote_services.py b/bimmer_connected/vehicle/remote_services.py
index 188955d..acf2bad 100644
--- a/bimmer_connected/vehicle/remote_services.py
+++ b/bimmer_connected/vehicle/remote_services.py
@@ -13,8 +13,8 @@ from bimmer_connected.const import (
     REMOTE_SERVICE_URL,
     VEHICLE_POI_URL,
 )
+from bimmer_connected.models import PointOfInterest, StrEnum
 from bimmer_connected.utils import MyBMWJSONEncoder
-from bimmer_connected.vehicle.models import PointOfInterest, StrEnum
 
 if TYPE_CHECKING:
     from bimmer_connected.vehicle import MyBMWVehicle
@@ -150,7 +150,7 @@ class RemoteServices:
         """Start a generic remote service."""
 
         url = REMOTE_SERVICE_URL.format(vin=self._vehicle.vin, service_type=service_id.value)
-        async with MyBMWClient(self._account.mybmw_client_config, brand=self._vehicle.brand) as client:
+        async with MyBMWClient(self._account.config, brand=self._vehicle.brand) as client:
             response = await client.post(url, params=params)
         return response.json().get("eventId")
 
@@ -177,7 +177,7 @@ class RemoteServices:
         """The execution status of the last remote service that was triggered."""
         _LOGGER.debug("getting remote service status for '%s'", event_id)
         url = REMOTE_SERVICE_STATUS_URL.format(vin=self._vehicle.vin, event_id=event_id)
-        async with MyBMWClient(self._account.mybmw_client_config, brand=self._vehicle.brand) as client:
+        async with MyBMWClient(self._account.config, brand=self._vehicle.brand) as client:
             response = await client.post(url)
         return RemoteServiceStatus(response.json())
 
@@ -199,7 +199,7 @@ class RemoteServices:
         if isinstance(poi, Dict):
             poi = PointOfInterest(**poi)
 
-        async with MyBMWClient(self._account.mybmw_client_config, brand=self._vehicle.brand) as client:
+        async with MyBMWClient(self._account.config, brand=self._vehicle.brand) as client:
             await client.post(
                 VEHICLE_POI_URL,
                 headers={"content-type": "application/json"},
@@ -229,19 +229,19 @@ class RemoteServices:
 
     async def _get_event_position(self, event_id) -> Dict:
         url = REMOTE_SERVICE_POSITION_URL.format(event_id=event_id)
-        if not self._account.observer_position:
+        if not self._account.config.observer_position:
             return {
                 "errorDetails": {
                     "title": "Unknown position",
                     "description": "Set observer position to retrieve vehicle coordinates!",
                 }
             }
-        async with MyBMWClient(self._account.mybmw_client_config, brand=self._vehicle.brand) as client:
+        async with MyBMWClient(self._account.config, brand=self._vehicle.brand) as client:
             response = await client.post(
                 url,
                 headers={
-                    "latitude": str(self._account.observer_position.latitude),
-                    "longitude": str(self._account.observer_position.longitude),
+                    "latitude": str(self._account.config.observer_position.latitude),
+                    "longitude": str(self._account.config.observer_position.longitude),
                 },
             )
         return response.json()
diff --git a/bimmer_connected/vehicle/reports.py b/bimmer_connected/vehicle/reports.py
index d9728a1..d01ff09 100644
--- a/bimmer_connected/vehicle/reports.py
+++ b/bimmer_connected/vehicle/reports.py
@@ -5,8 +5,8 @@ import logging
 from dataclasses import dataclass, field
 from typing import Any, Dict, List, Optional
 
+from bimmer_connected.models import StrEnum, ValueWithUnit, VehicleDataBase
 from bimmer_connected.utils import parse_datetime
-from bimmer_connected.vehicle.models import StrEnum, ValueWithUnit, VehicleDataBase
 
 _LOGGER = logging.getLogger(__name__)
 
diff --git a/bimmer_connected/vehicle/vehicle.py b/bimmer_connected/vehicle/vehicle.py
index 7f9d7a0..c109788 100644
--- a/bimmer_connected/vehicle/vehicle.py
+++ b/bimmer_connected/vehicle/vehicle.py
@@ -5,19 +5,19 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Type
 
 from bimmer_connected.api.client import MyBMWClient
 from bimmer_connected.const import SERVICE_PROPERTIES, SERVICE_STATUS, VEHICLE_IMAGE_URL, CarBrands
+from bimmer_connected.models import StrEnum, ValueWithUnit
 from bimmer_connected.utils import deprecated, parse_datetime
 from bimmer_connected.vehicle.charging_profile import ChargingProfile
 from bimmer_connected.vehicle.doors_windows import DoorsAndWindows
 from bimmer_connected.vehicle.fuel_and_battery import FuelAndBattery
 from bimmer_connected.vehicle.location import VehicleLocation
-from bimmer_connected.vehicle.models import StrEnum, ValueWithUnit
 from bimmer_connected.vehicle.remote_services import RemoteServices
 from bimmer_connected.vehicle.reports import CheckControlMessageReport, ConditionBasedServiceReport
 from bimmer_connected.vehicle.vehicle_status import VehicleStatus
 
 if TYPE_CHECKING:
     from bimmer_connected.account import MyBMWAccount
-    from bimmer_connected.vehicle.models import VehicleDataBase
+    from bimmer_connected.models import VehicleDataBase
 
 
 _LOGGER = logging.getLogger(__name__)
@@ -293,7 +293,7 @@ class MyBMWVehicle:
             view=direction.value,
         )
         # the accept field of the header needs to be updated as we want a png not the usual JSON
-        async with MyBMWClient(self.account.mybmw_client_config, brand=self.brand) as client:
+        async with MyBMWClient(self.account.config, brand=self.brand) as client:
             response = await client.get(url, headers={"accept": "image/png"})
         return response.content
 
diff --git a/bimmer_connected/vehicle/vehicle_status.py b/bimmer_connected/vehicle/vehicle_status.py
index 3e61ea3..ad62f65 100644
--- a/bimmer_connected/vehicle/vehicle_status.py
+++ b/bimmer_connected/vehicle/vehicle_status.py
@@ -4,8 +4,8 @@ import datetime
 import logging
 from typing import TYPE_CHECKING, Dict, List, Optional
 
+from bimmer_connected.models import GPSPosition, ValueWithUnit
 from bimmer_connected.utils import deprecated
-from bimmer_connected.vehicle.models import GPSPosition, ValueWithUnit
 
 if TYPE_CHECKING:
     from bimmer_connected.vehicle import MyBMWVehicle
diff --git a/docs/source/module/models.rst b/docs/source/module/models.rst
new file mode 100644
index 0000000..166b637
--- /dev/null
+++ b/docs/source/module/models.rst
@@ -0,0 +1,8 @@
+.. _models_module:
+
+:mod:`bimmer_connected.models`
+======================================
+ 
+.. automodule:: bimmer_connected.models
+    :members:
+    :undoc-members:
diff --git a/docs/source/module/vehicle.rst b/docs/source/module/vehicle.rst
index 86929a3..204abd3 100644
--- a/docs/source/module/vehicle.rst
+++ b/docs/source/module/vehicle.rst
@@ -53,14 +53,6 @@ The :mod:`bimmer_connected.vehicle` module contains all data & parsers for a veh
     :undoc-members:
 
 
-:mod:`bimmer_connected.vehicle.models`
---------------------------------------------------------
- 
-.. automodule:: bimmer_connected.vehicle.models
-    :members:
-    :undoc-members:
-
-
 :mod:`bimmer_connected.vehicle.reports`
 --------------------------------------------------------
  


Test patch:
diff --git a/test/test_account.py b/test/test_account.py
index f931f80..fac2ae9 100644
--- a/test/test_account.py
+++ b/test/test_account.py
@@ -19,9 +19,10 @@ import respx
 
 from bimmer_connected.account import ConnectedDriveAccount, MyBMWAccount
 from bimmer_connected.api.authentication import MyBMWAuthentication, MyBMWLoginRetry
+from bimmer_connected.api.client import MyBMWClient
 from bimmer_connected.api.regions import get_region_from_name
 from bimmer_connected.const import Regions
-from bimmer_connected.vehicle.models import GPSPosition
+from bimmer_connected.models import GPSPosition
 
 from . import (
     RESPONSE_DIR,
@@ -127,14 +128,14 @@ async def test_login_refresh_token_row_na_expired():
 
         with mock.patch(
             "bimmer_connected.api.authentication.MyBMWAuthentication._refresh_token_row_na",
-            wraps=account.mybmw_client_config.authentication._refresh_token_row_na,  # pylint: disable=protected-access
+            wraps=account.config.authentication._refresh_token_row_na,  # pylint: disable=protected-access
         ) as mock_listener:
             mock_listener.reset_mock()
             await account.get_vehicles()
 
             # Should not be called at all, as expiry date is not checked anymore
             assert mock_listener.call_count == 0
-            assert account.mybmw_client_config.authentication.refresh_token is not None
+            assert account.config.authentication.refresh_token is not None
 
 
 @pytest.mark.asyncio
@@ -146,7 +147,7 @@ async def test_login_refresh_token_row_na_401():
 
         with mock.patch(
             "bimmer_connected.api.authentication.MyBMWAuthentication._refresh_token_row_na",
-            wraps=account.mybmw_client_config.authentication._refresh_token_row_na,  # pylint: disable=protected-access
+            wraps=account.config.authentication._refresh_token_row_na,  # pylint: disable=protected-access
         ) as mock_listener:
             mock_api.get("/eadrax-vcs/v1/vehicles").mock(
                 side_effect=[httpx.Response(401), *([httpx.Response(200, json=[])] * 10)]
@@ -155,7 +156,7 @@ async def test_login_refresh_token_row_na_401():
             await account.get_vehicles()
 
             assert mock_listener.call_count == 1
-            assert account.mybmw_client_config.authentication.refresh_token is not None
+            assert account.config.authentication.refresh_token is not None
 
 
 @pytest.mark.asyncio
@@ -200,14 +201,14 @@ async def test_login_refresh_token_china_expired():
 
         with mock.patch(
             "bimmer_connected.api.authentication.MyBMWAuthentication._refresh_token_china",
-            wraps=account.mybmw_client_config.authentication._refresh_token_china,  # pylint: disable=protected-access
+            wraps=account.config.authentication._refresh_token_china,  # pylint: disable=protected-access
         ) as mock_listener:
             mock_listener.reset_mock()
             await account.get_vehicles()
 
             # Should not be called at all, as expiry date is not checked anymore
             assert mock_listener.call_count == 0
-            assert account.mybmw_client_config.authentication.refresh_token is not None
+            assert account.config.authentication.refresh_token is not None
 
 
 @pytest.mark.asyncio
@@ -219,7 +220,7 @@ async def test_login_refresh_token_china_401():
 
         with mock.patch(
             "bimmer_connected.api.authentication.MyBMWAuthentication._refresh_token_china",
-            wraps=account.mybmw_client_config.authentication._refresh_token_china,  # pylint: disable=protected-access
+            wraps=account.config.authentication._refresh_token_china,  # pylint: disable=protected-access
         ) as mock_listener:
             mock_api.get("/eadrax-vcs/v1/vehicles").mock(
                 side_effect=[httpx.Response(401), *([httpx.Response(200, json=[])] * 10)]
@@ -228,7 +229,7 @@ async def test_login_refresh_token_china_401():
             await account.get_vehicles()
 
             assert mock_listener.call_count == 1
-            assert account.mybmw_client_config.authentication.refresh_token is not None
+            assert account.config.authentication.refresh_token is not None
 
 
 @pytest.mark.asyncio
@@ -261,7 +262,7 @@ async def test_vehicles():
     account = MyBMWAccount(TEST_USERNAME, TEST_PASSWORD, get_region_from_name("china"))
     await account.get_vehicles()
 
-    assert account.mybmw_client_config.authentication.access_token is not None
+    assert account.config.authentication.access_token is not None
     assert get_fingerprint_count() == len(account.vehicles)
 
     vehicle = account.get_vehicle(VIN_G21)
@@ -345,7 +346,7 @@ async def test_set_observer_value():
 
     account.set_observer_position(1.0, 2.0)
 
-    assert account.observer_position == GPSPosition(1.0, 2.0)
+    assert account.config.observer_position == GPSPosition(1.0, 2.0)
 
 
 @pytest.mark.asyncio
@@ -353,11 +354,11 @@ async def test_set_observer_not_set():
     """Test set_observer_position with no arguments."""
     account = await get_mocked_account()
 
-    assert account.observer_position is None
+    assert account.config.observer_position is None
 
     account.set_observer_position(17.99, 179.9)
 
-    assert account.observer_position == GPSPosition(17.99, 179.9)
+    assert account.config.observer_position == GPSPosition(17.99, 179.9)
 
 
 @pytest.mark.asyncio
@@ -375,6 +376,26 @@ async def test_set_observer_invalid_values():
         account.set_observer_position(1.0, "16.0")
 
 
+@pytest.mark.asyncio
+async def test_set_use_metric_units():
+    """Test set_observer_position with no arguments."""
+    account = MyBMWAccount(TEST_USERNAME, TEST_PASSWORD, TEST_REGION)
+    assert account.config.use_metric_units is True
+
+    metric_client = MyBMWClient(account.config)
+    assert metric_client.generate_default_header()["bmw-units-preferences"] == "d=KM;v=L"
+
+    account.set_use_metric_units(False)
+    assert account.config.use_metric_units is False
+    imperial_client = MyBMWClient(account.config)
+    assert imperial_client.generate_default_header()["bmw-units-preferences"] == "d=MI;v=G"
+
+    imperial_account = MyBMWAccount(TEST_USERNAME, TEST_PASSWORD, TEST_REGION, use_metric_units=False)
+    assert imperial_account.config.use_metric_units is False
+    imperial_client = MyBMWClient(imperial_account.config)
+    assert imperial_client.generate_default_header()["bmw-units-preferences"] == "d=MI;v=G"
+
+
 @account_mock()
 @pytest.mark.asyncio
 async def test_deprecated_account(caplog):
diff --git a/test/test_vehicle.py b/test/test_vehicle.py
index c5c85f0..e2aebd5 100644
--- a/test/test_vehicle.py
+++ b/test/test_vehicle.py
@@ -2,8 +2,8 @@
 import pytest
 
 from bimmer_connected.const import CarBrands
+from bimmer_connected.models import GPSPosition, StrEnum, VehicleDataBase
 from bimmer_connected.vehicle import DriveTrainType, VehicleViewDirection
-from bimmer_connected.vehicle.models import GPSPosition, StrEnum, VehicleDataBase
 
 from . import (
     VIN_F11,