Βιβλιοθήκη για την υποβολή ερωτημάτων HTTP με μια μονάδα WiFi ESP8266 και Arduino
Ένας απλός τρόπος αποστολής πληροφοριών από και προς έναν μικροελεγκτή είναι η συγκέντρωση τους σε έναν διακομιστή web. Αν και δεν είναι τόσο αποτελεσματική μέθοδος όσο, για παράδειγμα, η απευθείας πρόσβαση σε μια βάση δεδομένων, είναι αρκετά αποτελεσματική, ειδικά αν σκεφτείτε ένα έργο που βασίζεται σε μικροελεγκτή και προσθέσετε τα πλεονεκτήματα της πανταχού παρουσίας (δεδομένα στο σύννεφο) και της απλότητας (αυτό μπορούν να αντιμετωπιστούν ως πληροφορίες κειμένου και παραγγελίες). Η αποστολή πληροφοριών χρησιμοποιώντας αυτό το σύστημα μπορεί να συνίσταται στην υποβολή αιτημάτων HTTP POST και στη λήψη τους με ανάλυση του περιεχομένου της απάντησης σε ένα αίτημα HTTP GET.
El ESP8266 Μονάδα WiFi Είναι μια πολύ οικονομική επιλογή, με απόδοση πολύ κατάλληλη για χρήση με μικροελεγκτές και πολύ εύκολη στη χρήση δουλεύοντας με εντολές AT.
Για να συστηματοποιήσω τη χρήση του με αιτήματα HTTP, έχω αναπτύξει μια μικρή βιβλιοθήκη που υποστηρίζει τις ανάγκες του έργου της συσκευής διαχείρισης ύπνου (το οποίο ονόμασα SleepManager), καθώς βασίζει την υποδομή του σε έναν διακομιστή ιστού που του επιτρέπει να επεκταθεί σε ένα αντικείμενο. IoT ως υπηρεσία cloud. Δεν είναι δύσκολο να προσθέσετε άλλες υπηρεσίες, όπως αιτήματα UDP στη βιβλιοθήκη, για παράδειγμα, σε συγχρονισμός χρόνου μέσω NTP αν και, όπως εξηγώ στο συνδεδεμένο κείμενο, δεν είναι κρίσιμο για τις ανάγκες μου και μπορώ να το επιλύσω αποδεκτά με ένα αίτημα HTTP σε μια ιστοσελίδα που έχει προετοιμαστεί για αυτόν τον σκοπό, όπως δείχνω σε ένα παράδειγμα χρήσης αυτής της βιβλιοθήκης.
Η λειτουργία της βιβλιοθήκης βασίζεται στην αποστολή εντολών AT όταν η συσκευή είναι διαθέσιμη και στην επανάληψη τους (με μικρή καθυστέρηση) σε περίπτωση σφάλματος, το οποίο ερμηνεύεται ως μη διαθεσιμότητα (επιτυχώς, με δοκιμή) για παράδειγμα από σημείο πρόσβασης WiFi ή διακομιστής υπό εξέταση.
Η βιβλιοθήκη εκμεταλλεύεται το γεγονός ότι η μονάδα WiFi ESP8266 επιστρέφει έναν κωδικό +IPD ως προειδοποίηση λήψης δεδομένων για να γεμίσει ένα μικρό buffer με τις πληροφορίες που επιστρέφονται από τον διακομιστή. Για το έργο της συσκευής διαχείρισης ύπνου πρέπει να αναλύσω πολύ λίγα δεδομένα που επιστρέφονται από τον διακομιστή, έτσι ώστε, για εξοικονόμηση, η προσωρινή μνήμη και ο δείκτης που διατρέχουν είναι ιδιαίτερα μικροί. Αυτό θα είναι ένα από τα πρώτα πράγματα που θα πρέπει να αλλάξετε για να χρησιμοποιήσετε ξανά τη βιβλιοθήκη για την επεξεργασία μεγαλύτερου όγκου δεδομένων.
Οι λειτουργίες που εκτίθενται ως δημόσια επιτρέπουν (1) να γνωρίζει την κατάσταση της μονάδας: εάν είναι συνδεδεμένη ή όχι, εάν υπάρχουν δεδομένα στο buffer και πόσα και εάν η μονάδα ESP8266 έχει ολοκληρώσει τη λειτουργία που έχει ζητηθεί. (2) συνδεθείτε σε ένα σημείο πρόσβασης WiFi σε ένα δίκτυο με διακομιστή DHCP και (3) κάντε αιτήματα HTTP GET και POST, αν και, όπως θα δείτε, ο κώδικας έχει σχεδιαστεί για να διευκολύνει την προσθήκη άλλων.
Όσον αφορά την εσωτερική λειτουργία, κατασκευάζονται αρχικά δύο πίνακες, ένας με τις εντολές AT και ένας άλλος με τις αναμενόμενες απαντήσεις για επιτυχία και λάθος. Στη συνέχεια, το πρόγραμμα που χρησιμοποιεί τη βιβλιοθήκη πρέπει να καλεί τη συνάρτηση από καιρό σε καιρό
η οποία θα είναι υπεύθυνη για την αποστολή των παραγγελιών στη μονάδα εάν είναι διαθέσιμες και η λειτουργία δεν είναι ήδη απασχολημένη το οποίο θα επεξεργάζεται απαντήσεις από τη μονάδα ESP8266 (και από τον διακομιστή HTTP μέσω αυτής, εάν υπάρχει)Καθώς υπάρχει πιθανότητα η μονάδα να αποσυνδεθεί λόγω απώλειας σήματος, το κύριο πρόγραμμα μπορεί να ελέγξει εάν η μονάδα ESP8266 είναι συνδεδεμένη στο σημείο πρόσβασης WiFi (με τη λειτουργία
) και προσπαθήστε να συνδεθείτε διαφορετικά (με τη λειτουργία )Για να μάθετε εάν η ζητούμενη λειτουργία έχει ολοκληρωθεί, το πρόγραμμα μπορεί να χρησιμοποιήσει τη λειτουργία
και σε αυτήν την περίπτωση στείλτε άλλο ή χρησιμοποιήστε τα δεδομένα που προκύπτουν για τα οποία χρησιμοποιείται η συνάρτηση , το οποίο επιστρέφει τα περιεχόμενα του buffer που έχει γεμίσει με τα δεδομένα που έφθασαν στη μονάδα ESP8266 μέχρι να ολοκληρωθεί η λειτουργία και τη συνάρτηση το οποίο αναφέρει την ποσότητα αυτών των δεδομένων που ο διακομιστής έχει προειδοποιήσει ότι επρόκειτο να σταλούν (ώστε να μπορούν να μειωθούν οι πληροφορίες από την ίδια τη μονάδα) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 | //ESP8266.cpp #if defined(ARDUINO) && ARDUINO>=100 #include “Arduino.h” #else #include “WProgram.h” #endif // Para monitorizar (CONSOLA) a la vez que se comunica con el módulo por el puerto serie hace falta una placa Arduino con varios puertos (como Mega o Leonardo) en caso contrario hay que cambiar a MODULO_WIFI Serial y desactivar la depuración // No se inicializan las comunicaciones serie, es necesario inicializarlas desde el programa que usa la librería #define CONSOLA Serial #define MODULO_WIFI Serial1 #include “ESP8266.h” ESP8266::ESP8266(boolean depuracion) { constructor(depuracion); } ESP8266::ESP8266() { constructor(false); } ESP8266::~ESP8266() { } void ESP8266::constructor(boolean depuracion) { mostrar_salida=false; // Sin depuración para Arduino Uno //mostrar_salida=depuracion; estado_orden=ORDEN_OK; indicador_operacion_terminada=&ESP8266_operacion_terminada; *indicador_operacion_terminada=true; reiniciar_buffer(); mensaje_buscado[ORDEN_RECIBIENDO]=CODIGO_INICIO_RECEPCION; } void ESP8266::conectar_wifi ( String ssid, String clave, String ip, byte timeout ) { estado_orden=ORDEN_OK; pasos_operacion=0; paso_operacion=255; //Para poder incrementar al principio del proceso y que empiece en cero ESP8266_conectado=false; indicador_operacion_terminada=&ESP8266_conectado; *indicador_operacion_terminada=false; respuesta[pasos_operacion][ORDEN_KO]=“”; //reiniciar para descartar la configuración anterior que es desconocida respuesta[pasos_operacion][ORDEN_OK]=“ready”; comando[pasos_operacion++]=“AT+RST”; //reiniciar para descartar la configuración anterior que es desconocida //respuesta[pasos_operacion][ORDEN_KO]=”ERROR”; //Consultar el firmware //respuesta[pasos_operacion][ORDEN_OK]=”OK”; //comando[pasos_operacion++]=”AT+GMR”; //Consultar el firmware respuesta[pasos_operacion][ORDEN_KO]=“”; //Modo Sta (1|3) respuesta[pasos_operacion][ORDEN_OK]=“”; comando[pasos_operacion++]=“AT+CWMODE=1”; //Modo Sta = 1 (también es posible con 3, mixto) //respuesta[pasos_operacion][ORDEN_KO]=””; //Listado de puntos de acceso //respuesta[pasos_operacion][ORDEN_OK]=””; //comando[pasos_operacion++]=”AT+CWLAP”; //Listado de puntos de acceso respuesta[pasos_operacion][ORDEN_KO]=“”; respuesta[pasos_operacion][ORDEN_OK]=“”; comando[pasos_operacion++]=“ATE0”; //Desactivar el eco antes de mandar la clave respuesta[pasos_operacion][ORDEN_KO]=“FAIL”; //En el firmware original era “Error” respuesta[pasos_operacion][ORDEN_OK]=“OK”; comando[pasos_operacion++]=“AT+CWJAP=\””+ssid+“\”,\””+clave+“\””; //SSID y clave respuesta[pasos_operacion][ORDEN_KO]=“”; respuesta[pasos_operacion][ORDEN_OK]=“”; comando[pasos_operacion++]=“ATE1”; //Activar el eco antes de seguir respuesta[pasos_operacion][ORDEN_KO]=“”; respuesta[pasos_operacion][ORDEN_OK]=“\””+ssid+“\””; comando[pasos_operacion++]=“AT+CWJAP?”; //Comprobar que se ha conectado respuesta[pasos_operacion][ORDEN_KO]=“ERROR”; respuesta[pasos_operacion][ORDEN_OK]=ip.substring(0,ip.lastIndexOf(‘.’)+1); comando[pasos_operacion++]=“AT+CIFSR”; //Consultar la dirección IP respuesta[pasos_operacion][ORDEN_KO]=“ERROR”; respuesta[pasos_operacion][ORDEN_OK]=“AT+CIPMUX=0\r\r\n\r\nOK”; comando[pasos_operacion++]=“AT+CIPMUX=0”; //Conenexión simple } void ESP8266::http ( byte tipo_consulta_http, String direccion_servidor, unsigned int puerto, String nombre_servidor, String agente, String pagina, String texto_consulta, String respuesta_ko, String respuesta_ok ) { String consulta=“”; estado_orden=ORDEN_OK; pasos_operacion=0; paso_operacion=255; //Para poder incrementar al principio del proceso y que empiece en cero consultando_http=true; reiniciar_buffer(); indicador_operacion_terminada=&consultando_http; *indicador_operacion_terminada=false; switch(tipo_consulta_http) { case HTTP_GET: consulta+=“GET”; if(texto_consulta!=“”) { pagina+=“?”+texto_consulta; } break; case HTTP_POST: consulta+=“POST”; break; } consulta+=” /”+pagina+” HTTP/1.1″+“\r\n”; consulta+=“User-Agent: “+agente+“\r\n”; consulta+=“Host: “+nombre_servidor+“\r\n”; if(tipo_consulta_http==HTTP_POST) { consulta+=“Content-Type: application/x-www-form-urlencoded\r\n”; consulta+=“Content-Length: “+String(texto_consulta.length(),DEC)+“\r\n”; consulta+=“\r\n”; consulta+=texto_consulta; } consulta+=“\r\n”; respuesta[pasos_operacion][ORDEN_KO]=“ERROR”; //en el firmware anterior era “Error” respuesta[pasos_operacion][ORDEN_OK]=“OK”; //en el firmware anterior era “Linked” comando[pasos_operacion++]=“AT+CIPSTART=\”TCP\”,\””+direccion_servidor+“\”,”+String(puerto,DEC); respuesta[pasos_operacion][ORDEN_KO]=“Error”; respuesta[pasos_operacion][ORDEN_OK]=“>”; comando[pasos_operacion++]=“AT+CIPSEND=”+String(consulta.length(),DEC); respuesta[pasos_operacion][ORDEN_KO]=respuesta_ko; respuesta[pasos_operacion][ORDEN_OK]=respuesta_ok; //respuesta[pasos_operacion][ORDEN_OK]=”CLOSED”; //en el firmware anterior era “Unlink” comando[pasos_operacion++]=consulta; /* respuesta[pasos_operacion][ORDEN_KO]=””; respuesta[pasos_operacion][ORDEN_OK]=”OK”; comando[pasos_operacion++]=”AT+CIPCLOSE”; */ } void ESP8266::enviar() { if(!*indicador_operacion_terminada) { switch(estado_orden) { case ORDEN_OK: paso_operacion++; if(paso_operacion<pasos_operacion) { enviar_comando ( comando[paso_operacion], respuesta[paso_operacion][ORDEN_KO], respuesta[paso_operacion][ORDEN_OK] ); } else { *indicador_operacion_terminada=true; } break; case ORDEN_KO: paso_operacion—; estado_orden=ORDEN_OK; delay(ESPERA_REINTENTO); break; /* case ORDEN_RECIBIENDO: break; case ORDEN_ACTIVA: break; */ } } } //integrar en enviar void ESP8266::enviar_comando(String comando,String respuesta_ko,String respuesta_ok) { /* //Monitorizar las ordenes que se envian if(mostrar_salida) { CONSOLA.print(“\n”); CONSOLA.print(“(“+String(millis(),DEC)+”)”); //CONSOLA.print(“\n”); CONSOLA.print(String(paso_operacion+1,DEC)+”/”+String(pasos_operacion,DEC)+”> “); CONSOLA.print(comando); CONSOLA.print(” [“+respuesta_ko+”|”+respuesta_ok+”]”); CONSOLA.print(“\n”); } */ MODULO_WIFI.println(comando); mensaje_buscado[ORDEN_KO]=respuesta_ko; mensaje_buscado[ORDEN_OK]=respuesta_ok; if(respuesta_ok==“”) { estado_orden=ORDEN_OK; delay(ESPERA_ORDEN); } else { estado_orden=ORDEN_ACTIVA; reiniciar_busqueda_mensaje(); } } void ESP8266::reiniciar_buffer() { puntero_buffer=0; buffer_activo=false; longitud_ipd=0; } void ESP8266::reiniciar_busqueda_mensaje() { byte contador; buscando_mensaje=true; //estados=sizeof(mensaje_buscado)/sizeof(String); //Es posible generalizar calculando los estados for(contador=0;contador<ESTADOS_COMUNICACION;contador++) { puntero_mensaje[contador]=0; longitud_mensaje[contador]=mensaje_buscado[contador].length(); } } void ESP8266::recibir() { char lectura; while(MODULO_WIFI.available()>0) { lectura=MODULO_WIFI.read(); if(mostrar_salida) { CONSOLA.print(lectura); } if(buffer_activo) { if(longitud_ipd==0&&lectura==CODIGO_FIN_RECEPCION) { ESP8266_buffer[puntero_buffer]=0; longitud_ipd=atoi(ESP8266_buffer); puntero_buffer=0; } else { ESP8266_buffer[puntero_buffer++]=lectura; } } if(estado_orden==ORDEN_ACTIVA||estado_orden==ORDEN_RECIBIENDO) { estado_orden=buscar_mensaje(lectura,mensaje_buscado); if(estado_orden==ORDEN_RECIBIENDO) { buffer_activo=true; estado_orden=ORDEN_ACTIVA; buscando_mensaje=true; } } } } byte ESP8266::buscar_mensaje(char lectura,String *mensaje) { byte contador; byte numero_de_estado=0; while(numero_de_estado<ESTADOS_COMUNICACION–buffer_activo&&buscando_mensaje) { if(longitud_mensaje[numero_de_estado]) { if(lectura==mensaje[numero_de_estado].charAt(puntero_mensaje[numero_de_estado])) { puntero_mensaje[numero_de_estado]++; if(puntero_mensaje[numero_de_estado]==longitud_mensaje[numero_de_estado]) { buscando_mensaje=false; for(contador=0;contador<ESTADOS_COMUNICACION–buffer_activo;contador++) { puntero_mensaje[contador]=0; } } } else { puntero_mensaje[numero_de_estado]=0; } } numero_de_estado=numero_de_estado+buscando_mensaje; } if(buscando_mensaje) { return ORDEN_ACTIVA; } else { return numero_de_estado; } } char *ESP8266::leer_buffer() { reiniciar_buffer(); return ESP8266_buffer; } byte ESP8266::longitud_buffer() { return longitud_ipd; } boolean ESP8266::conectado() { return ESP8266_conectado; } boolean ESP8266::desconectado() { return ESP8266_conectado; } boolean ESP8266::consulta_ok() { return estado_orden==ORDEN_OK; } boolean ESP8266::operacion_terminada() { return *indicador_operacion_terminada; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | //ESP8266.h #if defined(ARDUINO) && ARDUINO>=100 #include “Arduino.h” #else #include “WProgram.h” #endif #define HTTP_CONNECT 0 //Codigos HTTP (en uso + reservados) #define HTTP_DELETE 1 #define HTTP_GET 2 #define HTTP_HEAD 3 #define HTTP_OPTIONS 4 #define HTTP_PATCH 5 #define HTTP_POST 6 #define HTTP_PUT 7 #define HTTP_TRACE 8 #define PASOS_HTTP 4 #define MAXIMO_PASOS_OPERACION 8 //+listar puntos de acceso +verificar firmware #define ESTADOS_COMUNICACION 3 //Estados que contienen mensajes que hay que atender #define ORDEN_KO 0 #define ORDEN_OK 1 #define ORDEN_RECIBIENDO 2 //debe ser el último de los estados para desactivarlo cuando se este rellenando el buffer #define ORDEN_ACTIVA 3 //debe ser igual a ESTADOS_COMUNICACION (uno más que el último estado) #define ESPERA_ORDEN 3000 //milisegundos despues de una orden AT sin respuesta #define ESPERA_REINTENTO 5000 //milisegundos antes de reintentar una orden AT #define MAX_BUFFER 256 //cambiar también el tipo de puntero_buffer si aumenta #define CODIGO_INICIO_RECEPCION “+IPD,” #define CODIGO_FIN_RECEPCION ‘:’ class ESP8266 { private: boolean ESP8266_conectado; boolean consultando_http; boolean ESP8266_operacion_terminada; boolean *indicador_operacion_terminada; boolean mostrar_salida; boolean datos_recibidos; byte paso_operacion; byte pasos_operacion; //boolean estado_operacion; String comando[MAXIMO_PASOS_OPERACION]; String respuesta[MAXIMO_PASOS_OPERACION][ESTADOS_COMUNICACION]; String mensaje_buscado[MAXIMO_PASOS_OPERACION]; byte puntero_mensaje[ESTADOS_COMUNICACION]; //ORDEN_KO->error (0/false), ORDEN_OK->acierto (1/true) byte longitud_mensaje[ESTADOS_COMUNICACION]; //longitudes la cadena de error y de la de acierto boolean buscando_mensaje; byte estado_orden; //boolean error_de_conexion; byte buscar_mensaje(char lectura,String *mensaje); void reiniciar_busqueda_mensaje(); char ESP8266_buffer[MAX_BUFFER]; boolean buffer_activo; byte puntero_buffer; byte longitud_ipd; void enviar_comando ( String comando, String respuesta_ok, String respuesta_ko ); protected: public: ESP8266(); ESP8266(boolean depuracion); ~ESP8266(); void conectar_wifi ( String ssid, String clave, String ip, byte timeout ); void constructor(boolean depuracion); void http ( byte tipo_consulta_http, String direccion_servidor, unsigned int puerto, String nombre_servidor, String agente, String pagina, String texto_consulta, String respuesta_ko, String respuesta_ok ); void reiniciar_buffer(); char *leer_buffer(); byte longitud_buffer(); void enviar(); void recibir(); boolean conectado(); boolean desconectado(); boolean consulta_ok(); boolean operacion_terminada(); }; |
Το παρακάτω παράδειγμα χρησιμοποιεί τη βιβλιοθήκη ερωτημάτων HTTP με τη μονάδα WiFi ESP8266 για την αποστολή δεδομένων στον διακομιστή (ένα ποσοστό που προκύπτει από την ανάγνωση μιας αναλογικής εισόδου) κάθε συγκεκριμένο χρονικό διάστημα. Δεδομένου ότι δεν αναμένει να λάβει καμία απάντηση, δεν χρησιμοποιεί το buffer και αρκεί για να ολοκληρωθεί σωστά η λειτουργία. Αυτό το σύστημα είναι αυτό που χρησιμοποιώ στο έργο της συσκευής διαχείρισης ύπνου για την αποθήκευση των αποτελεσμάτων των μετρήσεων του αισθητήρα στον διακομιστή.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | #include “ESP8266.h” #define MODO_DEPURACION true #define PIN_LED_CONEXION 13 #define WIFI_VELOCIDAD 115200 #define WIFI_SSID “SleepManager” #define WIFI_CLAVE “****” #define CONSOLA_VELOCIDAD 115200 #define SERVIDOR_DIRECCION “192.168.1.22” #define SERVIDOR_PUERTO 80 #define SERVIDOR_PROTOCOLO “HTTP/1.1” #define SERVIDOR_NOMBRE “” #define SERVIDOR_AGENTE “sleepmanager-clinic-wifi” #define PAGINA_PRUEBA “pruebas/lectura_porcentaje.php” #define PARAMETRO_PRUEBA “porcentaje” #define CONSULTA_KO “” #define CONSULTA_OK “porcentaje recibido correctamente” #define TIMEOUT_CONEXION 30000 #define INTERVALO_LECTURAS_SENSOR 60000 float valor_sensor_analogico; String texto_consulta; unsigned long cronometro_lectura=0; ESP8266 conexion_wifi_servidor(MODO_DEPURACION); void setup() { Serial.begin(CONSOLA_VELOCIDAD); // Cambiar para que el puerto serie corresponda con el de la consola Serial1.begin(WIFI_VELOCIDAD); // Cambiar para que el puerto serie corresponda con el del módulo WiFi delay(5000); //Unos segundos para que el humano active la consola conexion_wifi_servidor.conectar_wifi ( WIFI_SSID, WIFI_CLAVE, SERVIDOR_DIRECCION, TIMEOUT_CONEXION ); } void loop() { if(conexion_wifi_servidor.operacion_terminada()) { if(conexion_wifi_servidor.conectado()) { digitalWrite(PIN_LED_CONEXION,HIGH); if(cronometro_lectura<millis()) { valor_sensor_analogico=analogRead(A0)*100.0/1023.0; texto_consulta=String(PARAMETRO_PRUEBA)+“=”+String(valor_sensor_analogico,DEC); cronometro_lectura=millis()+INTERVALO_LECTURAS_SENSOR; conexion_wifi_servidor.http ( HTTP_POST, SERVIDOR_DIRECCION, SERVIDOR_PUERTO, SERVIDOR_NOMBRE, SERVIDOR_AGENTE, PAGINA_PRUEBA, texto_consulta, CONSULTA_KO, CONSULTA_OK ); } } else { digitalWrite(PIN_LED_CONEXION,LOW); conexion_wifi_servidor.conectar_wifi ( WIFI_SSID, WIFI_CLAVE, SERVIDOR_DIRECCION, TIMEOUT_CONEXION ); } } else { conexion_wifi_servidor.enviar(); } conexion_wifi_servidor.recibir(); } |
Το παρακάτω παράδειγμα χρησιμοποιεί ένα ερώτημα HTTP GET για να ρωτήσει την ώρα του διακομιστή και να τον συγχρονίσει με τον χρόνο της μικροελεγχόμενης συσκευής προσθέτοντας τον εκτιμώμενο χρόνο απόκρισης. Στην πραγματικότητα, προσθέτει άλλα 4 έως 6 δευτερόλεπτα για να διασφαλίσει ότι η ώρα της συσκευής είναι μεγαλύτερη από την ώρα του διακομιστή και να ελέγχει εύκολα εάν η ώρα στο ρολόι πραγματικού χρόνου που αποτελεί μέρος της συσκευής είναι σωστή ή έχει χαθεί λόγω λήψης μπαταρία.
Μετά από πολλές δοκιμές έχω επαληθεύσει ότι αυτό το σύστημα του Συγχρονισμός ώρας με μονάδα WiFi ESP8266 Είναι αρκετά ακριβές για τις ανάγκες μου. στη χειρότερη περίπτωση με σφάλμα λιγότερο από 10 δευτερόλεπτα που είναι κάπως άσχετο στην περίπτωσή μου.
Όπως φαίνεται στον κώδικα, είναι απαραίτητο να ρωτήσετε πρώτα το μήκος του buffer αφού η ανάγνωση επαναφέρει έτσι ώστε να είναι διαθέσιμο για αποθήκευση νέων δεδομένων.
Μόλις διαβαστεί το περιεχόμενο του buffer, σε αυτό το παράδειγμα υποβάλλεται σε επεξεργασία για να ληφθεί ο χρόνος. Αρχικά, επιλέγεται το κείμενο μεταξύ των αγκύλων (ο διακομιστής απαντά χρησιμοποιώντας την εντολή PHP ) το μετατρέπει σε «χρονοαντικείμενο» και λαμβάνει την ημερομηνία και την ώρα από αυτό σε ανθρώπινη μορφή.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | #include <Time.h> #include “ESP8266.h” #define MODO_DEPURACION true #define PIN_LED_CONEXION 13 #define WIFI_VELOCIDAD 115200 #define WIFI_SSID “SleepManager” #define WIFI_CLAVE “****” #define CONSOLA_VELOCIDAD 115200 #define SERVIDOR_DIRECCION “192.168.1.22” #define SERVIDOR_PUERTO 80 #define SERVIDOR_PROTOCOLO “HTTP/1.1” #define SERVIDOR_NOMBRE “” #define SERVIDOR_AGENTE “sleepmanager-clinic-wifi” #define PAGINA_PRUEBA “pruebas/hora_servidor.php” #define CONSULTA_KO “” #define CONSULTA_OK “CLOSED” // Cuando se desconecte el servidor pasado el timeout #define TIMEOUT_CONEXION 3000 #define INTERVALO_LECTURAS_HORA 60000 String texto_consulta; unsigned long cronometro_lectura=0; ESP8266 conexion_wifi_servidor(MODO_DEPURACION); byte longitud_buffer; byte inicio_fecha; byte fin_fecha; char *buffer; time_t fecha_hora; void setup() { Serial.begin(CONSOLA_VELOCIDAD); // Cambiar para que el puerto serie corresponda con el de la consola Serial1.begin(WIFI_VELOCIDAD); // Cambiar para que el puerto serie corresponda con el del módulo WiFi delay(5000); //Unos segundos para que el humano active la consola conexion_wifi_servidor.conectar_wifi ( WIFI_SSID, WIFI_CLAVE, SERVIDOR_DIRECCION, TIMEOUT_CONEXION ); texto_consulta=“”; //no se envía información, solo se lee la pagina } void loop() { if(conexion_wifi_servidor.operacion_terminada()) { if(conexion_wifi_servidor.conectado()) { digitalWrite(PIN_LED_CONEXION,HIGH); if(cronometro_lectura<millis()) { cronometro_lectura=millis()+INTERVALO_LECTURAS_HORA; conexion_wifi_servidor.http ( HTTP_GET, SERVIDOR_DIRECCION, SERVIDOR_PUERTO, SERVIDOR_NOMBRE, SERVIDOR_AGENTE, PAGINA_PRUEBA, texto_consulta, CONSULTA_KO, CONSULTA_OK ); } else { longitud_buffer=conexion_wifi_servidor.longitud_buffer(); if(longitud_buffer) { buffer=conexion_wifi_servidor.leer_buffer(); inicio_fecha=String(buffer).indexOf(‘{‘); if(inicio_fecha<255) { fin_fecha=String(buffer).indexOf(‘}’); if(fin_fecha>0) { fecha_hora=String(buffer).substring(inicio_fecha+1,fin_fecha).toInt()+10; Serial.println ( “Fecha: “+ String(day(fecha_hora),DEC)+“/”+ String(month(fecha_hora),DEC)+“/”+ String(year(fecha_hora),DEC)+” “+ “Hora: “+ String(hour(fecha_hora),DEC)+“:”+ String(minute(fecha_hora),DEC)+“:”+ String(second(fecha_hora),DEC) ); } } } } } else { digitalWrite(PIN_LED_CONEXION,LOW); conexion_wifi_servidor.conectar_wifi ( WIFI_SSID, WIFI_CLAVE, SERVIDOR_DIRECCION, TIMEOUT_CONEXION ); } } else { conexion_wifi_servidor.enviar(); } conexion_wifi_servidor.recibir(); } |
Το ακόλουθο παράδειγμα προγράμματος, εμπνευσμένο από το ερώτημα ενός χρήστη, χρησιμοποιείται για την εύρεση της δημόσιας διεύθυνσης IP χρησιμοποιώντας την υπηρεσία Check IP AWS (Amazon Web Services) κάθε πέντε λεπτά.
Όπως και στα προηγούμενα παραδείγματα, γίνεται μια σειρά από υποθέσεις που θα πρέπει να αλλάξουν ανάλογα με τη διαμόρφωση δικτύου που χρησιμοποιείται (192.168.1.X, στο παράδειγμα), το SSID και το κλειδί WiFi... Ο τρόπος εύρεσης του Η διεύθυνση IP δεν είναι πολύ κομψή, υποθέτει ότι είναι η τελευταία γραμμή της απάντησης στο αίτημα HTTP GET, αν και μπορεί να υπάρχει ένα API για να το κάνει με πιο ορθόδοξο τρόπο.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | #include “ESP8266.h” #define MODO_DEPURACION true #define PIN_LED_CONEXION 13 #define WIFI_VELOCIDAD 115200 #define WIFI_SSID “SleepManager” #define WIFI_CLAVE “****” #define CONSOLA_VELOCIDAD 115200 #define RED_DIRECCION “192.168.1.X” #define SERVIDOR_DIRECCION “23.23.144.23” // ¡¡Mucho cuidado, puede cambiar la dirección IP!! (buscarla antes de usar el programa, por ejemplo, con ping checkip.amazonaws.com) #define SERVIDOR_PUERTO 80 #define SERVIDOR_PROTOCOLO “HTTP/1.1” #define SERVIDOR_NOMBRE “checkip.amazonaws.com” #define SERVIDOR_AGENTE “buscadordeipes” #define PAGINA_IP “” #define CONSULTA_KO “Error” #define CONSULTA_OK “\n\r\nOK” #define TIMEOUT_CONEXION 3000 #define INTERVALO_LECTURAS_IP 300000 //Leer la IP publica cada 5 minutos String texto_consulta; unsigned long cronometro_lectura=0; ESP8266 conexion_wifi_servidor(MODO_DEPURACION); byte longitud_buffer; byte inicio_ip; byte fin_ip; char *buffer; void setup() { Serial.begin(CONSOLA_VELOCIDAD); // Cambiar para que el puerto serie corresponda con el de la consola Serial1.begin(WIFI_VELOCIDAD); // Cambiar para que el puerto serie corresponda con el del módulo WiFi pinMode(PIN_LED_CONEXION,OUTPUT); digitalWrite(PIN_LED_CONEXION,LOW); delay(5000); //Unos segundos para que el humano active la consola conexion_wifi_servidor.conectar_wifi ( WIFI_SSID, WIFI_CLAVE, RED_DIRECCION, TIMEOUT_CONEXION ); texto_consulta=“”; //no se envia informacion, solo se lee la pagina } void loop() { if(conexion_wifi_servidor.operacion_terminada()) { if(conexion_wifi_servidor.conectado()) { digitalWrite(PIN_LED_CONEXION,HIGH); if(cronometro_lectura<millis()) { cronometro_lectura=millis()+INTERVALO_LECTURAS_IP; conexion_wifi_servidor.http ( HTTP_GET, SERVIDOR_DIRECCION, SERVIDOR_PUERTO, SERVIDOR_NOMBRE, SERVIDOR_AGENTE, PAGINA_IP, texto_consulta, CONSULTA_KO, CONSULTA_OK ); } else { longitud_buffer=conexion_wifi_servidor.longitud_buffer(); if(longitud_buffer) { buffer=conexion_wifi_servidor.leer_buffer(); inicio_ip=String(buffer).indexOf(“\r\n\r\n”)+4; fin_ip=String(buffer).indexOf(“\r\n”,inicio_ip)–1; Serial.println(“IP [“+String(buffer).substring(inicio_ip,fin_ip)+“]”); } } } else { digitalWrite(PIN_LED_CONEXION,LOW); conexion_wifi_servidor.conectar_wifi ( WIFI_SSID, WIFI_CLAVE, SERVIDOR_DIRECCION, TIMEOUT_CONEXION ); } } else { conexion_wifi_servidor.enviar(); } conexion_wifi_servidor.recibir(); } |
μπορείτε να κατεβάστε τη βιβλιοθήκη ESP8266 για ερωτήματα HTTP με το Arduino Uno (χωρίς κονσόλα) και από εδώ μπορείς κατεβάστε τη βιβλιοθήκη ερωτημάτων ESP8266 HTTP για το Arduino που χρησιμοποιεί μια κονσόλα, δηλαδή χρειάζεται να εφαρμόσει μια σειριακή θύρα μέσω λογισμικού ή να χρησιμοποιήσει ως υλικό, για παράδειγμα, μια μητρική πλακέτα arduino mega o arduino leonardo.
Δημοσίευση σχολίου