diff --git a/modules/et_awattarcap/awattarcapgetprices.py b/modules/et_awattarcap/awattarcapgetprices.py index 970a4ad41..80c3435aa 100644 --- a/modules/et_awattarcap/awattarcapgetprices.py +++ b/modules/et_awattarcap/awattarcapgetprices.py @@ -9,16 +9,15 @@ # --- Imports --- -from datetime import datetime, timedelta, time +from datetime import datetime, time import json import requests import os import sys - import factors -# --- Globale Variablen --- +# --- Globale Variablen --- debug = 0 priceFileToday = "/var/www/html/openWB/ramdisk/et_price_d0" priceFileTomorrow = "/var/www/html/openWB/ramdisk/et_price_d1" @@ -26,8 +25,8 @@ currentFile = "/var/www/html/openWB/ramdisk/etproviderprice" priceUrl = "https://api.awattar.de/v1/marketdata?start=" -# --- Helper-Funktionen --- +# --- Helper-Funktionen --- def logDebug(msgLevel, msgText): try: if debug >= msgLevel: @@ -38,20 +37,22 @@ def logDebug(msgLevel, msgText): f.write(line) except: pass - + return - + + def getWeekday(time): # 0=Montag,...,6=Sonntag dow = datetime.fromtimestamp(time).weekday() - + return dow - + + def getSeason(time): # 0=Sommer, 1=Winter, 2=Übergang month = datetime.fromtimestamp(time).month day = datetime.fromtimestamp(time).month - + if ((month == 5) and (day >= 15)) or (month == 6) or (month == 7) or (month == 8) or ((month == 9) and (day < 15)): season = 0 elif (month == 11) or (month == 12) or (month == 1) or (month == 2) or ((month == 3) and (day < 21)): @@ -62,100 +63,107 @@ def getSeason(time): season = 2 else: raise ValueError - + return season - -# --- Funktionen --- + +# --- Funktionen --- def checkPrices(fileName, time): try: data = loadPrices(fileName) fileTime = data['data'][0]['start_timestamp'] except: return False - + if fileTime == (time * 1000): return True - + return False + def downloadPrices(time): try: url = priceUrl + str(time) + "000" - jsond = requests.get(url, allow_redirects = True) + jsond = requests.get(url, allow_redirects=True) data = json.loads(jsond.text) except: return 0 - + return data + def loadPrices(fileName): try: with open(fileName, 'r') as f: data = json.loads(f.read()) except: return 0 - + return data - + + def savePrices(fileName, data): try: with open(fileName, 'w') as f: f.write(json.dumps(data)) except: return - + return - -def calculateCurve(data, time): + + +def calculateCurve(data, time): try: season = getSeason(time) weekday = getWeekday(time) avgprice = 0 pricecurve = {} - + for hour in range(24): factor = factors.getFactor(season, weekday, hour) hourprice = float(data['data'][hour]['marketprice']) avgprice = avgprice + (factor * hourprice) - + for hour in range(24): hourprice = data['data'][hour]['marketprice'] - pricecurve[hour] = round(((hourprice - avgprice) * 1.19) / 10, 2) + pricecurve[hour] = round(((hourprice - avgprice) * 1.19) / 10, 2) except: raise - + return pricecurve + def savePriceCurve(curve1, curve2, time1, time2): - try: - with open(curveFile, 'w') as f: + try: + with open(curveFile, 'w') as f: f.write("awattarcap_de\n") for hour in range(datetime.now().hour, 24): - f.write(str(time1 + (hour*60*60)) + "," + str(curve1[hour]) + "\n") + f.write(str(time1 + (hour*60*60)) + "," + str(curve1[hour]) + "\n") for hour in range(24): - f.write(str(time2 + (hour*60*60)) + "," + str(curve2[hour]) + "\n") + f.write(str(time2 + (hour*60*60)) + "," + str(curve2[hour]) + "\n") except: raise - + return - + + def saveCurrentPrice(curve1, time1): try: - with open(currentFile, 'w') as f: - f.write(str(curve1[datetime.now().hour])) + with open(currentFile, 'w') as f: + f.write(str(curve1[datetime.now().hour])) except: raise - + return - + + def publishPrices(): os.system('mosquitto_pub -r -t openWB/global/awattar/pricelist -m "$(cat ' + curveFile + ')"') os.system('mosquitto_pub -r -t openWB/global/awattar/ActualPriceForCharging -m "$(cat ' + currentFile + ')"') return - -# --- Hauptprogramm -- + +# --- Hauptprogramm -- def main(): try: debug = int(sys.argv[1]) @@ -163,43 +171,44 @@ def main(): timeTomorrow = int(timeToday + (24*60*60)) except: raise - + try: if checkPrices(priceFileToday, timeToday): dataToday = loadPrices(priceFileToday) else: dataToday = downloadPrices(timeToday) savePrices(priceFileToday, dataToday) - + curveToday = calculateCurve(dataToday, timeToday) except: curveToday = {} for hour in range(24): curveToday[hour] = 0 pass - + try: if checkPrices(priceFileTomorrow, timeTomorrow): dataTomorrow = loadPrices(priceFileTomorrow) else: dataTomorrow = downloadPrices(timeTomorrow) savePrices(priceFileTomorrow, dataTomorrow) - + curveTomorrow = calculateCurve(dataTomorrow, timeTomorrow) except: curveTomorrow = {} for hour in range(24): curveTomorrow[hour] = 0 pass - + try: savePriceCurve(curveToday, curveTomorrow, timeToday, timeTomorrow) saveCurrentPrice(curveToday, timeToday) publishPrices() except: raise - + exit(0) + if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/modules/et_awattarcap/factors.py b/modules/et_awattarcap/factors.py index f362fab4f..fc61468ee 100644 --- a/modules/et_awattarcap/factors.py +++ b/modules/et_awattarcap/factors.py @@ -1,9 +1,10 @@ data = [{"Season":"0","Day":"0","Hour":"0","Value":"0.02616"},{"Season":"0","Day":"0","Hour":"1","Value":"0.01948"},{"Season":"0","Day":"0","Hour":"2","Value":"0.01769"},{"Season":"0","Day":"0","Hour":"3","Value":"0.01666"},{"Season":"0","Day":"0","Hour":"4","Value":"0.01734"},{"Season":"0","Day":"0","Hour":"5","Value":"0.02106"},{"Season":"0","Day":"0","Hour":"6","Value":"0.03479"},{"Season":"0","Day":"0","Hour":"7","Value":"0.04610"},{"Season":"0","Day":"0","Hour":"8","Value":"0.05033"},{"Season":"0","Day":"0","Hour":"9","Value":"0.05120"},{"Season":"0","Day":"0","Hour":"10","Value":"0.04949"},{"Season":"0","Day":"0","Hour":"11","Value":"0.05044"},{"Season":"0","Day":"0","Hour":"12","Value":"0.05608"},{"Season":"0","Day":"0","Hour":"13","Value":"0.05426"},{"Season":"0","Day":"0","Hour":"14","Value":"0.04683"},{"Season":"0","Day":"0","Hour":"15","Value":"0.04221"},{"Season":"0","Day":"0","Hour":"16","Value":"0.04079"},{"Season":"0","Day":"0","Hour":"17","Value":"0.04353"},{"Season":"0","Day":"0","Hour":"18","Value":"0.05052"},{"Season":"0","Day":"0","Hour":"19","Value":"0.05869"},{"Season":"0","Day":"0","Hour":"20","Value":"0.05920"},{"Season":"0","Day":"0","Hour":"21","Value":"0.05598"},{"Season":"0","Day":"0","Hour":"22","Value":"0.05135"},{"Season":"0","Day":"0","Hour":"23","Value":"0.03983"},{"Season":"0","Day":"1","Hour":"0","Value":"0.02616"},{"Season":"0","Day":"1","Hour":"1","Value":"0.01948"},{"Season":"0","Day":"1","Hour":"2","Value":"0.01769"},{"Season":"0","Day":"1","Hour":"3","Value":"0.01666"},{"Season":"0","Day":"1","Hour":"4","Value":"0.01734"},{"Season":"0","Day":"1","Hour":"5","Value":"0.02106"},{"Season":"0","Day":"1","Hour":"6","Value":"0.03479"},{"Season":"0","Day":"1","Hour":"7","Value":"0.04610"},{"Season":"0","Day":"1","Hour":"8","Value":"0.05033"},{"Season":"0","Day":"1","Hour":"9","Value":"0.05120"},{"Season":"0","Day":"1","Hour":"10","Value":"0.04949"},{"Season":"0","Day":"1","Hour":"11","Value":"0.05044"},{"Season":"0","Day":"1","Hour":"12","Value":"0.05608"},{"Season":"0","Day":"1","Hour":"13","Value":"0.05426"},{"Season":"0","Day":"1","Hour":"14","Value":"0.04683"},{"Season":"0","Day":"1","Hour":"15","Value":"0.04221"},{"Season":"0","Day":"1","Hour":"16","Value":"0.04079"},{"Season":"0","Day":"1","Hour":"17","Value":"0.04353"},{"Season":"0","Day":"1","Hour":"18","Value":"0.05052"},{"Season":"0","Day":"1","Hour":"19","Value":"0.05869"},{"Season":"0","Day":"1","Hour":"20","Value":"0.05920"},{"Season":"0","Day":"1","Hour":"21","Value":"0.05598"},{"Season":"0","Day":"1","Hour":"22","Value":"0.05135"},{"Season":"0","Day":"1","Hour":"23","Value":"0.03983"},{"Season":"0","Day":"2","Hour":"0","Value":"0.02616"},{"Season":"0","Day":"2","Hour":"1","Value":"0.01948"},{"Season":"0","Day":"2","Hour":"2","Value":"0.01769"},{"Season":"0","Day":"2","Hour":"3","Value":"0.01666"},{"Season":"0","Day":"2","Hour":"4","Value":"0.01734"},{"Season":"0","Day":"2","Hour":"5","Value":"0.02106"},{"Season":"0","Day":"2","Hour":"6","Value":"0.03479"},{"Season":"0","Day":"2","Hour":"7","Value":"0.04610"},{"Season":"0","Day":"2","Hour":"8","Value":"0.05033"},{"Season":"0","Day":"2","Hour":"9","Value":"0.05120"},{"Season":"0","Day":"2","Hour":"10","Value":"0.04949"},{"Season":"0","Day":"2","Hour":"11","Value":"0.05044"},{"Season":"0","Day":"2","Hour":"12","Value":"0.05608"},{"Season":"0","Day":"2","Hour":"13","Value":"0.05426"},{"Season":"0","Day":"2","Hour":"14","Value":"0.04683"},{"Season":"0","Day":"2","Hour":"15","Value":"0.04221"},{"Season":"0","Day":"2","Hour":"16","Value":"0.04079"},{"Season":"0","Day":"2","Hour":"17","Value":"0.04353"},{"Season":"0","Day":"2","Hour":"18","Value":"0.05052"},{"Season":"0","Day":"2","Hour":"19","Value":"0.05869"},{"Season":"0","Day":"2","Hour":"20","Value":"0.05920"},{"Season":"0","Day":"2","Hour":"21","Value":"0.05598"},{"Season":"0","Day":"2","Hour":"22","Value":"0.05135"},{"Season":"0","Day":"2","Hour":"23","Value":"0.03983"},{"Season":"0","Day":"3","Hour":"0","Value":"0.02616"},{"Season":"0","Day":"3","Hour":"1","Value":"0.01948"},{"Season":"0","Day":"3","Hour":"2","Value":"0.01769"},{"Season":"0","Day":"3","Hour":"3","Value":"0.01666"},{"Season":"0","Day":"3","Hour":"4","Value":"0.01734"},{"Season":"0","Day":"3","Hour":"5","Value":"0.02106"},{"Season":"0","Day":"3","Hour":"6","Value":"0.03479"},{"Season":"0","Day":"3","Hour":"7","Value":"0.04610"},{"Season":"0","Day":"3","Hour":"8","Value":"0.05033"},{"Season":"0","Day":"3","Hour":"9","Value":"0.05120"},{"Season":"0","Day":"3","Hour":"10","Value":"0.04949"},{"Season":"0","Day":"3","Hour":"11","Value":"0.05044"},{"Season":"0","Day":"3","Hour":"12","Value":"0.05608"},{"Season":"0","Day":"3","Hour":"13","Value":"0.05426"},{"Season":"0","Day":"3","Hour":"14","Value":"0.04683"},{"Season":"0","Day":"3","Hour":"15","Value":"0.04221"},{"Season":"0","Day":"3","Hour":"16","Value":"0.04079"},{"Season":"0","Day":"3","Hour":"17","Value":"0.04353"},{"Season":"0","Day":"3","Hour":"18","Value":"0.05052"},{"Season":"0","Day":"3","Hour":"19","Value":"0.05869"},{"Season":"0","Day":"3","Hour":"20","Value":"0.05920"},{"Season":"0","Day":"3","Hour":"21","Value":"0.05598"},{"Season":"0","Day":"3","Hour":"22","Value":"0.05135"},{"Season":"0","Day":"3","Hour":"23","Value":"0.03983"},{"Season":"0","Day":"4","Hour":"0","Value":"0.02616"},{"Season":"0","Day":"4","Hour":"1","Value":"0.01948"},{"Season":"0","Day":"4","Hour":"2","Value":"0.01769"},{"Season":"0","Day":"4","Hour":"3","Value":"0.01666"},{"Season":"0","Day":"4","Hour":"4","Value":"0.01734"},{"Season":"0","Day":"4","Hour":"5","Value":"0.02106"},{"Season":"0","Day":"4","Hour":"6","Value":"0.03479"},{"Season":"0","Day":"4","Hour":"7","Value":"0.04610"},{"Season":"0","Day":"4","Hour":"8","Value":"0.05033"},{"Season":"0","Day":"4","Hour":"9","Value":"0.05120"},{"Season":"0","Day":"4","Hour":"10","Value":"0.04949"},{"Season":"0","Day":"4","Hour":"11","Value":"0.05044"},{"Season":"0","Day":"4","Hour":"12","Value":"0.05608"},{"Season":"0","Day":"4","Hour":"13","Value":"0.05426"},{"Season":"0","Day":"4","Hour":"14","Value":"0.04683"},{"Season":"0","Day":"4","Hour":"15","Value":"0.04221"},{"Season":"0","Day":"4","Hour":"16","Value":"0.04079"},{"Season":"0","Day":"4","Hour":"17","Value":"0.04353"},{"Season":"0","Day":"4","Hour":"18","Value":"0.05052"},{"Season":"0","Day":"4","Hour":"19","Value":"0.05869"},{"Season":"0","Day":"4","Hour":"20","Value":"0.05920"},{"Season":"0","Day":"4","Hour":"21","Value":"0.05598"},{"Season":"0","Day":"4","Hour":"22","Value":"0.05135"},{"Season":"0","Day":"4","Hour":"23","Value":"0.03983"},{"Season":"0","Day":"5","Hour":"0","Value":"0.02737"},{"Season":"0","Day":"5","Hour":"1","Value":"0.02121"},{"Season":"0","Day":"5","Hour":"2","Value":"0.01725"},{"Season":"0","Day":"5","Hour":"3","Value":"0.01649"},{"Season":"0","Day":"5","Hour":"4","Value":"0.01665"},{"Season":"0","Day":"5","Hour":"5","Value":"0.01703"},{"Season":"0","Day":"5","Hour":"6","Value":"0.02100"},{"Season":"0","Day":"5","Hour":"7","Value":"0.03070"},{"Season":"0","Day":"5","Hour":"8","Value":"0.04233"},{"Season":"0","Day":"5","Hour":"9","Value":"0.05135"},{"Season":"0","Day":"5","Hour":"10","Value":"0.05435"},{"Season":"0","Day":"5","Hour":"11","Value":"0.05642"},{"Season":"0","Day":"5","Hour":"12","Value":"0.06005"},{"Season":"0","Day":"5","Hour":"13","Value":"0.05802"},{"Season":"0","Day":"5","Hour":"14","Value":"0.05182"},{"Season":"0","Day":"5","Hour":"15","Value":"0.04892"},{"Season":"0","Day":"5","Hour":"16","Value":"0.04775"},{"Season":"0","Day":"5","Hour":"17","Value":"0.04911"},{"Season":"0","Day":"5","Hour":"18","Value":"0.05490"},{"Season":"0","Day":"5","Hour":"19","Value":"0.05947"},{"Season":"0","Day":"5","Hour":"20","Value":"0.05701"},{"Season":"0","Day":"5","Hour":"21","Value":"0.05072"},{"Season":"0","Day":"5","Hour":"22","Value":"0.04899"},{"Season":"0","Day":"5","Hour":"23","Value":"0.04110"},{"Season":"0","Day":"6","Hour":"0","Value":"0.03139"},{"Season":"0","Day":"6","Hour":"1","Value":"0.02335"},{"Season":"0","Day":"6","Hour":"2","Value":"0.01909"},{"Season":"0","Day":"6","Hour":"3","Value":"0.01773"},{"Season":"0","Day":"6","Hour":"4","Value":"0.01751"},{"Season":"0","Day":"6","Hour":"5","Value":"0.01709"},{"Season":"0","Day":"6","Hour":"6","Value":"0.01798"},{"Season":"0","Day":"6","Hour":"7","Value":"0.02435"},{"Season":"0","Day":"6","Hour":"8","Value":"0.03940"},{"Season":"0","Day":"6","Hour":"9","Value":"0.05615"},{"Season":"0","Day":"6","Hour":"10","Value":"0.06538"},{"Season":"0","Day":"6","Hour":"11","Value":"0.07208"},{"Season":"0","Day":"6","Hour":"12","Value":"0.07339"},{"Season":"0","Day":"6","Hour":"13","Value":"0.06145"},{"Season":"0","Day":"6","Hour":"14","Value":"0.05048"},{"Season":"0","Day":"6","Hour":"15","Value":"0.04358"},{"Season":"0","Day":"6","Hour":"16","Value":"0.03797"},{"Season":"0","Day":"6","Hour":"17","Value":"0.03838"},{"Season":"0","Day":"6","Hour":"18","Value":"0.04438"},{"Season":"0","Day":"6","Hour":"19","Value":"0.05327"},{"Season":"0","Day":"6","Hour":"20","Value":"0.05586"},{"Season":"0","Day":"6","Hour":"21","Value":"0.05273"},{"Season":"0","Day":"6","Hour":"22","Value":"0.04912"},{"Season":"0","Day":"6","Hour":"23","Value":"0.03787"},{"Season":"1","Day":"0","Hour":"0","Value":"0.02281"},{"Season":"1","Day":"0","Hour":"1","Value":"0.01687"},{"Season":"1","Day":"0","Hour":"2","Value":"0.01547"},{"Season":"1","Day":"0","Hour":"3","Value":"0.01506"},{"Season":"1","Day":"0","Hour":"4","Value":"0.01531"},{"Season":"1","Day":"0","Hour":"5","Value":"0.01834"},{"Season":"1","Day":"0","Hour":"6","Value":"0.03524"},{"Season":"1","Day":"0","Hour":"7","Value":"0.05063"},{"Season":"1","Day":"0","Hour":"8","Value":"0.05223"},{"Season":"1","Day":"0","Hour":"9","Value":"0.04820"},{"Season":"1","Day":"0","Hour":"10","Value":"0.04547"},{"Season":"1","Day":"0","Hour":"11","Value":"0.04629"},{"Season":"1","Day":"0","Hour":"12","Value":"0.05114"},{"Season":"1","Day":"0","Hour":"13","Value":"0.05066"},{"Season":"1","Day":"0","Hour":"14","Value":"0.04513"},{"Season":"1","Day":"0","Hour":"15","Value":"0.04101"},{"Season":"1","Day":"0","Hour":"16","Value":"0.04117"},{"Season":"1","Day":"0","Hour":"17","Value":"0.05033"},{"Season":"1","Day":"0","Hour":"18","Value":"0.06502"},{"Season":"1","Day":"0","Hour":"19","Value":"0.07318"},{"Season":"1","Day":"0","Hour":"20","Value":"0.06582"},{"Season":"1","Day":"0","Hour":"21","Value":"0.05516"},{"Season":"1","Day":"0","Hour":"22","Value":"0.04565"},{"Season":"1","Day":"0","Hour":"23","Value":"0.03380"},{"Season":"1","Day":"1","Hour":"0","Value":"0.02281"},{"Season":"1","Day":"1","Hour":"1","Value":"0.01687"},{"Season":"1","Day":"1","Hour":"2","Value":"0.01547"},{"Season":"1","Day":"1","Hour":"3","Value":"0.01506"},{"Season":"1","Day":"1","Hour":"4","Value":"0.01531"},{"Season":"1","Day":"1","Hour":"5","Value":"0.01834"},{"Season":"1","Day":"1","Hour":"6","Value":"0.03524"},{"Season":"1","Day":"1","Hour":"7","Value":"0.05063"},{"Season":"1","Day":"1","Hour":"8","Value":"0.05223"},{"Season":"1","Day":"1","Hour":"9","Value":"0.04820"},{"Season":"1","Day":"1","Hour":"10","Value":"0.04547"},{"Season":"1","Day":"1","Hour":"11","Value":"0.04629"},{"Season":"1","Day":"1","Hour":"12","Value":"0.05114"},{"Season":"1","Day":"1","Hour":"13","Value":"0.05066"},{"Season":"1","Day":"1","Hour":"14","Value":"0.04513"},{"Season":"1","Day":"1","Hour":"15","Value":"0.04101"},{"Season":"1","Day":"1","Hour":"16","Value":"0.04117"},{"Season":"1","Day":"1","Hour":"17","Value":"0.05033"},{"Season":"1","Day":"1","Hour":"18","Value":"0.06502"},{"Season":"1","Day":"1","Hour":"19","Value":"0.07318"},{"Season":"1","Day":"1","Hour":"20","Value":"0.06582"},{"Season":"1","Day":"1","Hour":"21","Value":"0.05516"},{"Season":"1","Day":"1","Hour":"22","Value":"0.04565"},{"Season":"1","Day":"1","Hour":"23","Value":"0.03380"},{"Season":"1","Day":"2","Hour":"0","Value":"0.02281"},{"Season":"1","Day":"2","Hour":"1","Value":"0.01687"},{"Season":"1","Day":"2","Hour":"2","Value":"0.01547"},{"Season":"1","Day":"2","Hour":"3","Value":"0.01506"},{"Season":"1","Day":"2","Hour":"4","Value":"0.01531"},{"Season":"1","Day":"2","Hour":"5","Value":"0.01834"},{"Season":"1","Day":"2","Hour":"6","Value":"0.03524"},{"Season":"1","Day":"2","Hour":"7","Value":"0.05063"},{"Season":"1","Day":"2","Hour":"8","Value":"0.05223"},{"Season":"1","Day":"2","Hour":"9","Value":"0.04820"},{"Season":"1","Day":"2","Hour":"10","Value":"0.04547"},{"Season":"1","Day":"2","Hour":"11","Value":"0.04629"},{"Season":"1","Day":"2","Hour":"12","Value":"0.05114"},{"Season":"1","Day":"2","Hour":"13","Value":"0.05066"},{"Season":"1","Day":"2","Hour":"14","Value":"0.04513"},{"Season":"1","Day":"2","Hour":"15","Value":"0.04101"},{"Season":"1","Day":"2","Hour":"16","Value":"0.04117"},{"Season":"1","Day":"2","Hour":"17","Value":"0.05033"},{"Season":"1","Day":"2","Hour":"18","Value":"0.06502"},{"Season":"1","Day":"2","Hour":"19","Value":"0.07318"},{"Season":"1","Day":"2","Hour":"20","Value":"0.06582"},{"Season":"1","Day":"2","Hour":"21","Value":"0.05516"},{"Season":"1","Day":"2","Hour":"22","Value":"0.04565"},{"Season":"1","Day":"2","Hour":"23","Value":"0.03380"},{"Season":"1","Day":"3","Hour":"0","Value":"0.02281"},{"Season":"1","Day":"3","Hour":"1","Value":"0.01687"},{"Season":"1","Day":"3","Hour":"2","Value":"0.01547"},{"Season":"1","Day":"3","Hour":"3","Value":"0.01506"},{"Season":"1","Day":"3","Hour":"4","Value":"0.01531"},{"Season":"1","Day":"3","Hour":"5","Value":"0.01834"},{"Season":"1","Day":"3","Hour":"6","Value":"0.03524"},{"Season":"1","Day":"3","Hour":"7","Value":"0.05063"},{"Season":"1","Day":"3","Hour":"8","Value":"0.05223"},{"Season":"1","Day":"3","Hour":"9","Value":"0.04820"},{"Season":"1","Day":"3","Hour":"10","Value":"0.04547"},{"Season":"1","Day":"3","Hour":"11","Value":"0.04629"},{"Season":"1","Day":"3","Hour":"12","Value":"0.05114"},{"Season":"1","Day":"3","Hour":"13","Value":"0.05066"},{"Season":"1","Day":"3","Hour":"14","Value":"0.04513"},{"Season":"1","Day":"3","Hour":"15","Value":"0.04101"},{"Season":"1","Day":"3","Hour":"16","Value":"0.04117"},{"Season":"1","Day":"3","Hour":"17","Value":"0.05033"},{"Season":"1","Day":"3","Hour":"18","Value":"0.06502"},{"Season":"1","Day":"3","Hour":"19","Value":"0.07318"},{"Season":"1","Day":"3","Hour":"20","Value":"0.06582"},{"Season":"1","Day":"3","Hour":"21","Value":"0.05516"},{"Season":"1","Day":"3","Hour":"22","Value":"0.04565"},{"Season":"1","Day":"3","Hour":"23","Value":"0.03380"},{"Season":"1","Day":"4","Hour":"0","Value":"0.02281"},{"Season":"1","Day":"4","Hour":"1","Value":"0.01687"},{"Season":"1","Day":"4","Hour":"2","Value":"0.01547"},{"Season":"1","Day":"4","Hour":"3","Value":"0.01506"},{"Season":"1","Day":"4","Hour":"4","Value":"0.01531"},{"Season":"1","Day":"4","Hour":"5","Value":"0.01834"},{"Season":"1","Day":"4","Hour":"6","Value":"0.03524"},{"Season":"1","Day":"4","Hour":"7","Value":"0.05063"},{"Season":"1","Day":"4","Hour":"8","Value":"0.05223"},{"Season":"1","Day":"4","Hour":"9","Value":"0.04820"},{"Season":"1","Day":"4","Hour":"10","Value":"0.04547"},{"Season":"1","Day":"4","Hour":"11","Value":"0.04629"},{"Season":"1","Day":"4","Hour":"12","Value":"0.05114"},{"Season":"1","Day":"4","Hour":"13","Value":"0.05066"},{"Season":"1","Day":"4","Hour":"14","Value":"0.04513"},{"Season":"1","Day":"4","Hour":"15","Value":"0.04101"},{"Season":"1","Day":"4","Hour":"16","Value":"0.04117"},{"Season":"1","Day":"4","Hour":"17","Value":"0.05033"},{"Season":"1","Day":"4","Hour":"18","Value":"0.06502"},{"Season":"1","Day":"4","Hour":"19","Value":"0.07318"},{"Season":"1","Day":"4","Hour":"20","Value":"0.06582"},{"Season":"1","Day":"4","Hour":"21","Value":"0.05516"},{"Season":"1","Day":"4","Hour":"22","Value":"0.04565"},{"Season":"1","Day":"4","Hour":"23","Value":"0.03380"},{"Season":"1","Day":"5","Hour":"0","Value":"0.02323"},{"Season":"1","Day":"5","Hour":"1","Value":"0.01833"},{"Season":"1","Day":"5","Hour":"2","Value":"0.01459"},{"Season":"1","Day":"5","Hour":"3","Value":"0.01375"},{"Season":"1","Day":"5","Hour":"4","Value":"0.01333"},{"Season":"1","Day":"5","Hour":"5","Value":"0.01388"},{"Season":"1","Day":"5","Hour":"6","Value":"0.01840"},{"Season":"1","Day":"5","Hour":"7","Value":"0.02839"},{"Season":"1","Day":"5","Hour":"8","Value":"0.04147"},{"Season":"1","Day":"5","Hour":"9","Value":"0.04909"},{"Season":"1","Day":"5","Hour":"10","Value":"0.05122"},{"Season":"1","Day":"5","Hour":"11","Value":"0.05370"},{"Season":"1","Day":"5","Hour":"12","Value":"0.05772"},{"Season":"1","Day":"5","Hour":"13","Value":"0.05745"},{"Season":"1","Day":"5","Hour":"14","Value":"0.05316"},{"Season":"1","Day":"5","Hour":"15","Value":"0.04981"},{"Season":"1","Day":"5","Hour":"16","Value":"0.05015"},{"Season":"1","Day":"5","Hour":"17","Value":"0.06253"},{"Season":"1","Day":"5","Hour":"18","Value":"0.07254"},{"Season":"1","Day":"5","Hour":"19","Value":"0.07280"},{"Season":"1","Day":"5","Hour":"20","Value":"0.05957"},{"Season":"1","Day":"5","Hour":"21","Value":"0.04646"},{"Season":"1","Day":"5","Hour":"22","Value":"0.04244"},{"Season":"1","Day":"5","Hour":"23","Value":"0.03600"},{"Season":"1","Day":"6","Hour":"0","Value":"0.02911"},{"Season":"1","Day":"6","Hour":"1","Value":"0.02096"},{"Season":"1","Day":"6","Hour":"2","Value":"0.01678"},{"Season":"1","Day":"6","Hour":"3","Value":"0.01532"},{"Season":"1","Day":"6","Hour":"4","Value":"0.01442"},{"Season":"1","Day":"6","Hour":"5","Value":"0.01438"},{"Season":"1","Day":"6","Hour":"6","Value":"0.01525"},{"Season":"1","Day":"6","Hour":"7","Value":"0.01862"},{"Season":"1","Day":"6","Hour":"8","Value":"0.03296"},{"Season":"1","Day":"6","Hour":"9","Value":"0.05157"},{"Season":"1","Day":"6","Hour":"10","Value":"0.06486"},{"Season":"1","Day":"6","Hour":"11","Value":"0.07551"},{"Season":"1","Day":"6","Hour":"12","Value":"0.07697"},{"Season":"1","Day":"6","Hour":"13","Value":"0.06443"},{"Season":"1","Day":"6","Hour":"14","Value":"0.05069"},{"Season":"1","Day":"6","Hour":"15","Value":"0.04342"},{"Season":"1","Day":"6","Hour":"16","Value":"0.03973"},{"Season":"1","Day":"6","Hour":"17","Value":"0.04681"},{"Season":"1","Day":"6","Hour":"18","Value":"0.05824"},{"Season":"1","Day":"6","Hour":"19","Value":"0.06564"},{"Season":"1","Day":"6","Hour":"20","Value":"0.05963"},{"Season":"1","Day":"6","Hour":"21","Value":"0.05047"},{"Season":"1","Day":"6","Hour":"22","Value":"0.04273"},{"Season":"1","Day":"6","Hour":"23","Value":"0.03151"},{"Season":"2","Day":"0","Hour":"0","Value":"0.02470"},{"Season":"2","Day":"0","Hour":"1","Value":"0.01824"},{"Season":"2","Day":"0","Hour":"2","Value":"0.01642"},{"Season":"2","Day":"0","Hour":"3","Value":"0.01599"},{"Season":"2","Day":"0","Hour":"4","Value":"0.01634"},{"Season":"2","Day":"0","Hour":"5","Value":"0.01952"},{"Season":"2","Day":"0","Hour":"6","Value":"0.03447"},{"Season":"2","Day":"0","Hour":"7","Value":"0.04812"},{"Season":"2","Day":"0","Hour":"8","Value":"0.05100"},{"Season":"2","Day":"0","Hour":"9","Value":"0.05043"},{"Season":"2","Day":"0","Hour":"10","Value":"0.04898"},{"Season":"2","Day":"0","Hour":"11","Value":"0.04943"},{"Season":"2","Day":"0","Hour":"12","Value":"0.05549"},{"Season":"2","Day":"0","Hour":"13","Value":"0.05403"},{"Season":"2","Day":"0","Hour":"14","Value":"0.04703"},{"Season":"2","Day":"0","Hour":"15","Value":"0.04207"},{"Season":"2","Day":"0","Hour":"16","Value":"0.03938"},{"Season":"2","Day":"0","Hour":"17","Value":"0.04315"},{"Season":"2","Day":"0","Hour":"18","Value":"0.05373"},{"Season":"2","Day":"0","Hour":"19","Value":"0.06377"},{"Season":"2","Day":"0","Hour":"20","Value":"0.06234"},{"Season":"2","Day":"0","Hour":"21","Value":"0.05785"},{"Season":"2","Day":"0","Hour":"22","Value":"0.05034"},{"Season":"2","Day":"0","Hour":"23","Value":"0.03719"},{"Season":"2","Day":"1","Hour":"0","Value":"0.02470"},{"Season":"2","Day":"1","Hour":"1","Value":"0.01824"},{"Season":"2","Day":"1","Hour":"2","Value":"0.01642"},{"Season":"2","Day":"1","Hour":"3","Value":"0.01599"},{"Season":"2","Day":"1","Hour":"4","Value":"0.01634"},{"Season":"2","Day":"1","Hour":"5","Value":"0.01952"},{"Season":"2","Day":"1","Hour":"6","Value":"0.03447"},{"Season":"2","Day":"1","Hour":"7","Value":"0.04812"},{"Season":"2","Day":"1","Hour":"8","Value":"0.05100"},{"Season":"2","Day":"1","Hour":"9","Value":"0.05043"},{"Season":"2","Day":"1","Hour":"10","Value":"0.04898"},{"Season":"2","Day":"1","Hour":"11","Value":"0.04943"},{"Season":"2","Day":"1","Hour":"12","Value":"0.05549"},{"Season":"2","Day":"1","Hour":"13","Value":"0.05403"},{"Season":"2","Day":"1","Hour":"14","Value":"0.04703"},{"Season":"2","Day":"1","Hour":"15","Value":"0.04207"},{"Season":"2","Day":"1","Hour":"16","Value":"0.03938"},{"Season":"2","Day":"1","Hour":"17","Value":"0.04315"},{"Season":"2","Day":"1","Hour":"18","Value":"0.05373"},{"Season":"2","Day":"1","Hour":"19","Value":"0.06377"},{"Season":"2","Day":"1","Hour":"20","Value":"0.06234"},{"Season":"2","Day":"1","Hour":"21","Value":"0.05785"},{"Season":"2","Day":"1","Hour":"22","Value":"0.05034"},{"Season":"2","Day":"1","Hour":"23","Value":"0.03719"},{"Season":"2","Day":"2","Hour":"0","Value":"0.02470"},{"Season":"2","Day":"2","Hour":"1","Value":"0.01824"},{"Season":"2","Day":"2","Hour":"2","Value":"0.01642"},{"Season":"2","Day":"2","Hour":"3","Value":"0.01599"},{"Season":"2","Day":"2","Hour":"4","Value":"0.01634"},{"Season":"2","Day":"2","Hour":"5","Value":"0.01952"},{"Season":"2","Day":"2","Hour":"6","Value":"0.03447"},{"Season":"2","Day":"2","Hour":"7","Value":"0.04812"},{"Season":"2","Day":"2","Hour":"8","Value":"0.05100"},{"Season":"2","Day":"2","Hour":"9","Value":"0.05043"},{"Season":"2","Day":"2","Hour":"10","Value":"0.04898"},{"Season":"2","Day":"2","Hour":"11","Value":"0.04943"},{"Season":"2","Day":"2","Hour":"12","Value":"0.05549"},{"Season":"2","Day":"2","Hour":"13","Value":"0.05403"},{"Season":"2","Day":"2","Hour":"14","Value":"0.04703"},{"Season":"2","Day":"2","Hour":"15","Value":"0.04207"},{"Season":"2","Day":"2","Hour":"16","Value":"0.03938"},{"Season":"2","Day":"2","Hour":"17","Value":"0.04315"},{"Season":"2","Day":"2","Hour":"18","Value":"0.05373"},{"Season":"2","Day":"2","Hour":"19","Value":"0.06377"},{"Season":"2","Day":"2","Hour":"20","Value":"0.06234"},{"Season":"2","Day":"2","Hour":"21","Value":"0.05785"},{"Season":"2","Day":"2","Hour":"22","Value":"0.05034"},{"Season":"2","Day":"2","Hour":"23","Value":"0.03719"},{"Season":"2","Day":"3","Hour":"0","Value":"0.02470"},{"Season":"2","Day":"3","Hour":"1","Value":"0.01824"},{"Season":"2","Day":"3","Hour":"2","Value":"0.01642"},{"Season":"2","Day":"3","Hour":"3","Value":"0.01599"},{"Season":"2","Day":"3","Hour":"4","Value":"0.01634"},{"Season":"2","Day":"3","Hour":"5","Value":"0.01952"},{"Season":"2","Day":"3","Hour":"6","Value":"0.03447"},{"Season":"2","Day":"3","Hour":"7","Value":"0.04812"},{"Season":"2","Day":"3","Hour":"8","Value":"0.05100"},{"Season":"2","Day":"3","Hour":"9","Value":"0.05043"},{"Season":"2","Day":"3","Hour":"10","Value":"0.04898"},{"Season":"2","Day":"3","Hour":"11","Value":"0.04943"},{"Season":"2","Day":"3","Hour":"12","Value":"0.05549"},{"Season":"2","Day":"3","Hour":"13","Value":"0.05403"},{"Season":"2","Day":"3","Hour":"14","Value":"0.04703"},{"Season":"2","Day":"3","Hour":"15","Value":"0.04207"},{"Season":"2","Day":"3","Hour":"16","Value":"0.03938"},{"Season":"2","Day":"3","Hour":"17","Value":"0.04315"},{"Season":"2","Day":"3","Hour":"18","Value":"0.05373"},{"Season":"2","Day":"3","Hour":"19","Value":"0.06377"},{"Season":"2","Day":"3","Hour":"20","Value":"0.06234"},{"Season":"2","Day":"3","Hour":"21","Value":"0.05785"},{"Season":"2","Day":"3","Hour":"22","Value":"0.05034"},{"Season":"2","Day":"3","Hour":"23","Value":"0.03719"},{"Season":"2","Day":"4","Hour":"0","Value":"0.02470"},{"Season":"2","Day":"4","Hour":"1","Value":"0.01824"},{"Season":"2","Day":"4","Hour":"2","Value":"0.01642"},{"Season":"2","Day":"4","Hour":"3","Value":"0.01599"},{"Season":"2","Day":"4","Hour":"4","Value":"0.01634"},{"Season":"2","Day":"4","Hour":"5","Value":"0.01952"},{"Season":"2","Day":"4","Hour":"6","Value":"0.03447"},{"Season":"2","Day":"4","Hour":"7","Value":"0.04812"},{"Season":"2","Day":"4","Hour":"8","Value":"0.05100"},{"Season":"2","Day":"4","Hour":"9","Value":"0.05043"},{"Season":"2","Day":"4","Hour":"10","Value":"0.04898"},{"Season":"2","Day":"4","Hour":"11","Value":"0.04943"},{"Season":"2","Day":"4","Hour":"12","Value":"0.05549"},{"Season":"2","Day":"4","Hour":"13","Value":"0.05403"},{"Season":"2","Day":"4","Hour":"14","Value":"0.04703"},{"Season":"2","Day":"4","Hour":"15","Value":"0.04207"},{"Season":"2","Day":"4","Hour":"16","Value":"0.03938"},{"Season":"2","Day":"4","Hour":"17","Value":"0.04315"},{"Season":"2","Day":"4","Hour":"18","Value":"0.05373"},{"Season":"2","Day":"4","Hour":"19","Value":"0.06377"},{"Season":"2","Day":"4","Hour":"20","Value":"0.06234"},{"Season":"2","Day":"4","Hour":"21","Value":"0.05785"},{"Season":"2","Day":"4","Hour":"22","Value":"0.05034"},{"Season":"2","Day":"4","Hour":"23","Value":"0.03719"},{"Season":"2","Day":"5","Hour":"0","Value":"0.02427"},{"Season":"2","Day":"5","Hour":"1","Value":"0.01868"},{"Season":"2","Day":"5","Hour":"2","Value":"0.01541"},{"Season":"2","Day":"5","Hour":"3","Value":"0.01453"},{"Season":"2","Day":"5","Hour":"4","Value":"0.01432"},{"Season":"2","Day":"5","Hour":"5","Value":"0.01498"},{"Season":"2","Day":"5","Hour":"6","Value":"0.01944"},{"Season":"2","Day":"5","Hour":"7","Value":"0.03094"},{"Season":"2","Day":"5","Hour":"8","Value":"0.04303"},{"Season":"2","Day":"5","Hour":"9","Value":"0.04990"},{"Season":"2","Day":"5","Hour":"10","Value":"0.05418"},{"Season":"2","Day":"5","Hour":"11","Value":"0.05701"},{"Season":"2","Day":"5","Hour":"12","Value":"0.06018"},{"Season":"2","Day":"5","Hour":"13","Value":"0.05888"},{"Season":"2","Day":"5","Hour":"14","Value":"0.05351"},{"Season":"2","Day":"5","Hour":"15","Value":"0.04933"},{"Season":"2","Day":"5","Hour":"16","Value":"0.04862"},{"Season":"2","Day":"5","Hour":"17","Value":"0.05288"},{"Season":"2","Day":"5","Hour":"18","Value":"0.06081"},{"Season":"2","Day":"5","Hour":"19","Value":"0.06572"},{"Season":"2","Day":"5","Hour":"20","Value":"0.05985"},{"Season":"2","Day":"5","Hour":"21","Value":"0.04888"},{"Season":"2","Day":"5","Hour":"22","Value":"0.04598"},{"Season":"2","Day":"5","Hour":"23","Value":"0.03866"},{"Season":"2","Day":"6","Hour":"0","Value":"0.03043"},{"Season":"2","Day":"6","Hour":"1","Value":"0.02246"},{"Season":"2","Day":"6","Hour":"2","Value":"0.01765"},{"Season":"2","Day":"6","Hour":"3","Value":"0.01598"},{"Season":"2","Day":"6","Hour":"4","Value":"0.01559"},{"Season":"2","Day":"6","Hour":"5","Value":"0.01562"},{"Season":"2","Day":"6","Hour":"6","Value":"0.01651"},{"Season":"2","Day":"6","Hour":"7","Value":"0.02367"},{"Season":"2","Day":"6","Hour":"8","Value":"0.04016"},{"Season":"2","Day":"6","Hour":"9","Value":"0.05759"},{"Season":"2","Day":"6","Hour":"10","Value":"0.06682"},{"Season":"2","Day":"6","Hour":"11","Value":"0.07407"},{"Season":"2","Day":"6","Hour":"12","Value":"0.07502"},{"Season":"2","Day":"6","Hour":"13","Value":"0.06088"},{"Season":"2","Day":"6","Hour":"14","Value":"0.04919"},{"Season":"2","Day":"6","Hour":"15","Value":"0.04369"},{"Season":"2","Day":"6","Hour":"16","Value":"0.03874"},{"Season":"2","Day":"6","Hour":"17","Value":"0.04035"},{"Season":"2","Day":"6","Hour":"18","Value":"0.04966"},{"Season":"2","Day":"6","Hour":"19","Value":"0.05810"},{"Season":"2","Day":"6","Hour":"20","Value":"0.05587"},{"Season":"2","Day":"6","Hour":"21","Value":"0.05196"},{"Season":"2","Day":"6","Hour":"22","Value":"0.04608"},{"Season":"2","Day":"6","Hour":"23","Value":"0.03393"}] + def getFactor(season, day, hour): for dataset in data: if (int(dataset["Season"]) == season) and (int(dataset["Day"]) == day) and (int(dataset["Hour"]) == hour): return float(dataset["Value"]) - return 0 \ No newline at end of file + return 0 diff --git a/modules/et_awattarcap/main.sh b/modules/et_awattarcap/main.sh index 54ab8b38c..d0ad30fe1 100644 --- a/modules/et_awattarcap/main.sh +++ b/modules/et_awattarcap/main.sh @@ -1,15 +1,16 @@ #!/bin/bash -OPENWBBASEDIR=$(cd `dirname $0`/../../ && pwd) +OPENWBBASEDIR=$(cd "$(dirname "$0")/../../" && pwd) +MODULEDIR=$(cd "$(dirname "$0")" && pwd) # check if config file is already in env if [[ -z "$debug" ]]; then echo "et_awattar: seems like openwb.conf is not loaded. Reading file." # try to load config - . $OPENWBBASEDIR/loadconfig.sh + . "$OPENWBBASEDIR/loadconfig.sh" fi # abort if we try to use unset variables set -o nounset # call module -sudo python3 $OPENWBBASEDIR/modules/et_awattarcap/awattarcapgetprices.py $debug +sudo python3 "$MODULEDIR/awattarcapgetprices.py" "$debug" diff --git a/modules/soc_carnet/main.sh b/modules/soc_carnet/main.sh index db7a8003d..0ec0e3586 100755 --- a/modules/soc_carnet/main.sh +++ b/modules/soc_carnet/main.sh @@ -1,8 +1,8 @@ #!/bin/bash -OPENWBBASEDIR=$(cd `dirname $0`/../../ && pwd) +OPENWBBASEDIR=$(cd "$(dirname "$0")/../../" && pwd) RAMDISKDIR="$OPENWBBASEDIR/ramdisk" -MODULEDIR=$(cd `dirname $0` && pwd) +MODULEDIR=$(cd "$(dirname "$0")" && pwd) DMOD="EVSOC" CHARGEPOINT=$1 @@ -10,9 +10,9 @@ CHARGEPOINT=$1 if [[ -z "$debug" ]]; then echo "soc_carnet: Seems like openwb.conf is not loaded. Reading file." # try to load config - . $OPENWBBASEDIR/loadconfig.sh + . "$OPENWBBASEDIR/loadconfig.sh" # load helperFunctions - . $OPENWBBASEDIR/helperFunctions.sh + . "$OPENWBBASEDIR/helperFunctions.sh" fi case $CHARGEPOINT in @@ -57,32 +57,32 @@ incrementTimer(){ ticksize=1 ;; esac - soctimer=$((soctimer+$ticksize)) - echo $soctimer > $soctimerfile + soctimer=$((soctimer + ticksize)) + echo $soctimer > "$soctimerfile" } -soctimer=$(<$soctimerfile) +soctimer=$(<"$soctimerfile") openwbDebugLog ${DMOD} 1 "Lp$CHARGEPOINT: timer = $soctimer" if (( soctimer < 60 )); then - openwbDebugLog ${DMOD} 1 "Lp$CHARGEPOINT: Nothing to do yet. Incrementing timer." + openwbDebugLog ${DMOD} 2 "Lp$CHARGEPOINT: Nothing to do yet. Incrementing timer." incrementTimer else openwbDebugLog ${DMOD} 1 "Lp$CHARGEPOINT: Requesting SoC" #Abfrage Ladung aktiv. Hochsetzen des soctimers, um das Intervall zu verkürzen. if (( ladeleistung > 800 )) ; then - soctimer=$((60 * (10 - $intervall) / 10)) - echo $soctimer > $soctimerfile + soctimer=$((60 * (10 - intervall) / 10)) + echo $soctimer > "$soctimerfile" else - echo 0 > $soctimerfile + echo 0 > "$soctimerfile" fi - response=$(sudo PYTHONIOENCODING=UTF-8 python $MODULEDIR/we_connect_client.py --user="$username" --password="$password") + response=$(sudo PYTHONIOENCODING=UTF-8 python "$MODULEDIR/we_connect_client.py" --user="$username" --password="$password") soclevel=$(echo "$response" | grep batteryPercentage | jq -r .EManager.rbc.status.batteryPercentage) openwbDebugLog ${DMOD} 1 "Lp$CHARGEPOINT: Filtered SoC from Server: $soclevel" if [[ $soclevel =~ $reValidSoc ]] ; then - if (( $soclevel != 0 )) ; then + if (( soclevel != 0 )) ; then openwbDebugLog ${DMOD} 1 "Lp$CHARGEPOINT: SoC is valid" - echo $soclevel > $socfile + echo "$soclevel" > "$socfile" fi else openwbDebugLog ${DMOD} 0 "Lp$CHARGEPOINT: SoC is not valid." diff --git a/modules/soc_carnet/we_connect_client.py b/modules/soc_carnet/we_connect_client.py index 7d54c1db7..7f87fc335 100755 --- a/modules/soc_carnet/we_connect_client.py +++ b/modules/soc_carnet/we_connect_client.py @@ -21,16 +21,18 @@ # V2.0 for new VW WE Connect portal thanks to youpixel - 2019-07-26 # Thanks to birgersp for a number of cleanups and rewrites. See https://github.com/birgersp/carnet-client +import argparse +import logging +import urllib3 +import sys +import json +import requests +import re debug = False certverify = False -import re -import requests -import json -import sys -import urllib3 # import correct lib for python v3.x or fallback to v2.x -try: +try: import urllib.parse as urlparse except ImportError: # Python 2 @@ -42,9 +44,7 @@ except ImportError: # Python 2 import httplib as http_client -import logging # ---- end uncomment -import argparse portal_base_url = 'https://www.portal.volkswagen-we.com' @@ -64,6 +64,7 @@ def remove_newline_chars(string): return string.replace('\n', '').replace('\r', '') + def extract_csrf(string): # Get value from HTML head _csrf meta tag. try: @@ -73,6 +74,7 @@ def extract_csrf(string): resp = '' return resp + def extract_login_hmac(string): # Get hmac value from html input form. try: @@ -92,6 +94,7 @@ def extract_login_csrf(string): resp = '' return resp + def extract_url_parameter(url, cmnd): # Get parameter value from url. try: @@ -108,7 +111,8 @@ def CarNetLogin(session, email, password): auth_base_url = 'https://identity.vwgroup.io' # Step 1 - if debug: print ("Step 1 ===========") + if debug: + print("Step 1 ===========") # Get initial CSRF from landing page to get login process started. # Python Session handles JSESSIONID cookie landing_page_url = base_url + '/portal/en_GB/web/guest/home' @@ -118,13 +122,15 @@ def CarNetLogin(session, email, password): csrf = extract_csrf(landing_page_response.text) if csrf == '': return '', 'Failed to get CSRF from landing page.' - if debug: print("_csrf from landing page : ", csrf) + if debug: + print("_csrf from landing page : ", csrf) # Step 1a,1b # Note: Portal performs a get-supported-browsers and get-countries at this point. We assumed en_GB - + # Step 2 - if debug: print ("Step 2 ===========") + if debug: + print("Step 2 ===========") # Get login page url. POST returns JSON with loginURL for next step. # returned loginURL includes client_id for step 4 auth_request_headers = { @@ -144,12 +150,14 @@ def CarNetLogin(session, email, password): return '', 'Failed to get login url.' login_url = json.loads(login_page_response.text).get('loginURL').get('path') client_id = extract_url_parameter(login_url, 'client_id') - if debug: print ("client_id found: ", client_id) + if debug: + print("client_id found: ", client_id) if client_id == '': return '', 'Failed to get client_id.' # Step 3 - if debug: print ("Step 3 ===========") + if debug: + print("Step 3 ===========") # Get login form url we are told to use, it will give us a new location. # response header location (redirect URL) includes relayState for step 5 # https://identity.vwgroup.io/oidc/v1/authorize...... @@ -158,12 +166,14 @@ def CarNetLogin(session, email, password): return '', 'Failed to get authorization page.' login_form_url = login_url_response.headers.get('location') login_relay_state_token = extract_url_parameter(login_form_url, 'relayState') - if debug: print ("relayState found: ", login_relay_state_token) + if debug: + print("relayState found: ", login_relay_state_token) if login_relay_state_token == '': return '', 'Failed to get relay State.' # Step 4 - if debug: print ("Step 4 ===========") + if debug: + print("Step 4 ===========") # Get login action url, relay state. hmac token 1 and login CSRF from form contents # https://identity.vwgroup.io/signin-service/v1/signin/@relayState= login_form_location_response = session.get(login_form_url, headers=auth_request_headers, verify=certverify) @@ -174,15 +184,18 @@ def CarNetLogin(session, email, password): login_form_location_response_data = remove_newline_chars(login_form_location_response.text) hmac_token1 = extract_login_hmac(login_form_location_response_data) login_csrf = extract_login_csrf(login_form_location_response_data) - if debug: print ("login_csrf found: ", login_csrf) - if debug: print ("hmac_token1 found: ", hmac_token1) + if debug: + print("login_csrf found: ", login_csrf) + if debug: + print("hmac_token1 found: ", hmac_token1) if login_csrf == '': return '', 'Failed to get login CSRF.' if hmac_token1 == '': return '', 'Failed to get 1st HMAC token.' # Step 5 - if debug: print ("Step 5 ===========") + if debug: + print("Step 5 ===========") # Post initial login data # https://identity.vwgroup.io/signin-service/v1//login/identifier del auth_request_headers['X-CSRF-Token'] @@ -195,7 +208,8 @@ def CarNetLogin(session, email, password): '_csrf': login_csrf, } login_action_url = auth_base_url + '/signin-service/v1/' + client_id + '/login/identifier' - login_action_url_response = session.post(login_action_url, data=post_data, headers=auth_request_headers, allow_redirects=True, verify=certverify) + login_action_url_response = session.post(login_action_url, data=post_data, + headers=auth_request_headers, allow_redirects=True, verify=certverify) # performs a 303 redirect to https://identity.vwgroup.io/signin-service/v1//login/authenticate?relayState=&email= # redirected GET returns form used below. if login_action_url_response.status_code != 200: @@ -203,14 +217,16 @@ def CarNetLogin(session, email, password): # Get 2nd hmac token from form content. login_action_url_response_data = remove_newline_chars(login_action_url_response.text) hmac_token2 = extract_login_hmac(login_action_url_response_data) - if debug: print ("hmac_token2 found: ", hmac_token2) + if debug: + print("hmac_token2 found: ", hmac_token2) if hmac_token2 == '': return '', 'Failed to get 2nd HMAC token.' # Step 6 - if debug: print ("Step 6 ===========") + if debug: + print("Step 6 ===========") # Post login data to "login action 2" url - # https://identity.vwgroup.io/signin-service/v1//login/authenticate + # https://identity.vwgroup.io/signin-service/v1//login/authenticate auth_request_headers['Referer'] = login_action_url auth_request_headers['Content-Type'] = 'application/x-www-form-urlencoded' login_data = { @@ -222,38 +238,44 @@ def CarNetLogin(session, email, password): 'login': 'true' } login_action2_url = auth_base_url + '/signin-service/v1/' + client_id + '/login/authenticate' - login_post_response = session.post(login_action2_url, data=login_data, headers=auth_request_headers, allow_redirects=True, verify=certverify) + login_post_response = session.post(login_action2_url, data=login_data, + headers=auth_request_headers, allow_redirects=True, verify=certverify) # performs a 302 redirect to GET https://identity.vwgroup.io/oidc/v1/oauth/sso?clientId=&relayState=&userId=&HMAC=<...>" # then a 302 redirect to GET https://identity.vwgroup.io/consent/v1/users//?scopes=openid%20profile%20birthdate%20nickname%20address%20email%20phone%20cars%20dealers%20mbb&relay_state=1bc582f3ff177afde55b590af92e17a006f9c532&callback=https://identity.vwgroup.io/oidc/v1/oauth/client/callback&hmac=<.....> # then a 302 redirect to https://identity.vwgroup.io/oidc/v1/oauth/client/callback/success?user_id=&client_id=&scopes=openid%20profile%20birthdate%20nickname%20address%20email%20phone%20cars%20dealers%20mbb&consentedScopes=openid%20profile%20birthdate%20nickname%20address%20email%20phone%20cars%20dealers%20mbb&relay_state=&hmac=<...> # then a 302 redirect to https://www.portal.volkswagen-we.com/portal/web/guest/complete-login?state=&code=<....> if login_post_response.status_code != 200: return '', 'Failed to process login sequence.' - #ref2_url = login_post_response.headers.get('location') # there is no location attribute, but does not seem to matter much. - ref2_url = login_post_response.url + # ref2_url = login_post_response.headers.get('location') # there is no location attribute, but does not seem to matter much. + ref2_url = login_post_response.url portlet_code = extract_url_parameter(ref2_url, 'code') state = extract_url_parameter(ref2_url, 'state') - if debug: print ("state found: ", state) + if debug: + print("state found: ", state) if portlet_code == '': return '', 'Failed to get portlet code.' if state == '': return '', 'Failed to get state.' # Step 7 - if debug: print ("Step 7 ===========") + if debug: + print("Step 7 ===========") # Site first does a POST https://www.portal.volkswagen-we.com/portal/web/guest/complete-login/-/mainnavigation/get-countries # Post login data to complete login url # https://www.portal.volkswagen-we.com/portal/web/guest/complete-login?p_auth=&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 auth_request_headers['Referer'] = ref2_url portlet_data = {'_33_WAR_cored5portlet_code': portlet_code} - final_login_url = base_url + '/portal/web/guest/complete-login?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' - complete_login_response = session.post(final_login_url, data=portlet_data, allow_redirects=False, headers=auth_request_headers, verify=certverify) + final_login_url = base_url + '/portal/web/guest/complete-login?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' + complete_login_response = session.post(final_login_url, data=portlet_data, + allow_redirects=False, headers=auth_request_headers, verify=certverify) if complete_login_response.status_code != 302: return '', 'Failed to post portlet page.' # Step 8 - if debug: print ("Step 8 ===========") - # Get base JSON url for commands + if debug: + print("Step 8 ===========") + # Get base JSON url for commands base_json_url = complete_login_response.headers.get('location') base_json_response = session.get(base_json_url, headers=auth_request_headers, verify=certverify) csrf = extract_csrf(base_json_response.text) @@ -263,8 +285,10 @@ def CarNetLogin(session, email, password): return '', 'Failed to get final CSRF.' request_headers['Referer'] = base_json_url request_headers['X-CSRF-Token'] = csrf - if debug: print('login csrf token: ',csrf) - if debug: print('login base json url: ',base_json_url) + if debug: + print('login csrf token: ', csrf) + if debug: + print('login base json url: ', base_json_url) print('=== login complete ===') return base_json_url, 'OK' @@ -280,10 +304,11 @@ def CarNetPostAction(session, url_base, command, data): r = session.post(url_base + command, json=data, headers=request_headers, verify=certverify) return r.text + def CarNetCheckSecurityLevel(session, url_base, data): print('Check security level for: ' + data.get('operationId')) cc = session.cookies['GUEST_LANGUAGE_ID'] - if cc: + if cc: if (len(cc) == 5): cc = cc[3:5] cc = cc.lower() @@ -294,13 +319,13 @@ def CarNetCheckSecurityLevel(session, url_base, data): url = portal_base_url + '/portal/group/' + cc + '/edit-profile/-/profile/check-security-level' response = session.post(url, json=data, headers=request_headers, verify=certverify) if response.status_code != 200: - return false, 'Check security failed, HTTP response ' + response.status_code + return False, 'Check security failed, HTTP response ' + response.status_code json_data = response.json() errCd = json_data['errorCode'] if errCd == "0": - return True, 'You are authorized for PIN action' + return True, 'You are authorized for PIN action' if errCd == "1" or errCd == "2": - return False, 'You are not authorized for PIN action' + return False, 'You are not authorized for PIN action' return False, 'Check security failed' @@ -311,8 +336,8 @@ def retrieveCarNetInfo(session, url_base): print(response) # Resp ex: {"errorCode":"0","fullyLoadedVehiclesResponse":{"completeVehicles":[],"vehiclesNotFullyLoaded":[{"vin":"WVWZZZAUZGWxxxxxx","name":"GTE Dhr Boer","expired":false,"model":null,"modelCode":null,"modelYear":null,"imageUrl":null,"vehicleSpecificFallbackImageUrl":null,"modelSpecificFallbackImageUrl":null,"defaultImageUrl":"/portal/delegate/vehicle-image/WVWZZZAUZGWxxxxx","vehicleBrand":"v","enrollmentDate":"20160923","deviceOCU1":null,"deviceOCU2":null,"deviceMIB":null,"engineTypeCombustian":false,"engineTypeHybridOCU1":true,"engineTypeHybridOCU2":false,"engineTypeElectric":false,"engineTypeCNG":false,"engineTypeDefault":false,"stpStatus":"UNAVAILABLE","windowstateSupported":true,"dashboardUrl":"/portal/user/55e2ea85-2a5c-46c4-bb0b-f0cde8bcf22e/v_c5rlgqwltznnz_l-k7dfv5l1vxyuyxuz","vhrRequested":false,"vsrRequested":false,"vhrConfigAvailable":false,"verifiedByDealer":false,"vhr2":false,"roleEnabled":true,"isEL2Vehicle":true,"workshopMode":false,"hiddenUserProfiles":false,"mobileKeyActivated":null,"enrollmentType":"MILEAGE","ocu3Low":false,"packageServices":[{"packageServiceId":"NET.500.010.F","propertyKeyReference":"NET.500.010.1","packageServiceName":"e-Remote","trackingName":"e-Remote","activationDate":"03-11-2015","expirationDate":"03-11-2020","expired":false,"expireInAMonth":false,"packageType":"er","enrollmentPackageType":"er"}],"defaultCar":true,"vwConnectPowerLayerAvailable":false,"xprofileId":"c5rlgqwltznnz_l-k7dfv5l1vxyuyxuz","smartCardKeyActivated":null,"fullyEnrolled":true,"secondaryUser":false,"fleet":false,"touareg":false,"iceSupported":false,"flightMode":false,"esimCompatible":false,"dkyenabled":false,"selected":true}],"status":"VALID","currentVehicleValid":true}} vin = json.loads(response).get('fullyLoadedVehiclesResponse').get('vehiclesNotFullyLoaded')[0].get('vin') - print('found vin: ',vin) - + print('found vin: ', vin) + # Check on invitations of some kind. print(CarNetPost(session, url_base, '/-/mainnavigation/check-unanswered-invitations')) # Resp ex: {"checkUnansweredInvitationsResponse":{"hasUnansweredInvitations":false},"errorCode":"0"} @@ -321,15 +346,15 @@ def retrieveCarNetInfo(session, url_base): post_data = { "timeZoneId": "Europe/Amsterdam" } - #print(CarNetPostAction(session, url_base, '/-/mainnavigation/set-time-zone', post_data)) + # print(CarNetPostAction(session, url_base, '/-/mainnavigation/set-time-zone', post_data)) # Resp ex: {"errorCode":"0"} - + # Get the car last reported location print(CarNetPost(session, url_base, '/-/cf/get-location')) # Resp ex: {"errorCode":"0","position":{"lat":52.xxxx,"lng":4.xxxx}} - + # get shutdown (no idea) - #print(CarNetPost(session, url_base, '-/mainnavigation/get-shutdown')) + # print(CarNetPost(session, url_base, '-/mainnavigation/get-shutdown')) # Resp ex: {"getShutdownResponse":{"enabled":false,"finalEnabled":false,"finalDate":null,"portalRedirect":null,"iosRedirect":null,"androidRedirect":null,"hideShutdownPromotion":false},"errorCode":"0"} # Get the latest messages from the car. Includes oil change etc. @@ -337,7 +362,7 @@ def retrieveCarNetInfo(session, url_base): # Resp ex: {"messageList":[],"errorCode":"0"} # Get some stuff if you have apple - #print(CarNetPost(session, url_base, '/-/service-container/get-apple-music-status')) + # print(CarNetPost(session, url_base, '/-/service-container/get-apple-music-status')) # Resp ex: {"errorCode":"0","appleMusicStatusResponse":{"showAppleMusic":false,"appleMenu":null}} # Get the web site navigation config. @@ -349,7 +374,7 @@ def retrieveCarNetInfo(session, url_base): # Resp ex: {"errorCode":"0","completeVehicleJson":{"vin":"WVWZZZAUZGWxxxx","name":"GTE Dhr Boer","expired":false,"model":"Golf","modelCode":"5G16YY","modelYear":"2016","imageUrl":null,"vehicleSpecificFallbackImageUrl":null,"modelSpecificFallbackImageUrl":null,"defaultImageUrl":"/portal/delegate/vehicle-image/WVWZZZAUZGWxxxxx","vehicleBrand":"v","enrollmentDate":"20160923","deviceOCU1":true,"deviceOCU2":false,"deviceMIB":false,"engineTypeCombustian":false,"engineTypeHybridOCU1":true,"engineTypeHybridOCU2":false,"engineTypeElectric":false,"engineTypeCNG":false,"engineTypeDefault":false,"stpStatus":"UNAVAILABLE","windowstateSupported":true,"dashboardUrl":"/portal/user/55e2ea85-2a5c-46c4-bb0b-f0cde8bcf22e/v_c5rlgqwltznnz_l-k7dfv5l1vxyuyxuz","vhrRequested":false,"vsrRequested":false,"vhrConfigAvailable":false,"verifiedByDealer":false,"vhr2":false,"roleEnabled":true,"isEL2Vehicle":true,"workshopMode":false,"hiddenUserProfiles":false,"mobileKeyActivated":null,"enrollmentType":"MILEAGE","ocu3Low":false,"packageServices":[{"packageServiceId":"NET.500.010.F","propertyKeyReference":"NET.500.010.1","packageServiceName":"e-Remote","trackingName":"e-Remote","activationDate":"03-11-2015","expirationDate":"03-11-2020","expired":false,"expireInAMonth":false,"packageType":"er","enrollmentPackageType":"er"}],"defaultCar":true,"vwConnectPowerLayerAvailable":false,"xprofileId":"c5rlgqwltznnz_l-k7dfv5l1vxyuyxuz","smartCardKeyActivated":null,"fullyEnrolled":true,"secondaryUser":false,"fleet":false,"touareg":false,"iceSupported":false,"flightMode":false,"esimCompatible":false,"dkyenabled":false,"selected":true}} # get psp status (no idea what it is) - #print(CarNetPost(session, url_base, '/-/mainnavigation/get-psp-status')) + # print(CarNetPost(session, url_base, '/-/mainnavigation/get-psp-status')) # Resp ex: {"errorCode":"0","pspStatusResponse":{"reminderStatus":false,"deleteStatus":false}} # Get vehicle maintenance data @@ -372,7 +397,7 @@ def retrieveCarNetInfo(session, url_base): post_data = { 'vehicleBrand': 'v' } - #print(CarNetPostAction(session, url_base, '/-/mainnavigation/get-preferred-dealer', post_data)) + # print(CarNetPostAction(session, url_base, '/-/mainnavigation/get-preferred-dealer', post_data)) # Resp ex: {"errorCode":"0","preferredDealerResponse":{"dealer":{"id":"00842","name":"Autobedrijf J. Maas Woerden B.V.","address":" Botnische Golf 22 WOERDEN 3446 CN","addressParts":{"houseNumber":"","streetPrefix":"","street":"Botnische Golf 22","state":"","city":"WOERDEN","postalCode":"3446 CN"},"position":{"lat":52.0733438,"lng":4.9031345},"brand":"V","phoneNumber":"088-0207600","services":["SERVICE"],"openingHours":[]},"dssAvailable":true,"stwAvailableForMarketAndBrand":false,"stwAvailableForPsp":false,"appointmentSchedulingSupported":false}} # Poll for new information as log as desired. @@ -382,6 +407,7 @@ def retrieveCarNetInfo(session, url_base): # Obsolete request: print(CarNetPost(session, url_base, '/-/vsr/request-vsr')) return 0 + def startCharge(session, url_base): post_data = { 'triggerAction': True, @@ -399,14 +425,16 @@ def stopCharge(session, url_base): print(CarNetPostAction(session, url_base, '/-/emanager/charge-battery', post_data)) return 0 + def getCharge(session, url_base): try: estat = json.loads(CarNetPost(session, url_base, '/-/emanager/get-emanager')) print('{"errorCode":"0","chargingState":"' + estat.get('EManager').get('rbc').get('status').get('chargingState') + '"}') except: - print('{"errorCode":"2","errorMsg":"Failed to get currect charging state"}') + print('{"errorCode":"2","errorMsg":"Failed to get currect charging state"}') return 0 + def startClimat(session, url_base): post_data = { 'triggerAction': True, @@ -424,28 +452,32 @@ def stopClimat(session, url_base): print(CarNetPostAction(session, url_base, '/-/emanager/trigger-climatisation', post_data)) return 0 + def getClimat(session, url_base): try: estat = json.loads(CarNetPost(session, url_base, '/-/emanager/get-emanager')) - print('{"errorCode":"0","climatisationState":"' + estat.get('EManager').get('rpc').get('status').get('climatisationState') + '"}') + print('{"errorCode":"0","climatisationState":"' + + estat.get('EManager').get('rpc').get('status').get('climatisationState') + '"}') except: - print('{"errorCode":"2","errorMsg":"Failed to get current climate state"}') + print('{"errorCode":"2","errorMsg":"Failed to get current climate state"}') return 0 + def getVIN(session, url_base, index): try: estat = json.loads(CarNetPost(session, url_base, '/-/mainnavigation/get-fully-loaded-cars')) - resp = { - 'errorCode': '0', - 'vin': estat.get('fullyLoadedVehiclesResponse').get('vehiclesNotFullyLoaded')[index].get('vin') + resp = { + 'errorCode': '0', + 'vin': estat.get('fullyLoadedVehiclesResponse').get('vehiclesNotFullyLoaded')[index].get('vin') } except: resp = { 'errorCode': '2', 'errorMsg': 'Failed to get VIN for index ' + index - } + } return resp + def startWindowMelt(session, url_base): post_data = { 'triggerAction': True @@ -461,109 +493,124 @@ def stopWindowMelt(session, url_base): print(CarNetPostAction(session, url_base, '/-/emanager/trigger-windowheating', post_data)) return 0 + def getWindowMelt(session, url_base): try: estat = json.loads(CarNetPost(session, url_base, '/-/emanager/get-emanager')) status = estat.get('EManager').get('rpc').get('status') - print('{"errorCode":"0","windowHeatingStateFront":"' + status.get('windowHeatingStateFront') + '","windowHeatingStateRear":"' + status.get('windowHeatingStateRear') + '"}') + print('{"errorCode":"0","windowHeatingStateFront":"' + status.get('windowHeatingStateFront') + + '","windowHeatingStateRear":"' + status.get('windowHeatingStateRear') + '"}') except: - print('{"errorCode":"2","errorMsg":"Failed to get currect windows melt state"}') + print('{"errorCode":"2","errorMsg":"Failed to get currect windows melt state"}') return 0 + def remoteLock(session, url_base, spin, vin): post_data = { - 'vin': vin, + 'vin': vin, 'operationId': 'LOCK', - 'serviceId': 'rlu_v1' } + 'serviceId': 'rlu_v1'} res, msg = CarNetCheckSecurityLevel(session, url_base, post_data) if res: post_data = { - 'spin': str(spin) } + 'spin': str(spin)} print(CarNetPostAction(session, url_base, '/-/vsr/remote-lock', post_data)) - else: + else: print(msg) return 0 + def remoteUnlock(session, url_base, spin, vin): post_data = { - 'vin': vin, + 'vin': vin, 'operationId': 'UNLOCK', - 'serviceId': 'rlu_v1' } + 'serviceId': 'rlu_v1'} res, msg = CarNetCheckSecurityLevel(session, url_base, post_data) if res: post_data = { - 'spin': str(spin) } + 'spin': str(spin)} print(CarNetPostAction(session, url_base, '/-/vsr/remote-unlock', post_data)) - else: + else: print(msg) return 0 + def startRemoteAccessVentilation(session, url_base, spin, vin): post_data = { - 'vin': vin, - 'operationId':'P_QSACT', - 'serviceId':'rheating_v1' } + 'vin': vin, + 'operationId': 'P_QSACT', + 'serviceId': 'rheating_v1'} res, msg = CarNetCheckSecurityLevel(session, url_base, post_data) if res: post_data = { - 'startMode':'VENTILATION', - 'spin': str(spin) } + 'startMode': 'VENTILATION', + 'spin': str(spin)} print(CarNetPostAction(session, url_base, '/-/rah/quick-start', post_data)) - else: + else: print(msg) return 0 + def stopRemoteAccessVentilation(session, url_base): print(CarNetPost(session, url_base, '/-/rah/quick-stop')) return 0 + def startRemoteAccessHeating(session, url_base, spin, vin): post_data = { - 'vin': vin, - 'operationId':'P_QSACT', - 'serviceId':'rheating_v1' } + 'vin': vin, + 'operationId': 'P_QSACT', + 'serviceId': 'rheating_v1'} res, msg = CarNetCheckSecurityLevel(session, url_base, post_data) if res: post_data = { - 'startMode':'HEATING', - 'spin': str(spin) } + 'startMode': 'HEATING', + 'spin': str(spin)} print(CarNetPostAction(session, url_base, '/-/rah/quick-start', post_data)) - else: + else: print(msg) return 0 + def stopRemoteAccessHeating(session, url_base): print(CarNetPost(session, url_base, '/-/rah/quick-stop')) return 0 + def getRemoteAccessHeating(session, url_base): print(CarNetPost(session, url_base, '/-/rah/get-status')) return 0 + def getLatestReport(session, url_base): print(CarNetPost(session, url_base, '/-/vhr/get-latest-report')) return 0 + def getAlerts(session, url_base): print(CarNetPost(session, url_base, '/-/rsa/get-alerts')) return 0 + def getGeofences(session, url_base): print(CarNetPost(session, url_base, '/-/geofence/get-fences')) return 0 + if __name__ == '__main__': # parse arguments parser = argparse.ArgumentParser(description='Control your Connected VW.') parser.add_argument('-u', '--user', required=True, help='Your WE-Connect user id.') parser.add_argument('-p', '--password', required=True, help='Your WE-Connect password.') parser.add_argument('-v', '--vin', help='Your car VIN if more cars on account.') - parser.add_argument('-c', '--command', choices=['startCharge', 'stopCharge', 'getCharge', 'startClimate', 'stopClimate', 'getClimate', 'startWindowMelt', 'stopWindowMelt','getWindowMelt', 'getVIN', 'remoteLock', 'remoteUnlock', 'startRemoteVentilation', 'stopRemoteVentilation', 'startRemoteHeating', 'stopRemoteHeating', 'getRemoteHeating', 'getLatestReport', 'getAlerts', 'getGeofences'], help='Command to send.') + parser.add_argument('-c', '--command', choices=['startCharge', 'stopCharge', 'getCharge', 'startClimate', 'stopClimate', 'getClimate', 'startWindowMelt', 'stopWindowMelt', 'getWindowMelt', 'getVIN', 'remoteLock', + 'remoteUnlock', 'startRemoteVentilation', 'stopRemoteVentilation', 'startRemoteHeating', 'stopRemoteHeating', 'getRemoteHeating', 'getLatestReport', 'getAlerts', 'getGeofences'], help='Command to send.') parser.add_argument('-s', '--spin', help='Your WE-Connect s-pin needed for some commands.') - parser.add_argument('-i', '--index', type=int, default=0, choices=range(0, 10), help='To get the VIN for the N-th car.') + parser.add_argument('-i', '--index', type=int, default=0, choices=range(0, 10), + help='To get the VIN for the N-th car.') parser.add_argument('-d', '--debug', action="store_true", help='Show debug commands.') args = parser.parse_args() CARNET_USERNAME = args.user @@ -576,8 +623,7 @@ def getGeofences(session, url_base): if args.debug: debug = True - - # Enable debugging of http requests (gives more details on Python 2 than 3 it seems) + # Enable debugging of http requests (gives more details on Python 2 than 3 it seems) if debug: http_client.HTTPConnection.debuglevel = 1 logging.basicConfig() @@ -587,8 +633,8 @@ def getGeofences(session, url_base): requests_log.propagate = True else: if not certverify: - urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) - + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + session = requests.Session() # Get list of browsers the site can support # print(CarNetPost(session, portal_base_url + '/portal/en_GB/web/guest/home', '/-/mainnavigation/get-supported-browsers')) @@ -596,28 +642,30 @@ def getGeofences(session, url_base): # Get list of countries the site can support # print(CarNetPost(session, portal_base_url + '/portal/en_GB/web/guest/home', '/-/mainnavigation/get-countries')) - # Resp ex: {"errorCode":"0", long list with supported countries} + # Resp ex: {"errorCode":"0", long list with supported countries} url, msg = CarNetLogin(session, CARNET_USERNAME, CARNET_PASSWORD) if url == '': print('Failed to login', msg) sys.exit() - - # If a VIN is specified, put that in the base URL so more than just first car can be controlled + + # If a VIN is specified, put that in the base URL so more than just first car can be controlled if CARNET_VIN: - vin_start = url.rfind('/',1,-2) + vin_start = url.rfind('/', 1, -2) url = url[0:vin_start+1] + CARNET_VIN + '/' else: resp = getVIN(session, url, args.index) CARNET_VIN = resp.get('vin') - - if debug: print('Using VIN : ' + CARNET_VIN) - + + if debug: + print('Using VIN : ' + CARNET_VIN) + # We need to load a car is spin commands are used if CARNET_SPIN: response = CarNetPost(session, url, '/-/mainnavigation/load-car-details/' + CARNET_VIN) - if debug: print(response) - + if debug: + print(response) + if CARNET_COMMAND == 'startCharge': startCharge(session, url) elif CARNET_COMMAND == 'stopCharge': @@ -664,25 +712,25 @@ def getGeofences(session, url_base): # Below is the flow the web app is using to determine when action really started # You should look at the notifications until it returns a status JSON like this # {"errorCode":"0","actionNotificationList":[{"actionState":"SUCCEEDED","actionType":"STOP","serviceType":"RBC","errorTitle":null,"errorMessage":null}]} - #print(CarNetPost(session, url, '/-/msgc/get-new-messages')) - #print(CarNetPost(session, url, '/-/emanager/get-notifications')) - #print(CarNetPost(session, url, '/-/emanager/get-emanager')) - + # print(CarNetPost(session, url, '/-/msgc/get-new-messages')) + # print(CarNetPost(session, url, '/-/emanager/get-notifications')) + # print(CarNetPost(session, url, '/-/emanager/get-emanager')) + # Get the remote heating request status # After start / stop command it will first report in progress # {"rahRequestStatus":{"state":"REQUEST_IN_PROGRESS"},"errorCode":"0"} # You should look at the notifications until it returns the JSON like this # {"rahRequestStatus":{"state":"REQUEST_SUCCESSFUL"},"errorCode":"0"} - #print(CarNetPost(session, url, '/-/rah/get-request-status')) + # print(CarNetPost(session, url, '/-/rah/get-request-status')) # Get the remote lock/unlock status # After lock / unlock command it will first report in progress # {"errorCode":"0","rluRequestStatus":{"status":"REQUEST_IN_PROGRESS","resultData":null}} # You should look at the notifications until it returns the JSON like this # {"rahRequestStatus":{"state":"REQUEST_SUCCESSFUL"},"errorCode":"0"} - #print(CarNetPost(session, url, '/-/vsr/get-request-status')) - + # print(CarNetPost(session, url, '/-/vsr/get-request-status')) + # End session properly response = CarNetPost(session, url, '/-/logout/revoke') - if debug: print(response) - + if debug: + print(response) diff --git a/modules/soc_kia/abrp.py b/modules/soc_kia/abrp.py index 1e4048d20..bb17d6568 100644 --- a/modules/soc_kia/abrp.py +++ b/modules/soc_kia/abrp.py @@ -6,21 +6,23 @@ import soclogging + def pushABRP(soc): now = int(time.time()) apiKey = "49589dbf-37a8-4c22-a49c-7d62fe1a6531" userTokenArray = parameters.getParameter('abrpToken').split(';') - + soclogging.logDebug(2, "Submitting ABRP-Data") - + for userToken in userTokenArray: - url = "https://api.iternio.com/1/tlm/send?api_key=" + requests.utils.quote(apiKey) + "&token=" + requests.utils.quote(userToken) + url = "https://api.iternio.com/1/tlm/send?api_key=" + \ + requests.utils.quote(apiKey) + "&token=" + requests.utils.quote(userToken) data = {'tlm': {'utc': now, 'soc': soc, 'is_charging': state.isCharging()}} - + try: f = open(parameters.getParameter('auxDataFile'), 'r') auxData = json.loads(f.read()) - f.close() + f.close() data['tlm']['odometer'] = auxData['odometer']['value'] data['tlm']['lat'] = auxData['vehicleLocation']['coord']['lat'] data['tlm']['lon'] = auxData['vehicleLocation']['coord']['lon'] @@ -28,17 +30,18 @@ def pushABRP(soc): data['tlm']['is_parked'] = auxData['vehicleStatus']['doorLock'] except: pass - + try: - response = requests.post(url, json = data) + response = requests.post(url, json=data) except requests.Timeout as err: soclogging.logDebug(1, "ABRP - Connection Timeout") pass except: soclogging.logDebug(1, "ABRP - HTTP Error") pass - + if response.status_code != 200: - soclogging.logDebug(1, 'ABRP - Request failed, StatusCode: ' + str(response.status_code) + ' - Error: '+ str(response.text)) - - return \ No newline at end of file + soclogging.logDebug(1, 'ABRP - Request failed, StatusCode: ' + + str(response.status_code) + ' - Error: ' + str(response.text)) + + return diff --git a/modules/soc_kia/kiaauth.py b/modules/soc_kia/kiaauth.py index c77ccc0f3..8538ba218 100644 --- a/modules/soc_kia/kiaauth.py +++ b/modules/soc_kia/kiaauth.py @@ -9,21 +9,23 @@ import kiahttp import stamps + def getUserHash(): try: account = parameters.getParameter('accountName') + ':' + parameters.getParameter('accountPassword') hash = hashlib.md5(account.encode()).hexdigest() except: raise - + return hash + def loadAccessToken(): try: f = open(parameters.getParameter('tokenFile'), 'r') tokenDict = json.loads(f.read()) f.close() - + parameters.setParameter('accessToken', tokenDict['accessToken']) parameters.setParameter('tokenType', tokenDict['tokenType']) parameters.setParameter('refreshToken', tokenDict['refreshToken']) @@ -33,39 +35,41 @@ def loadAccessToken(): parameters.setParameter('userHash', tokenDict['userHash']) else: raise - + except: parameters.setParameter('userHash', getUserHash()) raise - + except: raise - + return - + + def saveAccessToken(accessToken, deviceId): parameters.setParameter('accessToken', accessToken['access_token']) parameters.setParameter('tokenType', accessToken['token_type']) parameters.setParameter('refreshToken', accessToken['refresh_token']) parameters.setParameter('deviceId', deviceId) parameters.setParameter('userHash', getUserHash()) - + token = {} token['accessToken'] = accessToken['access_token'] token['tokenType'] = accessToken['token_type'] token['refreshToken'] = accessToken['refresh_token'] token['deviceId'] = deviceId token['userHash'] = getUserHash() - + f = open(parameters.getParameter('tokenFile'), 'w') f.write(json.dumps(token)) f.close() - + return - + + def refreshAccessToken(refreshToken): soclogging.logDebug(2, "Refreshing access token") - + url = parameters.getParameter('baseUrl') + '/api/v1/user/oauth2/token' data = 'grant_type=refresh_token&redirect_uri=https://www.getpostman.com/oauth2/callback&refresh_token=' + refreshToken headers = { @@ -78,10 +82,10 @@ def refreshAccessToken(refreshToken): 'User-Agent': 'okhttp/3.10.0'} try: - response = kiahttp.postHTTP(url = url, headers = headers, data = data, timeout = parameters.getParameter('reqTimeout')) + response = kiahttp.postHTTP(url=url, headers=headers, data=data, timeout=parameters.getParameter('reqTimeout')) except: raise - + try: accessToken = json.loads(response) accessToken['refresh_token'] = refreshToken @@ -89,11 +93,12 @@ def refreshAccessToken(refreshToken): soclogging.logDebug(0, "Token request failed, invalid response") soclogging.logDebug(2, response) raise - - soclogging.logDebug(2, "Access token = " + accessToken['access_token']) + + soclogging.logDebug(2, "Access token = " + accessToken['access_token']) return accessToken + def getDeviceId(): soclogging.logDebug(2, "Requesting DeviceId") @@ -110,10 +115,10 @@ def getDeviceId(): 'Stamp': stamps.getStamp()} try: - response = kiahttp.postHTTP(url = url, data = data, headers = headers, timeout = parameters.getParameter('reqTimeout')) + response = kiahttp.postHTTP(url=url, data=data, headers=headers, timeout=parameters.getParameter('reqTimeout')) except: raise - + try: responseDict = json.loads(response) deviceId = responseDict['resMsg']['deviceId'] @@ -121,16 +126,19 @@ def getDeviceId(): soclogging.logDebug(1, "Could not receive DeviceId, invalid response") soclogging.logDebug(2, response) raise - + soclogging.logDebug(2, "DeviceId = " + deviceId) - + return deviceId + def getCookies(): soclogging.logDebug(2, "Get cookies for login") - url = parameters.getParameter('baseUrl') + '/api/v1/user/oauth2/authorize?response_type=code&state=test&client_id=' + parameters.getParameter('clientId') + '&redirect_uri=' + parameters.getParameter('baseUrl') + '/api/v1/user/oauth2/redirect' - + url = parameters.getParameter('baseUrl') + '/api/v1/user/oauth2/authorize?response_type=code&state=test&client_id=' + \ + parameters.getParameter('clientId') + '&redirect_uri=' + \ + parameters.getParameter('baseUrl') + '/api/v1/user/oauth2/redirect' + try: cookies = kiahttp.getHTTPCookies(url) except: @@ -138,31 +146,35 @@ def getCookies(): return cookies + def setLanguage(cookies): soclogging.logDebug(2, "Setting language") - - url = parameters.getParameter('baseUrl') + '/api/v1/user/language' + + url = parameters.getParameter('baseUrl') + '/api/v1/user/language' headers = {'Content-type': 'application/json'} data = {"lang": "en"} - + try: - response = kiahttp.postHTTP(url = url, data = data, headers = headers, cookies = cookies, timeout = parameters.getParameter('reqTimeout')) + response = kiahttp.postHTTP(url=url, data=data, headers=headers, cookies=cookies, + timeout=parameters.getParameter('reqTimeout')) except: raise - + return + def getAuthCode(cookies): soclogging.logDebug(2, "Sending username/password") - url = parameters.getParameter('baseUrl') + '/api/v1/user/integrationinfo' + url = parameters.getParameter('baseUrl') + '/api/v1/user/integrationinfo' headers = {'Content-type': 'application/json'} - + try: - response = kiahttp.getHTTP(url = url, headers = headers, cookies = cookies, timeout = parameters.getParameter('reqTimeout')) + response = kiahttp.getHTTP(url=url, headers=headers, cookies=cookies, + timeout=parameters.getParameter('reqTimeout')) except: - raise - + raise + try: responseDict = json.loads(response) userId = responseDict['userId'] @@ -171,60 +183,67 @@ def getAuthCode(cookies): soclogging.logDebug(2, "ServiceId = " + serviceId) except: soclogging.logDebug(0, "Login failed, invalid response") - soclogging.logDebug(2, response) + soclogging.logDebug(2, response) raise - url = 'https://eu-account.' + parameters.getParameter('brand') + '.com/auth/realms/eu' + parameters.getParameter('brand') + 'idm/protocol/openid-connect/auth?client_id=' + parameters.getParameter('authClientId') + '&scope=openid%20profile%20email%20phone&response_type=code&hkid_session_reset=true&redirect_uri=' + parameters.getParameter('baseUrl') + '/api/v1/user/integration/redirect/login&ui_locales=en&state=' + serviceId + ':' + userId + url = 'https://eu-account.' + parameters.getParameter('brand') + '.com/auth/realms/eu' + parameters.getParameter('brand') + 'idm/protocol/openid-connect/auth?client_id=' + parameters.getParameter( + 'authClientId') + '&scope=openid%20profile%20email%20phone&response_type=code&hkid_session_reset=true&redirect_uri=' + parameters.getParameter('baseUrl') + '/api/v1/user/integration/redirect/login&ui_locales=en&state=' + serviceId + ':' + userId headers = {} try: - response = kiahttp.getHTTP(url = url, headers = headers, cookies = cookies, timeout = parameters.getParameter('reqTimeout')) + response = kiahttp.getHTTP(url=url, headers=headers, cookies=cookies, + timeout=parameters.getParameter('reqTimeout')) except: - raise - + raise + left = response.find('action="') + 8 right = response.find('"', left) url = response[left:right].replace('&', '&') - data = urlparse.urlencode({'username': parameters.getParameter('accountName'), 'password': parameters.getParameter('accountPassword'), 'credentialId': '', 'rememberMe': 'on'}) + data = urlparse.urlencode({'username': parameters.getParameter('accountName'), 'password': parameters.getParameter( + 'accountPassword'), 'credentialId': '', 'rememberMe': 'on'}) headers = { 'Content-type': 'application/x-www-form-urlencoded', 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_1 like Mac OS X) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0 Mobile/15B92 Safari/604.1'} cookiesForm = {'AUTH_SESSION_ID': kiahttp.lastCookies['AUTH_SESSION_ID']} - + try: - response = kiahttp.postHTTP(url = url, data = data, headers = headers, cookies = cookiesForm, timeout = parameters.getParameter('reqTimeout')) + response = kiahttp.postHTTP(url=url, data=data, headers=headers, cookies=cookiesForm, + timeout=parameters.getParameter('reqTimeout')) parsed = urlparse.urlparse(kiahttp.lastUrl) intUserId = ''.join(parse_qs(parsed.query)['intUserId']) - soclogging.logDebug(2, "intUserId = " + intUserId) + soclogging.logDebug(2, "intUserId = " + intUserId) except: soclogging.logDebug(0, "Login failed, invalid response") - soclogging.logDebug(2, response) + soclogging.logDebug(2, response) raise - - url = parameters.getParameter('baseUrl') + '/api/v1/user/silentsignin' + + url = parameters.getParameter('baseUrl') + '/api/v1/user/silentsignin' headers = {'Content-type': 'application/json'} data = {'intUserId': intUserId} - + try: - response = kiahttp.postHTTP(url = url, data = data, headers = headers, cookies = cookies, timeout = parameters.getParameter('reqTimeout'), allow_redirects = False) + response = kiahttp.postHTTP(url=url, data=data, headers=headers, cookies=cookies, + timeout=parameters.getParameter('reqTimeout'), allow_redirects=False) responseDict = json.loads(response) responseUrl = responseDict['redirectUrl'] parsed = urlparse.urlparse(responseUrl) - authCode = ''.join(parse_qs(parsed.query)['code']) + authCode = ''.join(parse_qs(parsed.query)['code']) except: soclogging.logDebug(0, "Login failed, invalid response") - soclogging.logDebug(2, response) + soclogging.logDebug(2, response) raise - + soclogging.logDebug(2, "AuthCode = " + authCode) - + return authCode + def getAuthToken(authCode): soclogging.logDebug(2, "Requesting access token") - + url = parameters.getParameter('baseUrl') + '/api/v1/user/oauth2/token' - data = 'grant_type=authorization_code&redirect_uri=' + parameters.getParameter('baseUrl') + '%2Fapi%2Fv1%2Fuser%2Foauth2%2Fredirect&code=' + authCode + data = 'grant_type=authorization_code&redirect_uri=' + \ + parameters.getParameter('baseUrl') + '%2Fapi%2Fv1%2Fuser%2Foauth2%2Fredirect&code=' + authCode headers = { 'Authorization': parameters.getParameter('basicToken'), 'Content-type': 'application/x-www-form-urlencoded', @@ -235,26 +254,27 @@ def getAuthToken(authCode): 'User-Agent': 'okhttp/3.10.0'} try: - response = kiahttp.postHTTP(url = url, headers = headers, data = data, timeout = parameters.getParameter('reqTimeout')) + response = kiahttp.postHTTP(url=url, headers=headers, data=data, timeout=parameters.getParameter('reqTimeout')) except: raise - + try: accessToken = json.loads(response) except: soclogging.logDebug(0, "Token request failed, invalid response") soclogging.logDebug(2, response) raise - - soclogging.logDebug(2, "Access token = " + accessToken['access_token']) + + soclogging.logDebug(2, "Access token = " + accessToken['access_token']) return accessToken + def getControlToken(pin): soclogging.logDebug(2, "Sending PIN") - + url = parameters.getParameter('baseUrl') + '/api/v1/user/pin' - data = {"deviceId": parameters.getParameter('deviceId'),"pin": pin} + data = {"deviceId": parameters.getParameter('deviceId'), "pin": pin} headers = { 'Authorization': parameters.getParameter('tokenType') + ' ' + parameters.getParameter('accessToken'), 'Content-type': 'application/json;charset=UTF-8', @@ -265,31 +285,33 @@ def getControlToken(pin): 'User-Agent': 'okhttp/3.10.0'} try: - response = kiahttp.putHTTP(url = url, data = data, headers = headers, timeout = parameters.getParameter('reqTimeout')) + response = kiahttp.putHTTP(url=url, data=data, headers=headers, timeout=parameters.getParameter('reqTimeout')) except: raise - + try: responseDict = json.loads(response) controlToken = 'Bearer ' + responseDict['controlToken'] except: soclogging.logDebug(1, "Sending PIN failed, invalid response") soclogging.logDebug(2, response) - raise - + raise + soclogging.logDebug(2, "Control token = " + controlToken) - + return controlToken - + + def refreshAuthToken(): try: accessToken = refreshAccessToken(parameters.getParameter('refreshToken')) saveAccessToken(accessToken, parameters.getParameter('deviceId')) except: raise - + return + def requestNewAuthToken(): try: deviceId = getDeviceId() @@ -300,18 +322,20 @@ def requestNewAuthToken(): saveAccessToken(accessToken, deviceId) except: raise - + return - + + def requestNewControlToken(): try: controlToken = getControlToken(parameters.getParameter('accountPin')) parameters.setParameter('controlToken', controlToken) except: raise - + return - + + def updateAuthToken(): try: loadAccessToken() @@ -322,5 +346,5 @@ def updateAuthToken(): except: raise pass - - return \ No newline at end of file + + return diff --git a/modules/soc_kia/kiahttp.py b/modules/soc_kia/kiahttp.py index f098b48c7..eecfed766 100644 --- a/modules/soc_kia/kiahttp.py +++ b/modules/soc_kia/kiahttp.py @@ -1,6 +1,4 @@ import json -import urllib.parse as urlparse -from urllib.parse import parse_qs import requests import soclogging @@ -8,19 +6,20 @@ lastCookies = {} lastUrl = "" -def getHTTP(url = '', headers = '', cookies = '', timeout = 30): + +def getHTTP(url='', headers='', cookies='', timeout=30): global lastCookies global lastUrl - + try: - response = requests.get(url, headers = headers, cookies = cookies, timeout = timeout) + response = requests.get(url, headers=headers, cookies=cookies, timeout=timeout) except requests.Timeout as err: soclogging.logDebug(1, "Connection Timeout") raise except: soclogging.logDebug(1, "HTTP Error") raise - + if response.status_code == 200 or response.status_code == 204: lastCookies = response.cookies.get_dict() return response.text @@ -35,15 +34,16 @@ def getHTTP(url = '', headers = '', cookies = '', timeout = 30): errorString = "[XXXX] Unidentified Error" + " " + response.text soclogging.logDebug(1, 'Request failed, StatusCode: ' + str(response.status_code) + ', Error: ' + errorString) raise RuntimeError - + return -def putHTTP(url = '', data = '', headers = '', cookies = '', timeout = 30): + +def putHTTP(url='', data='', headers='', cookies='', timeout=30): try: if isinstance(data, dict): - response = requests.put(url, json = data, headers = headers, cookies = cookies, timeout = timeout) + response = requests.put(url, json=data, headers=headers, cookies=cookies, timeout=timeout) else: - response = requests.put(url, data = data, headers = headers, cookies = cookies, timeout = timeout) + response = requests.put(url, data=data, headers=headers, cookies=cookies, timeout=timeout) except requests.Timeout as err: soclogging.logDebug(1, "Connection Timeout") raise @@ -64,25 +64,28 @@ def putHTTP(url = '', data = '', headers = '', cookies = '', timeout = 30): errorString = "[XXXX] Unidentified Error" soclogging.logDebug(1, 'Request failed, StatusCode: ' + str(response.status_code) + ', Error: ' + errorString) raise RuntimeError - + return - -def postHTTP(url = '', data = '', headers = '', cookies = '', timeout = 30, allow_redirects = True): + + +def postHTTP(url='', data='', headers='', cookies='', timeout=30, allow_redirects=True): global lastCookies global lastUrl - + try: if isinstance(data, dict): - response = requests.post(url, json = data, headers = headers, cookies = cookies, timeout = timeout, allow_redirects = allow_redirects) + response = requests.post(url, json=data, headers=headers, cookies=cookies, + timeout=timeout, allow_redirects=allow_redirects) else: - response = requests.post(url, data = data, headers = headers, cookies = cookies, timeout = timeout, allow_redirects = allow_redirects) + response = requests.post(url, data=data, headers=headers, cookies=cookies, + timeout=timeout, allow_redirects=allow_redirects) except requests.Timeout as err: soclogging.logDebug(1, "Connection Timeout") raise except: soclogging.logDebug(1, "HTTP Error") raise - + if response.status_code == 200 or response.status_code == 204: lastUrl = response.url return response.text @@ -97,21 +100,22 @@ def postHTTP(url = '', data = '', headers = '', cookies = '', timeout = 30, allo errorString = "[XXXX] Unidentified Error" soclogging.logDebug(1, 'Request failed, StatusCode: ' + str(response.status_code) + ', Error: ' + errorString) raise RuntimeError - + return + def getHTTPCookies(url): try: session = requests.Session() response = session.get(url) except requests.Timeout as err: soclogging.logDebug(1, "Connection Timeout") - raise - + raise + if response.status_code == 200: cookies = session.cookies.get_dict() else: soclogging.logDebug(1, "Receiving cookies failed, StatusCode: " + str(response.status_code)) raise - - return cookies \ No newline at end of file + + return cookies diff --git a/modules/soc_kia/kiaif.py b/modules/soc_kia/kiaif.py index 74f9639b8..d409c9b70 100644 --- a/modules/soc_kia/kiaif.py +++ b/modules/soc_kia/kiaif.py @@ -6,13 +6,15 @@ import kiahttp import stamps + def timeToStamp(timeString): timestamp = int(time.mktime(time.strptime(timeString, "%Y%m%d%H%M%S"))) return timestamp + def getVehicleId(vin): soclogging.logDebug(2, "Requesting vehicle list") - + url = parameters.getParameter('baseUrl') + '/api/v1/spa/vehicles' headers = { 'Authorization': parameters.getParameter('tokenType') + ' ' + parameters.getParameter('accessToken'), @@ -26,9 +28,9 @@ def getVehicleId(vin): 'Stamp': stamps.getStamp()} try: - response = kiahttp.getHTTP(url = url, headers = headers, timeout = parameters.getParameter('reqTimeout')) + response = kiahttp.getHTTP(url=url, headers=headers, timeout=parameters.getParameter('reqTimeout')) except: - raise + raise vehicleId = '' try: @@ -39,33 +41,34 @@ def getVehicleId(vin): except: soclogging.logDebug(1, "Vehicle request failed, invalid response") soclogging.logDebug(2, response) - raise - + raise + if vehicleId == '': soclogging.logDebug(1, "VIN " + vin + " unknown") raise - + soclogging.logDebug(2, "VehicleId = " + vehicleId) - + return vehicleId + def getStatusCached(vehicleId): soclogging.logDebug(2, "Receiving cached status") - + statusDict = { } - + url = parameters.getParameter('baseUrl') + '/api/v2/spa/vehicles/' + vehicleId + '/status/latest' headers = { 'Authorization': parameters.getParameter('controlToken'), 'ccsp-device-id': parameters.getParameter('deviceId'), 'Content-Type': 'application/json', 'Stamp': stamps.getStamp()} - + try: - response = kiahttp.getHTTP(url = url, headers = headers, timeout = parameters.getParameter('reqTimeout')) + response = kiahttp.getHTTP(url=url, headers=headers, timeout=parameters.getParameter('reqTimeout')) except: - raise + raise try: responseDict = json.loads(response) @@ -73,16 +76,17 @@ def getStatusCached(vehicleId): soclogging.logDebug(1, "Receiving cached status failed, invalid response") soclogging.logDebug(2, response) raise - + try: statusDict['soc12v'] = int(responseDict['resMsg']['vehicleStatusInfo']['vehicleStatus']['battery']['batSoc']) except: statusDict['soc12v'] = 100 pass - + try: statusDict['time'] = timeToStamp(responseDict['resMsg']['vehicleStatusInfo']['vehicleStatus']['time']) - statusDict['socev'] = int(responseDict['resMsg']['vehicleStatusInfo']['vehicleStatus']['evStatus']['batteryStatus']) + statusDict['socev'] = int(responseDict['resMsg']['vehicleStatusInfo'] + ['vehicleStatus']['evStatus']['batteryStatus']) statusDict['vehicleLocation'] = responseDict['resMsg']['vehicleStatusInfo']['vehicleLocation'] statusDict['vehicleStatus'] = responseDict['resMsg']['vehicleStatusInfo']['vehicleStatus'] statusDict['odometer'] = responseDict['resMsg']['vehicleStatusInfo']['odometer'] @@ -93,11 +97,12 @@ def getStatusCached(vehicleId): return statusDict + def doPrewakeup(vehicleId): soclogging.logDebug(2, "Triggering Pre-Wakeup") - + url = parameters.getParameter('baseUrl') + '/api/v1/spa/vehicles/' + vehicleId + '/control/engine' - data = {"action":"prewakeup","deviceId": parameters.getParameter('deviceId')} + data = {"action": "prewakeup", "deviceId": parameters.getParameter('deviceId')} headers = { 'Authorization': parameters.getParameter('tokenType') + ' ' + parameters.getParameter('accessToken'), 'ccsp-device-id': parameters.getParameter('deviceId'), @@ -112,18 +117,20 @@ def doPrewakeup(vehicleId): 'Stamp': stamps.getStamp()} try: - response = kiahttp.postHTTP(url = url, data = data, headers = headers, timeout = parameters.getParameter('statusTimeout')) + response = kiahttp.postHTTP(url=url, data=data, headers=headers, + timeout=parameters.getParameter('statusTimeout')) except: raise - + return -def getStatusFull(vehicleId): + +def getStatusFull(vehicleId): soclogging.logDebug(2, "Receiving current status from vehicle") statusDict = { } - + url = parameters.getParameter('baseUrl') + '/api/v2/spa/vehicles/' + vehicleId + '/status' headers = { 'Authorization': parameters.getParameter('controlToken'), @@ -132,17 +139,17 @@ def getStatusFull(vehicleId): 'Stamp': stamps.getStamp()} try: - response = kiahttp.getHTTP(url = url, headers = headers, timeout = parameters.getParameter('statusTimeout')) + response = kiahttp.getHTTP(url=url, headers=headers, timeout=parameters.getParameter('statusTimeout')) except: raise - + try: responseDict = json.loads(response) except: soclogging.logDebug(1, "Receiving current status failed, invalid response") soclogging.logDebug(2, response) raise - + try: statusDict['soc12v'] = int(responseDict['resMsg']['battery']['batSoc']) except: @@ -158,4 +165,4 @@ def getStatusFull(vehicleId): soclogging.logDebug(2, response) raise - return statusDict \ No newline at end of file + return statusDict diff --git a/modules/soc_kia/lock.py b/modules/soc_kia/lock.py index ba27e9a64..9f4d8a0fd 100644 --- a/modules/soc_kia/lock.py +++ b/modules/soc_kia/lock.py @@ -2,39 +2,42 @@ import parameters + def checkLockFile(): - + try: f = open(parameters.getParameter('lockFile'), 'r') lockTime = int(f.read()) f.close() except: lockTime = 0 - + now = time.time() if lockTime > (now - 10*60): raise RuntimeError - + return + def createLockFile(): - + try: f = open(parameters.getParameter('lockFile'), 'w') f.write(str(int(time.time()))) f.close() except: raise - + return + def purgeLockFile(): - + try: f = open(parameters.getParameter('lockFile'), 'w') f.write(str(0)) f.close() except: raise - - return \ No newline at end of file + + return diff --git a/modules/soc_kia/main.py b/modules/soc_kia/main.py index 7475f301f..865e4d271 100644 --- a/modules/soc_kia/main.py +++ b/modules/soc_kia/main.py @@ -7,6 +7,7 @@ import trigger import soc + def initialize(argsFile): try: parameters.loadParameters(argsFile) @@ -14,52 +15,50 @@ def initialize(argsFile): parameters.loadBrandData() except: raise - + return -#---------------Main Function------------------------------------------- + +# ---------------Main Function------------------------------------------- def main(): try: initialize(str(sys.argv[1])) - + lock.checkLockFile() lock.createLockFile() except: exit(1) - - soclogging.logDebug(1, "-------------------------------") + + soclogging.logDebug(1, "-------------------------------") soclogging.logDebug(1, "Kia/Hyundai SoC Module starting") - + try: state.saveUnplugState() state.saveChargedState() - + if trigger.isDownloadTriggered() == 1: soc.doExternalUpdate() elif parameters.getParameter('manualCalc') == 1: if state.isCharging() == 1: soclogging.logDebug(2, "Manual calculation starting") soc.doManualUpdate() - else: + else: soclogging.logDebug(2, "Nothing to do yet") except: pass - + try: state.saveTickTime() except: pass - + soclogging.logDebug(1, "Kia/Hyundai SoC Module ending") - + try: lock.purgeLockFile() except: exit(1) - raise - - exit(0) - + if __name__ == '__main__': main() diff --git a/modules/soc_kia/parameters.py b/modules/soc_kia/parameters.py index 85335c7a2..84a83ed2b 100644 --- a/modules/soc_kia/parameters.py +++ b/modules/soc_kia/parameters.py @@ -3,23 +3,26 @@ paramDict = {} + def getParameter(key): global paramDict - + if key in paramDict: value = paramDict[key] else: raise RuntimeError - + return value - + + def setParameter(key, value): global paramDict - + paramDict[key] = value - + return + def loadParameters(argsFile): setParameter('reqTimeout', 60) setParameter('statusTimeout', 150) @@ -29,11 +32,11 @@ def loadParameters(argsFile): argsStr = f.read() argsDict = json.loads(argsStr) f.close() - + setParameter('moduleName', str(argsDict['moduleName'])) setParameter('chargePoint', str(argsDict['chargePoint'])) - setParameter('debugLevel', int(argsDict['debugLevel'])) - setParameter('timerInterval',int(argsDict['timerInterval'])) + setParameter('debugLevel', int(argsDict['debugLevel'])) + setParameter('timerInterval', int(argsDict['timerInterval'])) setParameter('manualCalc', int(argsDict['manualCalc'])) setParameter('batterySize', float(argsDict['batterySize'])) setParameter('efficiency', float(argsDict['efficiency'])) @@ -45,7 +48,7 @@ def loadParameters(argsFile): setParameter('vehicleVin', str(argsDict['vehicleVin'])) setParameter('ramDiskDir', str(argsDict['ramDiskDir'])) setParameter('advEnable', int(argsDict['advEnable'])) - + if getParameter('advEnable') == 0: setParameter('cacheValid', 10 * 60) setParameter('soc12vLimit', 20) @@ -60,17 +63,22 @@ def loadParameters(argsFile): raise return - + + def loadFileNames(): try: ramDiskDir = getParameter('ramDiskDir') - + setParameter('logFile', ramDiskDir + "/soc.log") - setParameter('lockFile', ramDiskDir + "/soc_" + getParameter('moduleName')+ "_lp" + getParameter('chargePoint') + "_lock") - setParameter('tokenFile', ramDiskDir + "/soc_" + getParameter('moduleName')+ "_lp" + getParameter('chargePoint') + "_token") - setParameter('stateFile', ramDiskDir + "/soc_" + getParameter('moduleName')+ "_lp" + getParameter('chargePoint') + "_state") - setParameter('auxDataFile', ramDiskDir + "/soc_" + getParameter('moduleName')+ "_lp" + getParameter('chargePoint') + "_auxdata") - + setParameter('lockFile', ramDiskDir + "/soc_" + getParameter('moduleName') + + "_lp" + getParameter('chargePoint') + "_lock") + setParameter('tokenFile', ramDiskDir + "/soc_" + getParameter('moduleName') + + "_lp" + getParameter('chargePoint') + "_token") + setParameter('stateFile', ramDiskDir + "/soc_" + getParameter('moduleName') + + "_lp" + getParameter('chargePoint') + "_state") + setParameter('auxDataFile', ramDiskDir + "/soc_" + getParameter('moduleName') + + "_lp" + getParameter('chargePoint') + "_auxdata") + if getParameter('chargePoint') == '1': setParameter('currentSocFile', ramDiskDir + "/soc") setParameter('timerFile', ramDiskDir + "/soctimer") @@ -87,23 +95,24 @@ def loadFileNames(): raise RuntimeError except: raise - + return - + + def loadBrandData(): vin = getParameter('vehicleVin') - - if vin[:2]=='KN' or vin[:3]=='U5Y' or vin[:3]=='U6Z': + + if vin[:2] == 'KN' or vin[:3] == 'U5Y' or vin[:3] == 'U6Z': setParameter('brand', 'kia') - #soclogging.logDebug(2, "Vehicle identified as Kia") - elif vin[:3]=='KMH' or vin[:3]=='TMA': + # soclogging.logDebug(2, "Vehicle identified as Kia") + elif vin[:3] == 'KMH' or vin[:3] == 'TMA': setParameter('brand', 'hyundai') - #soclogging.logDebug(2, "Vehicle identified as Hyundai") + # soclogging.logDebug(2, "Vehicle identified as Hyundai") else: setParameter('brand', '') soclogging.logDebug(2, "Vehicle WMI unknown") raise RuntimeError - + if getParameter('brand') == 'kia': setParameter('host', 'prd.eu-ccapi.kia.com:8080') setParameter('baseUrl', 'https://' + getParameter('host')) @@ -119,6 +128,7 @@ def loadBrandData(): setParameter('authClientId', '64621b96-0f0d-11ec-82a8-0242ac130003') setParameter('appId', '014d2225-8495-4735-812d-2616334fd15d') setParameter('GCMSenderId', '414998006775') - setParameter('basicToken', 'Basic NmQ0NzdjMzgtM2NhNC00Y2YzLTk1NTctMmExOTI5YTk0NjU0OktVeTQ5WHhQekxwTHVvSzB4aEJDNzdXNlZYaG10UVI5aVFobUlGampvWTRJcHhzVg==') - - return \ No newline at end of file + setParameter( + 'basicToken', 'Basic NmQ0NzdjMzgtM2NhNC00Y2YzLTk1NTctMmExOTI5YTk0NjU0OktVeTQ5WHhQekxwTHVvSzB4aEJDNzdXNlZYaG10UVI5aVFobUlGampvWTRJcHhzVg==') + + return diff --git a/modules/soc_kia/soc.py b/modules/soc_kia/soc.py index 04e1a45db..2741fba17 100644 --- a/modules/soc_kia/soc.py +++ b/modules/soc_kia/soc.py @@ -6,21 +6,22 @@ import soc_external import abrp + def doExternalUpdate(): attempt = 0 - + if state.getState('lastSuccess') == 1: maxAttempt = 3 else: maxAttempt = 1 - + while attempt < maxAttempt: try: soc = soc_external.DownloadSoC() except: soc = 0 raise - + if soc > 0: saveSoc(soc, 0) state.setState('lastSuccess', 1) @@ -31,10 +32,11 @@ def doExternalUpdate(): if attempt < maxAttempt: soclogging.logDebug(2, "Retrying in 60 Seconds...") time.sleep(60) - + return - -def doManualUpdate(): + + +def doManualUpdate(): try: f = open(parameters.getParameter('meterFile'), 'r') currentMeter = float(f.read()) @@ -42,29 +44,33 @@ def doManualUpdate(): except: soclogging.logDebug(2, "Could not find current meter file") raise - + try: lastMeter = state.getState('lastMeter') lastSoc = state.getState('lastSoc') f.close() except: raise - + batterySize = parameters.getParameter('batterySize') efficiency = parameters.getParameter('efficiency') meterDiff = currentMeter - lastMeter meterDiffEff = meterDiff * (efficiency / 100) socDiff = 100 * (meterDiffEff / batterySize) newSoc = int(max(min(lastSoc + socDiff, 100), 1)) - - soclogging.logDebug(2, "Charged since last update: " + '{:.3f}'.format(meterDiff) + " kWh = " + '{:.3f}'.format(meterDiffEff) + " kWh @ " + '{:.0f}'.format(efficiency) + "% efficency") - soclogging.logDebug(2, "Charged since last update: " + '{:.3f}'.format(meterDiffEff) + " kWh of " + '{:.0f}'.format(batterySize) + " kWh = " + '{:.2f}'.format(socDiff) + "% SoC") - soclogging.logDebug(1, "Estimated SoC: " + '{:.0f}'.format(lastSoc) + "% (last update) + " + '{:.2f}'.format(socDiff) + "% (extrapolation) = " + '{:.0f}'.format(newSoc) + "% SoC") - + + soclogging.logDebug(2, "Charged since last update: " + '{:.3f}'.format(meterDiff) + " kWh = " + '{:.3f}'.format( + meterDiffEff) + " kWh @ " + '{:.0f}'.format(efficiency) + "% efficency") + soclogging.logDebug(2, "Charged since last update: " + '{:.3f}'.format( + meterDiffEff) + " kWh of " + '{:.0f}'.format(batterySize) + " kWh = " + '{:.2f}'.format(socDiff) + "% SoC") + soclogging.logDebug(1, "Estimated SoC: " + '{:.0f}'.format(lastSoc) + "% (last update) + " + + '{:.2f}'.format(socDiff) + "% (extrapolation) = " + '{:.0f}'.format(newSoc) + "% SoC") + saveSoc(newSoc, 1) - + return - + + def saveSoc(soc, manual): try: f = open(parameters.getParameter('currentSocFile'), 'r') @@ -73,28 +79,28 @@ def saveSoc(soc, manual): except: socOld = 0 pass - + try: f = open(parameters.getParameter('currentSocFile'), 'w') f.write(str(int(soc))) f.close() except: raise - + try: if (parameters.getParameter('abrpEnable') == 1) and ((manual == 0) or (soc != socOld)): abrp.pushABRP(soc) except: pass - - if manual == 0: + + if manual == 0: try: f = open(parameters.getParameter('meterFile'), 'r') meter = float(f.read()) f.close() except: meter = 0 - + try: state.setState('lastSoc', soc) state.setState('lastMeter', meter) @@ -102,5 +108,5 @@ def saveSoc(soc, manual): state.setState('charged', 0) except: raise - - return \ No newline at end of file + + return diff --git a/modules/soc_kia/soc_external.py b/modules/soc_kia/soc_external.py index f4c8298c0..b6be0fcc3 100644 --- a/modules/soc_kia/soc_external.py +++ b/modules/soc_kia/soc_external.py @@ -6,19 +6,20 @@ import kiaauth import kiaif + def DownloadSoC(): soclogging.logDebug(0, "SoC download starting") - now = int(time.time()) - + now = int(time.time()) + auxData = {} - - try: + + try: kiaauth.updateAuthToken() kiaauth.requestNewControlToken() except: soclogging.logDebug(0, "Login failed") raise - + try: vehicleId = kiaif.getVehicleId(parameters.getParameter('vehicleVin')) status = kiaif.getStatusCached(vehicleId) @@ -39,36 +40,36 @@ def DownloadSoC(): if status['soc12v'] < parameters.getParameter('soc12vLimit'): soclogging.logDebug(0, "12 V-battery low - 12 V-SoC: " + cachedStatus['soc12v'] + " %; Download cancelled") raise RuntimeError - + try: kiaif.doPrewakeup(vehicleId) status = kiaif.getStatusFull(vehicleId) except: soclogging.logDebug(0, "Collecting data from vehicle failed") raise - + try: auxData['vehicleStatus'] = status['vehicleStatus'] except: pass - + if status['soc12v'] >= 80: soclogging.logDebug(2, "Received SoC (12 V-battery): " + str(status['soc12v']) + "%") elif status['soc12v'] >= 70 and status['soc12v'] < 80: soclogging.logDebug(1, "Received SoC (12 V-battery): " + str(status['soc12v']) + "%") elif status['soc12v'] < 70: soclogging.logDebug(0, "Received SoC (12 V-battery): " + str(status['soc12v']) + "%") - + soc = status['socev'] soclogging.logDebug(0, "Received SoC (HV-battery): " + str(soc) + "%") - + try: f = open(parameters.getParameter('auxDataFile'), 'w') f.write(json.dumps(auxData)) f.close() except: pass - + soclogging.logDebug(1, "SoC download ending") - - return soc \ No newline at end of file + + return soc diff --git a/modules/soc_kia/soclogging.py b/modules/soc_kia/soclogging.py index 2845d86a8..a5852a558 100644 --- a/modules/soc_kia/soclogging.py +++ b/modules/soc_kia/soclogging.py @@ -2,14 +2,15 @@ import parameters + def logDebug(msgLevel, msgText): if parameters.getParameter('debugLevel') >= msgLevel: now = datetime.now() timestamp = now.strftime("%Y-%m-%d %H:%M:%S") line = timestamp + ": " + msgText + "\n" - + f = open(parameters.getParameter('logFile'), 'a') f.write(line) f.close() - - return \ No newline at end of file + + return diff --git a/modules/soc_kia/stamps.py b/modules/soc_kia/stamps.py index 509dab9f9..7cf052943 100644 --- a/modules/soc_kia/stamps.py +++ b/modules/soc_kia/stamps.py @@ -5,23 +5,24 @@ import stamps_kia import stamps_hyundai + def getStamp(): now = int(time.time()) stamp = "" brand = parameters.getParameter('brand') - + try: if brand == 'kia': - index = max(min(int((now - stamps_kia.start) / stamps_kia.step) - 1,len(stamps_kia.stamps) - 1), 0) + index = max(min(int((now - stamps_kia.start) / stamps_kia.step) - 1, len(stamps_kia.stamps) - 1), 0) stamp = stamps_kia.stamps[index] - + if brand == 'hyundai': - index = max(min(int((now - stamps_hyundai.start) / stamps_hyundai.step) - 1,len(stamps_hyundai.stamps) - 1), 0) + index = max(min(int((now - stamps_hyundai.start) / stamps_hyundai.step) - 1, len(stamps_hyundai.stamps) - 1), 0) stamp = stamps_hyundai.stamps[index] except: raise - + if stamp == "": raise - - return stamp \ No newline at end of file + + return stamp diff --git a/modules/soc_kia/state.py b/modules/soc_kia/state.py index b8a0c800e..609809b40 100644 --- a/modules/soc_kia/state.py +++ b/modules/soc_kia/state.py @@ -5,19 +5,20 @@ stateDict = {} + def getState(key): global stateDict - + try: f = open(parameters.getParameter('stateFile'), 'r') stateStr = f.read() stateDict = json.loads(stateStr) f.close() - + value = stateDict[key] except: value = 0 - + if key == 'lastTick': value = 0 if key == 'lastRun': @@ -32,14 +33,15 @@ def getState(key): value = 1 if key == 'lastSuccess': value = 1 - + pass - + return value - + + def setState(key, value): global stateDict - + try: f = open(parameters.getParameter('stateFile'), 'r') stateStr = f.read() @@ -47,9 +49,9 @@ def setState(key, value): f.close() except: pass - + stateDict[key] = value - + try: f = open(parameters.getParameter('stateFile'), 'w') stateStr = json.dumps(stateDict) @@ -57,56 +59,61 @@ def setState(key, value): f.close() except: raise - + return - -def isCharging(): - try: + + +def isCharging(): + try: f = open(parameters.getParameter('isChargingFile'), 'r') chargeState = int(f.read()) - f.close() + f.close() except: raise return chargeState - -def isPlugged(): - try: + + +def isPlugged(): + try: f = open(parameters.getParameter('isPluggedFile'), 'r') plugState = int(f.read()) - f.close() + f.close() except: raise return plugState - -def saveUnplugState(): - try: + + +def saveUnplugState(): + try: now = int(time.time()) secsSinceLastTick = now - getState('lastTick') - + if (isPlugged() == 0) or (secsSinceLastTick > 60): setState('unplug', 1) - + except: raise - + return - -def saveChargedState(): + + +def saveChargedState(): try: if isCharging() == 1: - setState('charged', 1) + setState('charged', 1) except: raise - + return - + + def saveTickTime(): try: now = int(time.time()) setState('lastTick', now) except: raise - - return \ No newline at end of file + + return diff --git a/modules/soc_kia/trigger.py b/modules/soc_kia/trigger.py index 8999ecaca..315702ca4 100644 --- a/modules/soc_kia/trigger.py +++ b/modules/soc_kia/trigger.py @@ -4,6 +4,7 @@ import soclogging import state + def ackExternalTrigger(): try: f = open(parameters.getParameter('timerFile'), 'w') @@ -11,25 +12,27 @@ def ackExternalTrigger(): f.close() except: raise - + return + def ackTimerTrigger(): try: now = int(time.time()) state.setState('lastRun', now) except: raise - + return - + + def isExternalTriggered(): trigger = 0 - - try: + + try: f = open(parameters.getParameter('timerFile'), 'r') ticksLeft = int(f.read()) - f.close() + f.close() except: ticksLeft = 0 pass @@ -37,37 +40,40 @@ def isExternalTriggered(): if ticksLeft > 0: trigger = 1 soclogging.logDebug(1, "SoC download triggered externally") - + return trigger - + + def isMinimumTimerExpired(): - now = int(time.time()) + now = int(time.time()) secSince = now - state.getState('lastRun') if secSince < parameters.getParameter('timerMinInterval'): trigger = 0 else: trigger = 1 - + return trigger + def isTimerExpired(): now = int(time.time()) - + if state.isPlugged() == 1: secLeft = (state.getState('lastRun') + (parameters.getParameter('timerInterval') * 60)) - now else: secLeft = (state.getState('lastRun') + (parameters.getParameter('timerIntervalUnplug') * 60)) - now - + if secLeft < 0: trigger = 1 soclogging.logDebug(1, "SoC download triggered by timer") else: trigger = 0 soclogging.logDebug(2, "Next Update: " + '{:.1f}'.format(secLeft / 60) + " minutes") - + return trigger - + + def isDownloadTriggered(): trigger = 0 @@ -84,16 +90,17 @@ def isDownloadTriggered(): if isMinimumTimerExpired() == 1: ackTimerTrigger() trigger = 1 - else: - soclogging.logDebug(1, "Last Download less then "+ '{:.0f}'.format(parameters.getParameter('timerMinInterval') / 60) + " minutes ago. Cancelling download") + else: + soclogging.logDebug(1, "Last Download less then " + '{:.0f}'.format( + parameters.getParameter('timerMinInterval') / 60) + " minutes ago. Cancelling download") trigger = 0 - + if trigger == 1: if state.getState('charged') == 0 and state.getState('unplug') == 0: trigger = 0 - soclogging.logDebug(1, "Vehicle was not unplugged or charging since last download. Cancelling download") - + soclogging.logDebug(1, "Vehicle was not unplugged or charging since last download. Cancelling download") + except: raise - - return trigger \ No newline at end of file + + return trigger