Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RS485/Modbus support? #1167

Open
tomsepe opened this issue Apr 3, 2022 · 8 comments
Open

RS485/Modbus support? #1167

tomsepe opened this issue Apr 3, 2022 · 8 comments

Comments

@tomsepe
Copy link

tomsepe commented Apr 3, 2022

I am looking at some industrial humidity/temperature sensors that use the Modbus protocol (RS485) such as this: https://www.vaisala.com/en/products/instruments-sensors-and-other-measurement-devices/instruments-industrial-measurements/hmd110-hmw110

I am wondering if there is a way to integrate Modbus sensors as a custom input?

I am considering interfacing them by using an RS485 shield https://www.hwhardsoft.de/english/projects/rs485-arduino/ and then using the Arduino to convert the data to i2c.

What do you think about this approach?

Thank you!

@tomsepe tomsepe changed the title rs485 support? RS485/Modbus support? Apr 3, 2022
@kizniche
Copy link
Owner

kizniche commented Apr 7, 2022

if there is a way to integrate Modbus sensors as a custom input?

I'm not sure. I've never worked with it, but it looks fairly straightforward. I'd be more inclined to try to interface directly to the Pi, rather than use an arduino, with only one intermediary IC, something like the following:

https://www.sparkfun.com/products/10124
https://www.sparkfun.com/products/9822
https://wiki.seeedstudio.com/RS-485_Shield_for_Raspberry_Pi/
https://www.amazon.com/RS485-CAN-HAT-Long-Distance-Communication/dp/B07VMB1ZKH

@Josuah8
Copy link

Josuah8 commented Apr 9, 2022

Hi, you can use a cheap CH340/341 serial to USB converter stick and plug it into your pi, connect the modbus wires to it. In Mycodo just write a custom Python script to read the Modbus registers and return the values to Mycodo. Works like a charm. But integration like the other interface types would have saved me quite some time for sure.

Example:

import minimalmodbus
import serial

instrument = minimalmodbus.Instrument('/dev/ttyUSB0', slaveaddress=1, close_port_after_each_call=True, debug=False)  # port name, slave address (in decimal)
#instrument.serial.port                     # this is the serial port name
instrument.serial.baudrate = 9600         # Baud
instrument.serial.bytesize = 8
instrument.serial.parity = serial.PARITY_NONE
instrument.serial.stopbits = 1
instrument.serial.timeout = 1          # seconds
#print(instrument)
#instrument.address = 1                         # this is the slave address number
#instrument.serial.rtscts = True
#instrumentseral.xonxoff = True
#instrument.serial.dsrdtr = True
instrument.mode = minimalmodbus.MODE_RTU   # rtu or ascii mode
instrument.clear_buffers_before_each_transaction = True
## Read temperature (PV = ProcessValue) ##instrument.serial.port                     # this is the serial port name
#print(instrument)
ECtemp = instrument.read_register(registeraddress=2, number_of_decimals=0, functioncode=3) #read_long(1, 3)  # Registernumber, function code
ECtemp = ECtemp / 10

ECms = instrument.read_long(0, 3) / 100 #instrument.read_register(registeraddress=0, number_of_decimals=2, functioncode=3)

#ECppm = instrument.read_long(2, 3)

# Store measurements in database (must specify the channel and measurement)
self.store_measurement(channel=0, measurement=ECtemp)
self.store_measurement(channel=1, measurement=ECms)
#self.store_measurement(channel=2, measurement=ECppm)

@lalebarde
Copy link

There are also cheap UART-RS485 converters like the MAX485 module. I have just bought it, but I don't find out how to read sensors connected to the UART with mycodo. @Josuah8, is your code applicable in my case, possibly changing the tty? Could you please elaborate on "just write a custom Python script to read the Modbus registers and return the values to Mycodo"?

@Josuah8
Copy link

Josuah8 commented Apr 12, 2022 via email

@kizniche
Copy link
Owner

This issue has been mentioned on Radical DIY Forum. There might be relevant details there:

https://forum.radicaldiy.com/t/custom-input-for-industrial-ec-with-rs485-protocol/751/2

@friedpenguin
Copy link

Haha. You pointed the forum back to here. MODBUS would be a cool addition because a lot of solar charge controllers use MODBUS as well. And the way you've integrated MQTT to send data to/from where needed is awesome. Great project! Getting some traction on Reddit too.

@kizniche
Copy link
Owner

kizniche commented Jun 6, 2023

This issue has been mentioned on Radical DIY Forum. There might be relevant details there:

https://forum.radicaldiy.com/t/brainstorming-par-photosynthetically-active-radiation-light-sensor-for-mycodo/1557/1

@tazomatalax
Copy link

tazomatalax commented Mar 5, 2024

I have solved it using minimalmodbus. Needed to add /dev/ttyUSB0 and i had my registers wrong as the master was starting the registers at 1 instead of 0.

The following code along with installing the libraries with sudo ~/Mycodo/env/bin/pip install minimalmodbus pyserial is all you need to get pH and temp from a hamilton arc pH sensor

import minimalmodbus
import serial
import struct

# Create an instrument object
instrument = minimalmodbus.Instrument('/dev/ttyUSB0', slaveaddress=1, debug=False)
instrument.serial.baudrate = 19200
instrument.serial.bytesize = 8
instrument.serial.parity = serial.PARITY_NONE
instrument.serial.stopbits = 2
instrument.serial.timeout = 1
instrument.mode = minimalmodbus.MODE_RTU
instrument.clear_buffers_before_each_transaction = True

# Read 10 registers starting from 2090
ph_values = instrument.read_registers(2089, 10, functioncode=3)

# Read 10 registers starting from 2410
temp_values = instrument.read_registers(2409, 10, functioncode=3)

# Combine the register values to form 32-bit integers
ph_int = (ph_values[3] << 16) | ph_values[2]
temp_int = (temp_values[3] << 16) | temp_values[2]

# Convert the 32-bit integers to bytes
ph_bytes = ph_int.to_bytes(4, 'little')
temp_bytes = temp_int.to_bytes(4, 'little')

# Interpret the bytes as 32-bit floats
pH = struct.unpack('f', ph_bytes)[0]
temperature = struct.unpack('f', temp_bytes)[0]

# Store measurements
self.store_measurement(channel=0, measurement=round(pH, 2))
self.store_measurement(channel=1, measurement=round(temperature, 2))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants