PZEM-016 single phase modbus energy meter

Hello, im new to this forum. i was wondering if there is a way to change the baud rate?

Google is your friend. Have you tried a search?

1 Like

Hello new this site, Looking for working code in Python for PZEM004T V3 I have had no luck get it to work yet.

Any help would be good thanks.

Kevin

Hi OM,

I canā€™t recall seeing any code for the 004T.
Paul and I had a go with the 016 and 014., but AFAICR, not the 004T.

I do recall a user mentioning he has a 004T, so try searching the forum.

73

Bill KR6K

Would you post post or email what you have may help get stated please.
Thanks Kevin

You should be able to get a fairly good idea if you start at the top of this thread and read it
in its entirety. There are code snippets in several of the posts that should give you an idea
of how to read the registers in the 004.

Have you tried a Google search for ā€œPZEM-004T and Pythonā€ ?
That should yield some usuable results too.

Yes did not find any that works with V3 there a old rs232 version but not for Rs485 and addressed will look at your code above tonight

Thanks

Python V3?

Not sure what you mean hereā€¦

@NA7KR
Have you searched here for just ā€œPZEMā€?

I added PZEM-016 support to RS485modbus. The device seems to be accurate, I tested it with a kmart 40cm pedestal fan.

pzem

I didnā€™t think of optoisolation issues like dBC did, good point, there is an isolated RS485 to USB available. You just need to read 25 bytes from the PZEM-016 and transcribe 6 of those bytes into 3 hex values into values.

The Windows source code is available on sourceforge. This is an open source hobby of mine. Youā€™ll need to customize this code for whatever purpose you have in mind. The Chinese make all these RS485 gadgets, but no one makes software to go with it. If you wanna help, email me and confirm the software works.

PB66 and I noticed the same thing. NOT bad for a ā€œ10 buckā€ device!

I had to get 3 of them, cos we have 3 phase. Itā€™s useful to know how much power youā€™.re using. The manual says itā€™s optoisolated.

Some performance data comparing a PZEM-016 to an Elkor WattsOn:

Hi, my name is daniel, someone knows how to reset the energy counter using modbus commands, i saw in the second page instructions and try to use it, but i cant do it, i dont know if it have a especial notation or i cant interpret it

Welcome to OEM Dan,

Hereā€™s a Python script I use to read my PZEM-016.
One section of that script contains a definition of the reset command.
The script uses a Python module called minimalmodbus as well as a few others.
Depending on what you want to do, you may or may not need anything other than minimalmodbus.

pzem-016.zip (874 Bytes)


Hereā€™s another script that contains only the code that performs the reset.
Like the first script, this one also uses minimalmodbus.

pzreset.zip (287 Bytes)


I use an RS-485 to USB adapter to read the PZEM-016. One similar to this:
https://www.ebay.com/itm/Adapter-Module-CH340-USB-to-RS485-For-Win7-Linux-Vista-XP-Converter-Raspberry-c/323980605150?epid=5027448925&hash=item4b6ebfb6de:g:~JoAAOSwbYZXciE9

Hi Bill, thankyou for your answer, i saw your code but I didnā€™t run it, because i cant undestand how the reset energy is activated, al commands in code are only read_registers, and if we want to reset the energy counter , its not could be a write command?

I am grateful with you for your help, if you need someting you can ask me, greetings from colombia

I share you the code of file that you share me and a photo of instruction manual that i cannot be solve, the section is 2.5 reset energy:

and code that you send me:

import logging, minimalmodbus
from apscheduler.scheduler import Scheduler #Advanced Python Scheduler v2.12
from time import sleep

pz = minimalmodbus.Instrument("/dev/ttyUSB0", 1)
pz.serial.timeout = 0.1 # had to bump this up from the default of 0.05
pz.serial.baudrate = 9600
logging.basicConfig()
sched = Scheduler()
sched.start()

def read_meter():
    VOLT = pz.read_register(0, 0, 4)
    AMPS = pz.read_register(1, 0, 4)
    WATT = pz.read_register(3, 0, 4)
    WHRS = pz.read_register(5, 0, 4)
    FREQ = pz.read_register(7, 0, 4)
    PWRF = pz.read_register(8, 0, 4)
    print VOLT * 0.1
    print AMPS * 0.001
    print WATT * 0.1
    print WHRS
    print FREQ * 0.1
    print PWRF * 0.01
    print

def main():
    sched.add_cron_job(read_meter, second='*/1')

    while True:
       sleep(1)

if __name__ == "__main__":
    main()

Iā€™m not sure what happened, but the code in your post doesnā€™t look like the code
in the zip file I attached to my post.

Hereā€™s a code snippet that performs only the reset function:

#!/usr/bin/python

import minimalmodbus

pz = minimalmodbus.Instrument('/dev/ttyUSB0', 1)
pz.serial.baudrate = 9600

pz._performCommand(66, '')

Youā€™ll need Python, the minimalmodbus module, and an RS-485 interface to enable your computer to talk to your PZEM-016.

