Skip to content

Superviseur — Simulateur de centrales ​

Émule des centrales de détection incendie INIS-E16 et AVISS afin d'exercer le Superviseur de bout en bout, sans matériel physique.

Le simulateur se présente sous deux formes, bâties sur un cœur commun :

ProjetFormeUsage
dotnet/simulator.coreBibliothèque (.NET 9, sans WPF)Serveurs Modbus TCP/RTU, centrales, profils, scénarios. Consommé par les deux hôtes ci-dessous et par dotnet/tests/simulator.
dotnet/simulatorApplication WPFInterface : ajout de centrales, bascule des états à la souris, modes automatiques.
dotnet/simulator.headlessConsoleSans interface, piloté par HTTP. Démarre automatiquement sous les tests de bout en bout.

La logique Modbus vivant dans le cœur, les deux hôtes se comportent identiquement sur le fil : même profils, mêmes adresses, même réaction aux commandes.

TechnologieC# .NET 9 ; WPF pour l'interface, console pour l'hôte sans interface
Points d'entréesimulator/MainWindow.xaml.cs, simulator.headless/Program.cs
Bibliothèque ModbusNModbus
Référence projetdotnet/shared — pour les cartographies de registres
Testsdotnet/tests/simulator

Structure du cœur ​

FichierRôle
PanelViewModel.csUne centrale émulée : serveur Modbus, état des zones et des points, pilotage des états système
PanelModels.csZones et points, une zone suivant ses points pour tenir ses états à jour
RtuBus.csBus RTU multi-drop : un transport physique, N esclaves, chacun avec son identifiant et son magasin de données
PanelDispatcher.csSérialise les mutations d'état d'une centrale sur un fil unique
ObservableDataStore.csNotifie les écritures venues du superviseur et sérialise tous les accès au tableau interne
ProfileConfig.csProfil Modbus d'une centrale simulée, dérivé des cartographies partagées
SlaveFaultModel.csDéfaut de communication d'un esclave voisin — adresses JBUS 9 à 16 de la table AVISS
ScenarioPreset.csScénarios prêts à jouer
DemoFixtureLoader.csLecture de demo-fixtures.json
CleanupHelper.csSeul endroit où une exception est délibérément avalée : la libération d'un transport déjà fermé ne doit pas interrompre le nettoyage

