recuperator fan control with esp32
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
esp-recuperator/main/fancontrol.c

214 lines
6.2 KiB

//
// 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);
2 years ago
// 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;
2 years ago
}
}
}
2 years ago
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;
}
2 years ago
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);
2 years ago
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;
}
2 years ago
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;
}
2 years ago
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;
}
}