0.2.1: temperatura della casa in cima alla home, acqua calda in sezione dedicata
This commit is contained in:
@@ -53,7 +53,7 @@ sfdk build # RPM in RPMS/
|
|||||||
sfdk deploy # sul dispositivo collegato
|
sfdk deploy # sul dispositivo collegato
|
||||||
```
|
```
|
||||||
|
|
||||||
Sorgenti dal tarball: `tar xzf harbour-aira-0.2.0.tar.gz` e compilare in una
|
Sorgenti dal tarball: `tar xzf harbour-aira-0.2.1.tar.gz` e compilare in una
|
||||||
cartella nuova (mai sopra una estrazione precedente: i Makefile restano stale).
|
cartella nuova (mai sopra una estrazione precedente: i Makefile restano stale).
|
||||||
|
|
||||||
### Verifica locale, senza SDK
|
### Verifica locale, senza SDK
|
||||||
|
|||||||
@@ -100,6 +100,10 @@ Non verificabile qui (serve il suo PC + il telefono): build RPM, istallazione, U
|
|||||||
- **App 0.2.0**: sezione "Riscaldamento" nella dashboard (temperatura in casa, obiettivo,
|
- **App 0.2.0**: sezione "Riscaldamento" nella dashboard (temperatura in casa, obiettivo,
|
||||||
stato zona, slider 5–30 °C a passi di 0,5 con conferma) e copertina con la temperatura di
|
stato zona, slider 5–30 °C a passi di 0,5 con conferma) e copertina con la temperatura di
|
||||||
casa. Aggiunte le etichette per gli stati `PUMP_MODE_STATE_*`. Nucleo: **29/29**.
|
casa. Aggiunte le etichette per gli stati `PUMP_MODE_STATE_*`. Nucleo: **29/29**.
|
||||||
|
- **App 0.2.1** (richiesta dell'utente): la temperatura della casa diventa il dato
|
||||||
|
principale **in cima** alla home (valore grande, barra, obiettivo, slider e pulsante),
|
||||||
|
l'acqua calda sanitaria scende in una propria sezione sotto, lo stato impianto va in
|
||||||
|
fondo. Stessa gerarchia nella copertina: casa in grande, ACS in una riga secondaria.
|
||||||
- **F3 fatto**: `harbour-aira-bridge.service` (systemd utente, `enable --now`, parte al boot
|
- **F3 fatto**: `harbour-aira-bridge.service` (systemd utente, `enable --now`, parte al boot
|
||||||
grazie a `Linger=yes`, `Restart=on-failure` verificato con SIGKILL → riparte in ~10 s) e
|
grazie a `Linger=yes`, `Restart=on-failure` verificato con SIGKILL → riparte in ~10 s) e
|
||||||
regola `52-aira-bridge-lan.conf` in `/etc/nftables.d/`. Il firewall YunoHost ha
|
regola `52-aira-bridge-lan.conf` in `/etc/nftables.d/`. Il firewall YunoHost ha
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 30 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 73 KiB |
@@ -29,7 +29,7 @@ CoverBackground {
|
|||||||
Label {
|
Label {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
text: cover.t("dhw_current") + " °C"
|
text: cover.t("zone1_temperature") + " °C"
|
||||||
color: Theme.primaryColor
|
color: Theme.primaryColor
|
||||||
font.pixelSize: Theme.fontSizeHuge
|
font.pixelSize: Theme.fontSizeHuge
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,7 @@ CoverBackground {
|
|||||||
Label {
|
Label {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
text: qsTr("ACS · obiettivo %1 °C").arg(cover.t("dhw_target"))
|
text: qsTr("casa · obiettivo %1 °C").arg(cover.t("zone1_setpoint"))
|
||||||
color: Theme.secondaryColor
|
color: Theme.secondaryColor
|
||||||
font.pixelSize: Theme.fontSizeExtraSmall
|
font.pixelSize: Theme.fontSizeExtraSmall
|
||||||
truncationMode: TruncationMode.Fade
|
truncationMode: TruncationMode.Fade
|
||||||
@@ -46,7 +46,7 @@ CoverBackground {
|
|||||||
Label {
|
Label {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
text: qsTr("casa %1 °C · obiettivo %2 °C").arg(cover.t("zone1_temperature")).arg(cover.t("zone1_setpoint"))
|
text: qsTr("ACS %1 °C · obiettivo %2 °C").arg(cover.t("dhw_current")).arg(cover.t("dhw_target"))
|
||||||
color: Theme.secondaryColor
|
color: Theme.secondaryColor
|
||||||
font.pixelSize: Theme.fontSizeExtraSmall
|
font.pixelSize: Theme.fontSizeExtraSmall
|
||||||
truncationMode: TruncationMode.Fade
|
truncationMode: TruncationMode.Fade
|
||||||
|
|||||||
+59
-63
@@ -139,46 +139,7 @@ Page {
|
|||||||
onClicked: page.openSettings()
|
onClicked: page.openSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- acqua calda ---------------------------------------------- //
|
// ---- casa: temperatura della casa (dato principale) ------------ //
|
||||||
Label {
|
|
||||||
visible: api.configured
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
text: qsTr("Acqua calda sanitaria")
|
|
||||||
color: Theme.secondaryColor
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
visible: api.configured
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
text: page.temp("dhw_current") + " °C"
|
|
||||||
color: Theme.primaryColor
|
|
||||||
font.pixelSize: Theme.fontSizeHuge
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
visible: api.configured
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
text: qsTr("obiettivo %1 °C").arg(page.temp("dhw_target"))
|
|
||||||
color: Theme.secondaryColor
|
|
||||||
font.pixelSize: Theme.fontSizeExtraSmall
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- riscaldamento: temperatura della casa --------------------- //
|
|
||||||
SectionHeader { visible: api.configured; text: qsTr("Riscaldamento") }
|
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
visible: api.configured
|
visible: api.configured
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
@@ -192,25 +153,34 @@ Page {
|
|||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
text: page.temp("zone1_temperature") + " °C"
|
text: page.temp("zone1_temperature") + " °C"
|
||||||
color: Theme.primaryColor
|
color: Theme.primaryColor
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
font.pixelSize: Theme.fontSizeHuge
|
||||||
}
|
}
|
||||||
|
|
||||||
InfoRow {
|
ProgressBar {
|
||||||
visible: api.configured
|
visible: api.configured
|
||||||
label: qsTr("Obiettivo casa")
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
value: page.temp("zone1_setpoint") + " °C"
|
width: parent.width - 4 * Theme.horizontalPageMargin
|
||||||
|
minimumValue: 5
|
||||||
|
maximumValue: 30
|
||||||
|
value: {
|
||||||
|
var v = page.raw("zone1_temperature")
|
||||||
|
return (v === undefined || v === null) ? 0 : Number(v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
InfoRow {
|
|
||||||
|
Label {
|
||||||
visible: api.configured
|
visible: api.configured
|
||||||
label: qsTr("Stato riscaldamento")
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
value: api.modeLabel(page.raw("zone1_mode"))
|
text: qsTr("obiettivo %1 °C · %2").arg(page.temp("zone1_setpoint")).arg(api.modeLabel(page.raw("zone1_mode")))
|
||||||
|
color: Theme.secondaryColor
|
||||||
|
font.pixelSize: Theme.fontSizeExtraSmall
|
||||||
}
|
}
|
||||||
|
|
||||||
Slider {
|
Slider {
|
||||||
id: casaSlider
|
id: casaSlider
|
||||||
visible: api.configured
|
visible: api.configured
|
||||||
width: parent.width
|
width: parent.width
|
||||||
label: qsTr("Nuovo obiettivo")
|
label: qsTr("Nuovo obiettivo casa")
|
||||||
minimumValue: 5
|
minimumValue: 5
|
||||||
maximumValue: 30
|
maximumValue: 30
|
||||||
stepSize: 0.5
|
stepSize: 0.5
|
||||||
@@ -237,27 +207,39 @@ Page {
|
|||||||
function() { api.sendCommand("set_heating_setpoint", page.targetCasa) })
|
function() { api.sendCommand("set_heating_setpoint", page.targetCasa) })
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- stato impianto ------------------------------------------- //
|
// ---- acqua calda sanitaria ------------------------------------- //
|
||||||
SectionHeader { visible: api.configured; text: qsTr("Impianto") }
|
SectionHeader { visible: api.configured; text: qsTr("Acqua calda sanitaria") }
|
||||||
|
|
||||||
InfoRow { visible: api.configured; label: qsTr("Temperatura esterna"); value: page.temp("outdoor_temperature") + " °C" }
|
Label {
|
||||||
InfoRow { visible: api.configured; label: qsTr("Temperatura interna (pompa)"); value: page.temp("indoor_temperature") + " °C" }
|
visible: api.configured
|
||||||
InfoRow { visible: api.configured; label: qsTr("Modalità"); value: api.modeLabel(page.raw("operating_status")) }
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
InfoRow { visible: api.configured; label: qsTr("Assenza"); value: page.flag("away_mode") }
|
text: page.temp("dhw_current") + " °C"
|
||||||
InfoRow { visible: api.configured; label: qsTr("Night mode"); value: page.flag("night_mode") }
|
color: Theme.primaryColor
|
||||||
InfoRow { visible: api.configured; label: qsTr("Riscaldamento forzato"); value: page.flag("force_heating") }
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
InfoRow { visible: api.configured; label: qsTr("Resistenze integrative"); value: page.flag("inline_heater") }
|
}
|
||||||
InfoRow { visible: api.configured; label: qsTr("Zone"); value: page.count("zones") }
|
|
||||||
InfoRow { visible: api.configured; label: qsTr("Errori"); value: page.count("errors_count") }
|
|
||||||
InfoRow { visible: api.configured; label: qsTr("Aggiornato alle"); value: page.shortTime(page.raw("pump_updated")) }
|
|
||||||
|
|
||||||
// ---- comandi --------------------------------------------------- //
|
ProgressBar {
|
||||||
SectionHeader { visible: api.configured; text: qsTr("Comandi acqua calda") }
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoRow {
|
||||||
|
visible: api.configured
|
||||||
|
label: qsTr("Obiettivo acqua calda")
|
||||||
|
value: page.temp("dhw_target") + " °C"
|
||||||
|
}
|
||||||
|
|
||||||
Slider {
|
Slider {
|
||||||
visible: api.configured
|
visible: api.configured
|
||||||
width: parent.width
|
width: parent.width
|
||||||
label: qsTr("Obiettivo acqua calda")
|
label: qsTr("Nuovo obiettivo")
|
||||||
minimumValue: 45
|
minimumValue: 45
|
||||||
maximumValue: 60
|
maximumValue: 60
|
||||||
stepSize: 1
|
stepSize: 1
|
||||||
@@ -312,6 +294,20 @@ Page {
|
|||||||
function() { api.sendCommand("hot_water_boost_off") })
|
function() { api.sendCommand("hot_water_boost_off") })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- stato impianto ------------------------------------------- //
|
||||||
|
SectionHeader { visible: api.configured; text: qsTr("Impianto") }
|
||||||
|
|
||||||
|
InfoRow { visible: api.configured; label: qsTr("Temperatura esterna"); value: page.temp("outdoor_temperature") + " °C" }
|
||||||
|
InfoRow { visible: api.configured; label: qsTr("Temperatura interna (pompa)"); value: page.temp("indoor_temperature") + " °C" }
|
||||||
|
InfoRow { visible: api.configured; label: qsTr("Modalità"); value: api.modeLabel(page.raw("operating_status")) }
|
||||||
|
InfoRow { visible: api.configured; label: qsTr("Assenza"); value: page.flag("away_mode") }
|
||||||
|
InfoRow { visible: api.configured; label: qsTr("Night mode"); value: page.flag("night_mode") }
|
||||||
|
InfoRow { visible: api.configured; label: qsTr("Riscaldamento forzato"); value: page.flag("force_heating") }
|
||||||
|
InfoRow { visible: api.configured; label: qsTr("Resistenze integrative"); value: page.flag("inline_heater") }
|
||||||
|
InfoRow { visible: api.configured; label: qsTr("Zone"); value: page.count("zones") }
|
||||||
|
InfoRow { visible: api.configured; label: qsTr("Errori"); value: page.count("errors_count") }
|
||||||
|
InfoRow { visible: api.configured; label: qsTr("Aggiornato alle"); value: page.shortTime(page.raw("pump_updated")) }
|
||||||
|
|
||||||
BusyIndicator {
|
BusyIndicator {
|
||||||
visible: api.busy
|
visible: api.busy
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Name: harbour-aira
|
Name: harbour-aira
|
||||||
Summary: Control your Aira heat pump through a local bridge
|
Summary: Control your Aira heat pump through a local bridge
|
||||||
Version: 0.2.0
|
Version: 0.2.1
|
||||||
Release: 1
|
Release: 1
|
||||||
Group: Qt/Qt
|
Group: Qt/Qt
|
||||||
License: MIT
|
License: MIT
|
||||||
|
|||||||
+26
-32
@@ -118,44 +118,41 @@ def main_screen() -> Image.Image:
|
|||||||
page_header(d, "Aira")
|
page_header(d, "Aira")
|
||||||
|
|
||||||
y = 156
|
y = 156
|
||||||
c = "Acqua calda"
|
# ---- casa: il dato principale, in cima ------------------------------- #
|
||||||
d.text(((W - d.textlength(c, font=font(26))) / 2, y), c, font=font(26), fill=SECONDARY)
|
c = "Temperatura in casa"
|
||||||
|
d.text(((W - d.textlength(c, font=font(24))) / 2, y), c, font=font(24), fill=SECONDARY)
|
||||||
y += 40
|
y += 40
|
||||||
big = "51,0 °C"
|
big = "23,0 °C"
|
||||||
d.text(((W - d.textlength(big, font=font(92, bold=True))) / 2, y),
|
d.text(((W - d.textlength(big, font=font(92, bold=True))) / 2, y),
|
||||||
big, font=font(92, bold=True), fill=PRIMARY)
|
big, font=font(92, bold=True), fill=PRIMARY)
|
||||||
y += 116
|
y += 116
|
||||||
progress(d, y, (51.0 - 20) / (65 - 20))
|
progress(d, y, (23.0 - 5) / (30 - 5))
|
||||||
y += 22
|
y += 22
|
||||||
t = "obiettivo 55,0 °C"
|
t = "obiettivo 19,0 °C · Riscaldamento"
|
||||||
d.text(((W - d.textlength(t, font=font(24))) / 2, y), t, font=font(24), fill=SECONDARY)
|
d.text(((W - d.textlength(t, font=font(24))) / 2, y), t, font=font(24), fill=SECONDARY)
|
||||||
|
y += 46
|
||||||
# ---- riscaldamento: temperatura della casa -------------------------- #
|
y = slider(d, y, (19.0 - 5) / (30 - 5), "19,0 °C", "Nuovo obiettivo casa")
|
||||||
y = section_header(d, y + 44, "Riscaldamento")
|
|
||||||
c = "Temperatura in casa"
|
|
||||||
d.text(((W - d.textlength(c, font=font(24))) / 2, y), c, font=font(24), fill=SECONDARY)
|
|
||||||
y += 34
|
|
||||||
big2 = "23,0 °C"
|
|
||||||
d.text(((W - d.textlength(big2, font=font(64, bold=True))) / 2, y),
|
|
||||||
big2, font=font(64, bold=True), fill=PRIMARY)
|
|
||||||
y += 88
|
|
||||||
y = label_pair(d, y, "Obiettivo casa", "19,0 °C")
|
|
||||||
y = label_pair(d, y, "Stato riscaldamento", "Riscaldamento")
|
|
||||||
y = slider(d, y + 14, (19.0 - 5) / (30 - 5), "19,0 °C", "Nuovo obiettivo")
|
|
||||||
y = button(d, y, "Imposta casa a 19,0 °C", primary=True)
|
y = button(d, y, "Imposta casa a 19,0 °C", primary=True)
|
||||||
|
|
||||||
y = section_header(d, y + 24, "Impianto")
|
# ---- acqua calda sanitaria ------------------------------------------- #
|
||||||
y = label_pair(d, y, "Esterna", "18,0 °C")
|
y = section_header(d, y + 24, "Acqua calda sanitaria")
|
||||||
y = label_pair(d, y, "Interna (pompa)", "22,5 °C")
|
acs = "51,0 °C"
|
||||||
y = label_pair(d, y, "Modalità", "Automatico")
|
d.text(((W - d.textlength(acs, font=font(56, bold=True))) / 2, y),
|
||||||
y = label_pair(d, y, "Errori", "0")
|
acs, font=font(56, bold=True), fill=PRIMARY)
|
||||||
|
y += 76
|
||||||
y = section_header(d, y + 24, "Comandi acqua calda")
|
progress(d, y, (51.0 - 20) / (65 - 20))
|
||||||
y = slider(d, y, (55.0 - 45) / (60 - 45), "55 °C")
|
y += 22
|
||||||
|
y = label_pair(d, y, "Obiettivo acqua calda", "55,0 °C")
|
||||||
|
y = slider(d, y + 10, (55.0 - 45) / (60 - 45), "55 °C")
|
||||||
y = button(d, y, "Imposta obiettivo ACS", primary=True)
|
y = button(d, y, "Imposta obiettivo ACS", primary=True)
|
||||||
y = button(d, y, "Avvia boost ACS")
|
y = button(d, y, "Avvia boost ACS")
|
||||||
y = button(d, y, "Ferma boost ACS")
|
y = button(d, y, "Ferma boost ACS")
|
||||||
|
|
||||||
|
# ---- stato impianto (scorre sotto) ----------------------------------- #
|
||||||
|
y = section_header(d, y + 24, "Impianto")
|
||||||
|
y = label_pair(d, y, "Esterna", "18,0 °C")
|
||||||
|
y = label_pair(d, y, "Interna (pompa)", "22,5 °C")
|
||||||
|
|
||||||
d.text(((W - d.textlength("Trascina verso il basso per aggiornare",
|
d.text(((W - d.textlength("Trascina verso il basso per aggiornare",
|
||||||
font=font(22))) / 2, y + 8),
|
font=font(22))) / 2, y + 8),
|
||||||
"Trascina verso il basso per aggiornare", font=font(22), fill=SECONDARY)
|
"Trascina verso il basso per aggiornare", font=font(22), fill=SECONDARY)
|
||||||
@@ -206,19 +203,16 @@ def cover_screen() -> Image.Image:
|
|||||||
d.line([(card[0] + 34, card[1] + 100), (card[2] - 34, card[1] + 100)],
|
d.line([(card[0] + 34, card[1] + 100), (card[2] - 34, card[1] + 100)],
|
||||||
fill=BTN_EDGE, width=2)
|
fill=BTN_EDGE, width=2)
|
||||||
y = card[1] + 132
|
y = card[1] + 132
|
||||||
big = "51,0 °C"
|
big = "23,0 °C"
|
||||||
d.text(((W - d.textlength(big, font=font(76, bold=True))) / 2, y),
|
d.text(((W - d.textlength(big, font=font(76, bold=True))) / 2, y),
|
||||||
big, font=font(76, bold=True), fill=PRIMARY)
|
big, font=font(76, bold=True), fill=PRIMARY)
|
||||||
y += 108
|
y += 108
|
||||||
for lab, val in (("obiettivo", "55,0 °C"), ("esterna", "18,0 °C")):
|
for lab, val in (("obiettivo", "19,0 °C"), ("ACS", "51,0 °C"), ("esterna", "18,0 °C")):
|
||||||
d.text((card[0] + 34, y), lab, font=font(24), fill=SECONDARY)
|
d.text((card[0] + 34, y), lab, font=font(24), fill=SECONDARY)
|
||||||
vw = d.textlength(val, font=font(24))
|
vw = d.textlength(val, font=font(24))
|
||||||
d.text((card[2] - 34 - vw, y), val, font=font(24), fill=PRIMARY)
|
d.text((card[2] - 34 - vw, y), val, font=font(24), fill=PRIMARY)
|
||||||
y += 52
|
y += 52
|
||||||
vw = d.textlength("23,0 °C", font=font(24))
|
d.text((card[0] + 34, card[3] - 60), "temperatura in casa", font=font(22), fill=SECONDARY)
|
||||||
d.text((card[0] + 34, y), "casa", font=font(24), fill=SECONDARY)
|
|
||||||
d.text((card[2] - 34 - vw, y), "23,0 °C", font=font(24), fill=PRIMARY)
|
|
||||||
d.text((card[0] + 34, card[3] - 60), "acqua calda sanitaria", font=font(22), fill=SECONDARY)
|
|
||||||
return img
|
return img
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user