diff --git a/.github/workflows/pull_request_build.yml b/.github/workflows/pull_request_build.yml index dc6ccce..6cec932 100644 --- a/.github/workflows/pull_request_build.yml +++ b/.github/workflows/pull_request_build.yml @@ -35,7 +35,7 @@ jobs: - name: Static analysis run: | sudo apt-get install -y cppcheck - cppcheck --enable=all --language=c++ --suppress=missingIncludeSystem --suppress=unusedFunction --suppress=unusedStructMember --suppress=noExplicitConstructor --suppress=noCopyConstructor --suppress=noOperatorEq --suppress=cstyleCast --suppress=constParameterCallback --suppress=constParameterPointer --suppress=constVariablePointer --suppress=unsignedLessThanZero --suppress=unsignedPositive --suppress=checkersReport --error-exitcode=1 *.ino *.cpp *.h + cppcheck --enable=all --language=c++ --suppress=missingIncludeSystem --suppress=unusedFunction --suppress=unusedStructMember --suppress=noExplicitConstructor --suppress=noCopyConstructor --suppress=noOperatorEq --suppress=cstyleCast --suppress=constParameterPointer --suppress=constVariablePointer --suppress=unsignedLessThanZero --suppress=unsignedPositive --suppress=checkersReport --error-exitcode=1 *.ino *.cpp *.h - name: Compile Arduino project run: | diff --git a/HeatingTemperatureRegulator.ino b/HeatingTemperatureRegulator.ino index 34c034d..33613f9 100644 --- a/HeatingTemperatureRegulator.ino +++ b/HeatingTemperatureRegulator.ino @@ -18,10 +18,6 @@ #define HEATINGPUMPRELAYPIN 10 #define HEATERWASTEGASTHERMOSTATPIN 11 #define ONEWIREBUSPIN 7 -#define SERVOMAXRANGE 70000 //Časový interval pohybu serva mezi krajními hodnotami -#define SERVO1PC 700L //Jedno procento z intervalu serva -#define MINSERVOINTERVAL 700 //Minimální interval pro aktivaci serva -#define AVGOUTTEMPVALUES 180 //Počet hodnot pro výpočet průměrné venkovní teploty (počet minut) #define FASTAVGALPHA 0.3 #define SLOWAVGALPHA 0.035 @@ -41,19 +37,6 @@ void convertToHalfByte(int value, uint8_t* result, uint8_t length) } } -void convert_to_utf8(const uint8_t* input, uint8_t length, char* output) { - int j = 0; - for(int i = 0; i < length; i++) - { - uint8_t first = input[i] >> 4; - uint8_t second = input[i] & 0x0F; - output[j++] = first<10? (char)('0'+first):(char)('7'+first); - output[j++] = second<10? (char)('0'+second):(char)('7'+second); - } - - output[j] = '\0'; // Null-terminate the UTF-8 string -} - /* 0 - currentTemperature 1 - inputTemperature @@ -77,6 +60,7 @@ void convert_to_utf8(const uint8_t* input, uint8_t length, char* output) { 19 - averageOutsideTemperature B2 20 - averageOutsideTemperature B3 (MSB) 21 - heatermode +22 - flame */ #pragma pack(push, 1) struct HeaterState { @@ -125,7 +109,6 @@ FVEData currentFveData; DiagData currentDiagData; BelData belData; -uint8_t temperatureDataToCompare[5]; Display lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES); Ds1302 rtc(4, 5, 6); TX07KTXC outsideTemperatureSensor(2, 3, OutsideTemperatureChanged); @@ -155,7 +138,6 @@ bool relayOn = false; int8_t direction = 0; double outsideTemperature = 14; double outsideTemperatureAverage = 0; -int sensor = 1; bool thermostat = false; uint8_t sensrId = 0; int lastCurrentTemp = 0; @@ -169,6 +151,7 @@ unsigned long mqttConnectionTimeout = 0; unsigned long mqttLastConnectionTry = 0; bool shouldHeatingBeOnByTemperature = false; bool outsideTemperatureWasSet = false; +unsigned long lastOutsideTemperatureMillis = 0; bool fveOnlineSent = false; bool fveOfflineSent = false; unsigned long fastReadMillis = 0; @@ -226,7 +209,6 @@ void setup() { ComputeWasteGasTemperature(); ComputeSlowWasteGasTemperature(); lcd.SetWasteGasTemperature(averageWasteGasTemperature); - ComputeOutsideTemperatureAverage(); lcd.EndInitialize(); convertToHalfByte(999, currentState.outsideAvgTemp, 4); resetServo = true; @@ -432,17 +414,33 @@ void OutsideTemperatureChanged(double temperature, uint8_t channel, uint8_t sens if(channel == 1 && sensrId == sensorId) { outsideTemperature = temperature; - if (memcmp(rawData, temperatureDataToCompare, 5) != 0) + client.Publish(TOPIC_OUTSIDETEMPERATURE, rawData, 5); + + //Časově vážený průměr pro ekviterm. Váha čerstvého čtení roste s dobou od + //posledního příjmu => krátké nepravidelné mezery i výpadek se zohlední samy. + double oldAverage = outsideTemperatureAverage; + if(!outsideTemperatureWasSet) { - convert_to_utf8(rawData, 5, utf8Buffer); - client.Publish(TOPIC_OUTSIDETEMPERATURE, (const char*) utf8Buffer, true); - memcpy(temperatureDataToCompare, rawData, 5); + outsideTemperatureAverage = temperature; //první čtení = nasazení } - if(!outsideTemperatureWasSet) + else + { + double elapsedMin = (currentMillis - lastOutsideTemperatureMillis) / 60000.0; + if(elapsedMin > 0) + { + double alpha = 1.0 - exp(-elapsedMin / OUTSIDEAVGTAU); + outsideTemperatureAverage = constrain(alpha * temperature + (1 - alpha) * outsideTemperatureAverage, -50, 50); + } + } + if(oldAverage != outsideTemperatureAverage) { - outsideTemperatureAverage = temperature; + int T = (int)(outsideTemperatureAverage * 10); + convertToHalfByte(T, currentState.outsideAvgTemp, 4); } + + lastOutsideTemperatureMillis = currentMillis; outsideTemperatureWasSet = true; + lcd.SetOutTemperature(temperature); } } @@ -477,22 +475,6 @@ void computeRequiredTemperature() } } -void ComputeOutsideTemperatureAverage() -{ - if(!outsideTemperatureWasSet) - { - return; - } - double oldAverage = outsideTemperatureAverage; - double alpha = 1.0 / 180.0; - outsideTemperatureAverage = constrain(alpha * outsideTemperature + (1 - alpha) * outsideTemperatureAverage, -50, 50); - if(oldAverage != outsideTemperatureAverage) - { - int T = (int)(outsideTemperatureAverage * 10); - convertToHalfByte(T, currentState.outsideAvgTemp, 4); - } -} - void ComputeSlowWasteGasTemperature() { int previousWasteGasTemperature = (int)slowAverageWasteGasTemperature; @@ -729,7 +711,6 @@ void sendToHomeAssistant() { if(sendIndex == 0) { - ComputeOutsideTemperatureAverage(); computeRequiredTemperature(); sendHeaterToHomeAssistant(); sendIndex = 1; @@ -880,6 +861,10 @@ void loop() { resetServo = false; } outsideTemperatureSensor.CheckTemperature(); + if(outsideTemperatureWasSet && currentMillis - lastOutsideTemperatureMillis > OUTSIDETEMPERATURETIMEOUT) + { + lcd.SetOutTemperatureNotSet(); + } belWattmeter.Loop(); if(currentMillis - fastReadMillis > 50) { diff --git a/config_default.h b/config_default.h index b262fbc..cc55c7b 100644 --- a/config_default.h +++ b/config_default.h @@ -19,6 +19,12 @@ #define OVERHEATINGTEMPERATURE 0 #define MININPUTTEMPERATURE 0 #define MAXIMALSERVOSTEP 3 +#define SERVOMAXRANGE 70000 //Časový interval pohybu serva mezi krajními hodnotami +#define SERVO1PC 700L //Jedno procento z intervalu serva +#define MINSERVOINTERVAL 700 //Minimální interval pro aktivaci serva +#define OUTSIDEAVGTAU 180.0 //Časová konstanta průměru venkovní teploty [min] (≈ původní 1/180) +#define OUTSIDETEMPERATURETIMEOUT 600000UL //Po této době bez dat ze snímače [ms] => na displeji --.- + #define HeaterOn(ht, wgt) false #define HeaterOff(ht, wgt) false diff --git a/display.cpp b/display.cpp index 2307eb0..6865f66 100644 --- a/display.cpp +++ b/display.cpp @@ -33,12 +33,12 @@ } } - void Display::printOutTemperature(bool blink) + void Display::printOutTemperature() { - if(blink) + lcd->setCursor(10, 1); + if(!outsideTemperatureWasSet) { - lcd->setCursor(10, 1); - lcd->print(" "); + lcd->print(" --.-"); } else { @@ -58,8 +58,8 @@ lcd->print(" "); } lcd->print(outTemperature, 1); - lcd->write((byte)1); } + lcd->write((byte)1); } Display::Display(uint8_t lcd_Addr,uint8_t lcd_cols,uint8_t lcd_rows) @@ -102,15 +102,25 @@ void Display::SetOutTemperature(double outTemperature) { + outsideTemperatureWasSet = true; if(this->outTemperature != outTemperature || forcePrint) { this->outTemperature = outTemperature; if(!initializing) { - printOutTemperature(false); + printOutTemperature(); } } - outsideTemperatureWasSet = true; + } + + void Display::SetOutTemperatureNotSet() + { + if(!outsideTemperatureWasSet) + { + return; + } + outsideTemperatureWasSet = false; + printOutTemperature(); } void Display::SetWasteGasTemperature(int wasteGasTemperature) @@ -246,10 +256,6 @@ lcd->write((byte)3); } } - if(!outsideTemperatureWasSet) - { - printOutTemperature(shouldBlink); - } if(mode == 2 && !thermostat) { PrintMode(mode, shouldBlink); @@ -282,7 +288,7 @@ forcePrint = true; lcd->clear(); SetRequiredTemperature(this->requiredTemperature); - SetOutTemperature(this->outTemperature); + printOutTemperature(); SetWasteGasTemperature(this->wasteGasTemperature); SetInputTemperature(this->inputTemperature); SetCurrentHeatingTemperature(this->currentHeatingTemperature); @@ -307,4 +313,4 @@ } } } - } \ No newline at end of file + } diff --git a/display.h b/display.h index a6e4660..4dfdf10 100644 --- a/display.h +++ b/display.h @@ -51,7 +51,7 @@ class Display void print2digits(uint8_t number); void printTime(); - void printOutTemperature(bool blink); + void printOutTemperature(); void Blink(); void PrintMode(uint8_t mode, bool blink); @@ -69,4 +69,5 @@ class Display void SetThermostat(bool thermostat); void EndInitialize(); void SetHeater(bool heaterOn); + void SetOutTemperatureNotSet(); }; \ No newline at end of file diff --git a/docs/PARAMETERS.md b/docs/PARAMETERS.md index c385d3d..a5c54a2 100644 --- a/docs/PARAMETERS.md +++ b/docs/PARAMETERS.md @@ -20,7 +20,7 @@ | `TOPIC_CURRENTDATETIEM` | IN | Synchronizace času ve formátu `YYYY-MM-DD HH:MM:SS` | | `TOPIC_THERMOSTATSETCHANGED` | IN | Požadovaná vnitřní teplota z termostatu (float) | | `TOPIC_OUTSIDETEMPERATURE` | OUT | Surová data z venkovního čidla (hex-encoded 5 bajtů) | -| `TOPIC_HEATERSTATE` | OUT | Binární paket `HeaterState` (22 bajtů) se stavem regulátoru | +| `TOPIC_HEATERSTATE` | OUT | Binární paket `HeaterState` (23 bajtů) se stavem regulátoru | | `TOPIC_FVE` | OUT | **Volitelný** — binární paket `FVEData` (16 bajtů) s daty z wattmetru | | `TOPIC_FVE_STATE` | OUT | **Volitelný** — stav FVE (`Online` / `Offline`) |