Files
harbour-aira/src/apiclient.h
T
kaneda 85702880d5 0.6.0 blocco 2: Comandi impianto con interruttori, diagnostica in Impianto
- CommandsPage: 4 interruttori (TextSwitch) al posto di 8 pulsanti in coppie
  accendi/spegni, piu' 3 pulsanti per le azioni senza stato. Gli interruttori
  seguono il dato vero (automaticCheck: false), non anticipano l'impianto, e
  la sezione 'Stato attuale' non serve piu'.
- La pagina si chiama 'Comandi impianto'.
- PlantPage: frase estesa dello stato, diagnostica (verifica impianto) e le
  letture che non avevano posto (pompa, modi consentiti, manuale, sbrinamento,
  luci di firma).
- SettingsPage: 'Salva' e 'Prova connessione' diventano 'Salva e prova'.
- ApiClient: dopo un comando riuscito lo stato si rilegge da solo (prima non
  si aggiornava nulla: l'aggiornamento automatico non esisteva).
- NoticeBar anche su Dati, Impianto e Comandi; via i messaggi dentro il
  contenuto che scorre.
2026-10-10 09:48:41 +02:00

114 lines
4.7 KiB
C++

#ifndef APICLIENT_H
#define APICLIENT_H
#include <QNetworkAccessManager>
#include <QObject>
#include <QVariant>
#include <QVariantMap>
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 &currencyCode) 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