Skip to content

Latest commit

 

History

History
286 lines (202 loc) · 13 KB

File metadata and controls

286 lines (202 loc) · 13 KB

Grundlegende Nutzung

Die Hauptklasse SDProtocols stellt die Schnittstelle zur Protokollverarbeitung bereit.

link:../../sd_protocols/sd_protocols.py[role=include]

PySignalduino ist als Bibliothek konzipiert, die beispielsweise in MQTT-Bridges oder Home-Automation-Skripten verwendet werden kann. Sie übernimmt die Erkennung und Dekodierung der Rohdaten.

Für Debugging-Zwecke können Sie eine eigene Callback-Funktion registrieren:

link:../../sd_protocols/sd_protocols.py[role=include]

PySignalduino bietet eine integrierte MQTT-Integration über die Klasse MqttPublisher. Diese ermöglicht das Veröffentlichen dekodierter Nachrichten an einen MQTT-Broker und das Empfangen von Befehlen über MQTT-Topics.

Die MQTT-Verbindung wird automatisch initialisiert, wenn die Umgebungsvariable MQTT_HOST gesetzt ist. Folgende Umgebungsvariablen können konfiguriert werden:

  • MQTT_HOST – Hostname oder IP-Adresse des MQTT-Brokers (Standard: localhost)

  • MQTT_PORT – Port des Brokers (Standard: 1883)

  • MQTT_TOPIC – Basis-Topic für alle Nachrichten (Standard: signalduino)

  • MQTT_USERNAME – Optionaler Benutzername für Authentifizierung

  • MQTT_PASSWORD – Optionales Passwort für Authentifizierung

  • MQTT_COMPRESSION_ENABLED – Boolescher Wert (0/1) zur Aktivierung der Payload-Kompression (Standard: 0)

Der MqttPublisher wird innerhalb des SignalduinoController verwendet und stellt eine asynchrone Context-Manager-Schnittstelle bereit:

link:../../main.py[role=include]
  • {topic}/messages – JSON‑kodierte dekodierte Nachrichten (DecodedMessage)

  • {topic}/commands/# – Topic für eingehende Befehle (Wildcard-Subscription)

  • {topic}/responses – Antworten auf GET-Befehle, inkl. get/cc1101/frequency.

  • {topic}/errors – Fehlerantworten.

  • {topic}/status – Heartbeat‑ und Statusmeldungen (optional)

Der Publisher sendet regelmäßig einen Heartbeat („online“) unter {topic}/status, solange die Verbindung besteht. Bei Verbindungsabbruch wird „offline“ gepublished.

link:../../tests/test_mqtt.py[role=include]

PySignalduino stellt eine umfangreiche Befehls-API zur Steuerung des SIGNALDuino-Firmware-Geräts bereit. Die Klasse SignalduinoCommands kapselt alle verfügbaren seriellen Befehle und bietet eine asynchrone Schnittstelle.

Die folgenden Befehle werden unterstützt (Auswahl):

  • Systembefehle:

  • get_version() – Firmware-Version abfragen (V)

  • get_help() – Hilfe anzeigen (?)

  • get_free_ram() – Freien RAM abfragen ®

  • get_uptime() – Uptime in Sekunden (t)

  • ping() – Ping-Gerät (P)

  • get_cc1101_status() – CC1101-Status (s)

  • disable_receiver() – Empfänger deaktivieren (XQ)

  • enable_receiver() – Empfänger aktivieren (XE)

  • factory_reset() – Werkseinstellungen wiederherstellen (e)

  • Konfigurationsbefehle:

  • get_config() – Konfiguration lesen (CG)

  • set_decoder_state(decoder, enabled) – Decoder aktivieren/deaktivieren (C<CMD><FLAG>)

  • set_manchester_min_bit_length(length) – MC Min Bit Length setzen (CSmcmbl=)

  • set_message_type_enabled(message_type, enabled) – Nachrichtentyp aktivieren/deaktivieren (C<FLAG><TYPE>)

  • get_ccconf() – CC1101-Konfiguration abfragen (C0DnF)

  • get_ccpatable() – CC1101 PA Table abfragen (C3E)

  • read_cc1101_register(register) – CC1101-Register lesen (C<reg>)

  • write_register(register, value) – EEPROM/CC1101-Register schreiben (W<reg><val>)

  • read_eeprom(address) – EEPROM-Byte lesen (r<addr>)

  • set_patable(value) – PA Table schreiben (x<val>)

  • set_bwidth(value) – Bandbreite setzen (C10<val>)

  • set_rampl(value) – Rampenlänge setzen (W1D<val>)

  • set_sens(value) – Empfindlichkeit setzen (W1F<val>)

  • Sendebefehle:

  • send_combined(params) – Kombinierten Sendebefehl (SC…​)

  • send_manchester(params) – Manchester senden (SM…​)

  • send_raw(params) – Rohdaten senden (SR…​)

  • send_xfsk(params) – xFSK senden (SN…​)

  • send_message(message) – Vorkodierte Nachricht senden

