domingo, 23 de julio de 2017

Tutorial #11 ESP8266 (Parte1) - MQTT + CloudMQTT

Este tutorial de IOT (internet de las cosas) es la primera parte de una serie de tutoriales sobre MQTT en ESP8266, para esto nos valemos del servicio gratuito de CloudMQTT.com

Vamos a usar exactamente el mismo hardware del tutorial 5(.../tutorial-5-esp8266-mqtt-ioadafruitcom.html), donde tenemos una entrada digital (pulsador), una entrada analógica (sensor de temperatura LM35), una salida digital (LED Rojo) y una salida analógica PWM (LED Verde).

En el video muestro como controlar la placa desde la consola de CloudMQTT; en próximos tutoriales voy a explicar cómo controlarlo desde una aplicación de Android, hacer nuestros propios tableros usando WebSocket, controlarlo desde Python, etc.



Código Fuente:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

//-------------------VARIABLES GLOBALES--------------------------
int contconexion = 0;

const char *ssid = "---";
const char *password = "---";
char   SERVER[50]   = "75.101.131.202"; //"m11.cloudmqtt.com"
int    SERVERPORT   = 10722;
String USERNAME = "placa1";   
char   PASSWORD[50] = "12345678";     

unsigned long previousMillis = 0;

char charPulsador [15];
String strPulsador;
String strPulsadorUltimo;

char PLACA[50];

char valueStr[15];
String strtemp = "";
char TEMPERATURA[50];
char PULSADOR[50];
char SALIDADIGITAL[50];
char SALIDAANALOGICA[50];


//-------------------------------------------------------------------------
WiFiClient espClient;
PubSubClient client(espClient);

//------------------------CALLBACK-----------------------------
void callback(char* topic, byte* payload, unsigned int length) {

  char PAYLOAD[5] = "    ";
  
  Serial.print("Mensaje Recibido: [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    PAYLOAD[i] = (char)payload[i];
  }
  Serial.println(PAYLOAD);

  if (String(topic) ==  String(SALIDADIGITAL)) {
    if (payload[1] == 'N'){
     digitalWrite(12, HIGH);
    }
    if (payload[1] == 'F'){
      digitalWrite(12, LOW);
    }
  }

  if (String(topic) ==  String(SALIDAANALOGICA)) {
    analogWrite(13, String(PAYLOAD).toInt());
  }
}

//------------------------RECONNECT-----------------------------
void reconnect() {
  uint8_t retries = 3;
  // Loop hasta que estamos conectados
  while (!client.connected()) {
    Serial.print("Intentando conexion MQTT...");
    // Crea un ID de cliente al azar
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    USERNAME.toCharArray(PLACA, 50);
    if (client.connect("", PLACA, PASSWORD)) {
      Serial.println("conectado");
      client.subscribe(SALIDADIGITAL);
      client.subscribe(SALIDAANALOGICA);
    } else {
      Serial.print("fallo, rc=");
      Serial.print(client.state());
      Serial.println(" intenta nuevamente en 5 segundos");
      // espera 5 segundos antes de reintentar
      delay(5000);
    }
    retries--;
    if (retries == 0) {
      // esperar a que el WDT lo reinicie
      while (1);
    }
  }
}

//------------------------SETUP-----------------------------
void setup() {

  //prepara GPI13 y 12 como salidas 
  pinMode(13, OUTPUT); // D7 salida analógica
  analogWrite(13, 0); // analogWrite(pin, value);
  pinMode(12, OUTPUT); // D6 salida digital
  digitalWrite(12, LOW);

  // Entradas
  pinMode(14, INPUT); // D5

  // Inicia Serial
  Serial.begin(115200);
  Serial.println("");

  // Conexión WIFI
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED and contconexion <50) { //Cuenta hasta 50 si no se puede conectar lo cancela
    ++contconexion;
    delay(500);
    Serial.print(".");
  }
  if (contconexion <50) {
      //para usar con ip fija
      IPAddress ip(192,168,1,156); 
      IPAddress gateway(192,168,1,1); 
      IPAddress subnet(255,255,255,0); 
      WiFi.config(ip, gateway, subnet); 
      
      Serial.println("");
      Serial.println("WiFi conectado");
      Serial.println(WiFi.localIP());
  }
  else { 
      Serial.println("");
      Serial.println("Error de conexion");
  }
  
  client.setServer(SERVER, SERVERPORT);
  client.setCallback(callback);

  String temperatura = "/" + USERNAME + "/" + "temperatura"; 
  temperatura.toCharArray(TEMPERATURA, 50);
  String pulsador = "/" + USERNAME + "/" + "pulsador"; 
  pulsador.toCharArray(PULSADOR, 50);
  String salidaDigital = "/" + USERNAME + "/" + "salidaDigital"; 
  salidaDigital.toCharArray(SALIDADIGITAL, 50);
  String salidaAnalogica = "/" + USERNAME + "/" + "salidaAnalogica"; 
  salidaAnalogica.toCharArray(SALIDAANALOGICA, 50);
  
}

