1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use crate::brain::modes::{InfoCache, Intention, Mode};
use crate::brain::python_like::control::heating_control::HeatPumpMode;
use crate::time_util::mytime::TimeProvider;
use crate::{expect_available, BrainFailure, IOBundle, PythonBrainConfig};
use core::option::Option::{None, Some};
use log::{error, info};
use tokio::runtime::Runtime;

use super::working_temp::{find_working_temp_action, CurrentHeatDirection, WorkingTempAction};

#[derive(Debug, PartialEq, Default)]
pub struct CirculateMode {}

impl Mode for CirculateMode {
    fn enter(
        &mut self,
        _config: &PythonBrainConfig,
        _runtime: &Runtime,
        io_bundle: &mut IOBundle,
    ) -> Result<(), BrainFailure> {
        let heating = expect_available!(io_bundle.heating_control())?;
        heating.set_heat_pump(HeatPumpMode::DrainTank, None)?;
        heating.set_heat_circulation_pump(true, None)
    }

    fn update(
        &mut self,
        rt: &Runtime,
        config: &PythonBrainConfig,
        info_cache: &mut InfoCache,
        io_bundle: &mut IOBundle,
        _time: &impl TimeProvider,
    ) -> Result<Intention, BrainFailure> {
        if !info_cache.heating_on() {
            return Ok(Intention::finish());
        }
        let temps = match rt.block_on(info_cache.get_temps(io_bundle.temperature_manager())) {
            Ok(temps) => temps,
            Err(e) => {
                error!("Failed to retrieve temperatures: {} - Turning off.", e);
                return Ok(Intention::off_now());
            }
        };
        let range = info_cache.get_working_temp_range();
        match find_working_temp_action(
            &temps,
            &range,
            &config.hp_circulation,
            CurrentHeatDirection::Falling,
            None, None,
        ) {
            Ok(WorkingTempAction::Cool { circulate: true }) => Ok(Intention::YieldHeatUps),
            Ok(WorkingTempAction::Cool { circulate: false }) => {
                info!("TKBT too cold, would be heating the tank. Ending circulation.");
                Ok(Intention::finish())
            }
            Ok(WorkingTempAction::Heat { .. }) => {
                info!("Reached bottom of working range, ending circulation.");
                Ok(Intention::Finish)
            }
            Err(missing_sensor) => {
                error!(
                    "Could not check whether to circulate due to missing sensor: {} - turning off.",
                    missing_sensor
                );
                Ok(Intention::off_now())
            }
        }
    }
}