jlrpy
jlrpy copied to clipboard
Charging curve or other charging details
thx @ardevd , you did an excellent job providing this lib! I am running this on my brand new Jaguar I-Pace now.
As I want to know more about the charging behaviour and compare e.g. like this Example Charging Curves the charging details about power, current, and SoC are required.
Up to now I could not find it. Did I miss something?
Glad to hear you're finding it useful.
I think get_status()
should give you at least some of the information you're after.
>>> v.get_status("EV_STATE_OF_CHARGE")
'74' # 74% SoC
>> > v.get_status("EV_CHARGING_RATE_KM_PER_HOUR")
'10'
I don't immediately see any indication of charging current or power though but considering how neither the app or car (IVI) reveals this either I'm not too sure the API provides that information currently.
Thx for your super quick answer. This is a starting point.
- How often can I call
get_status()
- Do you know what EV_CHARGING_RATE_KM_PER_HOUR really means?
I also share your impression that the API and I-Pace system is not made for too much information about the charging status.
I'm not aware of any limitations on how often you can call get_status()
but the API is a bit quirky so I wouldn't be surprised to find that there might be some sort of rate limitation in there.
I'm assuming EV_CHARGING_RATE_KM_PER_HOUR
means the same thing it means when it shows up in the vehicle. It's the number of kilometers of range being "added" to your battery every hour of charging. The value obviously reflects the current charging rate but instead of showing us what the rate is it's being converted into kilometers per hour.
OK - makes sense. Hence, EV_CHARGING_RATE_KM_PER_HOUR
also depends on our driving style ;-)
Right now I am charging with 7.2kW and tracking changes via get_status()
: This one looks interesting
{ "key": "EV_CHARGING_RATE_SOC_PER_HOUR", "value": "1.0" },
It is not consistent with the car display. There I have right now:
State-of-Charge 95%
Time left for charing: 58 Minutes
at least { "key": "EV_MINUTES_TO_FULLY_CHARGED", "value": "58" },
is consistent
After a view minutes
{ "key": "EV_CHARGING_RATE_SOC_PER_HOUR", "value": "6.8" },
is getting more consistent. I have calculated 8.5
instead of 6.8
Interesting! So no easy way to calculate charging current then?
Looks more complicated than I thought... I will do a more detailed analysis which data points change how over the charging process. What I have understood already that polling the status too often does not give more insights. You simply receive a status that is identical to the former status. The update of status from the vehicle is between 5-30 minutes.
Maybe we should croud-source more data in order to get "broader wisdom" ;-)
Based on the example script Charge Off-Peak
I am logging now every 5 minutes. As I am a Python beginner your review and honest feedback is welcome ;-)
# -*- coding: utf-8 -*-
"""Charge logging script
This script will download the get_vehicle_status every 5 minutes
and log them locally. Based on the Charge Off-Peak script.
"""
import jlrpy
import threading
import datetime
import math
from datetime import date
import os
import configparser
logger = jlrpy.logger
def check_soc():
"""Retrieve vehicle status.
"""
threading.Timer(5*60.0, check_soc).start() # Called every 5 minutes
# getting status update
status = { d['key'] : d['value'] for d in v.get_status()['vehicleStatus'] }
current_soc = int(status['EV_STATE_OF_CHARGE'])
charging_status = status['EV_CHARGING_STATUS']
logger.info("current SoC is "+str(current_soc)+"%")
if status['EV_CHARGING_METHOD'] == "WIRED":
logger.info("car is plugged in")
logger.info("charging status is "+charging_status)
p = v.get_position()
position = (p['position']['latitude'], p['position']['longitude'])
logger.info("car geo-position is "+str(position))
t = datetime.datetime.now()
clogfilename = "charging-log_" + t.strftime("%Y-%m-%d_%H-%M-%S") + ".json"
clogfile= open(clogfilename,"w+")
logger.info("writing charging log file " + clogfilename)
# getting health status forces a status update
healthstatus = v.get_health_status()
status = { d['key'] : d['value'] for d in v.get_status()['vehicleStatus'] }
clogfile.write(str(status))
clogfile.close()
else:
logger.info("car is not plugged in")
config = configparser.ConfigParser()
configfile = os.environ['HOME']+"/.jlrpy.ini"
config.read(configfile)
username = config['jlrpy']['email']
password = config['jlrpy']['password']
home = (float(config['jlrpy']['home_latitude']), float(config['jlrpy']['home_longitude']))
c = jlrpy.Connection(username, password)
v = c.vehicles[0]
logger.info("[*] Logging vehicle status")
check_soc()
Did some more smaller changes to the script above and now I am confident that I can log one json file for each time stamp.
Next step is to make a time-series out of this. What would you recommend?
Time-Series data
- bundle one charging process in a
panda
time series in the above loop - read each logged json with a separate python script
- store json data in a database:
mongoDB
orinflux
? - ....
Visualization
-
grafana
- plot with
R
-
Gnuplot
- ...
Happy for any help or sample code
here is which attributes I will store in a time series database
'BATTERY_VOLTAGE': '13.8',
'DISTANCE_TO_EMPTY_FUEL': '0',
'EV_BATTERY_PRECONDITIONING_STATUS': 'OFF',
'EV_CHARGE_NOW_SETTING': 'DEFAULT',
'EV_CHARGE_TYPE': 'UNKNOWN',
'EV_CHARGING_METHOD': 'WIRED',
'EV_CHARGING_MODE_CHOICE': 'TIMEDCHARGINGNOTACTIVE',
'EV_CHARGING_RATE_KM_PER_HOUR': '315',
'EV_CHARGING_RATE_MILES_PER_HOUR': '195',
'EV_CHARGING_RATE_SOC_PER_HOUR': 'UNKNOWN',
'EV_CHARGING_STATUS': 'FULLYCHARGED',
'EV_ENERGY_CONSUMED_LAST_CHARGE_KWH': '63',
'EV_IS_CHARGING': 'UNKNOWN',
'EV_IS_PLUGGED_IN': 'UNKNOWN',
'EV_IS_PRECONDITIONING': 'UNKNOWN',
'EV_MINUTES_TO_BULK_CHARGED': '10',
'EV_MINUTES_TO_FULLY_CHARGED': '10',
'EV_ONE_OFF_MAX_SOC_CHARGE_SETTING_CHOICE': 'CLEAR',
'EV_PERMANENT_MAX_SOC_CHARGE_SETTING_CHOICE': 'CLEAR',
'EV_PHEV_RANGE_COMBINED_KM': '-1',
'EV_PHEV_RANGE_COMBINED_MILES': '-1',
'EV_PRECONDITIONING_MODE': 'INACTIVE',
'EV_PRECONDITION_FUEL_FIRED_HEATER_SETTING': 'DISABLED',
'EV_PRECONDITION_OPERATING_STATUS': 'OFF',
'EV_PRECONDITION_PRIORITY_SETTING': 'PRIORITIZE_COMFORT',
'EV_PRECONDITION_REMAINING_RUNTIME_MINUTES': '0',
'EV_RANGE_COMFORTx10': '357.3',
'EV_RANGE_ECOx10': '366.0',
'EV_RANGE_GET_ME_HOMEx10': '373.4',
'EV_RANGE_ON_BATTERY_KM': '357',
'EV_RANGE_ON_BATTERY_MILES': '222',
'EV_RANGE_PREDICT_STATUS': 'DISPLAY_RANGE',
'EV_RANGE_VSC_HV_BATTERY_CONSUMPTION_SPD1': '178',
'EV_RANGE_VSC_HV_BATTERY_CONSUMPTION_SPD2': '160',
'EV_RANGE_VSC_HV_BATTERY_CONSUMPTION_SPD3': '124',
'EV_RANGE_VSC_HV_BATTERY_CONSUMPTION_SPD4': '190',
'EV_RANGE_VSC_HV_BATTERY_CONSUMPTION_SPD5': '298',
'EV_RANGE_VSC_HV_BATTERY_CONSUMPTION_SPD6': '400',
'EV_RANGE_VSC_HV_BATTERY_CONSUMPTION_SPD7': '652',
'EV_RANGE_VSC_HV_ENERGY_ASCENTx10': '7.0',
'EV_RANGE_VSC_HV_ENERGY_DESCENTx10': '5.0',
'EV_RANGE_VSC_HV_ENERGY_TIME_PENx100': '0.93',
'EV_RANGE_VSC_INITIAL_HV_BATT_ENERGYx100': '83.85',
'EV_RANGE_VSC_RANGE_MAP_REFACTR_COMF': '98',
'EV_RANGE_VSC_RANGE_MAP_REFACTR_ECO': '100',
'EV_RANGE_VSC_RANGE_MAP_REFACTR_GMH': '102',
'EV_RANGE_VSC_REGEN_ENERGY_AVAILABLEx100': '0.0',
'EV_RANGE_VSC_REGEN_ENERGY_FACTOR': '0',
'EV_RANGE_VSC_REVISED_HV_BATT_ENERGYx100': '83.85',
'EV_RANGE_VSC_VEH_ACCEL_FACTOR': '410',
'EV_STATE_OF_CHARGE': '100',
'ODOMETER': '696000',
'ODOMETER_METER': '696000',
'ODOMETER_METER_RESOLUTION': 'true',
'ODOMETER_MILES': '432',
'ODOMETER_MILES_RESOLUTION': 'false',
'TRANSPORT_MODE_START': '2019-05-01T12:39:51+0000',
'TRANSPORT_MODE_STOP': '2019-05-01T16:39:51+0000',
'TU_STATUS_POWER': 'MAIN_BATTERY',
'TU_STATUS_PRIMARY_CHARGE_PERCENT': '90',
'TU_STATUS_PRIMARY_VOLT': '4.1000000000000005',
'TU_STATUS_SECONDARY_VOLT': '0.0',
'TU_STATUS_SERIAL_NUMBER': '809VICL758219',
'TU_STATUS_SLEEP_CYCLES_START_TIME': '2019-05-18T13:19:24.000Z',
Looks good to me :) good luck and keep us posted.
With my collected charging data I came to the conclusion that remote preheating/precooling while the Jaguar is AC charging 'EV_CHARGING_METHOD': 'WIRED'
consumes the energy from the battery and not from the power line. Details in the next post.
Can you confirm this behaviour with your Jaguar?
results of DIFF
<
1. Status: Fully charged, Wired, no cooling
>
2. Status: Fully charged, Wired, cooling running for 1 Min
< 'BATTERY_VOLTAGE': '13.7',
> 'BATTERY_VOLTAGE': '15.7',
---
< 'BRAZIL_EVENT_MODE': 'FALSE',
> 'BRAZIL_EVENT_MODE': 'UNKNOWN',
---
< 'CLIMATE_STATUS_OPERATING_STATUS': 'OFF',
> 'CLIMATE_STATUS_OPERATING_STATUS': 'HEATING',
---
< 'ENGINE_BLOCK': 'NORMAL_UNBLOCKED',
> 'ENGINE_BLOCK': 'UNKNOWN',
---
< 'EV_BATTERY_PRECONDITIONING_STATUS': 'OFF',
> 'EV_BATTERY_PRECONDITIONING_STATUS': 'COOLING',
---
< 'EV_ENERGY_CONSUMED_LAST_CHARGE_KWH': '50',
> 'EV_ENERGY_CONSUMED_LAST_CHARGE_KWH': '0',
---
< 'EV_PRECONDITIONING_MODE': 'INACTIVE',
> 'EV_PRECONDITIONING_MODE': 'IMMEDIATE',
---
< 'EV_PRECONDITION_OPERATING_STATUS': 'OFF',
> 'EV_PRECONDITION_OPERATING_STATUS': 'PRECLIM',
---
< 'EV_PRECONDITION_REMAINING_RUNTIME_MINUTES': '0',
< 'EV_RANGE_COMFORTx10': '367.0',
< 'EV_RANGE_ECOx10': '374.4',
< 'EV_RANGE_GET_ME_HOMEx10': '381.9',
< 'EV_RANGE_ON_BATTERY_KM': '367',
< 'EV_RANGE_ON_BATTERY_MILES': '228',
---
> 'EV_PRECONDITION_REMAINING_RUNTIME_MINUTES': '29',
> 'EV_RANGE_COMFORTx10': '358.2',
> 'EV_RANGE_ECOx10': '367.0',
> 'EV_RANGE_GET_ME_HOMEx10': '374.4',
> 'EV_RANGE_ON_BATTERY_KM': '358',
> 'EV_RANGE_ON_BATTERY_MILES': '222',
---
< 'EV_RANGE_VSC_RANGE_MAP_REFACTR_COMF': '100',
< 'EV_RANGE_VSC_RANGE_MAP_REFACTR_ECO': '102',
< 'EV_RANGE_VSC_RANGE_MAP_REFACTR_GMH': '104',
> 'EV_RANGE_VSC_RANGE_MAP_REFACTR_COMF': '98',
> 'EV_RANGE_VSC_RANGE_MAP_REFACTR_ECO': '100',
> 'EV_RANGE_VSC_RANGE_MAP_REFACTR_GMH': '102',
---
< 'EV_RANGE_VSC_REVISED_HV_BATT_ENERGYx100': '83.95',
> 'EV_RANGE_VSC_REVISED_HV_BATT_ENERGYx100': '83.9',
---
< 'LOGTIMESTAMP': '2019-07-14T08: 53: 17.962754'
> 'LOGTIMESTAMP': '2019-07-14T08: 58: 17.958063'
results of DIFF
<
1. Status: Fully charged, Wired, before cooling
>
2. Status: Fully charged, Wired, after cooling finished
< 'BATTERY_VOLTAGE': '13.7',
> 'BATTERY_VOLTAGE': '15.3',
---
< 'EV_ENERGY_CONSUMED_LAST_CHARGE_KWH': '50',
> 'EV_ENERGY_CONSUMED_LAST_CHARGE_KWH': '7',
---
< 'EV_RANGE_COMFORTx10': '367.0',
< 'EV_RANGE_ECOx10': '374.4',
< 'EV_RANGE_GET_ME_HOMEx10': '381.9',
< 'EV_RANGE_ON_BATTERY_KM': '367',
< 'EV_RANGE_ON_BATTERY_MILES': '228',
> 'EV_RANGE_COMFORTx10': '358.2',
> 'EV_RANGE_ECOx10': '367.0',
> 'EV_RANGE_GET_ME_HOMEx10': '374.4',
> 'EV_RANGE_ON_BATTERY_KM': '358',
> 'EV_RANGE_ON_BATTERY_MILES': '222',
---
< 'EV_RANGE_VSC_INITIAL_HV_BATT_ENERGYx100': '83.95',
< 'EV_RANGE_VSC_RANGE_MAP_REFACTR_COMF': '100',
< 'EV_RANGE_VSC_RANGE_MAP_REFACTR_ECO': '102',
< 'EV_RANGE_VSC_RANGE_MAP_REFACTR_GMH': '104',
> 'EV_RANGE_VSC_INITIAL_HV_BATT_ENERGYx100': '83.75',
> 'EV_RANGE_VSC_RANGE_MAP_REFACTR_COMF': '98',
> 'EV_RANGE_VSC_RANGE_MAP_REFACTR_ECO': '100',
> 'EV_RANGE_VSC_RANGE_MAP_REFACTR_GMH': '102',
---
< 'EV_RANGE_VSC_REVISED_HV_BATT_ENERGYx100': '83.95',
> 'EV_RANGE_VSC_REVISED_HV_BATT_ENERGYx100': '83.75',
---
< 'LOGTIMESTAMP': '2019-07-14T08:53:17.962754'
> 'LOGTIMESTAMP': '2019-07-14T09:28:17.873646'
---
< 'TU_STATUS_CAN': 'UNCERTAIN',
> 'TU_STATUS_CAN': 'FUNCTIONING',
I read from this that 7kWh are consumed in 30 Min to cool the car and that range dropped from 367km to 358km. If this is correct the Jaguar looses one of the biggest electric vehicle advantages: remote precooling/preheating via the charging station
Very interesting! I'll forward this to a concerned party.
Unfortunately I'm currently out of the country so I am unable to conduct the same experiment with my own vehicle until I get back in a couple of weeks. I'm eager to see what happens though.
I did several more changes to the posted code. We have to options two share it
- [ ] make it part of your codebase at
github.com/ardevd/jlrpy/tree/master/examples
- [x] host it under my GitHub in a new repository
github.com/stefferber?tab=repositories
What would you prefer?
I'm happy either way but I reckon it makes more sense to merge it with this repo. Agree?
Yes. Please check out my code quality - probably needs some improvement
jaguar-charging.py
and then we move it...
First plot is done...
How is EV_CHARGING_RATE_SOC_PER_HOUR
define?
Probably it is the Percentage of the batty charged per hour:
7% * 84.7 kWh => 5.9 kW per hour
Do you agree?
Code for visualization is here jaguar-charging-viz.py
more data
For your reference: https://support.fastned.nl/hc/de/articles/360000788848-Laden-mit-einem-Jaguar-I-PACE
The best quick charging experience at INOITY 380kW charging station
INONITY-Himmelkron with a short interruption
And a typical charging at my home with Mennekes 22kW here only max 7.2kW
Added GPS logging, did some more bug fixing, and a bit more robustness. A sample time series is also included. Still this is very much happy path engineering... Ready for your code review github.com/stefferber/jaguar
While empirical scanning through the data I found the battery energy in kWh ;-)
EV_RANGE_VSC_INITIAL_HV_BATT_ENERGYx100
EV_RANGE_VSC_REVISED_HV_BATT_ENERGYx100
Which correlates nicely with
EV_STATE_OF_CHARGE
as you can see in the attached chart. My max turns out to be 85 kWh.
Now there is only one more mystery left:
How to calculate the real charging power in kW from EV_CHARGING_RATE_SOC_PER_HOUR
in %.
@stefferber I've played with that earlier but the values I got did not correlate with what I expected. If you figure it out, that would be awesome :)
@stefferber also, what's the difference between EV_RANGE_VSC_INITIAL_HV_BATT_ENERGYx100 and EV_RANGE_VSC_REVISED_HV_BATT_ENERGYx100?
I can only guess the difference between INITAL
and REVISED
. Maybe it is model the ageing of the battery? If you look at the chart above there is hardly a difference between the two.
Do you want me to do a formal correlation analysis for EV_STATE_OF_CHARGE
and EV_RANGE_VSC_INITIAL_HV_BATT_ENERGYx100
. Shouldn't be that difficult with python...
Sure, that would be very interesting actually. :)
SaaS = Statistics-as-a-Service ;-)
print(timeseries['EV_STATE_OF_CHARGE'].corr(timeseries['EV_RANGE_VSC_INITIAL_HV_BATT_ENERGYx100']))
print(timeseries['EV_STATE_OF_CHARGE'].corr(timeseries['EV_RANGE_VSC_REVISED_HV_BATT_ENERGYx100']))
print(timeseries['EV_RANGE_VSC_INITIAL_HV_BATT_ENERGYx100'].corr(timeseries['EV_RANGE_VSC_REVISED_HV_BATT_ENERGYx100']))
results in
0.9955738575736692
0.995446940831017
0.9999284070411001
no doubt - the data is highly correlated
... which leads to the idea of a correlation map like this https://medium.com/@sebastiannorena/finding-correlation-between-many-variables-multidimensional-dataset-with-python-5deb3f39ffb3 ... next week. Will be in the mountains the next 3 days ;-)
Correlation map is ready. Needs you and other eyes to gather insights
White spots are due to "NaN" correlation. This datasets have Zero variance and therefore correlation is not defined.
Ready. Reverting to my original posted question I have (almost) all the information I was looking for.
As I don't want to run my Mac around the clock I collect the data with my raspberry and fetch the log files with sftp.
import os
import paramiko
rserver = "raspberrypi"
ruser = "pi"
rpassword ="<your-password>"
rdirectory_charging_log = "/home/pi/logs/"
directory_charging_log = "/Users/<your-user>/logs/"
ssh = paramiko.SSHClient()
ssh.load_host_keys(os.path.expanduser(os.path.join("~", ".ssh", "known_hosts")))
ssh.connect(rserver, username=ruser, password=rpassword)
sftp = ssh.open_sftp()
rfiles = sftp.listdir(rdirectory_charging_log)
rfile = ""
for rfile in rfiles:
sftp.get(rdirectory_charging_log+rfile, directory_charging_log+rfile)
sftp.close()
ssh.close()
Here is the complete "picture"
Open issues:
- [ ] pairing charging-logs from Jaguar with .csv-file of Charge-Point-Operators
- [ ] exception handling: most is happy path programming
- [ ] adjust logging frequency to charging speed
- [ ] adding additional parameters to
.jlrpy.ini
- [ ] Code review
Now let's discuss how we can merge with jlrpy. Ready for a google hangout, Skype, or Zoom session?
This is awesome man. Sadly, I am also terribly busy but lets do a Google Hangout session for sure. Let's coordinate it on Gitter?
Played around with interactive vizualization and added plot.ly
. One example
Will share this as 3 MByte
.html
soon
Could you please check if you have access to this online chart
Hi @stefferber , Did you figure out what the 'EV_RANGE_VSC_INITIAL_HV_BATT_ENERGYx100' is ? On my car, the 'EV_RANGE_VSC_INITIAL_HV_BATT_ENERGYx100' = 102.35 and 'EV_RANGE_VSC_REVISED_HV_BATT_ENERGYx100' would go up to 85 ?
is EV_RANGE_VSC_REGEN_ENERGY_AVAILABLEx100 a absolute or relative value ? If I sum 'EV_RANGE_VSC_REVISED_HV_BATT_ENERGYx100' and EV_RANGE_VSC_REGEN_ENERGY_AVAILABLEx100, it is way above the 85kwh. I though EV_RANGE_VSC_REGEN_ENERGY_AVAILABLEx100 was the amount of kWh in the battery the regen can use.