Repository: bimmerconnected/bimmer_connected
Pull request #131 (2019-10-29 23:10:25)

Sendpoi
Add PRs from Sendpoi branch


Patch:
diff --git a/bimmer_connected/cli.py b/bimmer_connected/cli.py
index bfd9333..3e110b0 100644
--- a/bimmer_connected/cli.py
+++ b/bimmer_connected/cli.py
@@ -42,11 +42,15 @@ def main() -> None:
     image_parser.set_defaults(func=image)
 
     sendpoi_parser = subparsers.add_parser('sendpoi', description='send a point of interest to the vehicle')
-    _add_default_arguments(sendpoi_parser )
+    _add_default_arguments(sendpoi_parser)
     sendpoi_parser.add_argument('vin', help='vehicle identification number')
     sendpoi_parser.add_argument('latitude', help='latitude of the POI', type=float)
     sendpoi_parser.add_argument('longitude', help='longitude of the POI', type=float)
-    sendpoi_parser.add_argument('name', help='(optional) name of the POI', nargs='?', default=None)
+    sendpoi_parser.add_argument('--name', help='(optional, display only) Name of the POI', nargs='?', default=None)
+    sendpoi_parser.add_argument('--street', help='(optional, display only) Street & House No. of the POI', nargs='?', default=None)
+    sendpoi_parser.add_argument('--city', help='(optional, display only) City of the POI', nargs='?', default=None)
+    sendpoi_parser.add_argument('--postalcode', help='(optional, display only) Postal code of the POI', nargs='?', default=None)
+    sendpoi_parser.add_argument('--country', help='(optional, display only) Country of the POI', nargs='?', default=None)
     sendpoi_parser.set_defaults(func=send_poi)
 
     args = parser.parse_args()
@@ -117,7 +121,8 @@ def image(args) -> None:
 def send_poi(args) -> None:
     account = ConnectedDriveAccount(args.username, args.password, get_region_from_name(args.region))
     vehicle = account.get_vehicle(args.vin)
-    poi = PointOfInterest(args.latitude, args.longitude, name=args.name)
+    poi = PointOfInterest(args.latitude, args.longitude, name=args.name,
+                          street=args.street, city=args.city, postalCode=args.postalcode, country=args.country)
     vehicle.send_poi(poi)
 
 
diff --git a/bimmer_connected/vehicle.py b/bimmer_connected/vehicle.py
index 757da21..57b030d 100644
--- a/bimmer_connected/vehicle.py
+++ b/bimmer_connected/vehicle.py
@@ -1,7 +1,7 @@
 """Models state and remote services of one vehicle."""
 from enum import Enum
 import logging
-from typing import List, Dict
+from typing import List
 import json
 from urllib.parse import urlencode
 
@@ -54,6 +54,7 @@ class LscType(Enum):
     LSC_PHEV = 'LSC_PHEV'
 
 
+# pylint: disable=too-many-instance-attributes, too-few-public-methods
 class PointOfInterest:
     """Point of interest to be sent to the vehicle.
 
@@ -61,32 +62,42 @@ class PointOfInterest:
     used here so that we do not have to convert the names between the attributes and the keys as expected on the server.
     """
 
-    def __init__(self, latitude: float, longitude: float, * , name: str = None):
+    # pylint: disable=too-many-arguments
+    def __init__(self, latitude: float, longitude: float, name: str = None,
+                 additionalInfo: str = None, street: str = None, city: str = None,
+                 postalCode: str = None, country: str = None, website: str = None,
+                 phoneNumbers: [str] = None):
         """Constructor.
 
         :arg latitude: latitude of the POI
         :arg longitude: longitude of the POI
         :arg name: name of the POI (Optional)
+        :arg additionalInfo: additional text shown below the address (Optional)
+        :arg street: street with house number of the POI (Optional)
+        :arg city: city of the POI (Optional)
+        :arg postalCode: zip code of the POI (Optional)
+        :arg country: country of the POI (Optional)
+        :arg website: website of the POI (Optional)
+        :arg phoneNumbers: List of phone numbers of the POI (Optional)
         """
-        self.latitude = latitude  # type: float
-        self.longitude = longitude  # type: float
+        # pylint: disable=invalid-name
+        self.lat = latitude  # type: float
+        self.lon = longitude  # type: float
         self.name = name  # type: str
-        self.additionalInfo = None  # type: str
-        self.street = ""  # type: str
-        self.city = ""  # type: str
-        self.postalCode = ""  # type: str
-        self.country = ""  # type: str
-        self.website = None  # type: str
-        self.phoneNumbers = None  # type: List[str]
+        self.additionalInfo = additionalInfo if additionalInfo is not None \
+            else 'Sent with ♥ by bimmer_connected'  # type: str
+        self.street = street  # type: str
+        self.city = city  # type: str
+        self.postalCode = postalCode  # type: str
+        self.country = country  # type: str
+        self.website = website  # type: str
+        self.phoneNumbers = phoneNumbers  # type: List[str]
 
     @property
     def as_server_request(self) -> str:
         """Convert to a dictionary so that it can be sent to the server."""
         result = {
-            'poi' : {
-                'lat': self.latitude,
-                'lon': self.longitude,
-            }
+            'poi': {k: v for k, v in self.__dict__.items() if v is not None}
         }
         return urlencode({'data': json.dumps(result)})
 


