Hallo zusammen,
ich habe mal das PythonSkript: https://github.com/wez3/volkswagen-carn … net_web.py auf JavaScript für ioBroker portiert, so dass man sich verschiedene Werte aus dem CarNet als States in ioBroker speichern lassen kann:
! ````
/* Skript zum Abragen des Status im Car-Net von Volkswagen
** V1.0.0 - 03.06.2018 - initiale Version (02.07.2018 fertiggestellt)
** V1.0.1 - 03.07.2018 - Wenn Location leer, dann Info in Adresse stellen
** - Längen-/Breitengrad mit °= 0 anstelle > 0 abfragen
/
! var request = require('request');
! var base = "https://www.volkswagen-car-net.com";
var authbase = "https://security.volkswagen.com";
var csrf = "";
var refUrl = "";
var viewState = "";
var cookieJar = null;
var urlHeader = null;
var code = "";
var state = "";
var unterwegs = "unterwegs - zuletzt:";
var email = ""; // User Car-Net-Account
var password = ""; // Passwort Car-Net-Account
var mapsApiKey= ""; // API-Key für Google Maps Platform (noch optional)
var errCount = 0; // Anzahl zulässige Fehler bis Mail verschickt wird
var defaultHeader = {
'Accept': 'application/json, text/plain, /',
'Content-Type': 'application/json;charset=UTF-8',
'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0.1; D5803 Build/23.5.A.1.291; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36'
};
var stateBatterieProz = "emanager.batteryPercentage";
var stateLadevorgang = "emanager.chargingState";
var stateLadedauer = "emanager.chargingRemaining";
var stateReichweite = "emanager.electricRange";
var stateMinLadung = "emanager.minChargeLimit";
var stateletzteVerb = "vehicle.lastConnectionTimeStamp";
var stateGesamtKm = "vehicle.distanceCovered";
var stateReichweiteV = "vehicle.range";
var stateServiceTermin= "vehicle.serviceInspectionData";
var statePosBreite = "location.lat";
var statePosLaenge = "location.lng";
var statePosAdresse = "location.address";
! createState(stateBatterieProz, -1, {
read: true,
write: false,
name: "Ladezustand der Hauptbatterie in 10%-Schritten",
type: "number",
unit: "%",
def: -1
});
! createState(stateLadevorgang, null, {
read: true,
write: false,
name: "Zustand des Ladevorgangs",
type: "string",
unit: "",
def: null
});
! createState(stateLadedauer, null, {
read: true,
write: false,
name: "Verbleibende Ladedauer bis 100% SoC",
type: "string",
//role: "datetime",
def: null
});
! createState(stateReichweite, -1, {
read: true,
write: false,
name: "Elektrische Reichweite mit aktuellem Batteriestand",
type: "number",
unit: "km",
def: -1
});
! createState(stateMinLadung, -1, {
read: true,
write: false,
name: "Mindest-SoC bei Ladevorgang",
type: "number",
unit: "%",
def: -1
});
! createState(stateletzteVerb, null, {
read: true,
write: false,
name: "Zeitpunkt der letzten Verbindung zum Fahrzeug",
type: "string", // "number",
role: "datetime",
def: null
});
! createState(stateGesamtKm, -1, {
read: true,
write: false,
name: "Gesamt-Kilomater-Stand",
type: "number",
unit: "km",
def: -1
});
! createState(stateReichweiteV, -1, {
read: true,
write: false,
name: "Reichweite des Fahrzeugs",
type: "number",
unit: "km",
def: -1
});
! createState(stateServiceTermin, null, {
read: true,
write: false,
name: "Nächster Service-Termin",
type: "string",
def: null
});
! createState(statePosBreite, 0, {
read: true,
write: false,
name: "Breitengrad der Position des Fahrzeugs",
type: "number",
def: 0
});
! createState(statePosLaenge, 0, {
read: true,
write: false,
name: "Längengrad der Position des Fahrzeugs",
type: "number",
def: 0
});
! createState(statePosAdresse, null, {
read: true,
write: false,
name: "Anschrift der Position des Fahrzeugs",
type: "string",
def: null
});
! function carNet_error(meldung, typ) {
if (typ === undefined)
typ = "";
! var sendMail = true;
log('CarNet: ' + meldung, 'error');
if (typ == "main") {
errCount ++;
if (errCount < 3)
sendMail = false;
}
if (sendMail)
sendTo("email", {
subject: "FEHLER bei CarNet-Verarbeitung",
text: meldung
});
}
! function getPartOfSite(content, startTag, endTag, startOffset) {
if (startOffset === undefined)
startOffset = 0;
var pos = content.indexOf(startTag, startOffset);
if (pos >= 0) {
pos += startTag.length;
var pos2 = content.indexOf(endTag, pos +1);
if (pos2 >= 0) {
return {
found: true,
value: content.substring(pos, pos2).trim(),
start: pos,
end: pos2,
cutter: pos2 + endTag.length
};
}
}
return null;
}
! function get_csrf(body) {
var data = getPartOfSite(body, '');
if (data === null) {
carNet_error('Kein Token für Login gefunden\n' + body);
return "";
}
return data.value;
}
! function get_loginUrl(body) {
var data = getPartOfSite(body, '"path":"', '"');
if (data === null) {
carNet_error('Keine Login-URL gefunden\n' + body);
return "";
}
return data.value;
}
! function get_viewState(body) {
var data = getPartOfSite(body, 'name="javax.faces.ViewState" id="j_id1:javax.faces.ViewState:0" value="', '"');
if (data === null) {
carNet_error('Keinen Viewstate für Login gefunden\n' + body);
return "";
}
return data.value.replace(/\x3a/g, ":").replace(/\x2f/g, "/").replace(/\x2e/g, ".");
}
! function get_redirectUrl(body) {
var data = getPartOfSite(body, '');
if (data === null) {
carNet_error('Keine Redirect-URL nach Login gefunden\n' + body);
return "";
}
return data.value.replace('&', '&');
}
! function get_code(body) {
var data = getPartOfSite(body, 'code=', '&');
if (data === null) {
carNet_error('Keinen Code nach Login gefunden\n' + body);
return "";
}
return data.value;
}
! function get_state(body) {
// Hier indexOf anstelle getPartOfsite, weil es keinen EndeString gibt
var pos = body.indexOf('state=');
if (pos < 0) {
carNet_error('Keinen State nach Login gefunden\n' + body);
return "";
}
return body.substr(pos + 6);
}
! function get_newUrl(url) {
var data = getPartOfSite(url, '/', '?', 10);
if (data === null) {
carNet_error('Konnte keinen Path aus URL ' + url + ' extrahieren');
return "";
}
return base + '/' + data.value + '?p_auth=' + state + '&p_p_id=33_WAR_cored5portlet&p_p_lifecycle=1&p_p_state=normal&p_p_mode=view&p_p_col_id=column-1&p_p_col_count=1&_33_WAR_cored5portlet_javax.portlet.action=getLoginStatus';
}
! function get_request(url, mayRedirect, forms, doJSON) {
var options = {
url: url,
jar: cookieJar
};
if (urlHeader !== null)
options.headers = urlHeader;
if (mayRedirect === undefined || mayRedirect === null)
mayRedirect = true;
if (! mayRedirect)
options.followRedirect = function (resp) { return false; };
if (forms !== undefined)
options.form = forms;
if (doJSON === undefined || doJSON === null)
doJSON = false;
if (doJSON)
options.json = true;
return options;
}
! function isAbrufOk(oper, err, stat, body) {
if (err)
carNet_error('Fehler "' + err + '" beim ' + oper);
else if(body) {
return true;
} else
carNet_error("Kein Inhalt bei " + oper + " (Status " + stat.statusCode + ")");
return false;
}
! function isRedirectOk(oper, err, stat, body) {
if (err)
carNet_error('Fehler "' + err + '" beim ' + oper);
else if(stat.statusCode == 302) {
return true;
} else
carNet_error(oper + " ist keine Weiterleitung (Status " + stat.statusCode + "): " + body);
return false;
}
! function carNet_login() {
csrf = "";
refUrl = "";
viewState = "";
cookieJar = request.jar();
urlHeader = null;
code = "";
state = "";
//request(base + '/portal/en_GB/web/guest/home', process_login1);
request(get_request(base + '/portal/en_GB/web/guest/home'), process_login1);
}
! function process_login1(err, stat, body) {
if (isAbrufOk("Login-Seite", err, stat, body)) {
urlHeader = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/*;q=0.8',
'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0.1; D5803 Build/23.5.A.1.291; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36',
'Referer': base + '/portal'
};
var detailsUrl = stat.request.uri.href;
csrf = get_csrf(body);
if (csrf === "")
return;
//console.log("Session = " + csrf);
request(get_request(base + "/portal/web/guest/home/-/csrftokenhandling/get-login-url"), process_login2);
}
}
function process_login2(err, stat, body) {
if (isAbrufOk("Login-Seite 2", err, stat, body)) {
var loginUrl = get_loginUrl(body);
if (loginUrl === "")
return;
//console.log('Login-URL: ' + loginUrl);
request.get(get_request(loginUrl, false), process_login3);
}
}
function process_login3(err, stat, body) {
if (isRedirectOk("Login-Setie 3", err, stat, body)) {
refUrl = stat.headers.location;
if (refUrl === "") {
carNet_error("Keine Location für Redirect gefunden");
return;
}
//console.log('refURL: ' + refUrl);
request.get(get_request(refUrl), process_login4);
}
}
function process_login4(err, stat, body) {
if (isAbrufOk("Login-Setie 4", err, stat, body)) {
viewState = get_viewState(body);
if (viewState === "")
return;
//console.log('ViewState = ' + viewState);
var formData = {
'loginForm': 'loginForm',
'loginForm:email': email,
'loginForm:password': password,
'loginForm:j_idt19': '',
'javax.faces.ViewState': viewState,
'javax.faces.source': 'loginForm:submit',
'javax.faces.partial.event': 'click',
'javax.faces.partial.execute': 'loginForm:submit loginForm',
'javax.faces.partial.render': 'loginForm',
'javax.faces.behavior.event': 'action',
'javax.faces.partial.ajax': 'true'
};
// AuthHeader aktualisieren
urlHeader['Faces-Request'] = 'partial/ajax';
urlHeader.Referer = refUrl;
urlHeader['X-CSRF-Token'] = '';
request.post(get_request(authbase + '/ap-login/jsf/login.jsf', null, formData), process_login5);
}
}
function process_login5(err, stat, body) {
if (isAbrufOk("Login-Seite 5", err, stat, body)) {
//console.log('Status = ' + stat.statusCode);
var redirectUrl = get_redirectUrl(body);
if (redirectUrl === "")
return;
request.get(get_request(redirectUrl, false), process_login6);
}
}
function process_login6(err, stat, body) {
if (isRedirectOk("Login-Seite 6", err, stat, body)) {
var redirectUrl2 = stat.headers.location;
if (redirectUrl2 === "") {
carNet_error("Keine Location für Redirect2 gefunden");
return;
}
code = get_code(redirectUrl2);
if (code === "")
return;
state = get_state(redirectUrl2);
if (state === "")
return;
//console.log('redirectUrl2: ' + redirectUrl2 + ', code = ' + code + ', state = ' + state);
request.get(get_request(redirectUrl2), process_login7);
}
}
function process_login7(err, stat, body) {
if (isAbrufOk("Login-Seite 7", err, stat,body)) {
//console.log('Status = ' + stat.statusCode);
urlHeader['Faces-Request'] = '';
urlHeader.Referer = stat.request.uri.href;
var post_data = {
'_33_WAR_cored5portlet_code': code,
'_33_WAR_cored5portlet_landingPageUrl': ''
}
var newUrl = get_newUrl(urlHeader.Referer);
if (newUrl === "")
return;
//console.log('newUrl = ' + newUrl);
request.post(get_request(newUrl , false, post_data), process_login8);
}
}
function process_login8(err, stat, body) {
if (isRedirectOk("Login-Seite 8", err, stat,body)) {
var redirectUrl3 = stat.headers.location;
if (redirectUrl3 === "") {
carNet_error("Keine Location für Redirect3 gefunden");
return;
}
request.get(get_request(redirectUrl3), process_login9);
}
}
function process_login9(err, stat, body) {
if (isAbrufOk("Login-Seite 9", err, stat, body)) {
//console.log('Status = ' + stat.statusCode);
csrf = get_csrf(body);
if (csrf === "")
return;
//console.log('neuer csrf = ' + csrf);
urlHeader = defaultHeader;
urlHeader.Referer = stat.request.uri.href;
urlHeader['X-CSRF-Token'] = csrf;
//request.post(get_request(stat.request.uri.href + '/-/msgc/get-new-messages', null, null, true), process_messages);
//request.post(get_request(stat.request.uri.href + '/-/vsr/request-vsr', null, null, true), process_vsr);
//request.post(get_request(stat.request.uri.href + '/-/vsr/get-vsr', null, null, true), process_vsr2);
request.post(get_request(stat.request.uri.href + '/-/cf/get-location', null, null, true), process_location);
request.post(get_request(stat.request.uri.href + '/-/vehicle-info/get-vehicle-details', null, null, true), process_vehicleDetails);
request.post(get_request(stat.request.uri.href + '/-/emanager/get-emanager', null, null, true), process_emanager);
}
}
function process_messages(err, stat, body) {
if (isAbrufOk("Messages", err, stat, body)) {
//console.log('Status = ' + stat.statusCode);
console.log('Messages = ' + JSON.stringify(body));
}
}
function process_vsr(err, stat, body) {
if (isAbrufOk("Get VSR", err, stat, body)) {
//console.log('Status = ' + stat.statusCode);
console.log('Get VSR = ' + JSON.stringify(body));
}
}
function process_vsr2(err, stat, body) {
if (isAbrufOk("Process VSR", err, stat, body)) {
//console.log('Status = ' + stat.statusCode);
console.log('Process VSR = ' + JSON.stringify(body));
}
}
function process_location(err, stat, body) {
if (isAbrufOk("Location", err, stat, body)) {
//console.log('Status = ' + stat.statusCode);
//console.log('Location = ' + JSON.stringify(body));
//var data = body; // JSON.parse(body);
if (body.errorCode != 0)
carNet_error('Fehler ' + body.errorCode + ' beim Abruf Positions-Daten: ' + JSON.stringify(body));
else {
var posStatus = body.position;
if (posStatus !== undefined && posStatus !== null) {
if ((posStatus.lat != 0) && (posStatus.lng != 0)) {
setState(statePosBreite, posStatus.lat, true);
setState(statePosLaenge, posStatus.lng, true);
requestGeocoding(posStatus.lat, posStatus.lng);
}
} else
if (getState(statePosAdresse).val.substr(0, unterwegs.length) != unterwegs)
setState(statePosAdresse, unterwegs + ' ' + getState(statePosAdresse).val, true);
}
}
}
function process_vehicleDetails(err, stat, body) {
if (isAbrufOk("Vehicle Details", err, stat, body)) {
//console.log('Status = ' + stat.statusCode);
//console.log('Vehicle Details = ' + JSON.stringify(body));
if (body.errorCode != 0)
carNet_error('Fehler ' + body.errorCode + ' beim Abruf Fahrzeug-Daten: ' + JSON.stringify(body));
else {
var vehStatus = body.vehicleDetails;
if (vehStatus !== undefined && vehStatus !== null) {
if (vehStatus.lastConnectionTimeStamp.length > 0) {
var datum = vehStatus.lastConnectionTimeStamp[0];
// tt.mm.jjjj zu jjjj-mm-tt drehen
datum = datum.substr(6, 4) + '-' + datum.substr(3, 2) + '-' + datum.substr(0, 2);
datum = datum + " " + vehStatus.lastConnectionTimeStamp[1]
//setState(stateletzteVerb, datum, true);
var x = new Date(datum);
setState(stateletzteVerb, x, true);
//console.log("Timestamp: " + datum + '=>' + x);
}
if (vehStatus.distanceCovered > 0)
setState(stateGesamtKm, parseInt(vehStatus.distanceCovered.replace('.', "")), true);
if (vehStatus.range > 0)
setState(stateReichweiteV, parseInt(vehStatus.range), true);
if (vehStatus.serviceInspectionData !== "")
setState(stateServiceTermin, vehStatus.serviceInspectionData, true);
}
}
}
}
function process_emanager(err, stat, body) {
if (isAbrufOk("eManager-Daten", err, stat, body)) {
//console.log('Status = ' + stat.statusCode);
//console.log('eManager = ' + JSON.stringify(body));
if (body.errorCode != 0)
carNet_error('Fehler ' + body.errorCode + ' beim Abruf eManager-Daten: ' + JSON.stringify(body));
else {
var ladeStatus = body.EManager.rbc.status;
if (ladeStatus !== undefined && ladeStatus !== null) {
setState(stateBatterieProz, ladeStatus.batteryPercentage, true);
//console.log('Ladestand: ' + ladeStatus.batteryPercentage + "%");
setState(stateLadevorgang, ladeStatus.chargingState, true);
//console.log('Ladevorgang: ' + ladeStatus.chargingState);
if (ladeStatus.chargingRemaningHour > 0 || ladeStatus.chargingRemaningMinute > 0)
setState(stateLadedauer, ladeStatus.chargingRemaningHour + ":" + ladeStatus.chargingRemaningMinute, true);
else
setState(stateLadedauer, "", true);
//console.log('Verbl. Ladedauer: ' + ladeStatus.chargingRemaningHour + "h " + ladeStatus.chargingRemaningMinute + "min");
setState(stateReichweite, ladeStatus.electricRange, true);
//console.log('Reichweite: ' + ladeStatus.electricRange + "km");
}
setState(stateMinLadung, body.EManager.rdt.settings.minChargeLimit, true);
//console.log('Mindestladung: ' + body.EManager.rdt.settings.minChargeLimit + "%");
}
}
}
! function process_geocoding(err, stat, body) {
if (isAbrufOk("Geocoding", err, stat, body)) {
//console.log('Status = ' + stat.statusCode);
//console.log('Location = ' + JSON.stringify(body));
//var data = body; // JSON.parse(body);
if (body.status != "OK")
//carNet_error('Fehler ' + body.status + '/' + body.error_message + ' beim Abruf Geocoding: ' + JSON.stringify(body));
log('Fehler ' + body.status + '/' + body.error_message + ' beim Abruf Geocoding: ' + JSON.stringify(body), 'error');
else {
var address = "<unbekannt>";
if ((body.results.length> 0) & body.results[0].formatted_address !== "")
address = body.results[0].formatted_address;
setState(statePosAdresse, address, true);
}
}
}
function requestGeocoding(lat, lng) {
var url = 'https://maps.googleapis.com/maps/api/geocode/json?latlng='+lat+','+lng;
if (mapsApiKey !== "")
url = url + '&key=' + mapsApiKey;
//console.log("Geocoding-URL: " + url)
request({
url: url,
headers: defaultHeader,
json: true
}, process_geocoding);
}
function doRequest() {
carNet_login();
}
! doRequest(); // einmal gleich losstarten
schedule("*/30 * * * *", doRequest);</unbekannt>
Die Benachrichtigung bei Fehlern per Mail kann man natürlcih auch rauswerfen und User und Passwort Eures Accounts müsst Ihr selbst eintragen.
Ab und an bekomme ich noch den Fehler, dass ich die Abfrage "over quota" ausführe, aber insgesamt klappt das schon ganz gut.
Kommentare, Verbesserungswünsche, … nur zu :-)
Viele Grüße
Sneak-L8