Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Moderátor: Josef

Uživatelský avatar
stejk
Příspěvky: 410
Registrován: ned 16. pro 2018 5:31:05

Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod stejk » pon 04. lis 2019 7:57:36

prerekvizity:
- BMW i3 s funkčním Remote Services
- účet ConnectedDrive
- stroj FreeBSD 12 64bit (ideálně VPS virtuální privátní server) - pravidelné stahování a ukládání dat z BMW API + webový server pro následné zobrazení nasbíraných dat

https://shkspr.mobi/blog/2015/11/reverse-engineering-the-bmw-i3-api/
https://github.com/ipv6freely/bmw2018

Postupně si ukážeme jednotlivé kroky.

1. stroj FreeBSD 12 64bit
Lze objednat VPS u forpsicloud.cz za 70 Kč/měsíc. Výhoda nonstop běh stroje v cloudu. Zde pro příklad použijeme systém nainstalovaný ve virtualboxu.

1. nainstalujeme virtualbox https://www.virtualbox.org/wiki/Downloads
2. stáhneme FreeBSD virtual machine disk images https://download.freebsd.org/ftp/releases/VM-IMAGES/12.0-RELEASE/i386/Latest/FreeBSD-12.0-RELEASE-i386.vhd.xz
3. stažený image rozblíme a přidáme do virtualboxu
virtualbox.jpg
virtualbox.jpg (22.06 KiB) Zobrazeno 3038 x

4. spustíme FreeBSD a přihlásíme se jako uživatel root
freebsd.jpg
freebsd.jpg (24.65 KiB) Zobrazeno 3038 x


2. mc, python, první skript

2.1 nainstalujeme Midnight Commander

Kód: Vybrat vše

pkg install mc
Midnight_Commander.jpg
Midnight_Commander.jpg (20.07 KiB) Zobrazeno 3038 x


2.2 nainstalujeme python
 a balíčky pythonu

Kód: Vybrat vše

pkg install python3
pkg install py36-boto3
pkg install py36-pip
pkg install py36-pymysql
pkg install py36-requests
python.jpg
python.jpg (21.78 KiB) Zobrazeno 3038 x


2.3 Vytvoříme adresář, soubor bmw.py přeneseme z windows do freebsd a upravíme práva

Kód: Vybrat vše

mkdir /root/bmw
touch /root/bmw/bmw.py
chmod 754 /root/bmw/bmw.py
bmw_py.jpg
bmw_py.jpg (20.91 KiB) Zobrazeno 3038 x


bmw.py

Kód: Vybrat vše

#! /usr/bin/env python

import requests
import json
import urllib
import boto3
import logging
import sys
import pickle
import pymysql
# Import smtplib for the actual sending function
import smtplib
# Import the email modules we'll need
from email.mime.text import MIMEText

logging.basicConfig(filename='/root/bmw/bmw.log',
                            filemode='a',
                            format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',
                            datefmt='%H:%M:%S',
                            level=logging.INFO)

#   API Gateway
#   North America: b2vapi.bmwgroup.us
#   Rest of World: b2vapi.bmwgroup.com
#   China: b2vapi.bmwgroup.cn:8592
BASE_URL = 'b2vapi.bmwgroup.com'


def getToken(BASE_URL, username, password):
    try:
        headers = {
            "Content-Type": "application/x-www-form-urlencoded",
            "Content-Length": "124",
            "Connection": "Keep-Alive",
            "Host": BASE_URL,
            "Accept-Encoding": "gzip",
            "Authorization": "Basic blF2NkNxdHhKdVhXUDc0eGYzQ0p3VUVQOjF6REh4NnVuNGNEanli"
                             "TEVOTjNreWZ1bVgya0VZaWdXUGNRcGR2RFJwSUJrN3JPSg==",
            "Credentials": "nQv6CqtxJuXWP74xf3CJwUEP:1zDHx6un4cDjybLENN3kyfumX2kEYigWPcQpdvDRpIBk7rOJ",
            "User-Agent": "okhttp/2.60"}

        data = {
            'grant_type': 'password',
            'scope': 'authenticate_user vehicle_data remote_services',
            'username': username,
            'password': password}

        data = urllib.parse.urlencode(data)
        url = 'https://' + BASE_URL + '/webapi/oauth/token'
        r = requests.post(url, data=data, headers=headers)

        if r.status_code == 200:
            logging.info('Access token acquired')
            return r.json()['access_token']
        else:
            raise ValueError('Unable to login')

    except Exception as msg:
        logging.error(msg)
        sys.exit(1)

def getSocData(BASE_URL, token, vin):
    try:
        headers = {'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_1_1 like Mac OS X) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0 Mobile/15B150 Safari/604.1',
                    'Authorization': 'Bearer ' + token}

        url = 'https://' + BASE_URL + '/api/vehicle/navigation/v1/' + vin

        r = requests.get(url, headers=headers)
        if r.status_code == 200:
            status = r.json()
            if status.get('socmax'):
                 socMax = status['socmax']
            if status.get('socMax'):
                 socMax = status['socMax']
            logging.info('SoC Data retreived successfully')
            return socMax
        else:
            raise ValueError('Unable to retreive SoC data from vehicle')

    except Exception as msg:
        logging.error(msg)
        sys.exit(1)


