Main Content

Cette page a été traduite par traduction automatique. Cliquez ici pour voir la dernière version en anglais.

Contrôle à distance du capteur à l'aide de la publication et de l'abonnement MQTT sécurisés

Cet exemple montre comment utiliser l'architecture de publication et d'abonnement MQTT dans ThingSpeak. Le protocole MQTT est un système de messagerie de appareil à faible surcharge. A l'aide de MQTT, abonnez-vous au champ 1 d'un canal de contrôle . Lorsque vous mettez à jour le canal de contrôle, la valeur affichée est envoyée à votre appareil. Le servo tourne à l'angle spécifié. L' appareil mesure la force du réseau et met à jour le canal de stockage. Les commentaires dans le code indiquent comment adapter cet exemple pour une connexion non sécurisée.

Matériel pris en charge

  • ESP8266, NodeMCU, WeMOS

  • Arduino MKR1000

  • Arduino Uno, Mega, Due ou Leonardo avec connexion réseau sans fil

  • Particule Photon (avec de légers ajustements de code et de schéma)

L'exemple est conçu pour fonctionner avec seulement quelques composants supplémentaires, à savoir un seul servomoteur. Vous utilisez l'antenne Wi-Fi intégrée pour effectuer des mesures de puissance Wi-Fi.

Ces images montrent un exemple de sortie de canal du canal de stockage. Le champ 1 stocke l'angle du servomoteur défini à partir du canal de commande et le champ 2 affiche la valeur de puissance Wi-Fi mesurée.

L'analyse des données montre que l'orientation du hardware WeMOS a un effet directionnel sur la force du signal mesuré.

"Conditions préalables"

1) Créez un canal ThingSpeak pour le contrôle d'abonnement, comme indiqué dans Collect Data in a New Channel. Le canal d'abonnement contient l'angle pour le servomoteur. Lorsque l'angle du servomoteur est mis à jour, l' appareil abonné reçoit l'angle sous la forme d'un message MQTT. L' appareil définit l'angle d'asservissement et mesure la nouvelle force du réseau sans fil à cet angle.

2) Créez un autre canal ThingSpeak pour les données publiées. Le canal de publication enregistre l'angle défini et les données d'intensité du signal.

3) Dans la vue Paramètres du canal  , activez les champs 1 et 2 pour le canal de publication. Pour distinguer les champs, donnez à chaque champ un nom descriptif.

4) Notez les clés API de lecture et d'écriture sur l'onglet Clés API dans la vue Paramètres du canal (encerclées dans l'image).

5) Créez un MQTT device en cliquant sur Appareils > MQTT en haut de la page, puis Ajouter un nouvel appareil. Lorsque vous configurez l' appareil, autorisez les deux canaux pour la publication et l'abonnement. Pour plus de détails, voir Créer un appareil ThingSpeak MQTT.

6) Lors de l'ajout du nouveau appareil, cliquez sur Télécharger les informations d'identification > Arduino (mqtt_secrets.h) . Conservez ce fichier de secrets téléchargé pour y accéder dans la section Code ci-dessous.

 Matériel requis 

  • WeMOS D1 Mini, ou l'un des appareils suivants avec des modifications des bibliothèques utilisées : NodeMCU, ESP8266-01, ESP8266-04, ESP8266-12, ESP8266-12E, Arduino® MKR1000 ou autre Arduino avec connexion Ethernet ou réseau sans fil

  • Servomoteur (par exemple, Futaba S3003)

  • Fils de liaison (au moins 3)

  • cable USB

 Schéma et connexions 

1) Connectez D5 sur le WeMOS D1 Mini la ligne de signal du servo.

2) Connectez le fil de terre du servo à la terre sur la carte WeMOS.

3) Connectez l'alimentation servo à 3,3 V. L'utilisation directe de 5 V peut surcharger la limite de puissance USB dans certains cas.

Programmez votre Arduino

Utilisez l'IDE Arduino pour programmer votre appareil. Vous pouvez télécharger le dernier Arduino IDE here.

1) Ajoutez le package de carte ESP8266 :

un. Sous Fichier > Préférences , entrez https://arduino.esp8266.com/stable/package_esp8266com_index.json dans URL supplémentaires du gestionnaire de cartes .

