Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple PZEM004T #1051

Closed
0x3333 opened this issue Jul 13, 2018 · 6 comments
Closed

Multiple PZEM004T #1051

0x3333 opened this issue Jul 13, 2018 · 6 comments
Labels
Milestone

Comments

@0x3333
Copy link
Contributor

0x3333 commented Jul 13, 2018

Hi!

I'm working on a project that has 3 PZEM004T sensors connected to the same UART. They have addresses and only respond when the message is directed to them.

My schematics is like this:
1e1675e4-147b-4ebd-82ef-92ea8a1bca27

What is the way you think is right to implement on ESPurna? Create a new "sensor" , or retrofit the actual PZEM004TSensor.h?

@xoseperez
Copy link
Owner

Not sure but I would first try to use the current PZEM004TSensor class to handle it. Currently, it has a hardcoded address of 192.168.1.1. So you will first need to be able to pass a certain value and also a way to set the addresses individually. Not sure how this is done...

@xoseperez xoseperez added enhancement New feature or request sensors labels Jul 17, 2018
@0x3333
Copy link
Contributor Author

0x3333 commented Jul 17, 2018

Here is a preliminary version, not fully tested yet, I'll test tonight with 4 PZEM004T. See if it is in the right direction, I'll finalize it then I'll create a PR.

This implementation has no side effects for current users. It will work the same as before but will accept more addresses and work accordingly.

I'm also considering adding support for direction detection, see here: Measure direction hack. Do you believe we have space for this kind of modification or should this live in a private version?

diff --git a/code/espurna/config/sensors.h b/code/espurna/config/sensors.h
index 4df614e4..aa17e0ba 100644
--- a/code/espurna/config/sensors.h
+++ b/code/espurna/config/sensors.h
@@ -537,6 +537,10 @@
 #define PZEM004T_HW_PORT                Serial  // Hardware serial port (if PZEM004T_USE_SOFT == 0)
 #endif

+#ifndef PZEM004T_ADDRESSES
+#define PZEM004T_ADDRESSES              "192.168.1.1" // Multiple addresses can be provided, separated by space("192.168.1.1 192.168.1.2 192.168.1.3")
+#endif
+
 //------------------------------------------------------------------------------
 // SHT3X I2C (Wemos) temperature & humidity sensor
 // Enable support by passing SHT3X_SUPPORT=1 build flag
diff --git a/code/espurna/sensor.ino b/code/espurna/sensor.ino
index 06e40e7a..35c45b11 100644
--- a/code/espurna/sensor.ino
+++ b/code/espurna/sensor.ino
@@ -544,6 +544,7 @@ void _sensorLoad() {
         #else
             sensor->setSerial(& PZEM004T_HW_PORT);
         #endif
+        sensor->setAddresses(PZEM004T_ADDRESSES);
         _sensors.push_back(sensor);
     }
     #endif
diff --git a/code/espurna/sensors/PZEM004TSensor.h b/code/espurna/sensors/PZEM004TSensor.h
index 2d2f8037..a125e860 100644
--- a/code/espurna/sensors/PZEM004TSensor.h
+++ b/code/espurna/sensors/PZEM004TSensor.h
@@ -9,9 +9,13 @@

 #include "Arduino.h"
 #include "BaseSensor.h"
+#include <string.h>

 #include <PZEM004T.h>

