Aller au contenu

Simulateur Forge IoT — forge iot:simulate

Statut : outil pédagogique. Il publie des mesures factices mais conformes au contrat MQTT Forge IoT vers le broker configuré, sans capteur physique. Il ne lance pas le subscriber, n'écrit pas en base et n'appelle pas l'API HTTP.

Objectif

Permettre de tester le flux complet sans matériel :

forge iot:doctor --mqtt   # 1. le broker répond ?
forge iot:simulate        # 2. publier des mesures factices
subscriber MQTT           # 3. consommer (à brancher côté application)
iot_events                # 4. stockage
/api/iot/events           # 5. lecture HTTP

Le simulateur couvre uniquement l'étape 2 : la publication. Les étapes 3 à 5 relèvent du subscriber, du stockage et de l'API HTTP, déjà documentés ailleurs dans cette section.

Usage

forge iot:simulate

Publie une mesure par défaut sur le topic forge/atelier/esp32-001/telemetry :

{
  "kind": "temperature",
  "value": 22.4,
  "unit": "°C",
  "timestamp": "2026-05-29T10:00:00Z",
  "metadata": {
    "source": "forge-iot-simulator"
  }
}

Le timestamp est toujours en UTC avec suffixe Z, généré à la publication.

Aide via :

forge iot:simulate --help

Options

Option Défaut Description
--profile <nom> (aucun) Profil pédagogique : temperature, humidity, presence, energy. Fournit des défauts kind/value/unit.
--site <slug> atelier Site (slug [a-z0-9-]+).
--device <slug> esp32-001 Identifiant capteur (slug [a-z0-9-]+).
--kind <slug> temperature Type de mesure (slug [a-z0-9_-]+).
--value <nombre> 22.4 Valeur mesurée.
--unit <texte> °C Unité.
--count <n> 1 Nombre de messages, borné 1..1000.
--interval <s> 1 Délai entre messages, borné 0..60 s.

Exemples :

forge iot:simulate --site atelier --device esp32-001
forge iot:simulate --kind humidity --value 55 --unit %
forge iot:simulate --count 10 --interval 1

Profils de simulation

Plutôt que de retenir les bonnes valeurs --kind/--value/--unit pour chaque type de mesure, un profil les fournit d'un coup. Pratique pour construire des exercices sans capteur réel :

forge iot:simulate --profile temperature --count 5
forge iot:simulate --profile humidity --count 5
forge iot:simulate --profile presence --count 5
forge iot:simulate --profile energy --count 5
Profil kind value unit Note
temperature temperature 22.4 °C température ambiante
humidity humidity 55.0 % humidité relative
presence presence 1.0 state 0 = absence, 1 = présence
energy energy 120.5 W puissance instantanée

Quand un profil est actif, le payload porte metadata.profile :

{
  "kind": "temperature",
  "value": 22.4,
  "unit": "°C",
  "timestamp": "2026-05-29T10:00:00Z",
  "metadata": {
    "source": "forge-iot-simulator",
    "profile": "temperature"
  }
}

Un profil ne fournit que des défauts : --kind, --value et --unit peuvent encore les surcharger explicitement, quel que soit leur ordre :

forge iot:simulate --profile temperature --value 24.8
forge iot:simulate --profile humidity --unit "g/m³"

Un profil inconnu est rejeté (exit code 2) :

[ERREUR] Profil inconnu : unknown
Profils disponibles : temperature, humidity, presence, energy

Sans --profile, le comportement est inchangé (température simple, metadata sans profile).

Conformité au contrat

Le simulateur valide chaque message contre le contrat forge/{site}/{device_id}/telemetry avant de se connecter au broker. Une option hors slug est donc rejetée proprement, sans ouvrir de socket :

[ERREUR] message non conforme au contrat MQTT — Topic invalide : 'forge/Atelier/esp32-001/telemetry' (...)

C'est volontaire : on ne publie que des messages que le subscriber Forge IoT saura parser.

Sortie exemple

[INFO] publication de 3 mesure(s) vers localhost:1883
[OK] publié 1/3 → forge/atelier/esp32-001/telemetry (temperature=22.4°C)
[OK] publié 2/3 → forge/atelier/esp32-001/telemetry (temperature=22.4°C)
[OK] publié 3/3 → forge/atelier/esp32-001/telemetry (temperature=22.4°C)
[OK] 3 mesure(s) publiée(s).

Le mot de passe MQTT n'apparaît jamais dans la sortie, même quand un username/password est configuré (il est transmis au broker, pas affiché).

Connexion TLS

forge iot:simulate consomme la configuration TLS : si FORGE_IOT_MQTT_TLS_ENABLED=true, le client appelle client.tls_set(...) avant de se connecter (ca_certs = FORGE_IOT_MQTT_TLS_CA_FILE si fourni, sinon les certificats système). Pense à configurer aussi le port TLS du broker (généralement 8883) :

export FORGE_IOT_MQTT_HOST="mqtt.example.net"
export FORGE_IOT_MQTT_PORT="8883"
export FORGE_IOT_MQTT_TLS_ENABLED="true"
export FORGE_IOT_MQTT_TLS_CA_FILE="/etc/ssl/certs/mosquitto-ca.crt"

forge iot:simulate --profile temperature --count 3

Le chemin du CA n'apparaît jamais dans la sortie. Détails : Configuration — TLS MQTT.

Codes de sortie

Code Signification
0 Publication réussie.
2 Option invalide (valeur manquante, hors plage, message non conforme).
1 Configuration invalide ou échec de connexion / publication.

En cas d'échec de connexion, le message reste sobre (type d'erreur, pas de stacktrace) — lance d'abord forge iot:doctor --mqtt pour diagnostiquer le broker.

Parcours recommandé

Besoin d'un broker pour ces commandes ? Voir Mosquitto local pour l'installer et le lancer.

forge iot:doctor --mqtt              # 1. confirmer que le broker répond
forge iot:simulate --count 3 --interval 1   # 2. publier 3 mesures

Côté consommation, lance forge iot:listen dans un autre terminal : il écoute le broker et insère les mesures reçues dans iot_events. Tu peux ensuite les relire via GET /api/iot/events.

Limites (hors périmètre)

  • ne lance pas le subscriber, n'écrit pas en base, n'appelle pas l'API HTTP ;
  • pas de retain, pas de QoS avancé, pas de downlink ;
  • pas de capteur réel, pas de code embarqué ;
  • QoS 0 uniquement — un message peut être perdu si le broker est saturé (acceptable pour un simulateur pédagogique).

Tickets suivants

  • IOT-MOSQUITTO-LOCAL-DOCS-001 : documenter le lancement d'un Mosquitto local pour exécuter ce flux de bout en bout.