BenTheRighteous
Posts: 59
Joined: Tue Feb 14, 2017 5:36 am
Delivery Date: 14 Feb 2017
Location: Raleigh, NC

Please critique my Python

Mon Mar 13, 2017 8:01 am

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: Select all

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!
2017 Leaf S
OpenEVSE P50-D WiFi Kit
Raleigh, NC
USA

kingjamez
Posts: 26
Joined: Sun Mar 05, 2017 12:13 pm
Delivery Date: 05 Mar 2017
Location: Fairfax, VA

Re: Please critique my Python

Mon Mar 13, 2017 1:31 pm

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/10 ... =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
2014 S w/QC

BenTheRighteous
Posts: 59
Joined: Tue Feb 14, 2017 5:36 am
Delivery Date: 14 Feb 2017
Location: Raleigh, NC

Re: Please critique my Python

Mon Mar 13, 2017 5:27 pm

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: Select all

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.
2017 Leaf S
OpenEVSE P50-D WiFi Kit
Raleigh, NC
USA

Return to “LEAF CANBus”