//--------------------------LOOP--------------------------------
void loop() {

  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  unsigned long currentMillis = millis();
    
  if (currentMillis - previousMillis >= 10000) { //envia la temperatura cada 10 segundos
    previousMillis = currentMillis;
    int analog = analogRead(17);
    float temp = analog*0.322265625;
    strtemp = String(temp, 1); //1 decimal
    strtemp.toCharArray(valueStr, 15);
    Serial.println("Enviando: [" +  String(TEMPERATURA) + "] " + strtemp);
    client.publish(TEMPERATURA, valueStr);
  }
  
  if (digitalRead(14) == 0) {
    strPulsador = "presionado";
  } else {
    strPulsador = "NO presionado";
  }

  if (strPulsador != strPulsadorUltimo) { //envia el estado del pulsador solamente cuando cambia.
    strPulsadorUltimo = strPulsador;
    strPulsador.toCharArray(valueStr, 15);
    Serial.println("Enviando: [" +  String(PULSADOR) + "] " + strPulsador);
    client.publish(PULSADOR, valueStr);
  }
}

9 comentarios:

  1. Estimado,

    Al buscar la librería esp8266wifi no aparece en la opción del gestor de librerías del IDE. La he buscado y no la encuentro en github. Estoy usando la versión 1.8.5 de arduino. ¿Dónde podría encontrar esa librería o cuál sería la otra forma de enviar datos a través de ese dispositivo wifi?

    Saludos

    ResponderEliminar
    Respuestas
    1. Mira acate dejo un tutorial de como instalar las librerias:

      https://programarfacil.com/esp8266/como-programar-nodemcu-ide-arduino/

      Eliminar
  2. Hola,

    Gracias por el tutorial, útil para entender como funciona cloudmqtt.
    Funciona practicamente todo... pero no consigo desde el websocket UI de cloudmqtt ver las lecturas y forzar salidas en la placa sino defino un topic como: placa1 - #
    Desconozco si es porque cloudmqtt ha hecho algunos cambios desde que publicaste el vídeo. ¿Sabes como lo debería hacer sin necesidad de utilizar esta wildcard?

    Gracias,

    ResponderEliminar
    Respuestas
    1. Ya lo he resuelto yo mismo... en topic hay que poner toda la cadena

      Eliminar
    2. yo tengo ese problema podrias ayudarme a que te refieres con toda la cadena

      Eliminar
    3. Tengo el mismo problema, a que te refieres con toda la cadena?

      Eliminar
  3. Buenas a todos....son mis primeros pasos con mqtt y tengo el mismo problema con websocket UI no puedo visualizar los msj

    ResponderEliminar
  4. Buenas Alejandro, antes de nada muchísimas gracias por todo el material que tiene publicado, es de gran ayuda.
    Tengo un problema que no consigo solventar, no se si es porque no tengo bien hecha la función.
    Lo que quiero hacer es que si la alarma se activa EstadoAlarma1 (entrada booleana) y le mando un 0 por mqtt, la alarma se apague, la cosa es que cuando está activa y le mando un 0 esta sigue igual. Le dejo la función por si acaso la estoy haciendo mal:

    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();

    if (EstadoAlarma1==true && (char)payload[0] == '0') {
    digitalWrite(pinLED, LOW);
    Serial.println("Alarma desactivada");
    client.publish("dev/test", "ALARMA 1 DESACTIVADA");
    EstadoAlarma1=false;
    } else{
    }
    }

    Muchísimas gracias!

    ResponderEliminar
  5. Pueden ser mucho errore. ¿en algún lugar del código pone EstadoAlarma1==true?

    ResponderEliminar