def getBattery(BASE_URL, token, vin):
    try:
        headers = {'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_1_1 like Mac OS X) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0 Mobile/15B150 Safari/604.1',
                    'Authorization': 'Bearer ' + token}

        url = 'https://' + BASE_URL + '/webapi/v1/user/vehicles/' + vin + '/status'

        r = requests.get(url, headers=headers)
        if r.status_code == 200:
            status = r.json()
            chargingLevelHv = status['vehicleStatus']['chargingLevelHv']
            remainingRangeElectric = status['vehicleStatus']['remainingRangeElectric']
            connectionStatus = status['vehicleStatus']['connectionStatus']
            chargingStatus = status['vehicleStatus']['chargingStatus']
            mileage = status['vehicleStatus']['mileage']
            positionlat = status['vehicleStatus']['position']['lat']
            positionlon = status['vehicleStatus']['position']['lon']
            logging.info('Battery data retreived successfully')
            return chargingLevelHv, remainingRangeElectric, connectionStatus, chargingStatus, mileage, positionlat, positionlon
        else:
            raise ValueError('Unable to retreive battery data from vehicle')

    except Exception as msg:
        logging.error(msg)
        sys.exit(1)


def sendEMAIL(message_chargingLevelHv,message_connectionStatus,message_chargingStatus,message_subjectEmoji):
    try:
        logging.info(message_chargingLevelHv)
        logging.info(message_connectionStatus)
        logging.info(message_chargingStatus)
        SMTP_SERVER = 'smtp.gmail.com'
        SMTP_PORT = 587
        GMAIL_USERNAME = 'XXX@gmail.com'
        GMAIL_PASSWORD = 'XXXhesloXXX' #CAUTION: This is stored in plain text!
        recipient = 'XXX@gmail.com'
        Message_chargingLevelHv=str(message_chargingLevelHv)
#        message_subjectEmoji = '=?utf-8?Q? =F0=9F=9A=97 ?='
        subject = message_subjectEmoji + ' BMW ' + Message_chargingLevelHv + '% '
        emailText = 'pripojeni:' + message_connectionStatus + '<br>nabijeni:' + message_chargingStatus
        headers = ["From: " + GMAIL_USERNAME,
                "Subject: " + subject,
                "To: " + recipient,
                "MIME-Version: 1.0",
                "Content-Type: text/html"]
        headers = "\r\n".join(headers)
        session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
        session.ehlo()
        session.starttls()
        session.ehlo
        session.login(GMAIL_USERNAME, GMAIL_PASSWORD)
        session.sendmail(GMAIL_USERNAME, recipient, headers + "\r\n\r\n" + emailText)
        session.quit()
        logging.info('EMAIL message sent successfully')
    except Exception as msg:
        logging.error(msg)
        sys.exit(1)


def getCredentials():
    with open('/root/bmw/credentials.json', 'r') as cf:
        credentials = json.load(cf)
    return credentials

def getLastPercent():
    try:
        with open ('/root/bmw/last_percent', 'rb') as lp:
            last_percent = pickle.load(lp)
        logging.info(f'last_percent loaded with a value of {last_percent}')
        return last_percent
    except FileNotFoundError:
        logging.error('last_percent file not found')
        with open('/root/bmw/last_percent', 'wb') as lp:
            pickle.dump(0, lp)
        logging.info('last_percent file created with value of 0')
        with open ('/root/bmw/last_percent', 'rb') as lp:
            last_percent = pickle.load(lp)
        return last_percent

def setLastPercent(chargingLevelHv):
    try:
        with open('/root/bmw/last_percent', 'wb') as lp:
            pickle.dump(chargingLevelHv, lp)
        logging.info(f'last_percent file updated with {chargingLevelHv}')
    except Exception as msg:
        logging.error(msg)
        sys.exit(1)


try:
    last_percent = int(getLastPercent())
    credentials = getCredentials()
    token = getToken(BASE_URL, credentials['username'], credentials['password'])
    chargingLevelHv, remainingRangeElectric, connectionStatus, chargingStatus, mileage, positionlat, positionlon = getBattery(BASE_URL, token, credentials['vin'])
    socMax = getSocData(BASE_URL, token, credentials['vin'])
    message = 'BMW i3 Status:\n' + f'Battery: {chargingLevelHv}% ({remainingRangeElectric} km) - {connectionStatus}/{chargingStatus}\nMileage: {mileage} km\nPosition http://maps.apple.com/?ll={positionlat},{positionlon}\n' + f'socMax: {socMax} kWh\n'


 #   conn = pymysql.connect(host='127.0.0.1', unix_socket='/tmp/mysql.sock', user='root', passwd='XXXhesloXXX', db='bmw')
    cur = conn.cursor()

    try:
#        affected_count = cur.execute('''INSERT INTO i3 (mileage,positionlat,positionlon,chargingLevelHv,remainingRangeElectric,socMax,connectionStatus,chargingStatus) VALUES (%s,%s,%s,%s,%s,%s,%s,%s)''',(mileage,positionlat,positionlon,chargingLevelHv,remainingRangeElectric,socMax,connectionStatus,chargingStatus))
#        conn.commit()
        logging.info("inserted values to DB")
    except pymysql.IntegrityError:
        logging.warn("failed to insert values")
    finally:
        cur.close()
        conn.close()

#   nabijeni poprve dosalo 100 procent (mame plne nabito)
    if chargingLevelHv > last_percent and chargingLevelHv == 100:
        setLastPercent(chargingLevelHv)
        message_subjectEmoji = ''
        sendEMAIL(chargingLevelHv,connectionStatus,chargingStatus,message_subjectEmoji)
        logging.info(message)
