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')) except: raise try: responseDict = json.loads(response) statusDict['time'] = timeToStamp(responseDict['resMsg']['vehicleStatusInfo']['vehicleStatus']['time']) statusDict['socev'] = int(responseDict['resMsg']['vehicleStatusInfo']['vehicleStatus']['evStatus']['batteryStatus']) statusDict['soc12v'] = int(responseDict['resMsg']['vehicleStatusInfo']['vehicleStatus']['battery']['batSoc']) statusDict['vehicleLocation'] = responseDict['resMsg']['vehicleStatusInfo']['vehicleLocation'] statusDict['vehicleStatus'] = responseDict['resMsg']['vehicleStatusInfo']['vehicleStatus'] statusDict['odometer'] = responseDict['resMsg']['vehicleStatusInfo']['odometer'] except: soclogging.logDebug(1, "Receiving cached status failed, invalid response") soclogging.logDebug(2, response) raise return statusDict
def saveSoc(soc, manual): try: f = open(parameters.getParameter('currentSocFile'), 'w') f.write(str(int(soc))) f.close() except: raise try: if parameters.getParameter('abrpEnable') == 1: abrp.pushABRP(soc) except: pass 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) state.setState('unplug', 0) state.setState('charged', 0) except: raise return
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 headers = { 'Authorization': parameters.getParameter('basicToken'), 'Content-type': 'application/x-www-form-urlencoded', 'Content-Length': str(len(data)), 'Host': parameters.getParameter('host'), 'Connection': 'close', 'Accept-Encoding': 'gzip, deflate', 'User-Agent': 'okhttp/3.10.0' } try: 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']) return accessToken
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 = { 'Authorization': parameters.getParameter('basicToken'), 'Content-type': 'application/x-www-form-urlencoded', 'Content-Length': str(len(data)), 'Host': parameters.getParameter('host'), 'Connection': 'close', 'Accept-Encoding': 'gzip, deflate', 'User-Agent': 'okhttp/3.10.0' } try: response = kiahttp.postHTTP( url=url, headers=headers, data=data, timeout=parameters.getParameter('reqTimeout')) except: raise try: accessToken = json.loads(response) accessToken['refresh_token'] = refreshToken except: soclogging.logDebug(0, "Token request failed, invalid response") soclogging.logDebug(2, response) raise soclogging.logDebug(2, "Access token = " + accessToken['access_token']) return accessToken
def getUserHash(): try: account = parameters.getParameter( 'accountName') + ':' + parameters.getParameter('accountPassword') hash = hashlib.md5(account.encode()).hexdigest() except: raise return hash
def refreshAuthToken(): try: accessToken = refreshAccessToken( parameters.getParameter('refreshToken')) saveAccessToken(accessToken, parameters.getParameter('deviceId')) except: raise return
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
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' try: cookies = kiahttp.getHTTPCookies(url) except: raise return cookies
def isDownloadTriggered(): trigger = 0 try: if isExternalTriggered() == 1: ackExternalTrigger() trigger = 1 elif isTimerExpired() == 1: trigger = 1 else: trigger = 0 if trigger == 1: if isMinimumTimerExpired() == 1: ackTimerTrigger() trigger = 1 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") except: raise 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 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) 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) stamp = stamps_hyundai.stamps[index] except: raise if stamp == "": raise return stamp
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': value = 0 if key == 'lastSoc': value = 0 if key == 'lastMeter': value = 0 if key == 'charged': value = 1 if key == 'unplug': value = 1 if key == 'lastSuccess': value = 1 pass return value
def getStamp(): try: # Timestamp in ms an string now = str(int(time.time()) * 1000) # Set App-ID and App-ID specific key brand = parameters.getParameter('brand') if brand == 'kia': appid = "e7bcd186-a5fd-410d-92cb-6876a42288bd" secret_ba = bytearray.fromhex( "C0B4D5C7089D987F027C96015929C70FCE5B94FC9AE938CA6EE1E02F6142AFE2A1F20C7EB9C902C93E56EE1E0D81B9F7CEA3" ) if brand == 'hyundai': appid = "014d2225-8495-4735-812d-2616334fd15d" secret_ba = bytearray.fromhex( "445B6846AFEF0D726646776865A650C9F3A8B7B3AB22A195163F7A898D962F7CB21F967FA54BE5521AA60B10F6B7E0FA89E1" ) # Combine plaintext and convert to bytearray plaintext = appid + ":" + now plaintext_ba = bytearray(plaintext.encode()) # XOR plaintext and key stamp_ba = bytes(a ^ b for (a, b) in zip(plaintext_ba, secret_ba)) # Convert result to base64-string stamp_b64_ba = base64.b64encode(stamp_ba) stamp = stamp_b64_ba.decode() except: raise return stamp
def pushABRP(soc): now = int(time.time()) apiKey = "49589dbf-37a8-4c22-a49c-7d62fe1a6531" userToken = parameters.getParameter('abrpToken') soclogging.logDebug(2, "Submitting ABRP-Data") 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: 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
def requestNewControlToken(): try: controlToken = getControlToken(parameters.getParameter('accountPin')) parameters.setParameter('controlToken', controlToken) except: raise return
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) data = { 'tlm': { 'utc': now, 'soc': soc, 'is_charging': state.isCharging() } } try: f = open(parameters.getParameter('auxDataFile'), 'r') auxData = json.loads(f.read()) f.close() data['tlm']['odometer'] = auxData['odometer']['value'] data['tlm']['lat'] = auxData['vehicleLocation']['coord']['lat'] data['tlm']['lon'] = auxData['vehicleLocation']['coord']['lon'] data['tlm']['speed'] = auxData['vehicleLocation']['speed']['value'] data['tlm']['is_parked'] = auxData['vehicleStatus']['doorLock'] except: pass try: 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
def ackExternalTrigger(): try: f = open(parameters.getParameter('timerFile'), 'w') f.write(str(0)) f.close() except: raise return
def setLanguage(cookies): soclogging.logDebug(2, "Setting 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')) except: raise return
def isCharging(): try: f = open(parameters.getParameter('isChargingFile'), 'r') chargeState = int(f.read()) f.close() except: raise return chargeState
def isPlugged(): try: f = open(parameters.getParameter('isPluggedFile'), 'r') plugState = int(f.read()) f.close() except: raise return plugState
def isMinimumTimerExpired(): now = int(time.time()) secSince = now - state.getState('lastRun') if secSince < parameters.getParameter('timerMinInterval'): trigger = 0 else: trigger = 1 return trigger
def purgeLockFile(): try: f = open(parameters.getParameter('lockFile'), 'w') f.write(str(0)) f.close() except: raise return
def createLockFile(): try: f = open(parameters.getParameter('lockFile'), 'w') f.write(str(int(time.time()))) f.close() except: raise return
def getDeviceId(): soclogging.logDebug(2, "Requesting DeviceId") url = parameters.getParameter( 'baseUrl') + '/api/v1/spa/notifications/register' data = { "pushRegId": parameters.getParameter('GCMSenderId'), "pushType": "GCM", "uuid": str(uuid.uuid1()) } headers = { 'ccsp-service-id': parameters.getParameter('clientId'), 'Content-type': 'application/json;charset=UTF-8', 'Content-Length': str(len(data)), 'Host': parameters.getParameter('host'), 'Connection': 'close', 'Accept-Encoding': 'gzip, deflate', 'User-Agent': 'okhttp/3.10.0', 'Stamp': stamps.getStamp() } try: response = kiahttp.postHTTP( url=url, data=data, headers=headers, timeout=parameters.getParameter('reqTimeout')) except: raise try: responseDict = json.loads(response) deviceId = responseDict['resMsg']['deviceId'] except: soclogging.logDebug(1, "Could not receive DeviceId, invalid response") soclogging.logDebug(2, response) raise soclogging.logDebug(2, "DeviceId = " + deviceId) return deviceId
def setState(key, value): global stateDict try: f = open(parameters.getParameter('stateFile'), 'r') stateStr = f.read() stateDict = json.loads(stateStr) f.close() except: pass stateDict[key] = value try: f = open(parameters.getParameter('stateFile'), 'w') stateStr = json.dumps(stateDict) f.write(stateStr) f.close() except: raise return
def doManualUpdate(): try: f = open(parameters.getParameter('meterFile'), 'r') currentMeter = float(f.read()) f.close() 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") saveSoc(newSoc, 1) return
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 getVehicleId(vin): soclogging.logDebug(2, "Requesting vehicle list") url = parameters.getParameter('baseUrl') + '/api/v1/spa/vehicles' headers = { 'Authorization': parameters.getParameter('tokenType') + ' ' + parameters.getParameter('accessToken'), 'ccsp-device-id': parameters.getParameter('deviceId'), 'ccsp-application-id': parameters.getParameter('appId'), 'offset': '1', 'Host': parameters.getParameter('host'), 'Connection': 'close', 'Accept-Encoding': 'gzip, deflate', 'User-Agent': 'okhttp/3.10.0', 'Stamp': stamps.getStamp() } try: response = kiahttp.getHTTP( url=url, headers=headers, timeout=parameters.getParameter('reqTimeout')) except: raise vehicleId = '' try: responseDict = json.loads(response) for vehicle in responseDict['resMsg']['vehicles']: if vehicle['vin'] == vin: vehicleId = vehicle['vehicleId'] except: soclogging.logDebug(1, "Vehicle request failed, invalid response") soclogging.logDebug(2, response) raise if vehicleId == '': soclogging.logDebug(1, "VIN " + vin + " unknown") raise soclogging.logDebug(2, "VehicleId = " + vehicleId) return vehicleId
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') } headers = { 'Authorization': parameters.getParameter('tokenType') + ' ' + parameters.getParameter('accessToken'), 'ccsp-device-id': parameters.getParameter('deviceId'), 'ccsp-application-id': parameters.getParameter('appId'), 'offset': '1', 'Content-Type': 'application/json;charset=UTF-8', 'Content-Length': str(len(data)), 'Host': parameters.getParameter('host'), 'Connection': 'close', 'Accept-Encoding': 'gzip, deflate', 'User-Agent': 'okhttp/3.10.0', 'Stamp': stamps.getStamp() } try: response = kiahttp.postHTTP( url=url, data=data, headers=headers, timeout=parameters.getParameter('statusTimeout')) except: raise return
def isExternalTriggered(): trigger = 0 try: f = open(parameters.getParameter('timerFile'), 'r') ticksLeft = int(f.read()) f.close() except: ticksLeft = 0 pass if ticksLeft > 0: trigger = 1 soclogging.logDebug(1, "SoC download triggered externally") return trigger