← Tous les projets

Réseau de capteurs IoT

CPE Lyon, équipe de 4, 2025 à 2026

Une chaîne IoT complète construite par quatre étudiants pour le module Développement embarqué et IoT : capteurs micro:bit, un protocole radio sécurisé sur mesure, un serveur Python, Google Firestore et une application Android. Ma part était le firmware de la passerelle.

Objectif

  • Collecter la température, l’humidité, la pression et la luminosité d’un objet connecté et les envoyer sur une liaison radio sécurisée.
  • Permettre à un opérateur de reconfigurer l’affichage de l’objet à distance depuis une application Android.
  • Couvrir toute la chaîne, du firmware embarqué au cloud et au mobile. Chacun de nous était responsable d’un composant : le firmware de l’objet, le firmware de la passerelle (le mien), le serveur Python et l’application Android.

Architecture

Architecture du réseau de capteurs IoTUn objet micro:bit avec des capteurs communique en radio 2,4 GHz avec une passerelle micro:bit. La passerelle communique en série USB avec un serveur Python. Le serveur lit et écrit dans Google Firestore, que l’application Android écoute en temps réel. Chaque liaison fonctionne dans les deux sens : les mesures montent, la configuration descend.Objetmicro:bit, BME280Passerellemicro:bit (ma part)ServerPython 3Firestorebase cloudAndroid appKotlin, Compose2.4 GHzUSB serialSDKtemps réelArchitecture du réseau de capteurs IoTUn objet micro:bit avec des capteurs communique en radio 2,4 GHz avec une passerelle micro:bit. La passerelle communique en série USB avec un serveur Python. Le serveur lit et écrit dans Google Firestore, que l’application Android écoute en temps réel. Chaque liaison fonctionne dans les deux sens : les mesures montent, la configuration descend.Objetmicro:bit, BME280Passerellemicro:bit (ma part)ServerPython 3Firestorebase cloudAndroid appKotlin, Compose2.4 GHzUSB serialSDKtemps réel

Chaque liaison fonctionne dans les deux sens : les mesures montent, les ordres de configuration descendent.

Ma part : le firmware de la passerelle

  • Relais dans les deux sens

    Les mesures montent vers le serveur par la liaison série USB, les trames de configuration descendent vers l’objet en 2,4 GHz.

  • Filtrage des trames

    Tout ce qui est trop court ou sans VER=1 et ;CRC= est rejeté : la bande 2,4 GHz est pleine de paquets parasites.

  • Vérification CRC-8

    Chaque trame radio est vérifiée, et une trame rejetée reçoit une trame ERR avec un vrai checksum valide.

  • Trames tronquées corrigées

    Le tampon du printf() série de la micro:bit était trop petit : remplacé par snprintf() et un envoi du ManagedString complet.

  • Système de build

    Le projet yotta est séparé en firmware/gateway et firmware/object, choisis par un seul champ de module.json.

Fonctionnement

Protocole et sécurité

  • Protocole lisible

    Champs CLÉ=VALEUR séparés par des points-virgules : facile à déboguer dans un terminal série, simple à analyser sur une micro:bit et en Python.

  • Intégrité, CRC-8

    Un CRC-8 (polynôme 0x07) sur le corps de chaque trame.

  • Authentification

    Un champ AUTH : un CRC-8 sur la clé partagée, l’identifiant de l’objet et le compteur de trame.

  • Anti-rejeu

    Le serveur rejette toute trame dont le compteur n’est pas supérieur au dernier valide pour cet objet.

Les clés partagées sont dans un fichier keys.json tenu hors de Git.

Chemin des données

  1. 1

    Objet ↔ Passerelle2.4 GHz

    L’objet lit un capteur BME280, affiche les valeurs sur un écran OLED et envoie une trame toutes les 5 secondes.

  2. 2

    Passerelle ↔ ServerUSB serial

    La passerelle filtre et vérifie chaque trame et la relaie vers le PC ; les trames de configuration font le chemin inverse.

  3. 3

    Server ↔ FirestoreSDK

    Le serveur Python valide le CRC, le champ AUTH et le compteur, acquitte la trame et stocke les mesures dans Firestore.

  4. 4

    Firestore ↔ Android apptemps réel

    L’application Android (Kotlin, Jetpack Compose) écoute Firestore en temps réel. Confirmer un nouvel ordre d’affichage l’écrit dans Firestore, le serveur le transforme en trame CONFIG, et la passerelle le relaie à l’objet.

Une trame de mesure (valeurs d’exemple)
VER=1;SRC=OBJ;DST=GTW;ID=01;TYPE=DATA;PAYLOAD=T:22,L:150,H:45,P:1013;TS=0042;AUTH=5F;CRC=BF

Problèmes résolus

