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).
This commit is contained in:
@@ -0,0 +1,42 @@
|
|||||||
|
import QtQuick 2.2
|
||||||
|
import Sailfish.Silica 1.0
|
||||||
|
|
||||||
|
// Messaggio dell'ultimo comando, ancorato al bordo inferiore della pagina.
|
||||||
|
//
|
||||||
|
// Sta FUORI dal contenuto che scorre: prima il messaggio era la prima riga
|
||||||
|
// della colonna, quindi premendo un pulsante in fondo alla pagina nasceva
|
||||||
|
// fuori dallo schermo e non si capiva se il comando fosse partito.
|
||||||
|
//
|
||||||
|
// Lo stato sta in ApiClient (api.notice): qui si mostra e basta, cosi' il
|
||||||
|
// messaggio e' lo stesso su qualsiasi pagina.
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
height: message.height + 2 * Theme.paddingMedium
|
||||||
|
color: Qt.rgba(0, 0, 0, 0.78)
|
||||||
|
opacity: api.notice.length > 0 ? 1 : 0
|
||||||
|
visible: opacity > 0
|
||||||
|
z: 100
|
||||||
|
|
||||||
|
Behavior on opacity { NumberAnimation { duration: 200 } }
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: message
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
leftMargin: Theme.horizontalPageMargin
|
||||||
|
rightMargin: Theme.horizontalPageMargin
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
text: api.notice
|
||||||
|
color: api.noticeIsError ? Theme.errorColor : Theme.highlightColor
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import QtQuick 2.2
|
||||||
|
import Sailfish.Silica 1.0
|
||||||
|
|
||||||
|
// Riquadro di una lettura grande nella Home: titolo, valore, riga sotto e la
|
||||||
|
// barra di avanzamento (facoltativa). Toccabile: porta alle regolazioni.
|
||||||
|
//
|
||||||
|
// La barra c'e' sempre, anche quando non serve, e resta trasparente: cosi' i
|
||||||
|
// due riquadri affiancati hanno la stessa altezza senza vincoli circolari.
|
||||||
|
BackgroundItem {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string title: ""
|
||||||
|
property string value: ""
|
||||||
|
property string subtitle: ""
|
||||||
|
property real progress: 0
|
||||||
|
property bool showBar: false
|
||||||
|
property color valueColor: Theme.primaryColor
|
||||||
|
|
||||||
|
signal tapped()
|
||||||
|
|
||||||
|
height: content.height + 2 * Theme.paddingMedium
|
||||||
|
|
||||||
|
onClicked: root.tapped()
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: content
|
||||||
|
x: Theme.paddingMedium
|
||||||
|
y: Theme.paddingMedium
|
||||||
|
width: parent.width - 2 * Theme.paddingMedium
|
||||||
|
spacing: Theme.paddingSmall
|
||||||
|
|
||||||
|
Label {
|
||||||
|
width: parent.width
|
||||||
|
text: root.title
|
||||||
|
color: Theme.secondaryColor
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
width: parent.width
|
||||||
|
text: root.value
|
||||||
|
color: root.valueColor
|
||||||
|
font.pixelSize: Theme.fontSizeHuge
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
width: parent.width
|
||||||
|
text: root.subtitle
|
||||||
|
color: Theme.secondaryColor
|
||||||
|
font.pixelSize: Theme.fontSizeExtraSmall
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressBar {
|
||||||
|
width: parent.width
|
||||||
|
value: Math.max(0, Math.min(1, root.progress))
|
||||||
|
opacity: root.showBar ? 1 : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+174
-376
@@ -2,27 +2,65 @@ import QtQuick 2.2
|
|||||||
import Sailfish.Silica 1.0
|
import Sailfish.Silica 1.0
|
||||||
import "../components"
|
import "../components"
|
||||||
|
|
||||||
// Dashboard dell'impianto, ordinata come la schermata iniziale dell'app
|
// Home: una schermata da GUARDARE, non un modulo da compilare.
|
||||||
// ufficiale Aira: in alto la temperatura esterna, poi il messaggio di stato,
|
//
|
||||||
// poi la scheda dell'impianto con le due letture principali (casa e acqua
|
// Stato in una riga, le due letture che contano (casa e acqua calda), tre
|
||||||
// calda). I comandi restano piu' sotto, perche' qui si possono dare davvero.
|
// azioni rapide. Le regolazioni stanno in SetpointsPage, gli altri comandi in
|
||||||
// Legge api.summary (QVariantMap dal C++), quindi non dipende dallo scope
|
// CommandsPage, i numeri in DataPage, i dettagli in PlantPage: qui solo quello
|
||||||
// delle property del main qml.
|
// che si guarda molte volte al giorno, senza scorrere (docs/UX-STUDIO.md).
|
||||||
Page {
|
Page {
|
||||||
id: page
|
id: page
|
||||||
|
|
||||||
allowedOrientations: Orientation.All
|
allowedOrientations: Orientation.All
|
||||||
|
|
||||||
// obiettivo ACS scelto dall'utente (non sovrascritto dal refresh finche'
|
function raw(key) {
|
||||||
// non lo tocca, altrimenti lo slider "salta" a ogni lettura)
|
return api.summary[key]
|
||||||
property int targetAcs: 55
|
}
|
||||||
property bool targetAcsTouched: false
|
|
||||||
// obiettivo della casa (zona 1); parte dalla temperatura attuale e non
|
// I numeri si formattano nel C++ (ApiClient::formatValue): cosi' il
|
||||||
// viene sovrascritto dal refresh finche' l'utente non lo tocca
|
// separatore decimale segue la lingua dell'app, non il toFixed di JS.
|
||||||
property real targetCasa: 20
|
function fmt(value) { return api.formatValue(value) }
|
||||||
property bool targetCasaTouched: false
|
|
||||||
property string notice: ""
|
function count(key) {
|
||||||
property bool noticeIsError: false
|
var v = page.raw(key)
|
||||||
|
if (v === undefined || v === null)
|
||||||
|
return "—"
|
||||||
|
return String(Math.round(Number(v)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Colore del pallino di stato. Il livello (0 regolare, 1 modo attivo,
|
||||||
|
// 2 errore) lo calcola il C++; qui si sceglie il colore, e l'ambra quando
|
||||||
|
// i numeri sono vecchi: un dato vecchio non e' un dato buono.
|
||||||
|
function statusColor() {
|
||||||
|
if (!api.hasData || api.stale)
|
||||||
|
return "orange"
|
||||||
|
var livello = api.statusLevel()
|
||||||
|
if (livello === 2)
|
||||||
|
return Theme.errorColor
|
||||||
|
if (livello === 1)
|
||||||
|
return Theme.highlightColor
|
||||||
|
return "#4caf50"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quanto e' carica l'acqua calda verso l'obiettivo (da 10 °C in su).
|
||||||
|
function waterProgress() {
|
||||||
|
var ora = Number(page.raw("dhw_current"))
|
||||||
|
var obiettivo = Number(page.raw("dhw_target"))
|
||||||
|
if (!(obiettivo > 10) || isNaN(ora))
|
||||||
|
return 0
|
||||||
|
return (ora - 10) / (obiettivo - 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Riga sotto il titolo: dice anche quando i numeri sono vecchi.
|
||||||
|
function updateText() {
|
||||||
|
if (!api.hasData)
|
||||||
|
return qsTr("No data yet")
|
||||||
|
if (api.stale)
|
||||||
|
return qsTr("Not updated · last %1").arg(api.lastUpdate)
|
||||||
|
if (api.lastUpdate.length === 0)
|
||||||
|
return ""
|
||||||
|
return qsTr("Updated at %1").arg(api.lastUpdate)
|
||||||
|
}
|
||||||
|
|
||||||
function openSettings() {
|
function openSettings() {
|
||||||
pageStack.push(Qt.resolvedUrl("SettingsPage.qml"))
|
pageStack.push(Qt.resolvedUrl("SettingsPage.qml"))
|
||||||
@@ -40,100 +78,14 @@ Page {
|
|||||||
pageStack.push(Qt.resolvedUrl("DataPage.qml"))
|
pageStack.push(Qt.resolvedUrl("DataPage.qml"))
|
||||||
}
|
}
|
||||||
|
|
||||||
function showNotice(msg, isError) {
|
Component.onCompleted: {
|
||||||
page.notice = msg
|
if (api.configured)
|
||||||
page.noticeIsError = isError === true
|
api.refresh()
|
||||||
noticeTimer.restart()
|
|
||||||
}
|
|
||||||
|
|
||||||
function raw(key) {
|
|
||||||
return api.summary[key]
|
|
||||||
}
|
|
||||||
|
|
||||||
// I numeri si formattano nel C++ (ApiClient::formatValue): cosi' il
|
|
||||||
// separatore decimale segue la lingua dell'app, non il toFixed di JS.
|
|
||||||
function fmt(value) { return api.formatValue(value) }
|
|
||||||
|
|
||||||
function temp(key) {
|
|
||||||
return api.formatValue(page.raw(key))
|
|
||||||
}
|
|
||||||
|
|
||||||
function count(key) {
|
|
||||||
var v = page.raw(key)
|
|
||||||
if (v === undefined || v === null)
|
|
||||||
return "—"
|
|
||||||
return String(Math.round(Number(v)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// "2026-10-09 18:52:17.199340" -> "18:52"
|
|
||||||
function shortTime(s) {
|
|
||||||
if (!s)
|
|
||||||
return "—"
|
|
||||||
var parts = String(s).split(" ")
|
|
||||||
if (parts.length < 2)
|
|
||||||
return String(s)
|
|
||||||
return parts[1].substring(0, 5)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Messaggio grande in cima: e' la frase che l'app ufficiale mette al centro
|
|
||||||
// della schermata iniziale ("Relax, la tua pompa di calore..."). Si sceglie
|
|
||||||
// in ordine di importanza: errori, modalita' attive, pompa in funzione.
|
|
||||||
function stateMessage() {
|
|
||||||
if (!api.configured)
|
|
||||||
return ""
|
|
||||||
var errs = Number(page.raw("errors_count"))
|
|
||||||
if (errs > 0)
|
|
||||||
return (errs === 1)
|
|
||||||
? qsTr("Attention: one error on the plant")
|
|
||||||
: qsTr("Attention: %1 errors on the plant").arg(errs)
|
|
||||||
if (page.raw("away_mode") === true)
|
|
||||||
return qsTr("Away mode: the house is saving energy.")
|
|
||||||
if (page.raw("night_mode") === true)
|
|
||||||
return qsTr("Night mode is on.")
|
|
||||||
if (page.raw("force_heating") === true)
|
|
||||||
return qsTr("Boost: the house is heating at full power.")
|
|
||||||
if (page.raw("hot_water_heating") === true)
|
|
||||||
return qsTr("The heat pump is heating the hot water.")
|
|
||||||
if (String(page.raw("pump_active_state") || "").indexOf("RUNNING") >= 0)
|
|
||||||
return qsTr("The heat pump is working.")
|
|
||||||
return qsTr("Relax: the heat pump is running smoothly.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Riga piccola sotto il messaggio: modalita' e ora dell'ultima lettura.
|
|
||||||
function statusDetail() {
|
|
||||||
if (!api.configured)
|
|
||||||
return ""
|
|
||||||
return qsTr("%1 · last reading %2")
|
|
||||||
.arg(api.modeLabel(page.raw("operating_status")))
|
|
||||||
.arg(page.shortTime(page.raw("pump_updated")))
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: noticeTimer
|
|
||||||
interval: 4000
|
|
||||||
onTriggered: page.notice = ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fuori dal pulsante: dentro il pulsante i figli finiscono nel contentItem.
|
||||||
RemorseItem { id: remorse }
|
RemorseItem { id: remorse }
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: api
|
|
||||||
onErrorOccurred: page.showNotice(message, true)
|
|
||||||
onCommandFinished: page.showNotice(message, !ok)
|
|
||||||
onSummaryChanged: {
|
|
||||||
if (!page.targetAcsTouched) {
|
|
||||||
var v = page.raw("dhw_target")
|
|
||||||
if (v !== undefined && v !== null)
|
|
||||||
page.targetAcs = Math.round(Number(v))
|
|
||||||
}
|
|
||||||
if (!page.targetCasaTouched) {
|
|
||||||
var c = page.raw("zone1_setpoint")
|
|
||||||
if (c !== undefined && c !== null && Number(c) > 0)
|
|
||||||
page.targetCasa = Math.round(Number(c) * 2) / 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SilicaFlickable {
|
SilicaFlickable {
|
||||||
id: flick
|
id: flick
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -154,10 +106,6 @@ Page {
|
|||||||
text: qsTr("Plant")
|
text: qsTr("Plant")
|
||||||
onClicked: page.openPlant()
|
onClicked: page.openPlant()
|
||||||
}
|
}
|
||||||
MenuItem {
|
|
||||||
text: qsTr("Other commands")
|
|
||||||
onClicked: page.openCommands()
|
|
||||||
}
|
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: qsTr("Settings")
|
text: qsTr("Settings")
|
||||||
onClicked: page.openSettings()
|
onClicked: page.openSettings()
|
||||||
@@ -169,17 +117,9 @@ Page {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.paddingSmall
|
spacing: Theme.paddingSmall
|
||||||
|
|
||||||
PageHeader { title: "Aira" }
|
PageHeader {
|
||||||
|
title: "Aira"
|
||||||
// ---- avvisi ---------------------------------------------------- //
|
description: page.updateText()
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- bridge non configurato ------------------------------------ //
|
// ---- bridge non configurato ------------------------------------ //
|
||||||
@@ -200,300 +140,158 @@ Page {
|
|||||||
onClicked: page.openSettings()
|
onClicked: page.openSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- barra in alto: fuori casa / a casa ------------------------ //
|
// ---- stato in una riga ----------------------------------------- //
|
||||||
Item {
|
Item {
|
||||||
visible: api.configured
|
visible: api.configured
|
||||||
x: Theme.horizontalPageMargin
|
x: Theme.horizontalPageMargin
|
||||||
width: parent.width - 2 * Theme.horizontalPageMargin
|
width: parent.width - 2 * Theme.horizontalPageMargin
|
||||||
height: fuori.height
|
height: Math.max(stato.height, pallino.height, attesa.height)
|
||||||
|
|
||||||
Label {
|
Rectangle {
|
||||||
id: fuori
|
id: pallino
|
||||||
anchors.left: parent.left
|
width: Theme.fontSizeSmall * 0.6
|
||||||
text: qsTr("Outside %1 °C").arg(page.temp("outdoor_temperature"))
|
height: width
|
||||||
color: Theme.secondaryColor
|
radius: width / 2
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
color: page.statusColor()
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
|
id: stato
|
||||||
|
anchors {
|
||||||
|
left: pallino.right
|
||||||
|
leftMargin: Theme.paddingMedium
|
||||||
|
right: attesa.left
|
||||||
|
rightMargin: Theme.paddingMedium
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
text: api.stateShort()
|
||||||
|
color: Theme.primaryColor
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
BusyIndicator {
|
||||||
|
id: attesa
|
||||||
anchors {
|
anchors {
|
||||||
right: parent.right
|
right: parent.right
|
||||||
verticalCenter: parent.verticalCenter
|
verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
text: page.raw("away_mode") === true ? qsTr("Away") : qsTr("At home")
|
size: BusyIndicatorSize.Small
|
||||||
color: page.raw("away_mode") === true ? Theme.highlightColor : Theme.secondaryColor
|
running: api.busy
|
||||||
font.pixelSize: Theme.fontSizeExtraSmall
|
visible: api.busy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- messaggio di stato (il "centro" della schermata ufficiale) - //
|
// ---- le due letture che contano -------------------------------- //
|
||||||
Label {
|
Row {
|
||||||
|
id: letture
|
||||||
visible: api.configured
|
visible: api.configured
|
||||||
x: Theme.horizontalPageMargin
|
x: Theme.horizontalPageMargin
|
||||||
width: parent.width - 2 * Theme.horizontalPageMargin
|
width: parent.width - 2 * Theme.horizontalPageMargin
|
||||||
text: page.stateMessage()
|
spacing: Theme.paddingSmall
|
||||||
color: Theme.primaryColor
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
ReadingCell {
|
||||||
horizontalAlignment: Text.AlignHCenter
|
width: (letture.width - letture.spacing) / 2
|
||||||
wrapMode: Text.Wrap
|
title: qsTr("House")
|
||||||
|
value: page.fmt(page.raw("zone1_temperature")) + " °C"
|
||||||
|
subtitle: qsTr("target %1 °C").arg(page.fmt(page.raw("zone1_setpoint")))
|
||||||
|
valueColor: api.stale ? Theme.secondaryColor : Theme.primaryColor
|
||||||
|
onTapped: pageStack.push(Qt.resolvedUrl("SetpointsPage.qml"))
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadingCell {
|
||||||
|
width: (letture.width - letture.spacing) / 2
|
||||||
|
title: qsTr("Hot water")
|
||||||
|
value: page.fmt(page.raw("dhw_current")) + " °C"
|
||||||
|
subtitle: qsTr("target %1 °C").arg(page.fmt(page.raw("dhw_target")))
|
||||||
|
progress: page.waterProgress()
|
||||||
|
showBar: true
|
||||||
|
valueColor: api.stale ? Theme.secondaryColor : Theme.primaryColor
|
||||||
|
onTapped: pageStack.push(Qt.resolvedUrl("SetpointsPage.qml"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
visible: api.configured
|
visible: api.configured
|
||||||
x: Theme.horizontalPageMargin
|
x: Theme.horizontalPageMargin
|
||||||
width: parent.width - 2 * Theme.horizontalPageMargin
|
width: parent.width - 2 * Theme.horizontalPageMargin
|
||||||
text: page.statusDetail()
|
text: qsTr("Tap a value to adjust it")
|
||||||
color: Theme.secondaryColor
|
color: Theme.secondaryColor
|
||||||
font.pixelSize: Theme.fontSizeExtraSmall
|
font.pixelSize: Theme.fontSizeExtraSmall
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- scheda dell'impianto -------------------------------------- //
|
// ---- azioni rapide --------------------------------------------- //
|
||||||
// Come la scheda dispositivo dell'app ufficiale: intestazione con
|
SectionHeader {
|
||||||
// nome e connessione, poi le due letture principali. Toccandola si
|
visible: api.configured
|
||||||
// apre la pagina "Impianto" (accessori, versioni, errori).
|
text: qsTr("Quick actions")
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
visible: api.configured
|
||||||
|
x: Theme.horizontalPageMargin
|
||||||
|
width: parent.width - 2 * Theme.horizontalPageMargin
|
||||||
|
spacing: Theme.paddingSmall
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: boostBtn
|
||||||
|
width: (parent.width - 2 * parent.spacing) / 3
|
||||||
|
text: qsTr("Boost")
|
||||||
|
onClicked: remorse.execute(boostBtn, qsTr("Starting DHW boost"),
|
||||||
|
function() { api.sendCommand("hot_water_boost_on") })
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: assenzaBtn
|
||||||
|
width: (parent.width - 2 * parent.spacing) / 3
|
||||||
|
// Il pulsante dice cosa succede premendolo, non lo stato.
|
||||||
|
text: page.raw("away_mode") ? qsTr("Back home") : qsTr("Away mode")
|
||||||
|
onClicked: {
|
||||||
|
if (page.raw("away_mode")) {
|
||||||
|
remorse.execute(assenzaBtn, qsTr("Away mode off"),
|
||||||
|
function() { api.sendCommand("away_mode_off") })
|
||||||
|
} else {
|
||||||
|
remorse.execute(assenzaBtn, qsTr("Away mode on"),
|
||||||
|
function() { api.sendCommand("away_mode_on") })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
width: (parent.width - 2 * parent.spacing) / 3
|
||||||
|
text: qsTr("Commands")
|
||||||
|
onClicked: page.openCommands()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- letture di contorno (si toccano: portano a Impianto) ------ //
|
||||||
BackgroundItem {
|
BackgroundItem {
|
||||||
id: scheda
|
|
||||||
visible: api.configured
|
visible: api.configured
|
||||||
x: Theme.horizontalPageMargin
|
x: Theme.horizontalPageMargin
|
||||||
width: parent.width - 2 * Theme.horizontalPageMargin
|
width: parent.width - 2 * Theme.horizontalPageMargin
|
||||||
height: schedaCol.height + 3 * Theme.paddingMedium
|
height: contornoTxt.height + Theme.paddingMedium
|
||||||
onClicked: page.openPlant()
|
onClicked: page.openPlant()
|
||||||
|
|
||||||
Column {
|
Label {
|
||||||
id: schedaCol
|
id: contornoTxt
|
||||||
x: Theme.paddingMedium
|
anchors {
|
||||||
y: Theme.paddingMedium
|
left: parent.left
|
||||||
width: parent.width - 2 * Theme.paddingMedium
|
right: parent.right
|
||||||
spacing: Theme.paddingMedium
|
verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
Item {
|
|
||||||
width: parent.width
|
|
||||||
height: intestazione.height
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: intestazione
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
right: freccia.left
|
|
||||||
rightMargin: Theme.paddingSmall
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
text: qsTr("Aira heat pump")
|
|
||||||
color: Theme.primaryColor
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
}
|
|
||||||
Label {
|
|
||||||
text: qsTr("Connected through the cloud")
|
|
||||||
color: Theme.secondaryColor
|
|
||||||
font.pixelSize: Theme.fontSizeExtraSmall
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
id: freccia
|
|
||||||
anchors {
|
|
||||||
right: parent.right
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
text: "›"
|
|
||||||
color: Theme.highlightColor
|
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueRow {
|
|
||||||
title: qsTr("Room temperature")
|
|
||||||
subtitle: qsTr("Target %1 °C").arg(page.temp("zone1_setpoint"))
|
|
||||||
value: page.temp("zone1_temperature") + " °C"
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueRow {
|
|
||||||
title: qsTr("Domestic hot water")
|
|
||||||
subtitle: qsTr("Target %1 °C").arg(page.temp("dhw_target"))
|
|
||||||
value: page.temp("dhw_current") + " °C"
|
|
||||||
}
|
}
|
||||||
|
text: qsTr("Outside %1 °C · Thermostat %2 °C · Zones %3")
|
||||||
|
.arg(page.fmt(page.raw("outdoor_temperature")))
|
||||||
|
.arg(page.fmt(page.raw("thermostat_temperature")))
|
||||||
|
.arg(page.count("zones"))
|
||||||
|
color: Theme.secondaryColor
|
||||||
|
font.pixelSize: Theme.fontSizeExtraSmall
|
||||||
|
wrapMode: Text.Wrap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- riscaldamento della casa ---------------------------------- //
|
Item { width: 1; height: Theme.paddingMedium }
|
||||||
SectionHeader { visible: api.configured; text: qsTr("Heating the house") }
|
|
||||||
|
|
||||||
Label {
|
|
||||||
visible: api.configured
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
text: qsTr("Heating setpoint %1 °C · %2")
|
|
||||||
.arg(page.temp("zone1_setpoint"))
|
|
||||||
.arg(api.modeLabel(page.raw("zone1_mode")))
|
|
||||||
color: Theme.secondaryColor
|
|
||||||
font.pixelSize: Theme.fontSizeExtraSmall
|
|
||||||
}
|
|
||||||
|
|
||||||
Slider {
|
|
||||||
id: casaSlider
|
|
||||||
visible: api.configured
|
|
||||||
width: parent.width
|
|
||||||
label: qsTr("New house target")
|
|
||||||
minimumValue: 5
|
|
||||||
maximumValue: 30
|
|
||||||
stepSize: 0.5
|
|
||||||
value: page.targetCasa
|
|
||||||
valueText: page.fmt(value) + " °C"
|
|
||||||
onValueChanged: {
|
|
||||||
page.targetCasaTouched = true
|
|
||||||
page.targetCasa = Math.round(value * 2) / 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: setCasaButton
|
|
||||||
visible: api.configured
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
leftMargin: Theme.horizontalPageMargin
|
|
||||||
rightMargin: Theme.horizontalPageMargin
|
|
||||||
}
|
|
||||||
text: qsTr("Set house to %1 °C").arg(page.fmt(page.targetCasa))
|
|
||||||
onClicked: remorse.execute(setCasaButton,
|
|
||||||
qsTr("House temperature to %1 °C").arg(page.fmt(page.targetCasa)),
|
|
||||||
function() { api.sendCommand("set_heating_setpoint", page.targetCasa) })
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- acqua calda sanitaria ------------------------------------- //
|
|
||||||
SectionHeader { visible: api.configured; text: qsTr("Domestic hot water") }
|
|
||||||
|
|
||||||
ProgressBar {
|
|
||||||
visible: api.configured
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
width: parent.width - 4 * Theme.horizontalPageMargin
|
|
||||||
minimumValue: 20
|
|
||||||
maximumValue: 65
|
|
||||||
value: {
|
|
||||||
var v = page.raw("dhw_current")
|
|
||||||
return (v === undefined || v === null) ? 0 : Number(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Slider {
|
|
||||||
visible: api.configured
|
|
||||||
width: parent.width
|
|
||||||
label: qsTr("New target")
|
|
||||||
minimumValue: 45
|
|
||||||
maximumValue: 60
|
|
||||||
stepSize: 1
|
|
||||||
value: page.targetAcs
|
|
||||||
valueText: page.fmt(value) + " °C"
|
|
||||||
onValueChanged: {
|
|
||||||
page.targetAcsTouched = true
|
|
||||||
page.targetAcs = Math.round(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: setAcsButton
|
|
||||||
visible: api.configured
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
leftMargin: Theme.horizontalPageMargin
|
|
||||||
rightMargin: Theme.horizontalPageMargin
|
|
||||||
}
|
|
||||||
text: qsTr("Set target %1 °C").arg(page.targetAcs)
|
|
||||||
onClicked: remorse.execute(setAcsButton,
|
|
||||||
qsTr("DHW target to %1 °C").arg(page.targetAcs),
|
|
||||||
function() { api.sendCommand("set_hot_water_target", page.targetAcs) })
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: boostOnButton
|
|
||||||
visible: api.configured
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
leftMargin: Theme.horizontalPageMargin
|
|
||||||
rightMargin: Theme.horizontalPageMargin
|
|
||||||
}
|
|
||||||
text: qsTr("Start DHW boost")
|
|
||||||
onClicked: remorse.execute(boostOnButton, qsTr("Starting DHW boost"),
|
|
||||||
function() { api.sendCommand("hot_water_boost_on") })
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: boostOffButton
|
|
||||||
visible: api.configured
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
leftMargin: Theme.horizontalPageMargin
|
|
||||||
rightMargin: Theme.horizontalPageMargin
|
|
||||||
}
|
|
||||||
text: qsTr("Stop DHW boost")
|
|
||||||
onClicked: remorse.execute(boostOffButton, qsTr("Stopping DHW boost"),
|
|
||||||
function() { api.sendCommand("hot_water_boost_off") })
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- altre pagine ---------------------------------------------- //
|
|
||||||
SectionHeader { visible: api.configured; text: qsTr("Details") }
|
|
||||||
|
|
||||||
Button {
|
|
||||||
visible: api.configured
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
leftMargin: Theme.horizontalPageMargin
|
|
||||||
rightMargin: Theme.horizontalPageMargin
|
|
||||||
}
|
|
||||||
text: qsTr("Plant and accessories")
|
|
||||||
onClicked: page.openPlant()
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
visible: api.configured
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
leftMargin: Theme.horizontalPageMargin
|
|
||||||
rightMargin: Theme.horizontalPageMargin
|
|
||||||
}
|
|
||||||
text: qsTr("Consumption and savings")
|
|
||||||
onClicked: page.openData()
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
visible: api.configured
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
leftMargin: Theme.horizontalPageMargin
|
|
||||||
rightMargin: Theme.horizontalPageMargin
|
|
||||||
}
|
|
||||||
text: qsTr("Other commands")
|
|
||||||
onClicked: page.openCommands()
|
|
||||||
}
|
|
||||||
|
|
||||||
BusyIndicator {
|
|
||||||
visible: api.busy
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
size: BusyIndicatorSize.Small
|
|
||||||
running: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
visible: api.configured
|
|
||||||
x: Theme.horizontalPageMargin
|
|
||||||
width: parent.width - 2 * Theme.horizontalPageMargin
|
|
||||||
text: qsTr("Commands are sent to the bridge and from there to the plant: they may take a few seconds.")
|
|
||||||
color: Theme.secondaryColor
|
|
||||||
font.pixelSize: Theme.fontSizeExtraSmall
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
NoticeBar { }
|
||||||
if (api.configured)
|
|
||||||
api.refresh()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,234 @@
|
|||||||
|
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 { }
|
||||||
|
}
|
||||||
@@ -198,4 +198,82 @@ QString errorMessage(const QByteArray &body, int httpStatus)
|
|||||||
return QCoreApplication::translate("AiraJson", "HTTP error %1").arg(httpStatus);
|
return QCoreApplication::translate("AiraJson", "HTTP error %1").arg(httpStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Flag booleano del riassunto, con falso come ripiego.
|
||||||
|
bool flagValue(const QVariantMap &summary, const QString &key)
|
||||||
|
{
|
||||||
|
return summary.value(key).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
int errorCount(const QVariantMap &summary)
|
||||||
|
{
|
||||||
|
return summary.value(QStringLiteral("errors_count")).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pumpRunning(const QVariantMap &summary)
|
||||||
|
{
|
||||||
|
return summary.value(QStringLiteral("pump_active_state")).toString()
|
||||||
|
.contains(QStringLiteral("RUNNING"));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
QString stateShort(const QVariantMap &summary)
|
||||||
|
{
|
||||||
|
if (summary.isEmpty())
|
||||||
|
return QCoreApplication::translate("AiraJson", "No data");
|
||||||
|
const int errs = errorCount(summary);
|
||||||
|
if (errs > 0)
|
||||||
|
return (errs == 1)
|
||||||
|
? QCoreApplication::translate("AiraJson", "Attention: one error")
|
||||||
|
: QCoreApplication::translate("AiraJson", "Attention: %1 errors").arg(errs);
|
||||||
|
if (flagValue(summary, QStringLiteral("away_mode")))
|
||||||
|
return QCoreApplication::translate("AiraJson", "Away mode");
|
||||||
|
if (flagValue(summary, QStringLiteral("night_mode")))
|
||||||
|
return QCoreApplication::translate("AiraJson", "Night mode");
|
||||||
|
if (flagValue(summary, QStringLiteral("force_heating")))
|
||||||
|
return QCoreApplication::translate("AiraJson", "Heating at full power");
|
||||||
|
if (flagValue(summary, QStringLiteral("hot_water_heating")))
|
||||||
|
return QCoreApplication::translate("AiraJson", "Heating the hot water");
|
||||||
|
if (pumpRunning(summary))
|
||||||
|
return QCoreApplication::translate("AiraJson", "Working");
|
||||||
|
return QCoreApplication::translate("AiraJson", "Everything is fine");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString stateLong(const QVariantMap &summary)
|
||||||
|
{
|
||||||
|
if (summary.isEmpty())
|
||||||
|
return QString();
|
||||||
|
const int errs = errorCount(summary);
|
||||||
|
if (errs > 0)
|
||||||
|
return (errs == 1)
|
||||||
|
? QCoreApplication::translate("AiraJson", "Attention: one error on the plant")
|
||||||
|
: QCoreApplication::translate("AiraJson", "Attention: %1 errors on the plant").arg(errs);
|
||||||
|
if (flagValue(summary, QStringLiteral("away_mode")))
|
||||||
|
return QCoreApplication::translate("AiraJson", "Away mode: the house is saving energy.");
|
||||||
|
if (flagValue(summary, QStringLiteral("night_mode")))
|
||||||
|
return QCoreApplication::translate("AiraJson", "Night mode is on.");
|
||||||
|
if (flagValue(summary, QStringLiteral("force_heating")))
|
||||||
|
return QCoreApplication::translate("AiraJson", "Boost: the house is heating at full power.");
|
||||||
|
if (flagValue(summary, QStringLiteral("hot_water_heating")))
|
||||||
|
return QCoreApplication::translate("AiraJson", "The heat pump is heating the hot water.");
|
||||||
|
if (pumpRunning(summary))
|
||||||
|
return QCoreApplication::translate("AiraJson", "The heat pump is working.");
|
||||||
|
return QCoreApplication::translate("AiraJson", "Relax: the heat pump is running smoothly.");
|
||||||
|
}
|
||||||
|
|
||||||
|
int statusLevel(const QVariantMap &summary)
|
||||||
|
{
|
||||||
|
if (summary.isEmpty())
|
||||||
|
return 1;
|
||||||
|
if (errorCount(summary) > 0)
|
||||||
|
return 2;
|
||||||
|
if (flagValue(summary, QStringLiteral("away_mode"))
|
||||||
|
|| flagValue(summary, QStringLiteral("night_mode"))
|
||||||
|
|| flagValue(summary, QStringLiteral("force_heating")))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace AiraJson
|
} // namespace AiraJson
|
||||||
|
|||||||
@@ -30,6 +30,18 @@ QVariantMap parseStats(const QByteArray &body, bool *ok);
|
|||||||
// Codice di stato Aira ("OPERATING_STATUS_AUTO") in etichetta italiana.
|
// Codice di stato Aira ("OPERATING_STATUS_AUTO") in etichetta italiana.
|
||||||
QString modeLabel(const QString &operatingStatus);
|
QString modeLabel(const QString &operatingStatus);
|
||||||
|
|
||||||
|
// Riga di stato per la Home: breve, per stare in una riga sola
|
||||||
|
// ("Tutto regolare", "In assenza", "Attenzione: un errore").
|
||||||
|
QString stateShort(const QVariantMap &summary);
|
||||||
|
|
||||||
|
// Frase estesa per la pagina Impianto (quella dell'app ufficiale:
|
||||||
|
// "Relax: la pompa di calore funziona regolarmente").
|
||||||
|
QString stateLong(const QVariantMap &summary);
|
||||||
|
|
||||||
|
// Livello dello stato, per il colore della riga: 0 regolare, 1 modo attivo
|
||||||
|
// (assenza, notte, riscaldamento forzato), 2 errore sull'impianto.
|
||||||
|
int statusLevel(const QVariantMap &summary);
|
||||||
|
|
||||||
// Temperatura leggibile: "51,0" oppure "—" se il valore manca.
|
// Temperatura leggibile: "51,0" oppure "—" se il valore manca.
|
||||||
QString formatValue(const QVariant &value);
|
QString formatValue(const QVariant &value);
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QLocale>
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
|
#include <QTime>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
@@ -12,7 +14,32 @@ ApiClient::ApiClient(Settings *settings, QObject *parent)
|
|||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_settings(settings)
|
, m_settings(settings)
|
||||||
, m_busy(false)
|
, m_busy(false)
|
||||||
|
, m_stale(false)
|
||||||
|
, m_noticeIsError(false)
|
||||||
|
, m_noticeTimer(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
|
||||||
|
// in fondo alla schermata (NoticeBar), fuori dal contenuto che scorre.
|
||||||
|
m_noticeTimer = new QTimer(this);
|
||||||
|
m_noticeTimer->setSingleShot(true);
|
||||||
|
m_noticeTimer->setInterval(7000);
|
||||||
|
connect(m_noticeTimer, &QTimer::timeout, this, [this]() {
|
||||||
|
if (m_notice.isEmpty())
|
||||||
|
return;
|
||||||
|
m_notice.clear();
|
||||||
|
emit noticeChanged();
|
||||||
|
});
|
||||||
|
connect(this, &ApiClient::errorOccurred, this, [this](const QString &message) {
|
||||||
|
setNotice(message, true);
|
||||||
|
});
|
||||||
|
connect(this, &ApiClient::commandFinished, this, [this](bool ok, const QString &message) {
|
||||||
|
setNotice(message, !ok);
|
||||||
|
});
|
||||||
|
connect(this, &ApiClient::statsRefreshed, this, [this](bool ok, const QString &message) {
|
||||||
|
setNotice(message, !ok);
|
||||||
|
});
|
||||||
|
|
||||||
if (m_settings) {
|
if (m_settings) {
|
||||||
// La UI deve riflettere subito il passaggio da "non configurato" a
|
// La UI deve riflettere subito il passaggio da "non configurato" a
|
||||||
// "configurato" quando si salvano indirizzo o token.
|
// "configurato" quando si salvano indirizzo o token.
|
||||||
@@ -29,6 +56,30 @@ bool ApiClient::configured() const
|
|||||||
&& !m_settings->token().trimmed().isEmpty();
|
&& !m_settings->token().trimmed().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ApiClient::stateShort() const
|
||||||
|
{
|
||||||
|
return AiraJson::stateShort(m_summary);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ApiClient::stateLong() const
|
||||||
|
{
|
||||||
|
return AiraJson::stateLong(m_summary);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ApiClient::statusLevel() const
|
||||||
|
{
|
||||||
|
return AiraJson::statusLevel(m_summary);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApiClient::setNotice(const QString &message, bool isError)
|
||||||
|
{
|
||||||
|
m_notice = message;
|
||||||
|
m_noticeIsError = isError;
|
||||||
|
emit noticeChanged();
|
||||||
|
if (!message.isEmpty())
|
||||||
|
m_noticeTimer->start();
|
||||||
|
}
|
||||||
|
|
||||||
void ApiClient::setBusy(bool value)
|
void ApiClient::setBusy(bool value)
|
||||||
{
|
{
|
||||||
if (value == m_busy)
|
if (value == m_busy)
|
||||||
@@ -102,6 +153,10 @@ void ApiClient::refresh()
|
|||||||
? tr("Server unreachable (timeout)")
|
? tr("Server unreachable (timeout)")
|
||||||
: AiraJson::errorMessage(body, status);
|
: AiraJson::errorMessage(body, status);
|
||||||
qWarning() << "[api] summary non riuscito:" << status << msg;
|
qWarning() << "[api] summary non riuscito:" << status << msg;
|
||||||
|
if (!m_stale) {
|
||||||
|
m_stale = true;
|
||||||
|
emit staleChanged();
|
||||||
|
}
|
||||||
emit errorOccurred(msg);
|
emit errorOccurred(msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -110,10 +165,22 @@ void ApiClient::refresh()
|
|||||||
const QVariantMap summary = AiraJson::parseSummary(body, &ok);
|
const QVariantMap summary = AiraJson::parseSummary(body, &ok);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
qWarning() << "[api] riassunto non interpretabile";
|
qWarning() << "[api] riassunto non interpretabile";
|
||||||
|
if (!m_stale) {
|
||||||
|
m_stale = true;
|
||||||
|
emit staleChanged();
|
||||||
|
}
|
||||||
emit errorOccurred(tr("Unreadable response from the bridge"));
|
emit errorOccurred(tr("Unreadable response from the bridge"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_summary = summary;
|
m_summary = summary;
|
||||||
|
if (m_stale) {
|
||||||
|
m_stale = false;
|
||||||
|
emit staleChanged();
|
||||||
|
}
|
||||||
|
// Ora dell'ultimo aggiornamento riuscito: la Home la mostra, cosi' un
|
||||||
|
// numero vecchio non passa per un numero fresco.
|
||||||
|
m_lastUpdate = QLocale::system().toString(QTime::currentTime(), QLocale::ShortFormat);
|
||||||
|
emit lastUpdateChanged();
|
||||||
emit summaryChanged(summary);
|
emit summaryChanged(summary);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <QVariantMap>
|
#include <QVariantMap>
|
||||||
|
|
||||||
class QNetworkReply;
|
class QNetworkReply;
|
||||||
|
class QTimer;
|
||||||
class Settings;
|
class Settings;
|
||||||
|
|
||||||
// Client HTTP verso il bridge sul server (~/workspace/Carlo/Aira/aira_bridge.py).
|
// Client HTTP verso il bridge sul server (~/workspace/Carlo/Aira/aira_bridge.py).
|
||||||
@@ -24,6 +25,16 @@ class ApiClient : public QObject
|
|||||||
// Statistiche della pagina "Dati" (calore, elettricita', COP, risparmi).
|
// Statistiche della pagina "Dati" (calore, elettricita', COP, risparmi).
|
||||||
// Separata dal riassunto: e' una chiamata piu' lenta, con cache lato bridge.
|
// Separata dal riassunto: e' una chiamata piu' lenta, con cache lato bridge.
|
||||||
Q_PROPERTY(QVariantMap stats READ stats NOTIFY statsChanged)
|
Q_PROPERTY(QVariantMap stats READ stats NOTIFY statsChanged)
|
||||||
|
// Salute dell'aggiornamento: "stale" = l'ultimo tentativo non e' riuscito,
|
||||||
|
// quindi i numeri a schermo sono vecchi e vanno mostrati spenti.
|
||||||
|
Q_PROPERTY(bool stale READ stale NOTIFY staleChanged)
|
||||||
|
Q_PROPERTY(QString lastUpdate READ lastUpdate NOTIFY lastUpdateChanged)
|
||||||
|
Q_PROPERTY(bool hasData READ hasData NOTIFY summaryChanged)
|
||||||
|
// Messaggio dell'ultimo comando (o errore), mostrato in fondo alla pagina:
|
||||||
|
// sta qui e non nel QML perche' vale per OGNI pagina, e perche' cosi' il
|
||||||
|
// messaggio e' lo stesso ovunque si stia.
|
||||||
|
Q_PROPERTY(QString notice READ notice NOTIFY noticeChanged)
|
||||||
|
Q_PROPERTY(bool noticeIsError READ noticeIsError NOTIFY noticeChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ApiClient(Settings *settings, QObject *parent = 0);
|
explicit ApiClient(Settings *settings, QObject *parent = 0);
|
||||||
@@ -32,6 +43,18 @@ public:
|
|||||||
bool configured() const;
|
bool configured() const;
|
||||||
QVariantMap summary() const { return m_summary; }
|
QVariantMap summary() const { return m_summary; }
|
||||||
QVariantMap stats() const { return m_stats; }
|
QVariantMap stats() const { return m_stats; }
|
||||||
|
bool stale() const { return m_stale; }
|
||||||
|
QString lastUpdate() const { return m_lastUpdate; }
|
||||||
|
bool hasData() const { return !m_summary.isEmpty(); }
|
||||||
|
QString notice() const { return m_notice; }
|
||||||
|
bool noticeIsError() const { return m_noticeIsError; }
|
||||||
|
|
||||||
|
// Stato leggibile in una riga (stateShort) e per esteso (stateLong), piu'
|
||||||
|
// il livello da cui la UI prende il colore. Stanno in C++ perche' sono
|
||||||
|
// logica pura: verificate in tests/core_test.cpp e non duplicate fra pagine.
|
||||||
|
Q_INVOKABLE QString stateShort() const;
|
||||||
|
Q_INVOKABLE QString stateLong() const;
|
||||||
|
Q_INVOKABLE int statusLevel() const;
|
||||||
|
|
||||||
// Scarica il riassunto e lo emette con summaryChanged().
|
// Scarica il riassunto e lo emette con summaryChanged().
|
||||||
Q_INVOKABLE void refresh();
|
Q_INVOKABLE void refresh();
|
||||||
@@ -56,6 +79,9 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void busyChanged();
|
void busyChanged();
|
||||||
void configuredChanged();
|
void configuredChanged();
|
||||||
|
void staleChanged();
|
||||||
|
void lastUpdateChanged();
|
||||||
|
void noticeChanged();
|
||||||
void summaryChanged(const QVariantMap &summary);
|
void summaryChanged(const QVariantMap &summary);
|
||||||
void statsChanged(const QVariantMap &stats);
|
void statsChanged(const QVariantMap &stats);
|
||||||
void statsRefreshed(bool ok, const QString &message);
|
void statsRefreshed(bool ok, const QString &message);
|
||||||
@@ -68,10 +94,17 @@ private:
|
|||||||
const QByteArray &body, int timeoutSec);
|
const QByteArray &body, int timeoutSec);
|
||||||
void armTimeout(QNetworkReply *reply, int seconds);
|
void armTimeout(QNetworkReply *reply, int seconds);
|
||||||
void setBusy(bool value);
|
void setBusy(bool value);
|
||||||
|
// Mostra un messaggio in fondo alla pagina per qualche secondo.
|
||||||
|
void setNotice(const QString &message, bool isError);
|
||||||
|
|
||||||
Settings *m_settings;
|
Settings *m_settings;
|
||||||
QNetworkAccessManager m_nam;
|
QNetworkAccessManager m_nam;
|
||||||
bool m_busy;
|
bool m_busy;
|
||||||
|
bool m_stale;
|
||||||
|
QString m_lastUpdate;
|
||||||
|
QString m_notice;
|
||||||
|
bool m_noticeIsError;
|
||||||
|
QTimer *m_noticeTimer;
|
||||||
QVariantMap m_summary;
|
QVariantMap m_summary;
|
||||||
QVariantMap m_stats;
|
QVariantMap m_stats;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -190,6 +190,67 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- stato in una riga e per esteso (Home e pagina Impianto) ----------- //
|
||||||
|
{
|
||||||
|
QVariantMap calmo;
|
||||||
|
calmo.insert("errors_count", 0);
|
||||||
|
calmo.insert("away_mode", false);
|
||||||
|
calmo.insert("night_mode", false);
|
||||||
|
calmo.insert("force_heating", false);
|
||||||
|
calmo.insert("hot_water_heating", false);
|
||||||
|
calmo.insert("pump_active_state", "PUMP_ACTIVE_STATE_IDLE");
|
||||||
|
check(AiraJson::stateShort(calmo) == "Everything is fine",
|
||||||
|
"stato breve: nessuna attivita'");
|
||||||
|
check(AiraJson::stateLong(calmo) == "Relax: the heat pump is running smoothly.",
|
||||||
|
"stato esteso: frase dell'app ufficiale");
|
||||||
|
check(AiraJson::statusLevel(calmo) == 0, "livello: regolare");
|
||||||
|
|
||||||
|
QVariantMap lavora = calmo;
|
||||||
|
lavora.insert("pump_active_state", "PUMP_ACTIVE_STATE_RUNNING");
|
||||||
|
check(AiraJson::stateShort(lavora) == "Working", "stato breve: pompa in funzione");
|
||||||
|
check(AiraJson::statusLevel(lavora) == 0,
|
||||||
|
"livello: pompa in funzione e' comunque regolare");
|
||||||
|
|
||||||
|
QVariantMap acqua = calmo;
|
||||||
|
acqua.insert("hot_water_heating", true);
|
||||||
|
check(AiraJson::stateShort(acqua) == "Heating the hot water",
|
||||||
|
"stato breve: sta scaldando l'acqua");
|
||||||
|
check(AiraJson::stateLong(acqua) == "The heat pump is heating the hot water.",
|
||||||
|
"stato esteso: acqua calda in carica");
|
||||||
|
|
||||||
|
QVariantMap assente = calmo;
|
||||||
|
assente.insert("away_mode", true);
|
||||||
|
check(AiraJson::stateShort(assente) == "Away mode", "stato breve: assenza");
|
||||||
|
check(AiraJson::statusLevel(assente) == 1, "livello: modo attivo, non regolare");
|
||||||
|
|
||||||
|
QVariantMap uno = calmo;
|
||||||
|
uno.insert("errors_count", 1);
|
||||||
|
check(AiraJson::stateShort(uno) == "Attention: one error",
|
||||||
|
"stato breve: un errore (singolare)");
|
||||||
|
check(AiraJson::stateLong(uno) == "Attention: one error on the plant",
|
||||||
|
"stato esteso: un errore");
|
||||||
|
check(AiraJson::statusLevel(uno) == 2, "livello: errore");
|
||||||
|
|
||||||
|
QVariantMap due = calmo;
|
||||||
|
due.insert("errors_count", 2);
|
||||||
|
check(AiraJson::stateShort(due) == "Attention: 2 errors",
|
||||||
|
"stato breve: due errori (plurale)");
|
||||||
|
check(AiraJson::stateLong(due) == "Attention: 2 errors on the plant",
|
||||||
|
"stato esteso: due errori");
|
||||||
|
|
||||||
|
// L'errore ha la precedenza su tutto: e' quello che va visto per primo.
|
||||||
|
QVariantMap misto = assente;
|
||||||
|
misto.insert("errors_count", 3);
|
||||||
|
check(AiraJson::stateShort(misto) == "Attention: 3 errors",
|
||||||
|
"stato breve: l'errore vince sul modo attivo");
|
||||||
|
check(AiraJson::statusLevel(misto) == 2, "livello: errore prima di tutto");
|
||||||
|
|
||||||
|
check(AiraJson::stateShort(QVariantMap()) == "No data",
|
||||||
|
"stato breve: nessun dato");
|
||||||
|
check(AiraJson::stateLong(QVariantMap()).isEmpty(),
|
||||||
|
"stato esteso: nessun dato = nessuna frase");
|
||||||
|
}
|
||||||
|
|
||||||
qInfo() << "----";
|
qInfo() << "----";
|
||||||
qInfo() << checks - failures << "/" << checks << "verifiche superate";
|
qInfo() << checks - failures << "/" << checks << "verifiche superate";
|
||||||
return failures == 0 ? 0 : 1;
|
return failures == 0 ? 0 : 1;
|
||||||
|
|||||||
+275
-224
@@ -63,70 +63,155 @@
|
|||||||
<source>HTTP error %1</source>
|
<source>HTTP error %1</source>
|
||||||
<translation>errore HTTP %1</translation>
|
<translation>errore HTTP %1</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/airajson.cpp" line="225"/>
|
||||||
|
<source>No data</source>
|
||||||
|
<translation>Nessun dato</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/airajson.cpp" line="229"/>
|
||||||
|
<source>Attention: one error</source>
|
||||||
|
<translation>Attenzione: un errore</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/airajson.cpp" line="230"/>
|
||||||
|
<source>Attention: %1 errors</source>
|
||||||
|
<translation>Attenzione: %1 errori</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/airajson.cpp" line="232"/>
|
||||||
|
<source>Away mode</source>
|
||||||
|
<translation>Assenza</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/airajson.cpp" line="234"/>
|
||||||
|
<source>Night mode</source>
|
||||||
|
<translation>Modalità notte</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/airajson.cpp" line="236"/>
|
||||||
|
<source>Heating at full power</source>
|
||||||
|
<translation>Riscaldamento al massimo</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/airajson.cpp" line="238"/>
|
||||||
|
<source>Heating the hot water</source>
|
||||||
|
<translation>Sta scaldando l'acqua</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/airajson.cpp" line="240"/>
|
||||||
|
<source>Working</source>
|
||||||
|
<translation>In funzione</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/airajson.cpp" line="241"/>
|
||||||
|
<source>Everything is fine</source>
|
||||||
|
<translation>Tutto regolare</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/airajson.cpp" line="251"/>
|
||||||
|
<source>Attention: one error on the plant</source>
|
||||||
|
<translation>Attenzione: un errore sull'impianto</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/airajson.cpp" line="252"/>
|
||||||
|
<source>Attention: %1 errors on the plant</source>
|
||||||
|
<translation>Attenzione: %1 errori sull'impianto</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/airajson.cpp" line="254"/>
|
||||||
|
<source>Away mode: the house is saving energy.</source>
|
||||||
|
<translation>Modalità assenza: la casa sta risparmiando.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/airajson.cpp" line="256"/>
|
||||||
|
<source>Night mode is on.</source>
|
||||||
|
<translation>Modalità notte attiva.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/airajson.cpp" line="258"/>
|
||||||
|
<source>Boost: the house is heating at full power.</source>
|
||||||
|
<translation>Boost: la casa sta scaldando a pieno regime.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/airajson.cpp" line="260"/>
|
||||||
|
<source>The heat pump is heating the hot water.</source>
|
||||||
|
<translation>La pompa di calore sta scaldando l'acqua calda.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/airajson.cpp" line="262"/>
|
||||||
|
<source>The heat pump is working.</source>
|
||||||
|
<translation>La pompa di calore sta lavorando.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/airajson.cpp" line="263"/>
|
||||||
|
<source>Relax: the heat pump is running smoothly.</source>
|
||||||
|
<translation>Relax: la pompa di calore funziona regolarmente.</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ApiClient</name>
|
<name>ApiClient</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/apiclient.cpp" line="60"/>
|
<location filename="../src/apiclient.cpp" line="111"/>
|
||||||
<source>Bridge address not configured</source>
|
<source>Bridge address not configured</source>
|
||||||
<translation>Indirizzo del bridge non configurato</translation>
|
<translation>Indirizzo del bridge non configurato</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/apiclient.cpp" line="82"/>
|
<location filename="../src/apiclient.cpp" line="133"/>
|
||||||
<location filename="../src/apiclient.cpp" line="178"/>
|
<location filename="../src/apiclient.cpp" line="245"/>
|
||||||
<location filename="../src/apiclient.cpp" line="221"/>
|
<location filename="../src/apiclient.cpp" line="288"/>
|
||||||
<source>Set the bridge address and token</source>
|
<source>Set the bridge address and token</source>
|
||||||
<translation>Configura indirizzo e token del bridge</translation>
|
<translation>Configura indirizzo e token del bridge</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/apiclient.cpp" line="102"/>
|
<location filename="../src/apiclient.cpp" line="153"/>
|
||||||
<source>Server unreachable (timeout)</source>
|
<source>Server unreachable (timeout)</source>
|
||||||
<translation>Server non raggiungibile (timeout)</translation>
|
<translation>Server non raggiungibile (timeout)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/apiclient.cpp" line="113"/>
|
<location filename="../src/apiclient.cpp" line="172"/>
|
||||||
<location filename="../src/apiclient.cpp" line="209"/>
|
<location filename="../src/apiclient.cpp" line="276"/>
|
||||||
<source>Unreadable response from the bridge</source>
|
<source>Unreadable response from the bridge</source>
|
||||||
<translation>Risposta del bridge non interpretabile</translation>
|
<translation>Risposta del bridge non interpretabile</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/apiclient.cpp" line="125"/>
|
<location filename="../src/apiclient.cpp" line="192"/>
|
||||||
<source>Enter the bridge address</source>
|
<source>Enter the bridge address</source>
|
||||||
<translation>Inserisci l'indirizzo del bridge</translation>
|
<translation>Inserisci l'indirizzo del bridge</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/apiclient.cpp" line="141"/>
|
<location filename="../src/apiclient.cpp" line="208"/>
|
||||||
<source>Timeout: no response</source>
|
<source>Timeout: no response</source>
|
||||||
<translation>Timeout: nessuna risposta</translation>
|
<translation>Timeout: nessuna risposta</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/apiclient.cpp" line="142"/>
|
<location filename="../src/apiclient.cpp" line="209"/>
|
||||||
<source>Unreachable (HTTP %1)</source>
|
<source>Unreachable (HTTP %1)</source>
|
||||||
<translation>Irraggiungibile (HTTP %1)</translation>
|
<translation>Irraggiungibile (HTTP %1)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/apiclient.cpp" line="146"/>
|
<location filename="../src/apiclient.cpp" line="213"/>
|
||||||
<source>Bridge reachable</source>
|
<source>Bridge reachable</source>
|
||||||
<translation>Bridge raggiungibile</translation>
|
<translation>Bridge raggiungibile</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/apiclient.cpp" line="186"/>
|
<location filename="../src/apiclient.cpp" line="253"/>
|
||||||
<location filename="../src/apiclient.cpp" line="230"/>
|
<location filename="../src/apiclient.cpp" line="297"/>
|
||||||
<source>Bridge not configured</source>
|
<source>Bridge not configured</source>
|
||||||
<translation>Bridge non configurato</translation>
|
<translation>Bridge non configurato</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/apiclient.cpp" line="198"/>
|
<location filename="../src/apiclient.cpp" line="265"/>
|
||||||
<source>Timeout: no statistics</source>
|
<source>Timeout: no statistics</source>
|
||||||
<translation>Timeout: statistiche non disponibili</translation>
|
<translation>Timeout: statistiche non disponibili</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/apiclient.cpp" line="244"/>
|
<location filename="../src/apiclient.cpp" line="311"/>
|
||||||
<source>Timeout: command not sent</source>
|
<source>Timeout: command not sent</source>
|
||||||
<translation>Timeout: comando non inviato</translation>
|
<translation>Timeout: comando non inviato</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/apiclient.cpp" line="251"/>
|
<location filename="../src/apiclient.cpp" line="318"/>
|
||||||
<source>Command sent</source>
|
<source>Command sent</source>
|
||||||
<translation>Comando inviato</translation>
|
<translation>Comando inviato</translation>
|
||||||
</message>
|
</message>
|
||||||
@@ -434,263 +519,111 @@
|
|||||||
<context>
|
<context>
|
||||||
<name>MainPage</name>
|
<name>MainPage</name>
|
||||||
<message>
|
<message>
|
||||||
<source>yes</source>
|
<location filename="../qml/pages/MainPage.qml" line="57"/>
|
||||||
<translation type="vanished">sì</translation>
|
<source>No data yet</source>
|
||||||
|
<translation>Nessun dato</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>no</source>
|
<location filename="../qml/pages/MainPage.qml" line="59"/>
|
||||||
<translation type="vanished">no</translation>
|
<source>Not updated · last %1</source>
|
||||||
|
<translation>Non aggiornato · ultimo %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="146"/>
|
<location filename="../qml/pages/MainPage.qml" line="62"/>
|
||||||
|
<source>Updated at %1</source>
|
||||||
|
<translation>Aggiornato alle %1</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/MainPage.qml" line="98"/>
|
||||||
<source>Refresh</source>
|
<source>Refresh</source>
|
||||||
<translation>Aggiorna</translation>
|
<translation>Aggiorna</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="162"/>
|
<location filename="../qml/pages/MainPage.qml" line="110"/>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="199"/>
|
<location filename="../qml/pages/MainPage.qml" line="139"/>
|
||||||
<source>Settings</source>
|
<source>Settings</source>
|
||||||
<translation>Impostazioni</translation>
|
<translation>Impostazioni</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="158"/>
|
<location filename="../qml/pages/MainPage.qml" line="196"/>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="472"/>
|
<source>House</source>
|
||||||
<source>Other commands</source>
|
<translation>Casa</translation>
|
||||||
<translation>Altri comandi</translation>
|
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="87"/>
|
<location filename="../qml/pages/MainPage.qml" line="198"/>
|
||||||
<source>Attention: one error on the plant</source>
|
<location filename="../qml/pages/MainPage.qml" line="207"/>
|
||||||
<translation>Attenzione: un errore sull'impianto</translation>
|
<source>target %1 °C</source>
|
||||||
|
<translation>obiettivo %1 °C</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="88"/>
|
<location filename="../qml/pages/MainPage.qml" line="205"/>
|
||||||
<source>Attention: %1 errors on the plant</source>
|
<source>Hot water</source>
|
||||||
<translation>Attenzione: %1 errori sull'impianto</translation>
|
<translation>Acqua calda</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="90"/>
|
<location filename="../qml/pages/MainPage.qml" line="219"/>
|
||||||
<source>Away mode: the house is saving energy.</source>
|
<source>Tap a value to adjust it</source>
|
||||||
<translation>Modalità assenza: la casa sta risparmiando.</translation>
|
<translation>Tocca un valore per regolarlo</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="92"/>
|
<location filename="../qml/pages/MainPage.qml" line="227"/>
|
||||||
<source>Night mode is on.</source>
|
<source>Quick actions</source>
|
||||||
<translation>Modalità notte attiva.</translation>
|
<translation>Azioni rapide</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="94"/>
|
<location filename="../qml/pages/MainPage.qml" line="239"/>
|
||||||
<source>Boost: the house is heating at full power.</source>
|
<source>Boost</source>
|
||||||
<translation>Boost: la casa sta scaldando a pieno regime.</translation>
|
<translation>Boost</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="96"/>
|
<location filename="../qml/pages/MainPage.qml" line="248"/>
|
||||||
<source>The heat pump is heating the hot water.</source>
|
<source>Back home</source>
|
||||||
<translation>La pompa di calore sta scaldando l'acqua calda.</translation>
|
<translation>Torna a casa</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="98"/>
|
<location filename="../qml/pages/MainPage.qml" line="251"/>
|
||||||
<source>The heat pump is working.</source>
|
<source>Away mode off</source>
|
||||||
<translation>La pompa di calore sta lavorando.</translation>
|
<translation>Assenza disattivata</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="99"/>
|
<location filename="../qml/pages/MainPage.qml" line="254"/>
|
||||||
<source>Relax: the heat pump is running smoothly.</source>
|
<source>Away mode on</source>
|
||||||
<translation>Relax: la pompa di calore funziona regolarmente.</translation>
|
<translation>Assenza attivata</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="106"/>
|
<location filename="../qml/pages/MainPage.qml" line="262"/>
|
||||||
<source>%1 · last reading %2</source>
|
<source>Commands</source>
|
||||||
<translation>%1 · ultima lettura %2</translation>
|
<translation>Comandi</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="150"/>
|
<location filename="../qml/pages/MainPage.qml" line="282"/>
|
||||||
|
<source>Outside %1 °C · Thermostat %2 °C · Zones %3</source>
|
||||||
|
<translation>Esterno %1 °C · Termostato %2 °C · Zone %3</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/MainPage.qml" line="102"/>
|
||||||
<source>Data</source>
|
<source>Data</source>
|
||||||
<translation>Dati</translation>
|
<translation>Dati</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="190"/>
|
<location filename="../qml/pages/MainPage.qml" line="130"/>
|
||||||
<source>Bridge not configured. Open the settings and enter the server address and the token.</source>
|
<source>Bridge not configured. Open the settings and enter the server address and the token.</source>
|
||||||
<translation>Bridge non configurato. Apri le impostazioni e inserisci l'indirizzo del server e il token.</translation>
|
<translation>Bridge non configurato. Apri le impostazioni e inserisci l'indirizzo del server e il token.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="213"/>
|
<location filename="../qml/pages/MainPage.qml" line="240"/>
|
||||||
<source>Outside %1 °C</source>
|
|
||||||
<translation>Esterno %1 °C</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="223"/>
|
|
||||||
<source>Away</source>
|
|
||||||
<translation>Assente</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="223"/>
|
|
||||||
<source>At home</source>
|
|
||||||
<translation>In casa</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="283"/>
|
|
||||||
<source>Aira heat pump</source>
|
|
||||||
<translation>Aira Pompa di calore</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="288"/>
|
|
||||||
<source>Connected through the cloud</source>
|
|
||||||
<translation>Connessa tramite Cloud</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="307"/>
|
|
||||||
<source>Room temperature</source>
|
|
||||||
<translation>Temperatura stanza</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="308"/>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="314"/>
|
|
||||||
<source>Target %1 °C</source>
|
|
||||||
<translation>Obiettivo %1 °C</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="321"/>
|
|
||||||
<source>Heating the house</source>
|
|
||||||
<translation>Riscaldamento della casa</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="326"/>
|
|
||||||
<source>Heating setpoint %1 °C · %2</source>
|
|
||||||
<translation>Obiettivo riscaldamento %1 °C · %2</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="438"/>
|
|
||||||
<source>Details</source>
|
|
||||||
<translation>Dettagli</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="448"/>
|
|
||||||
<source>Plant and accessories</source>
|
|
||||||
<translation>Impianto e accessori</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="460"/>
|
|
||||||
<source>Consumption and savings</source>
|
|
||||||
<translation>Consumi e risparmi</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>House temperature</source>
|
|
||||||
<translation type="vanished">Temperatura in casa</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>target %1 °C · %2</source>
|
|
||||||
<translation type="vanished">obiettivo %1 °C · %2</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="337"/>
|
|
||||||
<source>New house target</source>
|
|
||||||
<translation>Nuovo obiettivo casa</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="358"/>
|
|
||||||
<source>Set house to %1 °C</source>
|
|
||||||
<translation>Imposta casa a %1 °C</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="360"/>
|
|
||||||
<source>House temperature to %1 °C</source>
|
|
||||||
<translation>Temperatura della casa a %1 °C</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="313"/>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="365"/>
|
|
||||||
<source>Domestic hot water</source>
|
|
||||||
<translation>Acqua calda sanitaria</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>DHW target</source>
|
|
||||||
<translation type="vanished">Obiettivo acqua calda</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="382"/>
|
|
||||||
<source>New target</source>
|
|
||||||
<translation>Nuovo obiettivo</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="403"/>
|
|
||||||
<source>Set target %1 °C</source>
|
|
||||||
<translation>Imposta obiettivo %1 °C</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="405"/>
|
|
||||||
<source>DHW target to %1 °C</source>
|
|
||||||
<translation>Obiettivo ACS a %1 °C</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="418"/>
|
|
||||||
<source>Start DHW boost</source>
|
|
||||||
<translation>Avvia boost ACS</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="419"/>
|
|
||||||
<source>Starting DHW boost</source>
|
<source>Starting DHW boost</source>
|
||||||
<translation>Avvio del boost ACS</translation>
|
<translation>Avvio del boost ACS</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/pages/MainPage.qml" line="432"/>
|
<location filename="../qml/pages/MainPage.qml" line="106"/>
|
||||||
<source>Stop DHW boost</source>
|
|
||||||
<translation>Ferma boost ACS</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="433"/>
|
|
||||||
<source>Stopping DHW boost</source>
|
|
||||||
<translation>Arresto del boost ACS</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="154"/>
|
|
||||||
<source>Plant</source>
|
<source>Plant</source>
|
||||||
<translation>Impianto</translation>
|
<translation>Impianto</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Outdoor temperature</source>
|
<location filename="../qml/pages/MainPage.qml" line="248"/>
|
||||||
<translation type="vanished">Temperatura esterna</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Indoor temperature (pump)</source>
|
|
||||||
<translation type="vanished">Temperatura interna (pompa)</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Mode</source>
|
|
||||||
<translation type="vanished">Modalità</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Away mode</source>
|
<source>Away mode</source>
|
||||||
<translation type="vanished">Assenza</translation>
|
<translation>Assenza</translation>
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Night mode</source>
|
|
||||||
<translation type="vanished">Night mode</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Forced heating</source>
|
|
||||||
<translation type="vanished">Riscaldamento forzato</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Inline heater</source>
|
|
||||||
<translation type="vanished">Resistenze integrative</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Zone</source>
|
|
||||||
<translation type="vanished">Zone</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Errors</source>
|
|
||||||
<translation type="vanished">Errori</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Last reading</source>
|
|
||||||
<translation type="vanished">Aggiornato alle</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/pages/MainPage.qml" line="487"/>
|
|
||||||
<source>Commands are sent to the bridge and from there to the plant: they may take a few seconds.</source>
|
|
||||||
<translation>I comandi vengono inviati al bridge e da lì all'impianto: possono richiedere qualche secondo.</translation>
|
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@@ -886,6 +819,124 @@
|
|||||||
<translation>Errori segnalati</translation>
|
<translation>Errori segnalati</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>SetpointsPage</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="73"/>
|
||||||
|
<source>Refresh</source>
|
||||||
|
<translation>Aggiorna</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="77"/>
|
||||||
|
<source>Data</source>
|
||||||
|
<translation>Dati</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="81"/>
|
||||||
|
<source>Plant</source>
|
||||||
|
<translation>Impianto</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="85"/>
|
||||||
|
<source>Settings</source>
|
||||||
|
<translation>Impostazioni</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="95"/>
|
||||||
|
<source>Setpoints</source>
|
||||||
|
<translation>Regolazioni</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="98"/>
|
||||||
|
<source>Heating the house</source>
|
||||||
|
<translation>Riscaldamento della casa</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="101"/>
|
||||||
|
<source>Current target</source>
|
||||||
|
<translation>Obiettivo attuale</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="102"/>
|
||||||
|
<source>What the plant is keeping now</source>
|
||||||
|
<translation>Quello che l'impianto mantiene adesso</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="109"/>
|
||||||
|
<source>New house target</source>
|
||||||
|
<translation>Nuovo obiettivo casa</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="146"/>
|
||||||
|
<source>Set house to %1 °C</source>
|
||||||
|
<translation>Imposta casa a %1 °C</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="147"/>
|
||||||
|
<source>House temperature to %1 °C</source>
|
||||||
|
<translation>Temperatura della casa a %1 °C</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="153"/>
|
||||||
|
<source>Domestic hot water</source>
|
||||||
|
<translation>Acqua calda sanitaria</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="156"/>
|
||||||
|
<source>DHW target</source>
|
||||||
|
<translation>Obiettivo acqua calda</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="157"/>
|
||||||
|
<source>Water now %1 °C</source>
|
||||||
|
<translation>Acqua ora %1 °C</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="164"/>
|
||||||
|
<source>New target</source>
|
||||||
|
<translation>Nuovo obiettivo</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="199"/>
|
||||||
|
<source>Set target %1 °C</source>
|
||||||
|
<translation>Imposta obiettivo %1 °C</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="200"/>
|
||||||
|
<source>DHW target to %1 °C</source>
|
||||||
|
<translation>Obiettivo ACS a %1 °C</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="206"/>
|
||||||
|
<source>Hot water boost</source>
|
||||||
|
<translation>Boost acqua calda</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="209"/>
|
||||||
|
<source>Start DHW boost</source>
|
||||||
|
<translation>Avvia boost ACS</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="210"/>
|
||||||
|
<source>Starting DHW boost</source>
|
||||||
|
<translation>Avvio del boost ACS</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="215"/>
|
||||||
|
<source>Stop DHW boost</source>
|
||||||
|
<translation>Ferma boost ACS</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="216"/>
|
||||||
|
<source>Stopping DHW boost</source>
|
||||||
|
<translation>Arresto del boost ACS</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/pages/SetpointsPage.qml" line="223"/>
|
||||||
|
<source>Commands go through the bridge and may take a few seconds. The status refreshes by itself afterwards.</source>
|
||||||
|
<translation>I comandi passano dal bridge e possono richiedere qualche secondo. Dopo l'invio lo stato si aggiorna da solo.</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsPage</name>
|
<name>SettingsPage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|||||||
Reference in New Issue
Block a user