Skip to content

Commit

Permalink
Preliminary support for ESP32/PZEM004Tv30
Browse files Browse the repository at this point in the history
Wrapper class for PZEM004T/PZEM004Tv30 libs, controlled with USE_PZEMv3 definition

Note: Async Server has lot's of issues under esp32

me-no-dev/ESPAsyncWebServer#876
me-no-dev/ESPAsyncWebServer#900
espressif/arduino-esp32#1101
me-no-dev/ESPAsyncWebServer#324
me-no-dev/ESPAsyncWebServer#932

Signed-off-by: Emil Muratov <gpm@hotplug.ru>
  • Loading branch information
vortigont committed Apr 23, 2021
1 parent f65315d commit c4b52ec
Show file tree
Hide file tree
Showing 10 changed files with 268 additions and 106 deletions.
20 changes: 15 additions & 5 deletions espem/config.h
Expand Up @@ -11,15 +11,25 @@


#define FW_NAME "espem"
#define PMeterESP_VER FW_NAME

#ifdef ESP8266
#define HWSERIAL_PORT UART0
#define ESPEM_USE_HWSERIAL

#ifndef HWSERIAL_PORT
#ifdef ESP8266
#define HWSERIAL_PORT UART0
#endif
#ifdef ESP32
#define HWSERIAL_PORT (2U)
#endif
#endif
#ifdef ESP32
#define HWSERIAL_PORT (2U)

#ifdef USE_PZEMv3
#define PZEM_LIB (PZEM004T)
#else
#define PZEM_LIB (PZEM004Tv30)
#endif


// LOG macro's
#if defined(LOG)
#undef LOG
Expand Down
63 changes: 44 additions & 19 deletions espem/default_config.h
Expand Up @@ -3,46 +3,71 @@

#pragma once

// Use HW serial pins to connect to PZEM
// see notes below
//#define ESPEM_USE_HWSERIAL
/*
* PZEM library version
* if defined 'USE_PZEMv3', than PZEM hardware version v3.0 is used with a library PZEM-004T-v30
* otherwise used an old PZEM004T with Oleh's library
*/
//#define USE_PZEMv3

// By default Hardware Serial is used for interacting with PZEM
/* ***** SoftWare Serial is deprecated *****
it might still work flawlessly but no longer supported
// ESP has two UART ports - UART0, UART1
// Note: UART0 pins are usually connected to an onboard USB2serial converter
// It's better not to share USB2serial pins for PZEM communication
// Also it's not possible to use 'DEBUG' and 'UART0' at the same time
// Use either UART1 pin for debug or software serial for pzem connection on any other GPIO's available
// for details, see http://esp8266.github.io/Arduino/versions/2.1.0-rc2/doc/reference.html#serial
*/ Uncomment this to use Software Serial pins to connect to PZEM
/*
#ifdef ESPEM_USE_HWSERIAL
#undef ESPEM_USE_HWSERIAL
#endif
*/

// Swap hw_serial from default gpio1,3 to gpio13(tx),gpio15(rx)
/* ESP8266 has two UART ports - UART0, UART1
Note: UART0 pins are usually connected to an onboard USB2serial converter
It's better not to share USB2serial pins for PZEM communication
Also it's not possible to use 'DEBUG' and 'UART0' at the same time
Use either UART1 pin for debug or software serial for pzem connection on any other GPIO's available
for details, see http://esp8266.github.io/Arduino/versions/2.1.0-rc2/doc/reference.html#serial
HW Serial to use:
for esp8266 values are: UART0, UART1 (can not actually be used)
for esp32 values are: (0U), (1U), (2U)
default is:
UART0 for esp8266
(2U) for esp32 /pins IO16 (RX2) and IO17 (TX2)/
*/
//#define HWSERIAL_PORT UART0

// ESP8266 - Swap hw_serial from default gpio1,3 to gpio13(tx),gpio15(rx)
// Note: gpio15 must be pulled low on esp start, otherwise it won't boot from eeprom
// Pzem pulls it's RX pin high via optocoupler's led, so make sure to workaround it anyhow
// https://github.com/olehs/PZEM004T/wiki/Connecting-PZEM-to-ESP8266

