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))
示例#2
0
    def test_parsing_attributes(self):
        """Test parsing different attributes of the vehicle.

        Just make sure parsing that no exception is raised.
        """
        backend_mock = BackendMock()
        with mock.patch('bimmer_connected.account.requests', new=backend_mock):
            backend_mock.setup_default_vehicles()
            account = ConnectedDriveAccount(TEST_USERNAME, TEST_PASSWORD,
                                            TEST_COUNTRY)
            account.update_vehicle_states()

            for vehicle in account.vehicles:
                print('testing vehicle {}'.format(vehicle.name))
                state = vehicle.state

                self.assertIsNotNone(state.lids)
                self.assertIsNotNone(state.is_vehicle_tracking_enabled)
                self.assertIsNotNone(state.windows)
                self.assertIsNotNone(state.condition_based_services)

                if vehicle.vin != F32_VIN:
                    # these values are not available in the F32
                    self.assertIsNotNone(state.door_lock_state)
                    self.assertIsNotNone(state.timestamp)
                    self.assertIsNotNone(state.mileage)
                    self.assertIsNotNone(state.remaining_fuel)
                    self.assertIsNotNone(state.all_windows_closed)
示例#3
0
def send_poi_from_address(args) -> None:
    """Create Point of Interest from OSM Nominatim and send to car."""
    account = ConnectedDriveAccount(args.username, args.password, get_region_from_name(args.region))
    vehicle = account.get_vehicle(args.vin)
    address = [(str(' '.join(args.address)))]
    try:
        response = requests.get("https://nominatim.openstreetmap.org",
                                params={
                                    "q": address,
                                    "format": "json",
                                    "addressdetails": 1,
                                    "limit": 1
                                }).json()[0]
    except IndexError:
        print('\nAddress not found')
        sys.exit(1)
    address = response.get("address", {})
    city = address.get("city")
    town = address.get("town")

    poi_data = dict(
        lat=response["lat"],
        lon=response["lon"],
        name=args.name,
        street=address.get("road"),
        city=town if city is None and town is not None else None,
        postal_code=address.get("postcode"),
        country=address.get("country")
    )
    vehicle.remote_services.trigger_send_poi(poi_data)
示例#4
0
def send_poi(args) -> None:
    """Send Point Of Interest to car."""
    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,
                          street=args.street, city=args.city, postalCode=args.postalcode, country=args.country)
    vehicle.send_poi(poi)
示例#5
0
    def test_parsing_attributes(self):
        """Test parsing different attributes of the vehicle.

        Just make sure parsing that no exception is raised.
        """
        backend_mock = BackendMock()
        with mock.patch('bimmer_connected.account.requests', new=backend_mock):
            backend_mock.setup_default_vehicles()
            account = ConnectedDriveAccount(TEST_USERNAME, TEST_PASSWORD, TEST_REGION)
            account.update_vehicle_states()

            for vehicle in account.vehicles:
                print('testing vehicle {}'.format(vehicle.name))
                state = vehicle.state

                self.assertIsNotNone(state.lids)
                self.assertIsNotNone(state.is_vehicle_tracking_enabled)
                self.assertIsNotNone(state.windows)
                self.assertIsNotNone(state.condition_based_services)

                self.assertIsNotNone(state.door_lock_state)
                self.assertIsNotNone(state.timestamp)
                self.assertGreater(state.mileage, 0)
                self.assertGreater(state.remaining_range_total, 0)
                self.assertIsNotNone(state.remaining_fuel)
                self.assertIsNotNone(state.all_windows_closed)
                self.assertEqual(0, len(state.check_control_messages))
                self.assertFalse(state.has_check_control_messages)

                for attrib in vehicle.drive_train_attributes:
                    print(attrib, getattr(state, attrib))
                    # charging_time is only set when charging
                    if attrib != 'charging_time_remaining':
                        self.assertIsNotNone(getattr(state, attrib), attrib)
