Skip to content

Commit

Permalink
Select available state services from vehicles list (#217)
Browse files Browse the repository at this point in the history
Co-authored-by: rikroe <rikroe@users.noreply.github.com>
  • Loading branch information
gerard33 and rikroe committed Oct 25, 2020
1 parent ef0cfd7 commit 233589c
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 3 deletions.
2 changes: 1 addition & 1 deletion bimmer_connected/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def update_data(self) -> None:
'dlon': self._vehicle.observer_longitude,
}

for service in self._url:
for service in self._vehicle.available_state_services:
try:
response = self._account.send_request(
self._url[service].format(server=self._account.server_url, vin=self._vehicle.vin),
Expand Down
45 changes: 44 additions & 1 deletion bimmer_connected/vehicle.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
from bimmer_connected.state import VehicleState
from bimmer_connected.vehicle_status import WINDOWS, LIDS
from bimmer_connected.remote_services import RemoteServices
from bimmer_connected.const import VEHICLE_IMAGE_URL
from bimmer_connected.const import VEHICLE_IMAGE_URL, SERVICE_ALL_TRIPS, SERVICE_CHARGING_PROFILE, \
SERVICE_DESTINATIONS, SERVICE_EFFICIENCY, SERVICE_LAST_TRIP, SERVICE_NAVIGATION, \
SERVICE_RANGEMAP, SERVICE_STATUS

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -107,6 +109,26 @@ def has_internal_combustion_engine(self) -> bool:
In this case we can get the state of the gas tank."""
return self.drive_train in COMBUSTION_ENGINE_DRIVE_TRAINS

@property
def has_statistics_service(self) -> bool:
"""Return True if statistics are available."""
return self.attributes.get('statisticsAvailable')

@property
def has_weekly_planner_service(self) -> bool:
"""Return True if charging control (weekly planner) is available."""
return self.attributes.get('chargingControl') == "WEEKLY_PLANNER"

@property
def has_destination_service(self) -> bool:
"""Return True if destinations are available."""
return self.attributes.get('lastDestinations') == "SUPPORTED"

@property
def has_rangemap_service(self) -> bool:
"""Return True if rangemap (range circle) is available."""
return self.attributes.get('rangeMap') == "RANGE_CIRCLE"

@property
def drive_train_attributes(self) -> List[str]:
"""Get list of attributes available for the drive train of the vehicle.
Expand Down Expand Up @@ -156,6 +178,27 @@ def available_attributes(self) -> List[str]:
result += ['lights_parking', 'lids', 'windows']
return result

@property
def available_state_services(self) -> List:
"""Get the list of all available state services for this vehicle."""
result = [SERVICE_STATUS]
if self.has_statistics_service:
result += [SERVICE_LAST_TRIP, SERVICE_ALL_TRIPS]

if self.has_weekly_planner_service:
result += [SERVICE_CHARGING_PROFILE]

if self.has_destination_service:
result += [SERVICE_DESTINATIONS]

if self.has_rangemap_service:
result += [SERVICE_RANGEMAP]

if self.drive_train != DriveTrainType.CONVENTIONAL:
result += [SERVICE_EFFICIENCY, SERVICE_NAVIGATION]

return result

def get_vehicle_image(self, width: int, height: int, direction: VehicleViewDirection) -> bytes:
"""Get a rendered image of the vehicle.
Expand Down
7 changes: 7 additions & 0 deletions test/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@
'vehicleCountry', # para not available in all vehicles
]

AVAILABLE_STATES_MAPPING = {
"statisticsAvailable": {True: ["LAST_TRIP", "ALL_TRIPS"]},
"chargingControl": {"WEEKLY_PLANNER": ["CHARGING_PROFILE"]},
"lastDestinations": {"SUPPORTED": ["DESTINATIONS"]},
"rangeMap": {"RANGE_CIRCLE": ["RANGEMAP"]}
}

POI_DATA = {
"lat": 37.4028943,
"lon": -121.9700289,
Expand Down
33 changes: 32 additions & 1 deletion test/test_vehicle.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
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, F31_VIN, TEST_VEHICLE_DATA, \
ATTRIBUTE_MAPPING, MISSING_ATTRIBUTES, ADDITIONAL_ATTRIBUTES, G30_PHEV_OS7_VIN
ATTRIBUTE_MAPPING, MISSING_ATTRIBUTES, ADDITIONAL_ATTRIBUTES, G30_PHEV_OS7_VIN, AVAILABLE_STATES_MAPPING

from bimmer_connected.vehicle import ConnectedDriveVehicle, DriveTrainType
from bimmer_connected.account import ConnectedDriveAccount
Expand Down Expand Up @@ -34,6 +34,10 @@ def test_parsing_attributes(self):
self.assertIsNotNone(vehicle.has_internal_combustion_engine)
self.assertIsNotNone(vehicle.has_hv_battery)
self.assertIsNotNone(vehicle.drive_train_attributes)
self.assertIsNotNone(vehicle.has_statistics_service)
self.assertIsNotNone(vehicle.has_weekly_planner_service)
self.assertIsNotNone(vehicle.has_destination_service)
self.assertIsNotNone(vehicle.has_rangemap_service)

def test_drive_train_attributes(self):
"""Test parsing different attributes of the vehicle."""
Expand Down Expand Up @@ -73,3 +77,30 @@ def test_available_attributes(self):
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_available_state_services(self):
"""Check that available_attributes returns exactly the arguments we have in our test data."""
backend_mock = BackendMock()
with mock.patch('bimmer_connected.account.requests', new=backend_mock):
account = ConnectedDriveAccount(TEST_USERNAME, TEST_PASSWORD, TEST_REGION)

vehicles = load_response_json('vehicles.json')

for test_vehicle in vehicles['vehicles']:
vehicle = account.get_vehicle(test_vehicle['vin'])
print(vehicle.name)

services_to_check = {
k: v
for k, v in test_vehicle.items()
if k in list(AVAILABLE_STATES_MAPPING)
}

available_services = ['STATUS']
for key, value in services_to_check.items():
if AVAILABLE_STATES_MAPPING[key].get(value):
available_services += AVAILABLE_STATES_MAPPING[key][value]
if vehicle.drive_train != DriveTrainType.CONVENTIONAL:
available_services += ['EFFICIENCY', 'NAVIGATION']

self.assertListEqual(sorted(vehicle.available_state_services), sorted(available_services))

0 comments on commit 233589c

Please sign in to comment.