//#define ESPEM_HWSERIAL_SWAP



// Debuging messages via hw serail
// undefined - disabled (default)
//#define ESPEM_DEBUG Serial // output via hwserial0
//#define ESPEM_DEBUG Serial1 // output via hwserial1 TX pin is GPIO2 for 8266


// RX/TX pins for sw_serial
// RX/TX pins for sw_serial OR custom pin maping for ESP32 HWSerial
// If 'USE_HWSERIAL' is not defined than use those GPIO pins for Software serial
//#define PIN_RX 13 // only pins 0-5,12-15 are allowed for RX,TX on ESP
// ***** SoftWare Serial is deprecated *****
//#define PIN_RX 13 // only pins 0-5,12-15 are allowed for RX,TX on ESP8266
//#define PIN_TX 15 // 5, 4 is D1,D2 on NodeMCU board
// 5,14 is D1,D5 on WittyCloud board
// Lolin
// RX D7 GPIO 13
// TX D8 GPIO 15

// TimeZone and country for NTP (optional)
//#define TZONE TZ_Europe_Moscow // Zones defined in cores/esp8266/TZ.h
//#define COUNTRY "ru" // Country double-letter code

// Build with FTP server suuport
// default credentials 'ftp:ftp'
//#define USE_FTP
// Build with FTP server support
/*
#ifndef USE_FTP
#define USE_FTP
*/

// FTP server credentials
// #define FTP_USER "ftp"
// #define FTP_PASSWORD "ftp"
25 changes: 15 additions & 10 deletions espem/espem.cpp
@@ -1,14 +1,19 @@
/* ESPEM - ESP Energy monitor
* A code for ESP8266 based boards to interface with PeaceFair PZEM PowerMeters
* A code for ESP8266/ESP32 based boards to interface with PeaceFair PZEM PowerMeters
* It can poll/collect PowerMeter data and provide it for futher processing in text/json format
*
* (c) Emil Muratov 2017
* (c) Emil Muratov 2018-2021 https://github.com/vortigont/espem
*
*/

#include "espem.h"
#include "EmbUI.h" // EmbUI framework

#ifdef ESP32
#define MAX_FREE_MEM_BLK ESP.getMaxAllocHeap()
#else
#define MAX_FREE_MEM_BLK ESP.getMaxFreeBlockSize()
#endif

