A better route planner

Here is a first stab at getting data uploaded to a better route planner ( https://abetterrouteplanner.com/ ). You will need a couple of things -

  1. Your token or email address - this is found on the https://abetterrouteplanner.com/ after you have logged in -
    Show Settings
    Show More Settings
    Live Car Connection Setup
    Next until User Email Address is shown - copy that here

  2. API token - can be obtained from contact@iternio.com, but I’m hoping we can share the same one

Custom code script is -

import time
import logging
import requests
import json
import urllib

log = logging.getLogger(__name__)

# ABRP token ( ie email address )
#
# See https://abetterrouteplanner.com/
#   Show Settings
#   Show More Settings
#   Live Car Connection Setup
#   Next until User Email Address is shown - copy that here 
#
abrt_token = 'some value'

# ABRP API KEY
#
# See contact@iternio.com
#
abrt_apikey = 'some value'

def telemetry():
    """
    Report telemetry to ABRP 
    """

    data = {}

    location = get_location()

    # Required

    # utc - Current UTC timestamp in seconds
    data['utc'] = time.time()
    log.info ('utc = '+str(data['utc']))

    # soc - State of Charge of the battery in percent (100 = fully charged battery)
    data['soc'] = get_soc()
    log.info ('soc = '+str(data['soc']))

    # speed - Speed of the car in km/h (GPS or OBD)
    data['speed'] = get_speed()
    log.info ('speed = '+str(data['speed']))

    # lat - User's current latitude
    data['lat'] = location['latitude']
    log.info ('lat = '+str(data['lat']))

    # lon - User's current longitude
    data['lon'] = location['longitude']
    log.info ('lon = '+str(data['lon']))

    # is_charging -  1 or 0, 1 = charging, 0 = driving
    data['is_charging'] = get_charging()
    log.info ('is_charging = '+str(data['is_charging']))

    # car_model - String like:chevy:bolt:17:60:other determining what car the user has connected
    data['car_model'] = 'hyundai:kona:17:64:other'

    # optional

    # voltage - Voltage of the battery in Volts
    data['voltage'] = get_voltage()
    log.info ('voltage = '+str(data['voltage']))

    # current - Current output (input is negative) of the battery in Amps
    data['current'] = get_current()
    log.info ('current = '+str(data['current']))

    # power - Power output (input is negative) of the battery in kW
    data['power'] = data['current']*data['voltage']/1000.0
    log.info ('power = '+str(data['power']))

    # soh - State of Health of the battery in percent (100 = fully healthy battery)
    data['soh'] = get_soh()
    log.info ('soh = '+str(data['soh']))

    # elevation - User's current elevation in meters
    data['elevation'] = location['altitude']
    log.info ('elevation = '+str(data['elevation']))

    # ext_temp - External temperature in Celsius
    data['ext_temp'] = get_externaltemp()
    log.info ('ext_temp = '+str(data['ext_temp']))

    # batt_temp - Battery temperature in Celsius
    data['batt_temp'] = get_batterytemp()
    log.info ('batt_temp = '+str(data['batt_temp']))

    params = {'token': abrt_token, 'api_key': abrt_apikey, 'tlm': json.dumps(data, separators=(',',':'))}

    log.info ('https://api.iternio.com/1/tlm/send?'+urllib.urlencode(params))  

    return {"msg": requests.get('https://api.iternio.com/1/tlm/send?'+urllib.urlencode(params))}

# get display state of charge
#
def get_soc():
    args = ['soc']
    kwargs = {
        'mode': '220',
        'pid': '105',
        'header': '7E4',
        'baudrate': 500000,
        'formula': 'bytes_to_int(message.data[34:35])/2.0',
        'protocol': '6',
        'verify': False,
        'force': True,
    }
    return __salt__['obd.query'](*args, **kwargs)['value']

# get speed ( needs validation )
#
def get_speed():
    try:
        args = ['speed']
        kwargs = {
            'mode': '220',
            'pid': '100',
            'header': '7B3',
            'baudrate': 500000,
            'formula': 'bytes_to_int(message.data[32:33])',
            'protocol': '6',
            'verify': False,
            'force': True,
        }
        return __salt__['obd.query'](*args, **kwargs)['value']
    except:
        return 0

# is charging
#
def get_charging():
    try:
        args = ['charging']
        kwargs = {
            'mode': '220',
            'pid': '101',
            'header': '7E4',
            'baudrate': 500000,
            'formula': 'bytes_to_int(message.data[53:54])',
            'protocol': '6',
            'verify': False,
            'force': True,
        }
        # note - sums are done outside of the forumla due to autopi failing
        # with 0
        #
        return 1-(int(__salt__['obd.query'](*args, **kwargs)['value'])&4)/4
    except:
        return 0

# get voltage
#
def get_voltage():
    args = ['voltage']
    kwargs = {
        'mode': '220',
        'pid': '101',
        'header': '7E4',
        'baudrate': 500000,
        'formula': '(bytes_to_int(message.data[15:16])*256+bytes_to_int(message.data[16:17]))/10.0',
        'protocol': '6',
        'verify': False,
        'force': True,
    }
    return __salt__['obd.query'](*args, **kwargs)['value']

# get current
#
def get_current():
    args = ['current']
    kwargs = {
        'mode': '220',
        'pid': '101',
        'header': '7E4',
        'baudrate': 500000,
        'formula': 'twos_comp(bytes_to_int(message.data[13:14])*256+bytes_to_int(message.data[14:15]),16)/10.0',
        'protocol': '6',
        'verify': False,
        'force': True,
    }
    return __salt__['obd.query'](*args, **kwargs)['value']

# get soh
#
def get_soh():
    args = ['soh']
    kwargs = {
        'mode': '220',
        'pid': '105',
        'header': '7E4',
        'baudrate': 500000,
        'formula': '(bytes_to_int(message.data[28:29])*256+bytes_to_int(message.data[29:30]))/10.0',
        'protocol': '6',
        'verify': False,
        'force': True,
    }
    return __salt__['obd.query'](*args, **kwargs)['value']

# get external temp
#
def get_externaltemp():
    args = ['externaltemp']
    kwargs = {
        'mode': '220',
        'pid': '100',
        'header': '7B3',
        'baudrate': 500000,
        'formula': '(bytes_to_int(message.data[9:10])/2.0)-40.0',
        'protocol': '6',
        'verify': False,
        'force': True,
    }
    return __salt__['obd.query'](*args, **kwargs)['value']

# get battery temp
#
def get_batterytemp():
    args = ['batterytemp']
    kwargs = {
        'mode': '220',
        'pid': '101',
        'header': '7E4',
        'baudrate': 500000,
        'formula': 'twos_comp(bytes_to_int(message.data[19:20]),8)',
        'protocol': '6',
        'verify': False,
        'force': True,
    }
    return __salt__['obd.query'](*args, **kwargs)['value']

# get location
#
def get_location():
    args = []
    kwargs = {}
    return __salt__['ec2x.gnss_nmea_gga'](*args, **kwargs)

Issues I’ve seen so far are -

  • AttributeError: ‘module’ object has no attribute ‘time’
  • OBD operations failing when they return zero. Sigh.
  • I don’t think the car_model is quite correct

So I’m pretty sure this still needs work … but sharing all the same.

02

Note that the route planner folks are interested in doing this properly - I suppose this could be a plug-in on the cloud so its very easy for all to use.

3 Likes

Added to github - see https://github.com/plord12/autopi-tools#user-content-a-better-route-planner

1 Like

Hi Peter,

I did install this on my dongle, worked stright away. Nice work :slight_smile:

One question though,

# car_model - String like:chevy:bolt:17:60:other determining what car the user has connected
data['car_model'] = 'hyundai:kona:17:64:other'

What does the “17” and “other” stand for? is that modell year? So for my e-Niro i should change to kia:eniro:19:64:other

Thank you

Good question :slight_smile: I asked the abrp folks and I found I should be using hyundai:kona:19:64:other - so I fixed that.

Full list can be found with https://api.iternio.com/1/tlm/get_carmodels_list?api_key=6f6a554f-d8c8-4c72-8914-d5895f58b1eb

Kia niro is “kia:niro:19:39:other” or “kia:niro:19:64:other”

1 Like

Hi There,

As a side question.
How does one get GPS speed?
I don’t see a field to request GPS speed anywhere.
I am avoiding the reliance on OBD speed.

Thanks

GPS speed is available as speed-over-ground (sog).

In widgets track.pos.sog.

In custom code sog_km from ec2x.gnss_location (see https://github.com/plord12/autopi-tools/blob/master/my_abrp.py ).

@plord Thanks very much Peter.

@plord Looking at ABRP forums, I’ve seen that Jason (ABRP) has recently (March15th) updated the code for AutoPi, starting from your initial code (it seems it wasn’t working correctly after thei last update).

Here’s the GitHub link: https://github.com/iternio/autopi-link

Have you tested Jason’s code so far?

Have you had any problem with your GitHub code lately? I’m testing it today on my Hyundai Kona 64kWh.
Update01: I’ve just tested your script and it works like a charm with ABRP.
Though, as ABRP interface for connecting live data has changed, I suggest you update the guide as now you have to setup Live Data as if you have a Torque enabled device

1 Like

Today with ABRP 4.0.4, the team added support and instructions to support AutoPi directly.

Jason has polished the AutoPi code in order to be able to poll every 5 seconds and greatly improve the performance of ABRP with AutoPi. I’m trying this out as soon as I can and give you a feedback.

1 Like

Any news? - I want this opportunitu, and I don’t know how to install you script.

Yes, the script has been updated and it currently works very well on Hyundai Kona and Chevrolet Bolt.

You can find AutoPi code and ABRP connection instructions here:

Moreover, the guys at ABRP are looking for support from AutoPi owners witth different vehicles, in order to be able to increase the number of compatible vehicles. :wink:

You can contact them in the following post on thier forum, dedicated to Live Data AutoPi integration:

Works like a charm on my new Kona electric MY20! :smile:

I really have no glue on setting this up on my Autopi.

Some hints? - What should I copy from Github?!?!

Trying to get this working on my TMU. Consistently fails at import requests.

There is a tutorial for live data under settings in the ABRP app