Repository: bimmerconnected/bimmer_connected (python)

Issue:
Add VEHICLE_FINDER service
Hi:
Many thanks for your project!

I have missed in your project the VEHICLE_FINDER service, that forces the vehicle to update its gps position on the BMW servers. At least in my vehicle (2015 F31), if you don't force the vehicle finder in the BMW app, this data is not updated automatically and the last location you requested remains.

The ideal would be to create a service that from time to time (could be 1, 2, 3 ... hours) runs the VEHICLE_FINDER service so that the location of the vehicle is always updated.

I have tried to make a simple modification in your code to test by CLI if it works, and yes, it works.

Thank you!


Pull request description:
Add VEHICLE_FINDER remote service
Fixes #182. Many thanks to @droneando for doing inital testing and development!

Adds `VEHICLE_FINDER` remote service to trigger an update of the vehicle position.
Can be called from anywhere, no GPS coordinates required for vehicles pre 7/2014.

Usage from HA requires an update to the component.

Patch:
diff --git a/bimmer_connected/cli.py b/bimmer_connected/cli.py
index 47cf3c4..202feba 100644
--- a/bimmer_connected/cli.py
+++ b/bimmer_connected/cli.py
@@ -40,6 +40,11 @@ def main_parser() -> argparse.ArgumentParser:
     flash_parser.add_argument('vin', help=TEXT_VIN)
     flash_parser.set_defaults(func=light_flash)
 
+    finder_parser = subparsers.add_parser('vehiclefinder', description='Update the vehicle GPS location.')
+    _add_default_arguments(finder_parser)
+    finder_parser.add_argument('vin', help=TEXT_VIN)
+    finder_parser.set_defaults(func=vehicle_finder)
+
     image_parser = subparsers.add_parser('image', description='Download a vehicle image.')
     _add_default_arguments(image_parser)
     image_parser.add_argument('vin', help=TEXT_VIN)
@@ -130,6 +135,18 @@ def light_flash(args) -> None:
     print(status.state)
 
 
+def vehicle_finder(args) -> None:
+    """Trigger the vehicle finder to locate it."""
+    account = ConnectedDriveAccount(args.username, args.password, get_region_from_name(args.region))
+    vehicle = account.get_vehicle(args.vin)
+    if not vehicle:
+        valid_vins = ", ".join(v.vin for v in account.vehicles)
+        print('Error: Could not find vehicle for VIN "{}". Valid VINs are: {}'.format(args.vin, valid_vins))
+        return
+    status = vehicle.remote_services.trigger_remote_vehicle_finder()
+    print(status.state)
+
+
 def image(args) -> None:
     """Download a rendered image of the vehicle."""
     account = ConnectedDriveAccount(args.username, args.password, get_region_from_name(args.region))
diff --git a/bimmer_connected/remote_services.py b/bimmer_connected/remote_services.py
index 2392b17..59958b0 100644
--- a/bimmer_connected/remote_services.py
+++ b/bimmer_connected/remote_services.py
@@ -38,6 +38,7 @@ class ExecutionState(Enum):
 class _Services(Enum):
     """Enumeration of possible services to be executed."""
     REMOTE_LIGHT_FLASH = 'LIGHT_FLASH'
+    REMOTE_VEHICLE_FINDER = 'VEHICLE_FINDER'
     REMOTE_DOOR_LOCK = 'DOOR_LOCK'
     REMOTE_DOOR_UNLOCK = 'DOOR_UNLOCK'
     REMOTE_HORN = 'HORN_BLOW'
@@ -290,3 +291,15 @@ class RemoteServices:
                                           data=msg.as_server_request,
                                           post=True,
                                           expected_response=204)
+
+    def trigger_remote_vehicle_finder(self) -> RemoteServiceStatus:
+        """Trigger the vehicle finder.
+
+        A state update is triggered after this, as the location state of the vehicle changes.
+        """
+        _LOGGER.debug('Triggering remote vehicle finder')
+        # needs to be called via POST, GET is not working
+        self._trigger_remote_service(_Services.REMOTE_VEHICLE_FINDER, post=True)
+        result = self._block_until_done(_Services.REMOTE_VEHICLE_FINDER)
+        self._trigger_state_update()
+        return result


Test patch:
diff --git a/test/test_remote_services.py b/test/test_remote_services.py
index 47062fd..c68fb95 100644
--- a/test/test_remote_services.py
+++ b/test/test_remote_services.py
@@ -51,6 +51,7 @@ class TestRemoteServices(unittest.TestCase):
             ('DOOR_LOCK', 'trigger_remote_door_lock', True),
             ('DOOR_UNLOCK', 'trigger_remote_door_unlock', True),
             ('CLIMATE_NOW', 'trigger_remote_air_conditioning', True),
+            ('VEHICLE_FINDER', 'trigger_remote_vehicle_finder', True),
             ('HORN_BLOW', 'trigger_remote_horn', False),
             ('SEND_MESSAGE', 'trigger_send_message', False),
             ('SEND_POI', 'trigger_send_poi', False),