ProblèmeCorrection
Trames série tronquées : le tampon du printf() série était trop petit.Remplacé par snprintf() et un envoi de la chaîne complète.
Erreurs BADCRC sans fin sans objet actif : des paquets radio parasites atteignaient les vérifications.Filtres de longueur et de marqueurs.
Trames ERR avec un checksum invalide : le CRC était codé en dur à 00.Il est maintenant réellement calculé.
Aucune trame radio reçue : la limite de paquet par défaut (38 octets) était inférieure à nos trames de 75 à 85 octets.Relevée dans config.json.
BADAUTH après chaque mise à jour du firmware : le schéma AUTH avait dérivé entre le firmware et le serveur.L’objet doit être reflashé après toute modification.

Résultat

  • Validé en direct

    Lors d’une démonstration en direct : quatre mesures, transmission radio authentifiée, stockage cloud et reconfiguration à distance de l’affichage.

  • Au-delà du sujet

    Un protocole applicatif complet, un serveur multi-thread avec un listener Firestore, et une interface Android avec graphiques, historique et glisser-déposer.

Ce que nous améliorerions ensuite

  • Conserver le compteur anti-rejeu entre les redémarrages du serveur.
  • Authentifier les trames CONFIG envoyées du serveur à l’objet (elles portent actuellement AUTH=00).
  • Passer du CRC-8 au CRC-16 pour une meilleure robustesse.
  • Ajouter un chiffrement de bout en bout sur la liaison radio, hors du périmètre de ce projet académique.
Tous les détails

Ma part : le firmware de la passerelle

  • Relais dans les deux sens entre la radio 2,4 GHz et la liaison série USB vers le PC : les mesures montent vers le serveur, les trames de configuration descendent vers l’objet.
  • Filtrage des trames. La bande 2,4 GHz est pleine de paquets parasites, donc la passerelle rejette tout ce qui est trop court ou qui n’a pas les marqueurs attendus (VER=1 et ;CRC=).
  • Vérification CRC-8 sur chaque trame radio, et trames ERR portant un vrai checksum valide quand une trame est rejetée.
  • Correction des trames série tronquées : le tampon du printf() série de la micro:bit était trop petit, je l’ai remplacé par snprintf() et un envoi du ManagedString complet.
  • Système de build : j’ai séparé le projet yotta en firmware/gateway et firmware/object, choisis par un seul champ de module.json, pour que personne n’ait à déplacer des fichiers entre les builds.

Protocole et sécurité

  • Un protocole texte lisible (champs CLÉ=VALEUR séparés par des points-virgules) : facile à déboguer dans un terminal série et simple à analyser sur une micro:bit et en Python.
  • Intégrité : un CRC-8 (polynôme 0x07) sur le corps de chaque trame.
  • Authentification : un champ AUTH calculé avec un CRC-8 sur la clé partagée, l’identifiant de l’objet et le compteur de trame.
  • Anti-rejeu : le serveur rejette toute trame dont le compteur n’est pas supérieur au dernier valide pour cet objet.
  • Les clés partagées sont dans un fichier keys.json tenu hors de Git.

Chemin des données

  • L’objet lit un capteur BME280, affiche les valeurs sur un écran OLED et envoie une trame toutes les 5 secondes.
  • Le serveur Python valide le CRC, le champ AUTH et le compteur, acquitte la trame et stocke les mesures dans Firestore.
  • L’application Android (Kotlin, Jetpack Compose) écoute Firestore en temps réel. Confirmer un nouvel ordre d’affichage l’écrit dans Firestore, le serveur le transforme en trame CONFIG, et la passerelle le relaie à l’objet.

Problèmes résolus

  • Trames série tronquées : le tampon du printf() série était trop petit. Corrigé avec snprintf() et un envoi de la chaîne complète.
  • Erreurs BADCRC sans fin sans objet actif : des paquets radio parasites atteignaient les vérifications. Corrigé avec des filtres de longueur et de marqueurs.
  • Trames ERR avec un checksum invalide : le CRC était codé en dur à 00. Il est maintenant réellement calculé.
  • Aucune trame radio reçue : la limite de paquet par défaut (38 octets) était inférieure à nos trames de 75 à 85 octets. Relevée dans config.json.
  • BADAUTH après chaque mise à jour du firmware : le schéma AUTH avait dérivé entre le firmware et le serveur. L’objet doit être reflashé après toute modification.

Résultat

  • Validé lors d’une démonstration en direct : quatre mesures, transmission radio authentifiée, stockage cloud et reconfiguration à distance de l’affichage.
  • Nous sommes allés au-delà du sujet avec un protocole applicatif complet, un serveur multi-thread avec un listener Firestore, et une interface Android avec graphiques, historique et glisser-déposer.

Contact

M’écrireLinkedIn

Basé à Lyon, France

Dernière mise à jour

Télécharger le CV (en anglais)Contact