DENMARK_V1_SDM120.ino 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. #include <FS.h>
  2. #include <ESP8266WiFi.h>
  3. #include <WiFiClient.h>
  4. #include <PubSubClient.h>
  5. #include <SDM.h>
  6. #include <SoftwareSerial.h>
  7. #include <ArduinoJson.h>
  8. #include <RTClib.h>
  9. #include <Wire.h>
  10. #include <SPI.h>
  11. #include <SD.h>
  12. #include <EEPROM.h>
  13. #include <WiFiManager.h>
  14. #include <ESP8266WebServer.h>
  15. #include <DNSServer.h>
  16. File myFile;
  17. #define ESP8266
  18. int band =1;
  19. int band_day =1;
  20. int dia_next;
  21. int mes_next;
  22. int dia_nextEEPROM;
  23. int mes_nextEEPROM;
  24. char t2_EEPROM[15];
  25. int anho_EEPROM;
  26. int dia_EEPROM;
  27. int mes_EEPROM;
  28. int diaEEPROM;
  29. int linea1_EEPROM;
  30. RTC_DS3231 rtc;
  31. char meterID[10];
  32. //Configuracion contador
  33. SoftwareSerial swSerSDM;
  34. SDM sdm(swSerSDM, 2400, 16, SWSERIAL_8N1, 0, 2);
  35. // Servidor MQTT
  36. char SERVER[50] = "192.168.100.5"; // denmark.inverlec.solar
  37. int SERVERPORT = 31010;
  38. WiFiClient espClient;
  39. PubSubClient client(espClient);
  40. // Callback al recibir mensaje por MQTT
  41. void callback(char* topic, byte* payload, unsigned int length) {
  42. Serial.print("Message arrived [");
  43. Serial.print(topic);
  44. Serial.print("] ");
  45. for (int i = 0; i < length; i++) {
  46. Serial.print((char)payload[i]);
  47. }
  48. Serial.println();
  49. }
  50. //funcion para mandar a mqqt la lectura cada 10s, 15 min y guardar en memoria SD
  51. int denmark() {
  52. char bufout[10];
  53. //Variable JSON que se mandara a mqtt aproximadamente cada 10 segundos
  54. StaticJsonDocument<500> JSONencoder;//Se define variable JSON
  55. char t1[15];
  56. DateTime now = rtc.now();
  57. 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
  58. JSONencoder["date"] = t1;//Manda al JSON la variable t
  59. JSONencoder["serialNumber"] = meterID;//numero serial de el medidor
  60. delay(50);
  61. JsonObject measures = JSONencoder.createNestedObject("measures");//Anidamos al JSON la variable measures
  62. float voltage = sdm.readVal(SDM120C_VOLTAGE);
  63. measures["Readings: Volts A-N"] = voltage;
  64. delay(50);
  65. float current = sdm.readVal(SDM120C_CURRENT);
  66. measures["Readings: I A"] = current;
  67. delay(50);
  68. float frequency = sdm.readVal(SDM120C_FREQUENCY);
  69. measures["Readings: Frequency"] = frequency;
  70. delay(50);
  71. float power = sdm.readVal(SDM120C_POWER);
  72. measures["Readings: Watts A"] = power;
  73. delay(50);
  74. float wh_total = sdm.readVal(SDM120C_TOTAL_ACTIVE_ENERGY)*1000;
  75. measures["Scaled Energy: Wh Net"] = wh_total;
  76. delay(50);
  77. float received = sdm.readVal(SDM120CT_IMPORT_ACTIVE_ENERGY)*1000;
  78. measures["Scaled Energy: Wh received"] = received;
  79. delay(50);
  80. float delivered = sdm.readVal(SDM120CT_EXPORT_ACTIVE_ENERGY)*1000;
  81. measures["Scaled Energy: Wh delivered"] = delivered;
  82. delay(50);
  83. float wh_net = (received-delivered);
  84. measures["Scaled Energy: Wh Total"] = wh_net ;
  85. delay(50);
  86. char JSONmessageBuffer[300];
  87. serializeJson(JSONencoder, JSONmessageBuffer);
  88. if (( now.day() == dia_nextEEPROM || diaEEPROM ==0 ||(now.day()>dia_nextEEPROM & mes_nextEEPROM == now.month())) & band_day==1)
  89. {
  90. if (diaEEPROM == 0) {
  91. EEPROM.write(2,2);
  92. diaEEPROM =2;
  93. EEPROM.commit();
  94. }
  95. dia_next= now.day() + 7;
  96. mes_next = now.month();
  97. //Estos if es para el no superen el valor de 29, 30 o 31 dependiendo el mes
  98. 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)){
  99. dia_next= dia_next -31;
  100. mes_next = now.month() + 1;
  101. }
  102. else if ((dia_next>30)&(now.month()==4 || now.month()==6 || now.month()==9 || now.month()==11)){
  103. dia_next= dia_next -30;
  104. mes_next = now.month() + 1;
  105. }
  106. else if ((dia_next>29)&(now.month()==2 & ((now.year()==2020 || now.year()==2024 || now.year()==2028 || now.year()==2032 || now.year()==2036)))){
  107. dia_next= dia_next -29;
  108. mes_next = now.month() + 1;
  109. }
  110. else if ((dia_next>28)&(now.month()==2)){
  111. dia_next= dia_next -28;
  112. mes_next = now.month() + 1;
  113. }
  114. //Guardando variables EEPROM
  115. EEPROM.write(6,dia_next);
  116. EEPROM.write(0,mes_next);
  117. EEPROM.write(3,now.day());
  118. EEPROM.write(4,now.year()-2000);//si toma mas de tres dijitos me escribe otra cosa
  119. EEPROM.write(5,now.month());
  120. EEPROM.write(7,0);//Variable linea 1
  121. dia_EEPROM = now.day();
  122. anho_EEPROM = now.year()-2000;
  123. mes_EEPROM = now.month();
  124. dia_nextEEPROM = dia_next;
  125. mes_nextEEPROM = mes_next;
  126. linea1_EEPROM = 0;
  127. EEPROM.commit();
  128. band_day=2;
  129. }
  130. else if (( now.day() != dia_nextEEPROM & diaEEPROM !=0) & band_day==2)
  131. {
  132. band_day=1;
  133. }
  134. // if ((now.minute()==00 || now.minute()==15 || now.minute()==30 || now.minute()==45) & band==1)
  135. 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) {
  136. //Variables que seran guardadas en el logging en formato csv
  137. String linea1=("date,serialNumber,Voltaje (V),Corriente (A),Frecuencia (Hz),Potencia (W),Energia Neta (Wh),Energia Importada (Wh),Energia Exportada (Wh),Energia Total (Wh)");
  138. String measurescsv = String(t1) + "," + String(meterID)+","+String(voltage) + "," + String(current) + "," + String(frequency) + "," + String(power) + "," + String(wh_total) + "," + String(received) + "," + String(delivered) + "," + String(wh_net);
  139. Serial.println(measurescsv);
  140. sprintf(t2_EEPROM, "%02d-%02d-20%02d.csv",dia_EEPROM,mes_EEPROM,anho_EEPROM);
  141. myFile = SD.open(t2_EEPROM, FILE_WRITE);
  142. // if the file opened okay, write to it:
  143. if (myFile) {
  144. if (linea1_EEPROM ==0) {
  145. EEPROM.write(7,1); //Solo inicialmente valdra cero o cuando inicie una nueva medicion cada 7 dias
  146. linea1_EEPROM = 1;
  147. myFile.println(linea1); //Imprime en el csv la linea 1
  148. EEPROM.commit();
  149. }
  150. myFile.println(measurescsv); //imprime en el csv los parametros medidos
  151. // close the file:
  152. myFile.close();
  153. Serial.println("done.");
  154. } else {
  155. // if the file didn't open, print an error:
  156. Serial.println("error opening .csv");
  157. }
  158. //Variable JSON la cual se mandara al mqtt cada 15 minuntos
  159. StaticJsonDocument<800> var_login;//Se define variable JSON
  160. var_login["date"] = t1;
  161. var_login["serialNumber"] = meterID;
  162. JsonArray feeds = var_login.createNestedArray("measures");
  163. JsonObject feed1=feeds.createNestedObject();
  164. feed1["tipo"] = "Voltaje";
  165. feed1["fase"] = "A";
  166. feed1["lectura"] = voltage;
  167. feed1["unidad"] = "V";
  168. JsonObject feed2=feeds.createNestedObject();
  169. feed2["tipo"] = "Corriente";
  170. feed2["fase"] = "A";
  171. feed2["lectura"] = current;
  172. feed2["unidad"] = "A";
  173. JsonObject feed3=feeds.createNestedObject();
  174. feed3["tipo"] = "Frecuencia";
  175. feed3["fase"] = "A";
  176. feed3["lectura"] = frequency;
  177. feed3["unidad"] = "Hz";
  178. JsonObject feed4=feeds.createNestedObject();
  179. feed4["tipo"] = "Potencia";
  180. feed4["fase"] = "A";
  181. feed4["lectura"] = power;
  182. feed4["unidad"] = "W";
  183. JsonObject feed5=feeds.createNestedObject();
  184. feed5["tipo"] = "Energy: Wh Total";
  185. feed5["fase"] = "A";
  186. feed5["lectura"] = wh_total;
  187. feed5["unidad"] = "Wh";
  188. JsonObject feed6=feeds.createNestedObject();
  189. feed6["tipo"] = "Energy: Wh received";
  190. feed6["fase"] = "A";
  191. feed6["lectura"] = received;
  192. feed6["unidad"] = "Wh";
  193. JsonObject feed7=feeds.createNestedObject();
  194. feed7["tipo"] = "Energy: Wh delivered";
  195. feed7["fase"] = "A";
  196. feed7["lectura"] = delivered;
  197. feed7["unidad"] = "Wh";
  198. JsonObject feed8=feeds.createNestedObject();
  199. feed8["tipo"] = "Energy: Wh Net";
  200. feed8["fase"] = "A";
  201. feed8["lectura"] = wh_net;
  202. feed8["unidad"] = "Wh";
  203. char JSONmessageBuffer2[800];
  204. serializeJson(var_login, JSONmessageBuffer2);
  205. Serial.println(JSONmessageBuffer2);
  206. char topic2[20];
  207. sprintf(topic2,"denmark/log/%s",meterID);
  208. Serial.println(topic2);
  209. if (client.publish(topic2, JSONmessageBuffer2) == true) { //update when server is changed
  210. Serial.println("Success sending message");
  211. } else {
  212. Serial.println("Error sending message");
  213. }
  214. band = 2;//Me limita que solo la primera medicion tomada en los minutos 0, 15, 30, 45 sean mandados al mqtt y al logging
  215. }
  216. // else if ((now.minute()!=00 & now.minute()!=15 & now.minute()!=30 & now.minute()!=45) & band==2)
  217. 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)
  218. {
  219. band=1;
  220. }
  221. char topic1[10];
  222. sprintf(topic1,"denmark/tr/%s",meterID);
  223. Serial.println(topic1);
  224. if (client.publish(topic1, JSONmessageBuffer) == true) { //update when server is changed
  225. Serial.println("Success sending message");
  226. } else {
  227. Serial.println("Error sending message");
  228. }
  229. Serial.print("JSON: ");
  230. Serial.println(JSONmessageBuffer);
  231. }
  232. //Reconeccion al servidor de mqtt
  233. void reconnect() {
  234. // Loop until we're reconnected
  235. // while (!client.connected()) { //Creo que si comentareo este while en lugar de quedarse probando que conecte solo lo haria una vez
  236. Serial.print("Attempting MQTT connection...");
  237. // Create a random client ID
  238. String clientId = "ESP8266Client";
  239. // Attempt to connect
  240. if (client.connect(clientId.c_str())) {
  241. Serial.println("connected");// Mostrar mensaje de exito a MQTT
  242. // Once connected, publish an announcement...
  243. StaticJsonDocument<300> JSONEncoder;
  244. JSONEncoder['status'] = "true";
  245. char JSONmessageBuffer[100];
  246. serializeJson(JSONEncoder, JSONmessageBuffer);
  247. //client.publish("testTopic", JSONmessageBuffer);
  248. //client.publish("testTopic2", JSONmessageBuffer);
  249. // ... and resubscribe
  250. //client.subscribe("inTopic");
  251. } else {
  252. Serial.print("Conexión MQTT Falló, rc=");// Mostrar mensaje de fallo a MQTT
  253. Serial.print(client.state());
  254. Serial.println(" try again in 5 seconds");
  255. // Wait 5 seconds before retrying
  256. delay(5000);
  257. }
  258. //}
  259. }
  260. void setup() {
  261. // put your setup code here, to run once:
  262. Serial.begin(115200);
  263. //initialize serial
  264. EEPROM.begin(512);
  265. Wire.begin();
  266. rtc.begin();
  267. if (! rtc.begin()) {
  268. Serial.println("Couldn't find RTC");
  269. while (1);
  270. }
  271. if (rtc.lostPower()) {
  272. Serial.println("RTC lost power, lets set the time!");
  273. // following line sets the RTC to the date & time this sketch was compiled
  274. rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  275. }
  276. sdm.begin();
  277. delay(10);
  278. WiFiManagerParameter custom_output("Meter ID", "Meter ID", meterID, 10);
  279. //WiFiManager
  280. //Local intialization. Once its business is done, there is no need to keep it around
  281. WiFiManager wifiManager;
  282. //reset settings - for testing
  283. //wifiManager.resetSettings();
  284. //start-block2
  285. IPAddress _ip = IPAddress(192, 168, 98, 164);
  286. IPAddress _gw = IPAddress(192, 168, 98, 254);
  287. IPAddress _sn = IPAddress(255, 255, 255, 0);
  288. //end-block2
  289. wifiManager.setSTAStaticIPConfig(_ip, _gw, _sn);
  290. wifiManager.addParameter(&custom_output);
  291. //tries to connect to last known settings
  292. //if it does not connect it starts an access point with the specified name
  293. //here "AutoConnectAP" with password "password"
  294. //and goes into a blocking loop awaiting configuration
  295. if (!wifiManager.autoConnect("DENMARK", "123456789")) {
  296. Serial.println("failed to connect, we should reset as see if it connects");
  297. delay(3000);
  298. ESP.reset();
  299. delay(5000);
  300. }
  301. //if you get here you have connected to the WiFi
  302. Serial.println("connected :)");
  303. //Guarda la variable IDMeter
  304. if (EEPROM.read(8) == 0) {
  305. strcpy(meterID, custom_output.getValue());//extrae el valor ingresado en la app
  306. EEPROM.write(8,1); //band para que no cambie el valor de IDMeter
  307. EEPROM.put(9,meterID); //guarda el valor de IDMeter y no se puede cambiar a menos que se borren las variable eeprom
  308. EEPROM.commit();
  309. }
  310. Serial.println("local ip");
  311. Serial.println(WiFi.localIP());
  312. delay(1000);
  313. Serial.println("Creando cliente MQTT...");
  314. client.setServer("192.168.100.5", 31010);
  315. client.setCallback(callback);
  316. if (!SD.begin(10)) {
  317. Serial.println("initialization SD card failed!");
  318. return;
  319. }
  320. else {
  321. Serial.println("initialization SD card done.");
  322. }
  323. ///Set variables en EEPROM
  324. EEPROM.get(9,meterID);
  325. diaEEPROM = EEPROM.read(2);// define que ya fue corrida al menos una vez el programa
  326. dia_EEPROM = EEPROM.read(3);//variable de dia de la carpeta actual csv
  327. anho_EEPROM = EEPROM.read(4);//variable de año de la carpeta actual csv
  328. mes_EEPROM = EEPROM.read(5); //variable de mes de la carpeta actual csv
  329. dia_nextEEPROM = EEPROM.read(6);//variable la cual contiene el siguiente dia en cual se creara la carpeta csv
  330. linea1_EEPROM = EEPROM.read(7);//Esta variable es para limitar que el encabezado se mande solo una vez al crar el csv
  331. mes_nextEEPROM = EEPROM.read(0);//variable la cual contiene el siguiente mes en cual se creara la carpeta csv
  332. /*Serial.println(mes_nextEEPROM);
  333. Serial.println(meterID);
  334. Serial.println(dia_nextEEPROM);
  335. Serial.println(anho_EEPROM);
  336. Serial.println(mes_EEPROM);
  337. */
  338. }
  339. void loop() {
  340. //Loop reconexion a Mqtt
  341. {
  342. if (!client.connected()) {
  343. reconnect();
  344. }
  345. client.loop();
  346. }
  347. denmark();
  348. delay(8370);
  349. }