Giter Site home page Giter Site logo

vortigont / pzem-edl Goto Github PK

View Code? Open in Web Editor NEW
17.0 5.0 2.0 1.04 MB

An event-driven library for ESP32 implementing PZEM-004T v3.0 / PZEM-003 / PZEM-017 Modbus-RTU proto

License: GNU General Public License v3.0

C++ 99.21% CMake 0.79%
pzem-004t pzem004t pzem004t30 pzem pzem-004tv30 peacefair energymonitoring powermeter pzem-017 pzem-003

pzem-edl's Introduction

PZEM-EDL - PZEM event-driven library

BUILD | EXAMPLES | CHANGELOG | DOCS | LINKS | PlatformIO CI

This is an ESP32 Arduino/esp-idf library implementing communication interface for PeaceFair PZEM-004Tv3.0/PZEM-003 Energy monitor modules via MODBUS proto.

The main idea is that lib uses FreeRTOS features to implement non-blocking event-driven operation when exchanging messages via serial port. It is written to run multiple PZEM devices simultaneously sharing same uart port(s) without blocking on rx/tx operations and at the same time to keep a strict message exchange ordering to prevent transmit collisions.

Feel free to open a discussion topic on any questions.

Main features

  • meant to run multiple PZEM devices, although works fine with a single device also
  • non-blocking code on PZEM request-reply exchange, UART runs in event-mode, no while() loops or polling on rx-read
  • no loop() hooks, loop blocking, etc... actually no loop-dependend code at all
  • background auto-polling driven by RTOS timers
  • event/callback API for user-code hooks
  • Class objects for managing single device/port instances (see example)
  • PZPool to handle multiple PZEM devices of different types groupped on single/multiple Serial port(s) (see example)
  • pzem_cli - a small sketch to interact with pzem via terminal cli
  • Collector module (see example)
    • collecting TimeSeries of metrics data
    • Averaging for TimeSeries
    • iterated circular buffers
    • PSRAM support
  • DummyPZEM004 - a dummy object that provides some random metrics like a real PZEM004 device

Supported modules

  • PZEM-004Tv3.0 (same as PZEM-014/PZEM-016) AC 10/100 Amps meter
  • PZEM-003 (same as PZEM-017) DC 10/50/100/200/300 Amps meter (not tested)

Reference project

I use this lib for my own poject - ESPEM. It has WebUI to display PZEM data, live charts to plot collected TimeSeries data, JSON export, MQTT publishing.

Limitations

  • ESP32 platform only (Arduino/ESP-IDF compatible)
  • Hardware Serial only (not a problem for esp32, it has 3 of it with pin remapping)

How it works

A classic design for Arduino code work like this:

  1. user code asks the lib "hey, send a message to PZEM and give me the reply"
  2. lib replies - "OK pls, wait right here, I'm sending a message and awaiting responce", than it makes a req message and sends it to PZEM via uart
  3. than lib blocks the whole loop() code and starts listening for uart RX data awaiting PZEM to craft a responce and return back
  4. lib code waits and waits while data slowly, byte by byte, arrives via uart everytime checking if it has enough data to proceed with a message
  5. when there is enough bytes received lib decodes message and returns control to the user code
  6. worst case scenario - PZEM is not responding and the whole code is blocked untill timeout expires
  7. only now user code is able to process the reply and make a new request

An average RTT that takes PZEM to respond is about 70ms. Multiply this sequence by 3 (or more) devices at 1 second poll rate and it will turn into MCU have to spend 20-25% of it's time just sit and waiting for UART TX/RX.

Now with event-driven approach:

  1. user code asks the lib "hey, send a message to PZEM and give me the reply"
  2. lib replies immidiately "hey, this will take too long to wait, go mind your own business, just leave me a hook and I will ping you, once reply received"
  3. then it crafts the packet and places it into the queue with an instruction like "hey, RTOS, pls pipe this data over serial when available and ping me when you got some reply data, I will take a nap meanwhile :)"
  4. user-code: "I know, it's too early, but here is another request for another PZEM..."
  5. lib: "no problem, leave it here, I will send it once uart is free "
  6. than lib sleep waits until an event from uart comes that there is some data received
  7. it retreives data from buffer and pings user-code - "here is your data, pick it up anytime"

