|
|
@ -13,7 +13,7 @@ |
|
|
|
|
|
|
|
|
|
|
|
const char *TAG = "fc"; |
|
|
|
const char *TAG = "fc"; |
|
|
|
|
|
|
|
|
|
|
|
#define UNIDIR_T_MEAS_PERIOD 15 /* s */ |
|
|
|
#define UNIDIR_T_MEAS_PERIOD 60 |
|
|
|
struct FanControlState gState = {}; |
|
|
|
struct FanControlState gState = {}; |
|
|
|
|
|
|
|
|
|
|
|
static void timerCallback(); |
|
|
|
static void timerCallback(); |
|
|
@ -85,10 +85,10 @@ static const char * vent_mode_labels[] = { |
|
|
|
[VENT_MODE_RECUP] = "RECUP", |
|
|
|
[VENT_MODE_RECUP] = "RECUP", |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
static const char * recup_mode_labels[] = { |
|
|
|
//static const char * recup_mode_labels[] = {
|
|
|
|
[RECUP_MODE_TIME] = "TIME", |
|
|
|
// [RECUP_MODE_TIME] = "TIME",
|
|
|
|
[RECUP_MODE_TEMP] = "TEMP", |
|
|
|
// [RECUP_MODE_TEMP] = "TEMP",
|
|
|
|
}; |
|
|
|
//};
|
|
|
|
|
|
|
|
|
|
|
|
static void timerCallback() |
|
|
|
static void timerCallback() |
|
|
|
{ |
|
|
|
{ |
|
|
@ -115,7 +115,9 @@ static void timerCallback() |
|
|
|
gState.ramp++; |
|
|
|
gState.ramp++; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
gState.run_time++; |
|
|
|
if (gState.run_time < 0xFFFF) { |
|
|
|
|
|
|
|
gState.run_time++; |
|
|
|
|
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
if (gState.ramp > 0) { |
|
|
|
if (gState.ramp > 0) { |
|
|
|
gState.ramp--; |
|
|
|
gState.ramp--; |
|
|
@ -141,7 +143,8 @@ static void timerCallback() |
|
|
|
if (gState.blind_position >= gSettings.blind_time) { |
|
|
|
if (gState.blind_position >= gSettings.blind_time) { |
|
|
|
act_motor_power_set(gState.set_power); |
|
|
|
act_motor_power_set(gState.set_power); |
|
|
|
} |
|
|
|
} |
|
|
|
if (gState.ramp >= gSettings.ramp_time * 2) { |
|
|
|
// some time is needed before the temperature means anything
|
|
|
|
|
|
|
|
if (gState.run_time >= UNIDIR_T_MEAS_PERIOD) { |
|
|
|
end_temp_meas = true; |
|
|
|
end_temp_meas = true; |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
break; |
|
|
@ -151,7 +154,7 @@ static void timerCallback() |
|
|
|
if (gState.blind_position >= gSettings.blind_time) { |
|
|
|
if (gState.blind_position >= gSettings.blind_time) { |
|
|
|
act_motor_power_set(gState.set_power); |
|
|
|
act_motor_power_set(gState.set_power); |
|
|
|
} |
|
|
|
} |
|
|
|
if (gState.ramp >= gSettings.ramp_time * 2) { |
|
|
|
if (gState.run_time >= UNIDIR_T_MEAS_PERIOD) { |
|
|
|
end_temp_meas = true; |
|
|
|
end_temp_meas = true; |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
break; |
|
|
@ -164,54 +167,14 @@ static void timerCallback() |
|
|
|
// Stop condition
|
|
|
|
// Stop condition
|
|
|
|
bool do_switch = false; |
|
|
|
bool do_switch = false; |
|
|
|
|
|
|
|
|
|
|
|
// TODO questionable logic, verify
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (gSettings.recup_mode == RECUP_MODE_TIME) { |
|
|
|
if (gSettings.recup_mode == RECUP_MODE_TIME) { |
|
|
|
do_switch = gState.run_time >= gSettings.recup_time; |
|
|
|
do_switch = gState.run_time >= gSettings.recup_time; |
|
|
|
} else if (gState.run_time >= gSettings.max_recup_time) { |
|
|
|
|
|
|
|
do_switch = true; |
|
|
|
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// temp-based switching - magic(tm)
|
|
|
|
if (gState.run_time >= gSettings.max_recup_time) { |
|
|
|
// Delta = IN - OUT
|
|
|
|
// Max time elapsed, switch even if the condition was not reached
|
|
|
|
const int16_t ideal_delta = gState.t_indoor - gState.t_outdoor; |
|
|
|
do_switch = true; |
|
|
|
int16_t stop_delta = ((int32_t) ideal_delta |
|
|
|
|
|
|
|
* (int32_t) (100 - gSettings.recup_factor)) / 100; |
|
|
|
|
|
|
|
int16_t delta = 0; |
|
|
|
|
|
|
|
bool allow_temp_switch = false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (gState.real_direction == MOTOR_DIR_OUT) { |
|
|
|
|
|
|
|
if (gState.valid_t_indoor && gState.valid_t_exhaust && gState.valid_t_outdoor) { |
|
|
|
|
|
|
|
delta = gState.t_indoor - gState.t_exhaust; |
|
|
|
|
|
|
|
allow_temp_switch = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// IN
|
|
|
|
// TODO
|
|
|
|
if (gState.valid_t_inflow && gState.valid_t_indoor && gState.valid_t_outdoor) { |
|
|
|
|
|
|
|
delta = gState.t_inflow - gState.t_outdoor; |
|
|
|
|
|
|
|
allow_temp_switch = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ESP_LOGI(TAG, "Delta now %d, max %d, stop %d (RF %d%%), allow_switch %d Cx10", delta, ideal_delta, stop_delta, gSettings.recup_factor, allow_temp_switch); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -243,8 +206,8 @@ static void timerCallback() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Measure temperatures
|
|
|
|
// Measure temperatures
|
|
|
|
int16_t t1 = act_temp1(); |
|
|
|
cels_t t1 = act_temp1(); |
|
|
|
int16_t t2 = act_temp2(); |
|
|
|
cels_t t2 = act_temp2(); |
|
|
|
|
|
|
|
|
|
|
|
gState.t_actual_in = t1; |
|
|
|
gState.t_actual_in = t1; |
|
|
|
gState.t_actual_out = t2; |
|
|
|
gState.t_actual_out = t2; |
|
|
@ -273,29 +236,24 @@ static void timerCallback() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ESP_LOGI(TAG, |
|
|
|
ESP_LOGI(TAG, |
|
|
|
"%s (ef %s, inst %s), rt %ds %d%%m, Tid %d%s, Tod %d%s, Tit %d%s, Teh %d%s, T1 %d%s, T2 %d%s Cx10", |
|
|
|
"%s (%s), B%ds, M%ds, %d%%, Tid %.2f%s, Tod %.2f%s, Tit %.2f%s, Teh %.2f%s, T1 %.2f%s, T2 %.2f%s C", |
|
|
|
vent_mode_labels[gState.set_vent_mode], vent_mode_labels[gState.effective_vent_mode], vent_mode_labels[gState.instantaneous_vent_mode], |
|
|
|
vent_mode_labels[gState.set_vent_mode], vent_mode_labels[gState.instantaneous_vent_mode], |
|
|
|
|
|
|
|
gState.blind_position, |
|
|
|
gState.run_time, |
|
|
|
gState.run_time, |
|
|
|
gAct.power, |
|
|
|
gAct.power, |
|
|
|
|
|
|
|
|
|
|
|
gState.t_indoor, |
|
|
|
gState.t_indoor, gState.valid_t_indoor ? "" : "!", |
|
|
|
gState.valid_t_indoor ? "" : "!", |
|
|
|
gState.t_outdoor, gState.valid_t_outdoor ? "" : "!", |
|
|
|
gState.t_outdoor, |
|
|
|
gState.t_inflow, gState.valid_t_inflow ? "" : "!", |
|
|
|
gState.valid_t_outdoor ? "" : "!", |
|
|
|
gState.t_exhaust, gState.valid_t_exhaust ? "" : "!", |
|
|
|
gState.t_inflow, |
|
|
|
gState.t_actual_in, gState.valid_t_actual_in ? "" : "!", |
|
|
|
gState.valid_t_inflow ? "" : "!", |
|
|
|
gState.t_actual_out, gState.valid_t_actual_out ? "" : "!" |
|
|
|
gState.t_exhaust, |
|
|
|
|
|
|
|
gState.valid_t_exhaust ? "" : "!", |
|
|
|
|
|
|
|
gState.t_actual_in, |
|
|
|
|
|
|
|
gState.valid_t_actual_in ? "" : "!", |
|
|
|
|
|
|
|
gState.t_actual_out, |
|
|
|
|
|
|
|
gState.valid_t_actual_out ? "" : "!" |
|
|
|
|
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void fan_set_vent_mode(enum ventilation_mode mode) |
|
|
|
void fan_set_vent_mode(enum ventilation_mode mode) |
|
|
|
{ |
|
|
|
{ |
|
|
|
ESP_LOGI(TAG, "Set vent mode = %d", mode); |
|
|
|
ESP_LOGI(TAG, "Set vent mode = %s", vent_mode_labels[mode]); |
|
|
|
|
|
|
|
|
|
|
|
if (mode == gState.set_vent_mode) { |
|
|
|
if (mode == gState.set_vent_mode) { |
|
|
|
return; |
|
|
|
return; |
|
|
@ -323,7 +281,7 @@ static void invalidate_temps() |
|
|
|
gState.valid_t_actual_out = false; |
|
|
|
gState.valid_t_actual_out = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void fan_set_power(uint16_t power) |
|
|
|
void fan_set_power(perc_t power) |
|
|
|
{ |
|
|
|
{ |
|
|
|
ESP_LOGI(TAG, "Set power = %d%%", power); |
|
|
|
ESP_LOGI(TAG, "Set power = %d%%", power); |
|
|
|
|
|
|
|
|
|
|
|