Befehle, die die Hardware-Konfiguration ändern (z. B. write_register, set_patable), werden in der Regel im EEPROM des SIGNALDuino persistent gespeichert. Die Persistenz wird durch die Firmware gewährleistet; PySignalduino sendet lediglich die entsprechenden Kommandos.

Wenn MQTT aktiviert ist, können Befehle über das Topic {base_topic}/commands/{command} gesendet werden. Die Basis für Antworten ist {base_topic}/responses (Erfolg) oder {base_topic}/errors (Fehler). Das base_topic ist standardmäßig signalduino/v1.

Die optionale req_id kann im Request-Payload gesendet werden und wird unverändert in die Response übernommen. Sie dient zur Korrelation von asynchronen Anfragen und Antworten.

Dieser Befehl fragt die aktuell im CC1101-Transceiver eingestellte Funkfrequenz ab.

1. Request Topic und Payload (Senden)

  • Topic: signalduino/v1/commands/get/cc1101/frequency (ersetze signalduino/v1 durch dein konfiguriertes {base_topic})

  • Payload: Muss eine req_id zur Korrelation der Antwort enthalten. Ist keine req_id im Payload enthalten, wird automatisch der Wert "NO_REQ_ID" verwendet.

{
    "req_id": "client-12345-freq-req-A"
}

2. Response Topic und Payload (Empfangen)

  • Erfolgs-Topic: signalduino/v1/responses

  • Fehler-Topic: signalduino/v1/errors

