I manged to get my bmw to openhab2 here is my solution:
bmw.items
String doorLockState "BMW [%s]"
String doorDriverFront "Fahrertür [%s]"
String doorPassengerFront "Beifahrertür [%s]"
String doorDriverRear "Hintenfahrertür [%s]"
String doorPassengerRear "Hintenbeifahrertür [%s]"
Number chargingLevelHv "Ladetestatus [%d Prz]"
Number remainingRangeElectric "Reichweite [%d Km]"
Switch bmwforceupadte {}
String access_token "AccessToken [%s]"
String token_expiry "TokenExpiry [%s]"
String bmwusername "Username [yourusername]"
String bmwpassword "Username [yourpassword]"
String bmwauth_basic "AuthBasic [yourAuthBasic]"
bmw.rules
rule "BMW"
when
Time cron "0 0/30 * * * ?"
then
val bmwresp = executeCommandLine("/usr/bin/python /etc/openhab2/scripts/bmw.py", 5000)
logInfo("BMW", bmwresp)
end
rule "BMW run script"
when
Item bmwforceupadte received update
then
val bmwresp = executeCommandLine("/usr/bin/python /etc/openhab2/scripts/bmw.py", 5000)
logInfo("BMW", bmwresp)
end
bmw.py just save it to the openhab config scripts path
#! /usr/bin/env python
#
# Use the BMW ConnectedDrive API using credentials from credentials.json
# You can see what should be in there by looking at credentials.json.sample.
#
# 'auth_basic' is the base64-encoded version of API key:API secret
# You can capture it if you can intercept the traffic from the app at
# the time when reauthentication is happening.
#
# Based on the excellent work by Terence Eden:
# https://github.com/edent/BMW-i-Remote
import json
import requests
import time
# API Gateway
ROOT_URL = "https://b2vapi.bmwgroup.com/webapi"
API_ROOT_URL = ROOT_URL + '/v1'
OpenHabIP = "192.168.1.37:8080"
# What are we pretending to be? Not sure if this is important.
# Might be tied to OAuth consumer (auth_basic) credentials?
USER_AGENT = "MCVApp/1.5.2 (iPhone; iOS 9.1; Scale/2.00)"
# USER_AGENT = "Dalvik/2.1.0 (Linux; U; Android 5.1.1; Nexus 6 Build/LMY48Y)"
# Constants
# To convert km to miles:
# miles = km * KM_TO_MILES
KM_TO_MILES = 0.621371
# To convert kWh/100Km to Miles/kWh:
# 1 / (EFFICIENCY * avgElectricConsumption)`
EFFICIENCY = 0.01609344
# For future use
class ConnectedDriveException(Exception):
pass
class ConnectedDrive(object):
"""
A wrapper for the BMW ConnectedDrive API used by mobile apps.
Caches credentials in credentials_file, so needs both read
and write access to it.
"""
def __init__(self):
username2 = json.loads(str(requests.get('http://' + str(OpenHabIP) + '/rest/items/bmwusername').content))
self.username = username2["stateDescription"]["pattern"]
password2 = json.loads(str(requests.get('http://' + str(OpenHabIP) + '/rest/items/bmwpassword').content))
self.password = password2["stateDescription"]["pattern"]
auth_basic2 = json.loads(str(requests.get('http://' + str(OpenHabIP) + '/rest/items/bmwauth_basic').content))
self.auth_basic = auth_basic2["stateDescription"]["pattern"]
self.access_token = str(requests.get('http://' + str(OpenHabIP) + '/rest/items/access_token/state').content)
if(self.access_token == "NULL"):
requests.put('http://' + str(OpenHabIP) + '/rest/items/access_token/state', "")
self.token_expiry = str(requests.get('http://' + str(OpenHabIP) + '/rest/items/token_expiry/state').content)
if(self.token_expiry == "NULL"):
self.token_expiry = 1495039940.767906
if (time.time() > float(self.token_expiry)):
self.generateCredentials()
def generateCredentials(self):
"""
If previous token has expired, create a new one from basics.
"""
headers = {
"Authorization": "Basic " + self.auth_basic,
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": USER_AGENT
}
data = {
"grant_type": "password",
"username": self.username,
"password": self.password,
"scope": "remote_services vehicle_data"
}
r = requests.post(ROOT_URL + "/oauth/token/", data=data, headers=headers)
json_data = r.json()
# Get the access token
self.access_token = json_data["access_token"]
self.token_expiry = time.time() + json_data["expires_in"]
self.saveCredentials()
def saveCredentials(self):
"""
Save current state to the JSON file.
"""
credentials = {
"username": self.username,
"password": self.password,
"auth_basic": self.auth_basic,
"access_token": self.access_token,
"token_expiry": self.token_expiry
}
requests.put('http://' + str(OpenHabIP) + '/rest/items/access_token/state', str(self.access_token))
requests.put('http://' + str(OpenHabIP) + '/rest/items/token_expiry/state', str(self.token_expiry))
def call(self, path, post_data=None):
"""
Call the API at the given path.
Argument should be relative to the API base URL, e.g:
print c.call('/user/vehicles/')
If a dictionary 'post_data' is specified, the request will be
a POST, otherwise a GET.
"""
#
if (time.time() > self.token_expiry):
self.generateCredentials()
headers = {"Authorization": "Bearer " + self.access_token,
"User-Agent":USER_AGENT}
if post_data is None:
r = requests.get(API_ROOT_URL + path, headers=headers)
else:
r = requests.post(API_ROOT_URL + path, headers=headers, data=post_data)
return r.json()
def executeService(self, vin, serviceType):
"""
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})
# A simple test example
def main():
c = ConnectedDrive()
#print "\nVehicle info"
resp = c.call('/user/vehicles/')
car = resp['vehicles'][0]
#for k,v in car.items():
#print " ",k, " : ", v
print "\nVehicle status"
status = c.call("/user/vehicles/{}/status".format(car['vin']))['vehicleStatus']
for k,v in status.items():
print " ", k, " : ", v
print "\nAusgabe"
#position = status['position'];
#for k,v in position.items():
#print " ", k, " : ", v
#print position['lat']
requests.put('http://' + str(OpenHabIP) + '/rest/items/chargingLevelHv/state', str(status['chargingLevelHv']))
requests.put('http://' + str(OpenHabIP) + '/rest/items/doorLockState/state', str(status['doorLockState']))
requests.put('http://' + str(OpenHabIP) + '/rest/items/doorDriverFront/state', str(status['doorDriverFront']))
requests.put('http://' + str(OpenHabIP) + '/rest/items/doorPassengerFront/state', str(status['doorPassengerFront']))
requests.put('http://' + str(OpenHabIP) + '/rest/items/doorDriverRear/state', str(status['doorDriverRear']))
requests.put('http://' + str(OpenHabIP) + '/rest/items/doorPassengerRear/state', str(status['doorPassengerRear']))
requests.put('http://' + str(OpenHabIP) + '/rest/items/remainingRangeElectric/state', str(status['remainingRangeElectric']))
if __name__ == '__main__':
main()
Sitemap
Text label="BMW" icon="bmw1600" {
Text item=chargingLevelHv valuecolor=[>90="green",>45="orange",<=45="red"] icon="battery-100"
Text item=remainingRangeElectric icon="line-incline"
Text item=doorLockState {
Text item=doorDriverFront
Text item=doorPassengerFront
Text item=doorDriverRear
Text item=doorPassengerRear
}
Switch item=bmwforceupadte
Text item=Connect {
Text item=access_token
Text item=token_expiry
Text item=bmwusername
Text item=bmwpassword
Text item=bmwauth_basic
}
}