Receive charging alerts on your phone ( and smart watch )

@plord
I tried by copying your code (from the starting post above) into custom code (changing the Telegram part only):
bot_token = ‘xx523xxxxxxxT6IU’

bot_chatID = ‘12345’

And then adding the job as you did.
That is all, am i missing some part?

As it is now the autopi sleeps after a while both driving and charging (so far only charging from 230V) and sends no messages via telegram.
I had the wrong chatt id yesterday, i changed it now and tested sending messages via a browser that works. I have not yet tried it today but even if the message fails shouldn’t the dongle stay awake when charging?

Could it be that it is not compatible with Ioniq? It should be the same as fo Kona i would think.

What do you mean by; the piece detecting start and stop? Is that in the code in the first post or somewhere else?

Sorry about all the questions but i am completly new to this.

Thanks. For me, my car when turn on is ok.
Autopi detect 0,20 voltage more, so turn autaumatiquely ON the dongle. This is ok

I try a lots of timer different. But autopi shut down at 40 minute after the car turned ON.

I try everything, but it is the maximum I can.

I don’t know why.

So for short trip 40 minute < it is ok. For more, autopi go to sleep. It maybe my python code crash.

You did update today ?
What is you maximum drive with autopi ok ?

I hope we will have update soon.

Thanks.

Actually you are right, I see the same ( just didn’t pay much attention I guess ) - I do have two triggers installed - one to send me an email when the system powers on and one when it goes to sleep - so I see when this happens.

Yesterday I set off at 8am and the autopi when to sleep at 8:41 am due to inactivity fallback and woke up again at 9:24.

1 Like

Yes, once charging is detected then it should stay awake.

The detection does use the kona PID’s, so maybe there is some updates needed for the Ioniq.

I found a good source of information for charging detection is EVNotify ( https://github.com/EVNotify/EVNotify/tree/master/app/www/components/cars ) … first glance it looks like the Ioniq uses different PID to detect charging.

@plord
Hi thanks for the answer.
Is there a way to query for what PID to use?
And is there a way to to get the needed formula for it to work?

I found a spreadsheet at git hub:
https://github.com/JejuSoul/OBD-PIDs-for-HKMC-EVs/blob/4b9872eb1a0bc8b382b7aded316f94e42d15d859/Ioniq%20EV/Spreadsheet_IoniqEV_BMS_2101_2105.xls

But not clear what and how to replace in the code
If i compare the spreadsheet with an existing command, it doesn’t map clearly.
e.g. obd.query BatMaxTemp mode=21 pid=01 header=7E4 bytes=64 formula='twos_comp(bytes_to_int(message.data[16:17]),8)’ unit=C baudrate=500000 protocol=6 verify=false force=true

Below are the refences to pid’s that i found in your code.
Is it the formula and pid number that needs to be changed or is there more?

def get_driving():
try:
args = [‘driving’]
kwargs = {
‘mode’: ‘220’,
‘pid’: ‘101’,
‘header’: ‘7E4’,
‘baudrate’: 500000,
‘formula’: ‘bytes_to_int(message.data[53:54])’,
‘protocol’: ‘6’,
‘verify’: False,
‘force’: True,
}
return (int(salt[‘obd.query’](*args, **kwargs)[‘value’])&4)/4
except:
return -1

AND

def get_charging_power():
args = [‘charging_power’]
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)((bytes_to_int(message.data[15:16])*256+bytes_to_int(message.data[16:17]))/10.0)/1000.0’,
‘protocol’: ‘6’,
‘verify’: False,
‘force’: True,
}
return salt[‘obd.query’](args, **kwargs)[‘value’]-1.0

AND

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’]

One way to attack this problem is to look at the Torque Pro configurations and try a conversion to auto pi.

In this case, from https://github.com/JejuSoul/OBD-PIDs-for-HKMC-EVs/blob/master/Ioniq%20EV/extendedpids/Hyundai_Ioniq_EV_BMS_data.csv we have -

000_HV_Charging,Charging,2101,{j:7},0,1,,7E4

There are some notes here Copying txt PID file from Torque Pro about converting from Torque Pro, my first guess for this function for the Ioniq would be -

