Arduino: MQTT: mudanças entre as edições

De Wiki Cursos IFPR Foz
Ir para navegaçãoIr para pesquisar
Sem resumo de edição
 
(29 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 1: Linha 1:
=MQTT e Arduino=
=Experimento: MQTT e Arduino=


O suporte para '''MQTT''' para '''Arduíno''' é provido por uma '''biblioteca''' que pode ser obtida em: https://github.com/knolleary/pubsubclient .
O suporte para '''MQTT''' para '''Arduíno''' é provido por uma '''biblioteca''' que pode ser obtida em: https://github.com/knolleary/pubsubclient .
Linha 7: Linha 7:
Para interagir com a '''rede''' é necessário um '''''shild'' Ethernet''' colocado sobre a placa Arduíno.
Para interagir com a '''rede''' é necessário um '''''shild'' Ethernet''' colocado sobre a placa Arduíno.


;Limitações do MQTT para Arduíno:
==Descrição do experimento==
*Suporta somente publicações com QoS=0 e subscrições com QoS=0 ou QoS=1.
*Suporta somente ''CleanSessions'' devido a limitação de memória.
*Tamanho máximo de mensagem com 128 bytes por ''default''.
*Intervalo de ''keep alive'' de 15 s por ''default''.
*:Os dois últimos parâmetros podem ser alterados na biblioteca PubSubClient.h:
*:MQTT_MAX_PACKET_SIZE
*:MQTT_KEEPALIVE


;Hardware compatível:
Neste experimento foi utilizado um '''Arduino UNO''' com um '''''Shield'' Ethernet''', rodando a '''biblioteca PubSubClient.h''' para interagir um com '''brocker Mosquitto''' e '''clientes publicadores''' e '''subscritores''' através do '''protocolo MQTT'''.
*''Shield'' Ethernet
*Arduíno Ethernet
*Arduíno Yun
*Arduíno Wifi
*ESP8266
*ESP32


==Experimento: MQTT e Arduino==
A comunicação foi realizada através de uma '''rede local''' residencial e foram utilizados os seguintes '''endereços IP''':
*brocker '''Mosquito''': 192.168.1.19/24
*'''Arduino''': 192.168.1.50/24
*Clientes ('''mosquitto_pub''' e '''mosquitto_sub'''): 192.168.1.19/24


Neste experimento foi utilizado um '''Arduino Leonardo''' com um '''''Shield'' Ethernet''', rodando a '''biblioteca PubSubClient.h''' para interagir um com '''brocker Mosquitto''' e '''clientes publicadores''' e '''subscritores''' através do '''protocolo MQTT'''.
===Código fonte Arduino===
 
A comunicação foi realizada através de uma '''rede local''' residencial e foram utilizados os seguintes '''endereços IP''':
*brocker '''Mosquito''': 192.168.0.13/24
*'''Arduino''': 192.168.0.30/24
*Clientes ('''mosquitto_pub''' e '''mosquitto_sub'''): 192.168.0.21/24


O '''código''' Arduino abaixo descreve o cenário da aplicação e ilustra o uso das funções da '''biblioteca PubSubClient.h''' para implementar a comunicação MQTT.
O '''código''' Arduino abaixo descreve o cenário da aplicação e ilustra o uso das funções da '''biblioteca PubSubClient.h''' para implementar a comunicação MQTT.
Linha 43: Linha 28:


  Este sketch demonstra a comunicação de um Arduino com um brocker Mosquitto usando MQTT:
  Este sketch demonstra a comunicação de um Arduino com um brocker Mosquitto usando MQTT:
   - conecta ao brocker e informa lastWill para o tópico "status" com mensagem "off-line"
   - conecta ao brocker e informa lastWill para o tópico "arduino/status" com mensagem "off-line"
     (será publicada caso o Arduino seja desconectado involuntariamente);
     (será publicada caso o Arduino seja desconectado involuntariamente);
   - publica para o tópico "status" a mensagem  "on-line" anunciando que está ativo;
   - publica para o tópico "arduino/status" a mensagem  "on-line" anunciando que está ativo;
   - subscreve o tópico "led" para receber comandos para um led;
   - subscreve o tópico "arduino/led" para receber comandos para um led;
   - caso receba mensagem para o tópico "led", aciona o led conforme comando recebido
   - caso receba mensagem para o tópico "arduino/led", aciona o led conforme comando recebido.
    e publica para o tópico "ledStatus" o estado do led após o comando.
*/
*/


Linha 57: Linha 41:
// Endereçamento IP utilizado para o cliente e servidor
// Endereçamento IP utilizado para o cliente e servidor
byte mac[]    = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
byte mac[]    = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 30);
IPAddress ip(192, 168, 1, 50);
IPAddress server(192, 168, 0, 13);
IPAddress server(192, 168, 1, 19);