示例#6
0
def get_status(args) -> None:
    """Get the vehicle status."""
    if args.json:
        for handler in logging.root.handlers[:]:
            logging.root.removeHandler(handler)

    account = ConnectedDriveAccount(args.username, args.password,
                                    get_region_from_name(args.region))
    if args.lat and args.lng:
        for vehicle in account.vehicles:
            vehicle.set_observer_position(args.lat, args.lng)
    account.update_vehicle_states()

    if args.json:
        print(to_json(account.vehicles))
    else:
        print('Found {} vehicles: {}'.format(
            len(account.vehicles),
            ','.join([v.name for v in account.vehicles])))

        for vehicle in account.vehicles:
            print('VIN: {}'.format(vehicle.vin))
            print('Mileage: {}'.format(vehicle.status.mileage))
            print('Vehicle data:')
            print(to_json(vehicle, indent=4))
示例#7
0
 def test_invalid_send_response(self):
     """Test parsing the results of an invalid request"""
     backend_mock = BackendMock()
     with mock.patch('bimmer_connected.account.requests', new=backend_mock):
         account = ConnectedDriveAccount(TEST_USERNAME, TEST_PASSWORD, Regions.REST_OF_WORLD)
         with self.assertRaises(IOError):
             account.send_request('invalid_url')
示例#8
0
def send_message(args) -> None:
    """Send a message to car."""
    account = ConnectedDriveAccount(args.username, args.password,
                                    get_region_from_name(args.region))
    vehicle = account.get_vehicle(args.vin)
    msg_data = dict(text=args.text, subject=args.subject)
    vehicle.remote_services.trigger_send_message(msg_data)
示例#9
0
 def test_us_header(self):
     """Test if the host is set correctly in the request."""
     backend_mock = BackendMock()
     with mock.patch('bimmer_connected.account.requests', new=backend_mock):
         ConnectedDriveAccount(TEST_USERNAME, TEST_PASSWORD, Regions.NORTH_AMERICA)
         request = [r for r in backend_mock.last_request if 'oauth' in r.url][0]
         self.assertEqual('b2vapi.bmwgroup.us', request.headers['Host'])
    def __init__(self, username: str, password: str, country: str,
                 name: str) -> None:
        """Constructor."""
        from bimmer_connected.account import ConnectedDriveAccount

        self.account = ConnectedDriveAccount(username, password, country)
        self.name = name
        self._update_listeners = []
示例#11
0
    def test_parsing_of_lsc_type(self):
        """Test parsing the lsc type field."""
        backend_mock = BackendMock()
        with mock.patch('bimmer_connected.account.requests', new=backend_mock):
            account = ConnectedDriveAccount(TEST_USERNAME, TEST_PASSWORD, TEST_REGION)

        for vehicle in account.vehicles:
            self.assertIsNotNone(vehicle.lsc_type)
示例#12
0
    def __init__(self, username: str, password: str, region_str: str,
                 name: str, read_only) -> None:
        """Initialize account."""
        region = get_region_from_name(region_str)

        self.read_only = read_only
        self.account = ConnectedDriveAccount(username, password, region)
        self.name = name
        self._update_listeners = []
示例#13
0
def image(args) -> None:
    """Download a rendered image of the vehicle."""
    account = ConnectedDriveAccount(args.username, args.password, get_region_from_name(args.region))
    vehicle = account.get_vehicle(args.vin)

    with open('image.png', 'wb') as output_file:
        image_data = vehicle.get_vehicle_image(400, 400, VehicleViewDirection.FRONT)
        output_file.write(image_data)
    print('vehicle image saved to image.png')
示例#14
0
 def test_update_data_error(self):
     """Test with server returning an error."""
     backend_mock = BackendMock()
     with mock.patch('bimmer_connected.account.requests', new=backend_mock):
         account = ConnectedDriveAccount(TEST_USERNAME, TEST_PASSWORD,
                                         TEST_COUNTRY)
         vehicle = account.get_vehicle(G31_VIN)
         with self.assertRaises(IOError):
             vehicle.update_state()
