· 6 years ago · Feb 22, 2020, 11:06 AM
1#define _DEBUG_
2
3#include "ESP8266WiFi.h"
4#include <ESP8266HTTPClient.h>
5#include "Nextion.h"
6#include <ArduinoJson.h>
7#include <PubSubClient.h>
8
9// Definición de constantes pantalla nextion
10#define ICON1D 1
11#define ICON2D 2
12#define ICON3D 3
13#define ICON4D 3
14#define ICON9D 4
15#define ICON10D 5
16#define ICON11D 6
17#define ICON13D 7
18#define ICON50D 8
19
20// Configuración red WiFi
21const char* ssid = "Be_Inspirational"; // Pon el nombre de tu red WiFi
22const char* password = "LaBaticueva"; // Pon la contraseña de tu red WiFi
23
24// Cliente web
25HTTPClient clienteHttp;
26
27// Parámetros configuración broker MQTT
28const char* brokerUrl = "192.168.40.137";
29int brokerPuerto = 1883; //Cambia por el puerto correspondiente
30const char* userMQTT = "USER-BROKER";
31const char* passMQTT = "PASS-BROKER";
32WiFiClient espClient;
33PubSubClient clienteMqtt(espClient);
34
35// Datos OpenWeatherMap
36String hostOpenWeatherMap = "http://api.openweathermap.org/data/2.5/weather";
37String idCiudad = "3130583"; // Sustituye por el id de tu ciudad
38String apiKey = "6b65a526cc4d477274bcebc3e5d54861"; // Sustituye por tu API Key
39
40// Campos pantalla Nextion Nextion
41// NexText(PageID, ComponentID, ComponentName)
42NexText ficticio = NexText(0, 1000, "t1000");
43NexText nexTemp = NexText(0, 7, "t5");
44NexText nexHumedad = NexText(0, 3, "t1");
45NexText nexViento = NexText(0, 4, "t2");
46NexText nexTempMin = NexText(0, 5, "t3");
47NexText nexTempMax = NexText(0, 6, "t4");
48NexText nexCiudad = NexText(0, 2, "t0");
49NexPicture nexIcono = NexPicture(0, 8, "p1");
50NexText nexTempExt1 = NexText(0, 10, "t7");
51NexText nexTempExt2 = NexText(0, 12, "t9");
52NexText nexNameTempExt1 = NexText(0, 9, "t6");
53NexText nexNameTempExt2 = NexText(0, 11, "t8");
54
55// Temporizador
56unsigned long ultimaConsulta = 0;
57unsigned long tiempoConsulta = 5000;
58
59// Temperaturas TT
60#define SIZETEMPEXT 7
61char tempExt1[SIZETEMPEXT];
62char* nombreTempExt1 = "Maker SS";
63char* topicTempExt1 = "tt/temp/ss";
64char tempExt2[SIZETEMPEXT];
65//char* nombreTempExt2 = "Salon";
66char* topicTempExt2 = "casa/temp/ext/2";
67
68void configWifi() {
69#ifdef _DEBUG_
70 // Conexión con la red WiFi
71 Serial.print("Conectando con ");
72 Serial.println(ssid);
73#endif
74
75
76 // Configuración en modo cliente
77 WiFi.mode(WIFI_STA);
78 // Iniciar conexión con la red WiFi
79 WiFi.begin(ssid, password);
80
81 while (WiFi.status() != WL_CONNECTED) {
82 delay(500);
83#ifdef _DEBUG_
84 Serial.print(".");
85#endif
86 }
87
88#ifdef _DEBUG_
89 Serial.println("");
90 Serial.println("Conectado a la WiFi");
91#endif
92}
93
94void obtenerDatosOpenWeather() {
95 // Crear URL para hacer la pretición
96 String url = hostOpenWeatherMap;
97 url += "?id=";
98 url += idCiudad;
99 url += "&appid=";
100 url += apiKey;
101#ifdef _DEBUG_
102 Serial.print("URL petición HTTP: ");
103 Serial.println(url);
104#endif
105
106 // Conexión con el servidor y configuración de la petición
107 clienteHttp.begin(url);
108
109 // Envío de petición HTTP al servidor
110 int codigoHttp = clienteHttp.GET();
111
112#ifdef _DEBUG_
113 Serial.print("Codigo HTTP: ");
114 Serial.println(codigoHttp);
115#endif
116
117 // Si todo ha ido bien devolverá un número positivo mayor que cero
118 if (codigoHttp > 0) {
119 // Si ha encontrado el recurso en el servidor
120 if (codigoHttp == HTTP_CODE_OK) {
121#ifdef _DEBUG_
122 Serial.print("Archivo JSON: ");
123 Serial.println(clienteHttp.getString());
124#endif
125
126 // Parsear archivo JSON
127 // Para obtener tamaño del buffer vistiar https://arduinojson.org/v6/assistant/
128 const size_t capacity = JSON_ARRAY_SIZE(3) +
129 2 * JSON_OBJECT_SIZE(1) +
130 JSON_OBJECT_SIZE(2) +
131 3 * JSON_OBJECT_SIZE(4) +
132 JSON_OBJECT_SIZE(5) +
133 JSON_OBJECT_SIZE(6) +
134 JSON_OBJECT_SIZE(12) +
135 304;
136 DynamicJsonDocument doc(capacity);
137
138 // Parsear objeto JSON
139 DeserializationError error = deserializeJson(doc, clienteHttp.getString());
140 if (error) {
141 // Si hay error no se continua
142#ifdef _DEBUG_
143 Serial.print("Fallo al parsear JSON. Error: ");
144 Serial.println(error.c_str());
145#endif
146 return;
147 }
148
149 // Temperatura
150 float tempF = doc["main"]["temp"];
151 tempF = tempF - 273.15; // A grados Celsius
152 char temp[7];
153 snprintf(temp, 7, "%.0f C", tempF);
154
155
156 // Humedad
157 String humedadS = String(int(doc["main"]["humidity"])) + " %";
158 char humedad[7];
159 humedadS.toCharArray(humedad, 7);
160
161 // Temperatura mínima
162 float tempMinF = doc["main"]["temp_min"];
163 tempMinF = tempMinF - 273.15; // A grados Celsius
164 char tempMin[7];
165 snprintf(tempMin, 7, "%.0f C", tempMinF);
166
167 // Temperatura máxima
168 float tempMaxF = doc["main"]["temp_max"];
169 tempMaxF = tempMaxF - 273.15; // A grados Celsius
170 char tempMax[7];
171 snprintf(tempMax, 7, "%.0f C", tempMaxF);
172
173
174 // Viento
175 float vientoF = doc["wind"]["speed"];
176 char viento[8];
177 snprintf(viento, 8, "%.0f m/S", vientoF);
178
179 //Buffer
180 ficticio.setText("");
181 // Ciudad
182 const char* ciudad = doc["name"];
183 nexCiudad.setText(ciudad);
184
185 // Volcado de datos a la pantalla
186 nexTemp.setText(temp);
187 nexHumedad.setText(humedad);
188 nexTempMin.setText(tempMin);
189 nexTempMax.setText(tempMax);
190 nexViento.setText(viento);
191 // Temperaturas Internas
192 nexTempExt1.setText(tempExt1);
193 nexTempExt2.setText(tempExt2);
194 nexNameTempExt1.setText(nombreTempExt1);
195 //nexNameTempExt2.setText(nombreTempExt2);
196
197 // Icono tiempo
198 const char* icono = doc["weather"][0]["icon"];
199
200 // Asignación icono comparar icono diurno y nocturno
201 if (strcmp(icono, "01d") == 0 || strcmp(icono, "01n") == 0) {
202 nexIcono.setPic(ICON1D);
203 } else if (strcmp(icono, "02d") == 0 || strcmp(icono, "02n") == 0) {
204 nexIcono.setPic(ICON2D);
205 } else if (strcmp(icono, "03d") == 0 || strcmp(icono, "03n") == 0) {
206 nexIcono.setPic(ICON3D);
207 } else if (strcmp(icono, "04d") == 0 || strcmp(icono, "04n") == 0) {
208 nexIcono.setPic(ICON4D);
209 } else if (strcmp(icono, "09d") == 0 || strcmp(icono, "09n") == 0) {
210 nexIcono.setPic(ICON9D);
211 } else if (strcmp(icono, "10d") == 0 || strcmp(icono, "10n") == 0) {
212 nexIcono.setPic(ICON10D);
213 } else if (strcmp(icono, "11d") == 0 || strcmp(icono, "11n") == 0) {
214 nexIcono.setPic(ICON11D);
215 } else if (strcmp(icono, "13d") == 0 || strcmp(icono, "13n") == 0) {
216 nexIcono.setPic(ICON13D);
217 } else if (strcmp(icono, "50d") == 0 || strcmp(icono, "50n") == 0) {
218 nexIcono.setPic(ICON50D);
219 } else {
220 nexIcono.setPic(ICON1D);
221 }
222
223#ifdef _DEBUG_
224 Serial.println("Datos OpenWeatherMap");
225 Serial.print("Temperatura: ");
226 Serial.println(temp);
227 Serial.print("Humedad: ");
228 Serial.println(humedad);
229 Serial.print("Temp. Min: ");
230 Serial.println(tempMin);
231 Serial.print("Temp. Max: ");
232 Serial.println(tempMax);
233 Serial.print("Viento: ");
234 Serial.println(viento);
235 Serial.print("Icono: ");
236 Serial.println(icono);
237 Serial.print("Ciudad: ");
238 Serial.println(ciudad);
239 Serial.print("Temp. Ext1: ");
240 Serial.println(tempExt1);
241 Serial.print("Temp. Ext2: ");
242 Serial.println(tempExt2);
243#endif
244 } else {
245#ifdef _DEBUG_
246 Serial.println("Error al recibir petición.");
247#endif
248 }
249 }
250}
251
252void temporizador() {
253 // Comprobar si se ha dado la vuelta
254 if (millis() < ultimaConsulta) {
255 // Asignar un nuevo valor
256 ultimaConsulta = millis();
257 }
258
259 if ((millis() - ultimaConsulta) > tiempoConsulta) {
260 // Marca de tiempo
261 ultimaConsulta = millis();
262 // Llamada a la función para obtener los datos y actualziar pantalla Nextion
263 obtenerDatosOpenWeather();
264 }
265}
266
267void callback(char* topic, byte* payload, unsigned int length) {
268#ifdef _DEBUG_
269 Serial.print("Mensaje recibido [");
270 Serial.print(topic);
271 Serial.println("]");
272 for (int i = 0; i < length; i++) {
273 Serial.print((char)payload[i]);
274 }
275 Serial.println();
276#endif
277
278 // Comprobación de qué topic viene
279 if (strcmp(topic, topicTempExt1) == 0) {
280 // Protección fuera de rango
281 if (length + 1 < SIZETEMPEXT) {
282 // Recorrer el array de bytes
283 for (int i = 0; i < length; i++) {
284 // Convertir cada byte en un char y concatenarlo
285 tempExt1[i] = (char)payload[i];
286 }
287 tempExt1[length] = ' ';
288 tempExt1[length + 1] = 'C';
289 } else {
290#ifdef _DEBUG_
291 Serial.println("Payload demasiado largo");
292#endif
293 }
294 } else if (strcmp(topic, topicTempExt2) == 0) {
295 // Protección fuera de rango
296 if (length + 1 < SIZETEMPEXT) {
297 // Recorrer el array de bytes
298 for (int i = 0; i < length; i++) {
299 // Convertir cada byte en un char y concatenarlo
300 tempExt2[i] = (char)payload[i];
301 }
302 tempExt2[length] = ' ';
303 tempExt2[length + 1] = 'C';
304 } else {
305#ifdef _DEBUG_
306 Serial.println("Payload demasiado largo");
307#endif
308 }
309 }
310}
311
312void reconnect() {
313 // Repetir hasta que se conecte
314 while (!clienteMqtt.connected()) {
315#ifdef _DEBUG_
316 Serial.print("Intentando conectarse al broker MQTT...");
317#endif
318 // Nombre único del cliente. No se puede repetir
319 String clientId = "ESP8266-Nextion";
320 // Intentando conectar
321 if (clienteMqtt.connect(clientId.c_str()/*, userMQTT, passMQTT*/)) {
322#ifdef _DEBUG_
323 Serial.println("Conectado");
324#endif
325
326 // Suscripción a los topics
327 clienteMqtt.subscribe(topicTempExt1);
328 clienteMqtt.subscribe(topicTempExt2);
329 } else {
330#ifdef _DEBUG_
331 Serial.print("Fallo al conectar al broker, rc=");
332 Serial.print(clienteMqtt.state());
333 Serial.println(" intentando conectar en 5 segundos");
334#endif
335 // Este delay habría que mejorarlo para que no bloquee
336 delay(5000);
337 }
338 }
339}
340
341void setup()
342{
343 // Iniciar comunicación con la pantalla
344 // Baudrate por defecto son 9600 para seleccionar en elmonitor serie
345 nexInit(); // Esta función se encuentra en NextHardware.h
346
347 // Configurar WiFi
348 configWifi();
349
350 // Configuración MQTT
351 clienteMqtt.setServer(brokerUrl, brokerPuerto);
352 clienteMqtt.setCallback(callback);
353}
354
355void loop() {
356 // Temporizador
357 temporizador();
358
359 // Gestión conexión MQTT
360 if (!clienteMqtt.connected()) {
361 reconnect();
362 }
363 clienteMqtt.loop();
364}