EthernetClient ethClient;
EthernetClient ethClient;
Linha 72: Linha 56:
   }
   }
   Serial.println();
   Serial.println();
   //comanda o "led" e publica "status"
   //comanda o LED
   if (length == 2 and !strncmp((char*)payload, "on", length)) {
   if ((char)payload[0] == '1') {
      digitalWrite(LED_BUILTIN, HIGH);
    digitalWrite(4, HIGH);
      client.publish("status", "ON_LINE: led ON");
   } else if ((char)payload[0] == '0') {
   } else if (length == 3 and !strncmp((char*)payload, "off", length)) {
    digitalWrite(4, LOW);
      digitalWrite(LED_BUILTIN, LOW);
   }  
      client.publish("status", "ON_LINE: led OFF");
  } else {
      client.publish("status", "ON_LINE: led UNCHANGED");
   }
}
}


Linha 87: Linha 67:
{
{
   Serial.begin(57600);
   Serial.begin(57600);
  pinMode(4, OUTPUT);


   client.setServer(server, 1883);
   client.setServer(server, 1883);
Linha 105: Linha 87:
     //Mensagem lastWill
     //Mensagem lastWill
     byte willQoS = 0;
     byte willQoS = 0;
     const char* willTopic = "status";
     const char* willTopic = "arduino/status";
     const char* willMessage = "OFF_LINE";
     const char* willMessage = "OFF_LINE";
     boolean willRetain = true;
     boolean willRetain = true;
Linha 115: Linha 97:
       int length = strlen(message);
       int length = strlen(message);
       boolean retained = true; //Retain message
       boolean retained = true; //Retain message
       client.publish("status", (byte*)message, length, retained);
       client.publish("arduino/status", (byte*)message, length, retained);
       // ... and resubscribe
       // ... and resubscribe
       client.subscribe("led");
       client.subscribe("arduino/led");
     } else {
     } else {
       Serial.print("failed, rc=");
       Serial.print("failed, rc=");
Linha 128: Linha 110:
   //e aguardar recebimento de mensagens
   //e aguardar recebimento de mensagens
   client.loop();
   client.loop();
}
}      
 
</syntaxhighlight>
</syntaxhighlight>


===Análise da troca de mensagens com Wireshark===
==Comandos nos terminais clientes MQTT==
 
;Cliente Subscritor:
mosquitto_sub -h 192.168.1.19 -t arduino/status
 
;Cliente Publicador:
mosquitto_pub -h 192.168.1.19 -t arduino/led -m 1
mosquitto_pub -h 192.168.1.19 -t arduino/led -m 0
 
==Análise da troca de mensagens com Wireshark==
 
A comunicação foi realizada através de uma '''rede local''' residencial e foram utilizados os seguintes '''endereços IP''':
*Brocker '''Mosquito''': 192.168.0.13/24
*'''Arduino''': 192.168.0.30/24
*Clientes ('''mosquitto_pub''' e '''mosquitto_sub'''): 192.168.0.18/24


