Sat, 01 Jun 2024 21:10:54 +0200
Added fields for target_water and auto upgrade the products table
/** * ChartFermenter.cpp is part of bmsapp. * * bmsapp is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * bmsapp is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "ChartFermenter.h" #include "callout.h" #include "MainWindow.h" ChartFermenter::ChartFermenter(QString code, QString name, QWidget *parent) : QDialog(parent) { QSqlQuery query; double timestamp; bool use_air = false, use_beer=false, use_chiller = false, use_room = false; bool use_sp_low = false, use_sp_high = false, use_heater = false, use_cooler = false; QAreaSeries *pwr_cool, *pwr_heat; QLineSeries *pv_air, *pv_beer, *pv_chiller; QLineSeries *pwr_cool1, *pwr_cool0, *pwr_heat1, *pwr_heat0; int min = 100, max = 0; qDebug() << "ChartFermenter:" << code << name; /* * First see which values are really used in the logfile. */ query.prepare("SELECT * FROM log_fermenter WHERE code=:code ORDER BY datetime"); query.bindValue(":code", code); query.exec(); while (query.next()) { if (query.value("temp_air").toDouble() > 0) use_air = true; if (query.value("temp_beer").toDouble() > 0) use_beer = true; if (query.value("temp_chiller").toDouble() > 0) use_chiller = true; if (query.value("temp_room").toDouble() > 0) use_room = true; if (query.value("sp_low").toDouble() > 0) use_sp_low = true; if (query.value("sp_high").toDouble() > 0) use_sp_high = true; if (query.value("heater_power").toDouble() > 0) use_heater = true; if (query.value("cooler_power").toDouble() > 0) use_cooler = true; if (use_air && use_beer && use_chiller && use_room && use_sp_low && use_sp_high && use_heater && use_cooler) break; } // qDebug() << "use" << use_air << use_beer << use_chiller << use_room << use_sp_low << use_sp_high << use_heater << use_cooler; QDialog* dialog = new QDialog(parent); dialog->setWindowTitle(tr("BMSapp - Fermenter log ") + "\"" + name + "\""); dialog->setObjectName(QString::fromUtf8("ChartFermenter")); dialog->setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint); dialog->resize(1024, 600); QPushButton *saveButton = new QPushButton(tr("Save")); saveButton->setAutoDefault(false); QIcon icon1; icon1.addFile(QString::fromUtf8(":icons/silk/disk.png"), QSize(), QIcon::Normal, QIcon::Off); saveButton->setIcon(icon1); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setObjectName(QString::fromUtf8("buttonBox")); buttonBox->setOrientation(Qt::Vertical); buttonBox->setStandardButtons(QDialogButtonBox::Ok); buttonBox->addButton(saveButton,QDialogButtonBox::ActionRole); if (use_air) pv_air = new QLineSeries(); if (use_beer) pv_beer = new QLineSeries(); if (use_chiller) pv_chiller = new QLineSeries(); if (use_cooler) { pwr_cool1 = new QLineSeries(); pwr_cool0 = new QLineSeries(); } if (use_heater) { pwr_heat1 = new QLineSeries(); // Top side of area pwr_heat0 = new QLineSeries(); // Bottom side of area } query.prepare("SELECT * FROM log_fermenter WHERE code=:code ORDER BY datetime"); query.bindValue(":code", code); query.exec(); while (query.next()) { timestamp = query.value("datetime").toDateTime().toSecsSinceEpoch() * 1000; if (use_air) { pv_air->append(timestamp, query.value("temp_air").toDouble()); if (ceil(query.value("temp_air").toDouble()) > max) max = ceil(query.value("temp_air").toDouble()); if (floor(query.value("temp_air").toDouble()) < min) min = floor(query.value("temp_air").toDouble()); } if (use_beer) { pv_beer->append(timestamp, query.value("temp_beer").toDouble()); if (ceil(query.value("temp_beer").toDouble()) > max) max = ceil(query.value("temp_beer").toDouble()); if (floor(query.value("temp_beer").toDouble()) < min) min = floor(query.value("temp_beer").toDouble()); } if (use_chiller && query.value("temp_chiller").toDouble() > 0) { pv_chiller->append(timestamp, query.value("temp_chiller").toDouble()); // if (ceil(query.value("temp_chiller").toDouble()) > max) // max = ceil(query.value("temp_chiller").toDouble()); // if (floor(query.value("temp_chiller").toDouble()) < min) // min = floor(query.value("temp_chiller").toDouble()); } if (use_cooler) { pwr_cool0->append(timestamp, 0); pwr_cool1->append(timestamp, query.value("cooler_power").toInt()); } if (use_heater) { pwr_heat0->append(timestamp, 0); pwr_heat1->append(timestamp, query.value("heater_power").toInt()); } } // qDebug() << "min" << min << "max" << max << "ticks" << max-min+1; /* * If the range is small, increase it. */ if ((max - min) < 5) { min = max - 5; } else if ((max - min) < 10) { min = max - 10; } if (use_air) { pv_air->setName(tr("Air")); if (use_beer) { pv_air->setColor(QColorConstants::Svg::lightgreen); } else { /* * If there is no beer line, then make this one fat. */ QPen pen(QColorConstants::Svg::lightgreen); pen.setWidth(2); pv_air->setPen(pen); } } if (use_beer) { pv_beer->setName(tr("Beer")); QPen pen(QColorConstants::Svg::navy); pen.setWidth(2); pv_beer->setPen(pen); } if (use_chiller) { pv_chiller->setName(tr("Chiller")); pv_chiller->setColor(QColorConstants::Svg::lightsalmon); pv_chiller->setOpacity(0.75); } if (use_cooler) { pwr_cool = new QAreaSeries(pwr_cool0, pwr_cool1); pwr_cool->setName("Cool %"); pwr_cool->setOpacity(0.50); pwr_cool->setColor(QColorConstants::Blue); } if (use_heater) { pwr_heat = new QAreaSeries(pwr_heat0, pwr_heat1); pwr_heat->setName("Heat %"); pwr_heat->setOpacity(0.50); pwr_heat->setColor(QColorConstants::Red); } chart = new QChart(); chart->setTitle(QString("%1 \"%2\"").arg(code).arg(name)); if (use_cooler) chart->addSeries(pwr_cool); // Order is important, first drawn is lowest layer. if (use_heater) chart->addSeries(pwr_heat); if (use_chiller) chart->addSeries(pv_chiller); if (use_air) chart->addSeries(pv_air); if (use_beer) chart->addSeries(pv_beer); // Top layer QDateTimeAxis *axisX = new QDateTimeAxis; axisX->setTickCount(10); axisX->setFormat("dd MMM"); axisX->setTitleText(tr("Date")); axisX->setLabelsFont(QFont("Helvetica", 8, QFont::Normal)); chart->addAxis(axisX, Qt::AlignBottom); if (use_air) pv_air->attachAxis(axisX); if (use_beer) pv_beer->attachAxis(axisX); if (use_chiller) pv_chiller->attachAxis(axisX); QValueAxis *axisY = new QValueAxis; axisY->setRange(min, max); axisY->setTickCount(max-min+1); axisY->setMinorTickCount(1); axisY->setLabelFormat("%.1f"); axisY->setTitleText(tr("Temp °C")); axisY->setLabelsFont(QFont("Helvetica", 8, QFont::Normal)); chart->addAxis(axisY, Qt::AlignLeft); if (use_air) pv_air->attachAxis(axisY); if (use_beer) pv_beer->attachAxis(axisY); if (use_chiller) pv_chiller->attachAxis(axisY); if (use_heater || use_cooler) { QValueAxis *axisYR = new QValueAxis; axisYR->setRange(0, 100); axisYR->setTickCount(11); axisYR->setLabelFormat("%i"); axisYR->setTitleText(tr("Power %")); axisYR->setLabelsFont(QFont("Helvetica", 8, QFont::Normal)); chart->addAxis(axisYR, Qt::AlignRight); if (use_cooler) pwr_cool->attachAxis(axisYR); if (use_heater) pwr_heat->attachAxis(axisYR); } if (use_air) connect(pv_air, &QLineSeries::hovered, this, &ChartFermenter::tooltip); if (use_beer) connect(pv_beer, &QLineSeries::hovered, this, &ChartFermenter::tooltip); if (use_chiller) connect(pv_chiller, &QLineSeries::hovered, this, &ChartFermenter::tooltip); chartView = new QChartView(chart); chartView->setRenderHint(QPainter::Antialiasing); dialog->setLayout(new QHBoxLayout); dialog->layout()->addWidget(chartView); dialog->layout()->addWidget(buttonBox); QObject::connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept())); QObject::connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject())); QObject::connect(saveButton, SIGNAL(clicked()), this, SLOT(savePNG())); dialog->setModal(true); dialog->exec(); } ChartFermenter::~ChartFermenter() {} void ChartFermenter::savePNG() { QSettings settings(QSettings::IniFormat, QSettings::UserScope, "mbse", "bmsapp"); QString dirName; /* * First check if the directory stored in the settings file exists. * It might be on a removable media that was last used ... * If so, fallback to the user's home directory. */ dirName = settings.value("paths/download").toString(); if (! QDir(dirName).exists()) { dirName = QDir::homePath(); } QString path = QFileDialog::getSaveFileName(this, tr("Save Image"), dirName + "/fermenter.png", tr("Image (*.png)")); if (path.isEmpty()) { QMessageBox::warning(this, tr("Save File"), tr("No image file selected.")); return; } /* * Update to current selected path */ settings.setValue("paths/download", QFileInfo(path).absolutePath()); QImage img((chartView->size()), QImage::Format_ARGB32); QPainter painter; painter.begin(&img); chartView->render(&painter); painter.setRenderHint(QPainter::Antialiasing); painter.end(); img.save(path); } void ChartFermenter::tooltip(QPointF point, bool state) { QAbstractSeries *series = qobject_cast<QAbstractSeries *>(sender()); if (t_tooltip == 0) t_tooltip = new Callout(chart, series); if (state) { QDateTime timeis = QDateTime::fromMSecsSinceEpoch(point.x()); //qDebug() << "tooltip" << QString("%1 %2°C").arg( timeis.toString("dd-MM-yyyy hh:mm") ).arg(point.y(), 2, 'f', 1); t_tooltip->setSeries(series); t_tooltip->setText(QString("%1\n%2 %3°C").arg(timeis.toString("dd-MM-yyyy hh:mm")).arg(series->name()).arg(point.y(), 2, 'f', 1)); t_tooltip->setAnchor(point); t_tooltip->setZValue(11); t_tooltip->updateGeometry(); t_tooltip->show(); } else { t_tooltip->hide(); } }