Coder Social home page Coder Social logo

bmw-i-remote's Introduction

BMW i Remote API

A reverse engineered interface for the BMW i3 Electric Car, created initially by Terence Eden, with some code modified by Quentin Stafford-Fraser.

Buy me a coffee

Description

These API calls are designed to allow you to interact with your BMW i3. They were reverse engineered from the official BMW i Remote Android app.

Your use of these API calls is entirely at your own risk. They are neither officially provided nor sanctioned.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Servers

There are three API servers.

  • https://b2vapi.bmwgroup.cn:8592 China
  • https://b2vapi.bmwgroup.us USA
  • https://b2vapi.bmwgroup.com Europe / Rest of World

Authorisation

In order to authenticate against the API you will need to be registered on BMW's Connected Drive service.

You will need:

  1. Your ConnectedDrive registered email address.
  2. Your ConnectedDrive registered password.
  3. The i Remote API Key.
  4. The i Remote API Secret.

You can get the i Remote details from either decompiling the Android App or from intercepting communications between your phone and the BMW server. This is left as an exercise for the reader ☺

Firstly, we use Basic authentication. That means taking the API Key and Secret and Base64 encoding them.

So key:secret becomes a2V5OnNlY3JldA==

We also need to send the following parameters as

  • Content-Type: application/x-www-form-urlencoded
 grant_type=password
&username=whatever%40example.com
&password=p4ssw0rd
&scope=remote_services+vehicle_data

Here's how to do it with curl:

curl \
   -H "Authorization: Basic a2V5OnNlY3JldA==" \
   -H "Content-Type: application/x-www-form-urlencoded" \
   -d "grant_type=password&username=whatever%40example.com&password=p4ssw0rd&scope=remote_services+vehicle_data" \
   "https://b2vapi.bmwgroup.com/webapi/oauth/token/"

If everything has worked, you should get back the following JSON:

{
  "access_token": "RCQ1hLP4AFaUBW9BjcPUN3i4WgkwF90R",
  "token_type": "Bearer",
  "expires_in": 28800,
  "refresh_token": "7WgKmEJ2kD1ydl9Hefp01eS8qDGzKnzjeORpA6vtsoFIEanz",
  "scope": "vehicle_data remote_services"
}

You must include

  • Authorization: Bearer RCQ1hLP4AFaUBW9BjcPUN3i4WgkwF90R

in your headers with every request.

The expires_in is in seconds - giving you 8 hours before you have to renew the token.

I've no idea what the refresh_token is for. Once the access_token expires, you can simply re-authenticate and gain a new one.

API

You must include

  • Authorization: Bearer RCQ1hLP4AFaUBW9BjcPUN3i4WgkwF90R

in your headers with every request.

Get Vehicle Data

  • /webapi/v1/user/vehicles/
    • Remember to include the Authorization: Bearer header.

Response

Returns a list of entries, one per registered vehicle.

[
  {
    "remote360": "NOT_SUPPORTED",
    "chargingControl": "WEEKLY_PLANNER",
    "countryCode": "V1-UK",
    "hornBlow": "NOT_SUPPORTED",
    "brand": "BMW_I",
    "smartSolution": "NOT_SUPPORTED",
    "hasAlarmSystem": true,
    "climateControl": "NOT_SUPPORTED",
    "doorUnlock": "ACTIVATED",
    "rangeMap": "RANGE_POLYGON",
    "climateFunction": "AIRCONDITIONING",
    "lscType": "I_LSC_IMM",
    "hub": "HUB_ECE",
    "statisticsAvailable": true,
    "doorLock": "ACTIVATED",
    "intermodalRouting": "AVAILABLE",
    "model": "I3 +REX",
    "vehicleFinder": "ACTIVATED",
    "color": "SOLARORANGE MET. M. AKZE",
    "vin": "WAB1C23456V123456",
    "bodytype": "I01",
    "chargeNow": "NOT_SUPPORTED",
    "supportedChargingModes": [
      "AC_LOW",
      "AC_HIGH",
      "DC"
    ],
    "sendPoi": "ACTIVATED",
    "yearOfConstruction": 2014,
    "climateNow": "ACTIVATED",
    "lightFlash": "ACTIVATED",
    "driveTrain": "BEV_REX",
    "licensePlate": "AB64 1BC",
    "statisticsCommunityEnabled": true,
    "colorCode": "B78",
    "onlineSearchMode": "MAP",
    "dealer": {
      "name": "BMW UK Ltd",
      "country": "GB",
      "postalCode": "GU14 0FB",
      "city": "Farnborough",
      "street": "Summit ONE"
    },
    "lastDestinations": "SUPPORTED"
  }
]

The most important thing here is the VIN - Vehicle Identification Number. You'll need that for all the other API calls as well as the Authorization Bearer.

Get Vehicle Status

  • /webapi/v1/user/vehicles/:VIN/status
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.

Response