# check if we are driving.  Returns :
#   0 - charging
#   1 - driving
#   -1 - can't read data
def get_driving():
    try:
        args = ['driving']
        kwargs = {
            'mode': '21',
            'pid': '01',
            'header': '7E4',
            'baudrate': 500000,
            'formula': 'bytes_to_int(message.data[12:13])',
            'protocol': '6',
            'verify': False,
            'force': True,
        }
        # note - sums are done outside of the forumla due to autopi failing
        # with 0
        #
        return (int(__salt__['obd.query'](*args, **kwargs)['value'])&128)/128
    except:
        return -1

# get charging power
#
def get_charging_power():
    args = ['charging_power']
    kwargs = {
        'mode': '21',
        'pid': '01',
        '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)*((bytes_to_int(message.data[15:16])*256+bytes_to_int(message.data[16:17]))/10.0)/1000.0',
        'protocol': '6',
        'verify': False,
        'force': True,
    }
    return __salt__['obd.query'](*args, **kwargs)['value']*-1.0

# get display state of charge
#
def get_soc():
    args = ['soc']
    kwargs = {
        'mode': '21',
        'pid': '05',
        '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']

@plord
THANK YOU!!
I will try that now and i will later go through the links you indicated and try to understand :slight_smile:
I’ll tell you about the results.

@plord
Nah, didn’t work. But it starts to look like Ioniq is not answering on those when turned off and charging. In the my.autopi web page displays the stuff related to car with no data in range. But that could be that it lags when updating to the cloud.
I have to figure out what’s going on when the car is of.
The autpi turns off after a while driving, so there seems to be some major differences between kona and Ioniq.

hello.
strange because telegram custom code version 1 work fine
but this new one, impossible to make it working…
job vas correct, like my_telegramV2.poll
and custom was my_telegramV2
and inside python code, def poll():
all is correct.
also my token and bot_chat id, I put this from old one
you did update from this post ?
strange it is not working…
thanks

me too
not working
but telegram version 1 work fine
strange

What v1 / v2 code are you referring to ?

the v1 is the first one you post there few months ago
v2 is the new one, with gps, co2 and other feature :slightly_smiling_face:

Ah. So v1 is -

# send message to telegram
#
def bot_sendtext(bot_message):

	send_text = 'https://api.telegram.org/bot' + bot_token + '/sendMessage?chat_id=' + bot_chatID + '&parse_mode=Markdown&text=' + bot_message
 
	requests.get(send_text)

and v2 -

# send message to telegram
#
def bot_sendtext(bot_message):
	send_text = 'https://api.telegram.org/bot' + bot_token + '/sendMessage?' + urllib.urlencode({'chat_id': bot_chatID, 'parse_mode': 'Markdown', 'text': unicode(bot_message).encode('utf-8')})
	requests.get(send_text)

So the change is using urllib.urlencode() - the intention here is to encode some characters ( such as the british pound sign ) as per api spec.

Maybe it works less well with other character sets ? Not sure.

What text ( exactly ) are you sending ?

