- Home: stato in una riga col pallino, due letture grandi toccabili, tre azioni rapide; via i due slider, i sette pulsanti e la scheda separata. - Nuova pagina Regolazioni: un blocco per grandezza, valore attuale sempre visibile, preimpostazioni per le dita fredde, conferma esplicita; il pulsante e' attivo solo se c'e' davvero qualcosa da cambiare. - Messaggi dei comandi spostati in ApiClient (api.notice) con NoticeBar ancorata in fondo: prima nascevano fuori dallo schermo. - Stato breve/esteso/livello in C++ (testabile senza SDK), 18 verifiche nuove: 79/79. - stale + lastUpdate: la Home dice 'aggiornato alle HH:MM' e spegne i numeri vecchi invece di farli passare per freschi. - 192/192 stringhe tradotte (54 nuove).
235 lines
8.0 KiB
QML
235 lines
8.0 KiB
QML
import QtQuick 2.2
|
|
import Sailfish.Silica 1.0
|
|
import "../components"
|
|
|
|
// Regolazioni: le grandezze che si cambiano (obiettivo casa, obiettivo acqua
|
|
// calda) e il boost, ognuna con il valore attuale sempre visibile, le
|
|
// preimpostazioni per le dita fredde e la conferma esplicita.
|
|
//
|
|
// Pagina a parte perche' la Home deve restare una schermata da guardare: due
|
|
// slider dentro la pagina che scorre si contendevano anche il trascinamento.
|
|
// Qui lo slider e' la PROPOSTA, il numero grande e' quello vero dell'impianto:
|
|
// i due coincidono solo dopo "Imposta".
|
|
Page {
|
|
id: page
|
|
|
|
allowedOrientations: Orientation.All
|
|
|
|
property real pendingHouse: 0
|
|
property bool houseTouched: false
|
|
property real pendingWater: 0
|
|
property bool waterTouched: false
|
|
|
|
function raw(key) {
|
|
return api.summary[key]
|
|
}
|
|
|
|
function fmt(value) { return api.formatValue(value) }
|
|
|
|
// Obiettivo vero dell'impianto (zona 1), a passi di mezzo grado.
|
|
function houseTarget() {
|
|
var v = page.raw("zone1_setpoint")
|
|
if (v === undefined || v === null || Number(v) <= 0)
|
|
return 0
|
|
return Math.round(Number(v) * 2) / 2
|
|
}
|
|
|
|
function waterTarget() {
|
|
var v = page.raw("dhw_target")
|
|
if (v === undefined || v === null)
|
|
return 0
|
|
return Math.round(Number(v))
|
|
}
|
|
|
|
// Allinea le proposte ai valori dell'impianto, ma non sovrascrive quello
|
|
// che l'utente sta scegliendo.
|
|
function syncFromPlant() {
|
|
if (!page.houseTouched)
|
|
page.pendingHouse = page.houseTarget()
|
|
if (!page.waterTouched)
|
|
page.pendingWater = page.waterTarget()
|
|
}
|
|
|
|
function houseChanged() { return Math.abs(page.pendingHouse - page.houseTarget()) > 0.001 }
|
|
function waterChanged() { return Math.abs(page.pendingWater - page.waterTarget()) > 0.001 }
|
|
|
|
Component.onCompleted: {
|
|
page.syncFromPlant()
|
|
if (api.configured)
|
|
api.refresh()
|
|
}
|
|
|
|
Connections {
|
|
target: api
|
|
onSummaryChanged: page.syncFromPlant()
|
|
}
|
|
|
|
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("Setpoints") }
|
|
|
|
// ---- riscaldamento casa ---------------------------------------- //
|
|
SectionHeader { text: qsTr("Heating the house") }
|
|
|
|
ValueRow {
|
|
title: qsTr("Current target")
|
|
subtitle: qsTr("What the plant is keeping now")
|
|
value: page.fmt(page.houseTarget()) + " °C"
|
|
}
|
|
|
|
Slider {
|
|
id: casaSlider
|
|
width: parent.width
|
|
label: qsTr("New house target")
|
|
minimumValue: 5
|
|
maximumValue: 30
|
|
stepSize: 0.5
|
|
value: page.pendingHouse
|
|
valueText: page.fmt(value) + " °C"
|
|
onValueChanged: {
|
|
// Solo un movimento vero dell'utente segna "toccato": il
|
|
// valore che arriva dall'impianto non deve bloccarlo.
|
|
if (Math.abs(page.pendingHouse - value) > 0.001) {
|
|
page.houseTouched = true
|
|
page.pendingHouse = Math.round(value * 2) / 2
|
|
}
|
|
}
|
|
}
|
|
|
|
Row {
|
|
x: Theme.horizontalPageMargin
|
|
width: col.width - 2 * Theme.horizontalPageMargin
|
|
spacing: Theme.paddingSmall
|
|
|
|
Repeater {
|
|
model: [16, 17, 18, 19, 20, 21]
|
|
|
|
Button {
|
|
width: (col.width - 2 * Theme.horizontalPageMargin
|
|
- 5 * Theme.paddingSmall) / 6
|
|
text: modelData + "°"
|
|
onClicked: {
|
|
page.houseTouched = true
|
|
page.pendingHouse = modelData
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ActionButton {
|
|
text: qsTr("Set house to %1 °C").arg(page.fmt(page.pendingHouse))
|
|
confirmText: qsTr("House temperature to %1 °C").arg(page.fmt(page.pendingHouse))
|
|
enabled: page.houseChanged()
|
|
onTriggered: api.sendCommand("set_heating_setpoint", page.pendingHouse)
|
|
}
|
|
|
|
// ---- acqua calda sanitaria ------------------------------------- //
|
|
SectionHeader { text: qsTr("Domestic hot water") }
|
|
|
|
ValueRow {
|
|
title: qsTr("DHW target")
|
|
subtitle: qsTr("Water now %1 °C").arg(page.fmt(page.raw("dhw_current")))
|
|
value: page.fmt(page.waterTarget()) + " °C"
|
|
}
|
|
|
|
Slider {
|
|
id: acquaSlider
|
|
width: parent.width
|
|
label: qsTr("New target")
|
|
minimumValue: 45
|
|
maximumValue: 60
|
|
stepSize: 1
|
|
value: page.pendingWater
|
|
valueText: page.fmt(value) + " °C"
|
|
onValueChanged: {
|
|
if (Math.abs(page.pendingWater - value) > 0.001) {
|
|
page.waterTouched = true
|
|
page.pendingWater = Math.round(value)
|
|
}
|
|
}
|
|
}
|
|
|
|
Row {
|
|
x: Theme.horizontalPageMargin
|
|
width: col.width - 2 * Theme.horizontalPageMargin
|
|
spacing: Theme.paddingSmall
|
|
|
|
Repeater {
|
|
model: [45, 47, 50, 55, 60]
|
|
|
|
Button {
|
|
width: (col.width - 2 * Theme.horizontalPageMargin
|
|
- 4 * Theme.paddingSmall) / 5
|
|
text: modelData + "°"
|
|
onClicked: {
|
|
page.waterTouched = true
|
|
page.pendingWater = modelData
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ActionButton {
|
|
text: qsTr("Set target %1 °C").arg(page.fmt(page.pendingWater))
|
|
confirmText: qsTr("DHW target to %1 °C").arg(page.fmt(page.pendingWater))
|
|
enabled: page.waterChanged()
|
|
onTriggered: api.sendCommand("set_hot_water_target", page.pendingWater)
|
|
}
|
|
|
|
// ---- boost ------------------------------------------------------ //
|
|
SectionHeader { text: qsTr("Hot water boost") }
|
|
|
|
ActionButton {
|
|
text: qsTr("Start DHW boost")
|
|
confirmText: qsTr("Starting DHW boost")
|
|
onTriggered: api.sendCommand("hot_water_boost_on")
|
|
}
|
|
|
|
ActionButton {
|
|
text: qsTr("Stop DHW boost")
|
|
confirmText: qsTr("Stopping DHW boost")
|
|
onTriggered: api.sendCommand("hot_water_boost_off")
|
|
}
|
|
|
|
Label {
|
|
x: Theme.horizontalPageMargin
|
|
width: parent.width - 2 * Theme.horizontalPageMargin
|
|
text: qsTr("Commands go through the bridge and may take a few seconds. The status refreshes by itself afterwards.")
|
|
color: Theme.secondaryColor
|
|
font.pixelSize: Theme.fontSizeExtraSmall
|
|
wrapMode: Text.Wrap
|
|
}
|
|
|
|
Item { width: 1; height: Theme.paddingMedium }
|
|
}
|
|
}
|
|
|
|
NoticeBar { }
|
|
}
|