Aller au contenu

L'IoT dans Forge (forge-mvc-iot)

Ce document explique ce que fait l'opt-in forge-mvc-iot, ce qu'il expose, et comment on s'en sert.

forge-mvc-iot reçoit des mesures de capteurs via MQTT, les stocke dans une table iot_events, et les expose par une API HTTP JSON.

Le cœur de Forge ignore tout de l'IoT : ce paquet fournit le subscriber, le stockage et l'API ; l'application décide de ce qu'elle fait des mesures.

1. Rôle du module

Des capteurs publient des mesures sur un broker MQTT. L'opt-in les écoute, les valide selon un contrat, les stocke dans iot_events, puis les expose en JSON pour l'application.

L'écoute MQTT tourne dans un process séparé (iot:listen), pas dans le serveur web ; l'API HTTP, elle, se branche sur le routeur du projet (modèle opt-in de type route).

2. Vue d'ensemble rapide

Élément Valeur
Paquet forge-mvc-iot
Module forge_mvc_iot
Catégorie Communication (ADR-055)
Couche opt-in de type route (couche optins/)
Dépend de forge-mvc, paho-mqtt, un backend BDD (ADR-054)
API publique register_iot_routes, load_iot_config, MqttSubscriber, IotEventRepository
Table SQL iot_events
Configuration MQTT via load_iot_config (IotConfig)
Commandes iot:doctor, iot:init, iot:simulate, iot:listen
Exposition API HTTP JSON (register_iot_routes)
Installation pip install --pre forge-mvc-iot

3. Schémas UML

Les deux schémas suivants montrent deux vues complémentaires de l'opt-in.

Le diagramme de classe montre le subscriber, le dépôt, l'API et la table.

Le diagramme de séquence montre le trajet d'une mesure, du capteur à l'API.

3.1 Diagramme de classe

Le diagramme de classe montre que le MqttSubscriber insère via IotEventRepository, et que register_iot_routes lit ce même dépôt pour l'API.

classDiagram
    direction LR

    class MqttSubscriber {
        +connect()
        +loop_forever()
        +handle_message(topic, payload)
    }

    class IotEventRepository {
        +insert(...)
        +list_recent(limit) list
        +find_by_device(...) list
        +count_by_device(site, device_id) int
    }

    class http {
        <<module>>
        +register_iot_routes(router, repository, config)
    }

    class iot_events {
        <<table>>
        +site
        +device_id
        +metric
        +value
        +recorded_at
    }

    class IotConfig {
        +from env (MQTT)
    }

    MqttSubscriber --> IotEventRepository : insert
    IotEventRepository --> iot_events : lit / écrit
    http --> IotEventRepository : lit
    MqttSubscriber --> IotConfig : se connecte avec

À retenir :

  • le subscriber transforme un message MQTT en ligne iot_events ;
  • le dépôt est la seule porte vers la table ;
  • l'API HTTP lit le même dépôt ;
  • la configuration MQTT vient de l'environnement (IotConfig).

3.2 Diagramme de séquence

Le diagramme de séquence montre une mesure du capteur jusqu'à l'API.

sequenceDiagram
    actor Capteur
    participant Broker as Broker MQTT
    participant Listen as iot:listen (MqttSubscriber)
    participant Repo as IotEventRepository
    participant Table as iot_events
    participant API as register_iot_routes
    actor App as Application

    Capteur->>Broker: publie une mesure (topic, payload)
    Listen->>Broker: abonné, reçoit le message
    Listen->>Listen: valide selon le contrat
    Listen->>Repo: insert(mesure)
    Repo->>Table: insère la ligne
    App->>API: GET /iot/events
    API->>Repo: list_recent / find_by_device
    Repo-->>API: lignes
    API-->>App: JSON

À retenir :

  • l'écoute MQTT tourne dans un process séparé (iot:listen) ;
  • chaque message valide devient une ligne iot_events ;
  • un message non conforme au contrat est rejeté ;
  • l'API HTTP expose les mesures en JSON, sans toucher au broker.

4. API publique

Élément Signature Rôle
register_iot_routes register_iot_routes(router, *, repository=None, config=None) -> None branche l'API HTTP JSON
load_iot_config load_iot_config(env=None) -> IotConfig configuration MQTT
MqttSubscriber classe abonné MQTT : connect, loop_forever, handle_message
IotEventRepository classe insert, list_recent, find_by_device, count_by_device
IotConfig dataclass configuration (broker, topics, TLS)

Commandes CLI

Commande Rôle
forge iot:doctor diagnostic (paquet, config, migration, API)
forge iot:init copie la migration IoT vers mvc/migrations/
forge iot:simulate publie des mesures MQTT factices (sans capteur)
forge iot:listen écoute le broker et insère dans iot_events

5. Contextes d'utilisation

Besoin Élément
Vérifier l'installation forge iot:doctor
Préparer la table forge iot:init puis forge db:apply
Tester sans capteur forge iot:simulate
Recevoir les mesures forge iot:listen (process séparé)
Exposer en JSON register_iot_routes(router)
Lire par appareil IotEventRepository.find_by_device(...)

6. Exemples d'utilisation

6.1 Brancher l'API HTTP JSON

# optins/iot/routes.py (couche optins du projet)
from forge_mvc_iot import register_iot_routes


def register(router) -> None:
    register_iot_routes(router)

forge opt-in:enable iot --apply crée cette couche ; le branchement reste explicite.

6.2 Écouter le broker (process séparé)

forge iot:init && forge db:apply     # crée la table iot_events
forge iot:simulate                   # publie des mesures de test
forge iot:listen                     # écoute et stocke

iot:listen tourne en service (systemd) ou en terminal dédié, pas dans le serveur web.

Aide-mémoire

Deux process, une table :

  • réception : iot:listen (MQTT vers iot_events) ;
  • exposition : register_iot_routes (HTTP JSON depuis iot_events).

7. MQTT, contrat et exécution

Les messages MQTT suivent un contrat (site, appareil, métrique, valeur, horodatage) ; un message non conforme est rejeté à la réception.

paho-mqtt est la dépendance MQTT ; TLS est géré par mqtt/tls.py.

L'écoute tourne à part

iot:listen (le subscriber MQTT) s'exécute dans un process distinct du serveur web.

Ne l'intégrez pas au process WSGI : le serveur doit rester disponible pour les requêtes.

Tester sans matériel

forge iot:simulate publie des mesures factices conformes au contrat.

Vous pouvez ainsi valider toute la chaîne (réception, stockage, API) sans capteur réel.

Indépendance du cœur

Le cœur de Forge ne dépend pas de forge-mvc-iot : la dépendance va de l'opt-in vers le cœur.

Voir aussi