Thanks.
I exactely copy - past your post without change. ``` si this one

Only I put my token and chat_bot ID. The same as V1

import logging
import requests
import pickle
import os

log = logging.getLogger(name)

Telegram tokens - see https://www.mariansauter.de/2018/01/send-telegram-notifications-to-your-mobile-from-python-opensesame/

bot_token = ‘759619847:AAEei0EZ0z7HfGWfaazvI6SAhb2ny-zx2oU’
bot_chatID = ‘735785677’

“”"
Poll to see if car is being charged. If so :

  1. Disable auto sleep whilst charging

  2. Send Telegram message when charging starts

  3. Send Telegram message when charging reaches 80%

  4. Send Telegram message when charging reaches 90%

  5. Send Telegram message when charging reaches 100%

  6. Send Telegram message when charging stops
    “”"
    def poll():

    enable sleep in case anything goes wrong below

    enable_sleep()

    load previous status

    persistance = load()

    check if we are driving or charging

    driving = get_driving()
    if driving == 1 or driving == -1:
    if persistance[‘charging’] == True:
    bot_sendtext(“Charge arrete. Derniere charge connu “+format(persistance[‘SOC’],’.1f’)+”%”)
    persistance[‘charging’] = False
    save(persistance)
    return {“msg”: “Not charging”}

    now we are charging

    disable_sleep()
    batt_power = get_charging_power()
    soc = get_soc()

    alert if just started to charge

    if persistance[‘charging’] == False:
    bot_sendtext("Voiture en charge a "+format(batt_power,’.2f’)+“kW. Etat de la batterie “+format(soc,’.1f’)+”%”)

    70% alert

    #if soc >= 70 and persistance[‘SOC’] < 70:

    bot_sendtext("Voiture en charge a "+format(batt_power,’.2f’)+“kW. Etat de la batterie “+format(soc,’.1f’)+”%”)

    75% alert

    #if soc >= 75 and persistance[‘SOC’] < 75:

    bot_sendtext("Voiture en charge a "+format(batt_power,’.2f’)+“kW. Etat de la batterie “+format(soc,’.1f’)+”%”)

    80% alert

    if soc >= 80 and persistance[‘SOC’] < 80:
    bot_sendtext("Voiture en charge a "+format(batt_power,’.2f’)+“kW. Etat de la batterie “+format(soc,’.1f’)+”%”)

    85% alert

    #if soc >= 85 and persistance[‘SOC’] < 85:

    bot_sendtext("Voiture en charge a "+format(batt_power,’.2f’)+“kW. Etat de la batterie “+format(soc,’.1f’)+”%”)

    90% alert

    if soc >= 90 and persistance[‘SOC’] < 90:
    bot_sendtext("Voiture en charge a "+format(batt_power,’.2f’)+“kW. Etat de la batterie “+format(soc,’.1f’)+”%”)

    99.5% alert

    if soc >= 99.5 and persistance[‘SOC’] < 99.5:
    bot_sendtext("Voiture en charge a "+format(batt_power,’.2f’)+“kW. Etat de la batterie “+format(soc,’.1f’)+”%”)

    100% alert … not work because 100% is impossible

    #if soc >= 100 and persistance[‘SOC’] < 100:

    bot_sendtext("Voiture en charge a "+format(batt_power,’.2f’)+“kW. Etat de la batterie “+format(soc,’.1f’)+”%”)

    each % alert

    #lastsoc = persistance[‘SOC’]
    #for level in xrange(1, 100):
    #if soc >= level and lastsoc < level:

    bot_sendtext("Charging now at a rate of "+format(batt_power,’.2f’)+“kW. State of charge now “+format(soc,’.1f’)+”%”)

    break

    store status for next time

    persistance[‘charging’] = True
    persistance[‘SOC’] = soc
    save(persistance)

    return {“msg”: "Charging at "+format(batt_power,’.2f’)+“kW, SOC now “+format(soc,’.1f’)+”%”}

send message to telegram

def bot_sendtext(bot_message):

send_text = 'https://api.telegram.org/bot' + bot_token + '/sendMessage?chat_id=' + bot_chatID + '&parse_mode=Markdown&text=' + bot_message

log.info ("Sending message with "+bot_message);

requests.get(send_text)

load persistance

def load():
try:
persistance = pickle.load( open( ‘charge_status.p’, ‘rb’ ) )
except:
persistance = { ‘charging’: False, ‘SOC’: 0 }

return persistance

save persistance

def save(persistance):
pickle.dump( persistance, open( “charge_status.p”, “wb” ) )

delete persistance

def delete():
os.remove(“charge_status.p”)

check if we are driving. Returns :

0 - charging

1 - driving

-1 - can’t read data

def get_driving():
try:
args = [‘driving’]
kwargs = {
‘mode’: ‘220’,
‘pid’: ‘101’,
‘header’: ‘7E4’,
‘baudrate’: 500000,
‘formula’: ‘bytes_to_int(message.data[53:54])’,
‘protocol’: ‘6’,
‘verify’: False,
‘force’: True,
}
return (int(salt[‘obd.query’](*args, **kwargs)[‘value’])&4)/4
except:
return -1

get charging power

def get_charging_power():
args = [‘charging_power’]
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)((bytes_to_int(message.data[15:16])*256+bytes_to_int(message.data[16:17]))/10.0)/1000.0’,
‘protocol’: ‘6’,
‘verify’: False,
‘force’: True,
}
return salt[‘obd.query’](args, **kwargs)[‘value’]-1.0

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’]

enable autopi sleep

def enable_sleep():
args = [‘sleep’]
kwargs = {
‘enable’: True,
}
salt’power.sleep_timer’

disable autopi sleep

def disable_sleep():
args = [‘sleep’]
kwargs = {
‘enable’: False,
}
salt’power.sleep_timer’

I did try the french text from my console with v2 -

peter26@Kona $  my_charge_status.bot_sendtext "Charge arrete. Derniere charge connu 10%"
16e737229d31f230c9d241ab498c8cb8:
  return: null

and got the message on my phone.

I also tried a re-copy and paste from github to my autopi config and still got the message on my phone.

So I’m still not sure why the v2 ( ie version on github ) doesn’t work for you.

Anything useful in the logs ?

Ok.
So i will copy past this from GitHub too and doing test do be sure all is ok.
I will see the log too and tell you.
Thanks

Hi,

I’m trying to get this working with the Ioniq but I’m not sure whats wrong…

Am i translating these wrong? 000_Rapid Charge Port CCS Plug 2101 {j:6}
From what I can tell the rapid charge should be 12:13, as in J
And &2^6 as in :6

These 3 all return 1 when the car is charing at a ‘normal’ plug.

 def get_charging():
        args = ['driving']
        kwargs = {
        'mode': '21',
        'pid': '01',
        'header': '7E4',
        'baudrate': 500000,
        'formula': 'bytes_to_int(message.data[12:13])',
        'protocol': '6',
        'verify': False,
        'force': True,
        }
        return (int(__salt__['obd.query'](*args, **kwargs)['value'])&128)/128

def get_charging_chademo():
        args = ['CCS Plug']
        kwargs = {
        'mode': '21',
        'pid': '01',
        'header': '7E4',
        'baudrate': 500000,
        'formula': 'bytes_to_int(message.data[12:13])',
        'protocol': '6',
        'verify': False,
        'force': True,
        }
        return (int(__salt__['obd.query'](*args, **kwargs)['value'])&64)/64

def get_charging_normal():
        args = ['J1772 Plug']
        kwargs = {
        'mode': '21',
        'pid': '01',
        'header': '7E4',
        'baudrate': 500000,
        'formula': 'bytes_to_int(message.data[12:13])',
        'protocol': '6',
        'verify': False,
        'force': True,
        }
        return (int(__salt__['obd.query'](*args, **kwargs)['value'])&32)/32

I’ve also had no success with getting the Ignition, that should be:
000_BMS Ignition BMS Ignit. 2101 {ay:2}

def get_carState():
        args = ['driving']
        kwargs = {
        'mode': '21',
        'pid': '01',
        'header': '7E4',
        'baudrate': 500000,
        'formula': 'bytes_to_int(message.data[53:54])',  # Ignition
        'protocol': '6',
        'verify': False,
        'force': True,
        }
        return (int(__salt__['obd.query'](*args, **kwargs)['value'])&4)/4

Any tips?

These seem reasonable to my eye.

I would try dumping the whole PID in the different cases. ie in the console -

obd.query test mode=21 pid=01 force=true

I had the same issue upon using the newer version. I watch the logs and discovered that I needed to delete the old persistent data file. Once I did that, it started working.

I do have one remaining issue that I wanted to make time to fix and open a PR for, and that is a bug where if you have multiple charge sessions without using the car between, all is well at the end of the first session, but on the second session you’ll receive a message per minute with incomplete data. I only notice this because I top up with solar power where possible, so don’t always complete a charge in one go.

1 Like

Good catch, thanks. There is my_charge_status.delete for this purpose, I added this to the comment block in the script.

I’ve not seen this myself but I’ll keep an eye out for it.

1 Like