示例#15
0
def get_status(args) -> None:
    """Get the vehicle status."""

    _LOGGER = logging.getLogger(__name__)
    for rtime in [1, 1, 1, 5, 30, 60, None]:
        try:
            account = ConnectedDriveAccount(args.username, args.password, get_region_from_name(args.region))
        except IOError as e:
            if rtime is not None:
                _LOGGER.debug('Request failed. Retry in {} seconds.'.format(rtime))
                time.sleep(rtime)
                continue
            else:
                raise
        break

    if args.lat and args.lng:
        for vehicle in account.vehicles:
            vehicle.set_observer_position(args.lat, args.lng)

    for rtime in [1, 1, 1, 5, 30, 60, None]:
        try:
            account.update_vehicle_states()
        except IOError as e:
            if rtime is not None:
                _LOGGER.debug('Request failed. Retry in {} seconds.'.format(rtime))
                time.sleep(rtime)
                continue
            else:
                raise
        break

    dict_resp = []
    for vehicle in account.vehicles:

        for rtime in [1, 1, 1, 5, 30, 60, None]:
            try:
                vehicle.last_trip.update_data()
            except IOError as e:
                if rtime is not None:
                    _LOGGER.debug('Request failed. Retry in {} seconds.'.format(rtime))
                    time.sleep(rtime)
                    continue
                else:
                    raise
            break

        dict_resp.append({
            'vin': vehicle.vin,
            'mileage': vehicle.state.mileage,
            'properties': vehicle.attributes,
            'status': vehicle.state.attributes,
            'last_trip': vehicle.last_trip.attributes
        })

    print(json.dumps(dict_resp, indent=4))
示例#16
0
 def test_invalid_password_china(self):
     """Test parsing the results of an invalid password."""
     with requests_mock.Mocker(adapter=get_base_adapter()) as mock:
         mock.post(
             "/eadrax-coas/v1/login/pwd",
             json=load_response(RESPONSE_DIR / "auth" / "auth_cn_login_error.json"),
             status_code=422,
         )
         with self.assertRaises(HTTPError):
             ConnectedDriveAccount(TEST_USERNAME, TEST_PASSWORD, get_region_from_name("china"))
示例#17
0
def light_flash(args) -> None:
    """Trigger the vehicle to flash its lights."""
    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_light_flash()
    print(status.state)
示例#18
0
 def test_invalid_password(self):
     """Test parsing the results of an invalid password."""
     with requests_mock.Mocker(adapter=get_base_adapter()) as mock:
         mock.post(
             "/gcdm/oauth/authenticate",
             json=load_response(RESPONSE_DIR / "auth" / "auth_error_wrong_password.json"),
             status_code=401,
         )
         with self.assertRaises(HTTPError):
             ConnectedDriveAccount(TEST_USERNAME, TEST_PASSWORD, TEST_REGION)
示例#19
0
 def test_token_vehicles(self):
     """Test getting backend token and vehicle list."""
     backend_mock = BackendMock()
     with mock.patch('bimmer_connected.account.requests', new=backend_mock):
         account = ConnectedDriveAccount(TEST_USERNAME, TEST_PASSWORD, TEST_COUNTRY)
         self.assertIsNotNone(account._oauth_token)
         self.assertEqual(5, len(account.vehicles))
         vin = 'G31_NBTEvo_VIN'
         vehicle = account.get_vehicle(vin)
         self.assertEqual(vehicle.vin, vin)
示例#20
0
    def test_vehicle_search_case(self):
        """Check if the search for the vehicle by VIN is NOT case sensitive."""
        backend_mock = BackendMock()
        with mock.patch('bimmer_connected.account.requests', new=backend_mock):
            account = ConnectedDriveAccount(TEST_USERNAME, TEST_PASSWORD, TEST_REGION)

        vin = account.vehicles[1].vin
        self.assertEqual(vin, account.get_vehicle(vin).vin)
        self.assertEqual(vin, account.get_vehicle(vin.lower()).vin)
        self.assertEqual(vin, account.get_vehicle(vin.upper()).vin)
