Receive charging alerts on your phone ( and smart watch )

#1

One of my objectives with the autopi is to receive alerts on my phone relating to charging.

For example, you stop off for lunch and a rapid charge, if the charge fails or completes, it would be great to get a notification … nothing worse than checking the car after 1 hour to find it failed after 10mins.

Before I start, this is definitely work-in-progess. Fixes, improvements, better ideas more than welcome ! I’ll update this post with changes as needed.

I figured telegram would be a good choice of app to sent alerts to - wide support and easy to integrate to. However, you will need to get a token and chatid - see https://www.mariansauter.de/2018/01/send-telegram-notifications-to-your-mobile-from-python-opensesame/ for some info.

Anyways, the idea is to have a custom script that is periodically run that -

  1. Checks if the car is charging
  2. Sends telegram message when charging starts
  3. Sends telegram message when charging reaches 80%
  4. Sends telegram message when charging reaches 100%
  5. Sends telegram message when charging stops
  6. Disables sleep whilst charging

I created my_charge_status custom code -

Custom code is -

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 = 'xxx'
bot_chatID = 'xxx'

"""
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 100%
5. 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("Charging stopped. Last known State of charge "+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("Charging started at a rate of "+format(batt_power,'.2f')+"kW. State of charge now "+format(soc,'.1f')+"%")

    # 80% alert
    #
    if soc >= 80 and persistance['SOC'] < 80:
        bot_sendtext("Charging now at a rate of "+format(batt_power,'.2f')+"kW. State of charge now "+format(soc,'.1f')+"%")

    # 100% alert ... not sure if this can really happen
    #
    if soc >= 100 and persistance['SOC'] < 100:
        bot_sendtext("Charging now at a rate of "+format(batt_power,'.2f')+"kW. State of charge now "+format(soc,'.1f')+"%")

    # 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
 
	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'](**kwargs)

# disable autopi sleep
#
def disable_sleep():
    args = ['sleep']
    kwargs = {
        'enable': False,
    }
    __salt__['power.sleep_timer'](**kwargs)

( hopefully this made in without format errors ! )

You’ll need to setup telegram, get your own bot_token and chatid - see link above.

I’m running this as a scheduled job every 10 mins -

I’m not entirly sure what to set the autopi sleep times to - but given I’m polling every 10mins, I’ve set -

  • Inactivity fallback period to 900 seconds ( 15mins )
  • Inactivity after sleep period to 900 seconds ( 15 mins )

On my phone I get alerts such as -

( last message should have been 100%, at the time I was using SOC BMS instead of SOC Display )

Since its on the phone, the usual smart watch notifications can be used -

One problem with the Kona Electric is that it takes so long to discharge the battery that testing this takes days :slight_smile: Still, big journey today so I can do some more testing tonight.

As I said that the beginning, fixes, improvements, better ideas more than welcome.

9 Likes
So, where are we?
What actually works?
#2

@plord
Hello.
Thanks you. It is good idea.
I try to do now
i had my token and all things from telegram
but.

where we put all entire code ? in the custom code or jobs ?
Ps: I will share my project too but still no working yet.

#3

@plord
like that ?

#4

Yes.

But the name of the function in the jobs should be name.function. So in my case I have -

So I would use my_charge_status.poll

1 Like
#5

Added work-around for autopi not returning 0 - original post updated.

#6

Thank’s

#7

Of course it would be a good cloud feature to send alerts in configurable cases (without custom code)

2 Likes
#8

I did all same as you but seem not work …

#9

@plord
mmmm, still not working …

49

#10

Your chatid doesn’t look right to me. Maybe check https://www.forsomedefinition.com/automation/creating-telegram-bot-notifications/ and try a test in your desktop browser -

https://api.telegram.org/bot$TOKEN/sendMessage?chat_id=CHATID&text=Hello+World

1 Like
#11

ha, I make mistenderstood, it is not a name ID “Abcd_bot” but a number ID like “1234”
I make test with postman, and saw it.
all it work great. I just should test with the car now
anyway thanks

#12

@plord
sorry to bother you again :sweat_smile:
Wich is right ?


or

or

many thanks:grimacing:

#13

This is what I have for logging to the minion log -

import logging
import requests
import pickle
import os

log = logging.getLogger(__name__)

Then when I want to use the logger -

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)

I do have my autopi set to log at INFO level BTW.

( plain text custom code is in the first post BTW, so you should be able to cut and paste and add your own telegram id’s )

3 Likes
#14

Nice to read about this! I’m having the same idea. I’ll try your solution. In the long run I would like to build a dedicated app for this but Telegram seems like a very good start. Great work @plord!

1 Like
#15

Yea, I was thinking about an app as well. One idea is to update EVnotify to use the autopi API ( as well as the existing bluetooth ). I might leave that to someone else though :slight_smile:

#16

I’m thinking about setting up a cloud api that will receive typical EV info and build a simple app that will display and notify about this info. This way we can use Autopi with one app for any EV. I’m always a little too optimistic about my project though :slight_smile:

#17

@plord
all work fine :grinning:

3 Likes
#18

Yea !

You just now need to do a translation :slight_smile:

2 Likes
#19

yes, I will do it. :sweat_smile:
Good job !
i have also my Apple Watch working
IMG_3018

#20

I also got this working (for e-Niro) using the Telegram bot. Kudos @pIord! I must say that you have made a fantastic work. So happy that you shared this with the community. It’s hard to understand that Hyundai/Kia did not manage to put out a service/app when @plord manages this from his couch :smile:

One thing I noticed is that I get a lower value for current charging speed than what is showing in the car. Not a big issue, the most important thing is to know if the car is charging or not.

3 Likes