// sprintf template for json sampling data
#define JSON_SMPL_LEN 80 // {"t":1615496537000,"U":229.50,"I":1.47,"P":1216,"W":5811338,"pF":0.64},
Expand Down Expand Up @@ -124,8 +129,8 @@ void ESPEM::wdatareply(AsyncWebServerRequest *request){
// return json-formatted response for in-RAM sampled data
void ESPEM::wsamples(AsyncWebServerRequest *request) {

// check if samples vector is not nullptr
if ( !metrics ) {
// check if there is any sampled data
if ( !getMetricsCap() ) {
request->send_P(503, PGmimetxt, PGsmpld);
return;
}
Expand Down Expand Up @@ -218,11 +223,11 @@ size_t PMETRICS::poolAlloc(size_t size){
if (!size)
return 0;

LOG(printf_P, PSTR("PMETRICS: FreeHeap: %d, MaxFreeBlockSize: %d\n"), ESP.getFreeHeap(), ESP.getMaxFreeBlockSize());
LOG(printf_P, PSTR("PMETRICS: FreeHeap: %d, MaxFreeBlockSize: %d\n"), ESP.getFreeHeap(), MAX_FREE_MEM_BLK);

delete samples; // make sure it is free
if (size > ESP.getMaxFreeBlockSize()/1024 - ESPEM_MEMRESERVE)
size = ESP.getMaxFreeBlockSize()/1024 - ESPEM_MEMRESERVE;
if (size > MAX_FREE_MEM_BLK/1024 - ESPEM_MEMRESERVE)
size = MAX_FREE_MEM_BLK/1024 - ESPEM_MEMRESERVE;

samples = new std::vector<pmeterData>(size*1024 / sizeof(pmeterData));

Expand Down Expand Up @@ -264,7 +269,7 @@ mcstate_t PMETRICS::collector(mcstate_t newstate){
break;
}
}
LOG(printf_P, PSTR("Collector state: %d\n"), mcstate);
LOG(printf_P, PSTR("Collector state: %d\n"), (int)mcstate);
return mcstate;
}

Expand All @@ -280,12 +285,12 @@ size_t PMETRICS::poolResize(size_t size){
LOG(printf_P, PSTR("Requested metrics pool change to %d KiB\n"), size);
poolsize = size;

if (!samples || !size){
if (!size){
collector(mcstate_t::MC_DISABLE);
return 0;
}

if (size*1024 < samples->capacity()*sizeof(pmeterData)){
if ( samples && (size*1024 < samples->capacity()*sizeof(pmeterData)) ){
LOG(printf_P, PSTR("Resizing metrics pool to fit %d samples\n"), size*1024 / sizeof(pmeterData));
samples->resize(size*1024 / sizeof(pmeterData));
samples->shrink_to_fit();
Expand Down
37 changes: 26 additions & 11 deletions espem/espem.h
@@ -1,16 +1,21 @@
/* ESPEM - ESP Energy monitor
* A code for ESP8266 based boards to interface with PeaceFair PZEM PowerMeters
* A code for ESP8266/ESP32 based boards to interface with PeaceFair PZEM PowerMeters
* It can poll/collect PowerMeter data and provide it for futher processing in text/json format
*
* (c) Emil Muratov 2018
* (c) Emil Muratov 2018-2021 https://github.com/vortigont/espem
*
*/

#include <vector>
#include <memory>
#include "main.h"
// Libs
#include <PZEM004T.h>
#ifdef USE_PZEMv3
#include <PZEM004Tv30.h>
#else
#include <PZEM004T.h>
#endif
// Tasker object from EmbUI
#include "ts.h"

// Defaults
Expand All @@ -31,10 +36,6 @@
#define ESPEM_MEMRESERVE (4*1024U) // Bytes


//declare pointer-to-member function for PZEM class
typedef float( PZEM004T::*PZPTMF) (const IPAddress& );


// Metrics collector state
enum class mcstate_t{MC_DISABLE=0, MC_RUN, MC_PAUSE};

Expand Down Expand Up @@ -97,6 +98,20 @@ float pf() const {
}
};

#ifdef USE_PZEMv3
class PZEM: public PZEM004Tv30 {
using PZEM004Tv30::PZEM004Tv30;
};
//declare pointer-to-member function for PZEM class
typedef float( PZEM::*PZPTMF)();
#else
class PZEM: public PZEM004T {
using PZEM004T::PZEM004T;
};
//declare pointer-to-member function for PZEM class
typedef float( PZEM::*PZPTMF) (const IPAddress& );
#endif



/**
Expand Down Expand Up @@ -136,7 +151,7 @@ class PMETER {
#endif

// An instance of PZEM lib object
std::unique_ptr<PZEM004T> pzem = nullptr;
std::unique_ptr<PZEM> pzem = nullptr;

IPAddress ip = ESPEM_IPADDR;

Expand All @@ -147,7 +162,7 @@ class PMETER {
unsigned long lastpoll = 0;

//pointer array to lib funtions
PZPTMF pzdatafunc[4] = {&PZEM004T::voltage, &PZEM004T::current, &PZEM004T::power, &PZEM004T::energy};
PZPTMF pzdatafunc[4] = {&PZEM::voltage, &PZEM::current, &PZEM::power, &PZEM::energy};

//a struct for meter data
pmeterData pdata;
Expand All @@ -156,7 +171,7 @@ class PMETER {
// Private Methods
bool pzeminit();

bool pollMeter(std::unique_ptr<PZEM004T> &meter, pmeterData &result, bool fixpf);
bool pollMeter(std::unique_ptr<PZEM> &meter, pmeterData &result, bool fixpf);


};
Expand Down Expand Up @@ -185,7 +200,7 @@ class PMETRICS {
};

~PMETRICS(){
tPoller.disable();
ts.deleteTask(tPoller);
delete samples;
};

Expand Down
17 changes: 9 additions & 8 deletions espem/ftpSrv.h
Expand Up @@ -11,24 +11,25 @@
#define LittleFS LITTLEFS
#endif

//#define FTP_DEBUG
#ifndef FTP_USER
#define FTP_USER "ftp"
#endif
#ifndef FTP_PASSWORD
#define FTP_PASSWORD "ftp"
#endif

//#define FTP_DEBUG
#include <FTPServer.h>

FTPServer ftpSrv(LittleFS); // construct with LittleFS

void ftp_setup(void){

/////FTP Setup, ensure LittleFS is started before ftp; /////////
if (LittleFS.begin()) {
ftpSrv.begin(F("ftp"), F("ftp")); //username, password for ftp. set ports in ESP8266FtpServer.h (default 21, 50009 for PASV)
}
ftpSrv.begin(F(FTP_USER), F(FTP_PASSWORD)); //username, password for ftp. set ports in ESP8266FtpServer.h (default 21, 50009 for PASV)
}
}

void ftp_loop(void){
ftpSrv.handleFTP(); //make sure in loop you call handleFTP()!!
}

//extern void ftp_setup(void);
//extern void ftp_loop(void);
//extern FTPServer ftpSrv;
2 changes: 1 addition & 1 deletion espem/interface.cpp
Expand Up @@ -260,7 +260,7 @@ void set_directctrls(Interface *interf, JsonObject *data){
if (!_s.compareTo(_k)){
mcstate_t _a = espem->collector((mcstate_t)kv.value().as<unsigned short>());
embui.var(_k, String((uint8_t)_a));
LOG(printf_P, PSTR("UI: Changed Collector state to: %d\n"), espem->collector() );
LOG(printf_P, PSTR("UI: Changed Collector state to: %d\n"), (int)espem->collector() );
}

_s=FPSTR(V_SMPLCNT);
Expand Down
19 changes: 17 additions & 2 deletions espem/main.cpp
Expand Up @@ -20,8 +20,11 @@ extern "C" int clock_gettime(clockid_t unused, struct timespec *tp);

// PROGMEM strings
// sprintf template for json version data
#ifdef ESP8266
static const char PGverjson[] PROGMEM = "{\"ChipID\":\"%x\",\"FlashSize\":%u,\"Core\":\"%s\",\"SDK\":\"%s\",\"firmware\":\"%s\",\"version\":\"%s\",\"CPUMHz\":%u,\"Heap\":%u,\"Uptime\":%u,}";

#elif defined ESP32
static const char PGverjson[] PROGMEM = "{\"ChipID\":\"%s\",\"FlashSize\":%u,\"SDK\":\"%s\",\"firmware\":\"%s\",\"version\":\"%s\",\"CPUMHz\":%u,\"Heap\":%u,\"Uptime\":%u,}";
#endif

// Our instance of espem
ESPEM *espem = nullptr;
Expand Down Expand Up @@ -84,7 +87,7 @@ void wver(AsyncWebServerRequest *request) {

timespec tp;
clock_gettime(0, &tp);

#ifdef ESP8266
snprintf_P(buff, sizeof(buff), PGverjson,
ESP.getChipId(),
ESP.getFlashChipSize(),
Expand All @@ -95,6 +98,18 @@ void wver(AsyncWebServerRequest *request) {
ESP.getCpuFreqMHz(),
ESP.getFreeHeap(),
(uint32_t)tp.tv_sec);
#else
snprintf_P(buff, sizeof(buff), PGverjson,
ESP.getChipModel(),
ESP.getFlashChipSize(),
ESP.getSdkVersion(),
FW_NAME,
TOSTRING(FW_VER),
ESP.getCpuFreqMHz(),
ESP.getFreeHeap(),
(uint32_t)tp.tv_sec);
#endif


request->send(200, FPSTR(PGmimejson), buff );
}
Expand Down
2 changes: 2 additions & 0 deletions espem/main.h
Expand Up @@ -6,6 +6,8 @@
*
*/

#pragma once

#define UPD_RESTART_DELAY 5 // restart delay when updating firmware
#define BAUD_RATE 115200 // serial debug port baud rate
#define HTTP_VER_BUFSIZE 200
Expand Down

0 comments on commit c4b52ec

Please sign in to comment.