{
    "vehicleStatus": {
        "vin": "WAB1C23456V123456",
        "mileage": 1234,
        "updateReason": "VEHICLE_SHUTDOWN_SECURED",
        "updateTime": "2015-10-30T18:45:04+0100",
        "doorDriverFront": "CLOSED",
        "doorDriverRear": "CLOSED",
        "doorPassengerFront": "CLOSED",
        "doorPassengerRear": "CLOSED",
        "windowDriverFront": "CLOSED",
        "windowDriverRear": "CLOSED",
        "windowPassengerFront": "CLOSED",
        "windowPassengerRear": "CLOSED",
        "trunk": "CLOSED",
        "rearWindow": "INVALID",
        "convertibleRoofState": "INVALID",
        "hood": "CLOSED",
        "doorLockState": "SECURED",
        "parkingLight": "OFF",
        "positionLight": "OFF",
        "remainingFuel": 8.9,
        "remainingRangeElectric": 73,
        "remainingRangeElectricMls": 45,
        "remainingRangeFuel": 126,
        "remainingRangeFuelMls": 78,
        "maxRangeElectric": 134,
        "maxRangeElectricMls": 83,
        "fuelPercent": 99,
        "maxFuel": 9,
        "connectionStatus": "DISCONNECTED",
        "chargingStatus": "INVALID",
        "chargingLevelHv": 58,
        "lastChargingEndReason": "UNKNOWN",
        "lastChargingEndResult": "FAILED",
        "position": {
            "lat": 51.123456,
            "lon": -1.2345678,
            "heading": 211,
            "status": "OK"
        },
        "chargingTimeRemaining": 45,
        "internalDataTimeUTC": "2015-10-30T18:47:44"
    }
}

Values

  • mileage is in Km.
  • remainingFuel is in Litres.
  • maxRangeElectric is in Km.
  • maxRangeElectricMls is in miles.
  • chargingLevelHv is the percentage of charge left in the (High voltage?) battery.
  • maxFuel is in Litres.
  • heading is in degrees.
  • chargingTimeRemaining is in minutes. Please mind that this value is only available if car is actively charging otherwise it is not present in the response.

Valid chargingStatus values appear to be:

  • CHARGING
  • ERROR
  • FINISHED_FULLY_CHARGED
  • FINISHED_NOT_FULL
  • INVALID
  • NOT_CHARGING
  • WAITING_FOR_CHARGING

Valid connectionStatus values appear to be:

  • CHARGING_DONE
  • CHARGING_INTERRUPED [sic]
  • CHARGING_PAUSED
  • CHARGIN_STARTED [sic] TYPO should be CHARGING_STARTED
  • CYCLIC_RECHARGING
  • DISCONNECTED
  • DOOR_STATE_CHANGED
  • NO_CYCLIC_RECHARGING
  • NO_LSC_TRIGGER
  • ON_DEMAND
  • PREDICTION_UPDATE
  • TEMPORARY_POWER_SUPPLY_FAILURE
  • UNKNOWN
  • VEHICLE_MOVING
  • VEHICLE_SECURED
  • VEHICLE_SHUTDOWN
  • VEHICLE_SHUTDOWN_SECURED
  • VEHICLE_UNSECURED

Valid doorLockState values appear to be:

  • UNLOCKED
  • LOCKED (remotely)
  • SECURED (with key fob)

Get Last Trip

Shows the details about your most recent trip.

  • /webapi/v1/user/vehicles/:VIN/statistics/lastTrip
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.

Response

{
   "lastTrip":{
      "efficiencyValue":0.53,
      "totalDistance":141,
      "electricDistance":100.1,
      "avgElectricConsumption":16.6,
      "avgRecuperation":2,
      "drivingModeValue":0,
      "accelerationValue":0.39,
      "anticipationValue":0.81,
      "totalConsumptionValue":0.79,
      "auxiliaryConsumptionValue":0.66,
      "avgCombinedConsumption":1.9,
      "electricDistanceRatio":71,
      "savedFuel":0,
      "date":"2015-12-01T20:44:00+0100",
      "duration":124
   }
}

Values

Distances appear to be in Kilometres rather than miles, so be sure to adjust accordingly. Multiply by 0.621371 to get miles.

  • totalDistance is in Km.
  • electricDistance is in Km.
  • avgElectricConsumption is in kWh/100Km.
  • avgRecuperation is in kWh/100Km.
  • duration is in minutes.

To convert kWh/100Km to Miles/kWh.

1 / (0.01609344 * avgElectricConsumption)

Get Charging Times

Shows when the car is scheduled to charge.

  • /webapi/v1/user/vehicles/:VIN/chargingprofile
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.

Response

{
   "weeklyPlanner":{
      "climatizationEnabled":true,
      "chargingMode":"DELAYED_CHARGING",
      "chargingPreferences":"CHARGING_WINDOW",
      "timer1":{
         "departureTime":"07:30",
         "timerEnabled":true,
         "weekdays":[
            "MONDAY"
         ]
      },
      "timer2":{
         "departureTime":"13:00",
         "timerEnabled":false,
         "weekdays":[
            "SATURDAY"
         ]
      },
      "timer3":{
         "departureTime":"08:00",
         "timerEnabled":false,
         "weekdays":[

         ]
      },
      "overrideTimer":{
         "departureTime":"07:30",
         "timerEnabled":false,
         "weekdays":[
            "MONDAY"
         ]
      },
      "preferredChargingWindow":{
         "enabled":true,
         "startTime":"05:02",
         "endTime":"17:31"
      }
   }
}

Values

  • departureTime appears to be the car's local time.

Get Vehicle Destinations

Shows the destinations you've previously sent to the car.

  • /webapi/v1/user/vehicles/:VIN/destinations
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.

Response

{
   "destinations":[
      {
         "lat":51.53053283691406,
         "lon":-0.08362331241369247,
         "country":"UNITED KINGDOM",
         "city":"LONDON",
         "street":"PITFIELD STREET",
         "type":"DESTINATION",
         "createdAt":"2015-09-25T08:06:11+0200"
      }
   ]
}

Values

  • An array of locations.