Fonctionnalités ​

  • Multi-centrales : simule plusieurs centrales simultanément, chacune avec son type, son profil Modbus et son identifiant esclave.
  • Modbus TCP : chaque centrale TCP écoute sur son propre port (ex. 502, 503).
  • Modbus RTU multi-drop : plusieurs centrales partagent un même bus série émulé via Named Pipe (ou port série réel), comme un vrai bus RS-485 multi-points.
  • Profils alignés : adresses de registres dérivées de la source unique partagée dotnet/shared/Profiles/StandardPanelProfiles.cs (INIS-E16 et AVISS), identiques à celles du backend.
  • Injection d'états : forçage des états de zones (Feu, Évacuation, Émission, DM, Dérangement, Test, Hors-Service, Neutralisation, Mode manuel seul, Arrêt d'urgence, Inhibition) et de points (Feu, Dérangement, Hors-Service). Les quatre derniers états de zone n'existent que sur les centrales dont le profil déclare les tables correspondantes (INIS-E16).
  • Injection des états système : chaque bit de la table des paramètres généraux servi par la centrale se force indépendamment de l'état des zones — synthèses feu et dérangement, points hors service, zone en essai, synthèses de neutralisation et de mode manuel seul, défauts de communication des esclaves 01 à 08 (AVISS). Chaque bit porte son adresse JBUS en infobulle, et les tables qu'une centrale ne sert pas n'apparaissent pas.
  • Génération de firmware : une bascule fait servir la table de synthèse d'origine, plus courte, la centrale répondant « adresse illégale » au-delà. Reproduit le parc antérieur aux synthèses d'exploitation, pour vérifier que la supervision reste connectée en mode dégradé.
  • Modes automatiques : Cascade (propagation progressive d'incidents) et Chaos (événements aléatoires) pour les tests de charge et de robustesse. Réservés à l'interface graphique.
  • Réception des commandes : interprète les commandes écrites par le backend (réarmement, mise hors/en service, essai).
  • Compteur de lectures temps réel pour visualiser l'activité de polling du backend.

Prérequis ​

  • .NET 9 SDK
  • Windows pour l'interface graphique (WPF). Le cœur et l'hôte sans interface ne visent aucune plateforme en particulier.

Interface graphique ​

bash
dotnet run --project dotnet/simulator

Au lancement, un parc de démonstration démarre : 2 centrales INIS-E16 (Modbus TCP, ports 502 et 503) et 3 centrales AVISS sur un bus RTU multi-drop partagé (Named Pipe). L'interface permet d'ajouter ou retirer des centrales, de basculer les états et d'activer les modes automatiques. Côté Superviseur, configurer les centrales avec les mêmes paramètres de connexion (port TCP ou bus RTU).

Simulateur sans interface ​

Sert les centrales décrites dans demo-fixtures.json — le fichier dont le backend tire aussi son jeu de démonstration, ce qui garantit que ports, tubes nommés et identifiants d'esclave concordent des deux côtés.

bash
# Toutes les centrales du fichier ; canal de pilotage sur :7000
dotnet run --project dotnet/simulator.headless

# Un sous-ensemble, et un autre port de pilotage
dotnet run --project dotnet/simulator.headless -- --panels demo-inis-01,demo-aviss-01 --control-port 7000

Une clé de centrale inconnue interrompt le démarrage et liste les clés disponibles, plutôt que de laisser une centrale silencieusement absente.

Canal de pilotage ​

Réservé au développement et aux tests : il permet de provoquer un changement d'état et de lire l'état réel de la centrale simulée — par exemple pour vérifier qu'une commande émise depuis l'interface l'a bien atteinte.

RouteEffet
GET /sim/healthSonde de démarrage ; liste les centrales servies.
POST /sim/{centrale}/zone/{n}/{état}Pose un état : fire, fault, test, disabled, neutralized, manualonly, emergencystop, inhibited, ou normal qui remet la zone au repos.
GET /sim/{centrale}/zone/{n}État courant de la zone, tel que la centrale le détient.
POST /sim/{centrale}/firmware/{legacy|current}Bascule la génération de firmware servie : legacy limite la table de synthèse à sa taille d'origine, la centrale répondant « adresse illégale » au-delà.
bash
curl http://127.0.0.1:7000/sim/health
curl -X POST -d '' http://127.0.0.1:7000/sim/demo-inis-01/zone/3/fire
curl http://127.0.0.1:7000/sim/demo-inis-01/zone/3

Une centrale, une zone ou un état inconnus sont refusés par un code d'erreur explicite : une faute de frappe échoue immédiatement au lieu de laisser croire à un test réussi.

Tests ​

dotnet/tests/simulator vérifie que le cœur réagit aux trames de commande hors de toute interface graphique, sur les deux profils et sous commandes concurrentes.

bash
dotnet test dotnet/tests/simulator/simulator.tests.csproj

Les tests de bout en bout du frontend (cd vue && npm run test:e2e) démarrent l'hôte sans interface automatiquement ; il n'y a rien à lancer à la main.

Mécanismes non évidents ​

Le cœur ne référence pas le backend ​

DemoFixtureLoader et ProfileConfig sont des répliques autonomes : même contrat JSON, mêmes adresses — puisées dans dotnet/shared/Profiles — mais aucune référence croisée. Le simulateur peut donc tourner sans le backend, et une divergence d'adressage reste impossible, les deux côtés lisant la même cartographie.

Toute mutation d'état passe par le répartiteur ​

PanelDispatcher sérialise les changements sur un fil unique. Le canal de pilotage HTTP poste sa mutation puis attend qu'elle soit réellement appliquée, dans la limite de cinq secondes : un test qui pose une alarme et lit aussitôt la centrale voit l'état posé, pas l'état précédent.

Une clé de centrale inconnue arrête le démarrage ​

L'hôte sans interface interrompt son démarrage et liste les clés disponibles plutôt que de laisser une centrale silencieusement absente. Le canal de pilotage refuse de même une centrale, une zone ou un état inconnus par un code d'erreur explicite.

Le bus RTU est un vrai multi-drop ​

Un seul transport — port série ou tube nommé — héberge N esclaves, chacun avec son identifiant et son magasin de données. Le superviseur les interroge par identifiant d'esclave, comme sur un RS-485 AVISS.

Contraintes actives ​

ContrainteConséquence si elle est ignorée
simulator.core et simulator.headless ne dépendent d'aucune interface graphiqueL'intégration continue les compile et les éprouve sur Ubuntu
Les adresses viennent de dotnet/shared/ProfilesLes déclarer localement ferait diverger simulateur et backend
Les modes automatiques restent propres à l'interface graphiqueCascade et Chaos n'existent pas dans l'hôte sans interface
demo-fixtures.json est partagé avec le jeu de démonstration du backendPorts, tubes nommés et identifiants d'esclave concordent des deux côtés par construction

Documentation Technique