示例#21
0
 def test_server_error(self):
     """Test parsing the results of a server error."""
     with requests_mock.Mocker(adapter=get_base_adapter()) as mock:
         mock.post(
             "/gcdm/oauth/authenticate",
             text=load_response(RESPONSE_DIR / "auth" / "auth_error_internal_error.txt"),
             status_code=500,
         )
         with self.assertRaises(HTTPError):
             ConnectedDriveAccount(TEST_USERNAME, TEST_PASSWORD, TEST_REGION)
示例#22
0
    def test_statistics_available(self):
        """Test parsing the statistics_available field."""
        backend_mock = BackendMock()
        with mock.patch('bimmer_connected.account.requests', new=backend_mock):
            account = ConnectedDriveAccount(TEST_USERNAME, TEST_PASSWORD, TEST_REGION)
        g31 = account.get_vehicle(G31_VIN)
        f45 = account.get_vehicle(F45_VIN)

        self.assertFalse(g31.statistics_available)
        self.assertTrue(f45.statistics_available)
示例#23
0
    def test_set_observer_value(self):
        """Test set_observer_position with valid arguments."""
        backend_mock = BackendMock()
        with mock.patch('bimmer_connected.account.requests', new=backend_mock):
            account = ConnectedDriveAccount(TEST_USERNAME, TEST_PASSWORD, Regions.REST_OF_WORLD)

            account.set_observer_position(1.0, 2.0)
            for vehicle in account.vehicles:
                self.assertEqual(vehicle.observer_latitude, 1.0)
                self.assertEqual(vehicle.observer_longitude, 2.0)
示例#24
0
    def test_token_vehicles(self):
        """Test getting backend token and vehicle list."""
        backend_mock = BackendMock()
        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(5, len(account.vehicles))
            vehicle = account.get_vehicle(G31_VIN)
            self.assertEqual(G31_VIN, vehicle.vin)

            self.assertIsNone(account.get_vehicle('invalid_vin'))
    def __init__(self, username: str, password: str, region_str: str,
                 name: str) -> None:
        """Constructor."""
        from bimmer_connected.account import ConnectedDriveAccount
        from bimmer_connected.country_selector import get_region_from_name

        region = get_region_from_name(region_str)

        self.account = ConnectedDriveAccount(username, password, region)
        self.name = name
        self._update_listeners = []
示例#26
0
    def test_parsing_attributes(self):
        """Test parsing different attributes of the vehicle."""
        backend_mock = BackendMock()
        with mock.patch('bimmer_connected.account.requests', new=backend_mock):
            account = ConnectedDriveAccount(TEST_USERNAME, TEST_PASSWORD,
                                            TEST_COUNTRY)

        for vehicle in account.vehicles:
            self.assertIsNotNone(vehicle.drive_train)
            self.assertIsNotNone(vehicle.name)
            self.assertIsNotNone(vehicle.has_rex)
示例#27
0
def get_all_trips(args) -> None:
    """Downlad statistics of all trips"""
    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
    print(json.dumps(vehicle.get_vehicle_alltrips(), indent=4))
示例#28
0
def get_vehicle_rangemap(args) -> None:
    """Get a set of lat/lon points defining a polygon bounding vehicle range"""
    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
    print(json.dumps(vehicle.get_vehicle_rangemap(), indent=4))
示例#29
0
def get_vehicle_destinations(args) -> None:
    """Shows the destinations you've previously sent to the car."""
    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
    print(json.dumps(vehicle.get_vehicle_destinations(), indent=4))
示例#30
0
def get_vehicle_charging_profile(args) -> None:
    """Download one-time and weekly charging schedules and settings"""
    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
    print(json.dumps(vehicle.get_vehicle_charging_profile(), indent=4))