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.
This commit is contained in:
+115
-110
@@ -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()
|
||||
}
|
||||
}
|
||||
NoticeBar { }
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user