#   blizime se uz nabitemu stavu
    elif chargingLevelHv > last_percent and chargingLevelHv > 83:
        setLastPercent(chargingLevelHv)
        message_subjectEmoji = ''
        sendEMAIL(chargingLevelHv,connectionStatus,chargingStatus,message_subjectEmoji)
        logging.info(message)

# chargingStatus
# INVALID
# ERROR
# NOT_CHARGING
# CHARGING
# FINISHED_FULLY_CHARGED

# connectionStatus
# CONNECTED
# DISCONNECTED

# DISCONNECTED INVALID      vuz neni pripojen a nenabiji se - nejcasteji
# CONNECTED    NOT_CHARGING vuz je   pripojen a nenabiji se - vypadek napajeni napr. BILLA


#   kabel pripojen a charging INVALID
    elif connectionStatus == 'CONNECTED' and chargingStatus == 'INVALID':
        setLastPercent(chargingLevelHv)
        message_subjectEmoji = '=?utf-8?Q? =E2=9D=8C ?='
        sendEMAIL(chargingLevelHv,connectionStatus,chargingStatus,message_subjectEmoji)
        logging.info(message)
#   kabel pripojen a charging ERROR
    elif connectionStatus == 'CONNECTED' and chargingStatus == 'ERROR':
        setLastPercent(chargingLevelHv)
        message_subjectEmoji = '=?utf-8?Q? =E2=9D=97=E2=9D=97 ?='
        sendEMAIL(chargingLevelHv,connectionStatus,chargingStatus,message_subjectEmoji)
        logging.info(message)
#   kabel pripojen a charging NOT_CHARGING
    elif connectionStatus == 'CONNECTED' and chargingStatus == 'NOT_CHARGING' and chargingLevelHv > last_percent:
        setLastPercent(chargingLevelHv)
        message_subjectEmoji = '=?utf-8?Q? =E2=9A=A0=F0=9F=94=8C ?='
        sendEMAIL(chargingLevelHv,connectionStatus,chargingStatus,message_subjectEmoji)
        logging.info(message)
#   kabel pripojen a charging FINISHED_FULLY_CHARGED
    elif connectionStatus == 'CONNECTED' and chargingStatus == 'FINISHED_FULLY_CHARGED' and chargingLevelHv > last_percent:
        setLastPercent(chargingLevelHv)
        message_subjectEmoji = '=?utf-8?Q? =F0=9F=92=AF ?='
        sendEMAIL(chargingLevelHv,connectionStatus,chargingStatus,message_subjectEmoji)
        logging.info(message)
    else:
        setLastPercent(chargingLevelHv)
        message_subjectEmoji = ''
#        message_subjectEmoji = '=?utf-8?Q?  =F0=9F=94=B4=E2=9A=A0=F0=9F=94=8C ?='
#        message_subjectEmoji = '=?utf-8?Q? =E2=9D=97=E2=9D=97 ?='
#        sendEMAIL(chargingLevelHv,connectionStatus,chargingStatus,message_subjectEmoji)
        logging.info(message)

except Exception as msg:
    logging.error(msg)
    sys.exit(1)



Ve Windows 10 nainstalujeme Server OpenSSH podle návodu
https://winaero.com/blog/enable-openssh-server-windows-10/

Stáhneme bmw.py z Windows 10

Kód: Vybrat vše

scp windows_username@10.0.2.2:/bmw.py /root/bmw/




2.4 Vytvoříme credentials.json a upravíme práva

Kód: Vybrat vše

touch /root/bmw/credentials.json
chmod 754 /root/bmw/credentials.json


credentials.json

Kód: Vybrat vše

{
    "username": "uzivatelske_jmeno_ci_email@pro_ucet_ConnectedDrive.com",
    "access_token": "TOKEN",
    "vin": "WBY0Z12345V678901",
    "password": "heslo_do_uctu_ConnectedDrive"
}

Username a password - přihlašovací údaje které používáme u BMW iRemote appky

2.5 první spuštění skriptu bmw.py a kontrola logu

Spustíme skript

Kód: Vybrat vše

python3 /root/bmw/bmw.py

Skript by si neměl na nic stěžovat. Pokud ano, nutno řešit... Pokud si nestěžuje, můžeme zkontrolovat log:

Kód: Vybrat vše

cat /root/bmw/bmw.log


V případě úspěchu uvidíme:

Kód: Vybrat vše

05:03:31,649 root ERROR last_percent file not found
05:03:31,649 root INFO last_percent file created with value of 0
05:03:32,548 root INFO Access token acquired
05:03:33,210 root INFO Battery data retreived successfully
05:03:34,393 root INFO SoC Data retreived successfully
05:03:34,393 root ERROR name 'conn' is not defined

Pokud v logu vidíme předposlední dva řádky Data retreived successfully, pak máme vše v pořádku a těšíme se na další díl seriálu.

V případě neúspěchu uvidíme:

Kód: Vybrat vše

06:35:33,888 root INFO last_percent loaded with a value of 0
06:35:35,930 root ERROR Unable to login
 

Unable to login značí nejspíše překlep v credentials.json

3. databáze
3.1 instalujeme MySQL

instalace

Kód: Vybrat vše

pkg install mysql56-server

Přidá do /etc/rc.conf mysql_enable=YES

Kód: Vybrat vše

sysrc mysql_enable=YES

Nastartujeme mysql server

Kód: Vybrat vše

service mysql-server start

instalace py36-mysql-connector-python

Kód: Vybrat vše

pkg install py36-mysql-connector-python


3.2 Pomocí mysql interactive interface se připojíme na MySQL server

