I was able to upload the sketch to Wemos successful.
The problems I got now is voltage only show up as 0.00V in serial monitor.
How do I fix it so the actual voltage, watt … can show up in the serial monitor?
Here is the sketch:
#include <SoftwareSerial.h> // Arduino IDE <1.6.6
#include <PZEM004T.h>
PZEM004T pzem(13,15); // (RX,TX) connect to TX,RX of PZEM
IPAddress ip(192,168,1,88);
void setup() {
Serial.begin(9600);
pzem.setAddress(ip);
}
void loop() {
float v = pzem.voltage(ip);
if (v < 0.0) v = 0.0;
Serial.print(v);Serial.print("V; ");
float i = pzem.current(ip);
if(i >= 0.0){ Serial.print(i);Serial.print("A; "); }
float p = pzem.power(ip);
if(p >= 0.0){ Serial.print(p);Serial.print("W; "); }
float e = pzem.energy(ip);
if(e >= 0.0){ Serial.print(e);Serial.print("Wh; "); }
Serial.println();
// delay(1000);
}
And here is the PZEM004T.cpp
#include "PZEM004T.h"
#define PZEM_VOLTAGE (uint8_t)0xB0
#define RESP_VOLTAGE (uint8_t)0xA0
#define PZEM_CURRENT (uint8_t)0xB1
#define RESP_CURRENT (uint8_t)0xA1
#define PZEM_POWER (uint8_t)0xB2
#define RESP_POWER (uint8_t)0xA2
#define PZEM_ENERGY (uint8_t)0xB3
#define RESP_ENERGY (uint8_t)0xA3
#define PZEM_SET_ADDRESS (uint8_t)0xB4
#define RESP_SET_ADDRESS (uint8_t)0xA4
#define PZEM_POWER_ALARM (uint8_t)0xB5
#define RESP_POWER_ALARM (uint8_t)0xA5
#define RESPONSE_SIZE sizeof(PZEMCommand)
#define RESPONSE_DATA_SIZE RESPONSE_SIZE - 2
#define PZEM_BAUD_RATE 9600
#ifdef PZEM004_SOFTSERIAL
PZEM004T::PZEM004T(uint8_t receivePin, uint8_t transmitPin)
{
SoftwareSerial *port = new SoftwareSerial(receivePin, transmitPin);
port->begin(PZEM_BAUD_RATE);
this->serial = port;
this->_isSoft = true;
}
#endif
PZEM004T::PZEM004T(HardwareSerial *port)
{
port->begin(PZEM_BAUD_RATE);
this->serial = port;
this->_isSoft = false;
}
PZEM004T::~PZEM004T()
{
if(_isSoft)
delete this->serial;
}
void PZEM004T::setReadTimeout(unsigned long msec)
{
_readTimeOut = msec;
}
float PZEM004T::voltage(const IPAddress &addr)
{
uint8_t data[RESPONSE_DATA_SIZE];
send(addr, PZEM_VOLTAGE);
if(!recieve(RESP_VOLTAGE, data))
return PZEM_ERROR_VALUE;
return (data[0] << 8) + data[1] + (data[2] / 10.0);
}
float PZEM004T::current(const IPAddress &addr)
{
uint8_t data[RESPONSE_DATA_SIZE];
send(addr, PZEM_CURRENT);
if(!recieve(RESP_CURRENT, data))
return PZEM_ERROR_VALUE;
return (data[0] << 8) + data[1] + (data[2] / 100.0);
}
float PZEM004T::power(const IPAddress &addr)
{
uint8_t data[RESPONSE_DATA_SIZE];
send(addr, PZEM_POWER);
if(!recieve(RESP_POWER, data))
return PZEM_ERROR_VALUE;
return (data[0] << 8) + data[1];
}
float PZEM004T::energy(const IPAddress &addr)
{
uint8_t data[RESPONSE_DATA_SIZE];
send(addr, PZEM_ENERGY);
if(!recieve(RESP_ENERGY, data))
return PZEM_ERROR_VALUE;
return ((uint32_t)data[0] << 16) + ((uint16_t)data[1] << 8) + data[2];
}
bool PZEM004T::setAddress(const IPAddress &newAddr)
{
send(newAddr, PZEM_SET_ADDRESS);
return recieve(RESP_SET_ADDRESS);
}
bool PZEM004T::setPowerAlarm(const IPAddress &addr, uint8_t threshold)
{
send(addr, PZEM_POWER_ALARM, threshold);
return recieve(RESP_POWER_ALARM);
}
void PZEM004T::send(const IPAddress &addr, uint8_t cmd, uint8_t data)
{
PZEMCommand pzem;
pzem.command = cmd;
for(int i=0; i<sizeof(pzem.addr); i++)
pzem.addr[i] = addr[i];
pzem.data = data;
uint8_t *bytes = (uint8_t*)&pzem;
pzem.crc = crc(bytes, sizeof(pzem) - 1);
while(serial->available())
serial->read();
serial->write(bytes, sizeof(pzem));
}
bool PZEM004T::recieve(uint8_t resp, uint8_t *data)
{
uint8_t buffer[RESPONSE_SIZE];
#ifdef PZEM004_SOFTSERIAL
if(_isSoft)
((SoftwareSerial *)serial)->listen();
#endif
unsigned long startTime = millis();
uint8_t len = 0;
while((len < RESPONSE_SIZE) && (millis() - startTime < _readTimeOut))
{
if(serial->available() > 0)
{
uint8_t c = (uint8_t)serial->read();
if(!c && !len)
continue; // skip 0 at startup
buffer[len++] = c;
}
yield(); // do background netw tasks while blocked for IO (prevents ESP watchdog trigger)
}
if(len != RESPONSE_SIZE)
return false;
if(buffer[6] != crc(buffer, len - 1))
return false;
if(buffer[0] != resp)
return false;
if(data)
{
for(int i=0; i<RESPONSE_DATA_SIZE; i++)
data[i] = buffer[1 + i];
}
return true;
}
uint8_t PZEM004T::crc(uint8_t *data, uint8_t sz)
{
uint16_t crc = 0;
for(uint8_t i=0; i<sz; i++)
crc += *data++;
return (uint8_t)(crc & 0xFF);
}
And here is the code for PZEM004T.h
#ifndef PZEM004T_H
#define PZEM004T_H
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
// #define PZEM004_NO_SWSERIAL
#if (not defined(PZEM004_NO_SWSERIAL)) && (defined(__AVR__) || defined(ESP8266))
#define PZEM004_SOFTSERIAL
#endif
#if defined(PZEM004_SOFTSERIAL)
#include <SoftwareSerial.h>
#endif
#include <IPAddress.h>
#define PZEM_DEFAULT_READ_TIMEOUT 1000
#define PZEM_ERROR_VALUE -1.0
struct PZEMCommand {
uint8_t command;
uint8_t addr[4];
uint8_t data;
uint8_t crc;
};
class PZEM004T
{
public:
PZEM004T(uint8_t receivePin, uint8_t transmitPin);
PZEM004T(HardwareSerial *port);
~PZEM004T();
void setReadTimeout(unsigned long msec);
unsigned long readTimeout() {return _readTimeOut;}
float voltage(const IPAddress &addr);
float current(const IPAddress &addr);
float power(const IPAddress &addr);
float energy(const IPAddress &addr);
bool setAddress(const IPAddress &newAddr);
bool setPowerAlarm(const IPAddress &addr, uint8_t threshold);
private:
Stream *serial;
bool _isSoft;
unsigned long _readTimeOut = PZEM_DEFAULT_READ_TIMEOUT;
void send(const IPAddress &addr, uint8_t cmd, uint8_t data = 0);
bool recieve(uint8_t resp, uint8_t *data = 0);
uint8_t crc(uint8_t *data, uint8_t sz);
};
#endif // PZEM004T_H
And here is the code for SoftwareSerial.h:
#include <SoftwareSerial.h>
// software serial #1: RX = digital pin 10, TX = digital pin 11
SoftwareSerial portOne(10, 11);
// software serial #2: RX = digital pin 8, TX = digital pin 9
// on the Mega, use other pins instead, since 8 and 9 don't work on the Mega
SoftwareSerial portTwo(8, 9);
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// Start each software serial port
portOne.begin(9600);
portTwo.begin(9600);
}
void loop() {
// By default, the last intialized port is listening.
// when you want to listen on a port, explicitly select it:
portOne.listen();
Serial.println("Data from port one:");
// while there is data coming in, read it
// and send to the hardware serial port:
while (portOne.available() > 0) {
char inByte = portOne.read();
Serial.write(inByte);
}
// blank line to separate data from the two ports:
Serial.println();
// Now listen on the second port
portTwo.listen();
// while there is data coming in, read it
// and send to the hardware serial port:
Serial.println("Data from port two:");
while (portTwo.available() > 0) {
char inByte = portTwo.read();
Serial.write(inByte);
}
// blank line to separate data from the two ports:
Serial.println();
}