Hi,
I am currently having trouble converting the script below written by @pb66 for use in Node-Red. If anyone is able to help me or guide me, it would be much appreciated. I am essentially after the output of script, which is numbers so I can put populate them into a graph for viewing. I am willing to pay if it can be done.
I am using the same meter as mentioned in the script. PZEM-016.
Thank you!
#!/usr/bin/env python
"""
Driver for the PZEM-014 and PZEM-016 Energy monitors, for communication using the Modbus RTU protocol.
"""
__author__ = "Paul Burnell"
__license__ = "TBC"
try:
import minimalmodbus
except ImportError:
print("Cannot import minimalmodbus, is it installed?\nExiting...")
quit()
class pzem(minimalmodbus.Instrument):
def __init__(self, serialPort, slaveAddress=1):
"""
Create monitor device instance
"""
minimalmodbus.Instrument.__init__(self, serialPort, slaveAddress)
self.serial.timeout = 0.1
self.serial.baudrate = 9600
def getData(self):
"""
Return array of [V, A, W, Wh, Hz, PF, alarm] values.
"""
for i in range(5):
try:
data = self.read_registers(0,10,4)
break
except IOError as e:
pass
# except Exception as e:
# print(e)
if 'data' in locals():
return [
round((data[0]*0.1),1), # Voltage(0.1V)
round((data[1]*65536+data[2]*0.001),3), # Current(0.001A)
round((data[3]*65536+data[4]*0.1),1), # Power(0.1W)
round((data[5]*65536+data[6]*1),0), # Energy(1Wh)
round((data[7]*0.1),1), # Frequency(0.1Hz)
round((data[8]*0.01),2), # Power Factor(0.01)
int(data[9]>0)] # Alarm(1)
else:
return False
def getVoltage(self):
"""
Return the line voltage (0.1V precision).
"""
return self.read_register(0,1,4)
def getCurrent(self):
"""
Return the load current (0.001A precision).
"""
return round((self.read_long(1,4)*0.001),3)
def getPower(self):
"""
Return the real power (0.1W precision).
"""
return round((self.read_long(3,4)*0.1),1)
def getEnergy(self):
"""
Return the real energy (1Wh precision).
"""
return self.read_long(5,4)
def getFrequency(self):
"""
Return the line frequency (0.1Hz precision).
"""
return self.read_register(7,1,4)
def getPowerFactor(self):
"""Return the power factor (0.01 precision).
"""
return self.read_register(8,2,4)
def getAlarmStatus(self):
"""Return the alarm status (0 or 1 for True or False).
"""
return 1 if self.read_register(9,0,4) == 65535 else 0
def getAlarmThreshold(self):
"""
Return the power alarm threshold (1W precision).
"""
return self.read_register(1,0,3)
def setAlarmThreshold(self, watts):
"""
Set the power alarm threshold (1W precision).
"""
# alarmMax = 23000 # 2300 max for pzem014 or 23000 max for pzem016
# if int(watts) > 0 and int(watts) <= alarmMax:
try:
self.write_register(1,watts,0,6)
return True
except Exception as e:
pass
return False
def setZeroEnergy(self):
"""
Reset the energy accumulator total to zero.
"""
try:
self._performCommand(66,'')
except Exception as e:
return False
return True
def setSlaveAddress(self, address):
"""
Set a new slave address (1 to 247), initially set to 1 from factory.
Each device must have a unique address, Max of 31 devices per network.
"""
return self.write_register(2,address,0,6)
#def setCalibration(self):
# return self._performCommand(61,'')
#class pzem014(pzem):
#class pzem016(pzem):
if __name__ == "__main__":
import time
serialPort = "COM7"
# # # Using a single devive with factory default address of "1"
# # pz = pzem(serialPort)
# Using a slave address other than the factory default of "1".
slaveAddress = 2
pz = pzem(serialPort, slaveAddress)
while True:
print(' '.join(str(v) for v in [time.time(),pz.address]+pz.getData()))
time.sleep(10)
# #pz.setZeroEnergy()
# #pz.setSlaveAddress(3)
# print(pz.setAlarmThreshold(22099))
# print(pz.getAlarmThreshold())
Ignore all the commented stuff at the bottom, that’s just where I have been trying different stuff, this is imported into the script I run, (I’ll post that to, but it needs another import too)
pzem.zip (3.0 KB)
[edit - original zip contained the pzem.pyc
file instead of pzem.py
in error, corrected now, although the later files have evolved a bit since originally posted]
Currently contains 3 files, pzem.py is the code above, timestamp.py is used to time the intervals and looping, the “read_pzems.py” is what I’m using to read multiple pzems on a 10s loop. It outputs like so as I intend it to send to an emonhub socket interfacer.
C:\Users\paulb\Desktop\wip\pzem>read_pzems.py
1532335960.0 2 249.5 0.0 0.0 0.0 50.0 0.0 0
1532335960.0 3 249.7 0.0 0.0 0.0 50.0 0.0 0
1532335970.0 2 249.6 0.0 0.0 0.0 50.0 0.0 0
1532335970.0 3 249.7 0.0 0.0 0.0 50.1 0.0 0
Exiting...
C:\Users\paulb\Desktop\wip\pzem>