A better route planner

#1

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.

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
Traccar support
#2

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

1 Like
#3

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

#4

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
#5

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

#6

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 ).

#7

@plord Thanks very much Peter.