-
-
Save bandaangosta/134c9d84ae9bd317297e96dcc0b9c860 to your computer and use it in GitHub Desktop.
# Reading PZEM-004t power sensor (new version v3.0) through Modbus-RTU protocol over TTL UART | |
# Run as: | |
# python3 pzem_004t.py | |
# To install dependencies: | |
# pip install modbus-tk | |
# pip install pyserial | |
import serial | |
import modbus_tk.defines as cst | |
from modbus_tk import modbus_rtu | |
# Connect to the sensor | |
sensor = serial.Serial( | |
port='/dev/PZEM_sensor', | |
baudrate=9600, | |
bytesize=8, | |
parity='N', | |
stopbits=1, | |
xonxoff=0 | |
) | |
master = modbus_rtu.RtuMaster(sensor) | |
master.set_timeout(2.0) | |
master.set_verbose(True) | |
data = master.execute(1, cst.READ_INPUT_REGISTERS, 0, 10) | |
voltage = data[0] / 10.0 # [V] | |
current = (data[1] + (data[2] << 16)) / 1000.0 # [A] | |
power = (data[3] + (data[4] << 16)) / 10.0 # [W] | |
energy = data[5] + (data[6] << 16) # [Wh] | |
frequency = data[7] / 10.0 # [Hz] | |
powerFactor = data[8] / 100.0 | |
alarm = data[9] # 0 = no alarm | |
print('Voltage [V]: ', voltage) | |
print('Current [A]: ', current) | |
print('Power [W]: ', power) # active power (V * I * power factor) | |
print('Energy [Wh]: ', energy) | |
print('Frequency [Hz]: ', frequency) | |
print('Power factor []: ', powerFactor) | |
print('Alarm : ', alarm) | |
# Changing power alarm value to 100 W | |
# master.execute(1, cst.WRITE_SINGLE_REGISTER, 1, output_value=100) | |
try: | |
master.close() | |
if sensor.is_open: | |
sensor.close() | |
except: | |
pass |
this only print the data once right and not a loop?
Hi, @FujiwaraKengo . That is correct, data is printed out only once and then the scripts ends, closing the communication channel. You could put the reading part in a loop (lines 27 to 43), allowing for a reasonable waiting time between iterations, or call the full script periodically.
Can this script be modified for usage with Windows? Changing "/dev/PZEM_sensor" to the comport of the FTDI-cable results in
Traceback (most recent call last):
File "g:\PZEM-004T\pzem_004t.py", line 27, in <module>
data = master.execute(1, cst.READ_INPUT_REGISTERS, 0, 10)
File "c:\Users\Bart\AppData\Local\Programs\Python\Python310\lib\site-packages\modbus_tk\utils.py", line 39, in new
raise excpt
File "c:\Users\Bart\AppData\Local\Programs\Python\Python310\lib\site-packages\modbus_tk\utils.py", line 37, in new
ret = fcn(*args, **kwargs)
File "c:\Users\Bart\AppData\Local\Programs\Python\Python310\lib\site-packages\modbus_tk\modbus.py", line 356, in execute
response_pdu = query.parse_response(response)
File "c:\Users\Bart\AppData\Local\Programs\Python\Python310\lib\site-packages\modbus_tk\modbus_rtu.py", line 46, in parse_response
raise ModbusInvalidResponseError("Response length is invalid {0}".format(len(response)))
modbus_tk.exceptions.ModbusInvalidResponseError: Response length is invalid 0
Yes, I checked the Tx-/Rx-connections.
edit: Hmm, seems it does this when there are no readings (didn't connect AC-side), I am getting output when AC-side is connected. So I added an try/except for modbus_rtu.ModbusInvalidResponseError and an if-statement to check if data contains something.
Now to figure out how to change the address from Python.
edit: data = master.execute(1, cst.WRITE_SINGLE_REGISTER, 2, output_value=2)
seems to do that :)
this only print the data once right and not a loop? what does the .close() method do?