Get All Trip Details

Shows the statistics for all trips taken in the vehicle.

  • /webapi/v1/user/vehicles/:VIN/statistics/allTrips
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.

Response

{
    "allTrips": {
        "avgElectricConsumption": {
            "communityLow": 0,
            "communityAverage": 16.33,
            "communityHigh": 35.53,
            "userAverage": 14.76
        },
        "avgRecuperation": {
            "communityLow": 0,
            "communityAverage": 3.76,
            "communityHigh": 14.03,
            "userAverage": 2.3
        },
        "chargecycleRange": {
            "communityAverage": 121.58,
            "communityHigh": 200,
            "userAverage": 72.62,
            "userHigh": 135,
            "userCurrentChargeCycle": 60
        },
        "totalElectricDistance": {
            "communityLow": 1,
            "communityAverage": 12293.65,
            "communityHigh": 77533.6,
            "userTotal": 3158.66
        },
        "avgCombinedConsumption": {
            "communityLow": 0,
            "communityAverage": 1.21,
            "communityHigh": 6.2,
            "userAverage": 0.36
        },
        "batterySizeMax": 35820,
        "savedCO2": 87.58,
        "savedCO2greenEnergy": 515.177,
        "totalSavedFuel": 0,
        "resetDate": "1970-01-01T01:00:00+0100"
    }
}

Values

  • chargecycleRange is in Km.
  • totalElectricDistance is in Km.
  • savedCO2 is in kg.
  • savedCO2greenEnergy is in kg.
  • batterySizeMaxis in Wh.

I'm not sure what units of the other values are.

Get Range Map

Generate a polyline displaying the predicted range of the vehicle.

  • /webapi/v1/user/vehicles/:VIN/rangemap
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.

Response

{
    "rangemap": {
        "center": {
            "lat": 51.123456,
            "lon": -1.2345678
        },
        "quality": "AVERAGE",
        "rangemaps": [
            {
                "type": "ECO_PRO_PLUS",
                "polyline": [
                    {
                        "lat": 51.6991281509399,
                        "lon": -2.00423240661621
                    },
                    {
                        "lat": 51.6909098625183,
                        "lon": -1.91526889801025
                    },
                    ...
                ]
            },
            {
                "type": "COMFORT",
                "polyline": [
                    {
                        "lat": 51.7212295532227,
                        "lon": -1.7363977432251
                    },
                    {
                        "lat": 51.6991496086121,
                        "lon": -1.73077583312988
                    },
                    ...
                ]
            }
        ]
    }
}

Values

  • ECO_PRO_PLUS driving using the efficient Eco mode.
  • COMFORT driving using comfort mode.

Get misc SoC Data

Get maximum state of charge of your battery and some redundant data.

The URL is different from the other API servers:

  • https://www.bmw-connecteddrive.de/api/vehicle/navigation/v1/VIN
    • Where VIN is your vehicle's VIN.
    • Use the same Authorization: Bearer header as with API Server

Response

example data from a PHEV:
{
  "latitude" : 62.250584,
  "longitude" : 3.7717776,
  "isoCountryCode" : "DEU",
  "auxPowerRegular" : 1.4,
  "auxPowerEcoPro" : 1.2,
  "auxPowerEcoProPlus" : 0.4,
  "soc" : 4.019000053405762,
  "socMax" : 5.6,
  "eco" : "1c94,1206,d9d,d0f,cd3,cf9,e2d,f49,10ec,10ec,117c",
  "norm" : "1e15,12f9,e54,dbf,d82,da7,eed,1017,11d0,1483,19a9",
  "ecoEv" : "c31,799,5c5,5a5,5ae,5fc,6fb,861,9df,9df,9df",
  "normEv" : "cd5,800,613,5f1,5fc,64c,759,8d2,a65,bf8,e7d",
  "vehicleMass" : "1560",
  "kAccReg" : "1440000",
  "kDecReg" : "3420000",
  "kAccEco" : "1548000",
  "kDecEco" : "3240000",
  "kUp" : "1800000",
  "kDown" : "2700000",
  "driveTrain" : "phev_otto",
  "pendingUpdate" : false,
  "vehicleTracking" : true
}

Values

  • socMax current maximum charge. kind of health check of you battery

Sending information to the car

Sending information to the car is slightly complicated.

Your app communicates with the API, the API then communicates with the car's 3G modem, then you have to wait for a response.

If your car is in poor coverage, you can expect significant latency. Often much higher than a typical timeout will allow for.

At a basic level, you can just send a request - for example to lock the doors, or set off-peak charging.

Get Request status

Shows the status of a POSTed request

  • /webapi/v1/user/vehicles/:VIN/serviceExecutionStatus?serviceType=:SERVICE
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.

Response

{
   "executionStatus":{
      "serviceType":"DOOR_LOCK",
      "status":"EXECUTED",
      "eventId":"[email protected]"
   }
}

Values

Valid statuses are:

  • DELIVERED
  • EXECUTED
  • INITIATED
  • NOT_EXECUTED
  • PENDING
  • TIMED_OUT

The following are valid :SERVICE types, but may not be supported by your vehicle.

POST a command

Instructs the car to perform an action.

  • /webapi/v1/user/vehicles/:VIN/executeService
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.

Available Commands

These commands are all available via the API, but may not be supported by your vehicle.

These are just what I've discovered so far.

Data must be POSTed to the server.

Initiate Charging

If the vehicle is plugged in, but not charging (due to an off peak setting?) it is possible to force the car to charge.

  • serviceType=CHARGE_NOW

Start Climate Control

This will activate climate control within your vehicle.

It appears to be limited to the last temperature you set when you were in the car. I can't find a way to instruct the car to reach a specific temperature.

  • serviceType=CLIMATE_NOW

Lock the doors

Performs central locking.

  • serviceType=DOOR_LOCK

Unlock the doors

This will unlock all the doors on your vehicle.

Please use extreme caution when sending this command. Ensure that you are in sight of the vehicle and are able to lock it if needed.

  • serviceType=DOOR_UNLOCK

If you recievce an error after DOOR_UNLOCK that looks like {"error":{"code":500,"description":"(SmartPhoneUtil-A-2013) Action is forbidden. secretKnowledge is missing but required!"}}

An addition field must be included

  • serviceType=DOOR_UNLOCK
  • bmwSkAnswer=BMW_ACCOUNT_SECURITY_QUESTION_ANSWER

Flash the headlights

If you can't find the vehicle, or need to illuminate something in its vicinity, you can briefly activate the headlights.

  • serviceType=LIGHT_FLASH&count=2
    • I assume that count relates to the number of seconds to keep the light on?

Charging Schedule

Set the peak / off peak charging schedule.

  • serviceType=CHARGING_CONTROL
    • Additional data needs to be sent as parameter data in JSON format. The data itself is the same as returned by Get Charging Times.
# Notes:
# - Linebreaks for "data" have been added for readability only.
curl -i \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencode" \
  --data-urlencode 'serviceType=CHARGING_CONTROL' \
  --data-urlencode 'data={
    "weeklyPlanner":
      {
        "climatizationEnabled": true,
        "chargingMode": "IMMEDIATE_CHARGING",
        "chargingPreferences": "CHARGING_WINDOW",
        "timer1":{
          "departureTime": "12:30",
          "timerEnabled": true,
          "weekdays": []
        },
        "timer2":{
          "weekdays": []
        },
        "timer3":{
          "departureTime": "19:30",
          "timerEnabled": false,
          "weekdays": []
        },
        "overrideTimer": {
          "weekdays": []
        },
        "preferredChargingWindow": {
          "enabled": false,
          "startTime": "00:00",
          "endTime": "00:00"
        }}}' \
  https://b2vapi.bmwgroup.com/webapi/v1/user/vehicles/:VIN/executeService
* Instead of `weeklyPlanner` `twoTimesTimer` can be used. 
# Notes:
# - Linebreaks for "data" have been added for readability only.
curl -i \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencode" \
  --data-urlencode 'serviceType=CHARGING_CONTROL' \
  --data-urlencode 'data={
    "twoTimesTimer":
      {
        "climatizationEnabled": true,
        "chargingMode": "DELAYED_CHARGING",
        "chargingPreferences": "CHARGING_WINDOW",
        "timer1":{
          "departureTime": "12:30",
          "timerEnabled": true,
        },
        "timer2":{
          "departureTime": "13:30",
          "timerEnabled": false,
        },
        "preferredChargingWindow": {
          "startTime": "00:00",
          "endTime": "00:00"
        }}}' \
  https://b2vapi.bmwgroup.com/webapi/v1/user/vehicles/:VIN/executeService

Vehicle Finder

  • serviceType=VEHICLE_FINDER
    • I'm not sure what this does.

Response

An example response for all POST commands:

{
    "executionStatus": {
        "serviceType": "LIGHT_FLASH",
        "status": "INITIATED",
        "eventId": "[email protected]"
    }
}

Send POI

Sending a POI to the car.

  • POST /webapi/v1/user/vehicles/:VIN/sendpoi
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.
    • Remember to include the Content-Type: application/x-www-form-urlencode header.

Body

body={
	"poi": {
		"city": "abc",
		"lat": nn.nnn,
		"lon": nn.nnn,
		"name": "name",
		"rating": -1,
		"postalCode": "12345",
		"street": "Musterstr. 6"
	}
}

Response

HTTP 204

What's Next?

Using these commands you should be able to replicate the functionality of the official app.

If you spot any errors or omissions, please raise an issue or send a Pull Request.

bmw-i-remote's People

Contributors

bdwilson avatar derbrobro avatar edent avatar nosrak113 avatar quentinsf avatar rs38 avatar schmidmuc avatar w7e3 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bmw-i-remote's Issues

Some first information regarding CHARGING_CONTROL

Hello,

I just dump my current findings here since not sure when I find more time to push this forward... although I'm pretty sure that it is more or less solved now...

Request:

curl -i \
  -X POST \
  -H "Authorization: Bearer *REDACTED*" \
  -H "Content-Type: application/x-www-form-urlencode" \
  -d 'serviceType=CHARGING_CONTROL&data=%7B%22weeklyPlanner%22%3A%7B%7D%7D' \
  https://b2vapi.bmwgroup.com/webapi/v1/user/vehicles/*REDCATED*/executeService

Response:

HTTP/1.1 200 OK
Date: Thu, 12 Jan 2017 19:14:03 GMT
Max-Forwards: 20
Via: 1.0 lpb2vcn01 (BMW Group API Gateway)
X-CorrelationID: Id-7bd577587eb70f0000000000070e98df 0
X-NodeID: 01
X-Powered-By: JOY
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked

{"executionStatus":{"serviceType":"CHARGING_CONTROL","status":"INITIATED","eventId":"[email protected]"}}

One needs to send the proper data as argument data. It's JSON (just URI encoded in my sample above: {"weeklyPlanner":{}}). I'm very confident that the data is the same as returned by chargingprofile API call!