+#define MAGNITUDE_COUNT                 4
+#define MAX_DEVICES                     5
+
 class PZEM004TSensor : public BaseSensor {

     public:
@@ -21,13 +25,15 @@ class PZEM004TSensor : public BaseSensor {
         // ---------------------------------------------------------------------

         PZEM004TSensor(): BaseSensor() {
-            _count = 4;
             _sensor_id = SENSOR_PZEM004T_ID;
-            _ip = IPAddress(192,168,1,1);
         }

         ~PZEM004TSensor() {
             if (_pzem) delete _pzem;
+            for(int i = 0; i < _addresses.size() ; i++) {
+                delete _addresses[i];
+            }
+            _addresses.clear();
         }

         // ---------------------------------------------------------------------
@@ -49,6 +55,25 @@ class PZEM004TSensor : public BaseSensor {
             _dirty = true;
         }

+        void setAddresses(char const *addresses) {
+            char const * sep = " ";
+            char tokens[strlen(addresses) + 1];
+            strlcpy(tokens, addresses, sizeof(tokens));
+            char *address = tokens;
+
+            int i = 0;
+            address = strtok(address, sep);
+            while (address != 0 && i++ < MAX_DEVICES) {
+                IPAddress * addr = new IPAddress();
+                if (addr->fromString(address)) {
+                    _addresses.push_back(addr);
+                }
+                address = strtok(0, sep);
+            }
+            _count = _addresses.size() * 4;
+            _dirty = true;
+        }
+
         // ---------------------------------------------------------------------

         unsigned char getRX() {
@@ -74,7 +99,9 @@ class PZEM004TSensor : public BaseSensor {
             } else {
                 _pzem = new PZEM004T(_pin_rx, _pin_tx);
             }
-            _pzem->setAddress(_ip);
+            if(_addresses.size() == 1) {
+                _pzem->setAddress(*(_addresses[0]));
+            }

             _ready = true;
             _dirty = false;
@@ -83,7 +110,7 @@ class PZEM004TSensor : public BaseSensor {

         // Descriptive name of the sensor
         String description() {
-            char buffer[28];
+            char buffer[27];
             if (_serial) {
                 snprintf(buffer, sizeof(buffer), "PZEM004T @ HwSerial");
             } else {
@@ -99,11 +126,14 @@ class PZEM004TSensor : public BaseSensor {

         // Address of the sensor (it could be the GPIO or I2C address)
         String address(unsigned char index) {
-            return _ip.toString();
+            int i = index / MAGNITUDE_COUNT;
+            return _addresses[i]->toString();
         }

         // Type for slot # index
         unsigned char type(unsigned char index) {
+            int i = index / MAGNITUDE_COUNT;
+            index = index - (i * MAGNITUDE_COUNT);
             if (index == 0) return MAGNITUDE_CURRENT;
             if (index == 1) return MAGNITUDE_VOLTAGE;
             if (index == 2) return MAGNITUDE_POWER_ACTIVE;
@@ -113,11 +143,13 @@ class PZEM004TSensor : public BaseSensor {

         // Current value for slot # index
         double value(unsigned char index) {
+            int i = index / MAGNITUDE_COUNT;
+            IPAddress ip = *(_addresses[i]);
             double response = 0;
-            if (index == 0) response = _pzem->current(_ip);
-            if (index == 1) response = _pzem->voltage(_ip);
-            if (index == 2) response = _pzem->power(_ip);
-            if (index == 3) response = _pzem->energy(_ip) * 3600;
+            if (index == 0) response = _pzem->current(ip);
+            if (index == 1) response = _pzem->voltage(ip);
+            if (index == 2) response = _pzem->power(ip);
+            if (index == 3) response = _pzem->energy(ip) * 3600;
             if (response < 0) response = 0;
             return response;
         }
@@ -130,7 +162,7 @@ class PZEM004TSensor : public BaseSensor {

         unsigned int _pin_rx = PZEM004T_RX_PIN;
         unsigned int _pin_tx = PZEM004T_TX_PIN;
-        IPAddress _ip;
+        std::vector<IPAddress *> _addresses;
         HardwareSerial * _serial = NULL;
         PZEM004T * _pzem = NULL;

@0x3333
Copy link
Contributor Author

0x3333 commented Jul 20, 2018

Looks like it is working, just some small changes to the diff I sent.

I also added a command PZEM.SETADDR X.X.X.X, this will set the Address in the PZEM004T, so the user can disconnect all PZEMs and connect one by one to set its address. This is necessary only once, the PZEM will hold its address across restarts.

Unfortunately, I have only 2 PZEMs to test, but others in the mail.

screen shot 2018-07-19 at 23 39 59

@0x3333
Copy link
Contributor Author

0x3333 commented Jul 20, 2018

I'll finish some tests and submit a PR.

@0x3333
Copy link
Contributor Author

0x3333 commented Jul 23, 2018

Well, after some digging, looks like the ESP can't handle 3 or more devices, it hangs, probably too busy to handle all magnitudes of all devices. I made it work for 3 devices, but too much unreliable, some readings fail, sometimes the device panic, doesn't worth the PR. I'll work on a version using an Atmega Pro Mini handling the PZEM reading and forwarding to an ESP-01 module with Espurna, probably will create a new sensor that can handle all readings in the same request.

I'll close this bug.

@0x3333 0x3333 closed this as completed Jul 23, 2018
@0x3333
Copy link
Contributor Author

0x3333 commented Oct 29, 2018

I'm reopening this issue because I could figure out a way to handle multiple PZEM004T devices.

The concept is the same, multidrop UART TX.

I also added 3 commands:

pz.address [ADDRESS]: Print the addresses of all devices, with ADDRESS will issue Set Address command on the bus. This is to be used to program PZEM004T to a specific address.
pz.reset [DEV_INDEX]: Reset the Energy magnitude on all devices or the device index specified(DEV_INDEX).
pz.value [DEV_INDEX]: Print the last reading of all devices or the device index specified(DEV_INDEX).

I just need to confirm that the set address in the PZEM004T is persistent across reboots, otherwise, I'll need to add more changes,

I'll submit the PR to start the discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants