|
| 1 | += Architektur-Proposal: MQTT-basierter Factory Reset und Hardware-Status |
| 2 | +:doctype: article |
| 3 | +:encoding: utf-8 |
| 4 | +:lang: de |
| 5 | +:author: Roo (Architekt) |
| 6 | +:email: roo@pythonsignalduino.com |
| 7 | +:revnumber: 1.0 |
| 8 | +:revdate: 2026-01-04 |
| 9 | +:xrefstyle: full |
| 10 | + |
| 11 | +[[status]] |
| 12 | +== Status |
| 13 | + |
| 14 | +|=== |
| 15 | +|Status|Datum der letzten Änderung|Entscheidungsträger |
| 16 | + |
| 17 | +|Draft |
| 18 | +|2026-01-04 |
| 19 | +|Roo (Architekt) |
| 20 | +|=== |
| 21 | + |
| 22 | +[[zusammenfassung]] |
| 23 | +== 1. Zusammenfassung (Executive Summary) |
| 24 | + |
| 25 | +Dieses Proposal beschreibt die Einführung von zwei neuen MQTT-Funktionalitäten: die Durchführung eines Factory Resets auf dem Signalduino-Gerät und das Abrufen der aktuellen CC1101-Hardware-Einstellungen (Frequenz, Bandbreite, Verstärkung, Empfindlichkeit, Datenrate) über MQTT. Die Implementierung basiert auf dem Refactoring des MQTT-Befehls-Handlings, indem der vorhandene `MqttCommandDispatcher` zentral in `signalduino/mqtt.py` verwendet wird. |
| 26 | + |
| 27 | +[[problem-definition]] |
| 28 | +== 2. Problemstellung und Motivation |
| 29 | + |
| 30 | +Aktuell müssen Hardware-Einstellungen direkt über die serielle Konsole des Signalduino-Geräts abgefragt werden. Für einen Factory Reset (Serial Command `e (EEPROM Defaults)`) fehlt ein hochstufiger, zugänglicher Mechanismus. Die bestehende MQTT-Befehlslogik in `signalduino/mqtt.py` ist eine unstrukturierte `if/elif`-Kette, die eine Erweiterung erschwert. Die Motivation ist, eine vollständig über MQTT fernsteuerbare und auslesbare Schnittstelle für die Geräteeinstellungen zu schaffen. |
| 31 | + |
| 32 | +[[ziele]] |
| 33 | +== 3. Ziele |
| 34 | + |
| 35 | +1. **Refactoring:** Ersetze die `if/elif`-Logik in `signalduino/mqtt.py` durch den [`MqttCommandDispatcher`](signalduino/commands.py:193) (siehe xref:ADR-002-mqtt-command-dispatcher.adoc[ADR 002]). |
| 36 | +2. **Factory Reset:** Definiere und implementiere den MQTT-Befehl für den Signalduino Factory Reset (`e`). |
| 37 | +3. **Hardware-Status-Abruf:** Implementiere neue Controller-Methoden und MQTT-Befehle, um die aktuellen CC1101-Einstellungen (Freq, Bandwidth, rAmpl, sens, DataRate) auszulesen. |
| 38 | +4. **Tooling:** Entwirf die Schnittstelle für ein CLI-Helfer-Tool zum Testen und Steuern dieser Befehle. |
| 39 | + |
| 40 | +[[vorgeschlagene-architektur]] |
| 41 | +== 4. Vorgeschlagene Architektur |
| 42 | + |
| 43 | +Die Architektur nutzt die bereits existierende Schichtenarchitektur von PySignalduino (MQTT Publisher -> Controller -> Serial Commands). Der Schlüssel liegt in der Zentralisierung des Befehls-Routings im `MqttCommandDispatcher`. |
| 44 | + |
| 45 | +=== 4.1. Komponenten-Diagramm (Mermaid) |
| 46 | + |
| 47 | +[mermaid] |
| 48 | +---- |
| 49 | +graph TD |
| 50 | + A[MQTT Client] --> B(MqttPublisher / Listener); |
| 51 | + B --> C{MqttCommandDispatcher}; |
| 52 | + C --> D[SignalduinoController]; |
| 53 | + D --> E[SignalduinoCommands (Serial API)]; |
| 54 | + E --> F[Signalduino Hardware]; |
| 55 | + |
| 56 | + subgraph Signal Path (Commands) |
| 57 | + B -- Refactored Handler --> C |
| 58 | + C -- Payload Validation / Routing --> D |
| 59 | + D -- High-Level Call --> E |
| 60 | + E -- Low-Level Serial --> F |
| 61 | + end |
| 62 | +---- |
| 63 | + |
| 64 | +=== 4.2. Sequenz-Diagramm (Mermaid) |
| 65 | + |
| 66 | +Dieses Diagramm zeigt den Ablauf für den Factory Reset und das Abrufen der Bandbreite. |
| 67 | + |
| 68 | +[mermaid] |
| 69 | +---- |
| 70 | +sequenceDiagram |
| 71 | + participant Mq as MQTT Client (Tool) |
| 72 | + participant Mqp as MqttPublisher (signalduino/mqtt.py) |
| 73 | + participant Disp as MqttCommandDispatcher |
| 74 | + participant Ctrl as SignalduinoController |
| 75 | + participant Cmd as SignalduinoCommands |
| 76 | + participant SDU as Signalduino Hardware |
| 77 | +
|
| 78 | + group Factory Reset (Command) |
| 79 | + Mq->>Mqp: PUBLISH (Topic: .../commands/command/factory_reset, Payload: {"req_id": "123"}) |
| 80 | + Mqp->>Disp: dispatch("command/factory_reset", payload) |
| 81 | + Disp->>Ctrl: command_factory_reset(payload) |
| 82 | + Ctrl->>Cmd: send_command("e") |
| 83 | + Cmd->>SDU: Serial: e |
| 84 | + SDU-->>Cmd: Serial: OK / Timeout |
| 85 | + Cmd-->>Ctrl: Result |
| 86 | + Ctrl-->>Disp: Response Data |
| 87 | + Disp-->>Mqp: Result Dict |
| 88 | + Mqp->>Mq: PUBLISH (Topic: .../responses, Payload: success: true, req_id: "123") |
| 89 | + end |
| 90 | +
|
| 91 | + group Hardware Status (GET) |
| 92 | + Mq->>Mqp: PUBLISH (Topic: .../commands/get/cc1101/bandwidth, Payload: {"req_id": "456"}) |
| 93 | + Mqp->>Disp: dispatch("get/cc1101/bandwidth", payload) |
| 94 | + Disp->>Ctrl: get_cc1101_bandwidth(payload) |
| 95 | + Ctrl->>Cmd: read_cc1101_register(0x10) |
| 96 | + Cmd->>SDU: Serial: C10 |
| 97 | + SDU-->>Cmd: Serial: C10 = 02 (Beispiel) |
| 98 | + Cmd->>Cmd: Decode to Bandwidth (z.B. 102 kHz) |
| 99 | + Cmd-->>Ctrl: 102 (kHz) |
| 100 | + Ctrl-->>Disp: 102 |
| 101 | + Disp-->>Mqp: Response Data |
| 102 | + Mqp->>Mq: PUBLISH (Topic: .../responses, Payload: data: 102, req_id: "456") |
| 103 | + end |
| 104 | +---- |
| 105 | + |
| 106 | +[[schnittstellen]] |
| 107 | +== 5. Betroffene Schnittstellen (APIs, MQTT Topics) |
| 108 | + |
| 109 | +=== 5.1. Neue MQTT Topics (PUBLISH an) |
| 110 | +* `signalduino/v1/commands/command/factory_reset` |
| 111 | +* `signalduino/v1/commands/get/cc1101/bandwidth` |
| 112 | +* `signalduino/v1/commands/get/cc1101/rampl` |
| 113 | +* `signalduino/v1/commands/get/cc1101/sensitivity` |
| 114 | +* `signalduino/v1/commands/get/cc1101/datarate` |
| 115 | + |
| 116 | +=== 5.2. `SignalduinoCommands` Erweiterungen (Serial API) |
| 117 | +Neue Methoden in [`SignalduinoCommands`](signalduino/commands.py:20), die das Lesen der CC1101-Register kapseln und die Rohwerte in nutzbare Einheiten (kHz, dB) umrechnen: |
| 118 | +* `factory_reset()` (Serial Command `e`) |
| 119 | +* `get_bwidth()` (liest Register `0x10` und berechnet die Bandbreite) |
| 120 | +* `get_rampl()` (liest Register `0x1B` und decodiert die Verstärkung) |
| 121 | +* `get_sens()` (liest Register `0x1D` und decodiert die Empfindlichkeit) |
| 122 | +* `get_datarate()` (liest Register `0x10` und `0x11` und berechnet die Datenrate) |
| 123 | + |
| 124 | +=== 5.3. `MqttCommandDispatcher.COMMAND_MAP` Erweiterungen |
| 125 | +Neue Einträge in der Map zur Weiterleitung der obigen MQTT Topics an die entsprechenden Controller-Methoden. |
| 126 | + |
| 127 | +[[alternativen]] |
| 128 | +== 6. Alternativen in Betracht gezogen |
| 129 | + |
| 130 | +* **Kein Refactoring:** Das Beibehalten der `if/elif`-Kette in `signalduino/mqtt.py` wurde abgelehnt, da es die Wartbarkeit reduziert und dem Architekturprinzip der Trennung der Zuständigkeiten widerspricht (siehe ADR-002). |
| 131 | +* **Keine Abfrage einzelner Werte:** Stattdessen nur einen Sammelbefehl (`get/cc1101/status`) implementieren. Dies wurde abgelehnt, da es die Konsistenz mit dem bereits vorhandenen `get/cc1101/frequency` bricht und nicht die Flexibilität für clientspezifische Abfragen bietet. |
| 132 | + |
| 133 | +[[auswirkungen]] |
| 134 | +== 7. Auswirkungen und Migration |
| 135 | + |
| 136 | +* **Bestehender Code:** Die Methode `MqttPublisher._handle_command` in `signalduino/mqtt.py` muss vollständig refaktorisiert werden, um den Dispatcher zu verwenden. Die bestehende Logik für `get/system/version` und `get/cc1101/frequency` wird entfernt und über den Dispatcher abgewickelt. |
| 137 | +* **Abhängigkeiten:** Keine neuen externen Abhängigkeiten erforderlich. |
| 138 | + |
| 139 | +[[implementierungsplan]] |
| 140 | +== 8. Implementierungs-Plan |
| 141 | + |
| 142 | +Der detaillierte Implementierungsplan wird in Phase 2 erstellt, basiert aber auf den folgenden High-Level-Schritten: |
| 143 | + |
| 144 | +1. **Refactoring:** Initialisiere den `MqttCommandDispatcher` in `MqttPublisher.__init__` und aktualisiere `MqttPublisher._handle_command` zur Verwendung des Dispatchers. |
| 145 | +2. **Controller-Erweiterung:** Füge die High-Level-Methoden `command_factory_reset`, `get_cc1101_bandwidth`, `get_cc1101_rampl`, `get_cc1101_sensitivity`, `get_cc1101_datarate` zum `SignalduinoController` hinzu. |
| 146 | +3. **Serial Commands:** Implementiere die entsprechenden Low-Level-Methoden (`factory_reset`, `get_bwidth`, `get_rampl`, `get_sens`, `get_datarate`) in [`SignalduinoCommands`](signalduino/commands.py:20) inklusive der Register-Decodierungslogik. |
| 147 | +4. **Dispatcher-Aktualisierung:** Erweitere `COMMAND_MAP` in `signalduino/commands.py` um die neuen Befehle und deren Schemata. |
| 148 | + |
| 149 | +[[cli-tool]] |
| 150 | +== 9. CLI Tool Design |
| 151 | + |
| 152 | +Es wird ein kleines Python-Helfer-Tool (z.B. `signalduino-mqtt-cli`) entworfen, das über die Kommandozeile MQTT-Befehle senden kann. Dieses Tool wird die neuen Funktionen demonstrieren und zur Verifikation dienen. |
| 153 | + |
| 154 | +=== 9.1. Befehlsdesign |
| 155 | +* `sd-mqtt-cli reset --req-id <ID>` (Sendet `command/factory_reset`) |
| 156 | +* `sd-mqtt-cli get hardware-status --req-id <ID> --parameter bandwidth` (Sendet `get/cc1101/bandwidth`) |
| 157 | +* `sd-mqtt-cli get hardware-status --all --req-id <ID>` (Optional: Implementiert einen Batch-Abruf oder ruft alle einzelnen GET-Befehle sequenziell ab und gibt das konsolidierte Ergebnis aus.) |
| 158 | + |
| 159 | +Dieses Tool würde die `MqttPublisher` Logik des Hauptprogramms in einem CLI-Kontext nachbilden, um PUBLISH/SUBSCRIBE für Request/Response zu handhaben. |
0 commit comments