HTH

Kind regards,
Dietmar

PS: Will update w/ new findings... but as said, I'm pretty confident. :)


Update: As expected, it works as written...

Snippet of working sample:

...
  -H "Content-Type: application/x-www-form-urlencode" \
  --data-urlencode 'serviceType=CHARGING_CONTROL' \
  --data-urlencode 'data={"weeklyPlanner":{"climatizationEnabled":true,"chargingMode":"IMMEDIATE_CHARGING","chargingPreferences":"CHARGING_WINDOW","timer1":{"departureTime":"12:30","timerEnabled":true,"weekdays":[]},"timer2":{"weekdays":[]},"timer3":{"departureTime":"19:30","timerEnabled":false,"weekdays":[]},"overrideTimer":{"weekdays":[]},"preferredChargingWindow":{"enabled":false,"startTime":"00:00","endTime":"00:00"}}}'
...

Helpful change in python/bmw.py:

  def executeService(self, vin, serviceType, data=""):
          """
          Post a request for the specified service. e.g.
 
              print c.executeService(vin, 'DOOR_LOCK')
 
          """
          return self.call("/user/vehicles/{}/executeService".format(vin),
              {'serviceType': serviceType, 'data': data})

certificate pinning

BMW ConnectedDrive App now uses certificate pinning, making impossible? to capture traffic using an external proxy (e.g. fiddler, charles etc) in order to read key/value and authenticate with API.
Any ideas on how to overcome? (I am using iOS)

Server selection API.

I noticed it's possible to log in to all servers and all servers return the vehicle list, but in order to retrieve the vehicle details and send commands it seems you'll have to log in to the server you're car is connected to (error: "Ressource [sic] not found. No status available for VIN ...")

Cars do have a "hub" key, which in my case is set to "HUB_US", which could point to the server where the car "lives on." What are other values people are seeing in Europe and Asia? If "hub" indeed points to the right server, it would be a great way to automatically log in to the right server.

A variation on your theme

Hi Terence -

I've made quite a few changes to your original - it's sufficiently different that you may want to completely ignore it, but I can do a pull request if wanted!

Basically, I've pulled your original tweeting code out into bmwtweet.py and made a more generic 'bmw' module.

You can do things like:

import bmw
c = bmw.ConnectedDrive()
print c.call('/user/vehicles/')

It uses the 'requests' module, so you need to pip install that if you don't already have it.

Anyway, it's at https://github.com/quentinsf/BMW-i-Remote if you're interested. More to come soon.

Thanks again!
Quentin

Vehicle status not working.

Any thoughts on why this isn't working? It has the VIN in vehicle info, but can't pull status info. I see the status info within Charles Proxy when I use the app.

 $ PYTHONWARNINGS="ignore:Unverified HTTPS request" ./bmw.py

Vehicle info
   sendPoi  :  ACTIVATED
   lastDestinations  :  SUPPORTED
   countryCode  :  V2-US
   color  :  LAURUSGRAU MET. M.AKZENT
   vin  :  WBY1Z4xxxxxxxxx
   climateControl  :  NOT_SUPPORTED
   climateNow  :  ACTIVATED
   hasAlarmSystem  :  True
   dealer  :  {u'postalCode': u'12345', u'city': u'City', u'street': u'Address', u'name': u'My BMW', u'country': u'US'}
   remote360  :  NOT_SUPPORTED
   smartSolution  :  NOT_SUPPORTED
   vehicleFinder  :  ACTIVATED
   colorCode  :  B79
   lscType  :  I_LSC_IMM
   rangeMap  :  RANGE_POLYGON
   statisticsCommunityEnabled  :  False
   hornBlow  :  ACTIVATED
   doorUnlock  :  NOT_SUPPORTED
   driveTrain  :  BEV_REX
   hub  :  HUB_US
   brand  :  BMW_I
   statisticsAvailable  :  True
   yearOfConstruction  :  2015
   climateFunction  :  AIRCONDITIONING
   supportedChargingModes  :  [u'AC_LOW', u'AC_HIGH', u'DC']
   doorLock  :  ACTIVATED
   bodytype  :  I01
   lightFlash  :  ACTIVATED
   intermodalRouting  :  AVAILABLE
   chargeNow  :  NOT_SUPPORTED
   model  :  I3 +REX
   onlineSearchMode  :  MAP
   chargingControl  :  WEEKLY_PLANNER

Vehicle status
Traceback (most recent call last):
  File "./bmw.py", line 155, in <module>
    main()
  File "./bmw.py", line 149, in main
    status = c.call("/user/vehicles/{}/status".format(car['vin']))['vehicleStatus']
KeyError: 'vehicleStatus'

noticed BMW CarData?

I am not sure if this is quite new, but this service also contains some explanations of data that is saved on BMW servers:
https://www.bmw-connecteddrive.de/app/de/index.html#/portal/cardata-intern/archive

I tested it and the query takes 24h to complete and they only provide a snapshot of the connecteddrive data and an PDF explaining the values. I got it in german language, so it wont be so much helpful here, I guess.

may be this helps.
it is also available for newer "i-performance" PHEV cars.

SSL certificate pinning in new clients?

Using IOS I am trying to capture the traffic using Charles proxy. Usually this works for me - but the BMW apps all refuse to connect. I get the same sort of error as when a browser is using HSTS I.e. the session terminates before completing handshake. Has anyone got traffic interception working recently?

Has the OAuth scope changed?