DummyPZEM004

A Dummy abstration class that inheritcs PZEM004 but is a fake device stub. It behaves like it has a connection to real PZEM device but responds with a faked random meterings. Could be really handy for prototyping without the need to connect to a real PZEM devices.

History

I needed to run 3 PZEM devices from one MCU for my ESPEM project and found that existing implementations are pretty poor on running multiple pzem devs, have issues with WiFi and blocking code. So deciced to make my own implementation along with learning some new features about RTOS and ESP IDF framework. My sincere regards to the authors of original PZEM libs - olehs and mandulaj. I've been using their libs for a long time and it inspired me to go on with a new design.

License

Library code is available under GNU General Public License v3.0

Links

PZEM-004Tv3.0 datasheet - User manual, datasheet and MODBUS commands specs

olehs - This is were it all started. An arduino lib for the legacy version of PZEM004t device

mandulaj - Jakub's version of the library for newer PZEM-004T-v3.0 devices supporting MODBUS proto

TheHWcave - reverse-engineered schematics and interface software (python)

zbx-sadman / zabbuino - A Zabbix agent firmware for Arduino supporting PZEM meters

PZEM on TASMOTA - Tasmota has it's own embeded support for PZEM

PZEM-017-v1 - lib for the DC version PZEM-017-v1

pzem-edl's People

Contributors

vortigont avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

pzem-edl's Issues

Multiple instance example crashes

I've setup my PZEMs as per the CLI instructions and run the sample. Only change is that my GPIO pins are 16 and 17. So changed

#define RX_PIN 16           // custom RX pin number
#define TX_PIN 17           // custom TX pin number

Upon running the example crashes with:

PZEM multiple instance example

Added port id:10
Added PZEM id:42 addr:10, port id:1
Added PZEM id:43 addr:11, port id:1
Added PZEM id:44 addr:12, port id:1
abort() was called at PC 0x400ebf8b on core 1

ELF file SHA256: 0000000000000000

Backtrace: 0x40084f18:0x3ffb1e50 0x4008518d:0x3ffb1e70 0x400ebf8b:0x3ffb1e90 0x400ebfd2:0x3ffb1eb0 0x400ec0eb:0x3ffb1ed0 0x400eec13:0x3ffb1ef0 0x400d12a6:0x3ffb1f10 0x400d4492:0x3ffb1fb0 0x40086dfd:0x
--- exit ---
3ffb1fd0
  #0  0x40084f18:0x3ffb1e50 in invoke_abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c:715
  #1  0x4008518d:0x3ffb1e70 in abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c:715
  #2  0x400ebf8b:0x3ffb1e90 in __cxxabiv1::__terminate(void (*)()) at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/eh_terminate.cc:112
  #3  0x400ebfd2:0x3ffb1eb0 in std::terminate() at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/eh_terminate.cc:112
  #4  0x400ec0eb:0x3ffb1ed0 in __cxa_pure_virtual at ??:?
  #5  0x400eec13:0x3ffb1ef0 in PZPool::updateMetrics() at .pio/libdeps/example/pzem-edl/src/pzem_edl.cpp:303
  #6  0x400d12a6:0x3ffb1f10 in setup() at src/main.cpp:110
  #7  0x400d4492:0x3ffb1fb0 in loopTask(void*) at /Users/nevilledastur/.platformio/packages/framework-arduinoespressif32/cores/esp32/main.cpp:18
  #8  0x40086dfd:0x3ffb1fd0 in vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c:355 (discriminator 1)

Multiple PZEM example - Single Variable Compile Error

Hi @vortigont, thanks for the nice Lib!

Im not a specialist in Programming, so I need to aks some silly questions.

I Use 3x PZEM and they work great with your example code.

pz004::rx_msg_prettyp(m); Gives me the Whole list of Values of the Boards wich is great!

What I need to do is only get Voltages / Currents / Power etc. and write them in custom variables.