[[Arquivo:brockerMQTT&Arduino.png]]
[[Arquivo:brockerMQTT&Arduino.png]]
Linha 144: Linha 141:
;Observação: As '''mensagens em preto''', com indicação de ''TCP ACKED unseen segment'', como indicado em <ref>https://osqa-ask.wireshark.org/questions/46134/tcp-acked-unseen-segment</ref>, "se referem a pacotes que foram transferidos e reconhecidos, mas que não foram capturados pelo Wireshark. Usualmente isto acontece quando o dispositivo não é rápido o suficiente". O que pede ser o caso do Arduino.
;Observação: As '''mensagens em preto''', com indicação de ''TCP ACKED unseen segment'', como indicado em <ref>https://osqa-ask.wireshark.org/questions/46134/tcp-acked-unseen-segment</ref>, "se referem a pacotes que foram transferidos e reconhecidos, mas que não foram capturados pelo Wireshark. Usualmente isto acontece quando o dispositivo não é rápido o suficiente". O que pede ser o caso do Arduino.


=MQTT e ESP8266=
<!--==Interação com Node-RED==
 
O suporte para '''MQTT''' para o '''ESP8266''' é provido por uma '''biblioteca''' que pode ser obtida em: https://github.com/knolleary/pubsubclient .
 
Neste experimento foi utilizado um '''NodeMCU 8266''' utilizando a '''biblioteca PubSubClient.h''' para interagir um com '''brocker Mosquitto''' e '''clientes publicadores''' e '''subscritores''' através do '''protocolo MQTT'''.
 
A comunicação foi realizada através de uma '''rede local''' residencial e foram utilizados os seguintes '''endereços IP''':
*brocker '''Mosquito''': 192.168.0.14/24
*'''Arduino''': 192.168.0.20/24
*Clientes ('''mosquitto_pub''' e '''mosquitto_sub'''): 192.168.0.14/24
 
O '''código''' abaixo é baseado no exemplo '''mqtt_esp8266''' da '''biblioteca PubSubClient.h''':
 
<syntaxhighlight lang="c">
 
/*
Basic ESP8266 MQTT example
This sketch demonstrates the capabilities of the pubsub library in combination
with the ESP8266 board/library.
It connects to an MQTT server then:
  - publishes "hello world" to the topic "outTopic" every two seconds
  - subscribes to the topic "inTopic", printing out any messages
    it receives. NB - it assumes the received payloads are strings not binary
  - If the first character of the topic "" is an 1, switch ON the ESP Led,
    else switch it off
It will reconnect to the server if the connection is lost using a blocking
reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
achieve the same result without blocking the main loop.
To install the ESP8266 board, (using Arduino 1.6.4+):
  - Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs":
      http://arduino.esp8266.com/stable/package_esp8266com_index.json
  - Open the "Tools -> Board -> Board Manager" and click install for the ESP8266"
  - Select your ESP8266 in "Tools -> Board"
*/
 
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
 
// Update these with values suitable for your network.
 
const char* ssid = "BAMBUZAL 2.4G";
const char* password = "aaaaabbbbb";
const char* mqtt_server = "192.168.0.14"; //"broker.mqtt-dashboard.com";
 
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;
 
void setup_wifi() {
 
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
 
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
 
  randomSeed(micros());
 
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}
 
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();


  // Switch on the LED if an 1 was received as first character
O mesmo exemplo pode ser utilizado para interação com '''[[Node-RED#Interação_do_Node_RED_e_ESP8266_via_brocker_Moquitto|Interação do Node_RED e ESP8266 via brocker Moquitto]] ''' utilizando o broker '''Mosquitto''' para intermediar a comunicação.-->
  if ((char)payload[0] == '1') {
==Projeto: Arduíno e MQTT==
    digitalWrite(BUILTIN_LED, LOW);  // Turn the LED on (Note that LOW is the voltage level
Construir um projeto utilizando dois '''Arduínos''' e comunicação utilizando o '''protocolo MQTT'''. Um dos Arduínos deve '''monitorar sensores''' (temperatura, luminosidade ou outros) e '''publicar''' periodicamente os dados lidos em um '''broker MQTT'''. O outro Arduío deve '''subscrever tópicos''' no '''broker''' e, a partir dos tópicos subscritos, '''comandar dispositivos''', como relés, leds ou motores.
    // but actually the LED is on; this is because
    // it is active low on the ESP-01)
  } else {
    digitalWrite(BUILTIN_LED, HIGH);  // Turn the LED off by making the voltage HIGH
  }
 
}
 
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("outTopic", "hello world");
      // ... and resubscribe
      client.subscribe("inTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}
 
void setup() {
  pinMode(BUILTIN_LED, OUTPUT);    // Initialize the BUILTIN_LED pin as an output
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}
 
void loop() {
 
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
 
  unsigned long now = millis();
  if (now - lastMsg > 2000) {
    lastMsg = now;
    ++value;
    snprintf (msg, MSG_BUFFER_SIZE, "hello world #%ld", value);
    Serial.print("Publish message: ");
    Serial.println(msg);
    client.publish("outTopic", msg);
  }
}
</syntaxhighlight>


==Referências==
==Referências==
Linha 295: Linha 152:
[[Categoria:IoT]]
[[Categoria:IoT]]
[[Categoria:Arduíno]]
[[Categoria:Arduíno]]
 
----
[[Usuário:Evandro.cantu|Evandro.cantu]] ([[Usuário Discussão:Evandro.cantu|discussão]]) 10h27min de 16 de abril de 2020 (-03)
[[Usuário:Evandro.cantu|Evandro.cantu]] ([[Usuário Discussão:Evandro.cantu|discussão]]) 17h21min de 27 de junho de 2023 (-03)

Edição atual tal como às 20h22min de 27 de junho de 2023

Experimento: MQTT e Arduino

O suporte para MQTT para Arduíno é provido por uma biblioteca que pode ser obtida em: https://github.com/knolleary/pubsubclient .

Uma boa descrição do uso da biblioteca PubSubClient.h pode ser encontrada em: [1]

Para interagir com a rede é necessário um shild Ethernet colocado sobre a placa Arduíno.

Descrição do experimento

Neste experimento foi utilizado um Arduino UNO com um Shield Ethernet, rodando a biblioteca PubSubClient.h para interagir um com brocker Mosquitto e clientes publicadores e subscritores através do protocolo MQTT.

A comunicação foi realizada através de uma rede local residencial e foram utilizados os seguintes endereços IP:

  • brocker Mosquito: 192.168.1.19/24
  • Arduino: 192.168.1.50/24
  • Clientes (mosquitto_pub e mosquitto_sub): 192.168.1.19/24

Código fonte Arduino

O código Arduino abaixo descreve o cenário da aplicação e ilustra o uso das funções da biblioteca PubSubClient.h para implementar a comunicação MQTT.

/*            
 Baseado no exemplo da bilbioteca PubSubClient.h: Basic MQTT example

 Exemplo: MQTT com Arduíno/Shield Ethernet e Mosquitto: 
 Anunciar status do Arduino, receber comando para led e publicar status do led.

 Este sketch demonstra a comunicação de um Arduino com um brocker Mosquitto usando MQTT:
  - conecta ao brocker e informa lastWill para o tópico "arduino/status" com mensagem "off-line"
    (será publicada caso o Arduino seja desconectado involuntariamente);
  - publica para o tópico "arduino/status" a mensagem  "on-line" anunciando que está ativo;
  - subscreve o tópico "arduino/led" para receber comandos para um led;
  - caso receba mensagem para o tópico "arduino/led", aciona o led conforme comando recebido.
*/

#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>

// Endereçamento IP utilizado para o cliente e servidor
byte mac[]    = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(192, 168, 1, 50);
IPAddress server(192, 168, 1, 19);

EthernetClient ethClient;
PubSubClient client(ethClient);

//Função callback chamada quando uma mensagem for recebida para subscrições:
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();
  //comanda o LED
  if ((char)payload[0] == '1') {
    digitalWrite(4, HIGH);
  } else if  ((char)payload[0] == '0') {
    digitalWrite(4, LOW);
  } 
}