Just started looking into this API as a new i3 owner. The OAuth token retrieval does not seem to accept "remote_services vehicle_data" as a valid scope:

% curl \
   -H "Authorization: Basic yes-i-fished-it-out-from-the-apk==" \
   -H "Content-Type: application/x-www-form-urlencoded" \
   -d "grant_type=password&username=me%40my.email&password=verysecret&scope=remote_services+vehicle_data" \
   "https://b2vapi.bmwgroup.com/webapi/oauth/token/"

and I get the result:

{
  "error" : "invalid_scope",
  "error_description" : "The requested scope is invalid, unknown, or malformed."
}

Also tried with other scope values (such as authenticate_user) but no luck. If I leave the scope parameter out, I am granted an access_token with scope=journey_mate but it cannot be used to access the API, resulting in an error:

% curl -H "Authorization: Bearer magic-token-here" "https://b2vapi.bmwgroup.com/webapi/v1/user/vehicles/"
{"error":"invalid_token","error_description":"The access token provided is expired, revoked, malformed, or invalid for other reasons."}

Am I doing something wrong here or has the API structure changed? The journey_mate scope is a clear reference to the Mini app..

Anyone know of additional values possible for these vehicles status values?

When calling /v1/user/vehicles to get the information for all i3 vehicles, I was wondering if anyone has found more values for model, drivetrain and color. For example I have:
"model":"I3 +REX",
"bodytype":"I01",
"driveTrain":"BEV_REX",
"color":"IONIC SILVER METALLIC/BM"

I'd like to know what the model name is for a non Rex i3, is it just model=I3 and drivetrain="BEV"?

And I'd like to see if I can gather more car color names that are possible as I can only get Ionic Silver Metallic for mine. I don't know what the /BM means at the end of IONIC SILVER METALLIC/BM.

Thanks,
Rick

why not use bmw-connecteddrive servers ?

I might be stupid, but why does one need to go through the hassle to reverse engineer the apps ( android or ios ) for that APIKey ?
To me it looks like connecting to the website bmw-connecteddrive.com and retrieving the same json data there is cleaner. All keys get generated on the go. Nothing fancy only a few nerds can use. Or are there advantages to using b2vapi.bmwgroup.com server ?

Auth failure in US

It appears we can no longer connect in the US.

Here is what I could figure out from my digging in the latest version of the android app:

Found this. Hoping it helps someone:
https://pastebin.com/QRHkRNhz
https://pastebin.com/eMema1J9
https://pastebin.com/QU7vZcmV
https://pastebin.com/en0HGBeT

New auth token path is: "/nlp/oauth/token"
New auth_basic token is: "ZGIxMzQzYWMtZWNiYS00MGRhLTk2NzMtNzA5NWEwZjJhNWQyOmQyNmMxYzhiLTI2NGQtNDc5MC05MjM3LTQ5NzQ3OWJiN2I5NQ=="

Change "scope": "remote_services vehicle_data" to "scope": "journey_mate"

This still doesn't fix everything, but you can get authenticated.

.

.

Get misc SoC Data not working anymore

Get misc SoC Data is not working anymore. I guess this has something to do with the link used to get it.

Error i get in from the server is:
The remote server returned an error: (403) Forbidden.'

Does anyone know how to get the SoC data now.

Still get the charge percentage. However not SOCmax and SOC

/rangemap API required deviceTime queryString

When I submit a GET method request to Rangemap API, it show the following error message.
{
"error": {
"code": 500,
"description": "(SmartPhoneUtil-A-101) Mandatory parameter(s) missed or blank: Cannot calculate remaining range circle, deviceTime is missing!"
}
}

After I added the (deviceTime=1) queryString it show other error message
{
"error": {
"code": 500,
"description": "(SmartPhoneUtil-A-2012) Ressource not found. Cannot calculate remaining range circle!"
}
}

What should I input at deviceTime queryString?
Thanks.

Unlock Command missing secretKnowledge

In order to call the DOOR_UNLOCK command, it seem the api is also looking for a secretKnowledge field.
{"error":{"code":500,"description":"(SmartPhoneUtil-A-2013) Action is forbidden. secretKnowledge is missing but required!"}}

This secret is the answer to the security question on the users account. I can't seem to find where to put it in the request. Ive tried in the body and headers under "secretKnowledge", but no luck.

Has anyone gotten this to work?

VehicleStatus Help

I'm able to successfully GET the list of vehicles in the account and POST a few instructions like "DOOR_LOCK" and "CLIMATE_NOW".

When trying to send a GET for Vehicle Status using the following code I receive an error and can't get past it. Hoping you can help. I'm in the US using ROOT_URL = "https://b2vapi.bmwgroup.us/webapi"

CODE:
print "\nStatus" status = c.call("/user/vehicles/{}/status".format(car['vin']))['vehicleStatus'] for k,v in status.items(): print " ", k, " : ", v

ERROR:
Status Traceback (most recent call last): File "./bmw.py", line 153, in <module> main() File "./bmw.py", line 147, in main status = c.call("/user/vehicles/{}/status".format(car['vin']))['vehicleStatus'] KeyError: 'vehicleStatus'

Add in 'batterySizeMax'

I get an extra value 'batterySizeMax' on /statistics/allTrips

...
"batterySizeMax": 35820,
...

Unit is 'Wh' ?!

A missing API call: updatePush

Hello,

(OT: Thanks for providing all the information.)

