My Nissan Leaf 2021 OBD2/ELM327/Bluetooth adventure...

My Nissan Leaf Forum

Help Support My Nissan Leaf Forum:

This site may earn a commission from merchant affiliate links, including eBay, Amazon, and others.

pmbdk

Well-known member
Joined
Dec 27, 2023
Messages
72
So I am trying to figure out how to communicate with my Leaf over the OBD2 using a bluetooth dongle. Leaf spy pro works fine, so I know it can be done. I simply want to extract battery information (SoC, SoH, cell voltages, temperatures) automatically and send it to my EVSE for optimal charging. I have BT communication up and running and can communicate with the embedded ELM327 chip using a raaspberry pi. But I cant seem to figure out what to send to the Leaf to get some data back. After several days of frustratingly searching the internet to no avail, I joined my first ever patreon to get into Dala's discord server to see if anyone could help me there.

Unfortunately no one could.

So I dismantled a OBD2 WiFi dongle I had laying around (it uses the same ELM327 as all other OBD2 dongles), found out where ground/power/signal lines were, and hooked up a digital analyzer to the two serial lines going from the WiFi module to the ELM327. I then connected Leaf Spy Pro in order to see which data was actually being sent/received.

I am now sitting with a very long trace I need to analyze, but it's a start. I am sure there is an easier way than reverse engineering what has already been done, but I just can't seem to find the right, complete information out there. So this is where I am...
 
So finally I got it figured out. The trace definitely helped me understand how to use the ELM327. The missing part was the ATFCSH/ATFCSD/ATFCSM sequence. Now I actually get data.

The following is what I have now, but I think everything will be fine now, just following the CAN polling documentation at Dala's repository.

# End-of-line: 0x0D
# OK0x0D0D> will be returned after each command unless otherwise noted
# Turn on echo
ATE1
# Reset
ATZ
>0xFC
>0x0D0D
>ELM327 v1.5
>
# Turn off echo
ATE0
# Turn off linefeeds
ATL0
# Information
ATI
>ELM327 v1.5
# Sets the protocol to ISO 15765-4 CAN (11 bit ID, 500 kbaud)
ATSP6
# Turns on headers in the responses
ATH1
# Turns off spaces in the output
ATS0
# Turns off automatic formatting of CAN messages, allowing for raw CAN data to be seen
ATCAF0
# Read 12V battery voltage
ATRV
>14.5V
# Sets the header for subsequent messages to 797 (Vehicle Control Module/VCM)
ATSH797
# Sets the Flow Control header to VCM, preparing the device for sending flow control frames to VCM.
ATFCSH797
# Sets the Flow Control data to "30 00 00". "30" is the Flow Control frame type indicating "Continue to Send", and "00 00" specifies no separation time between frames.
ATFCSD300000
# Sets the Flow Control mode to 1, which means the ELM327 will send a flow control frame before starting the transmission of data frames.
ATFCSM1
# ???Appears to be a request for data. The "02" is the length, but the rest is not covered in the data documentation
0210C0
# The below response is from the VCM (VCM response ID is 79A)
# No idea what it is though
>79A0250C00000000000
# Power switch status
03221304
# data[4]%128 == 0? The car was actually turned on here, soooo???
>79A0562130408FE0000
# Gear position
03221156
# data[4]==1 => park
>79A0462115601000000
 
Last edited:
So finally I got it figured out. The trace definitely helped me understand how to use the ELM327. The missing part was the ATFCSH/ATFCSD/ATFCSM sequence. Now I actually get data.

The following is what I have now, but I think everything will be fine now, just following the CAN polling documentation at Dala's repository.

Glad you got it figured out :) I think maybe the part that tripped you up is abstraction from the CAN bus provided by the (now defunct) ELM327 (or clone)? That hassle is a side-effect of using an OBD style BLE dongle. For anyone reading, the AT commands are documented on page 9 of the PDF here [1]

But even once you are past the hassles of the ELM abstraction and having to deal with it's very limited receive capability and constant re-polling of queries that are lost etc, in taking this hardware approach you are still limiting yourself to only obtaining data through OBD style UDS query/response CAN frame. These are the only frames that the car's onboard CAN gateway (in model year 2018+) will bridge onto the CAN bus that is terminated at the OBD port.

By dropping access through that port and moving to a direct CAN interface adapter on the bus not the OBD port, you gain a whole plethora of 'broadcast' traffic that is sent continuously on the main bus without having to do any polling. You can still send OBD style UDS packets to individual ECUs via the same bus for specific metrics if you wish, but many of the ones you seek are already being continually broadcast.

I realise you specifically wanted to use BLE hardware, and unfortunately I'm not aware of any BLE CAN adapters to recommend, although I'm sure someone out there must make one. I built my solution using the ESP32 platform with wifi.

I'm not on the Patreon but if you post any problems you've having here I'll try to help out :)

[1] https://www.elmelectronics.com/DSheets/ELM327DSH.pdf
 
Thanks! I do however hope that all I need is the documentation at the link below. My main problem was how to communicate with the ELM327 chip, which is not a problem now. I will try to make a small python program for interpreting all the data and run it on a pico so I can easily sent it using MQTT fro mwhere my EVSE control will pick up, and optimally charge my Leaf depending on temperature, price, SoC, etc.

 
But even once you are past the hassles of the ELM abstraction and having to deal with it's very limited receive capability and constant re-polling of queries that are lost etc, in taking this hardware approach you are still limiting yourself to only obtaining data through OBD style UDS query/response CAN frame. These are the only frames that the car's onboard CAN gateway (in model year 2018+) will bridge onto the CAN bus that is terminated at the OBD port.
Yes, I am aware that using polling only, I do not get access to all the data. On the other hand for my project - where I only need SoC, SoH, cell voltages and odometer from time to time that's really not a problem. Using a 10$ dongle with a 7$ microcontroller to do this without trying to gain access to CAN-busses hidden within my EV seems like the best/cheapest approach for that project. :)
 
As far as I know, OVMS does not support the 2018+ versions of Leaf

The approach they use for decoding many of the metrics available in earlier years still works fine when obtaining them from broadcast traffic on the main CAN bus. It's mainly the OBD queries that changed in my experience. I use the same SoC decoder for both my MY2017 and MY2018 for example :)
 
Yes, I am aware that using polling only, I do not get access to all the data. On the other hand for my project - where I only need SoC, SoH, cell voltages and odometer from time to time that's really not a problem. Using a 10$ dongle with a 7$ microcontroller to do this without trying to gain access to CAN-busses hidden within my EV seems like the best/cheapest approach for that project. :)
Absolutely! :) Don't get me wrong, my approach was cheap too. My micro was NZD$5 plus about the same for the 12V-5V switchmode power module. It's also actually very easy to access the CAN bus from under a panel near the foot well on the passengers side - just 2 wires for CAN and there is also 12V and GND available there too. And as I said it was much easier for me to write code to pluck the data from existing frames than have to do a whole polling engine with query tracking etc, plus my OBD port remains available for.. well, OBD! :) But each to their own. I'm glad you got it working. Well done.
 
Absolutely! :) Don't get me wrong, my approach was cheap too. My micro was NZD$5 plus about the same for the 12V-5V switchmode power module. It's also actually very easy to access the CAN bus from under a panel near the foot well on the passengers side - just 2 wires for CAN and there is also 12V and GND available there too. And as I said it was much easier for me to write code to pluck the data from existing frames than have to do a whole polling engine with query tracking etc, plus my OBD port remains available for.. well, OBD! :) But each to their own. I'm glad you got it working. Well done.
Well, once I have this working I am sure I will miss all the other data in any case... ;-) So I would be happy if you can share details on how/where to look. Having it all on the passenger side has definite advantages too! :)
 
Well, once I have this working I am sure I will miss all the other data in any case... ;-) So I would be happy if you can share details on how/where to look. Having it all on the passenger side has definite advantages too! :)