void setup()
{
  Serial.begin(57600);

  pinMode(4, OUTPUT);

  client.setServer(server, 1883);
  client.setCallback(callback);

  Ethernet.begin(mac, ip);
  delay(5000); // Allow the hardware to sort itself out
  
  delay(10000);
}

void loop(){
  // Aguarda conexão    
  while (!client.connected()) {

    Serial.print("Attempting MQTT connection...");

    //Mensagem lastWill
    byte willQoS = 0;
    const char* willTopic = "arduino/status";
    const char* willMessage = "OFF_LINE";
    boolean willRetain = true;
    //Conexão
    if (client.connect("arduinoClient", willTopic, willQoS, willRetain, willMessage)) {
      Serial.println("connected");
      //Uma vez conectado publica status
      char* message = "ON_LINE";
      int length = strlen(message);
      boolean retained = true; //Retain message
      client.publish("arduino/status", (byte*)message, length, retained);
      // ... and resubscribe
      client.subscribe("arduino/led");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
  //Uma vez conectado client.loop() deve ser chamada periodicamente para manter conexão
  //e aguardar recebimento de mensagens
  client.loop();
}

Comandos nos terminais clientes MQTT

Cliente Subscritor
mosquitto_sub -h 192.168.1.19 -t arduino/status
Cliente Publicador
mosquitto_pub -h 192.168.1.19 -t arduino/led -m 1
mosquitto_pub -h 192.168.1.19 -t arduino/led -m 0

Análise da troca de mensagens com Wireshark

A comunicação foi realizada através de uma rede local residencial e foram utilizados os seguintes endereços IP:

  • Brocker Mosquito: 192.168.0.13/24
  • Arduino: 192.168.0.30/24
  • Clientes (mosquitto_pub e mosquitto_sub): 192.168.0.18/24

Análise das mensagens trocadas
  • Na marca de tempo 5.6... um cliente se conectou ao brocker e subscreveu o tópico "status".
  • Na marca de tempo 36.3... o Arduíno se conectou ao brocker e informou tópico/mensagem lastWill ("status = OFF_LINE"), publicou o tópico "status = ON_LINE" e subscreveu o tópico "led". O brocker também publicou o tópico "status" para o cliente.
  • Na marca de tempo 42.6... outro cliente se conectou ao brocker e publicou o tópico "led = ON". O brocker também publicou o tópico "led = ON" ao Arduino (que acionou um led) e publicou ao cliente o tópico "status = ON_LINE: led ON"
  • Em seguida o Arduíno foi desligado.
  • Na marca de tempo 65.6..., como o brocker não recebeu do Arduíno um PINGREC, ele supos que o Arduino foi desconectado involuntariamente e publicou ao cliente o tópico "status = OFF_LINE".
Observação
As mensagens em preto, com indicação de TCP ACKED unseen segment, como indicado em [2], "se referem a pacotes que foram transferidos e reconhecidos, mas que não foram capturados pelo Wireshark. Usualmente isto acontece quando o dispositivo não é rápido o suficiente". O que pede ser o caso do Arduino.

Projeto: Arduíno e MQTT

Construir um projeto utilizando dois Arduínos e comunicação utilizando o protocolo MQTT. Um dos Arduínos deve monitorar sensores (temperatura, luminosidade ou outros) e publicar periodicamente os dados lidos em um broker MQTT. O outro Arduío deve subscrever tópicos no broker e, a partir dos tópicos subscritos, comandar dispositivos, como relés, leds ou motores.

Referências


Evandro.cantu (discussão) 17h21min de 27 de junho de 2023 (-03)