The RS-485 interface I use is a USB device like the one in the link two posts above this one.
More info on minimalmodbus here: Installation ā€” MinimalModbus 2.0.1 documentation

I finally got a chance to play around with my PZEM-016. FYI - I am getting a fairly consistent 20% higher current reading compared with my other meters. UNI-T UT804 (direct measurement through leads), UT210E (clamp meter), Fluke T5-600 (jaw clamp meter). I might have mixed up the CT from some similar toys that came from Peacefair.
Has anyone else checked the current to see how accurate it is?
Since it talks over modbus obviously I could apply my own scaling factor in software instead of dealing with the calibration process so itā€™s not the end of the world to me.
Surprisingly it was able to measure down to the lowest current that I tried at 3mA.

Check post 133 in this thread. I posted a graph comparing my PZEM-016 to an Elkor WattsOn
Watthour meter. You have to look closely, as the green trace (PZEM) overlays the red trace
(WattsOn) almost to the point of hiding it completely.

The 016 is quite accurate considering the cost. Iā€™ve had one for a bit over a year
and find that it tracks my WattsOn as well as a Continental Control Systems WattNode kWh meter
quite closely.

For a different way of communicating with the PZEM-016, hereā€™s how to do it from C.
First, install libmodbus:

sudo apt-get install libmodbus5
sudo apt-get install libmodbus-dev

The following will read the PZEM data using libmodbus:

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <modbus.h>

#define DOUBLEWORD	0x01
#define DIV10		0x02
#define DIV100		0x04
#define DIV1000		0x08
#define END			0xFF

int main( void )
	{
	static const char *configDeviceName = "/dev/ttyUSB0";
	static const int configBaudRate = 9600;
	static const int configSlaveAddress = 1;
	static const int modbusResultInfo[] = {
		DIV10,					/* Voltage in 0.1V */
		DOUBLEWORD | DIV1000,	/* Current in 0.001A */
		DOUBLEWORD | DIV10,		/* Power in 0.1W */
		DOUBLEWORD,				/* Energy in 1Wh */
		DIV10,					/* Frequency in 0.1Hz */
		DIV100,					/* Power factor in 0.01 */
		END
		};
	modbus_t *modbusCTX;
	uint16_t modbusResults[ 9 ];
	int i, resultIndex = 0, status;

	/* Create a libmodbus context and connect to the remote device */
	modbusCTX = modbus_new_rtu( configDeviceName, configBaudRate,
								'N', 8, 1 );
	if( modbusCTX == NULL )
		{
	    fprintf( stderr, "Couldn't create libmodbus context for %s.\n",
	    		 configDeviceName );
	    return( EXIT_FAILURE );
		}
	if( modbus_connect( modbusCTX ) == -1 )
		{
		fprintf( stderr, "modbus connect failed for %s: %s.\n",
				 configDeviceName, modbus_strerror( errno ) );
		modbus_free( modbusCTX );
		return( EXIT_FAILURE );
		}

	/* Set the slave ID of the device to connect to.  A value of 0x01 seems
	   to work, there's a command to set it to a value 0x01...0xF7 but we
	   don't touch that */
	modbus_set_slave( modbusCTX, configSlaveAddress );

	/* Let the user know that we've established a connection */
	printf( "Connected to %s at %d 8N1, slave ID %d.\n", configDeviceName,
			configBaudRate, configSlaveAddress );

	/* Try and read the first 9 registers, which is all the PZEM data
	   except the alarm status */
	if( modbus_read_input_registers( modbusCTX, 0, 9, modbusResults ) == -1 )
		{
		fprintf( stderr, "modbus register read failed for slave ID %d: %s.\n",
				 configSlaveAddress, modbus_strerror( errno ) );
		modbus_free( modbusCTX );
		return( EXIT_FAILURE );
		}

	/* Display the results */
	for( i = 0; modbusResultInfo[ i ] != END; i++ )
		{
		const int modbusInfo = modbusResultInfo[ i ];
		uint32_t value = modbusResults[ resultIndex++ ];
		float result, divisor;

		/* Get the high word if there is one */
		if( modbusInfo & DOUBLEWORD )
			value |= ( uint32_t ) modbusResults[ resultIndex ++ ] << 16;

		/* Scale the value to get the actual measurement */
		divisor = ( modbusInfo & DIV1000 ) ? 1000 : \
				  ( modbusInfo & DIV100 ) ? 100 : 10;
		result = value / divisor;

		printf( "%d %.2f\n", value, result );
		}
	printf( "\n" );

	modbus_free( modbusCTX );

	return( EXIT_SUCCESS );
	}

Finally, to build it:

cc pzem16.c -o pzem16 pkg-config --cflags --libs libmodbus`

Thatā€™s just some test code to dump the output, depending on how useful people find it it can be adapted to take command-line args for e.g. the port to use, and something for output formatting, Iā€™m going to be feeding it to Thingspeak so Iā€™ll probably add something to handle that.