Mar-05-2023, 07:05 PM
So, new to Python and still trying to learn the scope of variables. But, I have a small program that uses Bluetooth (BLE) to connect to a LiFePO4 battery management system controller, read some data, then publish a MQTT message.
Here's the very odd thing. When I was testing last night, and learning variable scope, I kept getting an index out of range error while unloading a list. So I put in a bunch of print statements to try and see what the heck was happening, as I think I was using the list properly (maybe not in the most efficient way, but should work).
When I did that and reloaded to the RPI the script ran fine with no range error! This confused me to know end. I then commented out the print statements and then I got the range error again. WTF? Here is the code if you have the time to help...
I've labeled the test print statements with # TEST.. If they are used the code runs. If they are commented out the code throws an error at the line marked # ERROR LINE.
I'm specifically looking for feedback in the error and why commenting out print statements would cause a problem. If you have style or "it's better to do it this way" comments, feel free. If you just want to tell me I'm a crappy Python programmer, save your breath, I already know that!
Here's the very odd thing. When I was testing last night, and learning variable scope, I kept getting an index out of range error while unloading a list. So I put in a bunch of print statements to try and see what the heck was happening, as I think I was using the list properly (maybe not in the most efficient way, but should work).
When I did that and reloaded to the RPI the script ran fine with no range error! This confused me to know end. I then commented out the print statements and then I got the range error again. WTF? Here is the code if you have the time to help...
I've labeled the test print statements with # TEST.. If they are used the code runs. If they are commented out the code throws an error at the line marked # ERROR LINE.
I'm specifically looking for feedback in the error and why commenting out print statements would cause a problem. If you have style or "it's better to do it this way" comments, feel free. If you just want to tell me I'm a crappy Python programmer, save your breath, I already know that!
#!/usr/bin/env python3 # This code should be run as SUDO as it does low level BLE scanning. # # Run it as follows: # # sudo python jbd-bms-mqtt-name.py -n "Cabin 580ah 100a" -i 0 -t solar # # This will scan for a bluetooth device called "Cabin 580ah 100a" and extract its # bluetooth MAC address, then use the address to attach to the BMS and read a set # if variables, one time, and then publish a MQTT message with those variable to # the Topic "solar". # # If you use a value other than 0 for the -i parm the program will loop forever # and read the BMS values every X seconds based on the value you passed. from bluepy.btle import Peripheral, DefaultDelegate, BTLEException from bluepy.btle import Scanner, DefaultDelegate import sys import struct import argparse import json import time import binascii import atexit import paho.mqtt.client as paho def disconnect(): mqtt.disconnect() print("broker disconnected") def cellinfo1(data): # process pack info print("In cellinfo1...") #TEST infodata = data i = 4 # Unpack into variables, skipping header bytes 0-3 volts, amps, remain, capacity, cycles, mdate, balance1, balance2 = struct.unpack_from('>HhHHHHHH', infodata, i) volts = volts / 100 amps = amps / 100 capacity = capacity / 100 remain = remain / 100 global ginfo ginfo.append(volts) ginfo.append(amps) ginfo.append(capacity) ginfo.append(remain) print(volts, amps, capacity, remain) # TEST print(ginfo) # TEST print("Leaving cellinfo1") # TEST def cellvolts1(data): # process cell voltages print("In cellvolts1...") # TEST celldata = data # Unpack into variables, skipping header bytes 0-3 i = 4 cell1, cell2, cell3, cell4 = struct.unpack_from('>HHHH', celldata, i) global ginfo ginfo.append(cell1) ginfo.append(cell2) ginfo.append(cell3) ginfo.append(cell4) print(cell1, cell2, cell3, cell4) #TEST print(ginfo) #TEST print("Leaving cellvolts1") #TEST class MyDelegate(DefaultDelegate): # notification responses def __init__(self): DefaultDelegate.__init__(self) def handleNotification(self, cHandle, data): hex_data = binascii.hexlify(data) # Given raw bytes, get an ASCII string representing the hex values text_string = hex_data.decode('utf-8') # check incoming data for routing to decoding routines if text_string.find('dd04') != -1: # x04 print("handleNotification-dd04") # TEST cellvolts1(data) elif text_string.find('dd03') != -1: # x03 print("handleNotification-dd03") #TEST cellinfo1(data) # Mainline Code # Process Command Line Arguments parser = argparse.ArgumentParser(description='Fetches and outputs JBD bms data') parser.add_argument("-n", "--name", help="BLE Device Name", required=True) parser.add_argument("-i", "--interval", type=int, help="Data fetch interval in seconds, 0=Once and Done", required=True) parser.add_argument("-t", "--topic", help="MQTT Topic name", required=True) args = parser.parse_args() z = args.interval topic = args.topic bleName = args.name ginfo = [] broker = "192.168.1.98" port = 1883 print("Searching for = '%s'" % (bleName)) scanner = Scanner() devices = scanner.scan(5) for dev in devices: for (adtype, desc, value) in dev.getScanData(): if value == bleName: print("=========== Found It ==============") print("Name = %s" % (value)) print("Device = %s" % (dev.addr)) print("RSSI = %d dB" % (dev.rssi)) print("===================================") bleAddr = dev.addr try: # If the variable was created we found the BLE device bleAddr except NameError: sys.exit("Did not find the BLE device...Halting!") try: print('attempting to connect') bms = Peripheral(bleAddr, addrType="public") except BTLEException as ex: time.sleep(5) print('2nd try connect') bms = Peripheral(bleAddr, addrType="public") except NameError: sys.exit("Can not connect to the BLE device...Halting!") else: print('connected ', bleAddr) atexit.register(disconnect) mqtt = paho.Client("control3") # create and connect mqtt client mqtt.connect(broker, port) bms.setDelegate(MyDelegate()) # setup bt delegate for notifications # write empty data to 0x15 for notification request -- address x03 handle for info & x04 handle for cell voltage # using waitForNotifications(5) as less than 5 seconds has caused some missed notifications while True: print("calling bms-x03") # TEST result = bms.writeCharacteristic(0x15, b'\xdd\xa5\x03\x00\xff\xfd\x77', False) # write x03 w/o cell info print(result) # TEST bms.waitForNotifications(5) print("calling bms-x04") # TEST result = bms.writeCharacteristic(0x15, b'\xdd\xa5\x04\x00\xff\xfc\x77', False) # write x04 w/o cell voltages print(result) #TEST bms.waitForNotifications(5) print(ginfo) # TEST gvolts = ginfo[0] gamps = ginfo[1] gcapacity = ginfo[2] gremain = ginfo[3] gcellvolt1 = ginfo[4] # ERROR LINE gcellvolt2 = ginfo[5] gcellvolt3 = ginfo[6] gcellvolt4 = ginfo[7] message0 = { "topic": topic, "volts": gvolts, "amps": gamps, "capacity": gcapacity, "remain": gremain, "cell1": gcellvolt1, "cell2": gcellvolt2, "cell3": gcellvolt3, "cell4": gcellvolt4 } ret = mqtt.publish(topic, payload=json.dumps(message0), qos=0, retain=False) if z != 0: # Loop unless interval is 0 otherwise one and done time.sleep(z) else: break