Following API call seems to be missing: /webapi/v1/user/vehicles/:VIN/updatePush (haven't tested it yet).

Kind regards,
Dietmar

General API comments

Hi all, great job on the APIs documentation. I used the Python to start off testing along with cURL but then once I got up to speed I built C# code on Windows to access the BMW service calls. I have been using Charles for URL sniffing which has been very helpful.
I noticed a few things.
In your article where you showed the response JSON from a vehicle status, there are more items that can be retrieved if the car is charging which would be good to include.
I found that the chargingTimeRemaining value added to the current time doesn't often match up with the estimated time to complete charging shown on the i3 dash. I wonder why.

When retrieving the vehicle status I was wondering why once I got status it didn't seem to change unless I restarted my app. I guessed that it was a caching issue and although I later figured out how to fix that through code I adopted the same technique BMW did to force each request to be new by appending the time stamp onto the request like this:
https://b2vapi.bmwgroup.us/webapi/v1/user/vehicles/MYVIN/status?deviceTime=2015-12-30T10%3A06%3A13

I included a polling cycle for command executions to look for DELIVERED, PENDING and then exit the wait if an EXECUTED or TIMED_OUT message is returned.

Something funny about door lock. It works fine but I noticed that it doesn't turn on the car alarm. If you look outside of your car when doing a DOORLOCK using the API, the doors lock but then the light under the rear-view mirror is not flashing. If I then press the lock button on my remote, it takes it a step further and turns on the alarm.

I noticed a status from door lock that was odd. I have seen selective_locked but I can't tell what that means. I have been trying to create alternative human readable messages to translate BMW messages but don't know what that means.

I tried to create a DOOR_UNLOCK command but that failed. I think why that is could be because it is not enabled by the car. In the vehicles information object retrieved it shows this:
"doorUnlock": "NOT_SUPPORTED". I assume that if an action says NOT-SUPPORTED then the API cannot control it. Does that sound right?

Has anyone found a way to generate the app's secret token based on using the user's ID and password? That would be super helpful.

Thanks,
Rick

GET works great, POST times out

I'm able to use the script in the US to gather information about my 535ix. However, the POST always times out. I'm interested in the best way you guys think to troubleshoot

Here's the part of the code that times out:

`import bmw
import time

c = bmw.ConnectedDrive()
resp = c.call('/user/vehicles/')
vin = resp['vehicles'][0]['vin']

service = 'LIGHT_FLASH'
print "Sending {} request...".format(service)
resp = c.executeService(vin, service)
status = resp['executionStatus']['status']
while status in ('INITIATED','PENDING'):
print status
time.sleep(2)
check = c.call('/user/vehicles/{}/serviceExecutionStatus?serviceType={}'.format(vin, service))
status = check['executionStatus']['status']

print status`

Send POI issues

I can't, for the life of me work out how to send a POI.

How do I send this as POST data?

body={
"poi": {
"city": "abc",
"lat": nn.nnn,
"lon": nn.nnn,
"name": "name",
"rating": -1,
"postalCode": "12345",
"street": "Musterstr. 6"
}
}

I have converted the whole class to c# and I have it all working nicely, except the POI. I can't even figure out how to send one from a python command line..

Help, please!

Request: Remote 3d view

Is it possible to get the image(s) of the remote 3d view? This is not possible with the connecteddrive website but only available in the app.

Latency Experience?

Hi,
we are experiencing latency time of 25-60s for an API call and the iRemote App using:

Looks like we need about
10s to connect with the BMW server
20-50s to wake up the car

What is your experience?

@stefferber

Mandatory parameter(s) missed or blank: dlat and dlon are required for BMW vehicles

I have a 3 series. I'm not using the API, but wondered if anyone else had noticed this too. When I make a call to /webapi/v1/user/vehicles/'.$vin.'/status i get:

{
  "error": {
    "code": 500,
    "description": "(SmartPhoneUtil-A-101) Mandatory parameter(s) missed or blank: dlat and dlon are required for BMW vehicles!"
  }
}

if i add the lat + long of my home as querystring paramaters (/?dlat=x&dlon=y) it works but i don't get a lot of other data (e.g. door status) although i guess that's to do with the options available on my car:

{
  "vehicleStatus": {
    "vin": "(my VIN)",
    "updateTime": "2016-08-28T17:52:44+0200",
    "position": {
      "lat": 5x.xxxxx,
      "lon": -y.yyyyy,
      "status": "OK"
    }
  }
}

Here's the problem - if the car is more than half a KM from home, when i get:

{
  "vehicleStatus": {
    "vin": "(my VIN)",
    "updateTime": "2016-08-28T17:52:44+0200",
    "position": {
      "status": "TOO_FAR_AWAY"
    }
  }
}

(not sure what the "updateTime" value is as that's clearly a long time ago).

Opening the trunk only?

Hi,
we played with the API and we tried to unlock the trunk ONLY. The remote key has that capability but we could not find the API call. As the vehicle status distinguishes all doors, trunk, and hood:

{
  "vehicleStatus": {
[...]
    "updateReason": "DOOR_STATE_CHANGED",
[...]
    "doorDriverFront": "CLOSED",
    "doorDriverRear": "CLOSED",
    "doorPassengerFront": "CLOSED",
    "doorPassengerRear": "CLOSED",
    "windowDriverFront": "CLOSED",
    "windowDriverRear": "CLOSED",
    "windowPassengerFront": "CLOSED",
    "windowPassengerRear": "CLOSED",
    "trunk": "CLOSED",
    "rearWindow": "INVALID",
    "hood": "CLOSED",
    "doorLockState": "SELECTIVE_LOCKED",
   [...]

why not have an API call for it, too. Any idea?
@stefferber

Use of refresh_token

Hi,

you state

I've no idea what the refresh_token is for. Once the access_token expires, you can simply re-authenticate and gain a new one.

in your readme.md.

Perhaps this helps:

https://www.oauth.com/oauth2-servers/access-tokens/refreshing-access-tokens/

Using

POST /oauth/token HTTP/1.1
Host: authorization-server.com
 
grant_type=refresh_token
&refresh_token=xxxxxxxxxxx
&client_id=xxxxxxxxxx
&client_secret=xxxxxxxxxx

you get a new token without login credentials:

The response to the refresh token grant is the same as when issuing an access token. You can optionally issue a new refresh token in the response, or if you don’t include a new refresh token, the client assumes the current refresh token will continue to be valid.

Greetings

Missing information that are available on the website

So far I made good progress with a nodejs relication, thanks for the very useful documentation. Some information that I cannot find though by using API that are available on the website are detailed battery informations:

The URI here returns it:

https://www.bmw-connecteddrive.de/api/vehicle/navigation/v1/

The resulting json is:
{
"latitude" : ...,
"longitude" : ...,
"isoCountryCode" : "...",
"auxPowerRegular" : ...,
"auxPowerEcoPro" : ...,
"auxPowerEcoProPlus" : ...,
"soc" : ...,
"socMax" : ...,
"pendingUpdate" : false,
"vehicleTracking" : true
}

the values soc and socMax are very interesting because they mean the state of charge in kilowatts and the maximum respectively.

Any idea how I could retrieve these values by using the API?

Thanks!

BMW server API rate limit

I have been playing about with this and my new i3 which I got last week. I prefer PHP rather than python so I went with that, I found the curl documentation here was invaluable in helping me to get things working. I have written a script that posts any changes in status to a slack channel rather than twitter.

Everything is working happily and I have a cron job running every 5 minutes to grab the status, if the timestamp has changed (or if the status has changed if it's charging) then it posts a new message to slack. yay!
screen shot 2016-07-06 at 14 09 01

While I was looking at this last night I noticed that the status doesn't change unless something physically is different with the car.. totally makes sense. What doesn't make sense to me from a technical perspective is that while the vehicle is in motion nothing seems to change. After a drive home from work the updatedReason changed to VEHICLE_MOVING and kept the same timestamp until I got home and parked. I guess the theory behind this is that people aren't going to be using the iRemote on their phones while driving the car.

I did however notice that when charging my i3 the timestamp would change upon every request (I hit refresh a bunch of times and even after a second or two it changed). I'm not sure that up to the second information is necessary and the implications on servers and mobile data would make that a silly thing to me for the car to be doing.. but there ya go. perhaps there is some backend tasks going on where the server calculates what the battery % increase should be based on the charging speed etc and so isn't actually talking to the car directly.

What's my point.. oh yes.. based on the fact that I appear to be able to make new requests every second what do people think is a sensible frequency for requests to be made. I was thinking of going down to 1 every 60 seconds. I'm not sure how easy it would be for BMW to detect/block access for a homemade client.. but I don't want to hammer something and then get myself or everyone blocked.. What does everyone/anyone think?

Also would a PR with the php->slack code be of use to anyone.. would it be better as a separate repo?

Send POI to Car

Does anyone know the format of the query parameters or post parameters for the "SEND_POI_TO_CAR' function?

Refresh Token

I've no idea what the refresh_token is for. Once the access_token expires, you can simply re-authenticate and gain a new one.

The refresh token is used to exchange an expired token for a new one without need for username/ password. Cannot provide more details as I don't have access to the endpoints.

Cancelling Pre-Conditioning?

Has anyone figured out if it is possible to cancel a CLIMATE_NOW or a scheduled pre-condition event? Or to get some indication that a CLIMATE_NOW event is active?

Thanks

any experience with encrypting profile data from USB Stick storage?

you get this XML File when you export your profile on a USB stick (e.g. in a i3):
what does it contain?

<?xml version="1.0" encoding="UTF-8"?>
    -<bmwExportData>
    -<signedContent>
-<header>
<date>2016-03-03T17:53:49</date>
<version>1</version>
<username>(------)</username>
<vin>V608xxx</vin>
<i-step>I001-15-11-504</i-step>
</header>
-<body>
<securityContainer securityLevel="1" type="vehicle"> 9PLCFuIS4uQa7KYKCty+APTHv2Kf9aY5trQ4GGJnOHVc69zlsPr2D1EWSEnqB02bWCy+==
[....ca. 2-3kbyte  encoded string omitted]
</securityContainer>
</body>
</signedContent>
<signature>XDLOP0X53m96jMqb+3gEJxxxxxx=</signature>
</bmwExportData>

Add in 'chargingTimeRemaining'

When the vehicle is actively charging, there's another data value in vehicleStatus:

chargingTimeRemaining

Unit is minutes.

Howto for dummy ?

Hi, can anybody give me a step by step guide... sorry
I´m not so deep into coding... and i have only the iPhone app.
Is there a way to get the password/secret of connected drive without an android phone?

Thanks

Is there a way to get the battery size?

I was wondering if there is a way to get the car's battery size? I saw that there is a batterySizeMax parameter in the response of the allTrips request but it seems like a strange place to put the battery size, which is a static value that should be returned with the car information. Is this parameter referring to something else maybe?

Thanks in advance for the response and for the great work documenting these APIs!!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.