Files
kaneda d5b63b57df 0.6.0 blocco 1: Home di consultazione e pagina Regolazioni
- 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).
2026-10-10 09:47:16 +02:00

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 { }
}