Erfolgreiche Antwort (auf `signalduino/v1/responses\`):

{
    "command": "get/cc1101/frequency",
    "success": true,
    "req_id": "client-12345-freq-req-A",
    "payload": {
        "frequency_mhz": 433.920
    }
}

Fehlerhafte Antwort (auf `signalduino/v1/errors\`):

{
    "command": "get/cc1101/frequency",
    "success": false,
    "req_id": "client-12345-freq-req-A",
    "error": "Hardware nicht initialisiert"
}

Beispiel mit mosquitto_pub und mosquitto_sub (angenommen base_topic ist signalduino/v1):

# Zum Senden des Requests
mosquitto_pub -h localhost -t "signalduino/v1/commands/get/cc1101/frequency" -m '{"req_id": "test-123"}'

# Zum Empfangen der Antwort
mosquitto_sub -h localhost -t "signalduino/v1/responses"

Alle anderen allgemeinen Befehle folgen ebenfalls diesem Schema, wobei {command} den Pfad nach /commands/ darstellt.

Beispiel mit mosquitto_pub:

# Sende Request für System-Version
mosquitto_pub -h localhost -t "signalduino/v1/commands/get/system/version" -m '{"req_id": "test-version"}'

# Antwort empfängst du auf signalduino/v1/responses
link:../../tests/test_controller.py[role=include]
link:../../main.py[role=include]

Die folgenden Klassen und Schnittstellen sind für die Integration besonders relevant:

Die Klasse signalduino.mqtt.MqttPublisher bietet eine asynchrone Context-Manager-Schnittstelle zur Kommunikation mit einem MQTT-Broker.

  • Methoden:

  • async publish(message: DecodedMessage) – Veröffentlicht eine dekodierte Nachricht unter {topic}/messages

  • async publish_simple(subtopic: str, payload: str, retain: bool = False) – Veröffentlicht eine einfache Zeichenkette unter {topic}/{subtopic}

  • async is_connected() → bool – Prüft, ob die Verbindung zum Broker besteht

  • register_command_callback(callback: Callable) – Registriert einen asynchronen Callback für eingehende Befehle

  • Context-Manager: async with MqttPublisher() as publisher:

Die Klasse signalduino.commands.SignalduinoCommands kapselt alle seriellen Befehle für die SIGNALDuino-Firmware.

  • Initialisierung: Erfordert eine asynchrone Sendefunktion (wird normalerweise vom SignalduinoController bereitgestellt)

  • Alle Methoden sind asynchron (async def) und geben entweder str (Antwort) zurück oder None (keine Antwort erwartet)

  • Umfang: Systembefehle, Konfiguration, Senden von Nachrichten (siehe Abschnitt „Command Interface“)

Sowohl SignalduinoController als auch MqttPublisher und die Transportklassen (TcpTransport, SerialTransport) implementieren das asynchrone Context-Manager-Protokoll (aenter/aexit). Dies gewährleistet eine sichere Ressourcenverwaltung (Verbindungsauf‑/abbau, Hintergrundtasks).

Beispiel für verschachtelte Context-Manager:

link:../../main.py[role=include]
  • SignalduinoController – Zentrale Steuerungsklasse, koordiniert Transport, Parser, MQTT und Befehle

  • TcpTransport, SerialTransport – Asynchrone Transportimplementierungen für TCP bzw. serielle Verbindungen

  • DecodedMessage, RawFrame – Datentypen für dekodierte Nachrichten und Rohframes

Eine vollständige API-Dokumentation kann mit pydoc oder mittels Sphinx generiert werden.

Dieser Abschnitt beschreibt häufige Probleme und deren Lösungen.

  • Keine Verbindung zum Broker: Stellen Sie sicher, dass die Umgebungsvariablen MQTT_HOST und MQTT_PORT korrekt gesetzt sind. Der Broker muss erreichbar sein und keine Authentifizierung erfordern (oder Benutzername/Passwort müssen gesetzt sein).

  • Verbindung bricht ab: Überprüfen Sie die Netzwerkverbindung und Broker-Konfiguration. Der MQTT-Client (aiomqtt) versucht automatisch, die Verbindung wiederherzustellen. Falls die Verbindung dauerhaft abbricht, prüfen Sie Firewall-Einstellungen und Broker-Logs.

  • MQTT-Nachrichten werden nicht empfangen: Stellen Sie sicher, dass das Topic {topic}/commands/# abonniert ist. Der Command-Listener startet automatisch, wenn MQTT aktiviert ist. Überprüfen Sie die Log-Ausgabe auf Fehler.

  • RuntimeError: no running event loop: Tritt auf, wenn asyncio-Funktionen außerhalb eines laufenden Event-Loops aufgerufen werden. Stellen Sie sicher, dass Ihr Code innerhalb einer asyncio-Coroutine läuft und asyncio.run() verwendet wird. Verwenden Sie async with für Context-Manager.

  • Tasks hängen oder werden nicht abgebrochen: Alle Hintergrundtasks sollten auf das _stop_event reagieren. Bei manuell erstellten Tasks müssen Sie asyncio.CancelledError abfangen und Ressourcen freigeben.

  • Deadlocks in Queues: Wenn eine Queue voll ist und kein Consumer mehr liest, kann await queue.put() blockieren. Stellen Sie sicher, dass die Consumer-Tasks laufen und die Queue nicht überfüllt wird. Verwenden Sie asyncio.wait_for mit Timeout.

  • Keine Antwort auf Befehle: Überprüfen Sie die serielle oder TCP-Verbindung. Stellen Sie sicher, dass das Gerät eingeschaltet ist und die korrekte Baudrate (115200) verwendet wird. Testen Sie mit einem Terminal-Programm, ob das Gerät auf V (Version) antwortet.

  • Timeout-Errors: Die Standard-Timeout für Befehle beträgt 2 Sekunden. Bei langsamen Verbindungen kann dies erhöht werden. Falls Timeouts trotzdem auftreten, könnte die Verbindung instabil sein.

  • Parser erkennt keine Protokolle: Überprüfen Sie, ob die Rohdaten im erwarteten Format ankommen (z.B. +MU;…​). Stellen Sie sicher, dass die Protokolldefinitionen (protocols.json) geladen werden und das Protokoll aktiviert ist.

Aktivieren Sie Debug-Logging, um detaillierte Informationen zu erhalten:

link:../../main.py[role=include]

Die Log-Ausgabe zeigt den Status von Transport, Parser und MQTT.

  • Entwicklungsstatus: Da PySignalduino noch in aktiver Entwicklung ist, können sich Verhalten und API zwischen Commits ändern. Bei unerwartetem Verhalten prüfen Sie bitte die aktuelle Codebasis und melden Sie Issues auf GitHub.

  • aiomqtt-Versionen: Verwenden Sie aiomqtt>=2.0.0. Ältere Versionen können Inkompatibilitäten aufweisen.

  • Windows und asyncio: Unter Windows kann es bei seriellen Verbindungen zu Problemen mit asyncio kommen. Verwenden Sie asyncio.ProactorEventLoop oder weichen Sie auf TCP-Transport aus.

  • Memory Leaks: Bei langem Betrieb können asyncio-Tasks Speicher verbrauchen. Stellen Sie sicher, dass abgeschlossene Tasks garbage-collected werden. Verwenden Sie asyncio.create_task mit Referenzen, um Tasks später abbrechen zu können.

Bei weiteren Problemen öffnen Sie bitte ein Issue auf GitHub mit den relevanten Logs und Konfigurationsdetails.