-
-
Save bfritscher/da9dac542d4d70604b607670c867d555 to your computer and use it in GitHub Desktop.
| /* FOR COMMENTS PLEASE USE https://github.com/bfritscher/esp8266_PZEM-004T */ | |
| /* NOTIFICATION ARE NOT SENT BY EMAIL FOR GISTS :-( */ | |
| // VERSION 2 with WiFIManager integration for device_name | |
| #include <FS.h> //this needs to be first, or it all crashes and burns... | |
| #include <ESP8266WiFi.h> // ESP8266 Core WiFi Library (you most likely already have this in your sketch) | |
| #include <Ticker.h> // for LED status | |
| #include <DNSServer.h> // Local DNS Server used for redirecting all requests to the configuration portal | |
| #include <ESP8266WebServer.h> // Local WebServer used to serve the configuration portal | |
| #include <WiFiManager.h> // https://github.com/tzapu/WiFiManager WiFi Configuration Magic | |
| #include <ArduinoJson.h> //https://github.com/bblanchon/ArduinoJson | |
| #include <ESP8266HTTPClient.h> | |
| #include <SoftwareSerial.h> | |
| #include <PZEM004T.h> // https://github.com/olehs/PZEM004T Power Meter | |
| // select which pin will trigger the configuration portal when set to LOW | |
| #define TRIGGER_PIN 0 | |
| #define MAX_ATTEMPTS 10 | |
| PZEM004T pzem(4,5); // RX,TX (D2, D1) on NodeMCU | |
| IPAddress ip(192,168,1,1); // required by pzem but not used | |
| HTTPClient http; | |
| Ticker ticker; | |
| boolean led = false; | |
| char device_name[40]; | |
| WiFiManagerParameter custom_device_name("name", "device name", device_name, 40, " required"); | |
| void tick() { | |
| //toggle state | |
| led = !led; | |
| pinMode(BUILTIN_LED, OUTPUT); | |
| digitalWrite(BUILTIN_LED, led); // set pin to the opposite state | |
| } | |
| //gets called when WiFiManager enters configuration mode | |
| void configModeCallback (WiFiManager *myWiFiManager) { | |
| //entered config mode, make led toggle faster | |
| ticker.attach(0.2, tick); | |
| } | |
| //callback notifying us of the need to save config | |
| void saveConfigCallback () { | |
| Serial.println("saving config"); | |
| strcpy(device_name, custom_device_name.getValue()); | |
| DynamicJsonBuffer jsonBuffer; | |
| JsonObject& json = jsonBuffer.createObject(); | |
| json["device_name"] = device_name; | |
| File configFile = SPIFFS.open("/config.json", "w"); | |
| if (!configFile) { | |
| Serial.println("failed to open config file for writing"); | |
| } | |
| json.printTo(Serial); | |
| json.printTo(configFile); | |
| configFile.close(); | |
| } | |
| boolean readConfig() { | |
| // clean FS, for testing | |
| // SPIFFS.format(); | |
| //read configuration from FS json | |
| Serial.println("mounting FS..."); | |
| if (SPIFFS.begin()) { | |
| Serial.println("mounted file system"); | |
| if (SPIFFS.exists("/config.json")) { | |
| //file exists, reading and loading | |
| Serial.println("reading config file"); | |
| File configFile = SPIFFS.open("/config.json", "r"); | |
| if (configFile) { | |
| Serial.println("opened config file"); | |
| size_t size = configFile.size(); | |
| // Allocate a buffer to store contents of the file. | |
| std::unique_ptr<char[]> buf(new char[size]); | |
| configFile.readBytes(buf.get(), size); | |
| DynamicJsonBuffer jsonBuffer; | |
| JsonObject& json = jsonBuffer.parseObject(buf.get()); | |
| json.printTo(Serial); | |
| if (json.success()) { | |
| Serial.println("\nparsed json"); | |
| strcpy(device_name, json["device_name"]); | |
| return true; | |
| } else { | |
| Serial.println("failed to load json config"); | |
| return false; | |
| } | |
| } | |
| } | |
| } else { | |
| Serial.println("failed to mount FS"); | |
| return false; | |
| } | |
| //end read | |
| } | |
| void setup() { | |
| // put your setup code here, to run once: | |
| Serial.begin(115200); | |
| Serial.println("Starting setup"); | |
| // set led pin as output | |
| pinMode(BUILTIN_LED, OUTPUT); | |
| // start ticker with 0.6 because we start in AP mode and try to connect | |
| ticker.attach(0.6, tick); | |
| // WiFiManager | |
| // Local intialization. Once its business is done, there is no need to keep it around | |
| WiFiManager wifiManager; | |
| // wifiManager.setDebugOutput(false); | |
| // reset settings - for testing | |
| // wifiManager.resetSettings(); | |
| // sets timeout until configuration portal gets turned off | |
| // useful to make it all retry or go to sleep in seconds | |
| wifiManager.setTimeout(180); | |
| //set config save notify callback | |
| wifiManager.setSaveConfigCallback(saveConfigCallback); | |
| // set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode | |
| wifiManager.setAPCallback(configModeCallback); | |
| //add all your parameters here | |
| wifiManager.addParameter(&custom_device_name); | |
| // wifiManager.setCustomHeadElement("<style>html{filter: invert(100%); -webkit-filter: invert(100%);}</style>"); | |
| if(!readConfig()) { | |
| wifiManager.resetSettings(); | |
| } | |
| // fetches ssid and pass and tries to connect | |
| // if it does not connect it starts an access point with auto generated name from 'ESP' and the esp's Chip ID use | |
| // and goes into a blocking loop awaiting configuration | |
| String ssid = "POWER_MONITOR_" + String(ESP.getChipId()); | |
| if(!wifiManager.autoConnect(ssid.c_str(), NULL)) { | |
| Serial.println("failed to connect and hit timeout"); | |
| //reset and try again, or maybe put it to deep sleep | |
| ESP.reset(); | |
| delay(5000); | |
| } | |
| // if you get here you have connected to the WiFi | |
| ticker.detach(); | |
| // keep LED on | |
| digitalWrite(BUILTIN_LED, LOW); | |
| pzem.setAddress(ip); | |
| delay(5000); | |
| // keep LED off | |
| digitalWrite(BUILTIN_LED, HIGH); | |
| } | |
| // could make generic and pass a pointer to the right function... | |
| float getVoltage() { | |
| int i = 0; | |
| float r = -1.0; | |
| do { | |
| r = pzem.voltage(ip); | |
| wdt_reset(); | |
| i++; | |
| } while ( i < MAX_ATTEMPTS && r < 0.0); | |
| return r; | |
| } | |
| float getCurrent() { | |
| int i = 0; | |
| float r = -1.0; | |
| do { | |
| r = pzem.current(ip); | |
| wdt_reset(); | |
| i++; | |
| } while ( i < MAX_ATTEMPTS && r < 0.0); | |
| return r; | |
| } | |
| float getPower() { | |
| int i = 0; | |
| float r = -1.0; | |
| do { | |
| r = pzem.power(ip); | |
| wdt_reset(); | |
| i++; | |
| } while ( i < MAX_ATTEMPTS && r < 0.0); | |
| return r; | |
| } | |
| float getEnergy() { | |
| int i = 0; | |
| float r = -1.0; | |
| do { | |
| r = pzem.energy(ip); | |
| wdt_reset(); | |
| i++; | |
| } while ( i < MAX_ATTEMPTS && r < 0.0); | |
| return r; | |
| } | |
| void sendMeasures() { | |
| float v = getVoltage(); | |
| Serial.print(v);Serial.print("V; "); | |
| float i = getCurrent(); | |
| Serial.print(i);Serial.print("A; "); | |
| float p = getPower(); | |
| Serial.print(p);Serial.print("W; "); | |
| float e = getEnergy(); | |
| Serial.print(e);Serial.print("Wh; "); | |
| String payload = ""; | |
| if(v >= 0.0) payload += "voltage,device_name=" + String(device_name) + " value=" + String(v, 2) + "\n"; | |
| if(i >= 0.0) payload += "current,device_name=" + String(device_name) + " value=" + String(i, 2) + "\n"; | |
| if(p >= 0.0) payload += "power,device_name=" + String(device_name) + " value=" + String(p, 2) + "\n"; | |
| if(e >= 0.0) payload += "energy,device_name=" + String(device_name) + " value=" + String(e, 2) + "\n"; | |
| Serial.print(payload); | |
| if (payload=="") { | |
| Serial.println(); | |
| return; | |
| } | |
| http.begin("[HOST]/influxdb/write?db=power"); | |
| http.addHeader("cache-control", "no-cache"); | |
| http.setAuthorization("[HASH]"); | |
| int httpCode = http.POST(payload); | |
| Serial.print(httpCode); | |
| if (httpCode < 0) { | |
| Serial.println(); | |
| Serial.printf("[HTTP]... failed, error: %s\n", http.errorToString(httpCode).c_str()); | |
| Serial.println(); | |
| Serial.print(payload); | |
| } | |
| http.end(); | |
| Serial.println(); | |
| } | |
| void loop() { | |
| // put your main code here, to run repeatedly: | |
| sendMeasures(); | |
| delay(5000); | |
| // is configuration portal requested? | |
| if ( digitalRead(TRIGGER_PIN) == LOW ) { | |
| digitalWrite(BUILTIN_LED, LOW); | |
| WiFiManager wifiManager; | |
| wifiManager.resetSettings(); | |
| SPIFFS.format(); | |
| ESP.reset(); | |
| delay(5000); | |
| } | |
| } |
I have a lot of bad readings -1, but polling until it gets a value works for me.
Hi, I have this same hardware working with TASMOTA firm. Did you connect it with 3.3v power supply? I modified R17 to work at 3.3v and arduino boards can read it, but I have problems with ESP8266 boards and 3.3v power supply. Thanks in advance!!
It looks like there is an error in the code. In line 166: while ( r < MAX_ATTEMPTS && r < 0.0);. I guess the r should be i instead as you want to quit the loop after the number of attempts, when nothing is read. Same issue in line 177, 188 and 199.
I used a stripped version of the code as I don't implement a wifi communication. Working well. Thanks for the good work
@amazigh007 Thanks!
@vicfergar I use 5V of the nodemcu and now from PSU see
https://github.com/bfritscher/esp8266_PZEM-004T
NOTIFICATION ARE NOT SENT BY EMAIL FOR GISTS :-(
Hey man, I wonder if you could show some code like this for ArduinoJson v 6. Thank you.
Hi, So im able to connect my Pzem and get all the readings, but ive noticed that sometimes the voltage comes 0 while the circuit is connected and sometimes the current comes 0 and the energy shows invalid values, all this happens randomly. Do you how this problem can be solved ?