
Voltando para casa de madrugada seria ótimo saber como está o clima – com a patroa, ou talvez você queira saber como está a atmosfera no trabalho.
E se tais informações pudessem ser obtidas de graça, na faixa, no vasco ? Você está bem próximo disso, basta seguir os passos :
Sensor -> ESP32 -> Servidor SSL -> Broker (MQTTS – mosquito) -> Dashboard (node-red) -> Você
Para tanto você precisará:
- BME680 Sensor(es) – Um sensor de temperatura, umidade, pressão e gás (VOC).
- ESP32 SoC – Um sistema-em-um-chip com microcontrolador integrado, Wi-Fi e Bluetooth.
- Servidor gratuito na nuvem – ou um computador antigo, ou raspberry PI ou …
Uma visão geral
Sensor BME-680

O BME680 é um sensor de gás que integra sensores de gás, pressão, umidade e temperatura. Ele vem de fábrica com 2 endereços 0x76 e 0x77, permitindo pendurar dois em cada saída I2C. Com o custo de R$70 (em 2023) vale a pena experimentar o BMP280 por R$10, mas que só oferece pressão e temperatura.
ESP-32

O ESP32 é uma série de microcontroladores de baixo custo e de baixo consumo de energia. É chamado de um sistema-em-um-chip com microcontrolador integrado, Wi-Fi e Bluetooth.
O ESP32-S3-WROOM-1 custa (em 2023) ca. de R$80,00 , mas existem modelos mais baratos. Qualquer SoC com WI-Fi deve funcionar , até mesmo um Arduino com uma expansão (shield) Wi-Fi
O servidor
A maioria das pessoas usa o raspberry PI como solução de automação, mas é muito caro. Desde 2019 qualquer pessoa (estudante, curioso ou empresário) pode criar e manter sua infraestrutura computacional na nuvem pública da Oracle sem pagar nenhum centavo por isto.
“TUDO ABSOLUTAMENTE DE GRAÇA! NO VASCO! FREE ou ALWAYS FREE!”
Você terá que fornecer:
- Um endereço de e-mail válido.
- Um número de celular válido.
- Um número de cartão de crédito válido.
Como cartão de crédito usei um virtual com um limite baixo, mas nunca me cobraram nada. O login exige instalação de um aplicativo para autenticação em 2 etapas.
- O “Always Free Services” oferece:
- Duas VMs AMD Compute
- E até 4 instâncias de ARM Ampere A1
Programando
Carregando o ESP32
Existem dezenas de tutoriais de como ligar um sensor no arduino. Possivelmente você terá que dividir a tarefa em etapas: primeiro fazer o esp32 piscar, depois reconhecer o sensor e enviar para a serial do PC, depois se conectar a uma rede Wi-Fi e só então enviar mensagens MQTT. Para testar o código utilize um broker (MQTT) para testes, algo como o Mosquitto.
/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-mqtt-publish-bme680-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
#include <WiFi.h>
extern "C" {
#include "freertos/FreeRTOS.h"
#include "freertos/timers.h"
}
#include <AsyncMqttClient.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"
#define WIFI_SSID "REPLACE_WITH_YOUR_SSID"
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD"
// Raspberry Pi Mosquitto MQTT Broker
#define MQTT_HOST IPAddress(192, 168, 1, XXX)
// For a cloud MQTT broker, type the domain name
//#define MQTT_HOST "example.com"
#define MQTT_PORT 1883
// Temperature MQTT Topics
#define MQTT_PUB_TEMP "esp/bme680/temperature"
#define MQTT_PUB_HUM "esp/bme680/humidity"
#define MQTT_PUB_PRES "esp/bme680/pressure"
#define MQTT_PUB_GAS "esp/bme680/gas"
/*#define BME_SCK 14
#define BME_MISO 12
#define BME_MOSI 13
#define BME_CS 15*/
Adafruit_BME680 bme; // I2C
//Adafruit_BME680 bme(BME_CS); // hardware SPI
//Adafruit_BME680 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK);
// Variables to hold sensor readings
float temperature;
float humidity;
float pressure;
float gasResistance;
AsyncMqttClient mqttClient;
TimerHandle_t mqttReconnectTimer;
TimerHandle_t wifiReconnectTimer;
unsigned long previousMillis = 0; // Stores last time temperature was published
const long interval = 10000; // Interval at which to publish sensor readings
void getBME680Readings(){
// Tell BME680 to begin measurement.
unsigned long endTime = bme.beginReading();
if (endTime == 0) {
Serial.println(F("Failed to begin reading :("));
return;
}
if (!bme.endReading()) {
Serial.println(F("Failed to complete reading :("));
return;
}
temperature = bme.temperature;
pressure = bme.pressure / 100.0;
humidity = bme.humidity;
gasResistance = bme.gas_resistance / 1000.0;
}
void connectToWifi() {
Serial.println("Connecting to Wi-Fi...");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}
void connectToMqtt() {
Serial.println("Connecting to MQTT...");
mqttClient.connect();
}
void WiFiEvent(WiFiEvent_t event) {
Serial.printf("[WiFi-event] event: %d\n", event);
switch(event) {
case SYSTEM_EVENT_STA_GOT_IP:
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
connectToMqtt();
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
Serial.println("WiFi lost connection");
xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
xTimerStart(wifiReconnectTimer, 0);
break;
}
}
void onMqttConnect(bool sessionPresent) {
Serial.println("Connected to MQTT.");
Serial.print("Session present: ");
Serial.println(sessionPresent);
}
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
Serial.println("Disconnected from MQTT.");
if (WiFi.isConnected()) {
xTimerStart(mqttReconnectTimer, 0);
}
}
/*void onMqttSubscribe(uint16_t packetId, uint8_t qos) {
Serial.println("Subscribe acknowledged.");
Serial.print(" packetId: ");
Serial.println(packetId);
Serial.print(" qos: ");
Serial.println(qos);
}
void onMqttUnsubscribe(uint16_t packetId) {
Serial.println("Unsubscribe acknowledged.");
Serial.print(" packetId: ");
Serial.println(packetId);
}*/
void onMqttPublish(uint16_t packetId) {
Serial.print("Publish acknowledged.");
Serial.print(" packetId: ");
Serial.println(packetId);
}
void setup() {
Serial.begin(115200);
Serial.println();
if (!bme.begin()) {
Serial.println(F("Could not find a valid BME680 sensor, check wiring!"));
while (1);
}
mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
wifiReconnectTimer = xTimerCreate("wifiTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToWifi));
WiFi.onEvent(WiFiEvent);
mqttClient.onConnect(onMqttConnect);
mqttClient.onDisconnect(onMqttDisconnect);
//mqttClient.onSubscribe(onMqttSubscribe);
//mqttClient.onUnsubscribe(onMqttUnsubscribe);
mqttClient.onPublish(onMqttPublish);
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
// If your broker requires authentication (username and password), set them below
//mqttClient.setCredentials("REPlACE_WITH_YOUR_USER", "REPLACE_WITH_YOUR_PASSWORD");
connectToWifi();
// Set up oversampling and filter initialization
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
}
void loop() {
unsigned long currentMillis = millis();
// Every X number of seconds (interval = 10 seconds)
// it publishes a new MQTT message
if (currentMillis - previousMillis >= interval) {
// Save the last time a new reading was published
previousMillis = currentMillis;
getBME680Readings();
Serial.println();
Serial.printf("Temperature = %.2f ºC \n", temperature);
Serial.printf("Humidity = %.2f % \n", humidity);
Serial.printf("Pressure = %.2f hPa \n", pressure);
Serial.printf("Gas Resistance = %.2f KOhm \n", gasResistance);
// Publish an MQTT message on topic esp/bme680/temperature
uint16_t packetIdPub1 = mqttClient.publish(MQTT_PUB_TEMP, 1, true, String(temperature).c_str());
Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", MQTT_PUB_TEMP, packetIdPub1);
Serial.printf("Message: %.2f \n", temperature);
// Publish an MQTT message on topic esp/bme680/humidity
uint16_t packetIdPub2 = mqttClient.publish(MQTT_PUB_HUM, 1, true, String(humidity).c_str());
Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_HUM, packetIdPub2);
Serial.printf("Message: %.2f \n", humidity);
// Publish an MQTT message on topic esp/bme680/pressure
uint16_t packetIdPub3 = mqttClient.publish(MQTT_PUB_PRES, 1, true, String(pressure).c_str());
Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_PRES, packetIdPub3);
Serial.printf("Message: %.2f \n", pressure);
// Publish an MQTT message on topic esp/bme680/gas
uint16_t packetIdPub4 = mqttClient.publish(MQTT_PUB_GAS, 1, true, String(gasResistance).c_str());
Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_GAS, packetIdPub4);
Serial.printf("Message: %.2f \n", gasResistance);
}
}
O projeto Mosquitto tem um broker público. Esta é a configuração mais fácil para testar, mas não há privacidade, pois todas as mensagens são públicas. Use isso apenas para fins de teste. Para usar o broker mosquitto público, configure a integração MQTT para se conectar ao broker test.mosquitto.org na porta 1883 ou 8883.
Servidor
Agora é hora de você criar um servidor na nuvem, ou você pode também instalar o linux em um computador local, o procedimento depois do servidor estar pronto será o mesmo para ambos (cloud ou local).
Estabelecendo Conexão com uma Instância do Linux em um Sistema Windows Usando PuTTY
No caso de um servidor local será mais fácil usar o teclado, mas caso o servidor seja remoto uma conexão ssh é necessária. A melhor ferramenta que conheço para windows é o PuTTY. Para tanto tenha em mãos :
Endereço IP , nome do Usuário. chave privada SSH e permissões SSH e que a porta22 não esta bloqueada.
No Cloud o endereço IP público está incluso, e a chave privada só pode ser baixada na criação da instância ( se não tem, apague e crie a instância novamente). O firewall do Cloud está fechado inicialmente, nem mesmo ping ele responde.
Considere comprar um domínio .com.br, torna tudo mais elegante. No registro.br custa R$40,00 por ano, existem domínios gratuitos também.
Let´s Encrypt
Antes de instalar o mosquitto e o node-red é necessário ter uma camada de segurança SSL. O Let´s Encrypt é uma autoridade certificadora gratuita que certificou 300 milhões de páginas web (no VASCO também).
Para tanto, um domínio é necessário. Caso ainda não possua, é possível prosseguir e usar os endereços IP – locais e públicos.
Abra um terminal ( no windows com Putty) e siga a instalação:
sudo apt-get update && sudo apt-get install certbot
sudo certbot certonly --standalone
Isso levará alguns minutos e deve fazer uma série de perguntas, como endereço de e-mail, nome de domínio, etc (nada complicado) durante o processo.
Se tudo correu bem (como deveria), agora você terá os certificados em algum lugar como:
‘/etc/letsencrypt/live/your.domain.com/’.
Como o Let´s Encrypt foi pensado em total segurança, somente aplicativos com elevação de root (Apache, SQL, …) conseguem ler os arquivos, Para o mosquitto e node-red é necessário permitir a leitura. A pior solução disponível na internet é abrir tudo (chmod 777). Veja que alternativa elegante :
// Create group with root and ubuntu as members
sudo addgroup nodecert
sudo adduser ubuntu nodecert
// sudo adduser mosquitto nodecert
sudo adduser root nodecert
// Make the relevant letsencrypt folders owned by said group.
sudo chgrp -R nodecert /etc/letsencrypt/live
sudo chgrp -R nodecert /etc/letsencrypt/archive
// Allow group to open relevant folders
sudo chmod -R 750 /etc/letsencrypt/live
sudo chmod -R 750 /etc/letsencrypt/archive
Instalando o Mosquitto para mensagens MQTT criptografadas no Cloud
As mensagens MQTT são fundamentais na nuvem. A ideia por trás do texto é lidar com aplicativos industriais de IoT que leem sensores e relatam condições de um edifício, uma linha fabril para um servidor central, para então ser integrado à sistemas de automação predial para controlar a ventilação mecânica ou natural para melhorar o conforto dos usuários.
Neste guia uma estância é criada desde o início, veja que o firewall tem que ser aberto para ao menos a porta 1883 -MQTT – “Add an ingress rule for ports 80, 1883, 8883”. Eu uso apt-get , diferente do guia que instala com snap.
sudo apt-get install mosquitto
//enable user mosquitto to read certificates Let's Encrypt
sudo adduser mosquitto nodecert
Instalado está, mas ainda é necessário alguns ajustes.
Autenticação de usuários também é importante, pois com o servidor aberto para internet qualquer um poderia acessá-lo.
Navegue até o diretório de instalação e crie uma lista de usuários e senhas.
cd /etc/mosquitto/conf.d
sudo nano credencial.txt
e então digite no editor, algo no formato:
usuario1:senha1
user2:pass2
guest:pass
Salve ^O e feche o edito com ^X. Agora temos que criptografar as senhas :
sudo mosquitto_passwd -U credencial.txt
E adicionar na configuração ao broker mosquitto. Eu considero uma má ideia mudar o arquivo original, melhor criar um separado com as mudanças.
sudo nano /etc/mosquitto/conf.d/default.conf
e preencher com as configurações:
listener 1883 0.0.0.0
allow_anonymous false
password_file /etc/mosquitto/conf.d/credencial.txt
listener 8883 0.0.0.0
keyfile /etc/letsencrypt/live/your.domain.com/privkey.pem
certfile /etc/letsencrypt/live/your.domain.com/cert.pem
cafile /etc/letsencrypt/live/your.domain.com/fullchain.pem
Cuidado com espaços em branco, corrompem o arquivo. Agora é hora de rodar o broker.
//verify status
sudo systemctl status mosquitto
sudo systemctl restart mosquitto
Se tudo correu bem, sua instância do Mosquitto agora estará aceitando conexões TLS. Certifique-se de que, ao se conectar, especifique no aplicativo cliente que você está usando TLS e que a porta do servidor é 8883. Para verificar os logs enquanto o Mosquitto está em execução, você pode usar tail para monitorar o log da seguinte forma:
sudo tail -f /var/log/mosquitto/mosquitto.log
Instalando o node-red
Agora tudo deve estar funcionando, mas não é possivel ver nada. As mensagens podem ser publicadas (publish) mas a assinatura tem de ser manual e não é nada divertido. Para automatizar o processo o nnode-red é necessário.
Node-RED é uma ferramenta de programação para conectar dispositivos de hardware, APIs e serviços on-line de maneiras novas e interessantes. Ele fornece um editor baseado em navegador que facilita a conexão de fluxos usando a ampla gama de nós na paleta que podem ser implantados em seu tempo de execução em um único clique.
A instalação oficial é complicada. Supõe que o npm node já estejam instalados:
// npm should be first installed
//sudo apt-get update
sudo apt-get install npm
Baixe e importe a chave fonte do Node GPG
//node should be first installed
sudo apt-get install -y ca-certificates curl gnupg
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
Crie um repositório deb
NODE_MAJOR=20
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
//Optional: NODE_MAJOR can be changed depending on the version you need.
//NODE_MAJOR=16
//NODE_MAJOR=18
//NODE_MAJOR=20
//NODE_MAJOR=21
Instale node:
sudo apt-get update
sudo apt-get install nodejs -y
Finalmente instale o node-red
sudo npm install -g --unsafe-perm node-red
No ubuntu 22.04 não foi possivel instalar , pois o script não consegue sobrescrever: libnode-dev
//remove whatever she complains
sudo apt-get remove libnode-dev
//try again
sudo npm install -g --unsafe-perm node-red
Alternativamente , Este guia para Raspberry Pi é bem mais simples e funciona para o ubuntu 22.04.
bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)
Antes de testar é bom garantir que o firewall não bloqueie nada.
sudo iptables -I INPUT 6 -m state --state NEW -p tcp --dport 1880 -j ACCEPT
sudo iptables -I INPUT 6 -m state --state NEW -p tcp --dport 1883 -j ACCEPT
sudo iptables -I INPUT 6 -m state --state NEW -p tcp --dport 8883 -j ACCEPT
sudo iptables -I INPUT 6 -m state --state NEW -p tcp --dport 80 -j ACCEPT
sudo iptables -I INPUT 6 -m state --state NEW -p tcp --dport 443 -j ACCEPT
//Then save the iptable rules even after reboot next time by
sudo netfilter-persistent save
Protegendo o Node-RED
Por padrão, o editor Node-RED não é protegido – qualquer pessoa que possa acessar seu endereço IP pode acessar o editor e implantar alterações.
Isso só é adequado se você estiver executando em uma rede confiável.
- Este guia descreve como você pode proteger o Node-RED. A segurança é dividida em três partes:
- Habilitando o acesso HTTPS
- Protegendo o editor e a
- API de administração Protegendo os nós HTTP e o painel do Node-RED
Live
Veja uma demonstração em :
https://iot.tudoemclima.com.br:1880