diff --git a/qml/pages/CommandsPage.qml b/qml/pages/CommandsPage.qml
index b98e420..e6486d9 100644
--- a/qml/pages/CommandsPage.qml
+++ b/qml/pages/CommandsPage.qml
@@ -2,90 +2,142 @@ import QtQuick 2.2
import Sailfish.Silica 1.0
import "../components"
-// Comandi secondari: quelli che non stanno nella home. In cima lo stato
-// attuale, cosi' non si preme alla cieca.
+// Comandi impianto: i comandi che non stanno nella Home.
+//
+// Prima erano 12 pulsanti in quattro sezioni, otto dei quali in coppie
+// accendi/spegni, con lo stato da leggere in sei righe piu' in alto. Ora ogni
+// cosa che ha uno stato e' un interruttore: lo stato si vede e si cambia in un
+// tocco solo (docs/UX-STUDIO.md).
+//
+// Gli interruttori NON anticipano l'impianto: `checked` segue l'ultimo dato
+// vero (automaticCheck: false) e al tocco parte il comando. Se il comando non
+// riesce, l'interruttore non si muove; se riesce, lo stato arriva da solo
+// (ApiClient rilegge il riassunto due secondi dopo).
Page {
id: page
allowedOrientations: Orientation.All
- property string notice: ""
- property bool noticeIsError: false
-
function raw(key) {
return api.summary[key]
}
- function flag(key) {
- return page.raw(key) ? qsTr("yes") : qsTr("no")
+ // La funzione riscaldamento e' abilitata quando i modi configurati della
+ // pompa la comprendono ("PUMP_MODE_STATE_HEATING").
+ function heatingEnabled() {
+ return String(page.raw("configured_modes") || "").indexOf("HEATING") >= 0
}
- function stato(key) {
- return api.modeLabel(page.raw(key))
+ Component.onCompleted: {
+ if (api.configured)
+ api.refresh()
}
- function showNotice(msg, isError) {
- page.notice = msg
- page.noticeIsError = isError === true
- noticeTimer.restart()
- }
-
- Timer {
- id: noticeTimer
- interval: 4000
- onTriggered: page.notice = ""
- }
-
- Connections {
- target: api
- onErrorOccurred: page.showNotice(message, true)
- onCommandFinished: page.showNotice(message, !ok)
- }
+ // Fuori dai pulsanti/interruttori: dentro finirebbero nel loro contentItem.
+ RemorseItem { id: remorse }
SilicaFlickable {
anchors.fill: parent
contentHeight: col.height + Theme.paddingLarge
+ PullDownMenu {
+ MenuItem {
+ text: qsTr("Refresh")
+ onClicked: api.refresh()
+ }
+ MenuItem {
+ text: qsTr("Data")
+ onClicked: pageStack.push(Qt.resolvedUrl("DataPage.qml"))
+ }
+ 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("Other commands") }
+ PageHeader { title: qsTr("Plant commands") }
- Label {
- visible: page.notice.length > 0
- x: Theme.horizontalPageMargin
- width: parent.width - 2 * Theme.horizontalPageMargin
- text: page.notice
- color: page.noticeIsError ? Theme.errorColor : Theme.highlightColor
- font.pixelSize: Theme.fontSizeSmall
- wrapMode: Text.Wrap
+ // ---- modalita' -------------------------------------------------- //
+ SectionHeader { text: qsTr("Modes") }
+
+ TextSwitch {
+ id: awaySwitch
+ text: qsTr("Away mode")
+ description: qsTr("Lowers the house and stops the hot water")
+ automaticCheck: false
+ checked: page.raw("away_mode") === true
+ onClicked: {
+ if (checked)
+ api.sendCommand("away_mode_off")
+ else
+ api.sendCommand("away_mode_on")
+ }
}
- // ---- stato attuale -------------------------------------------- //
- SectionHeader { text: qsTr("Current state") }
+ TextSwitch {
+ text: qsTr("Forced heating")
+ description: qsTr("Heats at full power until you stop it")
+ automaticCheck: false
+ checked: page.raw("force_heating") === true
+ onClicked: {
+ if (checked)
+ api.sendCommand("force_heating_off")
+ else
+ api.sendCommand("force_heating_on")
+ }
+ }
- InfoRow { label: qsTr("Away mode"); value: page.flag("away_mode") }
- InfoRow { label: qsTr("Night mode"); value: page.flag("night_mode") }
- InfoRow { label: qsTr("Forced heating"); value: page.flag("force_heating") }
- InfoRow { label: qsTr("Hot water active"); value: page.flag("hot_water_heating") }
- InfoRow { label: qsTr("Pump"); value: page.stato("pump_active_state") }
- InfoRow { label: qsTr("Allowed modes"); value: page.stato("configured_modes") }
+ TextSwitch {
+ id: heatingSwitch
+ text: qsTr("Heating")
+ description: qsTr("The heating can turn on")
+ automaticCheck: false
+ checked: page.heatingEnabled()
+ onClicked: {
+ // Spegnere il riscaldamento ha conseguenze: si conferma.
+ if (checked)
+ remorse.execute(heatingSwitch, qsTr("Heating will be disabled"),
+ function() { api.sendCommand("heating_off") })
+ else
+ api.sendCommand("heating_on")
+ }
+ }
- // ---- assenza --------------------------------------------------- //
- SectionHeader { text: qsTr("Away mode") }
+ // ---- acqua calda ------------------------------------------------ //
+ SectionHeader { text: qsTr("Domestic hot water") }
+
+ TextSwitch {
+ id: waterSwitch
+ text: qsTr("Hot water active")
+ description: qsTr("The heat pump keeps the water in temperature")
+ automaticCheck: false
+ checked: page.raw("hot_water_heating") === true
+ onClicked: {
+ if (checked)
+ remorse.execute(waterSwitch,
+ qsTr("Domestic hot water will stop being heated"),
+ function() { api.sendCommand("hot_water_heating_off") })
+ else
+ api.sendCommand("hot_water_heating_on")
+ }
+ }
ActionButton {
- text: qsTr("Turn away mode on")
- onTriggered: api.sendCommand("away_mode_on")
- }
- ActionButton {
- text: qsTr("Turn away mode off")
- onTriggered: api.sendCommand("away_mode_off")
+ text: qsTr("Legionella cycle")
+ confirmText: qsTr("Starting the legionella cycle: it takes a while")
+ onTriggered: api.sendCommand("legionella_cycle")
}
- // ---- rumore ---------------------------------------------------- //
+ // ---- rumore ----------------------------------------------------- //
SectionHeader { text: qsTr("Noise") }
ActionButton {
@@ -93,59 +145,13 @@ Page {
onTriggered: api.sendCommand("night_mode_1h")
}
- // ---- riscaldamento --------------------------------------------- //
- SectionHeader { text: qsTr("Heating") }
-
- ActionButton {
- text: qsTr("Force heating")
- confirmText: qsTr("Starting forced heating")
- onTriggered: api.sendCommand("force_heating_on")
- }
- ActionButton {
- text: qsTr("Stop forced heating")
- onTriggered: api.sendCommand("force_heating_off")
- }
- ActionButton {
- text: qsTr("Enable heating function")
- onTriggered: api.sendCommand("heating_on")
- }
- ActionButton {
- text: qsTr("Disable heating function")
- confirmText: qsTr("Heating will be disabled")
- onTriggered: api.sendCommand("heating_off")
- }
-
- // ---- acqua calda ----------------------------------------------- //
- SectionHeader { text: qsTr("Domestic hot water") }
-
- ActionButton {
- text: qsTr("Legionella cycle")
- confirmText: qsTr("Starting the legionella cycle: it takes a while")
- onTriggered: api.sendCommand("legionella_cycle")
- }
- ActionButton {
- text: qsTr("Enable DHW heating")
- onTriggered: api.sendCommand("hot_water_heating_on")
- }
- ActionButton {
- text: qsTr("Disable DHW heating")
- confirmText: qsTr("Domestic hot water will stop being heated")
- onTriggered: api.sendCommand("hot_water_heating_off")
- }
-
- // ---- diagnostica ----------------------------------------------- //
- SectionHeader { text: qsTr("Diagnostics") }
-
- ActionButton {
- text: qsTr("Plant check")
- onTriggered: api.sendCommand("ping")
- }
-
- BusyIndicator {
- visible: api.busy
- anchors.horizontalCenter: parent.horizontalCenter
- size: BusyIndicatorSize.Small
- running: true
+ Label {
+ x: Theme.horizontalPageMargin
+ width: parent.width - 2 * Theme.horizontalPageMargin
+ text: qsTr("The switches show the current state of the plant: the Status section is not needed any more.")
+ color: Theme.secondaryColor
+ font.pixelSize: Theme.fontSizeExtraSmall
+ wrapMode: Text.Wrap
}
Label {
@@ -156,11 +162,10 @@ Page {
font.pixelSize: Theme.fontSizeExtraSmall
wrapMode: Text.Wrap
}
+
+ Item { width: 1; height: Theme.paddingMedium }
}
}
- Component.onCompleted: {
- if (api.configured)
- api.refresh()
- }
-}
\ No newline at end of file
+ NoticeBar { }
+}
diff --git a/qml/pages/DataPage.qml b/qml/pages/DataPage.qml
index 1e2805d..8cef821 100644
--- a/qml/pages/DataPage.qml
+++ b/qml/pages/DataPage.qml
@@ -109,15 +109,8 @@ Page {
wrapMode: Text.Wrap
}
- Label {
- visible: page.error.length > 0
- x: Theme.horizontalPageMargin
- width: parent.width - 2 * Theme.horizontalPageMargin
- text: page.error
- color: Theme.errorColor
- font.pixelSize: Theme.fontSizeSmall
- 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
@@ -242,6 +235,8 @@ Page {
}
}
+ NoticeBar { }
+
Component.onCompleted: {
if (api.configured) {
page.loading = true
diff --git a/qml/pages/PlantPage.qml b/qml/pages/PlantPage.qml
index 37f7bd3..6599745 100644
--- a/qml/pages/PlantPage.qml
+++ b/qml/pages/PlantPage.qml
@@ -71,6 +71,19 @@ Page {
PageHeader { title: qsTr("Plant") }
+ // La frase estesa dell'app ufficiale ("Relax: la pompa di calore
+ // funziona regolarmente"): sta qui e non in Home, dove serve
+ // spazio per le due letture. La calcola il C++ (AiraJson::stateLong).
+ Label {
+ x: Theme.horizontalPageMargin
+ width: parent.width - 2 * Theme.horizontalPageMargin
+ text: api.stateLong()
+ color: Theme.primaryColor
+ font.pixelSize: Theme.fontSizeMedium
+ horizontalAlignment: Text.AlignHCenter
+ wrapMode: Text.Wrap
+ }
+
// ---- stato ------------------------------------------------------ //
SectionHeader { text: qsTr("Status") }
@@ -86,6 +99,11 @@ Page {
InfoRow { label: qsTr("Night mode"); value: page.flag("night_mode") }
InfoRow { label: qsTr("Forced heating"); value: page.flag("force_heating") }
InfoRow { label: qsTr("Inline heater"); value: page.flag("inline_heater") }
+ InfoRow { label: qsTr("Manual mode"); value: page.flag("manual_mode") }
+ InfoRow { label: qsTr("Defrost"); value: page.flag("outdoor_defrost") }
+ InfoRow { label: qsTr("Signature lights"); value: page.flag("signature_lights") }
+ InfoRow { label: qsTr("Pump"); value: api.modeLabel(page.raw("pump_active_state")) }
+ InfoRow { label: qsTr("Allowed modes"); value: api.modeLabel(page.raw("configured_modes")) }
InfoRow { label: qsTr("Outdoor temperature"); value: page.temp("outdoor_temperature") }
InfoRow { label: qsTr("Indoor temperature (pump)"); value: page.temp("indoor_temperature") }
InfoRow { label: qsTr("Zones"); value: page.count("zones") }
@@ -176,10 +194,20 @@ Page {
value: page.count("errors_count")
}
+ // ---- diagnostica ------------------------------------------------ //
+ SectionHeader { text: qsTr("Diagnostics") }
+
+ ActionButton {
+ text: qsTr("Plant check")
+ onTriggered: api.sendCommand("ping")
+ }
+
Item { width: 1; height: Theme.paddingMedium }
}
}
+ NoticeBar { }
+
Component.onCompleted: {
if (api.configured)
api.refresh()
diff --git a/qml/pages/SettingsPage.qml b/qml/pages/SettingsPage.qml
index 423e321..4ea99a6 100644
--- a/qml/pages/SettingsPage.qml
+++ b/qml/pages/SettingsPage.qml
@@ -128,19 +128,11 @@ Page {
wrapMode: Text.Wrap
}
+ // Un pulsante solo: salvare e provare erano due gesti per la stessa
+ // cosa (il secondo salvava comunque).
Button {
anchors.horizontalCenter: parent.horizontalCenter
- text: qsTr("Save")
- onClicked: {
- page.save()
- page.testResult = qsTr("settings saved")
- page.testOk = true
- }
- }
-
- Button {
- anchors.horizontalCenter: parent.horizontalCenter
- text: qsTr("Test connection")
+ text: qsTr("Save and test")
onClicked: page.testAndReport()
}
diff --git a/src/apiclient.cpp b/src/apiclient.cpp
index 4eeeb21..4145463 100644
--- a/src/apiclient.cpp
+++ b/src/apiclient.cpp
@@ -17,6 +17,7 @@ ApiClient::ApiClient(Settings *settings, QObject *parent)
, m_stale(false)
, m_noticeIsError(false)
, m_noticeTimer(0)
+ , m_refreshTimer(0)
{
// Il messaggio dell'ultimo comando (o dell'ultimo errore) vale per ogni
// pagina: lo stato sta qui, si spegne da solo e la UI lo mostra ancorato
@@ -40,6 +41,18 @@ ApiClient::ApiClient(Settings *settings, QObject *parent)
setNotice(message, !ok);
});
+ // Dopo un comando riuscito lo stato si rilegge da solo: l'impianto applica
+ // in qualche istante, e senza questa rilettura gli interruttori della
+ // pagina dei comandi resterebbero indietro rispetto alla pompa.
+ m_refreshTimer = new QTimer(this);
+ m_refreshTimer->setSingleShot(true);
+ m_refreshTimer->setInterval(2000);
+ connect(m_refreshTimer, &QTimer::timeout, this, &ApiClient::refresh);
+ connect(this, &ApiClient::commandFinished, this, [this](bool ok, const QString &) {
+ if (ok)
+ m_refreshTimer->start();
+ });
+
if (m_settings) {
// La UI deve riflettere subito il passaggio da "non configurato" a
// "configurato" quando si salvano indirizzo o token.
diff --git a/src/apiclient.h b/src/apiclient.h
index 6468d14..d05c16c 100644
--- a/src/apiclient.h
+++ b/src/apiclient.h
@@ -105,6 +105,7 @@ private:
QString m_notice;
bool m_noticeIsError;
QTimer *m_noticeTimer;
+ QTimer *m_refreshTimer;
QVariantMap m_summary;
QVariantMap m_stats;
};
diff --git a/translations/harbour-aira-it.ts b/translations/harbour-aira-it.ts
index 0a59ade..3546102 100644
--- a/translations/harbour-aira-it.ts
+++ b/translations/harbour-aira-it.ts
@@ -96,7 +96,7 @@
Heating the hot water
- Sta scaldando l'acqua
+ Sta scaldando l'acqua
@@ -111,12 +111,12 @@
Attention: one error on the plant
- Attenzione: un errore sull'impianto
+ Attenzione: un errore sull'impianto
Attention: %1 errors on the plant
- Attenzione: %1 errori sull'impianto
+ Attenzione: %1 errori sull'impianto
@@ -136,7 +136,7 @@
The heat pump is heating the hot water.
- La pompa di calore sta scaldando l'acqua calda.
+ La pompa di calore sta scaldando l'acqua calda.
@@ -152,66 +152,66 @@
ApiClient
-
+
Bridge address not configured
Indirizzo del bridge non configurato
-
-
-
+
+
+
Set the bridge address and token
Configura indirizzo e token del bridge
-
+
Server unreachable (timeout)
Server non raggiungibile (timeout)
-
-
+
+
Unreadable response from the bridge
Risposta del bridge non interpretabile
-
+
Enter the bridge address
Inserisci l'indirizzo del bridge
-
+
Timeout: no response
Timeout: nessuna risposta
-
+
Unreachable (HTTP %1)
Irraggiungibile (HTTP %1)
-
+
Bridge reachable
Bridge raggiungibile
-
-
+
+
Bridge not configured
Bridge non configurato
-
+
Timeout: no statistics
Timeout: statistiche non disponibili
-
+
Timeout: command not sent
Timeout: comando non inviato
-
+
Command sent
Comando inviato
@@ -219,153 +219,117 @@
CommandsPage
-
- yes
- sì
-
-
-
- no
- no
-
-
-
- Other commands
- Altri comandi
-
-
-
- Current state
- Stato attuale
-
-
-
-
+
Away mode
Assenza
-
- Night mode
- Night mode
-
-
-
+
Forced heating
Riscaldamento forzato
-
+
Hot water active
Acqua calda attiva
-
- Pump
- Pompa
-
-
-
- Allowed modes
- Modalità consentite
-
-
-
- Turn away mode on
- Attiva assenza
-
-
-
- Turn away mode off
- Disattiva assenza
-
-
-
+
Noise
Rumore
-
+
Night mode for one hour
Night mode per un'ora
-
+
Heating
Riscaldamento
-
- Force heating
- Forza riscaldamento
+
+ Refresh
+ Aggiorna
-
- Starting forced heating
- Avvio del riscaldamento forzato
+
+ Data
+ Dati
-
- Stop forced heating
- Ferma riscaldamento forzato
+
+ Plant
+ Impianto
-
- Enable heating function
- Abilita funzione riscaldamento
+
+ Settings
+ Impostazioni
-
- Disable heating function
- Disabilita funzione riscaldamento
+
+ Plant commands
+ Comandi impianto
-
+
+ Modes
+ Modalità
+
+
+
+ Lowers the house and stops the hot water
+ Abbassa la casa e spegne l'acqua calda
+
+
+
+ Heats at full power until you stop it
+ Scalda a pieno regime finché non lo fermi
+
+
+
+ The heating can turn on
+ Il riscaldamento può accendersi
+
+
+
Heating will be disabled
Il riscaldamento verrà disabilitato
-
+
Domestic hot water
Acqua calda sanitaria
-
+
+ The heat pump keeps the water in temperature
+ Mantiene l'acqua in temperatura
+
+
+
Legionella cycle
Ciclo antilegionella
-
+
Starting the legionella cycle: it takes a while
Avvio del ciclo antilegionella: richiede tempo
+
+
+ The switches show the current state of the plant: the Status section is not needed any more.
+ Gli interruttori mostrano lo stato attuale: la sezione Stato non serve più.
+
- Enable DHW heating
- Abilita riscaldamento ACS
-
-
-
- Disable DHW heating
- Disabilita riscaldamento ACS
-
-
-
Domestic hot water will stop being heated
L'acqua calda smetterà di essere riscaldata
-
- Diagnostics
- Diagnostica
-
-
-
- Plant check
- Verifica impianto
-
-
-
+
Commands go through the bridge and may take a few seconds. The status refreshes by itself afterwards.
I comandi passano dal bridge e possono richiedere qualche secondo. Dopo l'invio lo stato si aggiorna da solo.
@@ -421,97 +385,97 @@
Numeri calcolati da Aira nel cloud: l'app li legge soltanto dal tuo bridge.
-
+
Reading the data...
Lettura dei dati in corso...
-
+
Month of %1
Mese di %1
-
+
This month
Questo mese
-
+
Heat produced
Calore prodotto
-
+
What the heat pump gave the house
Quanto la pompa ha dato alla casa
-
+
Electricity used
Elettricità usata
-
+
What the heat pump took from the grid
Quanta ne ha presa dalla rete
-
+
Efficiency, domestic hot water
Efficienza, acqua calda
-
+
Efficiency, heating
Efficienza, riscaldamento
-
+
Efficiency (COP) is how much heat the pump delivers for each unit of electricity: higher is better.
L'efficienza (COP) è quanto calore la pompa produce per ogni unità di elettricità: più alta è, meglio è.
-
+
Your savings, last %1 days
I tuoi risparmi, ultimi %1 giorni
-
+
Saved on the bill
Risparmiati in bolletta
-
+
Compared with a gas boiler
Rispetto a una caldaia a gas
-
+
CO₂ avoided
CO₂ evitata
-
+
Not released into the air
Non immessa nell'aria
-
+
Smart Tariff Control
Smart Tariff Control
-
+
Saving from heating when energy is cheaper
Risparmio scaldando quando l'energia costa meno
-
+
Efficiency month by month
Efficienza mese per mese
-
+
Savings month by month
Risparmi mese per mese
@@ -659,165 +623,200 @@
Impianto
-
+
Status
Stato
-
+
Connection
Connessione
-
+
Mode
Modalità
-
+
Away mode
Modalità assenza
-
+
Night mode
Modalità notte
-
+
Forced heating
Riscaldamento forzato
-
+
Inline heater
Resistenza interna
-
+
+ Manual mode
+ Modalità manuale
+
+
+
+ Defrost
+ Sbrinamento
+
+
+
+ Signature lights
+ Luci di firma
+
+
+
+ Pump
+ Pompa
+
+
+
+ Allowed modes
+ Modi consentiti
+
+
+
Outdoor temperature
Temperatura esterna
-
+
Indoor temperature (pump)
Temperatura interna (pompa)
-
+
Zones
Zone
-
+
Last reading
Ultima lettura
-
+
Accessories
Accessori
-
+
No wall thermostat
Nessun termostato a parete
-
+
Aira wall thermostat
Termostato a parete Aira
-
+
Zone %1 · Connected
Zona %1 · Connesso
-
+
Measured temperature
Temperatura misurata
-
+
Humidity
Umidità
-
+
Signal
Segnale
-
+
Battery
Batteria
-
+
low
scarica
-
+
ok
ok
-
+
Article
Articolo
-
+
Versions
Versioni
-
+
Device ID
ID dispositivo
-
+
Platform
Piattaforma
-
+
Connectivity
Connettività
-
+
Climate control
Controllo climatico
-
+
Outdoor unit
Unità esterna
-
+
Outdoor unit EEPROM
EEPROM unità esterna
-
+
Errors
Errori
-
+
No errors reported by the plant.
Nessun errore segnalato dall'impianto.
-
+
Errors reported
Errori segnalati
+
+
+ Diagnostics
+ Diagnostica
+
+
+
+ Plant check
+ Verifica impianto
+
SetpointsPage
@@ -859,7 +858,7 @@
What the plant is keeping now
- Quello che l'impianto mantiene adesso
+ Quello che l'impianto mantiene adesso
@@ -934,7 +933,7 @@
Commands go through the bridge and may take a few seconds. The status refreshes by itself afterwards.
- I comandi passano dal bridge e possono richiedere qualche secondo. Dopo l'invio lo stato si aggiorna da solo.
+ I comandi passano dal bridge e possono richiedere qualche secondo. Dopo l'invio lo stato si aggiorna da solo.
@@ -987,19 +986,9 @@
Indirizzo e token si leggono sul server: il token è in aira_bridge.json accanto al bridge. Senza schema viene usato http://.
-
- Save
- Salva
-
-
-
- settings saved
- impostazioni salvate
-
-
-
- Test connection
- Prova connessione
+
+ Save and test
+ Salva e prova