Compare commits
4
Commits
36033daf3f
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4050b3b5d7 | ||
|
|
70fe2299ba | ||
|
|
75c61cace2 | ||
|
|
5305fab309 |
+7
-1
@@ -161,7 +161,7 @@ python3 tests/ui_contract_check.py http://192.168.3.21:8790
|
||||
senza telefono)
|
||||
- **48/48** verifiche offline del bridge (`bridge/test_bridge_commands.py`),
|
||||
comprese le conversioni Wh→kWh e degli importi delle statistiche
|
||||
- **190/190** stringhe tradotte nel catalogo italiano: il test carica il `.qm`
|
||||
- **191/191** stringhe tradotte nel catalogo italiano: il test carica il `.qm`
|
||||
compilato come fa `main.cpp` e verifica che in inglese l'etichetta di stato sia
|
||||
la sorgente e in italiano quella tradotta, e che togliendo il catalogo si torni
|
||||
all'inglese
|
||||
@@ -169,6 +169,11 @@ python3 tests/ui_contract_check.py http://192.168.3.21:8790
|
||||
posizione del simbolo di valuta seguono la lingua (verificato per entrambe)
|
||||
- `qmllint` pulito su tutti i QML (valida solo la sintassi: senza il modulo
|
||||
Silica una proprietà inesistente passa in silenzio)
|
||||
- **nessuna assegnazione duplicata** nei QML (`tests/qml_check_bindings.py`,
|
||||
13 file): assegnare due volte la stessa proprietà nello stesso oggetto — due
|
||||
`Component.onCompleted` in una pagina, tipicamente — fa fallire la creazione
|
||||
dell'oggetto in Qt 5.6, e sul telefono si vede solo `Type MainPage unavailable`
|
||||
senza il nome del file. Il controllo impiega millisecondi e dice la riga
|
||||
- provata dal vivo in **sola lettura** su un impianto Aira Home, statistiche
|
||||
comprese: coincidono con quelle mostrate dall'app ufficiale per lo stesso
|
||||
periodo (calore prodotto 70,8 kWh, elettricità 29,3 kWh, COP acqua calda 4,42,
|
||||
@@ -208,6 +213,7 @@ qml/components/NoticeBar.qml messaggi dei comandi, ancorati in fondo
|
||||
qml/components/ActionButton.qml pulsante di comando, con conferma opzionale
|
||||
tests/core_test.cpp verifiche del nucleo (headless)
|
||||
tests/ui_contract_check.py chiavi dei QML contro quelle del bridge (bridge attivo)
|
||||
tests/qml_check_bindings.py assegnazioni duplicate di proprieta' nei QML
|
||||
bridge/aira_bridge.py servizio HTTP/1.1 + JSON verso il cloud (gRPC)
|
||||
bridge/setup_creds.py salva le credenziali Aira (file 600)
|
||||
bridge/aira_probe.py sonda di sola lettura: login + stato impianto
|
||||
|
||||
@@ -149,13 +149,18 @@ Verified so far:
|
||||
including that a zone command always carries every zone, that absurd values
|
||||
are refused (40 °C, zone 3, text), and the Wh→kWh / money conversions of the
|
||||
statistics
|
||||
- **190/190** strings translated in the Italian catalogue, checked by loading
|
||||
- **191/191** strings translated in the Italian catalogue, checked by loading
|
||||
the compiled `.qm` in the test the same way `main.cpp` does: source English
|
||||
in, Italian out, and back to English when the catalogue is removed
|
||||
- numbers, amounts and month names formatted through `QLocale`, so the decimal
|
||||
separator and the currency position follow the language (verified for both)
|
||||
- `qmllint` clean on every QML file. Note it validates syntax only: without the
|
||||
Silica module an invalid Silica property passes silently
|
||||
- **no duplicate property assignment** in the QML (`tests/qml_check_bindings.py`,
|
||||
13 files): assigning the same property twice in one object — two
|
||||
`Component.onCompleted` in a page, typically — makes Qt 5.6 fail to create the
|
||||
object, and all you see on the device is `Type MainPage unavailable` with no
|
||||
file named. The check runs in milliseconds and names the line
|
||||
- read-only queries against one real Aira Home unit, through the bridge —
|
||||
including the cloud statistics, which match what the official app shows for
|
||||
the same period (heat produced 70.8 kWh, electricity 29.3 kWh, hot-water COP
|
||||
@@ -223,6 +228,7 @@ qml/components/NoticeBar.qml command messages, anchored to the bottom edge
|
||||
qml/components/ActionButton.qml command button, optional confirmation
|
||||
tests/core_test.cpp core checks (headless)
|
||||
tests/ui_contract_check.py QML keys vs bridge keys (bridge must be running)
|
||||
tests/qml_check_bindings.py duplicate property assignments in the QML
|
||||
bridge/ local HTTP bridge -> see bridge/README.md
|
||||
translations/ harbour-aira-it.ts (English is the source language)
|
||||
docs/PIANO.md project plan and decisions (Italian)
|
||||
|
||||
+19
-1
@@ -275,8 +275,26 @@ si rilegge da solo (2 s): l'aggiornamento automatico, prima, non esisteva.
|
||||
|
||||
**Stato breve ed esteso in C++** (`AiraJson::stateShort/stateLong/statusLevel`):
|
||||
logica pura, verificabile senza SDK e non duplicata fra Home e Impianto. Test
|
||||
del nucleo: **79/79** (erano 61). Stringhe: **190/190** tradotte. Anteprime
|
||||
del nucleo: **79/79** (erano 61). Stringhe: **191/191** tradotte. Anteprime
|
||||
rigenerate (nuova `regolazioni.png`) in italiano e inglese.
|
||||
|
||||
**Copertina** (`qml/cover/CoverPage.qml`): pallino di stato come in Home, la
|
||||
temperatura grande si spegne quando i numeri sono vecchi e l'etichetta finale è
|
||||
diventata "esterna 18,0 °C" (era "est.", sigla che non diceva niente), con la
|
||||
riga dei numeri vecchi al posto della temperatura esterna quando serve.
|
||||
|
||||
**Prima build sul telefono (0.6.0): la Home non si apriva.** Il log diceva
|
||||
`harbour-aira.qml:9:30: Type MainPage unavailable`, cioè l'app si avviava senza
|
||||
la pagina iniziale, e non nominava nessun file dei miei. Causa: due assegnazioni
|
||||
di `Component.onCompleted` nello stesso oggetto (`MainPage.qml`), una vecchia e
|
||||
una aggiunta con la riga di misura dell'altezza. In Qt 5.6 non è un warning
|
||||
innocuo: la pagina non si crea più. Il codice è stato unito in una sola
|
||||
assegnazione e, perché non ricapiti, `tests/qml_check_bindings.py` cerca le
|
||||
assegnazioni duplicate in tutti i QML (verificato: intercetta il caso
|
||||
`70fe229`, il codice attuale è pulito). Da questa prima esecuzione sappiamo
|
||||
anche che il resto dell'avvio funziona: configurazione letta
|
||||
(`baseUrl=[192.168.3.21:8790]`, token presente), catalogo italiano caricato
|
||||
(`it_IT`), versione corretta in log.
|
||||
|
||||
- Nessun comando nuovo all'impianto: anche questa versione resta **sola
|
||||
lettura** finché non si prova l'invio dal telefono.
|
||||
|
||||
+11
-3
@@ -10,6 +10,14 @@ Immagini di questo studio (schemi, non anteprime): `docs/ux/`.
|
||||
|
||||
## 0. Cosa è stato deciso e cosa è stato fatto (0.6.0)
|
||||
|
||||
**Prima build sul telefono:** la Home non si apriva — `Type MainPage unavailable`.
|
||||
Causa: due assegnazioni di `Component.onCompleted` nello stesso oggetto, che in
|
||||
Qt 5.6 impediscono la creazione della pagina. Corretto nella 0.6.1 e coperto da
|
||||
`tests/qml_check_bindings.py`. Tutto il resto dell'avvio funziona (configurazione
|
||||
letta, catalogo italiano caricato). Il primo giro sul device ha quindi già dato
|
||||
la sua risposta più importante: la riga `harbour-aira home: contenuto … schermo …`
|
||||
arriva nei log e si può leggere.
|
||||
|
||||
Le quattro scelte, applicate:
|
||||
|
||||
1. La frase di stato lunga sta nella pagina **Impianto**; in Home resta la riga
|
||||
@@ -26,12 +34,12 @@ P9, P10 (diagnostica in Impianto), P11.
|
||||
Rimandato: P8 (azioni sulla copertina), in attesa della prova sul telefono.
|
||||
|
||||
Verifiche fatte qui: **79 verifiche del nucleo** (erano 61), `qmllint` pulito su
|
||||
tutti i file QML, 190/190 stringhe tradotte, anteprime rigenerate in inglese e
|
||||
tutti i file QML, 191/191 stringhe tradotte, anteprime rigenerate in inglese e
|
||||
italiano, contratto dei dati fra UI e bridge rispettato
|
||||
(`tests/ui_contract_check.py`).
|
||||
Da provare sul telefono: che `TextSwitch` si istanzi davvero, l'altezza reale
|
||||
della Home (riga di log con `contentHeight` contro l'altezza dello schermo) e
|
||||
l'uso con una mano sola.
|
||||
della Home (la riga `harbour-aira home: contenuto … schermo …` è già nel codice,
|
||||
basta leggerla nei log) e l'uso con una mano sola.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 31 KiB |
+41
-9
@@ -11,14 +11,40 @@ CoverBackground {
|
||||
return api.formatValue(v)
|
||||
}
|
||||
|
||||
Label {
|
||||
id: titleLabel
|
||||
// Colore del pallino: gli stessi criteri della Home (vedi MainPage.qml).
|
||||
// Un dato vecchio e' ambra come un modo attivo: un dato vecchio non e' un
|
||||
// dato buono, e la copertina e' il posto dove si guarda di sfuggita.
|
||||
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"
|
||||
}
|
||||
|
||||
Row {
|
||||
id: intestazione
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: Theme.paddingLarge
|
||||
text: "Aira"
|
||||
color: Theme.primaryColor
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
spacing: Theme.paddingSmall
|
||||
|
||||
Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: Theme.paddingSmall
|
||||
height: width
|
||||
radius: width / 2
|
||||
color: cover.statusColor()
|
||||
}
|
||||
|
||||
Label {
|
||||
text: "Aira"
|
||||
color: Theme.primaryColor
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -29,8 +55,9 @@ CoverBackground {
|
||||
Label {
|
||||
width: parent.width
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
// Spenta quando i numeri sono vecchi: non deve sembrare fresca.
|
||||
color: api.stale ? Theme.secondaryColor : Theme.primaryColor
|
||||
text: cover.t("zone1_temperature") + " °C"
|
||||
color: Theme.primaryColor
|
||||
font.pixelSize: Theme.fontSizeHuge
|
||||
}
|
||||
|
||||
@@ -57,8 +84,13 @@ CoverBackground {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: Theme.paddingMedium
|
||||
text: qsTr("outdoor %1 °C").arg(cover.t("outdoor_temperature"))
|
||||
color: Theme.secondaryColor
|
||||
// Qui c'e' posto per dire che i numeri non sono freschi.
|
||||
text: api.stale
|
||||
? qsTr("Not updated · last %1").arg(api.lastUpdate)
|
||||
: qsTr("outside %1 °C").arg(cover.t("outdoor_temperature"))
|
||||
color: api.stale ? "orange" : Theme.secondaryColor
|
||||
font.pixelSize: Theme.fontSizeExtraSmall
|
||||
truncationMode: TruncationMode.Fade
|
||||
width: parent.width - 2 * Theme.paddingMedium
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,9 +78,13 @@ Page {
|
||||
pageStack.push(Qt.resolvedUrl("DataPage.qml"))
|
||||
}
|
||||
|
||||
// UNA sola assegnazione: in Qt 5.6 assegnare Component.onCompleted due volte
|
||||
// e' un errore di compilazione del file, e la pagina non si crea piu'
|
||||
// ("Type MainPage unavailable" e app senza Home).
|
||||
Component.onCompleted: {
|
||||
if (api.configured)
|
||||
api.refresh()
|
||||
misura.start()
|
||||
}
|
||||
|
||||
// Fuori dal pulsante: dentro il pulsante i figli finiscono nel contentItem.
|
||||
@@ -294,4 +298,15 @@ Page {
|
||||
}
|
||||
|
||||
NoticeBar { }
|
||||
|
||||
// La disposizione non e' definitiva subito: si misura un secondo dopo.
|
||||
// Questa e' la riga da leggere alla prima build sul telefono: la Home deve
|
||||
// stare in una schermata sola, se "contenuto" supera "schermo" c'e' ancora
|
||||
// qualcosa da togliere (o da accettare, ma sapendolo).
|
||||
Timer {
|
||||
id: misura
|
||||
interval: 1000
|
||||
onTriggered: console.log("harbour-aira home: contenuto", flick.contentHeight,
|
||||
"schermo", height)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Name: harbour-aira
|
||||
Summary: Control your Aira heat pump through a local bridge
|
||||
Version: 0.6.0
|
||||
Version: 0.6.1
|
||||
Release: 1
|
||||
Group: Qt/Qt
|
||||
License: MIT
|
||||
@@ -37,6 +37,12 @@ Address and token of the bridge live in the app settings (AppConfigLocation);
|
||||
no personal data is stored in the binary.
|
||||
|
||||
%changelog
|
||||
* Sat Oct 10 2026 Carlo <carlo@carlobaratto.it> - 0.6.1-1
|
||||
- correzione: la Home non si apriva ("Type MainPage unavailable", app senza
|
||||
pagina iniziale). Causa: due assegnazioni di Component.onCompleted nello
|
||||
stesso oggetto; in Qt 5.6 la pagina non si crea piu' e il messaggio non dice
|
||||
quale sia il file. Ora un controllo automatico le intercetta in pochi
|
||||
millisecondi (tests/qml_check_bindings.py), prima della build
|
||||
* Sat Oct 10 2026 Carlo <carlo@carlobaratto.it> - 0.6.0-1
|
||||
- Home di sola consultazione: stato in una riga con pallino colorato, le due
|
||||
letture (casa e acqua calda) grandi e toccabili, tre azioni rapide; le due
|
||||
@@ -78,7 +84,7 @@ make %{?_smp_mflags}
|
||||
# mancante NON fa fallire la compilazione: l'app resterebbe in inglese senza dire
|
||||
# niente. Qui lo si rigenera comunque; il file finisce nella stessa cartella dove
|
||||
# lo cerca src/translator.cpp. Il .ts si cerca con find perche' sfdk usa i
|
||||
# sorgenti live (shadow build) e la cartella puo' chiamarsi harbour-aira-0.5.0
|
||||
# sorgenti live (shadow build) e la cartella puo' chiamarsi harbour-aira-0.6.0
|
||||
# (tarball), harbour-aira (clone) o harbour-aira-main (archivio di Gitea).
|
||||
TS=$(find %{_builddir}/.. -maxdepth 4 -name 'harbour-aira-it.ts' 2>/dev/null | head -1)
|
||||
if [ -z "$TS" ]; then
|
||||
|
||||
@@ -557,6 +557,8 @@ def cover_screen() -> Image.Image:
|
||||
card = [96, 430, W - 96, 430 + 470]
|
||||
d.rounded_rectangle(card, radius=34, fill=(14, 18, 24), outline=ACCENT, width=2)
|
||||
d.text((card[0] + 34, card[1] + 30), T("app"), font=font(40, bold=True), fill=PRIMARY)
|
||||
# pallino di stato, come nella copertina vera (verde = tutto regolare)
|
||||
d.ellipse([card[2] - 56, card[1] + 48, card[2] - 32, card[1] + 72], fill=OK)
|
||||
d.line([(card[0] + 34, card[1] + 100), (card[2] - 34, card[1] + 100)],
|
||||
fill=BTN_EDGE, width=2)
|
||||
y = card[1] + 132
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
|
||||
|
||||
app->setOrganizationName(QStringLiteral("harbour"));
|
||||
app->setApplicationName(QStringLiteral("aira"));
|
||||
app->setApplicationVersion(QStringLiteral("0.6.0"));
|
||||
app->setApplicationVersion(QStringLiteral("0.6.1"));
|
||||
|
||||
Settings settings;
|
||||
ApiClient api(&settings);
|
||||
@@ -36,7 +36,7 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
|
||||
|
||||
// Prima riga del log: dice subito se il device sta girando la build nuova
|
||||
// o una stale (trappola nota del build engine).
|
||||
qDebug() << "harbour-aira v0.6.0 build" << __DATE__ << __TIME__;
|
||||
qDebug() << "harbour-aira v0.6.1 build" << __DATE__ << __TIME__;
|
||||
|
||||
view->rootContext()->setContextProperty(QStringLiteral("appSettings"), &settings);
|
||||
view->rootContext()->setContextProperty(QStringLiteral("api"), &api);
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Assegnazioni duplicate di proprieta' negli stessi oggetti QML.
|
||||
|
||||
Perche' esiste: in Qt 5.6 assegnare due volte la stessa proprieta' di un oggetto
|
||||
QML (tipico: due `Component.onCompleted` nella stessa pagina) non e' un errore
|
||||
innocuo: il file compila con un warning "Property value set multiple times" e
|
||||
l'oggetto NON si crea piu'. Dall'esterno si vede solo
|
||||
|
||||
harbour-aira.qml:9:30: Type MainPage unavailable
|
||||
|
||||
cioe' l'app che si apre senza la pagina iniziale, senza dire il perche'.
|
||||
Il kit Silica non vede niente di tutto questo (qmllint conosce il QML, non il
|
||||
significato di questi binding), quindi il controllo sta qui e gira in pochi
|
||||
millisecondi.
|
||||
|
||||
Uso:
|
||||
python3 tests/qml_check_bindings.py [cartella_qml]
|
||||
python3 tests/qml_check_bindings.py --dettagli # elenca anche l'ok
|
||||
Esce 1 se trova duplicati, 0 se e' pulito.
|
||||
"""
|
||||
|
||||
import pathlib
|
||||
import re
|
||||
import sys
|
||||
|
||||
# Riga che apre un oggetto QML: un componente (maiuscola) oppure un gruppo di
|
||||
# proprieta' noto. Il corpo di un gestore (onClicked:) o di una funzione e' JS,
|
||||
# e li' dentro i "duplicati" sono normali (ternari, oggetti letterali, rami).
|
||||
APRE_OGGETTO = re.compile(r"^\s*([A-Z][A-Za-z0-9_]*)\s*\{")
|
||||
APRE_GRUPPO = re.compile(r"^\s*(anchors|font|Layout\.[A-Za-z]+)\s*\{")
|
||||
APRE_JS = re.compile(r"^\s*(function\s+\w+|if\b|else\b|for\b|while\b|switch\b|do\b|try\b|catch\b)\s*[\({]")
|
||||
APRE_GESTORE = re.compile(r"^\s*on[A-Z][A-Za-z0-9_]*\s*:")
|
||||
|
||||
PROPRIETA = re.compile(r"^\s*((?:readonly\s+)?property\s+\S+\s+([A-Za-z_]\w*)|signal\s+(\w+)|function\s+(\w+)|([A-Za-z_][\w.]*))\s*:")
|
||||
SENZA_COMMENTO = re.compile(r"//.*$")
|
||||
|
||||
|
||||
def chiave(riga: str):
|
||||
"""Nome della proprieta' assegnata dalla riga, o None."""
|
||||
m = PROPRIETA.match(SENZA_COMMENTO.sub("", riga))
|
||||
if not m:
|
||||
return None
|
||||
return m.group(2) or m.group(3) or m.group(4) or m.group(5)
|
||||
|
||||
|
||||
def controlla(testo: str):
|
||||
"""Ritorna la lista di (riga, chiave) duplicate nello stesso oggetto."""
|
||||
pila = [("qml", {})] # (tipo ambiente, chiavi viste)
|
||||
problemi = []
|
||||
for numero, riga in enumerate(testo.splitlines(), 1):
|
||||
pulita = SENZA_COMMENTO.sub("", riga)
|
||||
if not pulita.strip():
|
||||
continue
|
||||
|
||||
# Chiusura: si esce dall'ambiente corrente.
|
||||
while pulita.strip().startswith("}") and len(pila) > 1:
|
||||
pila.pop()
|
||||
pulita = pulita.strip()[1:]
|
||||
if not pulita.strip():
|
||||
break
|
||||
if not pulita.strip():
|
||||
continue
|
||||
|
||||
ambiente, chiavi = pila[-1]
|
||||
if ambiente == "qml":
|
||||
k = chiave(pulita)
|
||||
if k:
|
||||
if k in chiavi:
|
||||
problemi.append((numero, k))
|
||||
else:
|
||||
chiavi[k] = numero
|
||||
|
||||
# Apertura di un nuovo ambiente: il contenuto e' QML solo se la riga
|
||||
# apre un oggetto o un gruppo; gestori e funzioni aprono JS.
|
||||
apre_js = bool(APRE_JS.match(pulita)) or bool(APRE_GESTORE.match(pulita))
|
||||
apre_qml = (bool(APRE_OGGETTO.match(pulita)) or bool(APRE_GRUPPO.match(pulita))) \
|
||||
and not apre_js
|
||||
# Una proprieta' il cui valore e' un oggetto letterale JS non e' QML.
|
||||
if ":" in pulita and "{" in pulita and not apre_qml and not apre_js:
|
||||
apre_js = True
|
||||
if pulita.count("{") > pulita.count("}"):
|
||||
pila.append(("qml" if apre_qml else "js", {}))
|
||||
return problemi
|
||||
|
||||
|
||||
def main(argv):
|
||||
argomenti = [a for a in argv[1:] if not a.startswith("--")]
|
||||
radice = pathlib.Path(argomenti[0] if argomenti else "qml")
|
||||
dettagli = "--dettagli" in argv
|
||||
|
||||
file_qml = sorted(radice.rglob("*.qml"))
|
||||
if not file_qml:
|
||||
print("nessun file QML in", radice)
|
||||
return 1
|
||||
|
||||
totale = 0
|
||||
for percorso in file_qml:
|
||||
problemi = controlla(percorso.read_text(encoding="utf-8"))
|
||||
relative = percorso.relative_to(radice.parent if radice.name == "qml" else radice)
|
||||
if problemi:
|
||||
totale += len(problemi)
|
||||
print("%s: %d assegnazioni duplicate" % (relative, len(problemi)))
|
||||
for numero, k in problemi:
|
||||
print(" riga %d: '%s' gia' assegnata in questo oggetto" % (numero, k))
|
||||
elif dettagli:
|
||||
print("%s: pulito" % relative)
|
||||
|
||||
print("---")
|
||||
if totale:
|
||||
print("ESITO: %d assegnazioni duplicate (l'oggetto non si crea: "
|
||||
"vedi Qt 5.6, 'Property value set multiple times')" % totale)
|
||||
return 1
|
||||
print("ESITO: nessuna assegnazione duplicata in %d file" % len(file_qml))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main(sys.argv))
|
||||
@@ -281,7 +281,7 @@
|
||||
<message>
|
||||
<location filename="../qml/pages/CommandsPage.qml" line="75"/>
|
||||
<source>Lowers the house and stops the hot water</source>
|
||||
<translation>Abbassa la casa e spegne l'acqua calda</translation>
|
||||
<translation>Abbassa la casa e spegne l'acqua calda</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/CommandsPage.qml" line="88"/>
|
||||
@@ -306,7 +306,7 @@
|
||||
<message>
|
||||
<location filename="../qml/pages/CommandsPage.qml" line="121"/>
|
||||
<source>The heat pump keeps the water in temperature</source>
|
||||
<translation>Mantiene l'acqua in temperatura</translation>
|
||||
<translation>Mantiene l'acqua in temperatura</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/CommandsPage.qml" line="135"/>
|
||||
@@ -337,19 +337,24 @@
|
||||
<context>
|
||||
<name>CoverPage</name>
|
||||
<message>
|
||||
<location filename="../qml/cover/CoverPage.qml" line="40"/>
|
||||
<location filename="../qml/cover/CoverPage.qml" line="67"/>
|
||||
<source>house · target %1 °C</source>
|
||||
<translation>casa · obiettivo %1 °C</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/cover/CoverPage.qml" line="49"/>
|
||||
<location filename="../qml/cover/CoverPage.qml" line="76"/>
|
||||
<source>DHW %1 °C · target %2 °C</source>
|
||||
<translation>ACS %1 °C · obiettivo %2 °C</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/cover/CoverPage.qml" line="60"/>
|
||||
<source>outdoor %1 °C</source>
|
||||
<translation>est. %1 °C</translation>
|
||||
<location filename="../qml/cover/CoverPage.qml" line="89"/>
|
||||
<source>Not updated · last %1</source>
|
||||
<translation>Non aggiornato · ultimo %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/cover/CoverPage.qml" line="90"/>
|
||||
<source>outside %1 °C</source>
|
||||
<translation>esterna %1 °C</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
Reference in New Issue
Block a user