Repository: bimmerconnected/bimmer_connected
Pull request #197 (2020-09-24 18:05:46)

New services and test data
* Added two legacy services "navigation" and "efficiency"
* Added test files from a G30 PHEV with OS7

Markinus: @rikroe , It would be great if you could check it. I had to change the test for the vehicle because the new data is a bit different. (e.g. "steering" is missing in the status.json). 

Patch:
diff --git a/bimmer_connected/const.py b/bimmer_connected/const.py
index 3f77caf..b443932 100644
--- a/bimmer_connected/const.py
+++ b/bimmer_connected/const.py
@@ -3,6 +3,7 @@
 AUTH_URL = 'https://customer.bmwgroup.com/{gcdm_oauth_endpoint}/authenticate'
 AUTH_URL_LEGACY = 'https://{server}/gcdm/oauth/token'
 BASE_URL = 'https://{server}/webapi/v1'
+BASE_URL_LEGACY = 'https://{server}/api/vehicle/'
 
 VEHICLES_URL = BASE_URL + '/user/vehicles'
 VEHICLE_VIN_URL = VEHICLES_URL + '/{vin}'
@@ -17,6 +18,8 @@ VEHICLE_STATISTICS_ALL_TRIPS_URL = VEHICLE_STATISTICS_URL + '/allTrips'
 VEHICLE_CHARGING_PROFILE_URL = VEHICLE_VIN_URL + '/chargingprofile'
 VEHICLE_DESTINATIONS_URL = VEHICLE_VIN_URL + '/destinations'
 VEHICLE_RANGEMAP_URL = VEHICLE_VIN_URL + '/rangemap'
+VEHICLE_EFFICIENCY = BASE_URL_LEGACY + '/efficiency' + '/v1/{vin}'
+VEHICLE_NAVIGATION = BASE_URL_LEGACY + '/navigation' + '/v1/{vin}'
 
 SERVICE_STATUS = 'STATUS'
 SERVICE_LAST_TRIP = 'LAST_TRIP'
@@ -24,7 +27,8 @@ SERVICE_ALL_TRIPS = 'ALL_TRIPS'
 SERVICE_CHARGING_PROFILE = 'CHARGING_PROFILE'
 SERVICE_DESTINATIONS = 'DESTINATIONS'
 SERVICE_RANGEMAP = 'RANGEMAP'