Test patch:
diff --git a/test/__init__.py b/test/__init__.py
index cb2233c..898c75d 100644
--- a/test/__init__.py
+++ b/test/__init__.py
@@ -74,6 +74,30 @@ MISSING_ATTRIBUTES = [
     'sunroof',                    # not available in all vehicles
 ]
 
+POI_DATA = {
+    "lat": 37.4028943,
+    "lon": -121.9700289,
+    "name": "49ers",
+    "additionalInfo": "Hi Sam",
+    "street": "4949 Marie P DeBartolo Way",
+    "city": "Santa Clara",
+    "postalCode": "CA 95054",
+    "country": "United States",
+    "website": "https://www.49ers.com/",
+    "phoneNumbers": ["+1 408-562-4949"]
+}
+
+POI_REQUEST = {
+    "min": ("data=%7B%22poi%22%3A+%7B%22lat%22%3A+37.4028943%2C+%22lon%22%3A+-121.9700289"
+            "%2C+%22additionalInfo%22%3A+%22Sent+with+%5Cu2665+by+bimmer_connected%22%7D%7D"),
+    "all": ("data=%7B%22poi%22%3A+%7B%22lat%22%3A+37.4028943%2C+%22lon%22%3A+-121.9700289"
+            "%2C+%22name%22%3A+%2249ers%22%2C+%22additionalInfo%22%3A+%22Hi+Sam%22"
+            "%2C+%22street%22%3A+%224949+Marie+P+DeBartolo+Way%22%2C+%22city%22%3A+%22Santa+Clara%22"
+            "%2C+%22postalCode%22%3A+%22CA+95054%22%2C+%22country%22%3A+%22United+States%22"
+            "%2C+%22website%22%3A+%22https%3A%2F%2Fwww.49ers.com%2F%22"
+            "%2C+%22phoneNumbers%22%3A+%5B%22%2B1+408-562-4949%22%5D%7D%7D")
+}
+
 
 def load_response_json(filename: str) -> dict:
     """load a stored response from a file"""
diff --git a/test/test_vehicle.py b/test/test_vehicle.py
index 3e78dfd..138228f 100644
--- a/test/test_vehicle.py
+++ b/test/test_vehicle.py
@@ -3,9 +3,9 @@ import unittest
 from unittest import mock
 from test import load_response_json, BackendMock, TEST_USERNAME, TEST_PASSWORD, TEST_REGION, \
     G31_VIN, F48_VIN, I01_VIN, I01_NOREX_VIN, F15_VIN, F45_VIN, TEST_VEHICLE_DATA, \
-    ATTRIBUTE_MAPPING, MISSING_ATTRIBUTES, ADDITIONAL_ATTRIBUTES
+    ATTRIBUTE_MAPPING, MISSING_ATTRIBUTES, ADDITIONAL_ATTRIBUTES, POI_DATA, POI_REQUEST
 
-from bimmer_connected.vehicle import ConnectedDriveVehicle, DriveTrainType
+from bimmer_connected.vehicle import ConnectedDriveVehicle, DriveTrainType, PointOfInterest
 from bimmer_connected.account import ConnectedDriveAccount
 
 
@@ -72,3 +72,17 @@ class TestVehicle(unittest.TestCase):
                                           if a not in MISSING_ATTRIBUTES])
             expected_attributes = sorted([a for a in vehicle.available_attributes if a not in ADDITIONAL_ATTRIBUTES])
             self.assertListEqual(existing_attributes, expected_attributes)
+
+    def test_parsing_of_poi_min_attributes(self):
+        """Check that a PointOfInterest can be constructed using only latitude & longitude."""
+        poi = PointOfInterest(POI_DATA["lat"], POI_DATA["lon"])
+        self.assertEqual(poi.as_server_request, POI_REQUEST["min"])
+
+    def test_parsing_of_poi_all_attributes(self):
+        """Check that a PointOfInterest can be constructed using all attributes."""
+        poi = PointOfInterest(POI_DATA["lat"], POI_DATA["lon"], name=POI_DATA["name"],
+                              additionalInfo=POI_DATA["additionalInfo"], street=POI_DATA["street"],
+                              city=POI_DATA["city"], postalCode=POI_DATA["postalCode"],
+                              country=POI_DATA["country"], website=POI_DATA["website"],
+                              phoneNumbers=POI_DATA["phoneNumbers"])
+        self.assertEqual(poi.as_server_request, POI_REQUEST["all"])