Kód: Vybrat vše

/usr/local/bin/mysql -u root -p


3.3 V mysql interactive interface zadáme následující příkazy:

Změna privilegií

Kód: Vybrat vše

GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY 'XXXhesloXXX';
měl by oznámit úspěch výpisem: Query OK, 0 rows affected (0.00 sec)

Vytvoření databáze

Kód: Vybrat vše

CREATE DATABASE bmw;
měl by oznámit úspěch výpisem: Query OK, 1 row affected (0.00 sec)

Použítí databáze

Kód: Vybrat vše

USE bmw;
měl by oznámit úspěch výpisem: Database changed

Vytvoření tabulek

Kód: Vybrat vše

CREATE TABLE `i3` (`datum` timestamp NULL DEFAULT CURRENT_TIMESTAMP, `mileage` mediumint(9) NOT NULL, `positionlat` decimal(10,8) NOT NULL, `positionlon` decimal(11,8) NOT NULL, `chargingLevelHv` tinyint(4) NOT NULL, `remainingRangeElectric` tinyint(4) NOT NULL, `socMax` float NOT NULL, `connectionStatus` tinytext COLLATE utf8mb4_unicode_ci NOT NULL, `chargingStatus` tinytext COLLATE utf8mb4_unicode_ci NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
měl by oznámit úspěch výpisem: Query OK, 0 rows affected (0.02 sec)

A ukončíme práci s databází:

Kód: Vybrat vše

quit
měl by oznámit úspěch výpisem: Bye


3.4 Upravíme skript pro uložení dat do databáze

Kód: Vybrat vše

mcedit /root/bmw/bmw.py

kde odkomentujeme řádky 182, 186 a 187 (odmažeme znak #)
Stávající stav skriptu:

Kód: Vybrat vše

 #   conn = pymysql.connect(host='127.0.0.1', unix_socket='/tmp/mysql.sock', user='root', passwd='XXXhesloXXX', db='bmw')
#        affected_count = cur.execute('''INSERT INTO i3 (mileage,positionlat,positionlon,chargingLevelHv,remainingRangeElectric,socMax,connectionStatus,chargingStatus) VALUES (%s,%s,%s,%s,%s,%s,%s,%s)''',(mileage,positionlat,positionlon,chargingLevelHv,remainingRangeElectric,socMax,connectionStatus,chargingStatus))
#        conn.commit()

Po editaci

Kód: Vybrat vše

   conn = pymysql.connect(host='127.0.0.1', unix_socket='/tmp/mysql.sock', user='root', passwd='XXXhesloXXX', db='bmw')
   affected_count = cur.execute('''INSERT INTO i3 (mileage,positionlat,positionlon,chargingLevelHv,remainingRangeElectric,socMax,connectionStatus,chargingStatus) VALUES (%s,%s,%s,%s,%s,%s,%s,%s)''',(mileage,positionlat,positionlon,chargingLevelHv,remainingRangeElectric,socMax,connectionStatus,chargingStatus))
   conn.commit()
Uložíme.
POZOR !!! výplň před "conn ..." nesmí být ze znaků mezer. Musí zde být odsazení tabulátorem (smažeme znaky mezery a odsadíme stiskem klávesy tabulátor). Jinak bude skript selhávat !!

3.5 Spustíme skrip a zkontolujeme log

Kód: Vybrat vše

python3 /root/bmw/bmw.py


Vypíšeme log

Kód: Vybrat vše

cat /root/bmw/bmw.log


Kde uvidíme řádky:

Kód: Vybrat vše

02:22:09,80 root INFO last_percent loaded with a value of 100
02:22:09,632 root INFO Access token acquired
02:22:10,235 root INFO Battery data retreived successfully
02:22:11,270 root INFO SoC Data retreived successfully
02:22:11,274 root INFO inserted values to DB
02:22:11,275 root INFO last_percent file updated with 100
02:22:11,275 root INFO BMW i3 Status:
Battery: 100% (93 km) - CONNECTED/FINISHED_FULLY_CHARGED
Pokud vidíme inserted values to DB , tak jsem postupovali správně a získaná data se nám uložila do databáze.


3.6 Zajistíme pravidelné spouštění skriptu CRONem

editujeme crontab

Kód: Vybrat vše

mcedit /etc/crontab


a přidáme řádek

Kód: Vybrat vše

*/5     *       *       *       *       root    /usr/local/bin/python3 /root/bmw/bmw.py
Což zajistí pravidelné spouštění skriptu v 5 minutových rozestupech = plnění databáze daty.

4. web server
4.1 instalujeme PHP

Kód: Vybrat vše

pkg install php71

4.2 Instalujeme nginx

Kód: Vybrat vše

pkg install nginx

Přidá do /etc/rc.conf nginx_enable=YES

Kód: Vybrat vše

sysrc nginx_enable=YES
Naposledy upravil(a) stejk dne ned 15. pro 2019 20:10:40, celkem upraveno 20 x.
Havrla
Příspěvky: 133
Registrován: úte 24. zář 2019 21:01:45
Bydliště: Praha
Kontaktovat uživatele:

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod Havrla » pon 04. lis 2019 11:19:59

Havrluv pokus o intuitivni rozchozeni podle navodu na CentOS7.

Poznamky pro Linuxare:
COS7 - doinstalovani python3 a potrebnych knihoven
MOJE:
yum install epel-release vim mc
yum install bind-utils bc perl-ExtUtils-MakeMaker unzip perl-Data-Dumper wget iptraf-ng fping lsof atop iptables-services net-snmp-utils smartmontools gdisk sgdisk iotop tcpdump perl dos2unix wget bash-completion-extras bash-completion mdadm perl-Data-Dumper xauth perl-ExtUtils-MakeMaker glibc ntpdate sysstat nmap unzip vim glibc-common gdisk screen psmisc rsync bridge-utils net-snmp net-tools libc.so.6 whois
yum install perl-Sys-Statistics-Linux perl-Test-Simple
yum install nrpe nagios-plugins nagios-plugins-perl
yum install perl-Nagios-Plugin perl-version ntp net-snmp
BMW addons:
yum install python3 python36
yum install python36-requests
yum install python-boto3
python3.6 -m ensurepip
pip3 install boto3
yum install python36-setuptools_scm
yum install python36-PyMySQL
yum install python36-cryptography

uprava BMW skryptu - hlavicky: #! /usr/bin/env python3



Stav : 13.11.2019

[root@CL-ITNK-BMW ~]# /root/bmw/bmw.py
[root@CL-ITNK-BMW ~]# echo $?
1
[root@CL-ITNK-BMW ~]#

16:00:05,331 root INFO last_percent loaded with a value of 0
16:00:05,332 root ERROR [Errno 2] No such file or directory: '/root/bmw/credentials.json'

skrypt se nezhrouti a dobehne s radnym chybovym kodem a log krasne napise co mu hybi

Havrla predbiha:
instalace MYSQL/MARIADB serveru pro ukladani dat
yum install mariadb mariadb-server
systemctl start mariadb
systemctl start mariadb
mysql
create database bmw;
create user bmw;
GRANT ALL PRIVILEGES ON bmw.* to bmw@localhost IDENTIFIED BY 'supertajneheslo';

skrypt uprava:
# conn = pymysql.connect(host='127.0.0.1', unix_socket='/tmp/mysql.sock', user='root', passwd='XXXhesloXXX', db='bmw')
# conn = pymysql.connect(host='127.0.0.1', unix_socket='/tmp/mysql.sock', user='bmw', passwd='supertajneheslo', db='bmw')

16.11.2019
### nutno mit definovane, v centosu maria db jiny sock file dle distribuce
conn = pymysql.connect(host='127.0.0.1', unix_socket='/var/lib/mysql/mysql.sock', user='bmw', passwd='supertajneheslo', db='bmw')




WAUUUU
20:48:15,398 root INFO last_percent loaded with a value of 0
20:48:16,126 root INFO Access token acquired
20:48:16,596 root INFO Battery data retreived successfully
20:48:20,78 root INFO SoC Data retreived successfully
20:48:20,85 root INFO inserted values to DB
20:48:20,86 root INFO last_percent file updated with 53
20:48:20,86 root INFO BMW i3 Status:
Battery: 53% (51 km) - CONNECTED/CHARGING
Mileage: 57403 km
Position http://maps.apple.com/?ll=49.832396,14.635092
socMax: 17.32 kWh


A tady si dovoluji ukazat co o sobe to auto praskne v tech 2 zpravach
[root@CL-ITNK-BMW ~]# /root/bmw/bmw.py
{'vehicleStatus': {'vin': 'WBY1Z41000VZ75700', 'mileage': 57403, 'updateReason': 'VEHICLE_SHUTDOWN', 'updateTime': '2019-11-16T20:19:55+0000', 'doorDriverFront': 'CLOSED', 'doorDriverRear': 'CLOSED', 'doorPassengerFront': 'CLOSED', 'doorPassengerRear': 'CLOSED', 'windowDriverFront': 'CLOSED', 'windowDriverRear': 'CLOSED', 'windowPassengerFront': 'CLOSED', 'windowPassengerRear': 'CLOSED', 'sunroof': 'CLOSED', 'trunk': 'CLOSED', 'rearWindow': 'INVALID', 'hood': 'CLOSED', 'doorLockState': 'UNLOCKED', 'parkingLight': 'OFF', 'positionLight': 'OFF', 'remainingFuel': 5, 'remainingRangeElectric': 57, 'remainingRangeElectricMls': 35, 'remainingRangeFuel': 78, 'remainingRangeFuelMls': 48, 'maxRangeElectric': 102, 'maxRangeElectricMls': 63, 'maxFuel': 8, 'connectionStatus': 'CONNECTED', 'chargingStatus': 'CHARGING', 'chargingTimeRemaining': 252, 'chargingLevelHv': 59, 'lastChargingEndReason': 'UNKNOWN', 'lastChargingEndResult': 'UNKNOWN', 'position': {'lat': 49.831196, 'lon': 14.691092, 'heading': 98, 'status': 'OK'}, 'internalDataTimeUTC': '2019-11-16T18:11:37', 'singleImmediateCharging': False, 'chargingConnectionType': 'CONDUCTIVE', 'chargingInductivePositioning': 'NOT_POSITIONED', 'vehicleCountry': 'CZ', 'checkControlMessages': [], 'cbsData': [{'cbsType': 'BRAKE_FLUID', 'cbsState': 'OK', 'cbsDueDate': '2020-10', 'cbsDescription': 'Next change due at the latest by the stated date.'}, {'cbsType': 'VEHICLE_CHECK', 'cbsState': 'OK', 'cbsDueDate': '2021-05', 'cbsDescription': 'Next visual inspection due when the stated distance has been covered or by the stated date.'}, {'cbsType': 'VEHICLE_TUV', 'cbsState': 'OK', 'cbsDueDate': '2021-05', 'cbsDescription': 'Next statutory vehicle inspection due by the stated date.'}], 'DCS_CCH_Activation': 'NA', 'DCS_CCH_Ongoing': False}}
{'latitude': 49.833446, 'longitude': 14.622442, 'isoCountryCode': 'CZE', 'auxPowerRegular': 1.4, 'auxPowerEcoPro': 1.2, 'auxPowerEcoProPlus': 0.4, 'soc': 9.844090461730957, 'socMax': 17.32, 'eco': '659,489,421,421,402,475,632,6d0,76f,8ac,9e9', 'norm': '698,4b6,4ac,4ac,41a,48f,632,6d0,76f,8ac,9e9', 'ecoEv': '659,489,421,421,402,475,632,6d0,76f,8ac,9e9', 'normEv': '698,4b6,4ac,4ac,41a,48f,632,6d0,76f,8ac,9e9', 'vehicleMass': '1400', 'kAccReg': '2412000', 'kDecReg': '3240000', 'kAccEco': '2520000', 'kDecEco': '3240000', 'kUp': '3132000', 'kDown': '3384000', 'driveTrain': 'bev_rex', 'pendingUpdate': False, 'vehicleTracking': True}


A opet predbehnuto sprovozneni poslani emailu :-)
21:42:24,296 root INFO last_percent loaded with a value of 63
21:42:24,773 root INFO Access token acquired
21:42:25,351 root INFO Battery data retreived successfully
21:42:26,353 root INFO SoC Data retreived successfully
21:42:26,364 root INFO inserted values to DB
21:42:26,365 root INFO last_percent file updated with 63
21:42:26,365 root INFO 63
21:42:26,365 root INFO CONNECTED
21:42:26,366 root INFO CHARGING
21:42:26,502 root INFO EMAIL message sent successfully
21:42:26,503 root INFO BMW i3 Status:
Battery: 63% (62 km) - CONNECTED/CHARGING
Mileage: 57403 km
Position http://maps.apple.com/?ll=popzice
socMax: 17.32 kWh



##########################################################################
Super mam vse potrebne pripraveno vcerne linuxovyho virtualku :-)

