#/bin/python import socket import sys import time import serial import select from collections import deque def parse_to_graphite(data, root='rc.bms', timestamp=None): if not timestamp: timestamp = int(time.time()) results = [] lines = data.strip().split('\n') for line in lines: if line.startswith('BMS'): parts = line.split() bank_battery = parts[1] metric_name = ' '.join(parts[2:-1]).replace(' ', '_') metric_value = parts[-1] # Remove trailing colon in the metric name if present if metric_name.endswith(':'): metric_name = metric_name[:-1] if 'Cell' in metric_name and 'Voltage' in metric_name and 'Cell' in metric_name.split('_')[0]: cell_number = metric_name.split('_')[1] metric_name = f"Cell.{cell_number}.Voltage" metric_path = f"{root}.{bank_battery}.{metric_name}" results.append(f"{metric_path} {metric_value} {timestamp}") return results def send_to_graphite(data, host='10.6.0.1', port=2003): try: with socket.create_connection((host, port), timeout=1) as sock: while data: message = data.popleft() sock.sendall(message.encode('utf-8')) #print(f"Sent to Graphite: {message.strip()}") except (socket.error, socket.timeout) as e: print(f"Failed to send data, will drop if buffer is full. Error: {e}", file=sys.stderr) def main(): ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=1) data_buffer = deque(maxlen=100) # Buffer up to 100 messages print("Reading data from /dev/ttyUSB0, press CTRL+C to quit:") try: while True: if select.select([ser], [], [], 0)[0]: # Check if there is data to read line = ser.readline().decode('utf-8').strip() if line: print(f"{line}") # Output raw line to screen graphite_data = parse_to_graphite(line) for data in graphite_data: if len(data_buffer) < data_buffer.maxlen: data_buffer.append(data + '\n') #print(f"Added to buffer: {data.strip()}") else: print("Buffer full, dropping data", file=sys.stderr) # Try to send data if the buffer is not empty if data_buffer: #print("Attempting to send data to Graphite...") send_to_graphite(data_buffer) except KeyboardInterrupt: print("Exiting...") finally: ser.close() if __name__ == '__main__': main()