diff --git a/soft/thermostat/inc/boost_dlg.h b/soft/thermostat/inc/boost_dlg.h new file mode 100644 index 0000000..71172d5 --- /dev/null +++ b/soft/thermostat/inc/boost_dlg.h @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + * Qt mutizone MQTT thermostat + * + * Copyright (C) 2020 Richard Genoud + * + */ + +#ifndef BOOSTDLG_H +#define BOOSTDLG_H + +#include +#include +#include +#include +#include + +struct boost_data +{ + double temperature; + QDateTime end_date; +}; + +class BoostDlg : public QDialog +{ + Q_OBJECT + +public: + BoostDlg(int idx, const QString &zoneName, double temperature = 21, + QWidget *parent = Q_NULLPTR, + Qt::WindowFlags f = Qt::WindowFlags()); + ~BoostDlg(); + int m_idx; // room index + +private: + QDoubleSpinBox m_boost_temperature; + QSpinBox m_boost_duration; + +private slots: + void send_result(void); + +signals: + void boost_changed(int idx, struct boost_data &data); +}; + +#endif // BOOSTDLG_H + +/* vim: set tabstop=8 shiftwidth=8 softtabstop=0 noexpandtab: */ diff --git a/soft/thermostat/inc/mainwindow.h b/soft/thermostat/inc/mainwindow.h index 7a83303..aa53134 100644 --- a/soft/thermostat/inc/mainwindow.h +++ b/soft/thermostat/inc/mainwindow.h @@ -16,6 +16,7 @@ #include "mqttclient.h" #include "zoneitem.h" +#include "boost_dlg.h" #include "settings.h" class MainWindow : public QMainWindow @@ -42,6 +43,8 @@ private slots: void availability_slot(int idx, bool ok); void change_state(void); void apply_order_to_heaters(void); + void show_boost(void); + void boost_slot(int idx, struct boost_data &data); signals: void setAllHeatersOn(bool on); diff --git a/soft/thermostat/inc/zoneitem.h b/soft/thermostat/inc/zoneitem.h index 55232c7..be76d3e 100644 --- a/soft/thermostat/inc/zoneitem.h +++ b/soft/thermostat/inc/zoneitem.h @@ -14,6 +14,8 @@ #include #include +#include "boost_dlg.h" + class ZoneItem : public QWidget { Q_OBJECT @@ -28,8 +30,9 @@ public: double m_target_temperature; bool m_available; bool m_heating_on; + QString m_name; + struct boost_data m_boost; -private: QPushButton m_zoneNameBtn; QPushButton m_temperatureBtn; QPushButton m_hygroBtn; diff --git a/soft/thermostat/src/boost_dlg.cpp b/soft/thermostat/src/boost_dlg.cpp new file mode 100644 index 0000000..72c9002 --- /dev/null +++ b/soft/thermostat/src/boost_dlg.cpp @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + * Qt mutizone MQTT thermostat + * + * Copyright (C) 2020 Richard Genoud + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "settings.h" +#include "boost_dlg.h" + +#define SPIN_ARROW_W 75 +#define SPIN_ARROW_H 50 +#define SPIN_FONT_SZ 20 + +BoostDlg::BoostDlg(int idx, const QString &zoneName, double temperature, QWidget *parent, Qt::WindowFlags f) : + QDialog(parent, f) +{ + QString sheet; + QLabel *room_name = new QLabel(QString(tr("Force %1 temperature:").arg(zoneName))); + room_name->setStyleSheet(QString("font-size: %1px;").arg(SPIN_FONT_SZ)); + + temperature = qFloor(temperature * 2) / 2.0; + m_idx = idx; + m_boost_temperature.setDecimals(1); + m_boost_temperature.setValue(temperature); + m_boost_temperature.setSingleStep(0.5); + m_boost_temperature.setSuffix(" °C"); + + /* + * TODO: setting size in pixels sucks + * We should set size in mm or ratio of the window size + */ + sheet = QString("QDoubleSpinBox { height: %1px; font-size: %4px }" + "QDoubleSpinBox::up-button { width: %2px; height: %3px }" + "QDoubleSpinBox::down-button { width: %2px; height: %3px }") + .arg(2*SPIN_ARROW_H) + .arg(SPIN_ARROW_W) + .arg(SPIN_ARROW_H) + .arg(SPIN_FONT_SZ); + m_boost_temperature.setStyleSheet(sheet); + + m_boost_duration.setRange(0, 99); + m_boost_duration.setValue(1); + m_boost_duration.setSuffix(" H"); + sheet = sheet.replace("QDoubleSpinBox", "QSpinBox"); + m_boost_duration.setStyleSheet(sheet); + + QHBoxLayout *spinLayout = new QHBoxLayout; + spinLayout->addWidget(&m_boost_temperature); + spinLayout->addWidget(&m_boost_duration); + + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + + connect(buttonBox, SIGNAL(accepted(void)), this, SLOT(accept(void))); + connect(buttonBox, SIGNAL(rejected(void)), this, SLOT(reject(void))); + connect(this, SIGNAL(accepted(void)), this, SLOT(send_result(void))); + + QVBoxLayout *topLayout = new QVBoxLayout; + + topLayout->addWidget(room_name); + topLayout->addLayout(spinLayout); + topLayout->addWidget(buttonBox); + + this->setLayout(topLayout); +} + +void BoostDlg::send_result(void) +{ + struct boost_data data; + QDateTime now = QDateTime::currentDateTime(); + + data.temperature = m_boost_temperature.value(); + data.end_date = now.addSecs(m_boost_duration.value() * 3600); + + emit boost_changed(m_idx, data); +} + +BoostDlg::~BoostDlg() +{ +} + +/* vim: set tabstop=8 shiftwidth=8 softtabstop=0 noexpandtab: */ + diff --git a/soft/thermostat/src/mainwindow.cpp b/soft/thermostat/src/mainwindow.cpp index e1f2e5f..c24adc2 100644 --- a/soft/thermostat/src/mainwindow.cpp +++ b/soft/thermostat/src/mainwindow.cpp @@ -8,12 +8,14 @@ #include #include +#include #include #include #include #include #include +#include "boost_dlg.h" #include "mqttclient.h" #include "zoneitem.h" #include "settings.h" @@ -28,7 +30,9 @@ MainWindow::MainWindow(QWidget *parent) : for (int i = 0; i < s->nbZones(); i++) { zone = new ZoneItem(s->m_rooms.at(i).name, this); + zone->m_zoneNameBtn.setProperty("idx", i); zone->m_target_temperature = get_target_temperature(i); + connect(&(zone->m_zoneNameBtn), SIGNAL(clicked()), this, SLOT(show_boost())); m_zones << zone; } @@ -93,6 +97,36 @@ MainWindow::~MainWindow() { } +void MainWindow::boost_slot(int idx, struct boost_data &data) +{ + qDebug() << "room " << m_zones.at(idx)->m_name << " new BOOST " << data.temperature << " end: " << data.end_date; + + m_zones.at(idx)->m_boost = data; + + apply_order_to_heaters(); +} + +void MainWindow::show_boost(void) +{ + QObject* obj = sender(); + QVariant v; + + v = obj->property("idx"); + if (!v.isValid()) + return; + + int idx = v.toInt(); + + if ((idx < 0) || (idx >= MAX_NB_ZONES)) + return; + + BoostDlg boost(idx, m_zones.at(idx)->m_name, m_zones.at(idx)->m_target_temperature, this); + + connect(&boost, SIGNAL(boost_changed(int, struct boost_data &)), this, SLOT(boost_slot(int, struct boost_data &))); + boost.showFullScreen(); + boost.exec(); +} + void MainWindow::update_state_btn(enum power_states st) { switch (st) { @@ -116,8 +150,9 @@ double MainWindow::get_target_temperature(int room_idx) Settings *s = Settings::getInstance(); const struct Room *r = NULL; const struct Program *p = NULL; + const struct boost_data *b = NULL; double target = FORCE_OFF; - QTime now = QTime::currentTime(); + QDateTime now = QDateTime::currentDateTime(); uint8_t dow = QDate::currentDate().dayOfWeek(); if ((room_idx < 0) || (room_idx >= MAX_NB_ZONES)) { @@ -131,6 +166,18 @@ double MainWindow::get_target_temperature(int room_idx) } /* + * Check if there's a boost programmation + */ + if (room_idx < m_zones.count()) { + b = &(m_zones.at(room_idx)->m_boost); + if (b->end_date.isValid() && (b->end_date > now)) { + /* BOOST is active */ + target = b->temperature; + goto out; + } + } + + /* * dayOfWeek() returns 1 for monday, 7 for sunday. * so dow -= 1 gives 0 for monday, 6 for sunday. * And (1 << dow) gives the day of week as a bit field @@ -147,17 +194,17 @@ double MainWindow::get_target_temperature(int room_idx) * Ex: from 10h to 18h */ if (p->start_time < p->end_time) { - if ((now >= p->start_time) && (now < p->end_time)) { + if ((now.time() >= p->start_time) && (now.time() < p->end_time)) { target = p->temperature; } } else { /* * Ex: from 22h to 6h */ - if (now >= p->start_time) { + if (now.time() >= p->start_time) { target = p->temperature; } else { - if (now < p->end_time) { + if (now.time() < p->end_time) { target = p->temperature; } } diff --git a/soft/thermostat/src/zoneitem.cpp b/soft/thermostat/src/zoneitem.cpp index 3bc9cb5..cbf01da 100644 --- a/soft/thermostat/src/zoneitem.cpp +++ b/soft/thermostat/src/zoneitem.cpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include "settings.h" #include "zoneitem.h" @@ -18,6 +20,7 @@ ZoneItem::ZoneItem(const QString &zoneName, QWidget *parent) : QWidget(parent) { + m_name = zoneName; m_zoneNameBtn.setText(zoneName); m_zoneNameBtn.setFlat(true); m_temperatureBtn.setFlat(true); @@ -28,6 +31,9 @@ ZoneItem::ZoneItem(const QString &zoneName, QWidget *parent) : m_target_temperature = FORCE_OFF; m_available = false; + m_boost.temperature = 0; + m_boost.end_date = QDateTime(); + /* * Layout for the left part of the window */ diff --git a/soft/thermostat/thermostat.pro b/soft/thermostat/thermostat.pro index c4433e9..4ca2f35 100644 --- a/soft/thermostat/thermostat.pro +++ b/soft/thermostat/thermostat.pro @@ -25,12 +25,14 @@ SOURCES += src/main.cpp \ src/zoneitem.cpp \ src/mqttclient.cpp \ src/settings.cpp \ + src/boost_dlg.cpp \ HEADERS += inc/mainwindow.h \ inc/zoneitem.h \ inc/mqttclient.h \ inc/settings.h \ + inc/boost_dlg.h \ RESOURCES += thermostat.qrc