Este ejemplo básico de un servidor web asíncrono para usarlo en el esp8266 cargándolo desde
el Sketch
de arduino gracias a que con un flasheo del firmware podemos reprogramarlo como si
de un atmega328p
se tratase, y olvidándonos de los tediosos comandos AT como hacemos aqui Flashear Esp8266, fucK AT-commands usaremos el sensor DHT22 que es mucho más preciso que su archienemigo el DHT11, necesitaremos un conversor serial como el que contiene el arduino por medio de los pines tx/rx
si no tendríamos que comprar un conversor usb-serial ttl
muy económicos.
Estas son breves característica de ambos sensores:
DHT-22 pinout
Fuente regulable MB102
Usaremos esta fuente de 3.3v | 5v
con un transformador externo de 2000mAh
más salida de 12vc. Se ve en la fuente de poder MB102
, el jumper que nos permite obtener 3.3v, se puede comprobar con un multímetro
con puntas de caiman, y o agujas.
Un transformador de menos de 6.5vdc no servirá para la MB102
> Sin Fritzing
Pero esto sirve como vista final.
-
Una resistencia de 10Kohm( muchos usan 4.7k ) como pull-up entre el DATA y VCC(3.3v)
-
La GND la obtengo de la fuente de poder.
Escribiendo el código del servidor web asíncrono (AsynchronousWebServer)
Usaremos las librerías siguientes:
#include <ESP8266WiFi.h> (1)
#include <ESPAsyncTCP.h> (2)
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h> (3)
#include <DHTStable.h> (4)
1 | Para la conexión wifi (ESP8266WiFi) |
2 | Para el servidor asincrono así como la ESPAsyncWebServer |
3 | Creación del json (ArduinoJson) para la api Rest |
4 | Donde <DHTStable.h> es una lib más actual, y del sensor de humedad y temperatura <DHTStable.h> |
#define DHT22_PIN 4 (1)
DHTStable DHT;
1 | Definimos las variables para usar el pin del sensor DHT22 |
AsyncWebServer server(8081); (1)
1 | Definimos el puerto del servidor en el 8081, tengo los otros típicos en uso XD |
//Endpoints
const char* TEMPERATURES = "/async-esp8266/api/v1/dht22/temperatures"; (1)
const char* HUMIDITIES = "/async-esp8266/api/v1/dht22/humidities"; (2)
const char* LED_STATUS = "/async-esp8266/api/v1/led"; (3)
1 | Endpoints de temperatura |
2 | Endpoints de humedad |
3 | Endpoints para cambiar el estado del led |
Configuración de red wifi, colocamos nombre y password.
const char* ssid = "Tu red";
const char* password = "misuperhax0rpassword";
//esperando por conexión
while (WiFi.status() != WL_CONNECTED) { (1)
delay(1000);
Serial.println("Connecting to WiFi..");
}
1 | While que se intentara conectar a la red wifi, y notificara por la consola. |
void loop(void) {
DHT.read22(DHT22_PIN); (1)
t = DHT.getTemperature();
h = DHT.getHumidity();
Serial.print("Humidity: ");
Serial.print(h);
Serial.println(HUMIDITY);
Serial.print("Temperature: ");
Serial.print(t);
Serial.println(TMP);
delay(2000); (2)
}
1 | Aqui la función loop() necesaria para hacer la lectura del sensor, |
2 | Colocar un delay de 2 segundos |
la función initRoute simplemente saluda con un texto al visitar la url principal /
//Hello world!
void initRoute() {
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request -> send(OK_HTTP, TEXT_PLAIN, "Welcome webserver Esp8266");
});
}
Endpoint de temperatura
/async-esp8266/api/v1/dht22/temperatures
//Temperaturesº
void temperatures() {
server.on(TEMPERATURES, HTTP_GET, [](AsyncWebServerRequest * request) {
String json;
StaticJsonDocument<300> doc;
doc["sensor"] = "DHT-22";
doc["type"] = "AM2302";
doc["temperature"] = t;
serializeJson(doc, json);
request -> send(OK_HTTP, APPLICATION_JSON, json);
});
}
Endpoint de humedad
/async-esp8266/api/v1/dht22/humidities
//Humidities%
void humidities() {
server.on(HUMIDITIES, HTTP_GET, [](AsyncWebServerRequest * request) {
String json;
StaticJsonDocument<300> doc;
doc["sensor"] = "DHT-22";
doc["type"] = "AM2302";
doc["humidity"] = h;
serializeJson(doc, json);
request -> send(OK_HTTP, APPLICATION_JSON, json);
});
}
La función handeLED la usaremos para ver el estado del led, prender y apagarlo, lo típico actualizaremos
en el pin 2
a HIGH o LOW, dependiendo el query parameters.
// On/off Led
void handleLED() { (1)
//Show led status
server.on(LED_STATUS, HTTP_GET, [](AsyncWebServerRequest * request) {
ledstatus = digitalRead(LED_PIN);
if (ledstatus == HIGH) {
//status is ON
request -> send(OK_HTTP, TEXT_PLAIN, "Status ON");
} else {
//status is Off
request -> send(OK_HTTP, TEXT_PLAIN, "Status OFF");
}
});
//async-esp8266/api/v1/led?id=2&newstatus=on //ON
//async-esp8266/api/v1/led?id=2&newstatus=off //OFF
server.on(LED_STATUS, HTTP_PUT, [](AsyncWebServerRequest * request) {
String id = request-> arg("id"); (2)
String newstatus = request-> arg("newstatus"); (3)
if (id.toInt() == LED_PIN && newstatus.equalsIgnoreCase("on")) {
Serial.println("PIN HIGH");
digitalWrite(LED_PIN, HIGH);
request -> send(OK_HTTP, TEXT_PLAIN, oK);
} else if (id.toInt() == LED_PIN && newstatus.equalsIgnoreCase("off")) {
Serial.println("PIN LOW");
digitalWrite(LED_PIN, LOW);
request -> send(OK_HTTP, TEXT_PLAIN, oK);
} else {
request -> send(400, TEXT_PLAIN, "Bad Request");
}
});
}
1 | Función para manejar el control del led, se debe factorizar un poco más, dividir mejor en otras funciones |
2 | Obtenemos el id del led |
3 | Por medio del estatus, apagamos o lo prendemos. |
Código completo
Endpoints
Operation | URI | ||||
---|---|---|---|---|---|
|
/async-esp8285/api/v1/dht22 |
||||
|
/async-esp8285/api/v1/dht22/temperatures |
||||
|
/async-esp8285/api/v1/dht22/humidities |
||||
|
/async-esp8285/api/v1/led
|
/**
*
* Make simple Asynchronous webserver using DHT22 for log temperature and humidity.
*
*/
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h>
#include <DHTStable.h>
#define DHT22_PIN 4
DHTStable DHT;
AsyncWebServer server(8081);// Create a asynchronous webserver object that listens for HTTP request on port 8081
int led_status = 0;
float t = 0;
float h = 0;
const int LED_PIN = 2;
const int OK_HTTP = 200;
//Endpoints
const char* DHT22 = "/async-esp8285/api/v1/dht22";
const char* TEMPERATURES = "/async-esp8285/api/v1/dht22/temperatures";
const char* HUMIDITIES = "/async-esp8285/api/v1/dht22/humidities";
const char* LED = "/async-esp8285/api/v1/led";
const char* DHT_22 = "DHT-22";
const char* AM2302 = "AM2302";
const char* CENTIGRADE = "ºC";
const char* PERCENTAGE = "%";
const char* TEXT_PLAIN = "text/plain";
const char* APPLICATION_JSON = "application/json";
const char* ON = "ON";
const char* OFF = "OFF";
const char* ID = "id";
const char* NEW_STATUS = "status";
const char* SENSOR = "sensor";
const char* TYPE = "type";
const char* TEMPERATURE = "temperature";
const char* HUMIDITY = "humidity";
//Wifi network credentials
const char* ssid = "Filomena 2.4";
const char* password = "zAHF4n+MMHniN*G"; //aqui les dejo mi contraseña para que se conecten, wifi free :)
void setup(void) {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
delay(10);
Serial.println('\n');
WiFi.begin(ssid, password);
//wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
Serial.println('\n');
Serial.print("Connected to ");
Serial.println(WiFi.SSID());
Serial.print("IP address:\t");
Serial.println(WiFi.localIP());
initRoute();
temperatures();
humidities();
dht22();
handleLED();
handleNotFound();
server.begin();// Actually start the server
Serial.println("HTTP server started");
}
void loop(void) {
DHT.read22(DHT22_PIN);
t = DHT.getTemperature();
h = DHT.getHumidity();
Serial.print("Humidity: ");
Serial.print(h);
Serial.println(PERCENTAGE);
Serial.print("Temperature: ");
Serial.print(t);
Serial.println(CENTIGRADE);
delay(2000);
}
//Welcome webserver Esp8266!!!
void initRoute() {
server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
request -> send(OK_HTTP, TEXT_PLAIN, "Welcome webserver Esp8266");
});
}
//Temperaturesª
void temperatures() {
server.on(TEMPERATURES, HTTP_GET, [](AsyncWebServerRequest * request) {
String json;
StaticJsonDocument<300> doc;
doc[SENSOR] = DHT_22;
doc[TYPE] = AM2302;
doc[TEMPERATURE] = t;
serializeJson(doc, json);
request -> send(OK_HTTP, APPLICATION_JSON, json);
});
}
//Humidities%
void humidities() {
server.on(HUMIDITIES, HTTP_GET, [](AsyncWebServerRequest * request) {
String json;
StaticJsonDocument<300> doc;
doc[SENSOR] = DHT_22;
doc[TYPE] = AM2302;
doc[HUMIDITY] = h;
serializeJson(doc, json);
request -> send(OK_HTTP, APPLICATION_JSON, json);
});
}
//DHT22 humidities% and temperaturesª
void dht22() {
server.on(DHT22, HTTP_GET, [](AsyncWebServerRequest * request) {
String json;
StaticJsonDocument<300> doc;
doc[SENSOR] = DHT_22;
doc[TYPE] = AM2302;
doc[TEMPERATURE] = t;
doc[HUMIDITY] = h;
serializeJson(doc, json);
request -> send(OK_HTTP, APPLICATION_JSON, json);
});
}
// On/off Led
void handleLED() {
//Show led status
server.on(LED, HTTP_GET, [](AsyncWebServerRequest * request) {
led_status = digitalRead(LED_PIN);
if (led_status == HIGH) {
String json;
StaticJsonDocument<300> doc;
doc[ID] = LED_PIN;
doc[NEW_STATUS] = ON;
serializeJson(doc, json);
request -> send(OK_HTTP, APPLICATION_JSON, json);
} else {
String json;
StaticJsonDocument<300> doc;
doc[ID] = LED_PIN;
doc[NEW_STATUS] = OFF;
serializeJson(doc, json);
request -> send(OK_HTTP, APPLICATION_JSON, json);
}
});
//async-esp8266/api/v1/led?id=2&status=on //ON
//async-esp8266/api/v1/led?id=2&status=off //OFF
server.on(LED, HTTP_PUT, [](AsyncWebServerRequest * request) {
String id = request-> arg(ID);
String new_status = request-> arg(NEW_STATUS);
if (id.toInt() == LED_PIN && new_status.equalsIgnoreCase(ON)) {
Serial.println("PIN HIGH");
digitalWrite(LED_PIN, HIGH);
String json;
StaticJsonDocument<300> doc;
doc[ID] = LED_PIN;
doc[NEW_STATUS] = ON;
serializeJson(doc, json);
request -> send(OK_HTTP, APPLICATION_JSON, json);
} else if (id.toInt() == LED_PIN && new_status.equalsIgnoreCase(OFF)) {
Serial.println("PIN LOW");
digitalWrite(LED_PIN, LOW);
String json;
StaticJsonDocument<300> doc;
doc[ID] = LED_PIN;
doc[NEW_STATUS] = OFF;
serializeJson(doc, json);
request -> send(OK_HTTP, APPLICATION_JSON, json);
} else {
request -> send(400, TEXT_PLAIN, "Bad Request");
}
});
}
//404
void handleNotFound() {
//Error 404 not found
server.onNotFound([](AsyncWebServerRequest * request) {
request->send(404, TEXT_PLAIN, "Sorry, 404 not found.");
});
}
// -- EOF --
Con respecto a la seguridad
Seria muy buena idea añadir autenticación y certificados ssl o redireccion via https forzada con un reverse-proxy nginx, así no tenemos que poner tanto código en el micro.