Main Content

Esta página se ha traducido mediante traducción automática. Haga clic aquí para ver la última versión en inglés.

Control remoto de sensores mediante publicación y suscripción segura de MQTT

Este ejemplo muestra cómo utilizar la arquitectura de publicación y suscripción MQTT en ThingSpeak. El protocolo MQTT es un sistema de mensajería de dispositivo de bajo costo. Usando MQTT, suscríbase al campo 1 de un canal de control. Cuando actualiza el canal de control, el valor publicado se envía a su dispositivo. El servo gira al ángulo especificado. El dispositivo mide la intensidad de la red y actualiza el canal de almacenamiento. Los comentarios en el código indican cómo adaptar este ejemplo para una conexión no segura.

Hardware compatible

  • ESP8266, NodeMCU, WeMOS

  • Arduino MKR1000

  • Arduino Uno, Mega, Due o Leonardo con conexión de red inalámbrica

  • Fotón de partículas (con ligeros ajustes de código y esquemáticos)

El ejemplo está diseñado para funcionar con sólo unos pocos componentes adicionales, concretamente un único servomotor. Utilice la antena Wi-Fi integrada para realizar mediciones de intensidad de Wi-Fi.

Estas imágenes muestran la salida del canal de muestra del canal de almacenamiento. El campo 1 almacena el ángulo del servomotor que se configura desde el canal de control y el campo 2 muestra el valor de intensidad de Wi-Fi medido.

El análisis de datos muestra que la orientación del hardware WeMOS tiene un efecto direccional en la intensidad de la señal medida.

Requisitos previos

1) Cree un canal ThingSpeak para el control de suscripción como se muestra en Collect Data in a New Channel. El canal de suscripción mantiene el ángulo para el servomotor. Cuando se actualiza el ángulo del servomotor, el dispositivo suscrito recibe el ángulo como un mensaje MQTT. El dispositivo establece el ángulo del servo y mide la intensidad de la nueva red inalámbrica en ese ángulo.

2) Crea otro canal de ThingSpeak para los datos publicados. El canal de publicación registra el ángulo establecido y los datos de intensidad de la señal.

3) En la vista Configuración del canal , habilite los campos 1 y 2 para el canal de publicación. Para distinguir entre los campos, asigne a cada campo un nombre descriptivo.

4) Tenga en cuenta las claves API de lectura y escritura en la pestaña Claves API en la vista Configuración del canal (encerrada en un círculo en la imagen).

5) Cree un dispositivo MQTT haciendo clic en Dispositivos > MQTT en la parte superior de la página, luego Agregar un nuevo dispositivo. Cuando configure el dispositivo, autorice ambos canales para publicar y suscribirse. Para obtener más información, consulte Crear un dispositivo ThingSpeak MQTT.

6) Mientras agrega el nuevo dispositivo, haga clic en Descargar credenciales > Arduino (mqtt_secrets.h). Guarde este archivo de secretos descargado para acceder a él en la sección Código a continuación.

Hardware requerido

  • WeMOS D1 Mini, o uno de los siguientes dispositivos con cambios en las bibliotecas utilizadas: NodeMCU, ESP8266-01, ESP8266-04, ESP8266-12, ESP8266-12E, Arduino® MKR1000 u otro Arduino con conexión de red Ethernet o inalámbrica

  • Servomotor (por ejemplo, Futaba S3003)

  • Cables de puente (al menos 3)

  • cable USB

Esquema y Conexiones

1) Conecte D5 en el WeMOS D1 Mini a la línea de señal del servo.

2) Conecte el cable de tierra del servo a tierra en la placa WeMOS.

3) Conecte la alimentación del servo a 3,3 V. El uso directo de 5 V puede sobrecargar el límite de alimentación del USB en algunos casos.

Programa tu Arduino

Utilice el IDE de Arduino para programar su dispositivo. Puede descargar el último IDE de Arduino here.

1) Agregue el paquete de placa ESP8266:

a. En Archivo > Preferencias, ingrese https://arduino.esp8266.com/stable/package_esp8266com_index.json en URL adicionales del Administrador de tableros.

b. Seleccione Herramientas > Tableros > Administrador de tableros. Ingrese ESP8266 en la barra de búsqueda e instale el paquete.

