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.