#ifndef APICLIENT_H #define APICLIENT_H #include #include #include #include class QNetworkReply; class QTimer; class Settings; // Client HTTP verso il bridge sul server (~/workspace/Carlo/Aira/aira_bridge.py). // Non parla con il cloud Aira: Qt 5.6 non ha HTTP/2, quindi il gRPC resta sul // server e qui arrivano solo JSON. class ApiClient : public QObject { Q_OBJECT Q_PROPERTY(bool busy READ busy NOTIFY busyChanged) Q_PROPERTY(bool configured READ configured NOTIFY configuredChanged) // Ultimo riassunto letto. Sta in C++ (context property) e non nel QML: // le property dell'ApplicationWindow NON sono visibili alle pagine dello // pageStack, quindi la dashboard e la copertina non potrebbero condividerle. Q_PROPERTY(QVariantMap summary READ summary NOTIFY summaryChanged) // Statistiche della pagina "Dati" (calore, elettricita', COP, risparmi). // Separata dal riassunto: e' una chiamata piu' lenta, con cache lato bridge. Q_PROPERTY(QVariantMap stats READ stats NOTIFY statsChanged) // Salute dell'aggiornamento: "stale" = l'ultimo tentativo non e' riuscito, // quindi i numeri a schermo sono vecchi e vanno mostrati spenti. Q_PROPERTY(bool stale READ stale NOTIFY staleChanged) Q_PROPERTY(QString lastUpdate READ lastUpdate NOTIFY lastUpdateChanged) Q_PROPERTY(bool hasData READ hasData NOTIFY summaryChanged) // Messaggio dell'ultimo comando (o errore), mostrato in fondo alla pagina: // sta qui e non nel QML perche' vale per OGNI pagina, e perche' cosi' il // messaggio e' lo stesso ovunque si stia. Q_PROPERTY(QString notice READ notice NOTIFY noticeChanged) Q_PROPERTY(bool noticeIsError READ noticeIsError NOTIFY noticeChanged) public: explicit ApiClient(Settings *settings, QObject *parent = 0); bool busy() const { return m_busy; } bool configured() const; QVariantMap summary() const { return m_summary; } QVariantMap stats() const { return m_stats; } bool stale() const { return m_stale; } QString lastUpdate() const { return m_lastUpdate; } bool hasData() const { return !m_summary.isEmpty(); } QString notice() const { return m_notice; } bool noticeIsError() const { return m_noticeIsError; } // Stato leggibile in una riga (stateShort) e per esteso (stateLong), piu' // il livello da cui la UI prende il colore. Stanno in C++ perche' sono // logica pura: verificate in tests/core_test.cpp e non duplicate fra pagine. Q_INVOKABLE QString stateShort() const; Q_INVOKABLE QString stateLong() const; Q_INVOKABLE int statusLevel() const; // Scarica il riassunto e lo emette con summaryChanged(). Q_INVOKABLE void refresh(); // Scarica le statistiche (GET /stats) e le emette con statsChanged(). Q_INVOKABLE void refreshStats(); // Prova GET /health (non richiede token) e risponde con connectionTested(). Q_INVOKABLE void testConnection(); // Invia un comando: sendCommand("set_hot_water_target", 55). Q_INVOKABLE void sendCommand(const QString &id, const QVariant &value = QVariant()); // Formattazione per la UI: unica fonte di verita' in C++ (testata in // tests/core_test.cpp), niente duplicazione di logica nel QML. Q_INVOKABLE QString modeLabel(const QString &operatingStatus) const; Q_INVOKABLE QString formatValue(const QVariant &value) const; Q_INVOKABLE QString formatNumber(const QVariant &value, int decimals) const; Q_INVOKABLE QString formatMoney(const QVariant &value, const QString ¤cyCode) const; Q_INVOKABLE QString monthLabel(const QString &yearMonth) const; signals: void busyChanged(); void configuredChanged(); void staleChanged(); void lastUpdateChanged(); void noticeChanged(); void summaryChanged(const QVariantMap &summary); void statsChanged(const QVariantMap &stats); void statsRefreshed(bool ok, const QString &message); void commandFinished(bool ok, const QString &message); void connectionTested(bool ok, const QString &message); void errorOccurred(const QString &message); private: QNetworkReply *send(const QByteArray &verb, const QString &path, const QByteArray &body, int timeoutSec); void armTimeout(QNetworkReply *reply, int seconds); void setBusy(bool value); // Mostra un messaggio in fondo alla pagina per qualche secondo. void setNotice(const QString &message, bool isError); Settings *m_settings; QNetworkAccessManager m_nam; bool m_busy; bool m_stale; QString m_lastUpdate; QString m_notice; bool m_noticeIsError; QTimer *m_noticeTimer; QTimer *m_refreshTimer; QVariantMap m_summary; QVariantMap m_stats; }; #endif // APICLIENT_H