Koukam, ze jsi na to tedy asi sel "hackem" ty remote apky, ja koukal a BMW umi poskytovat nejak informace o voze treti strane, ale nestudoval jsem detajly.


############################################################################
21.11.2019
No tak ja se pochlubim....
https://cloud.itnaklic.cz/grafy-i3/

prihlaseni: elektroforum
heslo napoveda; Hlavni mesto na zacatku a konci s velkym pismenem.

Mapicku jsem vypnul, nemusite cumet kde vsude jezdim, staci ze to vi manzelka :D
Schody dolu jsou dany tim, ze za jizdy BMW data neaktualizuje a zaktualizuje je po vypnuti vozu.
#############################################################################
10.12.2019
BMW zmenilo nazev klice, uprava kodu

Kód: Vybrat vše

       if r.status_code == 200:
            status = r.json()
            if status.get('socmax'):
                 socMax = status['socmax']
            if status.get('socMax'):
                 socMax = status['socMax']
            logging.info('SoC Data retreived successfully')
            return socMax
        else:


#################################################################################
17.2.2020
BMW zmenilo servery, nutno upravit:

# API Gateway
# North America: b2vapi.bmwgroup.us
# Rest of World: b2vapi.bmwgroup.com
# China: b2vapi.bmwgroup.cn:8592
BASE_URL = 'customer.bmwgroup.com'