-
+SERVICE_EFFICIENCY = 'EFFICIENCY'
+SERVICE_NAVIGATION = 'NAVIGATION'
 
 # Possible error codes, other codes are mapped to UNKNOWN_ERROR
 ERROR_CODE_MAPPING = {
diff --git a/bimmer_connected/efficiency.py b/bimmer_connected/efficiency.py
new file mode 100644
index 0000000..1e81954
--- /dev/null
+++ b/bimmer_connected/efficiency.py
@@ -0,0 +1,176 @@
+"""Models the efficiency of a vehicle."""
+
+import logging
+from typing import List
+
+from bimmer_connected.const import SERVICE_EFFICIENCY
+
+_LOGGER = logging.getLogger(__name__)
+
+
+class LastTrip:
+    """Last Trip.
+
+    This class provides a nicer API than parsing the JSON format directly.
+    """
+
+    def __init__(self, ccm_dict: dict):
+        self._ccm_dict = ccm_dict
+
+    @property
+    def name(self) -> str:
+        """Name."""
+        return self._ccm_dict["name"]
+
+    @property
+    def unit(self) -> str:
+        """Unit."""
+        return self._ccm_dict["unit"]
+
+    @property
+    def last_trip(self) -> str:
+        """Last Trip."""
+        return self._ccm_dict["lastTrip"]
+
+
+def backend_parameter_life_time(func):
+    """Decorator for parameters reading data from the backend.
+
+    Errors are handled in a default way.
+    """
+    def _func_wrapper(self: 'LifeTime', *args, **kwargs):
+        # pylint: disable=protected-access
+        try:
+            return func(self, *args, **kwargs)
+        except KeyError:
+            _LOGGER.debug('No data available for attribute %s!', str(func))
+            return None
+    return _func_wrapper
+
+
+class LifeTime:
+    """Life Time.
+
+    This class provides a nicer API than parsing the JSON format directly.
+    """
+
+    def __init__(self, ccm_dict: dict):
+        self._ccm_dict = ccm_dict
+
+    @property
+    @backend_parameter_life_time
+    def name(self) -> str:
+        """Name."""
+        return self._ccm_dict["name"]
+
+    @property
+    @backend_parameter_life_time
+    def unit(self) -> str:
+        """Unit."""
+        return self._ccm_dict["unit"]
+
+    @property
+    @backend_parameter_life_time
+    def life_time(self) -> str:
+        """Life Time."""
+        return self._ccm_dict["lifeTime"]
+
+
+class Characteristic:
+    """Characteristic.
+
+    This class provides a nicer API than parsing the JSON format directly.
+    """
+
+    def __init__(self, ccm_dict: dict):
+        self._ccm_dict = ccm_dict
+
+    @property
+    def characteristic(self) -> str:
+        """Characteristic."""
+        return self._ccm_dict["characteristic"]
+
+    @property
+    def quantity(self) -> int:
+        """Quantity."""
+        return int(self._ccm_dict["quantity"])
+
+
+def backend_parameter(func):
+    """Decorator for parameters reading data from the backend.
+
+    Errors are handled in a default way.
+    """
+    def _func_wrapper(self: 'Efficiency', *args, **kwargs):
+        # pylint: disable=protected-access
+        if self._state.attributes[SERVICE_EFFICIENCY] is None:
+            raise ValueError('No data available for vehicles efficiency!')
+        try:
+            return func(self, *args, **kwargs)
+        except KeyError:
+            _LOGGER.debug('No data available for attribute %s!', str(func))
+            return None
+    return _func_wrapper
+
+
+class Efficiency:  # pylint: disable=too-many-public-methods
+    """Models the navigation of a vehicle."""
+
+    def __init__(self, state):
+        """Constructor."""
+        self._state = state
+
+    @property
+    @backend_parameter
+    def attributes(self) -> dict:
+        """Retrieve all attributes from the sever.
+
+        This does not parse the results in any way.
+        """
+        return self._state.attributes[SERVICE_EFFICIENCY]
+
+    def __getattr__(self, item):
+        """Generic get function for all backend attributes."""
+        return self._state.attributes[SERVICE_EFFICIENCY][item]
+
+    @property
+    @backend_parameter
+    def model_type(self) -> str:
+        """Returns the average electric consumption."""
+        return self._state.attributes[SERVICE_EFFICIENCY]['modelType']
+
+    @property
+    @backend_parameter
+    def efficiency_quotient(self) -> int:
+        """Returns the average electric consumption."""
+        return int(self._state.attributes[SERVICE_EFFICIENCY]['efficiencyQuotient'])
+
+    @property
+    @backend_parameter
+    def last_trip_list(self) -> List[LastTrip]:
+        """Returns the average electric consumption."""
+        ret_list = []
+        last_trip_list = self._state.attributes[SERVICE_EFFICIENCY].get('lastTripList', [])
+        for trip in last_trip_list:
+            ret_list.append(LastTrip(trip))
+        return ret_list
+
+    @property
+    @backend_parameter
+    def life_time_list(self) -> List[LifeTime]:
+        """Returns the average electric consumption."""
+        ret_list = []
+        last_time_list = self._state.attributes[SERVICE_EFFICIENCY].get('lifeTimeList', [])
+        for time in last_time_list:
+            ret_list.append(LifeTime(time))
+        return ret_list
+
+    @property
+    @backend_parameter
+    def characteristic_list(self) -> List[Characteristic]:
+        """Returns the average electric consumption."""
+        ret_list = []
+        characteristic_list = self._state.attributes[SERVICE_EFFICIENCY].get('characteristicList', [])
+        for characteristic in characteristic_list:
+            ret_list.append(Characteristic(characteristic))
+        return ret_list
diff --git a/bimmer_connected/navigation.py b/bimmer_connected/navigation.py
new file mode 100644
index 0000000..cfc7754
--- /dev/null
+++ b/bimmer_connected/navigation.py
@@ -0,0 +1,180 @@
+"""Models the navigation of a vehicle."""
+
+import logging
+
+from bimmer_connected.const import SERVICE_NAVIGATION
+
+_LOGGER = logging.getLogger(__name__)
+
+
+def backend_parameter(func):
+    """Decorator for parameters reading data from the backend.
+
+    Errors are handled in a default way.
+    """
+    def _func_wrapper(self: 'Navigation', *args, **kwargs):
+        # pylint: disable=protected-access
+        if self._state.attributes[SERVICE_NAVIGATION] is None:
+            raise ValueError('No data available for vehicles navigation!')
+        try:
+            return func(self, *args, **kwargs)
+        except KeyError:
+            _LOGGER.debug('No data available for attribute %s!', str(func))
+            return None
+    return _func_wrapper
+
+
+class Navigation:  # pylint: disable=too-many-public-methods
+    """Models the navigation of a vehicle."""
+
+    def __init__(self, state):
+        """Constructor."""
+        self._state = state
+
+    @property
+    @backend_parameter
+    def attributes(self) -> dict:
+        """Retrieve all attributes from the sever.
+
+        This does not parse the results in any way.
+        """
+        return self._state.attributes[SERVICE_NAVIGATION]
+
+    def __getattr__(self, item):
+        """Generic get function for all backend attributes."""
+        return self._state.attributes[SERVICE_NAVIGATION][item]
+
+    @property
+    @backend_parameter
+    def latitude(self) -> float:
+        """Returns the average electric consumption."""
+        return float(self._state.attributes[SERVICE_NAVIGATION]['latitude'])
+
+    @property
+    @backend_parameter
+    def longitude(self) -> float:
+        """Returns the average electric consumption."""
+        return float(self._state.attributes[SERVICE_NAVIGATION]['longitude'])
+
+    @property
+    @backend_parameter
+    def iso_country_code(self) -> str:
+        """Returns the average electric consumption."""
+        return self._state.attributes[SERVICE_NAVIGATION]['isoCountryCode']
+
+    @property
+    @backend_parameter
+    def aux_power_regular(self) -> float:
+        """Returns the average electric consumption."""
+        return float(self._state.attributes[SERVICE_NAVIGATION]['auxPowerRegular'])
+
+    @property
+    @backend_parameter
+    def aux_power_eco_pro(self) -> float:
+        """Returns the average electric consumption."""
+        return float(self._state.attributes[SERVICE_NAVIGATION]['auxPowerEcoPro'])
+
+    @property
+    @backend_parameter
+    def aux_power_eco_pro_plus(self) -> float:
+        """Returns the average electric consumption."""
+        return float(self._state.attributes[SERVICE_NAVIGATION]['auxPowerEcoProPlus'])
+
+    @property
+    @backend_parameter
+    def soc(self) -> float:
+        """Returns the average electric consumption."""
+        return float(self._state.attributes[SERVICE_NAVIGATION]['soc'])
+
+    @property
+    @backend_parameter
+    def soc_max(self) -> float:
+        """Returns the average electric consumption."""
+        try:
+            return float(self._state.attributes[SERVICE_NAVIGATION]['socMax'])
+        except KeyError:
+            return float(self._state.attributes[SERVICE_NAVIGATION]['socmax'])
+
+    @property
+    @backend_parameter
+    def eco(self) -> str:
+        """Returns the average electric consumption."""
+        return self._state.attributes[SERVICE_NAVIGATION]['eco']
+
+    @property
+    @backend_parameter
+    def norm(self) -> str:
+        """Returns the average electric consumption."""
+        return self._state.attributes[SERVICE_NAVIGATION]['norm']
+
+    @property
+    @backend_parameter
+    def eco_ev(self) -> str:
+        """Returns the average electric consumption."""
+        return self._state.attributes[SERVICE_NAVIGATION]['ecoEv']
+
+    @property
+    @backend_parameter
+    def norm_ev(self) -> str:
+        """Returns the average electric consumption."""
+        return self._state.attributes[SERVICE_NAVIGATION]['normEv']
+
+    @property
+    @backend_parameter
+    def vehicle_mass(self) -> int:
+        """Returns the average electric consumption."""
+        return int(self._state.attributes[SERVICE_NAVIGATION]['vehicleMass'])
+
+    @property
+    @backend_parameter
+    def k_acc_reg(self) -> int:
+        """Returns the average electric consumption."""
+        return int(self._state.attributes[SERVICE_NAVIGATION]['kAccReg'])
+
+    @property
+    @backend_parameter
+    def k_dec_reg(self) -> int:
+        """Returns the average electric consumption."""
+        return int(self._state.attributes[SERVICE_NAVIGATION]['kDecReg'])
+
+    @property
+    @backend_parameter
+    def k_acc_eco(self) -> int:
+        """Returns the average electric consumption."""
+        return int(self._state.attributes[SERVICE_NAVIGATION]['kAccEco'])
+
+    @property
+    @backend_parameter
+    def k_dec_eco(self) -> int:
+        """Returns the average electric consumption."""
+        return int(self._state.attributes[SERVICE_NAVIGATION]['kDecEco'])
+
+    @property
+    @backend_parameter
+    def k_up(self) -> int:
+        """Returns the average electric consumption."""
+        return int(self._state.attributes[SERVICE_NAVIGATION]['kUp'])
+
+    @property
+    @backend_parameter
+    def k_down(self) -> int:
+        """Returns the average electric consumption."""
+        return int(self._state.attributes[SERVICE_NAVIGATION]['kDown'])
+
+    @property
+    @backend_parameter
+    def drive_train(self) -> str:
+        """Returns the average electric consumption."""
+        return self._state.attributes[SERVICE_NAVIGATION]['driveTrain']
+
+    @property
+    @backend_parameter
+    def pending_update(self) -> bool:
+        """Returns the average electric consumption."""
+        return bool(self._state.attributes[SERVICE_NAVIGATION]['pendingUpdate'])
+
+    @property
+    @backend_parameter
+    def vehicle_tracking(self) -> bool:
+        """Returns the average electric consumption."""
+        return bool(self._state.attributes[SERVICE_NAVIGATION]['vehicleTracking'])
diff --git a/bimmer_connected/state.py b/bimmer_connected/state.py
index 153fb4d..bcd4493 100644
--- a/bimmer_connected/state.py
+++ b/bimmer_connected/state.py
@@ -7,7 +7,8 @@ from typing import List
 from bimmer_connected.const import SERVICE_STATUS, VEHICLE_STATUS_URL, SERVICE_LAST_TRIP, \
     VEHICLE_STATISTICS_LAST_TRIP_URL, SERVICE_ALL_TRIPS, VEHICLE_STATISTICS_ALL_TRIPS_URL, \
     SERVICE_CHARGING_PROFILE, VEHICLE_CHARGING_PROFILE_URL, SERVICE_DESTINATIONS, VEHICLE_DESTINATIONS_URL, \
-    SERVICE_RANGEMAP, VEHICLE_RANGEMAP_URL
+    SERVICE_RANGEMAP, VEHICLE_RANGEMAP_URL, SERVICE_EFFICIENCY, VEHICLE_EFFICIENCY, SERVICE_NAVIGATION, \
+    VEHICLE_NAVIGATION
 
 from bimmer_connected.vehicle_status import VehicleStatus, LockState, ParkingLightState, ChargingState, \
     CheckControlMessage, ConditionBasedServiceReport, Lid, Window
@@ -16,6 +17,8 @@ from bimmer_connected.all_trips import AllTrips
 from bimmer_connected.charging_profile import ChargingProfile
 from bimmer_connected.last_destinations import LastDestinations
 from bimmer_connected.range_maps import RangeMaps
+from bimmer_connected.navigation import Navigation
+from bimmer_connected.efficiency import Efficiency
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -54,6 +57,8 @@ class VehicleState:
         self.last_trip = LastTrip(self)
         self.last_destinations = LastDestinations(self)
         self.range_maps = RangeMaps(self)
+        self.navigation = Navigation(self)
+        self.efficiency = Efficiency(self)
 
         self._url = {
             SERVICE_STATUS: VEHICLE_STATUS_URL,
@@ -61,7 +66,9 @@ class VehicleState:
             SERVICE_ALL_TRIPS: VEHICLE_STATISTICS_ALL_TRIPS_URL,
             SERVICE_CHARGING_PROFILE: VEHICLE_CHARGING_PROFILE_URL,
             SERVICE_DESTINATIONS: VEHICLE_DESTINATIONS_URL,
-            SERVICE_RANGEMAP: VEHICLE_RANGEMAP_URL}
+            SERVICE_RANGEMAP: VEHICLE_RANGEMAP_URL,
+            SERVICE_EFFICIENCY: VEHICLE_EFFICIENCY,
+            SERVICE_NAVIGATION: VEHICLE_NAVIGATION}
 
         self._key = {
             SERVICE_STATUS: 'vehicleStatus',
@@ -69,7 +76,9 @@ class VehicleState:
             SERVICE_ALL_TRIPS: 'allTrips',
             SERVICE_CHARGING_PROFILE: 'weeklyPlanner',
             SERVICE_DESTINATIONS: 'destinations',
-            SERVICE_RANGEMAP: 'rangemap'}
+            SERVICE_RANGEMAP: 'rangemap',
+            SERVICE_EFFICIENCY: '',
+            SERVICE_NAVIGATION: ''}
 
         for service in self._url:
             self._attributes[service] = {}
@@ -90,7 +99,10 @@ class VehicleState:
                 response = self._account.send_request(
                     self._url[service].format(server=self._account.server_url, vin=self._vehicle.vin),
                     logfilename=service, params=params)
-                self._attributes[service] = response.json()[self._key[service]]
+                if not self._key[service]:
+                    self._attributes[service] = response.json()
+                else:
+                    self._attributes[service] = response.json()[self._key[service]]
             except IOError:
                 _LOGGER.debug('Service %s failed', service)
 
diff --git a/bimmer_connected/vehicle.py b/bimmer_connected/vehicle.py
index f5acfe7..bbc99d7 100644
--- a/bimmer_connected/vehicle.py
+++ b/bimmer_connected/vehicle.py
@@ -20,7 +20,10 @@ class DriveTrainType(Enum):
 
 
 #: Set of drive trains that have a combustion engine
-COMBUSTION_ENGINE_DRIVE_TRAINS = {DriveTrainType.CONVENTIONAL, DriveTrainType.PHEV, DriveTrainType.BEV_REX}
+COMBUSTION_ENGINE_DRIVE_TRAINS = {DriveTrainType.CONVENTIONAL, DriveTrainType.PHEV}
+
+#: Set of drive trains that have a range extender
+RANGE_EXTENDER_DRIVE_TRAINS = {DriveTrainType.BEV_REX}
 
 #: set of drive trains that have a high voltage battery
 HV_BATTERY_DRIVE_TRAINS = {DriveTrainType.PHEV, DriveTrainType.BEV, DriveTrainType.BEV_REX}
@@ -90,6 +93,13 @@ class ConnectedDriveVehicle:
         """
         return self.drive_train in HV_BATTERY_DRIVE_TRAINS
 
+    @property
+    def has_range_extender(self) -> bool:
+        """Return True if vehicle is equipped with a range extender.
+
+        In this case we can get the state of the gas tank."""
+        return self.drive_train in RANGE_EXTENDER_DRIVE_TRAINS
+
     @property
     def has_internal_combustion_engine(self) -> bool:
         """Return True if vehicle is equipped with an internal combustion engine.