I tried this from the main.cpp to get the current from one Sensor:

void mycallback(uint8_t id, const RX_msg* m){

auto *m = (const pz004::metrics*)meters->getMetrics(PZEM_ID_2)
Serial.printf("PZEM '%s' current as float: %.3f (Amps)\n", meters->getDescr(PZEM_ID_2), m->asFloat(meter_t::cur));

But it wont compile and gives me errors.

I also dont need floats, so raw Integer values would be enough for me.

how do I access the single values within the callback (Raw values & Floats)?

Thanks in advance!

Your examples do not compile in Arduino IDE

Swears like this -

In file included from C:\Users\User\Documents\Arduino\libraries\pzem-edl-main\examples\03_MultiplePZEM004\src\main.h:14:0,
from C:\Users\User\Documents\Arduino\libraries\pzem-edl-main\examples\03_MultiplePZEM004\src\main.cpp:14:
C:\Users\User\Documents\Arduino\libraries\pzem-edl-main\src/pzem_edl.hpp:18:19: fatal error: LList.h: No such file or directory
compilation terminated.
exit status 1
Compilation error for board ESP32 Dev Module.

What to do?

esp32/spiram.h is missing

@vortigont , after updating to new version of this library, I get an error while compiling "In file included from espem/espem.h:12:0,
from espem/interface.cpp:1:
.pio/libdeps/espem/pzem-edl/src/timeseries.hpp:32:26: fatal error: esp32/spiram.h: No such file or directory
compilation terminated.
In file included from espem/espem.h:12:0,
from espem/espem.cpp:9:
.pio/libdeps/espem/pzem-edl/src/timeseries.hpp:32:26: fatal error: esp32/spiram.h: No such file or directory
compilation terminated.
*** [.pio\build\espem\src\interface.cpp.o] Error 1
*** [.pio\build\espem\src\espem.cpp.o] Error 1
In file included from espem/espem.h:12:0,
from espem/main.cpp:11:
.pio/libdeps/espem/pzem-edl/src/timeseries.hpp:32:26: fatal error: esp32/spiram.h: No such file or directory
compilation terminated.
*** [.pio\build\espem\src\main.cpp.o] Error 1
============================================================ [FAILED] Took 8.03 seconds ============================================================
Environment Status Duration


espem FAILED 00:00:08.027
====================================================== 1 failed, 0 succeeded in 00:00:08.027 ====================================================== "

and an error in the main.cpp also as shown in the screen shot below

image

loop() not working / Execute own program Code Example.

Hi @vortigont,

It´s Me again. I had success with the Signale Values, now I tried to add some stuff to loop() and it is not working.

this kind of Programing is new to me, can you give a newbie a example on how to execute my "own" code? with your Library?

Sorry for these kind of questions, but i would love to use ur Library for my projekt.

Thanks in advance.

Значение потребленной мощности в киловатт часах, сбросилось и начало считать заново

{"age":245,"U":200.1,"I":10.79,"P":2104,"W":16976,"hz":50.0,"pF":0.97}
Вчера значение когда подключил esp значение показало 52квч, хотя на прошивке тасмола было 378 квч, сегодня же значение пошло считать заново, при этом достало примерно до 65квч и сбросилось, мое предположение что это проблема может быть в переменной unsigned int у которой значения 0… 65 535

Resetting energy counter

I can't find a way to reset the power meters back to zero. I.e. a Energy counter reset

From https://github.com/mandulaj/PZEM-004T-v30/blob/master/src/PZEM004Tv30.cpp

/*!
 * PZEM004Tv30::resetEnergy
 *
 * Reset the Energy counter on the device
 *
 * @return success
*/
bool PZEM004Tv30::resetEnergy(){
    uint8_t buffer[] = {0x00, CMD_REST, 0x00, 0x00};
    uint8_t reply[5];
    buffer[0] = _addr;

    setCRC(buffer, 4);
    _serial->write(buffer, 4);

    uint16_t length = receive(reply, 5);

    if(length == 0 || length == 5){
        return false;
    }

    return true;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.