Skip to content

Latest commit

 

History

History
200 lines (140 loc) · 10.5 KB

File metadata and controls

200 lines (140 loc) · 10.5 KB

Übersicht

PySignalduino ist modular aufgebaut und trennt die Protokolldefinitionen (JSON) strikt von der Verarbeitungslogik (Python). Seit der Migration zu asyncio (Version 0.9.0) folgt das System einer ereignisgesteuerten, asynchronen Architektur, die auf asyncio-Tasks und -Queues basiert. Dies ermöglicht eine effiziente Verarbeitung von Sensordaten, Kommandos und MQTT-Nachrichten ohne Blockierung.

Die Klasse SDProtocols (sd_protocols/sd_protocols.py) ist der zentrale Einstiegspunkt. Sie vereint Funktionalitäten durch Mehrfachvererbung von Mixins:

  • ProtocolHelpersMixin: Grundlegende Bit-Operationen.

  • ManchesterMixin: Spezifische Logik für Manchester-kodierte Signale (mcBit2* Methoden).

  • PostdemodulationMixin: Nachbearbeitung dekodierter Daten (postDemo_* Methoden).

  • RSLMixin: Handler für das RSL-Protokoll.

Die Datei sd_protocols/protocols.json enthält die statischen Definitionen. Jedes Protokoll besitzt eine ID und Eigenschaften wie:

  • format: Kodierung (z.B. manchester, twostate, pwm).

  • preamble: Erkennungsmuster.

  • method: Mapping auf die Python-Methode zur Dekodierung.

Der Ablauf bei Manchester-Signalen ist wie folgt: 1. Erkennung: Match anhand der Preamble/Muster. 2. Vorvalidierung: ManchesterMixin._demodulate_mc_data() prüft Länge und Taktung. 3. Dekodierung: Aufruf der spezifischen mcBit2*-Methode.

Hinweis: Einige Protokolle wie TFA (mcBit2TFA) oder Grothe (mcBit2Grothe) haben spezielle Anforderungen an die Längenprüfung oder Duplikatfilterung.

PySignalduino verwendet asyncio für alle E/A-Operationen, um parallele Verarbeitung ohne Thread-Overhead zu ermöglichen. Die Architektur basiert auf drei Haupt-Tasks, die über asynchrone Queues kommunizieren:

  • Reader-Task: Liest kontinuierlich Zeilen vom Transport (Seriell/TCP) und legt sie in der _raw_message_queue ab.

  • Parser-Task: Entnimmt Rohzeilen aus der Queue, dekodiert sie über den SignalParser und veröffentlicht Ergebnisse via MQTT oder ruft den message_callback auf.

  • Writer-Task: Verarbeitet Kommandos aus der _write_queue, sendet sie an das Gerät und wartet bei Bedarf auf Antworten.

Zusätzlich gibt es spezielle Tasks für Initialisierung, Heartbeat und MQTT-Command-Listener.

  • _raw_message_queue (asyncio.Queue[str]): Rohdaten vom Reader zum Parser.

  • _write_queue (asyncio.Queue[QueuedCommand]): Ausstehende Kommandos vom Controller zum Writer.

  • _pending_responses (List[PendingResponse]): Verwaltet erwartete Antworten mit asyncio.Event für jede.

  • _stop_event (asyncio.Event): Signalisiert allen Tasks, dass sie beenden sollen.

  • _init_complete_event (asyncio.Event): Wird gesetzt, sobald die Geräteinitialisierung erfolgreich abgeschlossen ist.

Alle Ressourcen (Transport, MQTT-Client) implementieren aenter/aexit und werden mittels async with verwaltet. Der SignalduinoController selbst ist ein Kontextmanager, der die Lebensdauer der Verbindung steuert.

Die MQTT-Integration wurde auf eine versionierte, konsistente Befehlsschnittstelle umgestellt, basierend auf dem Architecture Decision Record (ADR-001, ADR-002).

Die Verarbeitung von eingehenden Befehlen erfolgt über ein dediziertes Command Dispatcher Pattern zur strikten Trennung von Netzwerk-Layer, Validierungslogik und Controller-Aktionen:

  1. MqttPublisher (signalduino/mqtt.py) empfängt eine Nachricht auf signalduino/v1/commands/#.

  2. Der SignalduinoController leitet die rohe Payload an den MqttCommandDispatcher weiter.

  3. Der Dispatcher (signalduino/commands.py) validiert die Payload gegen ein JSON-Schema (ADR-002).

  4. Bei Erfolg wird die entsprechende asynchrone Methode im SignalduinoController aufgerufen.

  5. Der Controller sendet serielle Kommandos (W<reg><val>, V, CG) und verpackt die Firmware-Antwort.

  6. Die finale Antwort (status: OK oder error: 400/500/502) wird an den Client zurückgesendet.

Alle Topics sind versioniert und verwenden das Präfix {MQTT_TOPIC}/v1.

Topic-Typ

Topic-Struktur

Zweck

Command (Request)

signalduino/v1/commands/<type>/<target>/<param>

Steuerung und Abfrage von Parametern (z.B. get/system/version)

Response (Success)

signalduino/v1/responses/<type>/<target>/<param>

Strukturierte Antwort auf Befehle ("status": "OK")

Error (Failure)

