Eu tenho me divertido bastante fazendo coisas para Internet of Things (IoT). Hoje, eu quero usar o protocolo MQTT para fazer a comunicação entre diferentes dispositivos. Primeiro, eu criei um broker mqtt no meu laptop. Para testar, eu vou usar o servidor mosquitto. Na produção, podemos usar RabbitMQ ou mesmo um servidor de terceiros, como iot.eclipse.org ou mesmo o serviço de IoT da Amazon.
A ideia é emitir um valor com um dispositivo e ouvir esse valor com o resto dos dispositivos, e executar uma ação dependendo desse valor. Por exemplo, vou usar um potenciômetro conectado ao microcontrolador NodeMcu.
Esse controlador se conectará ao broker mqtt e emitirá o valor do potenciômetro (lendo a entrada analógica) em um tópico (chamado “potenciômetro”). Podemos programar nosso NodeMcu com Lua, mas fico mais confortável com C++ e Arduino IDE. Primeiro, eu preciso me conectar à minha rede Wi-fi, depois me conectar ao broker e começar a emitir os valores do potenciômetro.
#include <PubSubClient.h> #include <ESP8266WiFi.h> // Wifi configuration const char* ssid = "MY_WIFI_SSID"; const char* password = "my_wifi_password"; // mqtt configuration const char* server = "192.168.1.104"; const char* topic = "potentiometer"; const char* clientName = "com.gonzalo123.nodemcu"; int value; int percent; String payload; WiFiClient wifiClient; PubSubClient client(wifiClient); void wifiConnect() { Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("WiFi connected."); Serial.print("IP address: "); Serial.println(WiFi.localIP()); if (client.connect(clientName)) { Serial.print("Connected to MQTT broker at "); Serial.print(server); Serial.print(" as "); Serial.println(clientName); Serial.print("Topic is: "); Serial.println(topic); } else { Serial.println("MQTT connect failed"); Serial.println("Will reset and try again..."); abort(); } } void mqttReConnect() { while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Attempt to connect if (client.connect(clientName)) { Serial.println("connected"); client.subscribe(topic); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); delay(5000); } } } void setup() { Serial.begin(9600); client.setServer(server, 1883); wifiConnect(); delay(10); } void loop() { value = analogRead(A0); percent = (int) ((value * 100) / 1010); payload = (String) percent; if (client.connected()) { if (client.publish(topic, (char*) payload.c_str())) { Serial.print("Publish ok ("); Serial.print(payload); Serial.println(")"); } else { Serial.println("Publish failed"); } } else { mqttReConnect(); } delay(200); }
Agora, vamos usar outro Arduíno (com um escudo ethernet).
Vamos mover um servomotor de acordo com o valor do potenciômetro NodeMcu. Esse Arduino só precisa fazer um listen do tópico do MQTT e mover o servo.
#include <SPI.h> #include <Servo.h> #include <Ethernet.h> #include <PubSubClient.h> #define SERVO_CONTROL 9 byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; Servo servo; EthernetClient ethClient; // mqtt configuration const char* server = "192.168.1.104"; const char* topic = "potentiometer"; const char* clientName = "com.gonzalo123.arduino"; PubSubClient client(ethClient); void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] angle:"); String data; for (int i = 0; i < length; i++) { data += (char)payload[i]; } double angle = ((data.toInt() * 180) / 100); constrain(angle, 0, 180); servo.write((int) angle); Serial.println((int) angle); } void mqttReConnect() { while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Attempt to connect if (client.connect(clientName)) { Serial.println("connected"); client.subscribe(topic); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); delay(5000); } } } void setup() { Serial.begin(9600); client.setServer(server, 1883); client.setCallback(callback); servo.attach(SERVO_CONTROL); if (Ethernet.begin(mac) == 0) { Serial.println("Failed to configure Ethernet using DHCP"); } delay(1500); // Allow the hardware to sort itself out } void loop() { if (!client.connected()) { mqttReConnect(); } client.loop(); }
Finalmente, usaremos um Raspberry Pi com um Sense Hat e exibiremos com sua matriz de led diferentes cores e pontos, dependendo do valor do NodeMcu. Da mesma forma que o script Arduino, aqui só precisamos fazer um listen do tópico do broker e executar as ações com o Sense Hat. Agora com Python:
import paho.mqtt.client as mqtt from sense_hat import SenseHat sense = SenseHat() sense.clear() mqttServer = "192.168.1.104" red = [255, 0, 0] green = [0, 255, 0] yellow = [255, 255, 0] black = [0, 0, 0] def on_connect(client, userdata, rc): print("Connected!") client.subscribe("potentiometer") def on_message(client, userdata, msg): value = (64 * int(msg.payload)) / 100 O = black if value < 21: X = red elif value < 42: X = yellow else: X = green sense.set_pixels(([X] * value) + ([O] * (64 - value))) client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message client.connect(mqttServer, 1883, 60) client.loop_forever()
O hardware:
- 1 Arduino Uno
- 1 NodeMCU (V3)
- 1 potenciômetro
- 1 Servo (SG90)
- 1 Raspberry Pi 3 (com um Sense Hat)
O código-fonte está disponível no meu GitHub.
***
Gonzalo Ayuso faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela Redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: https://gonzalo123.com/2017/06/26/playing-with-raspberry-pi-arduino-nodemcu-and-mqtt/