2) Modificar el tamaño de paquete permitido.

a. Navegue hasta la carpeta con el archivo de encabezado de la subbiblioteca pub, generalmente Documents\Arduino\libraries\PubSubClient\src.

b. Edite PubSubClient.h to c cambie el tamaño máximo del paquete a 4096. Cuando esté completa, la línea debería decir:

#define MQTT_MAX_PACKET_SIZE 4096

3) Crea la aplicación:

a. Abra una nueva ventana en el IDE de Arduino y guarde el archivo.

b. Agregue el código proporcionado en la sección Código.

C. Asegúrese de editar la información de la red inalámbrica y los ID de los canales en el código.

4) Agregue bibliotecas y archivos secretos al boceto:

a. Si aún no están presentes, agregue las siguientes bibliotecas al administrador de bibliotecas seleccionando Sketch ​​> Incluir biblioteca > Administrar bibliotecas. Para cada biblioteca busque su nombre y seleccione Instalar.

  • PubSubClient

  • ESP8266Wifi

  • servo

b. Agregue el archivo mqtt_secrets.h .

Pruebe su dispositivo

Después de cargar exitosamente su programa, puede monitorear la salida usando el monitor serial. Cargue un valor a su canal de control de ThingSpeak en el rango de 0 a 175. Puede copiar el formato de solicitud GET desde la pestaña Claves API o modificar este texto con su clave API de escritura. Ingrese cada URL directamente en la barra de direcciones de su navegador, cambiando SU CLAVE API DE ESCRITURA por la clave API de escritura para su canal.

https://api.thingspeak.com/update?api_key=YOUR_WRITE_API_KEY&field1=ANGLE_VALUE

El dispositivo publica el ángulo y la intensidad de la señal Wi-Fi en el canal de almacenamiento cada vez que publica en el canal de suscripción. Asegúrese de que el valor de su ángulo esté en el rango de 0 a 175.

Código

1) Incluya las bibliotecas requeridas y defina campos de datos:

#include <PubSubClient.h>
#include <WiFiClientSecure.h>                         // Needed only if using secure connection.
#include <ESP8266WiFi.h>
#include <Servo.h> 
#include "mqtt_secrets.h"
#define ANGLE_FIELD 0   
#define DATA_FIELD 1                                  // Data field to post the signal strength to.

2) Definir e inicializar las variables. Asegúrese de editar la información de la red inalámbrica, la identificación del canal y las credenciales. Encuentra el ID de tu canal en la parte superior de la página principal de tu canal.

char ssid[] = "YOUR_SSID";                   // Change to your network SSID (name).
char pass[] = "YOUR_WIFI_PASSWORD";          // Change to your network password.
const char* server = "mqtt3.thingspeak.com";
char mqttUserName[] = SECRET_MQTT_USERNAME;  // Change to your MQTT device username.    
char mqttPass[] = SECRET_MQTT_PASSWORD;      // Change to your MQTT device password.
char clientID[] = SECRET_MQTT_CLIENT_ID;     // Change to your MQTT device clientID.
long readChannelID = 85;
long writeChannelID = 86;

// Here's how to get ThingSpeak server fingerprint: https://www.a2hosting.com/kb/security/ssl/a2-hostings-ssl-certificate-fingerprints
const char* thingspeak_server_fingerprint = "27 18 92 dd a4 26 c3 07 09 b9 7a e6 c5 21 b9 5b 48 f7 16 e1";

// WiFiClient client;                                 // Initialize the Wi-Fi client library. Uncomment for nonsecure connection.
WiFiClientSecure client;                              // Uncomment for secure connection.  
PubSubClient mqttClient( client );                    // Initialize the PuBSubClient library.
Servo myservo;  // Create servo object to control a servo .

int fieldsToPublish[8]={1,1,0,0,0,0,0,0};             // Change to allow multiple fields.
float dataToPublish[8];                               // Holds your field data.
int changeFlag=0;                                     // Let the main loop know there is new data to set.
int servo_pos=0;                                      // Servo position

3) Defina los prototipos de funciones en este código.

//  
// Prototypes
//

