Please critique my Python

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.

BenTheRighteous

Well-known member
Joined
Feb 14, 2017
Messages
62
Location
Raleigh, NC
I'm trying to get a Raspberry Pi to monitor my Leaf's regen and here's the code I've come up with so far. It works but it's the result of trial-and-error so I'm sure it could get a lot cleaner, I just don't know how. Any feedback is welcome.

My two main issues are:
1. There's got to be a better way to read from the interface. Right now I just keep concatenating the result into a variable and once it ends with something logical, I assume I have the whole thing.
2. Not sure I'm sending the right series of AT commands. What I have works, but the AT MA command causes the scanner to spit out messages nonstop. I'd much rather have it provide a single message and stop until I ask again later, in other words I want to poll at my leisure instead of drink from a firehose.

For now the code just reads the value and prints it on the console, nothing more complicated than that.

Code:
import time
import os

dev = os.open('/dev/rfcomm0', os.O_RDWR | os.O_NONBLOCK | os.O_NOCTTY)

def printTwosComp(num, bits):
    mask = 1 << bits
    half = mask >> 1
    if num < half:
        return num
    else:
        return num - mask

def send(cmd):
    print('Sending command:', cmd)
    os.write(dev, cmd)
    # time.sleep(0.2)
    rsp = b''
    while not (rsp.endswith(b'\r') or rsp.endswith(b'\n')):
        time.sleep(0.2)
        rsp += os.read(dev, 160)
        print('partial:', rsp)
        if rsp.endswith(b'>'):
            print('early finish')
            return
    print('got echo')
    rsp = b''
    while not (rsp.endswith(b'\r') or rsp.endswith(b'>')):
        time.sleep(0.2)
        rsp += os.read(dev, 160)
        print('partial:', rsp)
    print(rsp)
    print('got result')
    time.sleep(0.2)

os.write(dev, b'at z\r')
time.sleep(1)
send(b'at z\r')
send(b'at l1\r')
send(b'at h1\r')
send(b'at cf 180\r')

os.write(dev, b'at ma\r')
rsp = b''
while True:
    time.sleep(0.0001)
    rsp += os.read(dev, 1)
    str = rsp.decode('UTF-8')
    if str.endswith('\r\n'):
        # print(str)
        print(rsp)
        if len(rsp) > 10:
            # 180 00 00 00 00 00 00 26 00
            # 012345678901234567890123456
            #           10        20
            # math = (int(chr(rsp[19]), 16) << 12) + (int(chr(rsp[20]), 16) << 8) + (int(chr(rsp[22]), 16) << 4) + (int(chr(rsp[23]), 16))  # throttle position
            math = (int(chr(rsp[10]), 16) << 12) + (int(chr(rsp[11]), 16) << 8) + (int(chr(rsp[13]), 16) << 4) + (int(chr(rsp[14]), 16))  # motor amps
            print(math)
            print(printTwosComp(math, 16))
        rsp = b''

Again, my code works, but I know there's a ton of room for improvement. Thanks for any feedback!
 
Looking good. I'm having a hard time getting my RPi to even read from my OBD2 reader (LeLink that works perfectly in LeafSpy). I've ordered another ELM327 module that hopefully will work better. I'm expecting to have a snow day tomorrow here, so it'll be a good opportunity for me to take a look at your code.

My problem right now is that I can't screen or Minicom into rfcomm0. Don't know why yet.

On a parallel path. I backed this on Kickstarter: https://www.kickstarter.com/projects/1029808658/macchina-the-ultimate-tool-for-taking-control-of-y?ref=user_menu

The advantage seems to be that it will also write to the various buses and has easy integration with WiFi/Bluetooth/LTE for connectivity to a cloud service.

I'm glad that you are working on this to, I'm quite motivated to get something going.

My main goals are:
1. Enable auto charging cutoff at 80%
2. Enable cloud based climate control (pre-heat / cool)
3. Automatic storage of LeafSpy like metrics without having to have LeafSpy open on my phone.
4. Alexa integration

-Jim
 
I improved my Python code, and I think this is the correct way to read from the interface. No arbitrary sleeps or polling rates. I'm still not thrilled with the 'AT MA' command, but don't see a good alternative.

Code:
import os

dev = os.open('/dev/rfcomm0', os.O_RDWR | os.O_NOCTTY)

def send(cmd):
    print('Command:', cmd)
    os.write(dev, cmd)
    rsp = b''
    while not rsp.endswith(b'>'):
        rsp += os.read(dev, 1)
    print('Response:', rsp)

def monitor(cmd):
    print('Monitor:', cmd)
    os.write(dev, cmd)
    while True:
        rsp = b''
        while not rsp.endswith(b'\r'):
            rsp += os.read(dev, 1)
        print('Response:', rsp)

send(b'at z\r')
send(b'at z\r')
send(b'at e0\r')
send(b'at l0\r')
send(b'at h1\r')
send(b'at cf 180\r')
monitor(b'at ma\r')
Jim, without knowing anything about your specifics, I assume your /dev/rfcomm0 device actually exists? (I have to create mine)
And you are accessing it as root? (i.e., running the screen command as root)
Basic questions, but gotta start somewhere. :)

That device looks cool, but I'm not sure I'd be able to wait for July to get my hands on one! They sure funded the heck out of it though, best of luck to them.
 
I know this is an old thread but I just got my Nissan leaf and am a data engineer by practice. I code mostly in python and would love to see where this project has left off. Any updates? anything I can help with?
 
Back
Top