b. Sélectionnez Outils > Tableaux > Gestionnaire de tableaux . Saisissez ESP8266 dans la barre de recherche et installez le package.

2) Modifiez la taille de paquet autorisée.

un. Accédez au dossier contenant le fichier d'en-tête de la sous-bibliothèque pub, généralement Documents\Arduino\libraries\PubSubClient\src.

b. Modifiez PubSubClient.h to cchangez la taille maximale du paquet à 4096. Une fois terminé, la ligne doit indiquer :

#define MQTT_MAX_PACKET_SIZE 4096

3) Créez l'application :

un. Ouvrez une nouvelle fenêtre dans l'IDE Arduino et enregistrez le fichier.

b. Ajoutez le code fourni dans la section Code.

c. Assurez-vous de modifier les informations sur le réseau sans fil et les ID de canal dans le code.

4) Ajouter des bibliothèques et un fichier de secrets à la figure:

un. Si ce n'est pas déjà fait, ajoutez les bibliothèques suivantes au gestionnaire de bibliothèques en sélectionnant Sketch > Inclure la bibliothèque > Gérer les bibliothèques . Pour chaque bibliothèque, recherchez son nom et sélectionnez  Installer .

  • PubSubClient

  • ESP8266Wifi

  • servo

b. Ajoutez le fichier mqtt_secrets.h.

Testez votre appareil

Une fois que vous avez réussi à télécharger votre programme, vous pouvez surveiller la sortie à l'aide du moniteur série. Chargez une valeur sur votre canal de contrôle ThingSpeak dans la plage de 0 à 175. Vous pouvez copier le format de requête GET depuis l'onglet Clés API ou modifier ce texte avec votre clé d'API en écriture. Saisissez chaque URL directement dans la barre d'adresse de votre navigateur, en remplaçant VOTRE CLÉ API D'ÉCRITURE par la clé d'API en écriture de votre canal.

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

L' appareil publie l'angle et la puissance du signal Wi-Fi sur le canal de stockage chaque fois que vous publiez sur le canal d'abonnement . Assurez-vous que la valeur de votre angle est comprise entre 0 et 175.

Code

1) Incluez les bibliothèques requises et définissez les champs de données :

#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) Définir et initialiser les variables. Assurez-vous de modifier les informations sur le réseau sans fil, l'ID de canal et les informations d'identification. Recherchez l'identifiant de votre canal en haut de la page principale de votre 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) Définir les prototypes de fonction dans ce code.

//  
// 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) Initialisez les broches d'entrée et de sortie, démarrez le moniteur série et initialisez le client MQTT dans la routine 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) Chaque fois que la boucle principale s'exécute, vérifiez si les données de l'abonnement MQTT sont disponibles pour le traitement. Réglez ensuite la position du servo pour qu'elle corresponde aux données. Assurez-vous que les clients sans fil et MQTT sont actifs et maintenez une connexion au serveur client.

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) Utilisez la fonction mqttSubscriptionCallback pour gérer les messages MQTT entrants. Le programme s'exécute plus facilement si la boucle principale exécute les étapes de traitement au lieu du rappel. Dans cette fonction, utilisez des drapeaux pour provoquer des changements dans la boucle principale.

/**
 * 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) Utilisez la fonction MQTTConnect pour configurer et maintenir une connexion au 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) Utilisez mqttSubscribe pour recevoir les mises à jour du champ de contrôle des LED. Dans cet exemple, vous vous abonnez à un champ, mais vous pouvez également utiliser cette fonction pour vous abonner à l'ensemble du flux du canal. Appelez la fonction avec field = 0 pour vous abonner à l'intégralité du flux.

/**
 * 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 fonction mqttUnsubscribe n'est pas utilisée dans le code, mais vous pouvez l'utiliser pour mettre fin à un abonnement.

/**
 * 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) Utilisez la fonction mqttPublish pour envoyer vos données d'angle et Wi-Fi RSSI à 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) Connectez votre appareil à un réseau sans fil à l'aide de la fonction 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) Utilisez la fonction updateRSSIValue pour lire la force du signal du réseau auquel vous êtes actuellement connecté.

void updateRSSIValue(){

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

}

Voir aussi

|

Sujets associés