diff --git a/main/actuators.c b/main/actuators.c index 184f3e4..5367e2b 100644 --- a/main/actuators.c +++ b/main/actuators.c @@ -154,3 +154,7 @@ cels_t act_temp2() { return gTempSensors[1]; } + +uint16_t act_temps_serial() { + return gTempsSerial; +} diff --git a/main/actuators.h b/main/actuators.h index abebf97..a0ecc6c 100644 --- a/main/actuators.h +++ b/main/actuators.h @@ -32,5 +32,6 @@ void act_statusled_set(bool on); cels_t act_temp1(); cels_t act_temp2(); +uint16_t act_temps_serial(); #endif //FANCTL_ACTUATORS_H diff --git a/main/fancontrol.c b/main/fancontrol.c index 54bd839..6da41b7 100644 --- a/main/fancontrol.c +++ b/main/fancontrol.c @@ -20,6 +20,8 @@ static void timerCallback(); static void invalidate_temps(); +static float absf(float f); + void settings_blind_time_set(uint16_t blind_time) { // if the blind is surely at the end @@ -92,6 +94,18 @@ static const char * vent_mode_labels[] = { static void timerCallback() { + // Measure temperatures + cels_t tin = act_temp1(); + cels_t tout = act_temp2(); + + float old_tin = gState.t_actual_in; + float old_tout = gState.t_actual_out; + + gState.t_actual_in = tin; + gState.t_actual_out = tout; + + gState.valid_t_actual_in = gState.valid_t_actual_out = tempSensorsOk; + // posun rolety if (gAct.blind) { if (gState.blind_position < gSettings.blind_time) { @@ -167,14 +181,55 @@ static void timerCallback() // Stop condition bool do_switch = false; + // vyfukovaci strana trubice, libovona strana + if (gState.real_direction == MOTOR_DIR_IN) { + if (gState.t_actual_in <= gSettings.t_in_min || gState.t_actual_in >= gSettings.t_in_max) { + ESP_LOGW(TAG, "Temp limit reached, change dir!"); + do_switch = true; + } + } + + float t_output = gState.real_direction == MOTOR_DIR_OUT ? gState.t_actual_out : gState.t_actual_in; + float t_input = gState.real_direction == MOTOR_DIR_IN ? gState.t_actual_out : gState.t_actual_in; + float delta = absf(t_input - t_output); + + if (gState.real_direction == MOTOR_DIR_IN) { + if (delta < gSettings.t_stopdelta_in) { + ESP_LOGW(TAG, "IN stop delta reached, change dir!"); + do_switch = true; + } + } else { + if (delta < gSettings.t_stopdelta_out) { + ESP_LOGW(TAG, "OUT stop delta reached, change dir!"); + do_switch = true; + } + } + if (gSettings.recup_mode == RECUP_MODE_TIME) { - do_switch = gState.run_time >= gSettings.recup_time; + if (gState.run_time >= gSettings.recup_time) { + ESP_LOGW(TAG, "Recup time elapsed, change dir!"); + do_switch = true; + } } else { if (gState.run_time >= gSettings.max_recup_time) { + ESP_LOGW(TAG, "Max time elapsed, change dir!"); // Max time elapsed, switch even if the condition was not reached do_switch = true; } else { - // TODO + if (gState.lastTempsSerial != act_temps_serial()) { + // expecting some change in temps + float speed; + if (gState.real_direction == MOTOR_DIR_IN) { + speed = absf(tin - old_tin); + } else { + speed = absf(tout - old_tout); + } + + if (speed < gSettings.t_stop_speed) { + ESP_LOGW(TAG, "Near-equilibrium reached, change dir!"); + do_switch = true; + } + } } } @@ -205,15 +260,6 @@ static void timerCallback() gState.instantaneous_vent_mode = gState.effective_vent_mode; } - // Measure temperatures - cels_t t1 = act_temp1(); - cels_t t2 = act_temp2(); - - gState.t_actual_in = t1; - gState.t_actual_out = t2; - - gState.valid_t_actual_in = gState.valid_t_actual_out = tempSensorsOk; - if (end_temp_meas) { switch (gState.real_direction) { case MOTOR_DIR_IN: @@ -251,6 +297,15 @@ static void timerCallback() ); } +static float absf(float f) +{ + if (f < 0) { + return -f; + } else { + return f; + } +} + void fan_set_vent_mode(enum ventilation_mode mode) { ESP_LOGI(TAG, "Set vent mode = %s", vent_mode_labels[mode]); diff --git a/main/fancontrol.h b/main/fancontrol.h index 2b398d6..d3ffacd 100644 --- a/main/fancontrol.h +++ b/main/fancontrol.h @@ -54,6 +54,7 @@ struct FanControlState { cels_t t_inflow; cels_t t_exhaust; + uint16_t lastTempsSerial; cels_t t_actual_in; cels_t t_actual_out; diff --git a/main/mbiface.c b/main/mbiface.c index 0fcb261..c7bd40b 100644 --- a/main/mbiface.c +++ b/main/mbiface.c @@ -30,8 +30,13 @@ enum HoldingRegisters { H_RECUP_TIME = 13, H_RECUP_TIME_MIN = 14, H_RECUP_TIME_MAX = 15, - H_RECUP_FACTOR = 16, +// H_RECUP_FACTOR = 16, H_MIN_POWER = 17, + H_T_IN_MIN = 18, + H_T_IN_MAX = 19, + H_T_STOPDELTA_IN = 20, + H_T_STOPDELTA_OUT = 21, + H_T_STOP_SPEED = 22, // Hardware settings (don't need to change once set correctly) H_RAMP_TIME = 30, @@ -98,7 +103,13 @@ void endOfAccess(ModbusSlave_t *ms) { // } -#define cels2reg(cels) ((uint16_t) roundf((cels) * 100)) +union ui16 { + uint16_t u; + uint16_t i; +}; + +#define cels2reg(cels) (((union ui16) { .i = ((int16_t) roundf((cels) * 100.0f)) }).u) +#define reg2cels(regv) (((float) ((union ui16) { .u = (regv) }).i) / 100.0f) ModbusException_t ri(ModbusSlave_t *pSlave, uint16_t ref, uint16_t *pValue) { ESP_LOGD(TAG, "Read input %d", ref); @@ -211,9 +222,26 @@ ModbusException_t rh(ModbusSlave_t *pSlave, uint16_t ref, uint16_t *pValue) { case H_RECUP_TIME_MAX: *pValue = gSettings.max_recup_time; break; - case H_RECUP_FACTOR: - *pValue = gSettings.recup_factor; +// case H_RECUP_FACTOR: +// *pValue = gSettings.recup_factor; +// break; + + case H_T_IN_MIN: + *pValue = cels2reg(gSettings.t_in_min); + break; + case H_T_IN_MAX: + *pValue = cels2reg(gSettings.t_in_max); + break; + case H_T_STOPDELTA_IN: + *pValue = cels2reg(gSettings.t_stopdelta_in); break; + case H_T_STOPDELTA_OUT: + *pValue = cels2reg(gSettings.t_stopdelta_out); + break; + case H_T_STOP_SPEED: + *pValue = cels2reg(gSettings.t_stop_speed); + break; + case H_RAMP_TIME: *pValue = gSettings.ramp_time; break; @@ -257,6 +285,7 @@ static bool is_valid_vent_mode(int value) { ModbusException_t wh(ModbusSlave_t *pSlave, uint16_t ref, uint16_t value) { ESP_LOGD(TAG, "Write holding %d := %02x", ref, value); + float f; switch (ref) { case H_MODE: @@ -317,13 +346,49 @@ ModbusException_t wh(ModbusSlave_t *pSlave, uint16_t ref, uint16_t value) { gSettings.max_recup_time = value; settings_persist(SETTINGS_max_recup_time); break; - case H_RECUP_FACTOR: - if (value > 100) { +// case H_RECUP_FACTOR: +// if (value > 100) { +// return MB_EXCEPTION_ILLEGAL_DATA_VALUE; +// } +// gSettings.recup_factor = value; +// settings_persist(SETTINGS_recup_factor); +// break; + + case H_T_IN_MIN: + f = reg2cels(value); + gSettings.t_in_min = f; + settings_persist(SETTINGS_t_in_min); + break; + case H_T_IN_MAX: + f = reg2cels(value); + gSettings.t_in_max = f; + settings_persist(SETTINGS_t_in_max); + break; + case H_T_STOPDELTA_IN: + f = reg2cels(value); + if (f < 0) { + return MB_EXCEPTION_ILLEGAL_DATA_VALUE; + } + gSettings.t_stopdelta_in = f; + settings_persist(SETTINGS_t_stopdelta_in); + break; + case H_T_STOPDELTA_OUT: + f = reg2cels(value); + if (f < 0) { return MB_EXCEPTION_ILLEGAL_DATA_VALUE; } - gSettings.recup_factor = value; - settings_persist(SETTINGS_recup_factor); + gSettings.t_stopdelta_out = f; + settings_persist(SETTINGS_t_stopdelta_out); break; + case H_T_STOP_SPEED: + f = reg2cels(value); + if (f < 0) { + return MB_EXCEPTION_ILLEGAL_DATA_VALUE; + } + gSettings.t_stop_speed = f; + settings_persist(SETTINGS_t_stop_speed); + break; + case H_RAMP_TIME: gSettings.ramp_time = value; settings_persist(SETTINGS_ramp_time); diff --git a/main/onewires.c b/main/onewires.c index 6e92670..1e758a8 100644 --- a/main/onewires.c +++ b/main/onewires.c @@ -17,6 +17,7 @@ static DS18B20_Info *sDevs[2] = {}; volatile float gTempSensors[2] = {}; volatile bool tempSensorsOk = false; +volatile uint16_t gTempsSerial = 0; static void owtask(void *dummy) { while (1) { @@ -26,6 +27,7 @@ static void owtask(void *dummy) { gTempSensors[0] = a; gTempSensors[1] = b; + gTempsSerial++; ESP_LOGI(TAG, "t1 %.2f, t2 %.2f C", a, b); } } diff --git a/main/onewires.h b/main/onewires.h index 7df6421..acc4e7c 100644 --- a/main/onewires.h +++ b/main/onewires.h @@ -14,5 +14,6 @@ int read_onewires(cels_t *a, cels_t *b); extern volatile cels_t gTempSensors[2]; extern volatile bool tempSensorsOk; +extern volatile uint16_t gTempsSerial; #endif //ONEWIRES_H diff --git a/main/settings.c b/main/settings.c index c55c8b3..137cf98 100644 --- a/main/settings.c +++ b/main/settings.c @@ -37,7 +37,6 @@ union fu { uint32_t u; }; -#if 0 /** Read float from NVS. See `nvs_get_u32` for more info. */ static esp_err_t nvs_get_f32 (nvs_handle_t handle, const char* key, float* out_value) { uint32_t u = 0; @@ -61,7 +60,6 @@ static esp_err_t nvs_set_f32 (nvs_handle_t handle, const char* key, float value) }; return nvs_set_u32(handle, key, reinterpret.u); } -#endif /** Dummy read from NVS; placeholder for XTABLE entries with manually implemented getters */ static esp_err_t nvs_get_none(nvs_handle handle, const char* key, void* out_value) { diff --git a/main/settings.h b/main/settings.h index 65eb9e3..08daade 100644 --- a/main/settings.h +++ b/main/settings.h @@ -41,7 +41,6 @@ extern nvs_handle g_nvs_storage; 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_factor , , 80 , true , u16 , &) /* perc */ \ X(uint16_t , min_recup_time , , 30 , true , u16 , &) /* seconds */ \ X(uint16_t , max_recup_time , , 180 , true , u16 , &) /* seconds */ \ X(uint16_t , ramp_time , , 6 , true , u16 , &) /* cas rozjezdu nebo zastaveni motoru (s) */ \ @@ -51,7 +50,14 @@ extern nvs_handle g_nvs_storage; X(uint16_t , min_power , , 5 , true , u16 , &) /* min power % */ \ X(bool , summer_mode , , 0 , true , bool , &) /* rezim po zapnuti napajeni */ \ X(bool , swap_temps , , 0 , true , bool , &) /* swap t0/t1 */ \ - X(bool , swap_pwm_dir , , 0 , true , bool , &) /* swap pwm/dir signal */ + X(bool , swap_pwm_dir , , 0 , true , bool , &) /* swap pwm/dir signal */ \ + X(float , t_in_min , , 10 , true , f32 , &) /* minimalni teplota do mistnosti */ \ + X(float , t_in_max , , 27 , true , f32 , &) /* maximalni teplota do mistnosti */ \ + X(float , t_stopdelta_in , , 3 , true , f32 , &) /* delta when recuperation stops in IN mode */ \ + X(float , t_stopdelta_out , , 1 , true , f32 , &) /* delta when recuperation stops in OUT mode */ \ + X(float , t_stop_speed , , 0.025 , true , f32 , &) /* zastav rekuperaci, pokud zmena teploty na vystupni strane roste/klesa pomaleji nez X/sec */ + +// X(uint16_t , recup_factor , , 80 , true , u16 , &) /* perc */ enum settings_key_enum { #undef X