// // Created by MightyPork on 2022/08/20. // #include "fancontrol.h" #include "freertos/FreeRTOS.h" #include "freertos/timers.h" #include "settings.h" #include "actuators.h" #define UNIDIR_T_MEAS_PERIOD 15 /* s */ struct FanControlState gState = {}; static void timerCallback(TimerHandle_t xTimer); static void invalidate_temps(); void settings_blind_time_set(uint16_t blind_time) { bool nadoraz = (gState.blind_position >= gSettings.blind_time) || (gState.blind_position >= blind_time); gSettings.blind_time = blind_time; if (nadoraz) { gState.blind_position = blind_time; } settings_persist(SETTINGS_blind_time); } void fancontrol_init() { gState.set_vent_mode = gSettings.initial_mode; gState.set_power = gSettings.initial_power; xTimerCreate("fanctl", pdMS_TO_TICKS(1000), pdTRUE, NULL, timerCallback); } static void timerCallback(TimerHandle_t xTimer) { // posun rolety if (gAct.blind) { if (gState.blind_position < gSettings.blind_time) { gState.blind_position++; } } else { if (gState.blind_position > 0) { gState.blind_position--; } } if (gAct.power > 0) { if (gState.real_direction != gAct.dir) { if (gState.ramp > 0) { gState.ramp--; } else { gState.run_time = 0; gState.real_direction = gAct.dir; } } else { if (gState.ramp < gSettings.ramp_time) { gState.ramp++; } } gState.run_time++; } else { if (gState.ramp > 0) { gState.ramp--; } else { gState.run_time = 0; } } bool end_temp_meas = false; switch (gState.effective_vent_mode) { case VENT_MODE_OFF: act_motor_power_set(0); act_blind_set(0); break; case VENT_MODE_FREE: act_motor_power_set(0); act_blind_set(1); break; case VENT_MODE_OUT: act_motor_direction_set(MOTOR_DIR_OUT); act_blind_set(1); if (gState.blind_position >= gSettings.blind_time) { act_motor_power_set(gState.set_power); } if (gState.t_aggr_cnt > UNIDIR_T_MEAS_PERIOD) { end_temp_meas = true; } break; case VENT_MODE_IN: act_motor_direction_set(MOTOR_DIR_IN); act_blind_set(1); if (gState.blind_position >= gSettings.blind_time) { act_motor_power_set(gState.set_power); } if (gState.t_aggr_cnt > UNIDIR_T_MEAS_PERIOD) { end_temp_meas = true; } break; case VENT_MODE_RECUP: act_blind_set(1); 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) { // zmena smeru gState.run_time = 0; act_motor_direction_set(1 - gAct.dir); end_temp_meas = true; } } } break; } if (gState.effective_vent_mode == VENT_MODE_RECUP) { if (gState.real_direction == MOTOR_DIR_OUT) { gState.instantaneous_vent_mode = VENT_MODE_OUT; } else { gState.instantaneous_vent_mode = VENT_MODE_IN; } } else { gState.instantaneous_vent_mode = gState.effective_vent_mode; } 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; } gState.t1_aggr = gState.t2_aggr = gState.t_aggr_cnt = 0; } if (gState.effective_vent_mode == VENT_MODE_IN || gState.effective_vent_mode == VENT_MODE_OUT || gState.effective_vent_mode == VENT_MODE_RECUP) { // Measure temperatures int16_t t1 = 200; int16_t t2 = 190; // TODO gState.t_actual_1 = t1; gState.t_actual_2 = t2; gState.valid_t_actual_1 = gState.valid_t_actual_2 = true; if (gAct.dir == gState.real_direction && gState.ramp >= gSettings.ramp_time) { gState.t1_aggr += t1; gState.t2_aggr += t2; gState.t_aggr_cnt++; } } else { gState.valid_t_actual_1 = gState.valid_t_actual_2 = false; } } void fan_set_vent_mode(enum ventilation_mode mode) { if (mode == gState.set_vent_mode) { return; } gState.set_vent_mode = mode; gState.t1_aggr = gState.t2_aggr = gState.t_aggr_cnt = 0; if (gState.set_power != 0) { gState.effective_vent_mode = mode; } if (mode == VENT_MODE_OFF || mode == VENT_MODE_FREE) { invalidate_temps(); } } static void invalidate_temps() { gState.valid_t_indoor = false; gState.valid_t_outdoor = false; gState.valid_t_intake = false; gState.valid_t_exhaust = false; gState.valid_t_actual_1 = false; gState.valid_t_actual_2 = false; } void fan_set_power(uint16_t power) { gState.set_power = power; if (power == 0) { gState.effective_vent_mode = VENT_MODE_OFF; invalidate_temps(); } else { gState.effective_vent_mode = gState.set_vent_mode; } }