a v sekci getSocData

BASE_URLL = 'b2vapi.bmwgroup.com'
url = 'https://' + BASE_URLL + '/api/vehicle/navigation/v1/' + vin


#####################################################################################
21.2.2020
BMWdalsi zmena a oprava:


Kód: Vybrat vše

BASE_URL = 'customer.bmwgroup.com'
#BASE_URL = 'b2vapi.bmwgroup.com'

def getToken(BASE_URL, username, password, timeout=(20, 20)):
    try:
        headers = {
                "Content-Type": "application/x-www-form-urlencoded",
                "Content-Length": "124",
                "Connection": "Keep-Alive",
                "Host": BASE_URL,
                "Accept-Encoding": "gzip",
                "Authorization": "Basic blF2NkNxdHhKdVhXUDc0eGYzQ0p3VUVQOjF6REh4NnVuNGNEanli"
                                 "TEVOTjNreWZ1bVgya0VZaWdXUGNRcGR2RFJwSUJrN3JPSg==",
                "Credentials": "nQv6CqtxJuXWP74xf3CJwUEP:1zDHx6un4cDjybLENN3kyfumX2kEYigWPcQpdvDRpIBk7rOJ",
                "User-Agent": "okhttp/2.60"}

        data = {
            'client_id': 'dbf0a542-ebd1-4ff0-a9a7-55172fbfce35',
            'response_type': 'token',
            'redirect_uri': 'https://www.bmw-connecteddrive.com/app/static/external-dispatch.html',
            'scope': 'authenticate_user vehicle_data remote_services',
            'username': username,
            'password': password}

        data = urllib.parse.urlencode(data)#       url = 'https://' + BASE_URL + '/webapi/oauth/token'