// Handle messages from MQTT subscription.
void mqttSubscriptionCallback(char* topic, byte* payload, unsigned int length);  

// Generate a unique client ID and connect to MQTT broker.
void mqttConnect();  

// Subscribe to a field or feed from a ThingSpeak channel.
int mqttSubscribe( long subChannelID,int field, int unSub);

// Publish messages to a channel feed.

// Connect to a given Wi-Fi SSID.
int connectWifi();

// Measure the Wi-Fi signal strength.
void updateRSSIValue();

4) Inicialice los pines de entrada y salida, inicie el monitor serie e inicialice el cliente MQTT en la rutina setup .

void setup() {
Serial.begin( 115200 );
Serial.println( "Start" );
int status = WL_IDLE_STATUS; // Set temporary Wi-Fi status.
       
    connectWifi();                                        // Connect to Wi-Fi network.
    // mqttClient.setServer( server, 1883 );              // Set the MQTT broker details, nonsecure port. Uncomment for nonsecure connection.
    mqttClient.setServer( server, 8883 );                 // Set the MQTT broker details, secure port. Uncomment for secure connection.
    mqttClient.setCallback( mqttSubscriptionCallback );   // Set the MQTT message handler function.
    myservo.attach(14);                                   // Attach the servo on GIO2 to the servo object. 
    myservo.write(90);                                    // Start in the middle.
}

5) Cada vez que se ejecute el bucle principal, verifique si los datos de la suscripción MQTT están disponibles para su procesamiento. Luego configure la posición del servo para que coincida con los datos. Asegúrese de que los clientes inalámbricos y MQTT estén activos y mantengan una conexión con el servidor del cliente.

void loop() {
    
    if (WiFi.status() != WL_CONNECTED) {
        connectWifi();
    }
    
    if (!mqttClient.connected())
    {
       
       mqttConnect(); // Connect if MQTT client is not connected.
        
         if(mqttSubscribe( readChannelID,1,0 )==1 ){
                Serial.println( " Subscribed " );
            }
    }
    
    mqttClient.loop(); // Call the loop to maintain connection to the server.                         

    if ((servo_pos>175)||(servo_pos<0)){
    servo_pos=0;
    }
   
    if (changeFlag){
      
        changeFlag=0;
        myservo.write(servo_pos);
        dataToPublish[ANGLE_FIELD]=servo_pos;
        delay(1100);                       // Wait for ThingSpeak to publish.
        Serial.println( "Servo value " + String( servo_pos ) );
        mqttPublish( writeChannelID, dataToPublish, fieldsToPublish );
    }
    
    delay(1);
}

6) Utilice la función mqttSubscriptionCallback para manejar mensajes MQTT entrantes. El programa se ejecuta mejor si el bucle principal realiza los pasos de procesamiento en lugar de la devolución de llamada. En esta función, utilice banderas para provocar cambios en el bucle principal.

/**
 * Process messages received from subscribed channel via MQTT broker.
 *   topic - Subscription topic for message.
 *   payload - Field to subscribe to. Value 0 means subscribe to all fields.
 *   mesLength - Message length.
 */

void mqttSubscriptionCallback( char* topic, byte* payload, unsigned int mesLength ) {
    
    char p[mesLength + 1];
    memcpy( p, payload, mesLength );
    p[mesLength] = NULL;
    Serial.print( "Answer: " );
    Serial.println( String(p) );
    servo_pos=atoi( p );
    changeFlag=1;
}

7) Utilice la función MQTTConnect para configurar y mantener una conexión al MQTT.

void mqttConnect()
{
    // Loop until connected.
    while ( !mqttClient.connected() )
    {
      Serial.println(String( mqttUserName)+ " , " + mqttPass + " , " + clientID);
   
        // Connect to the MQTT broker.
        Serial.print( "Attempting MQTT connection..." );
        if ( mqttClient.connect( clientID, mqttUserName, mqttPass ) )
        {
            Serial.println( "Connected with Client ID:  " + String( clientID ) + " User "+ String( mqttUserName ) + " Pwd "+String( mqttPass ) );
           
        } else
        {
            Serial.print( "failed, rc = " );
            // See https://pubsubclient.knolleary.net/api.html#state for the failure code explanation.
            Serial.print( mqttClient.state() );
            Serial.println( " Will try again in 5 seconds" );
            delay( 5000 );
        }
    }
}

