This shows you the differences between two versions of the page.
| 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 / | + | Using FTDI USB adapter which can be interfaced on / |
| + | Adding the current user to the " | ||
| sudo adduser pi dialout | sudo adduser pi dialout | ||
| - | | + | |
| + | Installing prerequisites: | ||
| sudo apt install python3 | sudo apt install python3 | ||
| wget https:// | wget https:// | ||
| 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: | Creating a new device and gathering credentials: | ||
| Line 129: | Line 131: | ||
| pip install wiotp-sdk | pip install wiotp-sdk | ||
| - | Modbus communication implementation based on: https:// | + | Modbus communication implementation based on: https:// |
| + | === 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_port = '/ | ||
| - | modbus_client = pymodbus.client.sync.ModbusSerialClient(method=' | + | modbus_client = pymodbus.client.sync.ModbusSerialClient(method=' |
| - | modbus_client.connect() | + | bytesize=8, stopbits=1, timeout=2, |
| + | my_config = wiotp.sdk.device.parseConfigFile(" | ||
| + | mqtt_client = wiotp.sdk.device.DeviceClient(config=my_config, | ||
| - | myConfig = wiotp.sdk.device.parseConfigFile("device.yaml") | + | |
| - | mqtt_client = wiotp.sdk.device.DeviceClient(config=myConfig, | + | def connect_modbus(): |
| - | mqtt_client.connect() | + | if not modbus_client.is_socket_open(): |
| + | modbus_client.connect() | ||
| + | print("connect_modbus: | ||
| + | |||
| + | |||
| + | def connect_mqtt(): | ||
| + | mqtt_client.connect() | ||
| + | print(" | ||
| Line 151: | Line 164: | ||
| def read_registers(address, | def read_registers(address, | ||
| - | | + | |
| + | result = modbus_client.read_holding_registers(address, | ||
| + | if not result.isError(): | ||
| + | register = result.registers | ||
| + | return register | ||
| - | modbus_client.read_holding_registers(0, 1, unit=0xAA) | + | def ask_registers(): |
| + | read_registers(0, | ||
| + | lifetime_counter = (convert(read_registers(32, | ||
| + | time_left = (convert(read_registers(34, | ||
| + | pack_voltage = convert(read_registers(36, | ||
| + | pack_current = convert(read_registers(38, | ||
| + | min_cell = (read_registers(40, | ||
| + | max_cell = (read_registers(41, 1)[0])/ | ||
| + | cell_diff = (read_registers(104, 1)[0])/ | ||
| + | soc = (convert(read_registers(46, | ||
| + | bms_temperature = (read_registers(48, | ||
| + | bms_online = hex(read_registers(50, | ||
| + | max_discharge_current = (read_registers(102, | ||
| + | max_charge_current = (read_registers(103, | ||
| + | charge_count = read_registers(111, | ||
| - | lifetime_counter | + | f_data = { |
| - | time_left | + | ' |
| - | pack_voltage | + | ' |
| - | pack_current | + | ' |
| - | min_cell | + | ' |
| - | max_cell | + | ' |
| - | cell_diff | + | ' |
| - | soc = convert(read_registers(46, 2), np.uint32) | + | ' |
| - | bms_temperature | + | ' |
| - | bms_online | + | ' |
| - | max_discharge_current | + | ' |
| - | max_charge_current | + | ' |
| - | charge_count | + | ' |
| + | ' | ||
| + | } | ||
| + | print(f_data) | ||
| + | print(" | ||
| + | return f_data | ||
| - | myData = { | + | |
| - | ' | + | def publish(p_data): |
| - | | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | def output_time(): |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | while True: |
| - | | + | |
| - | mqtt_client.publishEvent(eventId=" | + | |
| - | mqtt_client.disconnect() | + | |
| + | | ||
| + | | ||
| + | sleep(10) | ||
| </ | </ | ||
| + | {{: | ||
| + | |||
| + | ==== Receiving MQTT messages on Watson IoT platform ==== | ||
| + | Received messages:\\ | ||
| + | {{: | ||
| + | |||
| + | Raw status data available: | ||
| + | {{: | ||
| + | |||
| + | ===== 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: " | ||
| + | |||
| + | services: | ||
| + | node-red: | ||
| + | image: nodered/ | ||
| + | environment: | ||
| + | - TZ=Europe/ | ||
| + | ports: | ||
| + | - " | ||
| + | networks: | ||
| + | - node-red-net | ||
| + | volumes: | ||
| + | - ~/ | ||
| + | |||
| + | networks: | ||
| + | node-red-net: | ||
| + | </ | ||
| + | |||
| + | The node-red webapp can then be accessed via [[http:// | ||
| + | The Node-RED Dashboard module is needed to display the data with node-red\\ | ||
| + | To install, click the Menu Button and choose " | ||
| + | Then click on install and install in the pop-up window. Then return to the main view.\\ | ||
| + | {{: | ||
| + | |||
| + | |||
| ===== 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) | ||