Le Nano 33 IoT réunit le Wi-Fi, une IMU 6 axes et un élément sécurisé sur une minuscule carte, ce qui rend les projets Arduino Nano 33 IoT MQTT idéaux pour la surveillance de mouvements. Dans ce guide, vous allez diffuser les données de l'accéléromètre et du gyroscope via une connexion SSL chiffrée avec WiFiNINA et ArduinoMqttClient. Vous ajouterez aussi un Last Will, maintiendrez le débit de messages dans les limites du broker et corrigerez les erreurs de certificat les plus fréquentes.
L'architecture du Nano 33 IoT en une minute
La carte combine trois puces qui comptent pour ce projet :
| Composant | Rôle dans un projet MQTT |
|---|---|
| SAMD21 (Arm Cortex-M0+) | Exécute votre sketch |
| u-blox NINA-W102 | Coprocesseur Wi-Fi ; gère TCP et la poignée de main SSL/TLS |
| LSM6DS3 | Accéléromètre 3 axes et gyroscope 3 axes |
| ATECC608A | Élément cryptographique, utile pour une authentification avancée par certificat |
Votre sketch communique avec le module NINA via la bibliothèque WiFiNINA. Le firmware NINA stocke une liste de certificats racine, si bien que WiFiSSLClient peut vérifier la plupart des autorités de certification connues sans modifier le code. C'est la principale raison pour laquelle cette carte gère les connexions SSL plus facilement qu'un ESP8266 : le gros du travail est effectué par le coprocesseur.
Prérequis
- L'Arduino IDE 2.x avec Arduino SAMD Boards (32-bits ARM Cortex-M0+) installé depuis le gestionnaire de cartes.
- Les bibliothèques suivantes depuis le gestionnaire de bibliothèques : WiFiNINA, ArduinoMqttClient et Arduino_LSM6DS3.
- Un réseau Wi-Fi 2,4 GHz.
- Les outils en ligne de commande Mosquitto sur votre ordinateur pour les tests.
- Un firmware NINA à jour. Téléversez Fichier → Exemples → WiFiNINA → Tools → CheckWiFiNINAFirmware et mettez à jour si nécessaire avec Outils → WiFi101 / WiFiNINA Firmware Updater. Un firmware ancien est la première cause d'échec SSL.
Étape 1 : lire l'IMU
Avant d'ajouter le réseau, vérifiez que le capteur fonctionne :
#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);
}
Posée à plat sur le bureau, la valeur z doit être proche de 1,0 (un g). Inclinez la carte et regardez les valeurs évoluer.
Étape 2 : Arduino Nano 33 IoT MQTT en SSL
Vous allez vous connecter à broker.connectmq.com sur le port 8883. Le certificat du broker est émis par Let's Encrypt, dont la racine est incluse dans les firmwares NINA actuels : aucun certificat n'a donc besoin d'être collé dans le sketch. Pour le tout premier test, vous pouvez utiliser le serveur MQTT public gratuit, réservé aux tests et aux prototypes, de façon anonyme ; il exige seulement un client ID unique et non vide. N'oubliez pas que les topics publics sont lisibles par tous.
Créez arduino_secrets.h :
#define SECRET_SSID "YOUR_WIFI"
#define SECRET_PASS "YOUR_WIFI_PASSWORD"
// Laisser vide pour le broker public, à remplir pour votre broker ConnectMQ privé
#define SECRET_MQTT_CLIENT_ID "nano33-c7e2a4"
#define SECRET_MQTT_USER ""
#define SECRET_MQTT_PASS ""
Le sketch principal publie un message JSON compact contenant l'accélération et la rotation cinq fois par seconde, ce qui reste bien en deçà de la limite du serveur MQTT public gratuit de 10 messages par seconde par client :
#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 messages par seconde
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) { // jamais plus de 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); // degrés par seconde
// Envoyer le JSON en flux ; print(float, digits) évite les problèmes de prise en charge des floats par 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();
}
}
Observez le flux et ralentissez-le depuis votre ordinateur :
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
Remarquez que votre ordinateur utilise le port 1883 en clair tandis que la carte utilise le SSL sur 8883. Les deux atteignent les mêmes topics sur le même broker.
Le payload est envoyé en flux avec print(value, digits) plutôt qu'avec snprintf. La prise en charge des nombres flottants dans les fonctions de type printf varie selon les cores Arduino, alors que print() formate les flottants de la même manière partout, et le streaming évite de garder tout le message en RAM.
Étape 3 : passer à des identifiants privés
Le serveur MQTT public gratuit convient pour une démo, mais les données de mouvement issues de vraies machines ou de personnes ne doivent pas être publiques. Sur un broker MQTT managé comme ConnectMQ, vous créez un broker dans le portail et recevez un nom d'utilisateur, un mot de passe et un client ID générés. Placez-les dans arduino_secrets.h, gardez la connexion sur 8883 et supprimez le préfixe connectmq/demo/ au profit de votre propre structure de topics. Les client ID sont liés aux identifiants émis : le client ID doit donc correspondre exactement.
Pour des conseils sur la conception des topics, la rotation des identifiants et le moindre privilège, lisez les bonnes pratiques de sécurité MQTT.
Choisir le QoS et le débit pour les données de l'IMU
Les données de capteur à haut débit et les messages de commande ont des besoins différents :
- Télémétrie à 5 Hz ou plus : QoS 0. Perdre un échantillon sur des centaines n'a pas d'importance, et le QoS 0 évite le trafic d'acquittement supplémentaire sur la liaison NINA.
- Changements de débit et autres commandes : abonnez-vous en QoS 1 pour que le broker retente la livraison.
- Statut : QoS 1 retenu avec un Last Will correspondant, pour que les tableaux de bord sachent toujours si la carte est en ligne.
Si vous avez besoin de fonctions comme l'analyse vibratoire, envisagez de calculer des valeurs de synthèse sur l'appareil (par exemple l'accélération RMS sur une seconde) et de publier celles-ci plutôt que les échantillons bruts. Cela réduit la bande passante et reste largement dans les limites de messages de n'importe quelle offre. Les niveaux de QoS MQTT expliqués détaille ces compromis.
Calculer des synthèses de vibration sur la carte
Les échantillons bruts de l'IMU sont utiles pour expérimenter, mais pour surveiller un ventilateur, une pompe ou une machine à laver, ce qui compte généralement, c'est l'intensité des secousses dans le temps. Calculer la moyenne quadratique (RMS) de la norme de l'accélération sur une seconde transforme des dizaines d'échantillons en un seul nombre significatif. Retirer d'abord la composante de gravité de 1 g rend la valeur proche de zéro lorsque la machine est à l'arrêt.
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; // retirer la gravité
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();
}
}
Appelez sampleVibration() depuis loop() à côté de mqttClient.poll(). Vous obtenez un message par seconde au lieu d'un flux, et le champ n indique sur combien d'échantillons repose la valeur. Côté réception, un seuil sur rms_g est un moyen simple et efficace de signaler des secousses anormales. Étalonnez-le en enregistrant d'abord quelques minutes de fonctionnement normal, car chaque machine et chaque position de montage se comporte différemment.
Garder la connexion en bonne santé
Un enregistreur de mouvements tourne souvent sans surveillance pendant des jours : prévoyez donc les aléas du réseau. La logique de reconnexion du sketch réessaie toutes les quelques secondes, mais un redémarrage du routeur peut prendre plus longtemps ; envisagez donc d'allonger le délai après des échecs répétés pour ne pas saturer le réseau. Publiez le topic de statut retenu à chaque reconnexion réussie, et journalisez WiFi.RSSI() avec vos données : un signal faible est la raison la plus fréquente pour laquelle une carte placée dans un boîtier métallique décroche sans cesse. Si les mesures s'arrêtent alors que le statut indique toujours « online », vérifiez que poll() est appelé à chaque passage dans loop().
Liste de vérification pour le dépannage
connect()échoue sur 8883 mais fonctionne sur 1883 avecWiFiClient: mettez à jour le firmware NINA. Si vous utilisez un broker avec une autorité de certification peu courante, téléversez son certificat racine avec l'outil de certificats du programme de mise à jour du firmware.- « WiFi module not found » : mauvaise carte sélectionnée, ou bibliothèque WiFiNINA obsolète.
- Erreur 2 (identifiant rejeté) : client ID vide.
- Erreur 4 ou 5 : les identifiants ou le client ID ne correspondent pas à ceux émis par le portail.
- Déconnexions au bout de quelques minutes : quelque chose dans
loop()bloquepoll(), ou deux cartes partagent un client ID. - Valeurs de l'IMU figées : vérifiez que
IMU.begin()a réussi et que vous ne lisez que lorsqueaccelerationAvailable()est vrai.
Guides associés
Le guide de la bibliothèque ArduinoMqttClient approfondit l'API utilisée ici, et le tutoriel Arduino UNO R4 WiFi MQTT montre le même schéma avec la pile WiFiS3. Pour une vue plus large des projets MQTT embarqués, consultez le tutoriel IoT ESP32.
Diffusez les données de votre Nano 33 IoT vers ConnectMQ
ConnectMQ est un broker MQTT dans le cloud avec le SSL sur le port 8883, un certificat Let's Encrypt que le module NINA reconnaît d'emblée, et un portail doté d'un explorateur de topics en direct et de règles d'alerte de seuil, bien adaptées aux alertes de mouvement et de vibration. Créez un broker Serverless gratuit sur app.connectmq.com, sans carte bancaire.
Questions fréquentes
L'Arduino Nano 33 IoT prend-il en charge MQTT en SSL ?
Oui. Le module Wi-Fi NINA-W102 effectue la poignée de main SSL/TLS, et WiFiSSLClient combiné à ArduinoMqttClient se connecte au port 8883 avec très peu de code.
Dois-je ajouter un certificat racine pour ConnectMQ ?
Normalement, non. ConnectMQ utilise un certificat Let's Encrypt, dont la racine fait partie des firmwares NINA actuels. Mettez le firmware à jour si la vérification échoue.
À quelle fréquence puis-je publier les données de l'IMU ?
Restez dans les limites de votre broker. Sur le serveur MQTT public gratuit, c'est 10 messages par seconde par client ; pour des fréquences d'échantillonnage plus élevées, regroupez plusieurs mesures dans un message ou publiez des synthèses calculées.
Puis-je utiliser l'ATECC608A pour l'authentification MQTT ?
L'élément cryptographique peut stocker des clés pour une authentification par certificat auprès de brokers qui prennent en charge les certificats clients. Pour la configuration de ce guide, vous vous authentifiez avec le nom d'utilisateur, le mot de passe et le client ID émis dans le portail.