8) Utilice mqttSubscribe para recibir actualizaciones del campo de control LED. En este ejemplo, te suscribes a un campo, pero también puedes usar esta función para suscribirte a todo el canal. Llame a la función con field = 0 para suscribirse a todo el feed.

/**
 * Subscribe to fields of a channel.
 *   subChannelID - Channel to subscribe to.
 *   field - Field to subscribe to. Value 0 means subscribe to all fields.
 *   readKey - Read API key for the subscribe channel.
 *   unSub - Set to 1 for unsubscribe.
 */
 
int mqttSubscribe( long subChannelID, int field, int unsubSub ){
    String myTopic;
    
    // There is no field zero, so if field 0 is sent to subscribe to, then subscribe to the whole channel feed.
    if (field==0){
        myTopic="channels/"+String( subChannelID )+"/subscribe";
    }
    else{
        myTopic="channels/"+String( subChannelID )+"/subscribe/fields/field"+String( field );
    }
    
    Serial.println( "Subscribing to " +myTopic );
    Serial.println( "State= " + String( mqttClient.state() ) );

    if ( unsubSub==1 ){
        return mqttClient.unsubscribe(myTopic.c_str());
    }
    return mqttClient.subscribe( myTopic.c_str() ,0 );
}

9) La función mqttUnsubscribe no se usa en el código, pero puedes usarla para finalizar una suscripción.

/**
 * Unsubscribe channel
 *   subChannelID - Channel to unsubscribe from.
 *   field - Field to unsubscribe subscribe from. The value 0 means subscribe to all fields.
 *   readKey - Read API key for the subscribe channel.
 */

int mqttUnSubscribe(long subChannelID,int field,char* readKey){
    String myTopic;
    
    if (field==0){
         myTopic="channels/"+String( subChannelID )+"/subscribe";
    }
    else{
        myTopic="channels/"+String( subChannelID )+"/subscribe/fields/field"+String( field );
    }
    return mqttClient.unsubscribe( myTopic.c_str() );   
}

10) Utilice la función mqttPublish para enviar su ángulo y datos RSSI de Wi-Fi a un canal ThingSpeak.

/**
 * Publish to a channel
 *   pubChannelID - Channel to publish to.
 *   pubWriteAPIKey - Write API key for the channel to publish to.
 *   dataArray - Binary array indicating which fields to publish to, starting with field 1.
 *   fieldArray - Array of values to publish, starting with field 1.
 */

void mqttPublish(long pubChannelID, float dataArray[], int fieldArray[]) {
    int index=0;
    String dataString="";
    
    updateRSSIValue();  // Make sure the stored value is updated.
    
    // 
    while (index<8){
        
        // Look at the field array to build the posting string to send to ThingSpeak.
        if (fieldArray[ index ]>0){
          
            dataString+="&field" + String( index+1 ) + "="+String( dataArray [ index ] );
        }
        index++;
    }
    
    Serial.println( dataString );
    
    // Create a topic string and publish data to ThingSpeak channel feed.
     String topicString ="channels/" + String( pubChannelID ) + "/publish";
    mqttClient.publish( topicString.c_str(), dataString.c_str() );
    Serial.println( "Published to channel " + String( pubChannelID ) );
}

11) Conecte su dispositivo a una red inalámbrica usando la función connectWiFi .

int connectWifi()
{
    while ( WiFi.status() != WL_CONNECTED ) {
        WiFi.begin( ssid, pass );
        delay( 8500 );
        Serial.println( "Connecting to Wi-Fi" ); 
    }
    Serial.println( "Connected" );
    client.setFingerprint(thingspeak_server_fingerprint);  // Comment this line if using nonsecure connection.
}

12) Utilice la función updateRSSIValue para leer la intensidad de la señal de la red a la que está conectado actualmente.

void updateRSSIValue(){

   long rssi = WiFi.RSSI();  
   Serial.print( "RSSI:" );
   Serial.println(rssi);
   dataToPublish[ DATA_FIELD ]=float( rssi );

}

Consulte también

|

Temas relacionados