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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use crate::brain::python_like::control::heating_control::HeatPumpMode;
use crate::brain::BrainFailure;
use crate::python_like::control::heating_control::{HeatCirculationPumpControl, HeatPumpControl};
use crate::python_like::control::misc_control::WiserPowerControl;
use crate::{HeatingControl, ImmersionHeaterControl, MiscControls};
use chrono::{DateTime, Utc};
use log::debug;
use std::sync::mpsc;
use std::sync::mpsc::{Receiver, Sender, TryRecvError};
use std::time::Duration;

pub trait DummyIO {
    type MessageType;
    type Config;

    fn create(config: &Self::Config) -> (Self, Sender<Self::MessageType>)
    where
        Self: Sized,
    {
        let (sender, receiver) = mpsc::channel();
        let dummy_obj = Self::new(receiver, &config);
        return (dummy_obj, sender);
    }

    fn new(receiver: Receiver<Self::MessageType>, config: &Self::Config) -> Self;
}

pub fn read_all<T, F>(receiver: &Receiver<T>, on_value: F)
where
    F: Fn(T),
{
    loop {
        match receiver.try_recv() {
            Ok(x) => on_value(x),
            Err(TryRecvError::Empty) => break,
            Err(TryRecvError::Disconnected) => panic!("Disconnected!"),
        }
    }
}

pub struct DummyAllOutputs {
    heat_pump_mode: HeatPumpMode,
    heat_circulation_pump: bool,
    immersion_heater_on: bool,
    wiser_power_on: bool,

    heat_pump_last_changed: DateTime<Utc>,
}

impl Default for DummyAllOutputs {
    fn default() -> Self {
        Self {
            heat_pump_mode: HeatPumpMode::Off,
            heat_circulation_pump: false,
            immersion_heater_on: false,
            wiser_power_on: true,
            heat_pump_last_changed: Utc::now(),
        }
    }
}

fn to_on_off(on: bool) -> String {
    String::from(match on {
        true => "On",
        false => "Off",
    })
}

impl HeatPumpControl for DummyAllOutputs {
    fn try_set_heat_pump(&mut self, mode: HeatPumpMode) -> Result<(), BrainFailure> {
        debug!("Set HP to {:?}", mode);
        if mode.is_hp_on() != self.heat_pump_mode.is_hp_on() {
            self.heat_pump_last_changed = Utc::now();
        }
        self.heat_pump_mode = mode;
        Ok(())
    }

    fn try_get_heat_pump(&self) -> Result<HeatPumpMode, BrainFailure> {
        Ok(self.heat_pump_mode.clone())
    }

    fn get_heat_pump_on_with_time(&self) -> Result<(bool, Duration), BrainFailure> {
        Ok((self.heat_pump_mode.is_hp_on(), (Utc::now() - self.heat_pump_last_changed).to_std().expect("Time travelling")))
    }
}

impl HeatCirculationPumpControl for DummyAllOutputs {
    fn try_set_heat_circulation_pump(&mut self, on: bool) -> Result<(), BrainFailure> {
        debug!("Set CP to {}", to_on_off(on));
        self.heat_circulation_pump = on;
        Ok(())
    }

    fn try_get_heat_circulation_pump(&self) -> Result<bool, BrainFailure> {
        Ok(self.heat_circulation_pump)
    }
}

impl HeatingControl for DummyAllOutputs {
    fn as_hp(&mut self) -> &mut dyn HeatPumpControl {
        self
    }

    fn as_cp(&mut self) -> &mut dyn HeatCirculationPumpControl {
        self
    }
}

impl ImmersionHeaterControl for DummyAllOutputs {
    fn try_set_immersion_heater(&mut self, on: bool) -> Result<(), BrainFailure> {
        debug!("Set immersion heater to {}", to_on_off(on));
        self.immersion_heater_on = on;
        Ok(())
    }

    fn try_get_immersion_heater(&self) -> Result<bool, BrainFailure> {
        Ok(self.immersion_heater_on)
    }
}

impl WiserPowerControl for DummyAllOutputs {
    fn try_set_wiser_power(&mut self, on: bool) -> Result<(), BrainFailure> {
        debug!("Turned wiser power {}", to_on_off(on));
        self.wiser_power_on = on;
        Ok(())
    }

    fn try_get_wiser_power(&mut self) -> Result<bool, BrainFailure> {
        Ok(self.wiser_power_on)
    }
}

impl MiscControls for DummyAllOutputs {
    fn as_ih(&mut self) -> &mut dyn ImmersionHeaterControl {
        self
    }

    fn as_wp(&mut self) -> &mut dyn WiserPowerControl {
        self
    }
}