#include <QTimer> #include <QFile> #include <sstream> #include <cassert> #include "heatControl.h" HeatControl * HeatControl::C[SHNodeIdSize * SHSensorIdSize] = {nullptr}; QFile HeatControl::m_file(CSVfileName); // QDir::setCurrent("/tmp"); /* * */ HeatControl::HeatControl(SHsensor *temp, SHactuator *swtch, float maxTempDay, float maxTempNight, QTime startTimeDay, QTime startTimeNight, QObject *parent) : QObject(parent), m_temp(temp), m_switch(swtch), m_maxTempDay(maxTempDay), m_maxTempNight(maxTempNight), m_startTimeDay(startTimeDay), m_startTimeNight(startTimeNight) { m_mode = Mode::Auto; // default is Auto // Hinzufügen: m_pos = m_switch->pos(); // qDebug() << m_name << pos; if (C[m_pos] != nullptr) throw std::invalid_argument("HeatControl::HeatControl: double usage"); C[m_pos] = this; m_suspended = Suspension::NONE; } /* * */ HeatControl::~HeatControl() { C[m_pos] = nullptr; } /* * */ HeatControl::Mode HeatControl::mode() const { return m_mode; } /* * */ QString HeatControl::value() const { return modeName(m_mode); } /* * */ SHactuator::State HeatControl::state() const { return m_switch->switchState(); } /* * */ int HeatControl::demand() const { return m_switch->powerDemand(); } /* * */ float HeatControl::temperature() const { if (m_temp == nullptr) return -9.0; // kleiner Fantasie-Wert ohne jede Bedeutung, d.h. Gerät soll einfach an bleiben return m_temp->value().toFloat(); } /* * */ float HeatControl::minTemp() const { QDateTime now = SHsensor::currentTime(); if (m_startTimeDay <= now.time() and now.time() < m_startTimeNight) // Tag return m_maxTempDay - autoTempMargin; else return m_maxTempNight; } /* * */ QString HeatControl::name() const { return m_switch->name(); } /* * */ void HeatControl::grant(bool ON) { m_granted = ON; if (ON) m_switch->ON(); else m_switch->OFF(); } /* * */ void HeatControl::suspend(bool maxTemp) { Suspension suspendedOld = m_suspended; if (maxTemp) m_suspended = Suspension::MaxTemp; else m_suspended = Suspension::MinTemp; // Zeit wird nur neu gesetzt, wenn sich der Zustand ändert: if (suspendedOld != m_suspended) { QDateTime now = SHsensor::currentTime(); QDateTime newExpireTime = now.addSecs(60*suspensionTime()); m_expireTime = newExpireTime; } } /* * */ void HeatControl::checkSusExpiration() { QDateTime now = SHsensor::currentTime(); // qDebug() << "HeatControl::checkSusExpiration before =>" << (int) m_suspended; // qDebug() << "check" << name() << m_expireTime << now; // if (m_expireTime.hour() == 0 and now.hour() == 23) // return; // wait until after midnight if (m_expireTime <= now) m_suspended = Suspension::NONE; // qDebug() << "HeatControl::checkSusExpiration after =>" << (int) m_suspended; } /* * check reset im Zustand MinTemp (weil die Rahmenbedingungen sich geändert haben) */ void HeatControl::checkResetSus(bool supplyPossible) { if (m_suspended == Suspension::MinTemp) { // mehr Solar verfügbar: bool couldBeMoore = (supplyPossible and not maxReached()); QTime expireSetTime = SHsensor::currentTime().time().addSecs(-60*suspensionTime()); // Zeitpunkt der Suspendierung // Tagesanbruch mit neuer minimal Temperatur: bool newDayTemp = (expireSetTime < m_startTimeDay and m_startTimeDay < m_expireTime.time() and not minReached()); if (couldBeMoore or newDayTemp) m_suspended = Suspension::NONE; } } /* * */ bool HeatControl::maxReached() const { return (temperature() >= m_maxTempDay); } /* * */ bool HeatControl::minReached() const { return (not m_temp->isError() and temperature() >= minTemp()); } /* * */ int HeatControl::suspensionTime() const { return 15; // min } /* * */ bool HeatControl::grantPossible(bool supplyPossible) const { bool smartMode = (mode() == HeatControl::Mode::Smart); return (not suspended() and ((smartMode and not minReached()) or (supplyPossible and not maxReached()))); } /* * */ void HeatControl::checkMaxTempSus(bool supplyPossible) { if (maxReached() and supplyPossible) suspend(true); // auf MaxTemp Suspension setzen } /* * */ void HeatControl::checkMinTempSus(bool supplyPossible) { bool smartMode = (mode() == HeatControl::Mode::Smart); if (not suspended() and smartMode and minReached() and not supplyPossible) suspend(false); // auf MinTemp Suspension setzen } /* * */ QString HeatControl::output() const { QString s_output; s_output += " " + name() + "(" + QString::number(demand()) + ","; s_output += QString::number(temperature()) + "/"; if (mode() == HeatControl::Mode::Smart) s_output += QString::number(minTemp()); else if (mode() == HeatControl::Mode::Auto) s_output += QString::number(m_maxTempDay); else s_output += "-"; s_output += "):"; return s_output; } /* * */ bool HeatControl::granted() const { return m_granted; } /* * */ bool HeatControl::suspended() const { return (m_suspended != Suspension::NONE); } /* * */ QDateTime HeatControl::expireTime() const { return m_expireTime; } /* * */ QString HeatControl::susName() const { switch (m_suspended) { case Suspension::NONE: return "OFF"; // no suspension -> else-part in SolarControl::process() case Suspension::MaxTemp: return "MXT"; case Suspension::MinTemp: return "MIT"; } return "ERR"; } /* * */ void HeatControl::remoteOn(int pos /* , bool setOn */) { // if (C[pos]->m_switch->nodeID() == NodeIdSolarheat ) // qDebug() << "remoteMsg" << C[pos]->m_switch->nodeID() << C[pos]->m_switch->sensorID() ; C[pos]->m_previousMode = C[pos]->m_mode; C[pos]->m_previousState = C[pos]->m_switch->switchState(); C[pos]->m_mode = Mode::RemoteOn; C[pos]->m_switch->ON(); // d.h. nicht auf process() warten } /* * */ void HeatControl::resumeMode(int pos) { C[pos]->m_mode = C[pos]->m_previousMode; C[pos]->m_switch->set(C[pos]->m_previousState); // d.h. nicht auf process() warten } /* * */ void HeatControl::processTimed() { QDateTime now = SHsensor::currentTime(); // qDebug() << "HeatControl::processTimed" << temperature() << m_maxTempNight << m_maxTempDay; if (m_startTimeDay <= now.time() and now.time() < m_startTimeNight) { // Tag if (m_suspended == Suspension::NONE and temperature() < m_maxTempDay) m_switch->ON(); else { m_switch->OFF(); if (temperature() >= m_maxTempDay) suspend(true); } } else { // Nacht if (m_suspended == Suspension::NONE and temperature() < m_maxTempNight) m_switch->ON(); else { m_switch->OFF(); if (temperature() >= m_maxTempNight) suspend(true); } } if (suspended()) checkSusExpiration(); // Debug: /* if (m_switch->switchState() == SHactuator::State::ON) qDebug() << "ON"; else if (m_switch->switchState() == SHactuator::State::UNKOWN) qDebug() << "err"; else if (suspended()) qDebug() << "SUS"; else qDebug() << "OFF"; */ } /* * */ void HeatControl::process() { // qDebug() << "HeatControl::process" << m_switch->name(); switch (m_mode) { case Mode::Off: m_switch->OFF(); break; case Mode::Timed: processTimed(); break; case Mode::On: m_switch->ON(); break; case Mode::Auto: // nichts zu tun -> wird von SolarControl gehandhabt case Mode::Smart: case Mode::RemoteOn: // nur der Vollständigkeit halber case Mode::size: break; } } /* * static */ void HeatControl::processALL() { for (auto c : C) if (c != nullptr) c->process(); } static QString getToken(std::istringstream & ss, char delim = sep) { std::string token; std::getline(ss, token, delim); // qDebug() << "token <" << token.c_str() << ">"; return token.c_str(); } /* * */ void HeatControl::readCSV() { QDir dir; if (m_file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "open" << dir.absolutePath() << CSVfileName; while (not m_file.atEnd()) { QString line = m_file.readLine(); qDebug() << line; std::string input = line.toStdString(); std::istringstream ss(input); QString name = getToken(ss); int nid = getToken(ss).toInt(); int sid = getToken(ss).toInt(); int pos = SHsensor::hash(nid, sid); // int pos = getToken(ss).toInt(); -- Alte Version // if (pos < 0 or pos > SHNodeIdSize * SHSensorIdSize) { // qDebug() << "pos out of range" << pos; // continue; // } if (C[pos] == nullptr) { qDebug() << "C[pos] == nullptr" << pos; continue; } if (C[pos]->m_switch->name() != name) { qDebug() << "C[pos]->m_switch->name() != name" << pos; continue; } C[pos]->m_mode = HeatControl::toMode(getToken(ss)); C[pos]->m_maxTempDay = getToken(ss).toFloat(); C[pos]->m_maxTempNight = getToken(ss).toFloat(); C[pos]->m_startTimeDay = QTime::fromString(getToken(ss)); C[pos]->m_startTimeNight = QTime::fromString(getToken(ss, '\n')); qDebug() << name << nid << sid << modeName(C[pos]->m_mode) << C[pos]->m_maxTempDay << C[pos]->m_maxTempNight << C[pos]->m_startTimeDay << C[pos]->m_startTimeNight; } m_file.close(); } else { // erstmalig qDebug() << "writing defaults" << dir.absolutePath() << CSVfileName; writeCSV(); } } /* * */ void HeatControl::writeCSV() { if (not m_file.open(QIODevice::WriteOnly | QIODevice::Text)) return; QTextStream out(&m_file); for (auto c : C) if (c != nullptr) { out << c->m_switch->name() << sep; out << c->m_switch->nodeID() << sep; out << c->m_switch->sensorID() << sep; // out << c->m_pos << sep; - alte Version out << modeName(c->mode()) << sep; out << c->m_maxTempDay << sep; out << c->m_maxTempNight << sep; out << c->m_startTimeDay.toString("hh:mm") << sep; out << c->m_startTimeNight.toString("hh:mm") << "\n"; } m_file.close(); } /* * */ void HeatControl::setMode(int pos, const Mode &mode) { assert(pos >= 0 and pos < SHNodeIdSize * SHSensorIdSize); C[pos]->m_mode = mode; C[pos]->m_switch->setIgnoreF3error(); writeCSV(); } /* * */ HeatControl::Mode HeatControl::getMode(int nid, int sid) { int pos = SHsensor::hash(nid, sid); if (pos == -1 or C[pos] == nullptr) return Mode::size; else return C[pos]->m_mode; } /* * */ float HeatControl::getMaxTempDay(int nid, int sid) { int pos = SHsensor::hash(nid, sid); if (pos == -1 or C[pos] == nullptr) return -42; else return C[pos]->m_maxTempDay; } /* * */ float HeatControl::getMaxTempNight(int nid, int sid) { int pos = SHsensor::hash(nid, sid); if (pos == -1 or C[pos] == nullptr) return -42; else return C[pos]->m_maxTempNight; } /* * */ QTime HeatControl::getStartTimeDay(int nid, int sid) { int pos = SHsensor::hash(nid, sid); if (pos == -1 or C[pos] == nullptr) return QTime(11,11); else return C[pos]->m_startTimeDay; } /* * */ QTime HeatControl::getStartTimeNight(int nid, int sid) { int pos = SHsensor::hash(nid, sid); if (pos == -1 or C[pos] == nullptr) return QTime(11,11); else return C[pos]->m_startTimeNight; } /* * */ QString HeatControl::getName(int nid, int sid) { int pos = SHsensor::hash(nid, sid); if (pos == -1 or C[pos] == nullptr) return "ERRname"; else return C[pos]->name(); } /* * */ void HeatControl::setStartTimeNight(int pos, const QTime &startTimeNight) { assert(pos >= 0 and pos < SHNodeIdSize * SHSensorIdSize); C[pos]->m_startTimeNight = startTimeNight; writeCSV(); } /* * */ void HeatControl::setStartTimeDay(int pos, const QTime &startTimeDay) { assert(pos >= 0 and pos < SHNodeIdSize * SHSensorIdSize); C[pos]->m_startTimeDay = startTimeDay; writeCSV(); } /* * */ void HeatControl::setMaxTempNight(int pos, float maxTempNight) { assert(pos >= 0 and pos < SHNodeIdSize * SHSensorIdSize); C[pos]->m_maxTempNight = maxTempNight; writeCSV(); } /* * */ void HeatControl::setMaxTempDay(int pos, float maxTempDay) { assert(pos >= 0 and pos < SHNodeIdSize * SHSensorIdSize); C[pos]->m_maxTempDay = maxTempDay; writeCSV(); } static QVector<QString> N = {"Off", "Auto", "Smart", "Timed", "On", "Manuell", "ERRnoMode"}; /* * */ QString HeatControl::modeName(HeatControl::Mode m) { return N[(int) m]; } /* * */ HeatControl::Mode HeatControl::toMode(const QString &m) { for (int i=0; i<N.size(); i++) if (N[i] == m) return (Mode) i; return HeatControl::Mode::Off; // default }