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
Next revision Both sides next revision
projects:farmrobot:batteriemanagement [2021/03/21 18:23]
jonas [Monitoring BMS]
projects:farmrobot:batteriemanagement [2021/03/21 18:56]
jonas [Web Interface to view and graph the data]
Line 103: Line 103:
  
  
-===== Modbus Python and WatsonIoT 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
  
Line 134: Line 134:
 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 161:
  
 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.txt · Last modified: 2021/03/21 19:02 by jonas