/** * Controller of Power PWM (PID) Regler for StromLog * Version 0.09 * 11.04.2024 P. Rebesky * author Creator P.Rebesky * Copyright (©): 2024-2028 by Peter Rebesky * This code can use in private cases only. Every business or companies using of this codes or codes parts is required an approval of us (me) * Every private using can exchange some parts of code or modify some code-lines. This code is allowed change for private use only. * This software is basicly owned by Peter Rebesky and any comercial using is forbidden without approval of us (me). **/ #ifndef CONTROL_CLIENT_H_ #define CONTROL_CLIENT_H_ //#define CONTROL_DEBUG #include "global.h" #include "diagram.h" #include "configPWR.h" extern configPWR cPWR; //***************** class for remember of conditions of relais *********** class controlRelais{ private: void begin(); public: uint32_t PWM_active_time = 0; uint32_t CirculationPumpOffTime = 0; int PWMvalue = 255; int PWM_Power = 0; int temperatureBefore = 0; // bool AllRelaisesOff = false; bool statusMaxTemp = false; int getPumpOffTime(); int getPumpOnTime(); }; void controlRelais::begin(){ // do nothing. Is for compatibility only } int controlRelais::getPumpOffTime(){ int offTime = this->PWM_active_time + cPWR.getPumpOFF() -_timestamp; if(offTime>0)offTime = (offTime/60)+1; else offTime=0; return offTime; } int controlRelais::getPumpOnTime(){ int onTime=this->CirculationPumpOffTime + WAIT_TIME_PUMP - _timestamp; if(onTime>0)onTime = (onTime/60)+1; else onTime=0; return onTime; } controlRelais relais; // declare after writing class //****************** set pins for relais output ************************** void SetupRelais(){ pinMode(SecureRELAIS, OUTPUT); digitalWrite(SecureRELAIS, OFF); // set relais off pinMode(CirculationPump, OUTPUT); digitalWrite(CirculationPump, OFF); // set relais off pinMode(PWM_OUT, OUTPUT); // set as PWM output analogWriteRange(255); // set range from 0 (on) to 255 (off) analogWrite(PWM_OUT, 255); // turn off #ifdef PMW_4_X4 pinMode(RELAIS1, OUTPUT); digitalWrite(RELAIS1, OFF); // set relais off pinMode(RELAIS2, OUTPUT); digitalWrite(RELAIS2, OFF); // set relais off #endif } //********** calculate power from PWM value ****************************** int calculatePower(){ int p=255-relais.PWMvalue; float x= (float)p / 255.0; x = x*x* (float)cPWR.getMaxConsumption(); _sumConsumption = _sumConsumption + x; return x; } //******************** turn off the relais and set variable to zero ********** void turnAllOff(){ relais.PWMvalue=255; _controlValue=0; //del control-Value too analogWrite(PWM_OUT, relais.PWMvalue); // turn PWM off relais.PWM_Power=0; digitalWrite(SecureRELAIS, OFF); } bool turnAllOffAfterTime(){ _waitTimeOffCount += cPWR.getScanTime(); //debug //Serial.println(_waitTimeOffCount); relais.PWMvalue += 75; // reduce PWM by count of 75 if(relais.PWMvalue > 255) relais.PWMvalue=255; // PWM is off already analogWrite(PWM_OUT, relais.PWMvalue); // reduce PWM before turn off because consumption is too high relais.PWM_Power=calculatePower(); if(_waitTimeOffCount >= cPWR.getOffWait()){ _waitTimeOffCount=0; turnAllOff(); return true; } else return false; } //*********************** handle on or off circulationpump ********************* bool turnOffCirculationPump(){ if(relais.PWM_active_time + cPWR.getPumpOFF() < _timestamp && digitalRead(CirculationPump)){ // only turn off if pump is on, because of remember the turn off time relais.CirculationPumpOffTime=_timestamp; // remember of off-time of pump turnAllOff(); // turn all relais off if they are on yet digitalWrite(CirculationPump, OFF); return true; } else return false; } bool turnOnCirculationPump(){ bool ret=false; if(relais.CirculationPumpOffTime < (_timestamp - WAIT_TIME_PUMP)){ // after turn off pump wait x minutes before turn on again digitalWrite(CirculationPump, ON); relais.PWM_active_time=_timestamp; // remember that pump is switch on ret=true; } return ret; } bool switchCirculationPump(bool onOff){ if(onOff) return turnOnCirculationPump(); else return turnOffCirculationPump(); } //********** calculate PI result of difference by consumption ************ int calculatePIanswer(int consumption){ int rglValue=0; int difference=cPWR.getValueREG()-consumption; // calculate difference example -100 - -200 = 100 int x = ((difference* -cPWR.getValueKP())/cPWR.getMaxConsumption()); // calculate steps of regel-value by Kp if(difference != 0){ rglValue= x; // set PWM higher by -value, PWM lower by +value } _controlValue= rglValue * -1; return rglValue; } //**************** stop to get PWM value higher and reduce this value by 10 ************* int tempControlExtended(int diff){ if(_temperature0 >= cPWR.minTemperatur() && diff<0){ int tempDiff = _temperature0 - relais.temperatureBefore; if(tempDiff > 5) tempDiff=5; switch (tempDiff){ // stop and reduce regulation by temp sensor case 0: diff=5; break; case 1: diff=10; break; case 2: diff=40; break; case 3: diff=80; break; case 4: diff=120; break; case 5: diff=200; break; default: diff=diff;// diff = input diff } relais.temperatureBefore = _temperature0; } else relais.temperatureBefore = _temperature0; // save temperatur it was check before for d-regulation return diff; } //*********************** Set PWM Value ********************************** void setPWMvalue(int consumption){ if(consumption < cPWR.getValueOFF() && relais.PWMvalue <= 255 && relais.PWMvalue >= 0){ // check if consumption is lower as turn-off-value and is PWM value valid int diff = calculatePIanswer(consumption); // calculate difference value by difference of consumption and target-value relais.PWMvalue += tempControlExtended(diff); // combine difference value by check if max. temperature is reached if(relais.PWMvalue < 0) relais.PWMvalue=0; // if value lower as zero then set zero as result. Zero is the max value of PWM if(relais.PWMvalue > 255) relais.PWMvalue=255; // if value higher as 255 then set 255. 255 is the min value of PWM analogWrite(PWM_OUT, relais.PWMvalue); relais.PWM_Power = calculatePower(); // calculate consumption as W of heater if(relais.PWMvalue<255){ // if the value lower as 255, then turn pump on turnOnCirculationPump(); // turn circulation pump on relais.PWM_active_time=_timestamp; // set timestamp that regulation is active now } } if (relais.PWMvalue < 0 || relais.PWMvalue > 255 || consumption > cPWR.getValueOFF()){ turnAllOff(); // error handling if values are invalide } } //********************* check temperature *********************************** bool checkTemperature(){ if(_temperature0 >= cPWR.maxTemperatur()) relais.statusMaxTemp = true; // set flag as marker if (_temperature0 < cPWR.minTemperatur()) relais.statusMaxTemp = false; // check if temperature is go down again return relais.statusMaxTemp; } //********************* handle control of PWM depended of consumpion ******** void handleRegulation(int consumption){ if(!checkTemperature() && consumption < cPWR.getValueOFF()){ // check if temperatur is or was too high (return true) or is consumption too high if(consumption < cPWR.getValuePumpOn()) turnOnCirculationPump(); // turn pump on if consumption is lower (FeedIn) if(consumption < cPWR.getValueREG()) digitalWrite(SecureRELAIS,ON); // secure relais turn on if consumption of regulation is reached if(digitalRead(CirculationPump)) setPWMvalue(consumption); // set PWM value by difference of consumption just if is pump on (relais is on) } else { // turn off relais and set of PWM Value if(turnAllOffAfterTime()){ // check if off time is reached value entered by user? relais.PWMvalue=255; analogWrite(PWM_OUT, relais.PWMvalue); relais.PWM_Power=0; digitalWrite(SecureRELAIS, OFF); turnOffCirculationPump(); // turn pump off after x minutes when relaises were off. After off there is a wait time of 10 minutes before turn on pump again } } } //********************* error handling *********************************** void errorConnect(){ _errorCount++; if(_errorWait>=cPWR.getErrorWait()){ turnAllOff(); _receivedOK=false; // connect meter = false _actualConsumption=0; // set power to zero } } #endif //*** CONTROL_CLIENT_H_