From 475478aea4b020f893a49399a2df13b7810e89a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 21 Aug 2022 18:34:35 +0200 Subject: [PATCH] more logic and fixes, maybe buggy --- main/actuators.c | 2 + main/fancontrol.c | 105 ++++++++++++++++++++++++++++++++++++---------- main/fancontrol.h | 21 +++++++--- main/settings.h | 5 ++- 4 files changed, 103 insertions(+), 30 deletions(-) diff --git a/main/actuators.c b/main/actuators.c index 108db96..69357f5 100644 --- a/main/actuators.c +++ b/main/actuators.c @@ -76,6 +76,7 @@ static void motor_init() { } void act_motor_power_set(uint16_t perc) { + if (gAct.power == perc) return; if (perc > 0) { if (perc < gSettings.min_power) { perc = gSettings.min_power; @@ -88,6 +89,7 @@ void act_motor_power_set(uint16_t perc) { ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, duty); ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1); } else { + gAct.power = 0; ledc_stop(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, 0); } } diff --git a/main/fancontrol.c b/main/fancontrol.c index 365b070..9d4f03b 100644 --- a/main/fancontrol.c +++ b/main/fancontrol.c @@ -107,9 +107,64 @@ static void timerCallback(TimerHandle_t xTimer) { if (gState.blind_position >= gSettings.blind_time) { act_motor_power_set(gState.set_power); - // Stop condition - if (gState.real_direction == gAct.dir) { - if (gState.run_time >= gSettings.recup_time) { + if (gState.real_direction == gAct.dir && gState.run_time >= gSettings.min_recup_time) { + // Stop condition + bool do_switch = false; + + // TODO questionable logic, verify + + if (gSettings.recup_mode == RECUP_MODE_TIME) { + do_switch = gState.run_time >= gSettings.recup_time; + } else if (gState.run_time >= gSettings.max_recup_time) { + do_switch = true; + } else { + // temp-based switching - magic(tm) + const int16_t ideal_delta = gState.t_indoor - gState.t_outdoor; + int16_t delta, stop_delta; + bool allow_temp_switch = false; + if (gState.real_direction == MOTOR_DIR_OUT) { + delta = gState.t_indoor - gState.t_exhaust; + // 100% factor = nadoraz + stop_delta = ((int32_t)ideal_delta + * (int32_t)(100 - gSettings.recup_factor)) / 100; + // Delta = IN - OUT + if (gState.valid_t_indoor && gState.valid_t_exhaust && gState.valid_t_outdoor) { + allow_temp_switch = true; + } + } else { + // IN + delta = gState.t_inflow - gState.t_outdoor; + // 100% factor = nadoraz + stop_delta = ((int32_t)ideal_delta + * (int32_t)(gSettings.recup_factor)) / 100; + // Delta = IN - OUT + if (gState.valid_t_intake && gState.valid_t_indoor && gState.valid_t_outdoor) { + allow_temp_switch = true; + } + } + + if (allow_temp_switch) { + if (gSettings.summer_mode) { + if (ideal_delta < 0) { + // warmer outside, trying to keep cool in + if (delta >= stop_delta) { + do_switch = true; + } + } + // colder outside - no stopping (will run to max recup time) + } else { + if (ideal_delta > 0) { + // colder outside, trying to keep warmth in + if (delta <= stop_delta) { + do_switch = true; + } + } + // warmer outside - no stopping (will run to max recup time) + } + } + } + + if (do_switch) { // zmena smeru gState.run_time = 0; act_motor_direction_set(1 - gAct.dir); @@ -132,25 +187,27 @@ static void timerCallback(TimerHandle_t xTimer) { } if (end_temp_meas) { - uint16_t t1 = (uint16_t) (gState.t1_aggr / gState.t_aggr_cnt); - uint16_t t2 = (uint16_t) (gState.t2_aggr / gState.t_aggr_cnt); - switch (gState.real_direction) { - case MOTOR_DIR_IN: - gState.t_outdoor = t2; - gState.t_intake = t1; - gState.valid_t_outdoor = gState.valid_t_intake = true; - if (gState.effective_vent_mode == VENT_MODE_IN) { - gState.valid_t_indoor = gState.valid_t_exhaust = false; - } - break; - case MOTOR_DIR_OUT: - gState.t_indoor = t1; - gState.t_exhaust = t2; - gState.valid_t_indoor = gState.valid_t_exhaust = true; - if (gState.effective_vent_mode == VENT_MODE_OUT) { - gState.valid_t_outdoor = gState.valid_t_intake = false; - } - break; + if (gState.t_aggr_cnt > 0) { + uint16_t t1 = (uint16_t) (gState.t1_aggr / gState.t_aggr_cnt); + uint16_t t2 = (uint16_t) (gState.t2_aggr / gState.t_aggr_cnt); + switch (gState.real_direction) { + case MOTOR_DIR_IN: + gState.t_outdoor = t2; + gState.t_inflow = t1; + gState.valid_t_outdoor = gState.valid_t_intake = true; + if (gState.effective_vent_mode == VENT_MODE_IN) { + gState.valid_t_indoor = gState.valid_t_exhaust = false; + } + break; + case MOTOR_DIR_OUT: + gState.t_indoor = t1; + gState.t_exhaust = t2; + gState.valid_t_indoor = gState.valid_t_exhaust = true; + if (gState.effective_vent_mode == VENT_MODE_OUT) { + gState.valid_t_outdoor = gState.valid_t_intake = false; + } + break; + } } gState.t1_aggr = gState.t2_aggr = gState.t_aggr_cnt = 0; } @@ -185,8 +242,10 @@ void fan_set_vent_mode(enum ventilation_mode mode) { gState.set_vent_mode = mode; gState.t1_aggr = gState.t2_aggr = gState.t_aggr_cnt = 0; - if (gState.set_power != 0) { + if (gState.set_power != 0 || mode == VENT_MODE_FREE) { gState.effective_vent_mode = mode; + } else if (gState.set_power == 0) { + gState.effective_vent_mode = VENT_MODE_OFF; } if (mode == VENT_MODE_OFF || mode == VENT_MODE_FREE) { diff --git a/main/fancontrol.h b/main/fancontrol.h index 32bce03..4610dbc 100644 --- a/main/fancontrol.h +++ b/main/fancontrol.h @@ -18,6 +18,15 @@ enum ventilation_mode { VENT_MODE_RECUP = 7, }; +enum recup_mode { + /** stricly time based recuperation switching */ + RECUP_MODE_TIME = 0, + /** Temperature-based recuperation switching + * (switch direction when further blowing won't save energy) */ + RECUP_MODE_TEMP = 1, +}; + + struct FanControlState { /** * Power requested trough register or as the default value. @@ -39,13 +48,13 @@ struct FanControlState { bool valid_t_actual_1; bool valid_t_actual_2; - uint16_t t_indoor; - uint16_t t_outdoor; - uint16_t t_intake; - uint16_t t_exhaust; + int16_t t_indoor; + int16_t t_outdoor; + int16_t t_inflow; + int16_t t_exhaust; - uint16_t t_actual_1; - uint16_t t_actual_2; + int16_t t_actual_1; + int16_t t_actual_2; // Private /** diff --git a/main/settings.h b/main/settings.h index c1edab0..ba2079f 100644 --- a/main/settings.h +++ b/main/settings.h @@ -40,7 +40,10 @@ extern nvs_handle g_nvs_storage; X(uint32_t , ap_ip , , 0x0100a8c0 , true , u32 , &) /* 192.168.0.1 */ \ X(uint32_t , static_dns , , 0x08080808 , true , u32 , &) /* 8.8.8.8 */ \ X(uint16_t , recup_mode , , 0 , true , u16 , &) /* recuperator control mode - 0=time, 1=min time+temp equilibrium */ \ - X(uint16_t , recup_time , , 60 , true , u16 , &) /* seconds */ \ + X(uint16_t , recup_time , , 60 , true , u16 , &) /* seconds */ \ + X(uint16_t , recup_factor , , 80 , true , u16 , &) /* perc */ \ + X(uint16_t , min_recup_time , , 30 , true , u16 , &) /* seconds */ \ + X(uint16_t , max_recup_time , , 120 , true , u16 , &) /* seconds */ \ X(uint16_t , ramp_time , , 3 , true , u16 , &) /* cas rozjezdu nebo zastaveni motoru (s) */ \ X(uint16_t , blind_time , , 30 , true , u16 , &) /* cas otevreni nebo zavreni rolety (s) */ \ X(uint16_t , initial_mode , , 0 , true , u16 , &) /* rezim po zapnuti napajeni */ \