O Nano 33 IoT reúne Wi-Fi, uma IMU de 6 eixos e um elemento de segurança em uma placa minúscula, o que torna os projetos de Arduino Nano 33 IoT com MQTT ideais para monitoramento de movimento. Neste guia, você vai transmitir dados do acelerômetro e do giroscópio por uma conexão SSL criptografada usando WiFiNINA e ArduinoMqttClient. Também vai adicionar um Last Will, manter a taxa de mensagens dentro dos limites do broker e resolver os erros de certificado mais comuns.
A Arquitetura do Nano 33 IoT em Um Minuto
A placa combina três chips que importam para este projeto:
| Componente | Papel em um projeto MQTT |
|---|---|
| SAMD21 (Arm Cortex-M0+) | Executa o seu sketch |
| u-blox NINA-W102 | Coprocessador Wi-Fi; cuida do TCP e do handshake SSL/TLS |
| LSM6DS3 | Acelerômetro de 3 eixos e giroscópio de 3 eixos |
| ATECC608A | Elemento criptográfico, útil para autenticação avançada baseada em certificados |
O seu sketch conversa com o módulo NINA pela biblioteca WiFiNINA. O firmware do NINA armazena uma lista de certificados raiz, então o WiFiSSLClient consegue verificar a maioria das autoridades certificadoras conhecidas sem mudanças no código. Esse é o principal motivo pelo qual esta placa lida com conexões SSL mais facilmente do que um ESP8266: o trabalho pesado acontece no coprocessador.
Pré-requisitos
- Arduino IDE 2.x com Arduino SAMD Boards (32-bits ARM Cortex-M0+) instalado pelo Boards Manager.
- Bibliotecas do Gerenciador de Bibliotecas: WiFiNINA, ArduinoMqttClient e Arduino_LSM6DS3.
- Uma rede Wi-Fi de 2,4 GHz.
- Ferramentas de linha de comando do Mosquitto no seu computador, para testes.
- Firmware do NINA atualizado. Faça o upload de File → Examples → WiFiNINA → Tools → CheckWiFiNINAFirmware e atualize com Tools → WiFi101 / WiFiNINA Firmware Updater se necessário. Firmware antigo é a principal causa de falhas de SSL.
Passo 1: Leia a IMU
Antes de adicionar a rede, confirme que o sensor funciona:
#include <Arduino_LSM6DS3.h>
void setup() {
Serial.begin(115200);
while (!Serial) {}
if (!IMU.begin()) {
Serial.println("IMU not found");
while (true) {}
}
Serial.print("Accelerometer sample rate: ");
Serial.println(IMU.accelerationSampleRate());
}
void loop() {
float x, y, z;
if (IMU.accelerationAvailable()) {
IMU.readAcceleration(x, y, z);
Serial.print(x); Serial.print('\t');
Serial.print(y); Serial.print('\t');
Serial.println(z);
}
delay(200);
}
Com a placa deitada sobre a mesa, z deve ficar perto de 1,0 (um g). Incline a placa e veja os valores mudarem.
Passo 2: Arduino Nano 33 IoT MQTT via SSL
Você vai se conectar ao broker.connectmq.com na porta 8883. O certificado do broker é emitido pela Let's Encrypt, cuja raiz está incluída no firmware atual do NINA, então não é preciso colar nenhum certificado no sketch. Para o primeiríssimo teste, você pode usar o servidor MQTT público (gratuito) de forma anônima; ele exige apenas um client ID único e não vazio. Lembre-se de que os topics públicos podem ser lidos por qualquer pessoa.
Crie o arduino_secrets.h:
#define SECRET_SSID "YOUR_WIFI"
#define SECRET_PASS "YOUR_WIFI_PASSWORD"
// Deixe vazio para o broker público, preencha para o seu broker privado do ConnectMQ
#define SECRET_MQTT_CLIENT_ID "nano33-c7e2a4"
#define SECRET_MQTT_USER ""
#define SECRET_MQTT_PASS ""
O sketch principal publica uma mensagem JSON compacta com aceleração e rotação cinco vezes por segundo, o que fica bem dentro do limite do servidor MQTT público de 10 mensagens por segundo por cliente:
#include <WiFiNINA.h>
#include <ArduinoMqttClient.h>
#include <Arduino_LSM6DS3.h>
#include "arduino_secrets.h"
const char broker[] = "broker.connectmq.com";
const int port = 8883;
const char topicImu[] = "connectmq/demo/nano33-c7e2a4/imu";
const char topicStatus[] = "connectmq/demo/nano33-c7e2a4/status";
const char topicRate[] = "connectmq/demo/nano33-c7e2a4/rate/set";
WiFiSSLClient sslClient;
MqttClient mqttClient(sslClient);
unsigned long publishIntervalMs = 200; // 5 mensagens por segundo
unsigned long lastPublish = 0;
void connectWifi() {
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("WiFi module not found");
while (true) {}
}
while (WiFi.status() != WL_CONNECTED) {
Serial.print("Connecting to ");
Serial.println(SECRET_SSID);
WiFi.begin(SECRET_SSID, SECRET_PASS);
delay(5000);
}
Serial.print("IP: ");
Serial.println(WiFi.localIP());
}
void onMqttMessage(int size) {
char buf[16];
int i = 0;
while (mqttClient.available() && i < (int)sizeof(buf) - 1) {
buf[i++] = (char)mqttClient.read();
}
buf[i] = '\0';
unsigned long ms = strtoul(buf, nullptr, 10);
if (ms >= 100 && ms <= 60000) { // nunca mais rápido que 10 msg/s
publishIntervalMs = ms;
Serial.print("New interval: ");
Serial.println(publishIntervalMs);
}
}
bool connectMqtt() {
mqttClient.setId(SECRET_MQTT_CLIENT_ID);
if (strlen(SECRET_MQTT_USER) > 0) {
mqttClient.setUsernamePassword(SECRET_MQTT_USER, SECRET_MQTT_PASS);
}
mqttClient.setKeepAliveInterval(30 * 1000L);
mqttClient.setConnectionTimeout(10 * 1000L);
mqttClient.beginWill(topicStatus, true, 1);
mqttClient.print("offline");
mqttClient.endWill();
Serial.print("MQTT over SSL... ");
if (!mqttClient.connect(broker, port)) {
Serial.print("failed, error ");
Serial.println(mqttClient.connectError());
return false;
}
Serial.println("connected");
mqttClient.onMessage(onMqttMessage);
mqttClient.subscribe(topicRate, 1);
mqttClient.beginMessage(topicStatus, true, 1);
mqttClient.print("online");
mqttClient.endMessage();
return true;
}
void setup() {
Serial.begin(115200);
unsigned long start = millis();
while (!Serial && millis() - start < 3000) {}
if (!IMU.begin()) {
Serial.println("IMU init failed");
while (true) {}
}
connectWifi();
while (!connectMqtt()) delay(5000);
}
void loop() {
if (WiFi.status() != WL_CONNECTED) connectWifi();
if (!mqttClient.connected()) {
delay(3000);
connectMqtt();
return;
}
mqttClient.poll();
if (millis() - lastPublish >= publishIntervalMs &&
IMU.accelerationAvailable() && IMU.gyroscopeAvailable()) {
lastPublish = millis();
float ax, ay, az, gx, gy, gz;
IMU.readAcceleration(ax, ay, az); // g
IMU.readGyroscope(gx, gy, gz); // graus por segundo
// Envia o JSON direto em stream; print(float, digits) evita problemas de suporte a float no printf
mqttClient.beginMessage(topicImu);
mqttClient.print("{\"ax\":"); mqttClient.print(ax, 3);
mqttClient.print(",\"ay\":"); mqttClient.print(ay, 3);
mqttClient.print(",\"az\":"); mqttClient.print(az, 3);
mqttClient.print(",\"gx\":"); mqttClient.print(gx, 1);
mqttClient.print(",\"gy\":"); mqttClient.print(gy, 1);
mqttClient.print(",\"gz\":"); mqttClient.print(gz, 1);
mqttClient.print("}");
mqttClient.endMessage();
}
}
Acompanhe o stream e diminua a taxa a partir do seu computador:
mosquitto_sub -h broker.connectmq.com -p 1883 -i pc-c7e2a4 -t "connectmq/demo/nano33-c7e2a4/#" -v
mosquitto_pub -h broker.connectmq.com -p 1883 -i ctl-c7e2a4 -t "connectmq/demo/nano33-c7e2a4/rate/set" -m 1000
Repare que o seu notebook usa a porta 1883 sem criptografia, enquanto a placa usa SSL na 8883. Os dois alcançam os mesmos topics no mesmo broker.
O payload é enviado em stream com print(value, digits) em vez de snprintf. O suporte a float em funções no estilo printf varia entre os cores do Arduino, enquanto print() formata floats da mesma forma em todos eles, e o envio em stream evita manter a mensagem inteira na RAM.
Passo 3: Migre para Credenciais Privadas
O servidor MQTT público serve para demonstrações, testes e protótipos, mas dados de movimento de máquinas ou pessoas reais não devem ser públicos. Em um broker MQTT gerenciado como o ConnectMQ, você cria um broker no portal e recebe usuário, senha e client ID gerados. Coloque-os no arduino_secrets.h, mantenha a conexão na 8883 e remova o prefixo connectmq/demo/ em favor da sua própria estrutura de topics. Os client IDs ficam vinculados às credenciais emitidas, então o client ID precisa corresponder exatamente.
Para orientações sobre o projeto de topics, rotação de credenciais e privilégio mínimo, leia boas práticas de segurança MQTT.
Escolhendo QoS e Taxa para Dados da IMU
Dados de sensores em alta taxa e mensagens de comando têm necessidades diferentes:
- Telemetria a 5 Hz ou mais: QoS 0. Perder uma amostra entre centenas não faz diferença, e o QoS 0 evita tráfego extra de confirmações no link com o NINA.
- Mudanças de taxa e outros comandos: inscreva-se com QoS 1 para que o broker tente a entrega novamente.
- Status: QoS 1 retido com um Last Will correspondente, para que os dashboards sempre saibam se a placa está online.
Se você precisa de recursos como análise de vibração, considere calcular valores-resumo no dispositivo (por exemplo, a aceleração RMS em um segundo) e publicá-los, em vez das amostras brutas. Isso reduz a largura de banda e fica bem dentro dos limites de mensagens de qualquer plano. Níveis de QoS do MQTT explicados aborda essas escolhas com mais profundidade.
Calculando Resumos de Vibração na Placa
Amostras brutas da IMU são úteis para experimentos, mas, para monitorar um ventilador, uma bomba de uma estação de saneamento ou uma máquina de lavar, normalmente o que importa é o quanto o equipamento está vibrando ao longo do tempo. Calcular a raiz da média dos quadrados (RMS) da magnitude da aceleração em um segundo transforma dezenas de amostras em um único número significativo. Remover antes a componente de 1 g da gravidade faz o valor ficar perto de zero quando a máquina está parada.
float sumSq = 0;
int samples = 0;
unsigned long windowStart = 0;
void sampleVibration() {
float x, y, z;
if (IMU.accelerationAvailable()) {
IMU.readAcceleration(x, y, z);
float mag = sqrt(x * x + y * y + z * z) - 1.0; // remove a gravidade
sumSq += mag * mag;
samples++;
}
if (millis() - windowStart >= 1000 && samples > 0) {
float rms = sqrt(sumSq / samples);
mqttClient.beginMessage("connectmq/demo/nano33-c7e2a4/vibration");
mqttClient.print("{\"rms_g\":");
mqttClient.print(rms, 4);
mqttClient.print(",\"n\":");
mqttClient.print(samples);
mqttClient.print("}");
mqttClient.endMessage();
sumSq = 0;
samples = 0;
windowStart = millis();
}
}
Chame sampleVibration() em loop() junto com mqttClient.poll(). O resultado é uma mensagem por segundo em vez de um stream, e o campo n informa em quantas amostras o valor se baseia. Do lado de quem recebe, um limite sobre rms_g é uma forma simples e eficaz de sinalizar vibração anormal. Calibre-o gravando primeiro alguns minutos de operação normal, porque cada máquina e cada posição de montagem se comportam de forma diferente.
Mantendo a Conexão Saudável
Um registrador de movimento costuma rodar sem supervisão por dias, então se prepare para instabilidades de rede. A lógica de reconexão do sketch tenta de novo a cada poucos segundos, mas a reinicialização de um roteador pode demorar mais, então considere aumentar o intervalo após falhas repetidas para não sobrecarregar a rede. Publique o topic de status retido a cada reconexão bem-sucedida e registre WiFi.RSSI() junto com seus dados: sinal fraco é o motivo mais comum para uma placa dentro de um gabinete metálico ficar caindo. Se as leituras pararem enquanto o status ainda indica online, verifique se poll() é chamado a cada passagem por loop().
Checklist de Solução de Problemas
connect()falha na 8883, mas funciona na 1883 comWiFiClient: atualize o firmware do NINA. Se você usa um broker com uma CA incomum, envie o certificado raiz dela com a ferramenta de certificados do atualizador de firmware.- "WiFi module not found": placa errada selecionada ou biblioteca WiFiNINA desatualizada.
- Erro 2 (identificador rejeitado): client ID vazio.
- Erro 4 ou 5: as credenciais ou o client ID não correspondem ao que o portal emitiu.
- Desconexões após alguns minutos: algo em
loop()bloqueia opoll(), ou duas placas compartilham um client ID. - Valores da IMU congelados: verifique se
IMU.begin()teve sucesso e se você só lê quandoaccelerationAvailable()é verdadeiro.
Guias Relacionados
O guia da biblioteca ArduinoMqttClient se aprofunda na API usada aqui, e o tutorial Arduino UNO R4 WiFi MQTT mostra o mesmo padrão na pilha WiFiS3. Para uma visão mais ampla de projetos MQTT embarcados, veja o tutorial IoT com ESP32.
Envie os Dados do Seu Nano 33 IoT para o ConnectMQ
O ConnectMQ é um broker MQTT gerenciado, ou seja, um broker MQTT na nuvem com SSL na porta 8883, um certificado Let's Encrypt em que o módulo NINA confia de fábrica e um portal com explorador de topics ao vivo e regras de alerta por limite, o que combina bem com alertas de movimento e vibração. Crie um broker Serverless gratuito em app.connectmq.com, sem precisar de cartão de crédito.
Perguntas frequentes
O Arduino Nano 33 IoT suporta MQTT via SSL?
Sim. O módulo Wi-Fi NINA-W102 realiza o handshake SSL/TLS, e o WiFiSSLClient combinado com o ArduinoMqttClient se conecta à porta 8883 com muito pouco código.
Preciso adicionar um certificado raiz para o ConnectMQ?
Normalmente não. O ConnectMQ usa um certificado Let's Encrypt, e a raiz dele faz parte do firmware atual do NINA. Atualize o firmware se a verificação falhar.
Com que velocidade posso publicar dados da IMU?
Mantenha o dispositivo dentro dos limites do seu broker. No servidor MQTT público, são 10 mensagens por segundo por cliente; para taxas de amostragem maiores, agrupe várias leituras em uma mensagem ou publique resumos calculados.
Posso usar o ATECC608A para autenticação MQTT?
O elemento criptográfico pode armazenar chaves para autenticação baseada em certificados com brokers que suportam certificados de cliente. Na configuração deste guia, você se autentica com o usuário, a senha e o client ID emitidos no portal.



