Skip to content
Snippets Groups Projects
heatControl.cpp 13.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • Peter Altenbernd's avatar
    Peter Altenbernd committed
    #include <QTimer>
    #include <QFile>
    #include <sstream>
    #include <cassert>
    
    #include "heatControl.h"
    
    HeatControl * HeatControl::C[SHNodeIdSize * SHSensorIdSize] = {nullptr};
    
    QFile HeatControl::m_file(CSVfileName);
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    //    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();
    
    }
    
    
    
    /*
     *
     */
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    {
        return m_switch->powerDemand();
    }
    
    
    /*
     *
     */
    float HeatControl::temperature() const
    {
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
        if (m_temp == nullptr)
            return -9.0; // kleiner Fantasie-Wert ohne jede Bedeutung, d.h. Gerät soll einfach an bleiben
    
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
        return m_temp->value().toFloat();
    }
    
    
    
    /*
     *
     */
    float HeatControl::minTemp() const
    {
    
        QDateTime now = SHsensor::currentTime();
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    
    
        if (m_startTimeDay <= now.time() and now.time() < m_startTimeNight) // Tag
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
            return m_maxTempDay - autoTempMargin;
        else
            return m_maxTempNight;
    
    }
    
    
    /*
     *
     */
    QString HeatControl::name() const
    {
        return m_switch->name();
    }
    
    
    /*
     *
     */
    void HeatControl::grant(bool ON)
    {
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
        if (ON)
            m_switch->ON();
        else
            m_switch->OFF();
    }
    
    
    
    
    /*
     *
     */
    void HeatControl::suspend(bool maxTemp)
    {
    
        Suspension suspendedOld = m_suspended;
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
        if (maxTemp)
            m_suspended = Suspension::MaxTemp;
        else
    
            m_suspended = Suspension::MinTemp;
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    
    
        // Zeit wird nur neu gesetzt, wenn sich der Zustand ändert:
        if (suspendedOld != m_suspended) {
            QDateTime now = SHsensor::currentTime();
            QDateTime newExpireTime = now.addSecs(60*suspensionTime());
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    
    
            m_expireTime = newExpireTime;
        }
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    }
    
    
    
    
    
    /*
     *
     */
    void HeatControl::checkSusExpiration()
    {
    
        QDateTime now = SHsensor::currentTime();
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    
    
    //    qDebug() << "HeatControl::checkSusExpiration before =>" << (int) m_suspended;
    //    qDebug() << "check" << name() << m_expireTime << now;
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    
    
    //    if (m_expireTime.hour() == 0 and now.hour() == 23)
    //        return; // wait until after midnight
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
            m_suspended = Suspension::NONE;
    
    
    //    qDebug() << "HeatControl::checkSusExpiration after =>" << (int) m_suspended;
    
     * check reset im Zustand MinTemp (weil die Rahmenbedingungen sich geändert haben)
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
     */
    
    void HeatControl::checkResetSus(bool supplyPossible)
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    {
    
        if (m_suspended == Suspension::MinTemp) {
            // mehr Solar verfügbar:
            bool couldBeMoore = (supplyPossible and not maxReached());
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    
    
            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());
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    
    
            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;
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    }
    
    
    
    /*
     *
     */
    bool HeatControl::granted() const
    {
        return m_granted;
    }
    
    
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    
    /*
     *
     */
    bool HeatControl::suspended() const
    {
        return (m_suspended != Suspension::NONE);
    }
    
    
    
    
    
    /*
     *
     */
    QDateTime HeatControl::expireTime() const
    {
        return m_expireTime;
    }
    
    
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    /*
     *
     */
    QString HeatControl::susName() const
    {
        switch (m_suspended) {
        case Suspension::NONE:
    
            return "OFF"; // no suspension -> else-part in SolarControl::process()
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
        case Suspension::MaxTemp:
            return "MXT";
        case Suspension::MinTemp:
            return "MIT";
        }
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    }
    
    
    
    /*
     *
     */
    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() ;
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    
    
        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();
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    
        // qDebug() << "HeatControl::processTimed" << temperature() << m_maxTempNight << m_maxTempDay;
    
    
        if (m_startTimeDay <= now.time() and now.time() < m_startTimeNight) { // Tag
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
            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()
    {
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
        if (m_file.open(QIODevice::ReadOnly | QIODevice::Text)) {
    
            qDebug() << "open" << dir.absolutePath() << CSVfileName;
    
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
            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;
    //            }
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    
                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)
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
                         << 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;
    
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
            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
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
                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();
    
    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)
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    {
        int pos = SHsensor::hash(nid, sid);
    
        if (pos == -1 or C[pos] == nullptr)
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
        else
    
            return C[pos]->m_startTimeDay;
    }
    
    
    /*
     *
     */
    QTime HeatControl::getStartTimeNight(int nid, int sid)
    {
        int pos = SHsensor::hash(nid, sid);
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    
    
        if (pos == -1 or C[pos] == nullptr)
            return QTime(11,11);
        else
            return C[pos]->m_startTimeNight;
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    }
    
    
    /*
     *
     */
    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"};
    
    Peter Altenbernd's avatar
    Peter Altenbernd committed
    
    /*
     *
     */
    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
    }