signalduino/v1/errors/<type>/<target>/<param>

Strukturierte Fehlerinformationen ("error_code": 400/500/502)

Telemetry

signalduino/v1/state/messages

JSON-serialisierte, dekodierte Sensordaten (DecodedMessage)

Status

signalduino/v1/status/{alive,data}

Heartbeat- und Gerätestatus (z.B. free_ram, uptime)

Alle Requests (Commands) und Responses (Responses/Errors) verwenden eine standardisierte JSON-Struktur, die eine req_id zur Korrelation von Anfrage und Antwort erfordert.

{
  "req_id": "uuid-12345",
  "data": "V 3.5.7+20250219" // Nur in Responses
}
+-------------------+      +-------------------+      +-------------------+
|   Transport       |      |   Controller      |      |   MQTT Publisher  |
|   (Serial/TCP)    |----->|   (asyncio Tasks) |----->|   (aiomqtt)       |
+-------------------+      +-------------------+      +-------------------+
         ^                          |                          |
         |                          v                          v
+-------------------+      +-------------------+      +-------------------+
|   SIGNALDuino     |      |   Parser          |      |   MQTT Broker     |
|   Hardware        |<-----|   (SDProtocols)   |<-----|   (extern)        |
+-------------------+      +-------------------+      +-------------------+
  • Transport: Abstrahiert die physikalische Verbindung (asynchrone Lese-/Schreiboperationen).

  • Controller: Orchestriert die drei Haupt-Tasks und verwaltet die Queues.

  • Parser: Wendet die Protokoll‑Definitions‑JSON an und dekodiert Rohdaten.

  • MQTT Publisher: Stellt die Verbindung zum Broker her, publiziert Nachrichten und empfängt Kommandos.

  1. Empfang: Hardware sendet Rohdaten → Transport liest Zeile → Reader‑Task legt Zeile in _raw_message_queue.

  2. Verarbeitung: Parser‑Task entnimmt Zeile, erkennt Protokoll, dekodiert Nachricht.

  3. Ausgabe: Dekodierte Nachricht wird an message_callback übergeben und/oder via MQTT publiziert.

  4. Kommando: Externe Quelle (MQTT oder API) ruft send_command auf → Kommando landet in _write_queue → Writer‑Task sendet es an Hardware.

  5. Antwort: Falls Antwort erwartet wird, wartet der Controller auf das passende Event in _pending_responses.

Alle Schritte sind asynchron und nicht‑blockierend; Tasks können parallel laufen, solange die Queues nicht leer sind.

Die Architektur wurde von einer threading‑basierten Implementierung (Version 0.8.x) zu einer reinen asyncio‑Implementierung migriert. Wichtige Änderungen:

  • Ersetzung von threading.Thread durch asyncio.Task

  • Ersetzung von queue.Queue durch asyncio.Queue

  • Ersetzung von threading.Event durch asyncio.Event

  • async/await in allen E/A‑Methoden

  • Asynchrone Kontextmanager für Ressourcenverwaltung

Details zur Migration sind im Dokument ASYNCIO_MIGRATION.md zu finden.

Die PySignalduino-Dokumentation wird automatisch mit einer dynamischen Sitemap und branch-spezifischen robots.txt-Dateien versehen, um die Auffindbarkeit in Suchmaschinen zu verbessern.

Die Sitemap wird durch das Python-Skript tools/generate_sitemap.py generiert, das:

  1. Den Build-Output-Ordner (build/site/html) nach HTML-Dateien scannt

  2. Prioritäten (0.1–1.0) und Update-Frequenzen (changefreq) basierend auf Dateipfaden zuweist

  3. Branch-spezifische Base-URLs unterstützt (main: pysignalduino.rfd-fhem.github.io, preview: preview.rfd-fhem.github.io)

  4. Gültige XML-Sitemap gemäß sitemaps.org-Schema generiert

  5. Fehlerbehandlung und Logging enthält

Das Skript kann manuell ausgeführt werden:

python tools/generate_sitemap.py --build-dir build/site/html --output sitemap.xml --branch main

Die Datei docs/robots.txt wird im CI/CD-Workflow branch-spezifisch angepasst:

  • main-Branch: Erlaubt Crawling aller Pfade, schließt Preview-/Develop-Pfade aus

  • preview-Branch: Verbietet Crawling des /preview/-Pfads

  • develop-Branch: Verbietet Crawling des /develop/-Pfads

Zusätzlich wird ein Crawl-delay: 2 gesetzt, um Serverlast zu reduzieren.

Der GitHub Actions Workflow .github/workflows/docs.yml wurde erweitert, um:

  1. Nach dem Asciidoctor-Build das Sitemap-Generierungsskript auszuführen

  2. Die robots.txt in das Ausgabeverzeichnis zu kopieren und branch-spezifisch anzupassen

  3. Bei Fehlern der Sitemap-Generierung nicht den gesamten Build fehlschlagen zu lassen (continue-on-error: true)

Für den Fall, dass die dynamische Generierung fehlschlägt, stehen statische Vorlagen bereit:

  • docs/sitemap_template.xml – Grundlegende Sitemap mit den wichtigsten URLs

  • docs/robots.txt – Generische robots.txt-Vorlage

Diese Dateien werden automatisch durch den CI/CD-Workflow verwendet.