Files
harbour-aira/qml/pages/DataPage.qml
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

247 lines
7.9 KiB
QML

import QtQuick 2.2
import Sailfish.Silica 1.0
import "../components"
// Dati: calore prodotto, elettricita' usata, efficienza (COP) e risparmi, come
// la scheda "Dati" dell'app ufficiale. Sono numeri che Aira calcola nel cloud:
// il bridge li legge in sola lettura e li tiene in cache per 10 minuti.
Page {
id: page
allowedOrientations: Orientation.All
// La pagina non ha solo la lettura: mostra anche cosa sta facendo.
property bool loading: false
property string error: ""
function stats() {
return api.stats
}
function mese() {
return page.stats()["month"] || {}
}
function risparmi() {
return page.stats()["savings"] || {}
}
function tariffa() {
return page.stats()["smart_tariff"] || {}
}
function valuta() {
return page.stats()["currency"] || "EUR"
}
function kwh(valore) {
if (valore === undefined || valore === null)
return "—"
return api.formatValue(valore) + " kWh"
}
// Il COP ha due decimali, la temperatura uno: per questo non basta fmt().
function cop(valore) {
if (valore === undefined || valore === null)
return qsTr("no data")
return api.formatNumber(valore, 2)
}
function soldi(valore) {
if (valore === undefined || valore === null)
return "—"
return api.formatMoney(valore, page.valuta())
}
function meseNome(chiave) {
return api.monthLabel(chiave)
}
Connections {
target: api
onStatsChanged: {
page.error = ""
page.loading = false
}
onStatsRefreshed: {
page.loading = false
if (!ok)
page.error = message
}
onErrorOccurred: page.error = message
}
SilicaFlickable {
anchors.fill: parent
contentHeight: col.height + Theme.paddingLarge
PullDownMenu {
MenuItem {
text: qsTr("Refresh")
onClicked: {
page.loading = true
api.refreshStats()
}
}
MenuItem {
text: qsTr("Plant")
onClicked: pageStack.push(Qt.resolvedUrl("PlantPage.qml"))
}
MenuItem {
text: qsTr("Settings")
onClicked: pageStack.push(Qt.resolvedUrl("SettingsPage.qml"))
}
}
Column {
id: col
width: parent.width
spacing: Theme.paddingSmall
PageHeader { title: qsTr("Data") }
Label {
x: Theme.horizontalPageMargin
width: parent.width - 2 * Theme.horizontalPageMargin
text: qsTr("Numbers calculated by Aira in the cloud: the app only reads them from your own bridge.")
color: Theme.secondaryColor
font.pixelSize: Theme.fontSizeExtraSmall
wrapMode: Text.Wrap
}
// Gli errori non si mostrano piu' qui dentro: il messaggio arriva
// ancorato in fondo alla pagina (NoticeBar), dove si vede sempre.
Label {
visible: Object.keys(page.stats()).length === 0 && page.error.length === 0
x: Theme.horizontalPageMargin
width: parent.width - 2 * Theme.horizontalPageMargin
text: qsTr("Reading the data...")
color: Theme.secondaryColor
font.pixelSize: Theme.fontSizeSmall
wrapMode: Text.Wrap
}
// ---- energia e efficienza del mese ----------------------------- //
SectionHeader {
visible: Object.keys(page.stats()).length > 0
text: page.mese()["label"]
? qsTr("Month of %1").arg(page.meseNome(page.mese()["label"]))
: qsTr("This month")
}
ValueRow {
visible: Object.keys(page.stats()).length > 0
title: qsTr("Heat produced")
subtitle: qsTr("What the heat pump gave the house")
value: page.kwh(page.mese()["heat_kwh"])
}
ValueRow {
visible: Object.keys(page.stats()).length > 0
title: qsTr("Electricity used")
subtitle: qsTr("What the heat pump took from the grid")
value: page.kwh(page.mese()["energy_kwh"])
}
InfoRow {
visible: Object.keys(page.stats()).length > 0
label: qsTr("Efficiency, domestic hot water")
value: page.cop(page.mese()["cop_dhw"])
}
InfoRow {
visible: Object.keys(page.stats()).length > 0
label: qsTr("Efficiency, heating")
value: page.cop(page.mese()["cop_heating"])
}
Label {
visible: Object.keys(page.stats()).length > 0
x: Theme.horizontalPageMargin
width: parent.width - 2 * Theme.horizontalPageMargin
text: qsTr("Efficiency (COP) is how much heat the pump delivers for each unit of electricity: higher is better.")
color: Theme.secondaryColor
font.pixelSize: Theme.fontSizeExtraSmall
wrapMode: Text.Wrap
}
// ---- risparmi --------------------------------------------------- //
SectionHeader {
visible: Object.keys(page.risparmi()).length > 0
text: qsTr("Your savings, last %1 days").arg(page.stats()["period_days"] || 30)
}
ValueRow {
visible: Object.keys(page.risparmi()).length > 0
title: qsTr("Saved on the bill")
subtitle: qsTr("Compared with a gas boiler")
value: page.soldi(page.risparmi()["amount"])
valueColor: Theme.highlightColor
}
ValueRow {
visible: Object.keys(page.risparmi()).length > 0
title: qsTr("CO₂ avoided")
subtitle: qsTr("Not released into the air")
value: api.formatValue(page.risparmi()["co2_kg"]) + " kg"
}
ValueRow {
visible: Object.keys(page.tariffa()).length > 0
title: qsTr("Smart Tariff Control")
subtitle: qsTr("Saving from heating when energy is cheaper")
value: page.soldi(page.tariffa()["amount"])
valueColor: Theme.highlightColor
}
// ---- dettaglio mese per mese ------------------------------------ //
SectionHeader {
visible: page.stats()["cop_monthly"] && page.stats()["cop_monthly"].length > 0
text: qsTr("Efficiency month by month")
}
Repeater {
model: page.stats()["cop_monthly"] || []
InfoRow {
label: page.meseNome(modelData["month"])
value: page.cop(modelData["dhw_cop"])
}
}
SectionHeader {
visible: page.stats()["monthly_savings"] && page.stats()["monthly_savings"].length > 0
text: qsTr("Savings month by month")
}
Repeater {
model: page.stats()["monthly_savings"] || []
InfoRow {
label: page.meseNome(modelData["month"])
value: page.soldi(modelData["amount"])
}
}
BusyIndicator {
visible: page.loading
anchors.horizontalCenter: parent.horizontalCenter
size: BusyIndicatorSize.Small
running: true
}
Item { width: 1; height: Theme.paddingMedium }
}
}
NoticeBar { }
Component.onCompleted: {
if (api.configured) {
page.loading = true
api.refreshStats()
}
}
}