User Tools

Site Tools


projects:farmrobot:batteriemanagement

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
projects:farmrobot:batteriemanagement [2021/03/21 18:23]
jonas
projects:farmrobot:batteriemanagement [2021/03/21 19:02] (current)
jonas [Modbus Python and Watson-IoT MQTT publish on Raspberry Pi 4B]
Line 104: Line 104:
  
 ===== Modbus Python and Watson-IoT MQTT publish on Raspberry Pi 4B ===== ===== Modbus Python and Watson-IoT MQTT publish on Raspberry Pi 4B =====
-Using FTDI USB adapter which can be interfaced on /dev/ttyUSB0 +Using FTDI USB adapter which can be interfaced on /dev/ttyUSB0\\ 
 +Adding the current user to the "dialout" user group to access serial interfaces without root permissions:
     sudo adduser pi dialout     sudo adduser pi dialout
-    + 
 +Installing prerequisites:\\
     sudo apt install python3     sudo apt install python3
     wget https://bootstrap.pypa.io/get-pip.py     wget https://bootstrap.pypa.io/get-pip.py
     sudo python3 get-pip.py     sudo python3 get-pip.py
-    sudo pip install pymodbus +    sudo pip install pymodbus\\ 
-\\+ 
 +ModbusSerialClient is the Modbus client that is used to interface the registers on the BMS:
     from pymodbus.client.sync import ModbusSerialClient     from pymodbus.client.sync import ModbusSerialClient
  
-Using IBM Watson IoT platform+=== IBM Watson IoT platform ===
  
 Creating a new device and gathering credentials: https://q74k3e.internetofthings.ibmcloud.com/dashboard/devices/browse/ Creating a new device and gathering credentials: https://q74k3e.internetofthings.ibmcloud.com/dashboard/devices/browse/
Line 129: Line 131:
     pip install wiotp-sdk     pip install wiotp-sdk
  
-Modbus communication implementation based on: https://github.com/clarkni5/tinybms/blob/master/python/tinybms.py+Modbus communication implementation based on: https://github.com/clarkni5/tinybms/blob/master/python/tinybms.py\\
  
 +=== Code: ===
 <file py pc_bms_modbus_mqtt.py> <file py pc_bms_modbus_mqtt.py>
 import numpy as np import numpy as np
 import wiotp.sdk.device import wiotp.sdk.device
 +from time import sleep
 +from datetime import datetime
 import pymodbus.client.sync import pymodbus.client.sync
  
-# Modbus client 
 dev_port = '/dev/ttyUSB0' dev_port = '/dev/ttyUSB0'
