| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395 |
- #include <FS.h>
- #include <ESP8266WiFi.h>
- #include <WiFiClient.h>
- #include <PubSubClient.h>
- #include <SDM.h>
- #include <SoftwareSerial.h>
- #include <ArduinoJson.h>
- #include <RTClib.h>
- #include <Wire.h>
- #include <SPI.h>
- #include <SD.h>
- #include <EEPROM.h>
- #include <WiFiManager.h>
- #include <ESP8266WebServer.h>
- #include <DNSServer.h>
- File myFile;
- #define ESP8266
- int band =1;
- int band_day =1;
- int dia_next;
- int mes_next;
- int dia_nextEEPROM;
- int mes_nextEEPROM;
- char t2_EEPROM[15];
- int anho_EEPROM;
- int dia_EEPROM;
- int mes_EEPROM;
- int diaEEPROM;
- int linea1_EEPROM;
- RTC_DS3231 rtc;
- char meterID[10];
- //Configuracion contador
- SoftwareSerial swSerSDM;
- SDM sdm(swSerSDM, 2400, 16, SWSERIAL_8N1, 0, 2);
- // Servidor MQTT
- char SERVER[50] = "192.168.100.5"; // denmark.inverlec.solar
- int SERVERPORT = 31010;
- WiFiClient espClient;
- PubSubClient client(espClient);
- // Callback al recibir mensaje por MQTT
- void callback(char* topic, byte* payload, unsigned int length) {
- Serial.print("Message arrived [");
- Serial.print(topic);
- Serial.print("] ");
- for (int i = 0; i < length; i++) {
- Serial.print((char)payload[i]);
- }
- Serial.println();
- }
- //funcion para mandar a mqqt la lectura cada 10s, 15 min y guardar en memoria SD
- int denmark() {
- char bufout[10];
- //Variable JSON que se mandara a mqtt aproximadamente cada 10 segundos
- StaticJsonDocument<500> JSONencoder;//Se define variable JSON
- char t1[15];
- DateTime now = rtc.now();
- sprintf(t1, "%02d-%02d-%02d %02d:%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second()); //Extrae del rtc hora y fecha
- JSONencoder["date"] = t1;//Manda al JSON la variable t
- JSONencoder["serialNumber"] = meterID;//numero serial de el medidor
- delay(50);
- JsonObject measures = JSONencoder.createNestedObject("measures");//Anidamos al JSON la variable measures
- float voltage = sdm.readVal(SDM120C_VOLTAGE);
- measures["Readings: Volts A-N"] = voltage;
- delay(50);
- float current = sdm.readVal(SDM120C_CURRENT);
- measures["Readings: I A"] = current;
- delay(50);
- float frequency = sdm.readVal(SDM120C_FREQUENCY);
- measures["Readings: Frequency"] = frequency;
- delay(50);
- float power = sdm.readVal(SDM120C_POWER);
- measures["Readings: Watts A"] = power;
- delay(50);
- float wh_total = sdm.readVal(SDM120C_TOTAL_ACTIVE_ENERGY)*1000;
- measures["Scaled Energy: Wh Net"] = wh_total;
- delay(50);
- float received = sdm.readVal(SDM120CT_IMPORT_ACTIVE_ENERGY)*1000;
- measures["Scaled Energy: Wh received"] = received;
- delay(50);
- float delivered = sdm.readVal(SDM120CT_EXPORT_ACTIVE_ENERGY)*1000;
- measures["Scaled Energy: Wh delivered"] = delivered;
- delay(50);
- float wh_net = (received-delivered);
- measures["Scaled Energy: Wh Total"] = wh_net ;
- delay(50);
-
- char JSONmessageBuffer[300];
- serializeJson(JSONencoder, JSONmessageBuffer);
-
- if (( now.day() == dia_nextEEPROM || diaEEPROM ==0 ||(now.day()>dia_nextEEPROM & mes_nextEEPROM == now.month())) & band_day==1)
- {
- if (diaEEPROM == 0) {
- EEPROM.write(2,2);
- diaEEPROM =2;
- EEPROM.commit();
- }
- dia_next= now.day() + 7;
- mes_next = now.month();
-
- //Estos if es para el no superen el valor de 29, 30 o 31 dependiendo el mes
- if ((now.month()==1 || now.month()==3 || now.month()==5 || now.month()==7 || now.month()==8 || now.month()==10 || now.month()==12) & (dia_next>31)){
- dia_next= dia_next -31;
- mes_next = now.month() + 1;
- }
- else if ((dia_next>30)&(now.month()==4 || now.month()==6 || now.month()==9 || now.month()==11)){
- dia_next= dia_next -30;
- mes_next = now.month() + 1;
- }
- else if ((dia_next>29)&(now.month()==2 & ((now.year()==2020 || now.year()==2024 || now.year()==2028 || now.year()==2032 || now.year()==2036)))){
- dia_next= dia_next -29;
- mes_next = now.month() + 1;
- }
- else if ((dia_next>28)&(now.month()==2)){
- dia_next= dia_next -28;
- mes_next = now.month() + 1;
- }
-
- //Guardando variables EEPROM
- EEPROM.write(6,dia_next);
- EEPROM.write(0,mes_next);
- EEPROM.write(3,now.day());
- EEPROM.write(4,now.year()-2000);//si toma mas de tres dijitos me escribe otra cosa
- EEPROM.write(5,now.month());
- EEPROM.write(7,0);//Variable linea 1
- dia_EEPROM = now.day();
- anho_EEPROM = now.year()-2000;
- mes_EEPROM = now.month();
- dia_nextEEPROM = dia_next;
- mes_nextEEPROM = mes_next;
- linea1_EEPROM = 0;
- EEPROM.commit();
- band_day=2;
- }
- else if (( now.day() != dia_nextEEPROM & diaEEPROM !=0) & band_day==2)
- {
- band_day=1;
- }
-
-
- // if ((now.minute()==00 || now.minute()==15 || now.minute()==30 || now.minute()==45) & band==1)
- if ((now.minute()==00 || now.minute()==05 || now.minute()==10 || now.minute()==15 || now.minute()==20 || now.minute()==25 || now.minute()==30 || now.minute()==35 || now.minute()==40 || now.minute()==45 || now.minute()==50 || now.minute()==55) & band==1) {
- //Variables que seran guardadas en el logging en formato csv
- String linea1=("date,serialNumber,Voltaje (V),Corriente (A),Frecuencia (Hz),Potencia (W),Energia Neta (Wh),Energia Importada (Wh),Energia Exportada (Wh),Energia Total (Wh)");
- String measurescsv = String(t1) + "," + String(meterID)+","+String(voltage) + "," + String(current) + "," + String(frequency) + "," + String(power) + "," + String(wh_total) + "," + String(received) + "," + String(delivered) + "," + String(wh_net);
- Serial.println(measurescsv);
- sprintf(t2_EEPROM, "%02d-%02d-20%02d.csv",dia_EEPROM,mes_EEPROM,anho_EEPROM);
- myFile = SD.open(t2_EEPROM, FILE_WRITE);
- // if the file opened okay, write to it:
- if (myFile) {
- if (linea1_EEPROM ==0) {
- EEPROM.write(7,1); //Solo inicialmente valdra cero o cuando inicie una nueva medicion cada 7 dias
- linea1_EEPROM = 1;
- myFile.println(linea1); //Imprime en el csv la linea 1
- EEPROM.commit();
- }
- myFile.println(measurescsv); //imprime en el csv los parametros medidos
- // close the file:
- myFile.close();
- Serial.println("done.");
- } else {
- // if the file didn't open, print an error:
- Serial.println("error opening .csv");
- }
- //Variable JSON la cual se mandara al mqtt cada 15 minuntos
- StaticJsonDocument<800> var_login;//Se define variable JSON
- var_login["date"] = t1;
- var_login["serialNumber"] = meterID;
- JsonArray feeds = var_login.createNestedArray("measures");
- JsonObject feed1=feeds.createNestedObject();
- feed1["tipo"] = "Voltaje";
- feed1["fase"] = "A";
- feed1["lectura"] = voltage;
- feed1["unidad"] = "V";
- JsonObject feed2=feeds.createNestedObject();
- feed2["tipo"] = "Corriente";
- feed2["fase"] = "A";
- feed2["lectura"] = current;
- feed2["unidad"] = "A";
- JsonObject feed3=feeds.createNestedObject();
- feed3["tipo"] = "Frecuencia";
- feed3["fase"] = "A";
- feed3["lectura"] = frequency;
- feed3["unidad"] = "Hz";
- JsonObject feed4=feeds.createNestedObject();
- feed4["tipo"] = "Potencia";
- feed4["fase"] = "A";
- feed4["lectura"] = power;
- feed4["unidad"] = "W";
- JsonObject feed5=feeds.createNestedObject();
- feed5["tipo"] = "Energy: Wh Total";
- feed5["fase"] = "A";
- feed5["lectura"] = wh_total;
- feed5["unidad"] = "Wh";
- JsonObject feed6=feeds.createNestedObject();
- feed6["tipo"] = "Energy: Wh received";
- feed6["fase"] = "A";
- feed6["lectura"] = received;
- feed6["unidad"] = "Wh";
- JsonObject feed7=feeds.createNestedObject();
- feed7["tipo"] = "Energy: Wh delivered";
- feed7["fase"] = "A";
- feed7["lectura"] = delivered;
- feed7["unidad"] = "Wh";
- JsonObject feed8=feeds.createNestedObject();
- feed8["tipo"] = "Energy: Wh Net";
- feed8["fase"] = "A";
- feed8["lectura"] = wh_net;
- feed8["unidad"] = "Wh";
- char JSONmessageBuffer2[800];
- serializeJson(var_login, JSONmessageBuffer2);
- Serial.println(JSONmessageBuffer2);
-
- char topic2[20];
- sprintf(topic2,"denmark/log/%s",meterID);
- Serial.println(topic2);
- if (client.publish(topic2, JSONmessageBuffer2) == true) { //update when server is changed
-
- Serial.println("Success sending message");
- } else {
- Serial.println("Error sending message");
- }
- band = 2;//Me limita que solo la primera medicion tomada en los minutos 0, 15, 30, 45 sean mandados al mqtt y al logging
- }
- // else if ((now.minute()!=00 & now.minute()!=15 & now.minute()!=30 & now.minute()!=45) & band==2)
- else if ((now.minute()!=00 & now.minute()!=05 & now.minute()!=10 & now.minute()!=15 & now.minute()!=20 & now.minute()!=25 & now.minute()!=30 & now.minute()!=35 & now.minute()!=40 & now.minute()!=45 & now.minute()!=50 & now.minute()!=55) & band==2)
- {
- band=1;
- }
- char topic1[10];
- sprintf(topic1,"denmark/tr/%s",meterID);
- Serial.println(topic1);
- if (client.publish(topic1, JSONmessageBuffer) == true) { //update when server is changed
- Serial.println("Success sending message");
- } else {
- Serial.println("Error sending message");
- }
- Serial.print("JSON: ");
- Serial.println(JSONmessageBuffer);
- }
- //Reconeccion al servidor de mqtt
- void reconnect() {
- // Loop until we're reconnected
- // while (!client.connected()) { //Creo que si comentareo este while en lugar de quedarse probando que conecte solo lo haria una vez
- Serial.print("Attempting MQTT connection...");
- // Create a random client ID
- String clientId = "ESP8266Client";
-
- // Attempt to connect
- if (client.connect(clientId.c_str())) {
- Serial.println("connected");// Mostrar mensaje de exito a MQTT
- // Once connected, publish an announcement...
- StaticJsonDocument<300> JSONEncoder;
- JSONEncoder['status'] = "true";
- char JSONmessageBuffer[100];
- serializeJson(JSONEncoder, JSONmessageBuffer);
- //client.publish("testTopic", JSONmessageBuffer);
- //client.publish("testTopic2", JSONmessageBuffer);
- // ... and resubscribe
- //client.subscribe("inTopic");
- } else {
- Serial.print("Conexión MQTT Falló, rc=");// Mostrar mensaje de fallo a MQTT
- Serial.print(client.state());
- Serial.println(" try again in 5 seconds");
- // Wait 5 seconds before retrying
- delay(5000);
- }
- //}
- }
- void setup() {
- // put your setup code here, to run once:
-
- Serial.begin(115200);
- //initialize serial
- EEPROM.begin(512);
- Wire.begin();
- rtc.begin();
- if (! rtc.begin()) {
- Serial.println("Couldn't find RTC");
- while (1);
- }
- if (rtc.lostPower()) {
- Serial.println("RTC lost power, lets set the time!");
- // following line sets the RTC to the date & time this sketch was compiled
- rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
- }
- sdm.begin();
- delay(10);
- WiFiManagerParameter custom_output("Meter ID", "Meter ID", meterID, 10);
-
- //WiFiManager
- //Local intialization. Once its business is done, there is no need to keep it around
- WiFiManager wifiManager;
- //reset settings - for testing
- //wifiManager.resetSettings();
- //start-block2
- IPAddress _ip = IPAddress(192, 168, 98, 164);
- IPAddress _gw = IPAddress(192, 168, 98, 254);
- IPAddress _sn = IPAddress(255, 255, 255, 0);
- //end-block2
-
- wifiManager.setSTAStaticIPConfig(_ip, _gw, _sn);
- wifiManager.addParameter(&custom_output);
- //tries to connect to last known settings
- //if it does not connect it starts an access point with the specified name
- //here "AutoConnectAP" with password "password"
- //and goes into a blocking loop awaiting configuration
- if (!wifiManager.autoConnect("DENMARK", "123456789")) {
- Serial.println("failed to connect, we should reset as see if it connects");
- delay(3000);
- ESP.reset();
- delay(5000);
- }
- //if you get here you have connected to the WiFi
- Serial.println("connected :)");
- //Guarda la variable IDMeter
- if (EEPROM.read(8) == 0) {
- strcpy(meterID, custom_output.getValue());//extrae el valor ingresado en la app
- EEPROM.write(8,1); //band para que no cambie el valor de IDMeter
- EEPROM.put(9,meterID); //guarda el valor de IDMeter y no se puede cambiar a menos que se borren las variable eeprom
- EEPROM.commit();
- }
- Serial.println("local ip");
- Serial.println(WiFi.localIP());
-
- delay(1000);
- Serial.println("Creando cliente MQTT...");
- client.setServer("192.168.100.5", 31010);
- client.setCallback(callback);
- if (!SD.begin(10)) {
- Serial.println("initialization SD card failed!");
- return;
- }
- else {
- Serial.println("initialization SD card done.");
- }
- ///Set variables en EEPROM
- EEPROM.get(9,meterID);
- diaEEPROM = EEPROM.read(2);// define que ya fue corrida al menos una vez el programa
- dia_EEPROM = EEPROM.read(3);//variable de dia de la carpeta actual csv
- anho_EEPROM = EEPROM.read(4);//variable de año de la carpeta actual csv
- mes_EEPROM = EEPROM.read(5); //variable de mes de la carpeta actual csv
- dia_nextEEPROM = EEPROM.read(6);//variable la cual contiene el siguiente dia en cual se creara la carpeta csv
- linea1_EEPROM = EEPROM.read(7);//Esta variable es para limitar que el encabezado se mande solo una vez al crar el csv
- mes_nextEEPROM = EEPROM.read(0);//variable la cual contiene el siguiente mes en cual se creara la carpeta csv
- /*Serial.println(mes_nextEEPROM);
- Serial.println(meterID);
- Serial.println(dia_nextEEPROM);
- Serial.println(anho_EEPROM);
- Serial.println(mes_EEPROM);
- */
- }
- void loop() {
-
- //Loop reconexion a Mqtt
- {
- if (!client.connected()) {
- reconnect();
- }
- client.loop();
- }
-
- denmark();
- delay(8370);
- }
|