@@ -113,8 +123,11 @@ class ConnectedDriveVehicle:
                        'lastChargingEndReason', 'remaining_range_electric', 'lastChargingEndResult']
         if self.has_internal_combustion_engine:
             result += ['remaining_range_fuel']
+        if self.has_hv_battery and self.has_range_extender:
+            result += ['maxFuel', 'remaining_range_fuel']
         if self.has_hv_battery and self.has_internal_combustion_engine:
-            result += ['maxFuel']
+            result += ['fuelPercent']
+            result.remove('max_range_electric')
         return result
 
     @property
diff --git a/bimmer_connected/vehicle_status.py b/bimmer_connected/vehicle_status.py
index 9079a14..19552ff 100644
--- a/bimmer_connected/vehicle_status.py
+++ b/bimmer_connected/vehicle_status.py
@@ -335,6 +335,12 @@ class VehicleStatus:  # pylint: disable=too-many-public-methods
         """State of charge of the high voltage battery in percent."""
         return int(self._state.attributes[SERVICE_STATUS]['chargingLevelHv'])
 
+    @property
+    @backend_parameter
+    def fuel_percent(self) -> int:
+        """State of fuel in percent."""
+        return int(self._state.attributes[SERVICE_STATUS]['fuelPercent'])
+
     @property
     @backend_parameter
     def check_control_messages(self) -> List[CheckControlMessage]:


Test patch:
diff --git a/test/__init__.py b/test/__init__.py
index e6da393..2b97d3d 100644
--- a/test/__init__.py
+++ b/test/__init__.py
@@ -18,6 +18,7 @@ F15_VIN = 'F15_VIN'
 I01_NOREX_VIN = 'I01_NOREX_VIN'
 F45_VIN = 'F45_VIN'
 F31_VIN = 'F31_VIN'
+G30_PHEV_OS7_VIN = 'G30_PHEV_OS7_VIN'
 
 #: Mapping of VINs to test data directories
 TEST_VEHICLE_DATA = {
@@ -28,6 +29,7 @@ TEST_VEHICLE_DATA = {
     F15_VIN: 'F15',
     F45_VIN: 'F45',
     F31_VIN: 'F31',
+    G30_PHEV_OS7_VIN: 'G30_PHEV_OS7'
 }
 
 _AUTH_RESPONSE_HEADERS = {
@@ -60,7 +62,7 @@ ATTRIBUTE_MAPPING = {
     'parkingLight': 'parking_lights',
     'remainingRangeFuel': 'remaining_range_fuel',
     'updateTime': 'timestamp',
-    'chargingTimeRemaining': 'charging_time_remaining',
+    'chargingTimeRemaining': 'charging_time_remaining'
 }
 
 # these are additional attributes in the API, not available in the status.json
@@ -71,6 +73,7 @@ ADDITIONAL_ATTRIBUTES = [
     'lids',                     # required for existing Home Assistant binary sensors
     'windows',                  # required for existing Home Assistant binary sensors
     'lights_parking',           # required for existing Home Assistant binary sensors
+    'steering',                 # para not available in all vehicles
 ]
 
 # there attributes are not (yet) implemented
@@ -81,7 +84,8 @@ MISSING_ATTRIBUTES = [
     'chargingTimeRemaining',      # only present while charging
     'sunroof',                    # not available in all vehicles
     'lights_parking',             # required for existing Home Assistant binary sensors
-
+    'steering',                   # para not available in all vehicles
+    'vehicleCountry',             # para not available in all vehicles
 ]
 
 POI_DATA = {
diff --git a/test/responses/G30_PHEV_OS7/all_trips.json b/test/responses/G30_PHEV_OS7/all_trips.json
new file mode 100644
index 0000000..487cc0b
--- /dev/null
+++ b/test/responses/G30_PHEV_OS7/all_trips.json
@@ -0,0 +1,30 @@
+{
+	"allTrips": {
+		"avgElectricConsumption": {
+			"communityLow": -4.75,
+			"communityAverage": 5.89,
+			"communityHigh": 21.11
+		},
+		"avgRecuperation": {
+			"communityLow": 1.27,
+			"communityAverage": 5.31,
+			"communityHigh": 19.77
+		},
+		"chargecycleRange": {
+			"communityAverage": 11.04,
+			"communityHigh": 169.59
+		},
+		"totalElectricDistance": {
+			"communityLow": 468.19,
+			"communityAverage": 15879.33,
+			"communityHigh": 58982
+		},
+		"avgCombinedConsumption": {
+			"communityLow": 2.45,
+			"communityAverage": 6.06,
+			"communityHigh": 10.86
+		},
+		"resetDate": "2020-01-11T21:51:10+0000",
+		"batterySizeMax": 9140
+	}
+}
\ No newline at end of file
diff --git a/test/responses/G30_PHEV_OS7/charging_profile.json b/test/responses/G30_PHEV_OS7/charging_profile.json
new file mode 100644
index 0000000..03b9108
--- /dev/null
+++ b/test/responses/G30_PHEV_OS7/charging_profile.json
@@ -0,0 +1,39 @@
+{
+	"weeklyPlanner": {
+		"climatizationEnabled": false,
+		"chargingMode": "IMMEDIATE_CHARGING",
+		"chargingPreferences": "NO_PRESELECTION",
+		"timer1": {
+			"departureTime": "06:55",
+			"timerEnabled": true,
+			"weekdays": [
+				"MONDAY",
+				"TUESDAY",
+				"WEDNESDAY",
+				"THURSDAY",
+				"FRIDAY"
+			]
+		},
+		"timer2": {
+			"departureTime": "07:00",
+			"timerEnabled": false,
+			"weekdays": []
+		},
+		"timer3": {
+			"departureTime": "07:00",
+			"timerEnabled": false,
+			"weekdays": []
+		},
+		"overrideTimer": {
+			"departureTime": "05:54",
+			"timerEnabled": false,
+			"weekdays": [
+				"MONDAY"
+			]
+		},
+		"preferredChargingWindow": {
+			"startTime": "00:00",
+			"endTime": "00:00"
+		}
+	}
+}
\ No newline at end of file
diff --git a/test/responses/G30_PHEV_OS7/efficiency.json b/test/responses/G30_PHEV_OS7/efficiency.json
new file mode 100644
index 0000000..5a0c1b9
--- /dev/null
+++ b/test/responses/G30_PHEV_OS7/efficiency.json
@@ -0,0 +1,55 @@
+{
+	"modelType": "PHEV",
+	"lastTripList": [
+		{
+			"name": "LASTTRIP_DELTA_KM",
+			"unit": "KM",
+			"lastTrip": "--"
+		},
+		{
+			"name": "LASTTRIP_DELTA_TIME",
+			"unit": "NONE",
+			"lastTrip": "--"
+		},
+		{
+			"name": "COMBINED_AVG_CONSUMED_LITERS_OVERALL",
+			"unit": "L_PER_100KM",
+			"lastTrip": "--"
+		}
+	],
+	"lifeTimeList": [
+		{
+			"name": "CUMULATED_ELECTRIC_DRIVEN_DISTANCE",
+			"unit": "KM",
+			"lifeTime": "--"
+		},
+		{
+			"name": "SAVED_LITERS_OVERALL",
+			"unit": "LITER",
+			"lifeTime": "0.0"
+		},
+		{
+			"name": "TIMESTAMP_STATISTICS_RESET",
+			"lifeTime": "12.01.2020"
+		}
+	],
+	"efficiencyQuotient": 0,
+	"characteristicList": [
+		{
+			"characteristic": "CONSUMPTION",
+			"quantity": 0
+		},
+		{
+			"characteristic": "DRIVING_MODE",
+			"quantity": 0
+		},
+		{
+			"characteristic": "CHARGING_BEHAVIOUR",
+			"quantity": 0
+		},
+		{
+			"characteristic": "ELECTRIC_DRIVING",
+			"quantity": 0
+		}
+	]
+}
\ No newline at end of file
diff --git a/test/responses/G30_PHEV_OS7/last_destinations.json b/test/responses/G30_PHEV_OS7/last_destinations.json
new file mode 100644
index 0000000..517115c
--- /dev/null
+++ b/test/responses/G30_PHEV_OS7/last_destinations.json
@@ -0,0 +1,3 @@
+{
+	"destinations": []
+}
\ No newline at end of file
diff --git a/test/responses/G30_PHEV_OS7/last_trip.json b/test/responses/G30_PHEV_OS7/last_trip.json
new file mode 100644
index 0000000..80a9063
--- /dev/null
+++ b/test/responses/G30_PHEV_OS7/last_trip.json
@@ -0,0 +1,3 @@
+{
+	"lastTrip": {}
+}
\ No newline at end of file
diff --git a/test/responses/G30_PHEV_OS7/navigation.json b/test/responses/G30_PHEV_OS7/navigation.json
new file mode 100644
index 0000000..6772bbd
--- /dev/null
+++ b/test/responses/G30_PHEV_OS7/navigation.json
@@ -0,0 +1,12 @@
+{
+	"latitude": 52.82273,
+	"longitude": 8.8276,
+	"isoCountryCode": "DEU",
+	"auxPowerRegular": 1.4,
+	"auxPowerEcoPro": 1.2,
+	"auxPowerEcoProPlus": 0.4,
+	"soc": 4.98700008381234,
+	"pendingUpdate": false,
+	"vehicleTracking": false,
+	"socmax": 9.48
+}
\ No newline at end of file
diff --git a/test/responses/G30_PHEV_OS7/range_maps.json b/test/responses/G30_PHEV_OS7/range_maps.json
new file mode 100644
index 0000000..c21462b
--- /dev/null
+++ b/test/responses/G30_PHEV_OS7/range_maps.json
@@ -0,0 +1,3 @@
+{
+	"rangemap": {}
+}
\ No newline at end of file
diff --git a/test/responses/G30_PHEV_OS7/status.json b/test/responses/G30_PHEV_OS7/status.json
new file mode 100644
index 0000000..40d60c1
--- /dev/null
+++ b/test/responses/G30_PHEV_OS7/status.json
@@ -0,0 +1,75 @@
+{
+	"vehicleStatus": {
+		"vin": "G30_PHEV_OS7_VIN",
+		"mileage": 5050,
+		"updateReason": "DOOR_STATE_CHANGED",
+		"updateTime": "2020-07-25T12:27:42+0000",
+		"doorDriverFront": "CLOSED",
+		"doorDriverRear": "CLOSED",
+		"doorPassengerFront": "CLOSED",
+		"doorPassengerRear": "CLOSED",
+		"windowDriverFront": "CLOSED",
+		"windowDriverRear": "CLOSED",
+		"windowPassengerFront": "CLOSED",
+		"windowPassengerRear": "CLOSED",
+		"trunk": "CLOSED",
+		"rearWindow": "INVALID",
+		"hood": "CLOSED",
+		"doorLockState": "SECURED",
+		"parkingLight": "OFF",
+		"positionLight": "OFF",
+		"remainingFuel": 39,
+		"remainingRangeElectric": 32,
+		"remainingRangeElectricMls": 19,
+		"remainingRangeFuel": 484,
+		"remainingRangeFuelMls": 300,
+		"fuelPercent": 92.4,
+		"connectionStatus": "DISCONNECTED",
+		"chargingStatus": "INVALID",
+		"chargingLevelHv": 85,
+		"lastChargingEndReason": "CHARGING_GOAL_REACHED",
+		"lastChargingEndResult": "SUCCESS",
+		"position": {
+			"lat": 52.82273,
+			"lon": 8.82767,
+			"heading": 81,
+			"status": "OK"
+		},
+		"internalDataTimeUTC": "2020-07-25T12:27:43+0000",
+		"singleImmediateCharging": false,
+		"chargingConnectionType": "CONDUCTIVE",
+		"chargingInductivePositioning": "NOT_POSITIONED",
+		"vehicleCountry": "DE",
+		"checkControlMessages": [],
+		"cbsData": [
+			{
+				"cbsType": "OIL",
+				"cbsState": "OK",
+				"cbsRemainingMileage": 26000,
+				"cbsDueDate": "2021-12",
+				"cbsDescription": "Next service due when the stated distance has been covered or by the specified date."
+			},
+			{
+				"cbsType": "BRAKE_FLUID",
+				"cbsState": "OK",
+				"cbsDueDate": "2022-12",
+				"cbsDescription": "Next change due at the latest by the stated date."
+			},
+			{
+				"cbsType": "VEHICLE_TUV",
+				"cbsState": "OK",
+				"cbsDueDate": "2023-02",
+				"cbsDescription": "Next statutory vehicle inspection due by the stated date."
+			},
+			{
+				"cbsType": "VEHICLE_CHECK",
+				"cbsState": "OK",
+				"cbsRemainingMileage": 60000,
+				"cbsDueDate": "2023-12",
+				"cbsDescription": "Next visual inspection due when the stated distance has been covered or by the stated date."
+			}
+		],
+		"DCS_CCH_Activation": "NA",
+		"DCS_CCH_Ongoing": false
+	}
+}
\ No newline at end of file
diff --git a/test/responses/vehicles.json b/test/responses/vehicles.json
index fe73476..95b88f7 100644
--- a/test/responses/vehicles.json
+++ b/test/responses/vehicles.json
@@ -1,407 +1,461 @@
 {
-  "vehicles" : [ {
-    "vehicleFinderRestriction" : "NONE",
-    "doorUnlock" : "ACTIVATED",
-    "color" : "SOPHISTOGRAU BRILLANTEFFEKT METALLI",
-    "onlineSearchMode" : "MAP",
-    "breakdownNumber" : "+4912345678",
-    "smartSolution" : "NOT_SUPPORTED",
-    "yearOfConstruction" : 2018,
-    "driveTrain" : "CONV",
-    "rangeMap" : "NOT_SUPPORTED",
-    "vehicleFinder" : "ACTIVATED",
-    "a4a" : "BLUETOOTH",
-    "hornBlow" : "ACTIVATED",
-    "chargeNow" : "NOT_SUPPORTED",
-    "countryCode" : "V6",
-    "bodytype" : "G31",
-    "lightFlash" : "ACTIVATED",
-    "vin" : "G31_NBTevo_VIN",
-    "model" : "530i xDrive",
-    "ipa" : "NOT_SUPPORTED",
-    "brand" : "BMW",
-    "climateControl" : "DEPARTURE_TIMER",
-    "sendPoi" : "ACTIVATED",
-    "lastDestinations" : "NOT_SUPPORTED",
-    "doorLock" : "ACTIVATED",
-    "chargingControl" : "NOT_SUPPORTED",
-    "onlineSearchProvider" : "GOOGLE",
-    "steering" : "LH",
-    "intermodalRouting" : "NOT_AVAILABLE",
-    "lscType" : "LSC_BASIS",
-    "hasAlarmSystem" : true,
-    "statisticsCommunityEnabled" : false,
-    "climateNow" : "ACTIVATED",
-    "fuelType" : "PETROL",
-    "hub" : "HUB_ECE",
-    "remote360" : "NOT_SUPPORTED",
-    "hmiVersion" : "ID5",
-    "climateFunction" : "PARK_HEATING",
-    "colorCode" : "A90",
-    "carCloud" : "ACTIVATED",
-    "statisticsAvailable" : false
-  },
-  {
-    "vehicleFinderRestriction" : "NONE",
-    "doorUnlock" : "ACTIVATED",
-    "color" : "ALPINWEISS  III",
-    "onlineSearchMode" : "MAP",
-    "breakdownNumber" : "+4989358111111",
-    "smartSolution" : "NOT_SUPPORTED",
-    "yearOfConstruction" : 2017,
-    "driveTrain" : "CONV",
-    "rangeMap" : "NOT_SUPPORTED",
-    "vehicleFinder" : "ACTIVATED",
-    "a4a" : "BLUETOOTH",
-    "hornBlow" : "ACTIVATED",
-    "chargeNow" : "NOT_SUPPORTED",
-    "countryCode" : "V1-NL",
-    "bodytype" : "F48",
-    "lightFlash" : "ACTIVATED",
-    "vin" : "F48_VIN",
-    "model" : "X1 sDrive18i",
-    "ipa" : "NOT_SUPPORTED",
-    "brand" : "BMW",
-    "climateControl" : "START_TIMER",
-    "sendPoi" : "ACTIVATED",
-    "lastDestinations" : "NOT_SUPPORTED",
-    "doorLock" : "ACTIVATED",
-    "chargingControl" : "NOT_SUPPORTED",
-    "onlineSearchProvider" : "GOOGLE",
-    "steering" : "LH",
-    "intermodalRouting" : "NOT_AVAILABLE",
-    "lscType" : "LSC_BASIS",
-    "hasAlarmSystem" : true,
-    "statisticsCommunityEnabled" : false,
-    "climateNow" : "ACTIVATED",
-    "fuelType" : "PETROL",
-    "hub" : "HUB_ECE",
-    "remote360" : "NOT_SUPPORTED",
-    "hmiVersion" : "ID5",
-    "dealer" : {
-      "country" : "NL",
-      "city" : "city",
-      "phone" : "phone",
-      "street" : "street",
-      "postalCode" : "1234 AB",
-      "name" : "BMW dealer"
-    },
-    "climateFunction" : "VENTILATION",
-    "colorCode" : "300",
-    "carCloud" : "ACTIVATED",
-    "statisticsAvailable" : false
-  }
-  ,
-  {
-    "vehicleFinderRestriction" : "NONE",
-    "doorUnlock" : "ACTIVATED",
-    "color" : "ARRAVANIGRAU/BMW i BLAU",
-    "onlineSearchMode" : "MAP",
-    "breakdownNumber" : "+4989358957103",
-    "smartSolution" : "NOT_SUPPORTED",
-    "yearOfConstruction" : 2014,
-    "driveTrain" : "BEV_REX",
-    "rangeMap" : "RANGE_CIRCLE",
-    "vehicleFinder" : "ACTIVATED",
-    "a4a" : "USB_ONLY",
-    "hornBlow" : "ACTIVATED",
-    "chargeNow" : "NOT_SUPPORTED",
-    "licensePlate" : "ABC000",
-    "countryCode" : "V1-R1-SE",
-    "bodytype" : "I01",
-    "lightFlash" : "ACTIVATED",
-    "vin" : "I01_VIN",
-    "model" : "i3 (+ REX)",
-    "ipa" : "NOT_SUPPORTED",
-    "brand" : "BMW_I",
-    "climateControl" : "NOT_SUPPORTED",
-    "sendPoi" : "ACTIVATED",
-    "lastDestinations" : "SUPPORTED",
-    "doorLock" : "ACTIVATED",
-    "chargingControl" : "WEEKLY_PLANNER",
-    "onlineSearchProvider" : "GOOGLE",
-    "steering" : "LH",
-    "intermodalRouting" : "NOT_AVAILABLE",
-    "supportedChargingModes" : [ "AC_LOW", "AC_HIGH", "DC" ],
-    "lscType" : "I_LSC_IMM",
-    "hasAlarmSystem" : false,
-    "statisticsCommunityEnabled" : false,
-    "climateNow" : "ACTIVATED",
-    "hub" : "HUB_ECE",
-    "remote360" : "NOT_SUPPORTED",
-    "hmiVersion" : "ID4",
-    "dealer" : {
-      "country" : "SE",
-      "city" : "Solna",
-      "phone" : "+46 8 7353900",
-      "street" : "G�rdsv�gen 9-11",
-      "postalCode" : "169 70",
-      "name" : "Bavaria Sverige Bil AB/ Solna"
-    },
-    "climateFunction" : "AIRCONDITIONING",
-    "colorCode" : "B74",
-    "carCloud" : "NOT_SUPPORTED",
-    "statisticsAvailable" : true
-  },
-  {
-    "vehicleFinderRestriction" : "NONE",
-    "doorUnlock" : "NOT_SUPPORTED",
-    "color" : "BLACK SAPPHIRE METALLIC",
-    "onlineSearchMode" : "MAP",
-    "breakdownNumber" : "+4989358957103",
-    "smartSolution" : "NOT_SUPPORTED",
-    "yearOfConstruction" : 2017,
-    "driveTrain" : "CONV",
-    "rangeMap" : "NOT_SUPPORTED",
-    "vehicleFinder" : "ACTIVATED",
-    "a4a" : "BLUETOOTH",
-    "hornBlow" : "ACTIVATED",
-    "chargeNow" : "NOT_SUPPORTED",
-    "countryCode" : "V2-CA",
-    "bodytype" : "F15",
-    "lightFlash" : "ACTIVATED",
-    "vin" : "F15_VIN",
-    "model" : "X5 xDrive35i",
-    "ipa" : "NOT_SUPPORTED",
-    "brand" : "BMW",
-    "climateControl" : "DEPARTURE_TIMER",
-    "sendPoi" : "ACTIVATED",
-    "lastDestinations" : "NOT_SUPPORTED",
-    "doorLock" : "ACTIVATED",
-    "chargingControl" : "NOT_SUPPORTED",
-    "steering" : "LH",
-    "intermodalRouting" : "NOT_AVAILABLE",
-    "lscType" : "LSC_BASIS",
-    "hasAlarmSystem" : true,
-    "statisticsCommunityEnabled" : false,
-    "climateNow" : "ACTIVATED",
-    "fuelType" : "PETROL",
-    "hub" : "HUB_US",
-    "remote360" : "NOT_SUPPORTED",
-    "hmiVersion" : "ID5",
-    "dealer" : {
-      "country" : "CA",
-      "city" : "Ottawa",
-      "phone" : "1-866-599-4999",
-      "street" : "85 Wellington St",
-      "postalCode" : "K1A 1A1",
-      "name" : "Parliament of Canada"
-    },
-    "climateFunction" : "VENTILATION",
-    "colorCode" : "475",
-    "carCloud" : "NOT_SUPPORTED",
-    "statisticsAvailable" : false
-  },
-  {
-    "vehicleFinderRestriction": "NONE",
-    "doorUnlock": "ACTIVATED",
-    "color": "SOLARORANGE MET. M. AKZENT FROZEN G",
-    "onlineSearchMode": "MAP",
-    "breakdownNumber": "+4989358957103",
-    "smartSolution": "NOT_SUPPORTED",
-    "yearOfConstruction": 2014,
-    "driveTrain": "BEV",
-    "rangeMap": "RANGE_CIRCLE",
-    "vehicleFinder": "ACTIVATED",
-    "a4a": "USB_ONLY",
-    "hornBlow": "ACTIVATED",
-    "chargeNow": "NOT_SUPPORTED",
-    "licensePlate": "HIDDEN",
-    "countryCode": "B3-ZA",
-    "bodytype": "I01",
-    "lightFlash": "ACTIVATED",
-    "vin": "I01_NOREX_VIN",
-    "model": "i3",
-    "ipa": "NOT_SUPPORTED",
-    "brand": "BMW_I",
-    "climateControl": "NOT_SUPPORTED",
-    "sendPoi": "ACTIVATED",
-    "lastDestinations": "SUPPORTED",
-    "doorLock": "ACTIVATED",
-    "chargingControl": "WEEKLY_PLANNER",
-    "onlineSearchProvider": "GOOGLE",
-    "steering": "RH",
-    "intermodalRouting": "NOT_AVAILABLE",
-    "supportedChargingModes": [
-      "AC_LOW",
-      "AC_HIGH"
-    ],
-    "lscType": "I_LSC_IMM",
-    "hasAlarmSystem": true,
-    "statisticsCommunityEnabled": true,
-    "climateNow": "ACTIVATED",
-    "hub": "HUB_ECE",
-    "remote360": "NOT_SUPPORTED",
-    "hmiVersion": "ID4",
-    "dealer": {
-      "country": "ZA",
-      "city": "Midrand",
-      "phone": "+27 12 522 3000",
-      "street": "1 Bavaria Avenue",
-      "postalCode": "1685",
-      "name": "BMW (South Africa) (Pty) Ltd. ZA"
-    },
-    "climateFunction": "AIRCONDITIONING",
-    "colorCode": "B78",
-    "carCloud": "NOT_SUPPORTED",
-    "statisticsAvailable": true
-  },
-  {
-    "a4a": "USB_ONLY",
-    "bodytype": "F45",
-    "brand": "BMW",
-    "breakdownNumber": "+4989358957103",
-    "carCloud": "NOT_SUPPORTED",
-    "chargeNow": "NOT_SUPPORTED",
-    "chargingControl": "NOT_SUPPORTED",
-    "climateControl": "START_TIMER",
-    "climateFunction": "VENTILATION",
-    "climateNow": "ACTIVATED",
-    "color": "MEDITERRANBLAU METALLIC",
-    "colorCode": "C10",
-    "countryCode": "V1-ES",
-    "dealer": {
-      "city": "Madrid",
-      "country": "ES",
-      "name": "BMW Iberica S.A.",
-      "phone": "+34 913350505",
-      "postalCode": "28050",
-      "street": "Avenida de Burgos ,118"
-    },
-    "doorLock": "ACTIVATED",
-    "doorUnlock": "ACTIVATED",
-    "driveTrain": "CONV",
-    "fuelType": "PETROL",
-    "hasAlarmSystem": false,
-    "hmiVersion": "ID4",
-    "hornBlow": "ACTIVATED",
-    "hub": "HUB_ECE",
-    "intermodalRouting": "NOT_AVAILABLE",
-    "ipa": "NOT_SUPPORTED",
-    "lastDestinations": "NOT_SUPPORTED",
-    "licensePlate": "some_license_plate",
-    "lightFlash": "ACTIVATED",
-    "lscType": "NOT_SUPPORTED",
-    "model": "225i",
-    "onlineSearchMode": "MAP",
-    "onlineSearchProvider": "GOOGLE",
-    "rangeMap": "NOT_SUPPORTED",
-    "remote360": "NOT_SUPPORTED",
-    "sendPoi": "ACTIVATED",
-    "smartSolution": "NOT_SUPPORTED",
-    "statisticsAvailable": false,
-    "statisticsCommunityEnabled": false,
-    "steering": "LH",
-    "vehicleFinder": "ACTIVATED",
-    "vehicleFinderRestriction": "NONE",
-    "vin": "F45_VIN",
-    "yearOfConstruction": 2016
-  },
-  {
-    "a4a": "USB_ONLY",
-    "bodytype": "F31",
-    "brand": "BMW",
-    "breakdownNumber": "+4989358957103",
-    "carCloud": "NOT_SUPPORTED",
-    "chargeNow": "NOT_SUPPORTED",
-    "chargingControl": "NOT_SUPPORTED",
-    "climateControl": "START_TIMER",
-    "climateControlRES": "NOT_SUPPORTED",
-    "climateFunction": "VENTILATION",
-    "climateNow": "ACTIVATED",
-    "climateNowRES": "NOT_SUPPORTED",
-    "color": "PLATINSILBER METALLIC",
-    "colorCode": "C08",
-    "countryCode": "V1-UK",
-    "dealer": {
-        "city": "Farnborough",
-        "country": "GB",
-        "name": "BMW (UK) Ltd. ICS - DIRECT SUPPLY",
-        "phone": "+44 1252 920000",
-        "postalCode": "GU14 0FB",
-        "street": "Summit ONE"
-    },
-    "doorLock": "ACTIVATED",
-    "doorUnlock": "ACTIVATED",
-    "driveTrain": "CONV",
-    "fuelType": "DIESEL",
-    "hasAlarmSystem": true,
-    "hmiVersion": "ID4",
-    "hornBlow": "NOT_SUPPORTED",
-    "hub": "HUB_ECE",
-    "intermodalRouting": "NOT_AVAILABLE",
-    "ipa": "NOT_SUPPORTED",
-    "lastDestinations": "NOT_SUPPORTED",
-    "licensePlate": "some_license_plate",
-    "lightFlash": "ACTIVATED",
-    "lscType": "NOT_SUPPORTED",
-    "model": "320d",
-    "onlineSearchMode": "MAP",
-    "onlineSearchProvider": "GOOGLE",
-    "rangeMap": "NOT_SUPPORTED",
-    "remote360": "NOT_SUPPORTED",
-    "remoteSoftwareUpgrade": "NOT_SUPPORTED",
-    "sendPoi": "ACTIVATED",
-    "smartSolution": "NOT_SUPPORTED",
-    "statisticsAvailable": false,
-    "statisticsCommunityEnabled": false,
-    "steering": "RH",
-    "vehicleFinder": "ACTIVATED",
-    "vehicleFinderRestriction": "NONE",
-    "vin": "F31_VIN",
-    "yearOfConstruction": 2015
-  },
-  {
-    "a4a": "NOT_SUPPORTED",
-    "bodytype": "F35",
-    "brand": "BMW",
-    "breakdownNumber": "+4989358957103",
-    "carCloud": "NOT_SUPPORTED",
-    "chargeNow": "NOT_SUPPORTED",
-    "chargingControl": "NOT_SUPPORTED",
-    "climateControl": "NOT_SUPPORTED",
-    "climateControlRES": "NOT_SUPPORTED",
-    "climateFunction": "VENTILATION",
-    "climateNow": "NOT_SUPPORTED",
-    "climateNowRES": "NOT_SUPPORTED",
-    "color": "MINERALWEISS METALLIC",
-    "colorCode": "A96",
-    "countryCode": "V5-CN",
-    "dealer": {
-      "city": "Beijing",
-      "country": "CN",
-      "name": "Beijing Baozen Baiwang Automotive Sales Co., Ltd.",
-      "phone": "+86 10 62826789",
-      "postalCode": "100094",
-      "street": "F2 Baiwang Green Valley"
-    },
-    "doorLock": "NOT_SUPPORTED",
-    "doorUnlock": "NOT_SUPPORTED",
-    "driveTrain": "CONV",
-    "fuelType": "PETROL",
-    "hasAlarmSystem": false,
-    "hmiVersion": "ID5",
-    "hornBlow": "NOT_SUPPORTED",
-    "hub": "HUB_CN",
-    "intermodalRouting": "NOT_AVAILABLE",
-    "ipa": "NOT_SUPPORTED",
-    "lastDestinations": "NOT_SUPPORTED",
-    "licensePlate": "some_license_plate",
-    "lightFlash": "NOT_SUPPORTED",
-    "lscType": "NOT_SUPPORTED",
-    "model": "328Li",
-    "onlineSearchMode": "MAP",
-    "rangeMap": "NOT_SUPPORTED",
-    "remote360": "NOT_SUPPORTED",
-    "remoteSoftwareUpgrade": "NOT_SUPPORTED",
-    "sendPoi": "NOT_SUPPORTED",
-    "smartSolution": "NOT_SUPPORTED",
-    "statisticsAvailable": false,
-    "statisticsCommunityEnabled": false,
-    "steering": "LH",
-    "vehicleFinder": "NOT_SUPPORTED",
-    "vin": "F31_VIN",
-    "yearOfConstruction": 2015
-  }
-  ]
-}
+	"vehicles": [
+		{
+			"vehicleFinderRestriction": "NONE",
+			"doorUnlock": "ACTIVATED",
+			"color": "SOPHISTOGRAU BRILLANTEFFEKT METALLI",
+			"onlineSearchMode": "MAP",
+			"breakdownNumber": "+4912345678",
+			"smartSolution": "NOT_SUPPORTED",
+			"yearOfConstruction": 2018,
+			"driveTrain": "CONV",
+			"rangeMap": "NOT_SUPPORTED",
+			"vehicleFinder": "ACTIVATED",
+			"a4a": "BLUETOOTH",
+			"hornBlow": "ACTIVATED",
+			"chargeNow": "NOT_SUPPORTED",
+			"countryCode": "V6",
+			"bodytype": "G31",
+			"lightFlash": "ACTIVATED",
+			"vin": "G31_NBTevo_VIN",
+			"model": "530i xDrive",
+			"ipa": "NOT_SUPPORTED",
+			"brand": "BMW",
+			"climateControl": "DEPARTURE_TIMER",
+			"sendPoi": "ACTIVATED",
+			"lastDestinations": "NOT_SUPPORTED",
+			"doorLock": "ACTIVATED",
+			"chargingControl": "NOT_SUPPORTED",
+			"onlineSearchProvider": "GOOGLE",
+			"steering": "LH",
+			"intermodalRouting": "NOT_AVAILABLE",
+			"lscType": "LSC_BASIS",
+			"hasAlarmSystem": true,
+			"statisticsCommunityEnabled": false,
+			"climateNow": "ACTIVATED",
+			"fuelType": "PETROL",
+			"hub": "HUB_ECE",
+			"remote360": "NOT_SUPPORTED",
+			"hmiVersion": "ID5",
+			"climateFunction": "PARK_HEATING",
+			"colorCode": "A90",
+			"carCloud": "ACTIVATED",
+			"statisticsAvailable": false
+		},
+		{
+			"vehicleFinderRestriction": "NONE",
+			"doorUnlock": "ACTIVATED",
+			"color": "ALPINWEISS  III",
+			"onlineSearchMode": "MAP",
+			"breakdownNumber": "+4989358111111",
+			"smartSolution": "NOT_SUPPORTED",
+			"yearOfConstruction": 2017,
+			"driveTrain": "CONV",
+			"rangeMap": "NOT_SUPPORTED",
+			"vehicleFinder": "ACTIVATED",
+			"a4a": "BLUETOOTH",
+			"hornBlow": "ACTIVATED",
+			"chargeNow": "NOT_SUPPORTED",
+			"countryCode": "V1-NL",
+			"bodytype": "F48",
+			"lightFlash": "ACTIVATED",
+			"vin": "F48_VIN",
+			"model": "X1 sDrive18i",
+			"ipa": "NOT_SUPPORTED",
+			"brand": "BMW",
+			"climateControl": "START_TIMER",
+			"sendPoi": "ACTIVATED",
+			"lastDestinations": "NOT_SUPPORTED",
+			"doorLock": "ACTIVATED",
+			"chargingControl": "NOT_SUPPORTED",
+			"onlineSearchProvider": "GOOGLE",
+			"steering": "LH",
+			"intermodalRouting": "NOT_AVAILABLE",
+			"lscType": "LSC_BASIS",
+			"hasAlarmSystem": true,
+			"statisticsCommunityEnabled": false,
+			"climateNow": "ACTIVATED",
+			"fuelType": "PETROL",
+			"hub": "HUB_ECE",
+			"remote360": "NOT_SUPPORTED",
+			"hmiVersion": "ID5",
+			"dealer": {
+				"country": "NL",
+				"city": "city",
+				"phone": "phone",
+				"street": "street",
+				"postalCode": "1234 AB",
+				"name": "BMW dealer"
+			},
+			"climateFunction": "VENTILATION",
+			"colorCode": "300",
+			"carCloud": "ACTIVATED",
+			"statisticsAvailable": false
+		},
+		{
+			"vehicleFinderRestriction": "NONE",
+			"doorUnlock": "ACTIVATED",
+			"color": "ARRAVANIGRAU/BMW i BLAU",
+			"onlineSearchMode": "MAP",
+			"breakdownNumber": "+4989358957103",
+			"smartSolution": "NOT_SUPPORTED",
+			"yearOfConstruction": 2014,
+			"driveTrain": "BEV_REX",
+			"rangeMap": "RANGE_CIRCLE",
+			"vehicleFinder": "ACTIVATED",
+			"a4a": "USB_ONLY",
+			"hornBlow": "ACTIVATED",
+			"chargeNow": "NOT_SUPPORTED",
+			"licensePlate": "ABC000",
+			"countryCode": "V1-R1-SE",
+			"bodytype": "I01",
+			"lightFlash": "ACTIVATED",
+			"vin": "I01_VIN",
+			"model": "i3 (+ REX)",
+			"ipa": "NOT_SUPPORTED",
+			"brand": "BMW_I",
+			"climateControl": "NOT_SUPPORTED",
+			"sendPoi": "ACTIVATED",
+			"lastDestinations": "SUPPORTED",
+			"doorLock": "ACTIVATED",
+			"chargingControl": "WEEKLY_PLANNER",
+			"onlineSearchProvider": "GOOGLE",
+			"steering": "LH",
+			"intermodalRouting": "NOT_AVAILABLE",
+			"supportedChargingModes": [
+				"AC_LOW",
+				"AC_HIGH",
+				"DC"
+			],
+			"lscType": "I_LSC_IMM",
+			"hasAlarmSystem": false,
+			"statisticsCommunityEnabled": false,
+			"climateNow": "ACTIVATED",
+			"hub": "HUB_ECE",
+			"remote360": "NOT_SUPPORTED",
+			"hmiVersion": "ID4",
+			"dealer": {
+				"country": "SE",
+				"city": "Solna",
+				"phone": "+46 8 7353900",
+				"street": "G�rdsv�gen 9-11",
+				"postalCode": "169 70",
+				"name": "Bavaria Sverige Bil AB/ Solna"
+			},
+			"climateFunction": "AIRCONDITIONING",
+			"colorCode": "B74",
+			"carCloud": "NOT_SUPPORTED",
+			"statisticsAvailable": true
+		},
+		{
+			"vehicleFinderRestriction": "NONE",
+			"doorUnlock": "NOT_SUPPORTED",
+			"color": "BLACK SAPPHIRE METALLIC",
+			"onlineSearchMode": "MAP",
+			"breakdownNumber": "+4989358957103",
+			"smartSolution": "NOT_SUPPORTED",
+			"yearOfConstruction": 2017,
+			"driveTrain": "CONV",
+			"rangeMap": "NOT_SUPPORTED",
+			"vehicleFinder": "ACTIVATED",
+			"a4a": "BLUETOOTH",
+			"hornBlow": "ACTIVATED",
+			"chargeNow": "NOT_SUPPORTED",
+			"countryCode": "V2-CA",
+			"bodytype": "F15",
+			"lightFlash": "ACTIVATED",
+			"vin": "F15_VIN",
+			"model": "X5 xDrive35i",
+			"ipa": "NOT_SUPPORTED",
+			"brand": "BMW",
+			"climateControl": "DEPARTURE_TIMER",
+			"sendPoi": "ACTIVATED",
+			"lastDestinations": "NOT_SUPPORTED",
+			"doorLock": "ACTIVATED",
+			"chargingControl": "NOT_SUPPORTED",
+			"steering": "LH",
+			"intermodalRouting": "NOT_AVAILABLE",
+			"lscType": "LSC_BASIS",
+			"hasAlarmSystem": true,
+			"statisticsCommunityEnabled": false,
+			"climateNow": "ACTIVATED",
+			"fuelType": "PETROL",
+			"hub": "HUB_US",
+			"remote360": "NOT_SUPPORTED",
+			"hmiVersion": "ID5",
+			"dealer": {
+				"country": "CA",
+				"city": "Ottawa",
+				"phone": "1-866-599-4999",
+				"street": "85 Wellington St",
+				"postalCode": "K1A 1A1",
+				"name": "Parliament of Canada"
+			},
+			"climateFunction": "VENTILATION",
+			"colorCode": "475",
+			"carCloud": "NOT_SUPPORTED",
+			"statisticsAvailable": false
+		},
+		{
+			"vehicleFinderRestriction": "NONE",
+			"doorUnlock": "ACTIVATED",
+			"color": "SOLARORANGE MET. M. AKZENT FROZEN G",
+			"onlineSearchMode": "MAP",
+			"breakdownNumber": "+4989358957103",
+			"smartSolution": "NOT_SUPPORTED",
+			"yearOfConstruction": 2014,
+			"driveTrain": "BEV",
+			"rangeMap": "RANGE_CIRCLE",
+			"vehicleFinder": "ACTIVATED",
+			"a4a": "USB_ONLY",
+			"hornBlow": "ACTIVATED",
+			"chargeNow": "NOT_SUPPORTED",
+			"licensePlate": "HIDDEN",
+			"countryCode": "B3-ZA",
+			"bodytype": "I01",
+			"lightFlash": "ACTIVATED",
+			"vin": "I01_NOREX_VIN",
+			"model": "i3",
+			"ipa": "NOT_SUPPORTED",
+			"brand": "BMW_I",
+			"climateControl": "NOT_SUPPORTED",
+			"sendPoi": "ACTIVATED",
+			"lastDestinations": "SUPPORTED",
+			"doorLock": "ACTIVATED",
+			"chargingControl": "WEEKLY_PLANNER",
+			"onlineSearchProvider": "GOOGLE",
+			"steering": "RH",
+			"intermodalRouting": "NOT_AVAILABLE",
+			"supportedChargingModes": [
+				"AC_LOW",
+				"AC_HIGH"
+			],
+			"lscType": "I_LSC_IMM",
+			"hasAlarmSystem": true,
+			"statisticsCommunityEnabled": true,
+			"climateNow": "ACTIVATED",
+			"hub": "HUB_ECE",
+			"remote360": "NOT_SUPPORTED",
+			"hmiVersion": "ID4",
+			"dealer": {
+				"country": "ZA",
+				"city": "Midrand",
+				"phone": "+27 12 522 3000",
+				"street": "1 Bavaria Avenue",
+				"postalCode": "1685",
+				"name": "BMW (South Africa) (Pty) Ltd. ZA"
+			},
+			"climateFunction": "AIRCONDITIONING",
+			"colorCode": "B78",
+			"carCloud": "NOT_SUPPORTED",
+			"statisticsAvailable": true
+		},
+		{
+			"a4a": "USB_ONLY",
+			"bodytype": "F45",
+			"brand": "BMW",
+			"breakdownNumber": "+4989358957103",
+			"carCloud": "NOT_SUPPORTED",
+			"chargeNow": "NOT_SUPPORTED",
+			"chargingControl": "NOT_SUPPORTED",
+			"climateControl": "START_TIMER",
+			"climateFunction": "VENTILATION",
+			"climateNow": "ACTIVATED",
+			"color": "MEDITERRANBLAU METALLIC",
+			"colorCode": "C10",
+			"countryCode": "V1-ES",
+			"dealer": {
+				"city": "Madrid",
+				"country": "ES",
+				"name": "BMW Iberica S.A.",
+				"phone": "+34 913350505",
+				"postalCode": "28050",
+				"street": "Avenida de Burgos ,118"
+			},
+			"doorLock": "ACTIVATED",
+			"doorUnlock": "ACTIVATED",
+			"driveTrain": "CONV",
+			"fuelType": "PETROL",
+			"hasAlarmSystem": false,
+			"hmiVersion": "ID4",
+			"hornBlow": "ACTIVATED",
+			"hub": "HUB_ECE",
+			"intermodalRouting": "NOT_AVAILABLE",
+			"ipa": "NOT_SUPPORTED",
+			"lastDestinations": "NOT_SUPPORTED",
+			"licensePlate": "some_license_plate",
+			"lightFlash": "ACTIVATED",
+			"lscType": "NOT_SUPPORTED",
+			"model": "225i",
+			"onlineSearchMode": "MAP",
+			"onlineSearchProvider": "GOOGLE",
+			"rangeMap": "NOT_SUPPORTED",
+			"remote360": "NOT_SUPPORTED",
+			"sendPoi": "ACTIVATED",
+			"smartSolution": "NOT_SUPPORTED",
+			"statisticsAvailable": false,
+			"statisticsCommunityEnabled": false,
+			"steering": "LH",
+			"vehicleFinder": "ACTIVATED",
+			"vehicleFinderRestriction": "NONE",
+			"vin": "F45_VIN",
+			"yearOfConstruction": 2016
+		},
+		{
+			"a4a": "USB_ONLY",
+			"bodytype": "F31",
+			"brand": "BMW",
+			"breakdownNumber": "+4989358957103",
+			"carCloud": "NOT_SUPPORTED",
+			"chargeNow": "NOT_SUPPORTED",
+			"chargingControl": "NOT_SUPPORTED",
+			"climateControl": "START_TIMER",
+			"climateControlRES": "NOT_SUPPORTED",
+			"climateFunction": "VENTILATION",
+			"climateNow": "ACTIVATED",
+			"climateNowRES": "NOT_SUPPORTED",
+			"color": "PLATINSILBER METALLIC",
+			"colorCode": "C08",
+			"countryCode": "V1-UK",
+			"dealer": {
+				"city": "Farnborough",
+				"country": "GB",
+				"name": "BMW (UK) Ltd. ICS - DIRECT SUPPLY",
+				"phone": "+44 1252 920000",
+				"postalCode": "GU14 0FB",
+				"street": "Summit ONE"
+			},
+			"doorLock": "ACTIVATED",
+			"doorUnlock": "ACTIVATED",
+			"driveTrain": "CONV",
+			"fuelType": "DIESEL",
+			"hasAlarmSystem": true,
+			"hmiVersion": "ID4",
+			"hornBlow": "NOT_SUPPORTED",
+			"hub": "HUB_ECE",
+			"intermodalRouting": "NOT_AVAILABLE",
+			"ipa": "NOT_SUPPORTED",
+			"lastDestinations": "NOT_SUPPORTED",
+			"licensePlate": "some_license_plate",
+			"lightFlash": "ACTIVATED",
+			"lscType": "NOT_SUPPORTED",
+			"model": "320d",
+			"onlineSearchMode": "MAP",
+			"onlineSearchProvider": "GOOGLE",
+			"rangeMap": "NOT_SUPPORTED",
+			"remote360": "NOT_SUPPORTED",
+			"remoteSoftwareUpgrade": "NOT_SUPPORTED",
+			"sendPoi": "ACTIVATED",
+			"smartSolution": "NOT_SUPPORTED",
+			"statisticsAvailable": false,
+			"statisticsCommunityEnabled": false,
+			"steering": "RH",
+			"vehicleFinder": "ACTIVATED",
+			"vehicleFinderRestriction": "NONE",
+			"vin": "F31_VIN",
+			"yearOfConstruction": 2015
+		},
+		{
+			"a4a": "NOT_SUPPORTED",
+			"bodytype": "F35",
+			"brand": "BMW",
+			"breakdownNumber": "+4989358957103",
+			"carCloud": "NOT_SUPPORTED",
+			"chargeNow": "NOT_SUPPORTED",
+			"chargingControl": "NOT_SUPPORTED",
+			"climateControl": "NOT_SUPPORTED",
+			"climateControlRES": "NOT_SUPPORTED",
+			"climateFunction": "VENTILATION",
+			"climateNow": "NOT_SUPPORTED",
+			"climateNowRES": "NOT_SUPPORTED",
+			"color": "MINERALWEISS METALLIC",
+			"colorCode": "A96",
+			"countryCode": "V5-CN",
+			"dealer": {
+				"city": "Beijing",
+				"country": "CN",
+				"name": "Beijing Baozen Baiwang Automotive Sales Co., Ltd.",
+				"phone": "+86 10 62826789",
+				"postalCode": "100094",
+				"street": "F2 Baiwang Green Valley"
+			},
+			"doorLock": "NOT_SUPPORTED",
+			"doorUnlock": "NOT_SUPPORTED",
+			"driveTrain": "CONV",
+			"fuelType": "PETROL",
+			"hasAlarmSystem": false,
+			"hmiVersion": "ID5",
+			"hornBlow": "NOT_SUPPORTED",
+			"hub": "HUB_CN",
+			"intermodalRouting": "NOT_AVAILABLE",
+			"ipa": "NOT_SUPPORTED",
+			"lastDestinations": "NOT_SUPPORTED",
+			"licensePlate": "some_license_plate",
+			"lightFlash": "NOT_SUPPORTED",
+			"lscType": "NOT_SUPPORTED",
+			"model": "328Li",
+			"onlineSearchMode": "MAP",
+			"rangeMap": "NOT_SUPPORTED",
+			"remote360": "NOT_SUPPORTED",
+			"remoteSoftwareUpgrade": "NOT_SUPPORTED",
+			"sendPoi": "NOT_SUPPORTED",
+			"smartSolution": "NOT_SUPPORTED",
+			"statisticsAvailable": false,
+			"statisticsCommunityEnabled": false,
+			"steering": "LH",
+			"vehicleFinder": "NOT_SUPPORTED",
+			"vin": "F31_VIN",
+			"yearOfConstruction": 2015
+		},
+		{
+			"vin": "G30_PHEV_OS7_VIN",
+			"model": "530e xDrive iPerformance",
+			"bodytype": "G30",
+			"driveTrain": "PHEV",
+			"color": "PLATINSILBER METALLIC",
+			"colorCode": "300",
+			"brand": "BMW",
+			"yearOfConstruction": 2019,
+			"statisticsCommunityEnabled": false,
+			"statisticsAvailable": false,
+			"hub": "HUB_ECE",
+			"hasAlarmSystem": true,
+			"breakdownNumber": "+4989358957103",
+			"countryCode": "V6",
+			"egoVehiclePath": null,
+			"chargingUpdateMode": "NORMAL_PROGNOSE_BASED",
+			"steering": "LH",
+			"vehicleFinderRestriction": "NONE",
+			"hmiVersion": "id7",
+			"a4a": "NOT_SUPPORTED",
+			"vehicleFinder": "ACTIVATED",
+			"remote360": "NOT_SUPPORTED",
+			"hornBlow": "ACTIVATED",
+			"lightFlash": "ACTIVATED",
+			"doorLock": "ACTIVATED",
+			"doorUnlock": "ACTIVATED",
+			"climateControl": "NOT_SUPPORTED",
+			"climateNow": "ACTIVATED",
+			"climateNowRES": "NOT_SUPPORTED",
+			"climateControlRES": "NOT_SUPPORTED",
+			"chargingControl": "WEEKLY_PLANNER",
+			"chargeNow": "NOT_SUPPORTED",
+			"sendPoi": "ACTIVATED",
+			"rangeMap": "NOT_SUPPORTED",
+			"lastDestinations": "NOT_SUPPORTED",
+			"intermodalRouting": "NOT_AVAILABLE",
+			"climateFunction": "AIRCONDITIONING",
+			"onlineSearchMode": "MAP",
+			"onlineSearchProvider": "GOOGLE",
+			"smartSolution": "NOT_SUPPORTED",
+			"carCloud": "NOT_SUPPORTED",
+			"supportedChargingModes": [
+				"AC_LOW"
+			],
+			"lscType": "LSC_PHEV",
+			"ipa": "NOT_SUPPORTED",
+			"puStep": "1119",
+			"remoteSoftwareUpgrade": "NOT_SUPPORTED"
+		}
+	]
+}
\ No newline at end of file
diff --git a/test/test_account.py b/test/test_account.py
index 1b15820..715b9ce 100644
--- a/test/test_account.py
+++ b/test/test_account.py
@@ -18,7 +18,7 @@ class TestAccount(unittest.TestCase):
         with mock.patch('bimmer_connected.account.requests', new=backend_mock):
             account = ConnectedDriveAccount(TEST_USERNAME, TEST_PASSWORD, Regions.REST_OF_WORLD)
             self.assertIsNotNone(account._oauth_token)
-            self.assertEqual(8, len(account.vehicles))
+            self.assertEqual(9, len(account.vehicles))
             vehicle = account.get_vehicle(G31_VIN)
             self.assertEqual(G31_VIN, vehicle.vin)
 
diff --git a/test/test_efficiency.py b/test/test_efficiency.py
new file mode 100644
index 0000000..7bcaa27
--- /dev/null
+++ b/test/test_efficiency.py
@@ -0,0 +1,31 @@
+"""Test for Efficiency"""
+import unittest
+from unittest import mock
+from test import load_response_json
+from bimmer_connected.account import ConnectedDriveAccount
+from bimmer_connected.state import VehicleState
+from bimmer_connected.const import SERVICE_EFFICIENCY
+
+G30_PHEV_OS7_TEST_DATA = load_response_json('G30_PHEV_OS7/efficiency.json')
+
+
+class TestState(unittest.TestCase):
+    """Test for Efficiency."""
+
+    # pylint: disable=protected-access
+
+    def test_parse_g30_phev_os7(self):
+        """Test if the parsing of the attributes is working."""
+        account = mock.MagicMock(ConnectedDriveAccount)
+        state = VehicleState(account, None)
+        state._attributes[SERVICE_EFFICIENCY] = G30_PHEV_OS7_TEST_DATA
+        self.assertEqual('PHEV', state.efficiency.model_type)
+        self.assertEqual(0, state.efficiency.efficiency_quotient)
+        self.assertEqual('LASTTRIP_DELTA_KM', state.efficiency.last_trip_list[0].name)
+        self.assertEqual('KM', state.efficiency.last_trip_list[0].unit)
+        self.assertEqual('--', state.efficiency.last_trip_list[0].last_trip)
+        self.assertEqual('TIMESTAMP_STATISTICS_RESET', state.efficiency.life_time_list[2].name)
+        self.assertIsNone(state.efficiency.life_time_list[2].unit)
+        self.assertEqual('12.01.2020', state.efficiency.life_time_list[2].life_time)
+        self.assertEqual('DRIVING_MODE', state.efficiency.characteristic_list[1].characteristic)
+        self.assertEqual(0, state.efficiency.characteristic_list[1].quantity)
diff --git a/test/test_navigation.py b/test/test_navigation.py
new file mode 100644
index 0000000..1d49045
--- /dev/null
+++ b/test/test_navigation.py
@@ -0,0 +1,43 @@
+"""Test for Navigation"""
+import unittest
+from unittest import mock
+from test import load_response_json
+from bimmer_connected.account import ConnectedDriveAccount
+from bimmer_connected.state import VehicleState
+from bimmer_connected.const import SERVICE_NAVIGATION
+
+G30_PHEV_OS7_TEST_DATA = load_response_json('G30_PHEV_OS7/navigation.json')
+
+
+class TestState(unittest.TestCase):
+    """Test for Navigation."""
+
+    # pylint: disable=protected-access
+
+    def test_parse_g30_phev_os7(self):
+        """Test if the parsing of the attributes is working."""
+        account = mock.MagicMock(ConnectedDriveAccount)
+        state = VehicleState(account, None)
+        state._attributes[SERVICE_NAVIGATION] = G30_PHEV_OS7_TEST_DATA
+        self.assertEqual(52.82273, state.navigation.latitude)
+        self.assertEqual(8.8276, state.navigation.longitude)
+        self.assertEqual('DEU', state.navigation.iso_country_code)
+        self.assertEqual(1.4, state.navigation.aux_power_regular)
+        self.assertEqual(1.2, state.navigation.aux_power_eco_pro)
+        self.assertEqual(0.4, state.navigation.aux_power_eco_pro_plus)
+        self.assertEqual(4.98700008381234, state.navigation.soc)
+        self.assertEqual(9.48, state.navigation.soc_max)
+        self.assertIsNone(state.navigation.eco)
+        self.assertIsNone(state.navigation.norm)
+        self.assertIsNone(state.navigation.eco_ev)
+        self.assertIsNone(state.navigation.norm_ev)
+        self.assertIsNone(state.navigation.vehicle_mass)
+        self.assertIsNone(state.navigation.k_acc_reg)
+        self.assertIsNone(state.navigation.k_dec_reg)
+        self.assertIsNone(state.navigation.k_acc_eco)
+        self.assertIsNone(state.navigation.k_dec_eco)
+        self.assertIsNone(state.navigation.k_up)
+        self.assertIsNone(state.navigation.k_down)
+        self.assertIsNone(state.navigation.drive_train)
+        self.assertFalse(state.navigation.pending_update)
+        self.assertFalse(state.navigation.vehicle_tracking)
diff --git a/test/test_vehicle.py b/test/test_vehicle.py
index 6ff6a8e..0e78683 100644
--- a/test/test_vehicle.py
+++ b/test/test_vehicle.py
@@ -3,7 +3,7 @@ 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, F31_VIN, TEST_VEHICLE_DATA, \
-    ATTRIBUTE_MAPPING, MISSING_ATTRIBUTES, ADDITIONAL_ATTRIBUTES
+    ATTRIBUTE_MAPPING, MISSING_ATTRIBUTES, ADDITIONAL_ATTRIBUTES, G30_PHEV_OS7_VIN
 
 from bimmer_connected.vehicle import ConnectedDriveVehicle, DriveTrainType
 from bimmer_connected.account import ConnectedDriveAccount
@@ -42,10 +42,12 @@ class TestVehicle(unittest.TestCase):
             account = ConnectedDriveAccount(TEST_USERNAME, TEST_PASSWORD, TEST_REGION)
 
         for vehicle in account.vehicles:
-            self.assertEqual(vehicle.vin in [G31_VIN, F48_VIN, F15_VIN, I01_VIN, F45_VIN, F31_VIN],
+            self.assertEqual(vehicle.vin in [G31_VIN, F48_VIN, F15_VIN, F45_VIN, F31_VIN, G30_PHEV_OS7_VIN],
                              vehicle.has_internal_combustion_engine)
-            self.assertEqual(vehicle.vin in [I01_VIN, I01_NOREX_VIN],
+            self.assertEqual(vehicle.vin in [I01_VIN, I01_NOREX_VIN, G30_PHEV_OS7_VIN],
                              vehicle.has_hv_battery)
+            self.assertEqual(vehicle.vin in [I01_VIN],
+                             vehicle.has_range_extender)
 
     def test_parsing_of_lsc_type(self):
         """Test parsing the lsc type field."""