#        url = 'https://' + BASE_URL + '/webapi/oauth/token'
        url = 'https://' + BASE_URL + '/gcdm/oauth/authenticate'
        #print (url)
        r = requests.post(url, data=data, headers=headers, allow_redirects=False)
        #print (r)
        if r.status_code == 302:
            logging.info('Access token acquired')
            response_json = dict(
                    urllib.parse.parse_qsl(urllib.parse.urlparse(r.headers['Location']).fragment)
                )
            #print(response_json)
            #print(response_json['access_token'])
            return response_json['access_token']
        else:
            raise ValueError('Unable to login')

    except Exception as msg:
        logging.error(msg)









Havrla
Naposledy upravil(a) Havrla dne pát 21. úno 2020 15:12:44, celkem upraveno 19 x.
Havrla
Jezdive: BMW i3REx; Volvo V70 T6; Tatra T700-II.
Nejezdive: Tatra 613-4; Skoda 105L
Uživatelský avatar
stejk
Příspěvky: 410
Registrován: ned 16. pro 2018 5:31:05

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod stejk » pon 04. lis 2019 18:56:48

ano, hackem... Rozhodně u Remote Services "stojí za to" si přečíst (při odsouhlasování podmínek) část o polohových údajích o voze.
Postupně ve volném čas sepisuji návod. Já mám VPS na FreeBSD. Linux nemám.
Uživatelský avatar
stejk
Příspěvky: 410
Registrován: ned 16. pro 2018 5:31:05

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod stejk » sob 09. lis 2019 18:39:45

Omlouvám se za neaktivitu, ale narazil jsem na několik zádrhelů.
Rozhodl jsem se, že budu publikovat postupně po částech... A sám si postupem znovu projdu...
Dnes jsem do hlavního příspěvku nahoře přidal první část, jak si stáhnout a rozchodit pracovní prostředí. Stroj s freebsd...
Pokud máte otázky, nebo se někde zadrhnete, tak napište.
Další díl postupu zase za týden o víkendu... Abyste se měli na co těšit :lol: :lol:
Havrla
Příspěvky: 133
Registrován: úte 24. zář 2019 21:01:45
Bydliště: Praha
Kontaktovat uživatele:

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod Havrla » sob 09. lis 2019 22:09:22

Ja se tesim, doufam ze to obslehnu, jenom misto BSD budu mit Linux :) , max se v pulce vratim na zacatek :-)
DIk za serial a tesim se na dalsi dil :-)
Havrla
Havrla
Jezdive: BMW i3REx; Volvo V70 T6; Tatra T700-II.
Nejezdive: Tatra 613-4; Skoda 105L
Havrla
Příspěvky: 133
Registrován: úte 24. zář 2019 21:01:45
Bydliště: Praha
Kontaktovat uživatele:

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod Havrla » stř 13. lis 2019 15:54:28

Poznamky pro Linuxare:
COS7 - doinstalovani python3 a potrebnych knihoven

yum install epel-release
yum install python3 python36
python3.6 -m ensurepip
yum install python36-setuptools_scm
pip3 install boto3
yum install python36-PyMySQL
yum install python36-cryptography

uprava BMW skryptu - hlavicky: #! /usr/bin/env python3
Havrla
Jezdive: BMW i3REx; Volvo V70 T6; Tatra T700-II.
Nejezdive: Tatra 613-4; Skoda 105L
Uživatelský avatar
stejk
Příspěvky: 410
Registrován: ned 16. pro 2018 5:31:05

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod stejk » čtv 14. lis 2019 13:42:36

Jsem mě předběhl :) . Díl č.2 bude až v sobotu, jen jsem si část už uložil... ale není celý. Ano, musí skript zhavarovat, protože tam chybí /root/bmw/credentials.json
Havrla
Příspěvky: 133
Registrován: úte 24. zář 2019 21:01:45
Bydliště: Praha
Kontaktovat uživatele:

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod Havrla » čtv 14. lis 2019 16:32:32

Tak on na neexistenci souboru nezhavaruje, ale radne se ukonci a zapise do logu, zhavaruje napriklad na neexisteci knihoven :-)
Linuxovou verzi budu take doplnovat nahor ejako druhy prispevek
Havrla
Jezdive: BMW i3REx; Volvo V70 T6; Tatra T700-II.
Nejezdive: Tatra 613-4; Skoda 105L
Uživatelský avatar
stejk
Příspěvky: 410
Registrován: ned 16. pro 2018 5:31:05

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod stejk » sob 16. lis 2019 7:51:44

Je zde omezení na množství příloh u jednoho příspěvku? Max 5 příloh?
Uživatelský avatar
stejk
Příspěvky: 410
Registrován: ned 16. pro 2018 5:31:05

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod stejk » ned 17. lis 2019 0:56:05

Druhý díl je venku. Pokud máte dotazy, tak pište. Další díl o víkendu rozchodíme DB a začneme sbíraná data ukládat do databáze.
Havrla
Příspěvky: 133
Registrován: úte 24. zář 2019 21:01:45
Bydliště: Praha
Kontaktovat uživatele:

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod Havrla » čtv 21. lis 2019 0:05:49

No tak ja se pochlubim.... a trochu navnadim...

https://cloud.itnaklic.cz/grafy-i3/

uzivatel: elektroforum
heslo napoveda; Hlavni mesto na zacatku a konci s velkym pismenem.

Mapicku jsem vypnul, nemusite cumet, kde vsude jezdim.
Schody dolu jsou dany tim, ze za jizdy BMW data neaktualizuje a zaktualizuje je po vypnuti vozu.
Havrla
Jezdive: BMW i3REx; Volvo V70 T6; Tatra T700-II.
Nejezdive: Tatra 613-4; Skoda 105L
Uživatelský avatar
Josef
Moderátor
Příspěvky: 1114
Registrován: čtv 27. dub 2017 5:11:54

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod Josef » pát 22. lis 2019 17:30:32