-modbus_client = pymodbus.client.sync.ModbusSerialClient(method='rtu', port=dev_port, timeout=2, baudrate=115200+modbus_client = pymodbus.client.sync.ModbusSerialClient(method='rtu', port=dev_port, baudrate=115200, parity='N', 
-modbus_client.connect()+                                                        bytesize=8, stopbits=1, timeout=2, strict=False
 +my_config = wiotp.sdk.device.parseConfigFile("device.yaml"
 +mqtt_client = wiotp.sdk.device.DeviceClient(config=my_config, logHandlers=None)
  
-myConfig = wiotp.sdk.device.parseConfigFile("device.yaml") + 
-mqtt_client = wiotp.sdk.device.DeviceClient(config=myConfig, logHandlers=None+def connect_modbus(): 
-mqtt_client.connect()+    if not modbus_client.is_socket_open(): 
 +        modbus_client.connect() 
 +    print("connect_modbus: ok") 
 + 
 + 
 +def connect_mqtt(): 
 +    mqtt_client.connect(
 +    print("connect_mqtt: ok")
  
  
Line 151: Line 164:
  
 def read_registers(address, count): def read_registers(address, count):
-    return modbus_client.read_holding_registers(address, count, unit=0xAA).registers+    while True: 
 +        result = modbus_client.read_holding_registers(address, count, unit=0xAA) 
 +        if not result.isError(): 
 +            register = result.registers 
 +            return register
  
  
-modbus_client.read_holding_registers(0, 1, unit=0xAA)+def ask_registers(): 
 +    read_registers(0, 1) 
 +    lifetime_counter = (convert(read_registers(32, 2), np.uint32))/60  # min 
 +    time_left = (convert(read_registers(34, 2), np.uint32))/60  # min 
 +    pack_voltage = convert(read_registers(36, 2), np.float32)  # V 
 +    pack_current = convert(read_registers(38, 2), np.float32)  # C 
 +    min_cell = (read_registers(40, 1)[0])/1000  # V 
 +    max_cell = (read_registers(41, 1)[0])/1000  # V 
 +    cell_diff = (read_registers(1041)[0])/10000  # V 
 +    soc (convert(read_registers(46, 2), np.uint32))/1000000  # % 
 +    bms_temperature = (read_registers(48, 1)[0])/10  # °C 
 +    bms_online = hex(read_registers(50, 1)[0]) 
 +    max_discharge_current = (read_registers(102, 1)[0])/1000  # A 
 +    max_charge_current = (read_registers(103, 1)[0])/1000  # A 
 +    charge_count = read_registers(111, 1)[0]
  
-lifetime_counter = convert(read_registers(322), np.uint32) +    f_data = { 
-time_left = convert(read_registers(342), np.uint32) +        'lifetime_counter': "%.2f"lifetime_counter, 
-pack_voltage = convert(read_registers(362), np.float32) +        'time_left': "%.2f" % time_left, 
-pack_current = convert(read_registers(382), np.float32) +        'pack_voltage': "%.2f"pack_voltage, 
-min_cell = read_registers(401)[0] +        'pack_current': "%.2f"pack_current, 
-max_cell = read_registers(411)[0] +        'min_cell': "%.2f"min_cell, 
-cell_diff = read_registers(1041)[0] +        'max_cell': "%.2f"max_cell, 
-soc = convert(read_registers(462), np.uint32) +        'cell_diff': "%.2f"cell_diff, 
-bms_temperature = read_registers(481)[0] +        'soc': "%.2f"soc, 
-bms_online = read_registers(50, 1)[0] +        'bms_temperature': "%.1f"bms_temperature, 
-max_discharge_current = read_registers(1021)[0] +        'bms_online': str(bms_online), 
-max_charge_current = read_registers(1031)[0] +        'max_discharge_current': "%.2f"max_discharge_current, 
-charge_count = read_registers(111, 1)[0]+        'max_charge_current': "%.2f"max_charge_current, 
 +        'charge_count': str(charge_count) 
 +        } 
 +    print(f_data) 
 +    print("stored register values: ok") 
 +    return f_data
  
-myData = { + 
-    'lifetime_counter'lifetime_counter, +def publish(p_data)
-    'time_left': time_left, +    mqtt_client.publishEvent(eventId="status"msgFormat="json"data=p_dataqos=0, onPublish=print("publish: ok")) 
-    'pack_voltage': pack_voltage, + 
-    'pack_current': pack_current+ 
-    'min_cell'min_cell, +def output_time()
-    'max_cell': max_cell, +    now = datetime.now() 
-    'cell_diff'cell_diff, +    current_time = now.strftime("%H:%M:%S") 
-    'soc': soc, +    print("-------------------------------------------------------------------") 
-    'bms_temperature': bms_temperature, +    print(current_time) 
-    'bms_online'bms_online, +    print("-------------------------------------------------------------------"
-    'max_discharge_current': max_discharge_current, + 
-    'max_charge_current': max_charge_current, + 
-    'charge_count': charge_count +while True
-    } +    output_time() 
-mqtt_client.publishEvent(eventId="status", msgFormat="json", data=myData, qos=0, onPublish=None+    connect_modbus() 
-mqtt_client.disconnect()+    connect_mqtt() 
 +    my_data = ask_registers() 
 +    publish(my_data
 +    sleep(10)
 </file> </file>
 +{{:projects:farmrobot:run_terminal.png|}}
 +
 +==== Receiving MQTT messages on Watson IoT platform ====
 +Received messages:\\
 +{{:projects:farmrobot:watson_iot_received_messages.png?600|}}\\
 +
 +Raw status data available:\\
 +{{:projects:farmrobot:watson_iot_raw_data.png?600|}}
 +
 +===== Web Interface to view and graph the data =====
 +An easy way to set up a web interface is to host a node-red instance on a server, for example on a stationary Raspberry Pi 4, which can be accesses via network or can be made accessible with port forwarding from the internet.\\
 +
 +Setting up a Raspberry Pi 4B with docker and docker run portainer.
 +Create a new Node-Red Stack with a compose file, which creates a node-red web instance on the device on port 1880.
 +The ip adress is needed which can be requested with:
 +    ifconfig
 +
 +<file yaml compose.yaml>
 +version: "2"
 +
 +services:
 +  node-red:
 +    image: nodered/node-red:latest
 +    environment:
 +      - TZ=Europe/Berlin
 +    ports:
 +      - "1880:1880"
 +    networks:
 +      - node-red-net
 +    volumes:
 +      - ~/data/node-red:/data
 +
 +networks:
 +  node-red-net:
 +</file>
 +
 +The node-red webapp can then be accessed via [[http://ip-adress:1880]]\\
 +The Node-RED Dashboard module is needed to display the data with node-red\\
 +To install, click the Menu Button and choose "Manage palette". Click the "Install" tab and search for "node-red-dashboard".\\
 +Then click on install and install in the pop-up window. Then return to the main view.\\
 +{{:projects:farmrobot:node-red-palette.png?600|}}
 +
 +
 ===== Micropython implementation on espressiv ESP32 DevKitc v4 ===== ===== Micropython implementation on espressiv ESP32 DevKitc v4 =====
 Required software: Linux OS and python3 (sudo apt-get install python3) Required software: Linux OS and python3 (sudo apt-get install python3)
projects/farmrobot/batteriemanagement.1616351013.txt.gz · Last modified: 2021/03/21 18:23 by jonas