diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index e37626d7d..65133b4d8 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -410,6 +410,7 @@ #define USE_SONOFF_SC // Add support for Sonoff Sc (+1k1 code) #define USE_TUYA_MCU // Add support for Tuya Serial MCU #define TUYA_DIMMER_ID 0 // Default dimmer Id +// #define USE_TUYA_TIME // Add support for Set Time in Tuya MCU #define USE_ARMTRONIX_DIMMERS // Add support for Armtronix Dimmers (+1k4 code) #define USE_PS_16_DZ // Add support for PS-16-DZ Dimmer (+2k code) #define USE_SONOFF_IFAN // Add support for Sonoff iFan02 and iFan03 (+2k code) @@ -420,8 +421,8 @@ #define USE_EXS_DIMMER // Add support for ES-Store WiFi Dimmer (+1k5 code) // #define EXS_MCU_CMNDS // Add command to send MCU commands (+0k8 code) //#define USE_HOTPLUG // Add support for sensor HotPlug -#define USE_DEVICE_GROUPS // Add support for device groups (+5k code) - #define USE_DEVICE_GROUPS_SEND // Add support for the DevGroupSend command (+0k6 code) +#define USE_DEVICE_GROUPS // Add support for device groups (+5k6 code) + #define USE_DEVICE_GROUPS_SEND // Add support for the DevGroupSend command (+0k5 code) #define USE_PWM_DIMMER // Add support for MJ-SD01/acenx/NTONPOWER PWM dimmers (+2k5 code) #define USE_PWM_DIMMER_REMOTE // Add support for remote switches to PWM Dimmer, also adds device groups support (+1k code plus device groups size) //#define USE_KEELOQ // Add support for Jarolift rollers by Keeloq algorithm (+4k5 code) @@ -566,7 +567,8 @@ //#define USE_IBEACON // Add support for bluetooth LE passive scan of ibeacon devices (uses HM17 module) //#define USE_GPS // Add support for GPS and NTP Server for becoming Stratus 1 Time Source (+3k1 code, +132 bytes RAM) // #define USE_FLOG // Add support for GPS logging in OTA's Flash (Experimental) (+2k9 code, +8 bytes RAM) -//#define USE_HM10 // Add support for HM-10 as a BLE-bridge for the LYWSD03 (+5k1 code) +//#define USE_HM10 // (ESP8266 only) Add support for HM-10 as a BLE-bridge (+9k3 code) +//#define USE_MI_ESP32 // (ESP32 only) Add support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash) //#define USE_HRXL // Add support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7) // -- Power monitoring sensors -------------------- @@ -683,7 +685,7 @@ #define THERMOSTAT_TEMP_FROST_PROTECT 40 // Default minimum temperature for frost protection, in tenths of degrees celsius #define THERMOSTAT_TEMP_RAMPUP_DELTA_IN 4 // Default minimum delta temperature to target to get into rampup mode, in tenths of degrees celsius #define THERMOSTAT_TEMP_RAMPUP_DELTA_OUT 2 // Default minimum delta temperature to target to get out of the rampup mode, in tenths of degrees celsius -#define THERMOSTAT_TEMP_PI_RAMPUP_ACC_E 200 // Default accumulated error when switching from ramp-up controller to PI in hundreths of degrees celsius +#define THERMOSTAT_TEMP_PI_RAMPUP_ACC_E 20 // Default accumulated error when switching from ramp-up controller to PI #define THERMOSTAT_TIME_OUTPUT_DELAY 180 // Default output delay between state change and real actuation event (f.i. valve open/closed) #define THERMOSTAT_TEMP_INIT 180 // Default init target temperature for the thermostat controller diff --git a/tasmota/xdrv_39_thermostat.ino b/tasmota/xdrv_39_thermostat.ino index 88f460e8b..c3e97f3bf 100644 --- a/tasmota/xdrv_39_thermostat.ino +++ b/tasmota/xdrv_39_thermostat.ino @@ -341,7 +341,7 @@ bool HeatStateAllToOff(void) return change_state; } -void ThermostatState(void) +void ThermostatState() { switch (Thermostat.status.thermostat_mode) { case THERMOSTAT_OFF: // State if Off or Emergency @@ -394,28 +394,14 @@ void ThermostatOutputRelay(bool active) } } -void ThermostatCalculatePI(void) +void ThermostatCalculatePI() { - int32_t aux_time_error; - // Calculate error - aux_time_error = (int32_t)(Thermostat.temp_target_level_ctr - Thermostat.temp_measured) * 10; - - // Protect overflow - if (aux_time_error <= (int32_t)(INT16_MIN)) { - Thermostat.temp_pi_error = (int16_t)(INT16_MIN); - } - else if (aux_time_error >= (int32_t)INT16_MAX) { - Thermostat.temp_pi_error = (int16_t)INT16_MAX; - } - else { - Thermostat.temp_pi_error = (int16_t)aux_time_error; - } - + Thermostat.temp_pi_error = Thermostat.temp_target_level_ctr - Thermostat.temp_measured; // Kp = 100/PI.propBand. PI.propBand(Xp) = Proportional range (4K in 4K/200 controller) Thermostat.kP_pi = 100 / (uint16_t)(Thermostat.val_prop_band); // Calculate proportional - Thermostat.time_proportional_pi = ((int32_t)(Thermostat.temp_pi_error * (int16_t)Thermostat.kP_pi) * ((int32_t)Thermostat.time_pi_cycle * 60)) / 10000; + Thermostat.time_proportional_pi = ((int32_t)(Thermostat.temp_pi_error * (int16_t)Thermostat.kP_pi) * ((int32_t)Thermostat.time_pi_cycle * 60)) / 1000; // Minimum proportional action limiter // If proportional action is less than the minimum action time @@ -433,14 +419,13 @@ void ThermostatCalculatePI(void) Thermostat.time_proportional_pi = ((int32_t)Thermostat.time_pi_cycle * 60); } - // Calculate integral (resolution increased to avoid use of floats in consequent operations) - //Thermostat.kI_pi = (uint16_t)(((float)Thermostat.kP_pi * ((float)((uint32_t)Thermostat.time_pi_cycle * 60) / (float)Thermostat.time_reset)) * 100); - Thermostat.kI_pi = (uint16_t)((((uint32_t)Thermostat.kP_pi * (uint32_t)Thermostat.time_pi_cycle * 6000)) / (uint32_t)Thermostat.time_reset); + // Calculate integral + Thermostat.kI_pi = (uint16_t)(((float)Thermostat.kP_pi * ((float)((uint32_t)Thermostat.time_pi_cycle * 60) / (float)Thermostat.time_reset)) * 100); // Reset of antiwindup // If error does not lay within the integrator scope range, do not use the integral // and accumulate error = 0 - if (abs((Thermostat.temp_pi_error) / 10) > Thermostat.temp_reset_anti_windup) { + if (abs(Thermostat.temp_pi_error) > (int16_t)Thermostat.temp_reset_anti_windup) { Thermostat.time_integral_pi = 0; Thermostat.temp_pi_accum_error = 0; } @@ -455,26 +440,13 @@ void ThermostatCalculatePI(void) // very high cummulated error when beingin hysteresis. This triggers high // integral actions - // Update accumulated error - aux_time_error = (int32_t)Thermostat.temp_pi_accum_error + (int32_t)Thermostat.temp_pi_error; - - // Protect overflow - if (aux_time_error <= (int32_t)INT16_MIN) { - Thermostat.temp_pi_accum_error = INT16_MIN; - } - else if (aux_time_error >= (int32_t)INT16_MAX) { - Thermostat.temp_pi_accum_error = INT16_MAX; - } - else { - Thermostat.temp_pi_accum_error = (int16_t)aux_time_error; - } - // If we are under setpoint // AND we are within the hysteresis // AND we are rising if ((Thermostat.temp_pi_error >= 0) - && (abs((Thermostat.temp_pi_error) / 10) <= (int16_t)Thermostat.temp_hysteresis) + && (abs(Thermostat.temp_pi_error) <= (int16_t)Thermostat.temp_hysteresis) && (Thermostat.temp_measured_gradient > 0)) { + Thermostat.temp_pi_accum_error += Thermostat.temp_pi_error; // Reduce accumulator error 20% in each cycle Thermostat.temp_pi_accum_error *= 0.8; } @@ -482,9 +454,13 @@ void ThermostatCalculatePI(void) // AND temperature is rising else if ((Thermostat.temp_pi_error < 0) && (Thermostat.temp_measured_gradient > 0)) { + Thermostat.temp_pi_accum_error += Thermostat.temp_pi_error; // Reduce accumulator error 20% in each cycle Thermostat.temp_pi_accum_error *= 0.8; } + else { + Thermostat.temp_pi_accum_error += Thermostat.temp_pi_error; + } // Limit lower limit of acumErr to 0 if (Thermostat.temp_pi_accum_error < 0) { @@ -492,7 +468,7 @@ void ThermostatCalculatePI(void) } // Integral calculation - Thermostat.time_integral_pi = (((int32_t)Thermostat.temp_pi_accum_error * (int32_t)Thermostat.kI_pi) * (int32_t)((uint32_t)Thermostat.time_pi_cycle * 60)) / 1000000; + Thermostat.time_integral_pi = (((int32_t)Thermostat.temp_pi_accum_error * (int32_t)Thermostat.kI_pi) * (int32_t)((uint32_t)Thermostat.time_pi_cycle * 60)) / 100000; // Antiwindup of the integrator // If integral calculation is bigger than cycle time, adjust result @@ -520,7 +496,7 @@ void ThermostatCalculatePI(void) // If target value has been reached or we are over it]] if (Thermostat.temp_pi_error <= 0) { // If we are over the hysteresis or the gradient is positive - if ((abs((Thermostat.temp_pi_error) / 10) > Thermostat.temp_hysteresis) + if ((abs(Thermostat.temp_pi_error) > Thermostat.temp_hysteresis) || (Thermostat.temp_measured_gradient >= 0)) { Thermostat.time_total_pi = 0; } @@ -530,7 +506,7 @@ void ThermostatCalculatePI(void) // AND gradient is positive // then set value to 0 else if ((Thermostat.temp_pi_error > 0) - && (abs((Thermostat.temp_pi_error) / 10) <= Thermostat.temp_hysteresis) + && (abs(Thermostat.temp_pi_error) <= Thermostat.temp_hysteresis) && (Thermostat.temp_measured_gradient > 0)) { Thermostat.time_total_pi = 0; } @@ -557,7 +533,7 @@ void ThermostatCalculatePI(void) Thermostat.time_ctr_checkpoint = uptime + ((uint32_t)Thermostat.time_pi_cycle * 60); } -void ThermostatWorkAutomaticPI(void) +void ThermostatWorkAutomaticPI() { char result_chr[FLOATSZ]; // Remove! @@ -580,9 +556,8 @@ void ThermostatWorkAutomaticPI(void) } } -void ThermostatWorkAutomaticRampUp(void) +void ThermostatWorkAutomaticRampUp() { - int32_t aux_temp_delta; uint32_t time_in_rampup; int16_t temp_delta_rampup;