Pěkný!
Obrázek
Sono motors, SION refferal code - josef464477 - pro každého 1% slevy na auto.
Uživatelský avatar
stejk
Příspěvky: 410
Registrován: ned 16. pro 2018 5:31:05

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod stejk » ned 24. lis 2019 19:05:14

Doplněn další díl našeho seriálu ve kterém jsem rozchodili DB MySQL, upravili skript tak, že získaná data z vozu ukládáme do DB. Skript voláme cronem, takže již plníme data pravidelně do DB.
Příště se pokusíme o rozchození webového serveru a zobrazení nasbíraných dat.
Mishaczech
Příspěvky: 86
Registrován: stř 10. črc 2019 8:18:43

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod Mishaczech » úte 26. lis 2019 17:00:04

Tak to by byla paráda kdybych to zvládl - zatím jsem skončil na úpravě bmw.py - copy/paste to ve VirtualBoxu pod windows fakt nedává ani v MC a přepisovat to fakt nebudu...

Nebyla by cesta sem pak hodit celý to ISO nainstalovaný a hotový tak, že by se pouze dalo do VIrtualBoxu a pomocí MC upravily ty soubory, které jsou třeba "decentně" upravit (jméno, heslo, atp.)?
Havrla
Příspěvky: 133
Registrován: úte 24. zář 2019 21:01:45
Bydliště: Praha
Kontaktovat uživatele:

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod Havrla » úte 26. lis 2019 23:47:01

Ty mi a stejkovi ctes soukrome zpravy ? :-)

HINT: vkladani a kopirovani v MC pomoci mysi pokud neni nativni terminal lze pouzit v kombinaci s stiskem klavesy shift
Havrla
Jezdive: BMW i3REx; Volvo V70 T6; Tatra T700-II.
Nejezdive: Tatra 613-4; Skoda 105L
Mishaczech
Příspěvky: 86
Registrován: stř 10. črc 2019 8:18:43

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod Mishaczech » stř 27. lis 2019 6:56:24

Tak soukromé zprávy ti nečtu (zatím jsi mě neudělal tiskovým mluvčím :-) ), ale přemýšlíme jako IT zřejmě stejně :-)

A co se týká myši, tak tu bych nejdřív musel rozchodit zřejmě s CD přídavky pro hosta, ale i když je to cd0 který vidím v /dev i v dmesg tak ho stejně pomocí "mount /dev/cd0 /media/cdrom" nepřipojím. Jsem Linuxový animimino a takový už asi zůstanu do smrti
tak edit -
# mkdir -p /media/cdrom
# mount_cd9660 /dev/cd0 /media/cdrom

cd mám, ale zase nespustím .sh protože nemám linux distribuci, tudíž jsem tam co jsem byl - verze sdíleného ISO souboru bude pro mě asi nejlepší :-D
Uživatelský avatar
stejk
Příspěvky: 410
Registrován: ned 16. pro 2018 5:31:05

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod stejk » stř 27. lis 2019 18:59:28

V sobotu udělám návod, jak soubor přenést pomocí SSH do freebsd (z windows). Na MACu jsem v terminálu soubor pomocí SCP nakopíroval jednoduše, taky dám do návodu.
Uživatelský avatar
stejk
Příspěvky: 410
Registrován: ned 16. pro 2018 5:31:05

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod stejk » ned 08. pro 2019 15:45:03

Do našeho víkendového občasníku jsem přidal odkaz na rozchození openssh na windows 10 a příkaz který stáhnete z hostujích windows soubor... Nic lepšího jsem dosud nenašel. Zkoušel jsem opačné cesty (hostující windows jako klient, který odešle pomohí ssh souboro do freebsd) ale vždy jsem se někde zasekl. Na zprovoznění sdíleného adresáře mezi windows a freebsd jsem se taky kousl... Prostě s windows jen samé překážky. A tak bohužel nyní nic lepšího nemám, než to co jsem do návodu přidal. Příští víkend pokračujeme.
Naposledy upravil(a) stejk dne ned 15. pro 2019 18:52:13, celkem upraveno 1 x.
Havrla
Příspěvky: 133
Registrován: úte 24. zář 2019 21:01:45
Bydliště: Praha
Kontaktovat uživatele:

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod Havrla » úte 10. pro 2019 16:43:05

uprava kodu pro socMax

Kód: Vybrat vše


        if r.status_code == 200:
            status = r.json()
            if status.get('socmax'):
                 socMax = status['socmax']
            if status.get('socMax'):
                 socMax = status['socMax']
            logging.info('SoC Data retreived successfully')
            return socMax
        else:
       
 
Havrla
Jezdive: BMW i3REx; Volvo V70 T6; Tatra T700-II.
Nejezdive: Tatra 613-4; Skoda 105L
Uživatelský avatar
stejk
Příspěvky: 410
Registrován: ned 16. pro 2018 5:31:05

Re: Vyčítání dat z BMW telematiky, uložení do vlastní databáze a následné zobrazení

Příspěvekod stejk » stř 11. pro 2019 21:05:20

Díky moc. Opravu jsem do skriptu v prvním "master" příspěvku tohoto vlákna dodělal. Pokud někdo již máte u sebe skript nasazený, tak si opravu aplikujte, protože od včerejšího odpoledne vám jinak skript nebude fungovat, protože BMW API začalo vracet dala jinak.