Sure! See here:

 
Thanks. :) I would also just like to say that this is exactly why I would _not_ want to do this as the first thing just to get the SoC data... Connecting to the OBD2 connector is a whole lot easier than removing the panels to get hold of the wires... :)
 
Thanks. :) I would also just like to say that this is exactly why I would _not_ want to do this as the first thing just to get the SoC data... Connecting to the OBD2 connector is a whole lot easier than removing the panels to get hold of the wires...

I think that if i had a module permanently installed in my OBD port I'd knock it out with my big knees every day ;-)
 
So BLE communication is now working from my normal Raspberry Pi to the OBD2 dongle. Since I also had a WiFi dongle laying around I wanted support for that as well (because BLE on a Raspberry Pi Pico is not really well supported and I want to use the Pico). So this also works now, but for fun I just tried to measure the power consumption during idle. 70 mA!!!! Wtf!!!!! That's like almost 1W of continuous power usage. I wonder how much the BLE dongle uses; have to measure that tonight. It is easily solvable by have a pair of transistors turning it off, but this then requires me to extend the wires from the OBD2 port. And then we are back to why not just hack into the (unbridged) CAN bus. But hey, now I want this to work... ;-)
 
I think that if i had a module permanently installed in my OBD port I'd knock it out with my big knees every day ;-)
You can buy (for very cheap online - AliExpress) right-angle OBD2 extension cables that will plug into the OBD2 port and only extend a few millimeters downwards. This is in fact how I am getting 12V power to my solution.
 
hey PMBDK, I found your thread while going through my own ELM327 headache. I bought the Freematics OBD@ to arduino adapter. planning on only grabbing the vehicle speed, and throttle pos. Well its be interested for a few weeks. But stumbling upon your thread helped a bit, I have been struggling to talk to my ELM327 chip inside the freematic adapter. So Im using your quoted list of AT commands to get data out. I seem to get stuck on the ATSH797 commands on. ( which you kinda eluded to be your holy grail moment for getting actually data...... Im not having my moment)

I am having an issue trying to find the syntax used for programming the commands. currently in the arduino environment I am providing "ATZ\r" \r being carriage return. when I try to send "ATSH797\r" I get a "?". basically anything asking detailed can data it tends to give me "?"

Im sending 7 AT commands in series completely fine with "ok" response ( first 7 in your list )

Im not asking you to fix my project at all. I would like to discuss the syntax for the AT commands. I think im getting the order wrong. as some commands influence the commands after them. You posted a list of how you GOT data, but really didnt describe HOW you did.

was that the log quoted section of commands, from your can sniffer log? I have been following Dalas stuff and I have some of the can files from his repository. but im stuck here on why some commands are working and some are not. Im stuck not getting data from the car at all, and it seems you were too. I havent gotten my ELM327 to talk to the car and give back any data. I can read voltage ( ATRV\r ), but thats pin voltage on the obd connector, not really anything.

I tried your commands in series, and it never provided data to me. Im wondering if you have any input for me

basically im trying to find wheel speed, throttle position if avail.


void testOut()
{
static const char PROGMEM cmds[][8] = {"ATZ\r", "ATI\r", "ATL0\r"};
char buf[128];
 

Attachments

  • IMG_5671.JPG
    4 MB
  • IMG_5674.JPG
    4.1 MB
  • IMG_5673.JPG
    4 MB
  • IMG_5672.JPG
    4 MB
Last edited:
You can buy (for very cheap online - AliExpress) right-angle OBD2 extension cables that will plug into the OBD2 port and only extend a few millimeters downwards. This is in fact how I am getting 12V power to my solution.
I just purchased a 3 way splitter, on amazon. has two extra obd connectors with ALL wired. so I connect one to my factory port, removed from the panel. then I take ONE of the new ports and install it back into the panel, with the clips provided. now I have TWO hidden obd ports and the factory one still accesible and useable and NOT obtrusive to knees.

Amazon 3 way obd splitter - ($22) the White connector comes with the correct tabs to lock it back into the factory panel. zip tie the rest out of the way.
 
Back
Top