// ===================================================================================== // protocol_client.h - UART-Protokoll-Client (P4-Seite) // ===================================================================================== // Implementiert die Display-Seite des in Doku/JC-Display_UART-Protokoll.md (v2) // beschriebenen Protokolls: // - empfaengt : state / ack / error / profiles / profileDetails / hello // - sendet : hello / ping / getState / listProfiles / loadProfile / action / // saveBrew / saveService / saveSensor / setPid / // startAutotune / stopAutotune / getProfileDetails // - Heartbeat, hello-Handshake, Link-Timeout-Ueberwachung // // Parsen: ArduinoJson (der ESP32-P4 hat reichlich RAM/PSRAM). // ===================================================================================== #pragma once #include #include "config.h" #include "machine_state.h" class ProtocolClient { public: // Callback-Typen typedef void (*StateCb)(const MachineState& st); typedef void (*ProfilesCb)(const String profiles[], int count); typedef void (*RawJsonCb)(const String& json); // profileDetails (Roh-JSON) typedef void (*AckCb)(uint32_t id, bool ok, const String& message); explicit ProtocolClient(MachineState& state) : _state(state) {} void begin(); void loop(); bool linkUp() const { return _state.linkUp; } // --- Diagnose-Zaehler (fuer On-Screen-Debug) --- unsigned long rxByteCount = 0; // gesamt empfangene Bytes (auch unvollstaendige) unsigned long rxLineCount = 0; // vollstaendige Zeilen unsigned long txCmdCount = 0; // gesendete Kommandos unsigned long helloCount = 0; // gesendete hello unsigned long parseErrorCount = 0; // JSON-Parse-Fehler String lastRxLine; // zuletzt empfangene Rohzeile // --- Callbacks registrieren --- void onState(StateCb cb) { _stateCb = cb; } void onProfiles(ProfilesCb cb) { _profilesCb = cb; } void onProfileDetails(RawJsonCb cb) { _profileDetailsCb = cb; } void onUsageStats(RawJsonCb cb) { _usageStatsCb = cb; } // Antwort auf getUsageStats (Roh-JSON) void onWifiNetworks(RawJsonCb cb) { _wifiNetworksCb = cb; } // Antwort auf scanWifi (Roh-JSON) void onOta(RawJsonCb cb) { _otaCb = cb; } // OTA-Nachrichten von der S3 (Roh-JSON) void onAck(AckCb cb) { _ackCb = cb; } // --- Kommandos (Rueckgabe: vergebene id) --- uint32_t sendHello(); uint32_t sendPing(); uint32_t sendGetState(); uint32_t sendListProfiles(); uint32_t sendGetUsageStats(); // Nutzungsstatistik anfordern uint32_t sendLoadProfile(const String& profile); uint32_t sendGetProfileDetails(const String& profile); uint32_t sendAction(const String& action, const String& value = ""); uint32_t sendSetPid(const String& fieldsJson); // z.B. "\"kpW\":5.0,\"kiW\":0.2" uint32_t sendStartAutotune(const String& target);// "water" | "steam" uint32_t sendStopAutotune(); uint32_t sendScanWifi(); // WLAN-Scan anstossen uint32_t sendSetWifi(const String& ssid, const String& password); // verbinden // Frei-Form: zusaetzliche Felder als bereits serialisiertes JSON-Fragment ohne // aeussere Klammern, z.B. sendCommand("saveBrew", "\"bbtEnabled\":true,\"bbtSecs\":25"); uint32_t sendCommand(const String& op, const String& extraFields = ""); private: void handleLine(const String& line); void applyState(const String& json); void applyProfiles(const String& json); void maintainLink(); MachineState& _state; String _rxBuf; bool _rxOverflow = false; uint32_t _nextId = 1; unsigned long _lastHeartbeatMs = 0; unsigned long _lastHelloMs = 0; StateCb _stateCb = nullptr; ProfilesCb _profilesCb = nullptr; RawJsonCb _profileDetailsCb = nullptr; RawJsonCb _usageStatsCb = nullptr; RawJsonCb _wifiNetworksCb = nullptr; RawJsonCb _otaCb = nullptr; AckCb _ackCb = nullptr; };