Mercurial > templog
annotate rust/src/fridge.rs @ 634:a5721c02d3ee rust
build succeeds
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sun, 22 Sep 2019 20:35:40 +0800 |
parents | 490e9e15b98c |
children | 4424a8b30f9c |
rev | line source |
---|---|
634 | 1 // TODO: |
2 // - riker | |
3 // - use monotonic clock | |
4 // - timer.rs should use rx.recv_timeout(next_time) instead of rx.try_recv() | |
5 // and then could remove cfg.frequency_millis | |
632
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
6 use std; |
594
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
7 |
597 | 8 use std::time::{Duration,Instant}; |
632
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
9 use riker::actors::*; |
621 | 10 |
11 #[cfg(target_os = "linux")] | |
626 | 12 use self::sysfs_gpio::{Direction, Pin}; |
593
bf138339d20a
fiddling with timeouts and closures
Matt Johnston <matt@ucc.asn.au>
parents:
592
diff
changeset
|
13 |
632
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
14 use super::config::Config; |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
15 use super::params::Params; |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
16 use super::types::*; |
592 | 17 |
634 | 18 #[derive(Debug,Clone)] |
632
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
19 pub struct Tick; |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
20 |
633 | 21 #[actor(Params, Tick, Readings)] |
593
bf138339d20a
fiddling with timeouts and closures
Matt Johnston <matt@ucc.asn.au>
parents:
592
diff
changeset
|
22 pub struct Fridge { |
bf138339d20a
fiddling with timeouts and closures
Matt Johnston <matt@ucc.asn.au>
parents:
592
diff
changeset
|
23 params: Params, |
603
b45b8b4cf0f5
get rid of lazy_static, config is passed around
Matt Johnston <matt@ucc.asn.au>
parents:
601
diff
changeset
|
24 config: Config, |
620 | 25 |
26 on: bool, | |
593
bf138339d20a
fiddling with timeouts and closures
Matt Johnston <matt@ucc.asn.au>
parents:
592
diff
changeset
|
27 temp_wort: Option<f32>, |
bf138339d20a
fiddling with timeouts and closures
Matt Johnston <matt@ucc.asn.au>
parents:
592
diff
changeset
|
28 temp_fridge: Option<f32>, |
620 | 29 last_off_time: Instant, |
30 wort_valid_time: Instant, | |
31 integrator: StepIntegrator, | |
621 | 32 control: FridgeControl, |
632
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
33 } |
593
bf138339d20a
fiddling with timeouts and closures
Matt Johnston <matt@ucc.asn.au>
parents:
592
diff
changeset
|
34 |
632
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
35 impl Actor for Fridge { |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
36 type Msg = FridgeMsg; |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
37 fn recv(&mut self, |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
38 ctx: &Context<Self::Msg>, |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
39 msg: Self::Msg, |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
40 sender: Sender) { |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
41 self.receive(ctx, msg, sender); |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
42 // TODO: should we do self.tick(ctx) here instead? |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
43 } |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
44 |
634 | 45 fn pre_start(&mut self, ctx: &Context<Self::Msg>) { |
46 let chan: ChannelRef<Readings> = channel("readings", &ctx.system).unwrap(); | |
633 | 47 let sub = Box::new(ctx.myself()); |
48 chan.tell(Subscribe {actor: sub, topic: "readings".into()}, None); | |
49 | |
634 | 50 let chan: ChannelRef<Params> = channel("params", &ctx.system).unwrap(); |
633 | 51 let sub = Box::new(ctx.myself()); |
52 chan.tell(Subscribe {actor: sub, topic: "params".into()}, None); | |
634 | 53 |
54 self.tick(ctx); | |
632
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
55 } |
594
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
56 } |
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
57 |
633 | 58 impl Receive<Readings> for Fridge { |
632
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
59 type Msg = FridgeMsg; |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
60 fn receive(&mut self, |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
61 ctx: &Context<Self::Msg>, |
633 | 62 r: Readings, |
632
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
63 _sender: Sender) { |
634 | 64 self.temp_wort = r.get_temp(&self.config.WORT_NAME); |
65 self.temp_fridge = r.get_temp(&self.config.FRIDGE_NAME); | |
594
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
66 |
632
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
67 if self.temp_wort.is_some() { |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
68 self.wort_valid_time = Instant::now(); |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
69 } |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
70 |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
71 self.tick(ctx); |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
72 } |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
73 } |
594
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
74 |
632
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
75 impl Receive<Params> for Fridge { |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
76 type Msg = FridgeMsg; |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
77 fn receive(&mut self, |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
78 ctx: &Context<Self::Msg>, |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
79 p: Params, |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
80 _sender: Sender) { |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
81 self.params = p; |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
82 println!("fridge set_params {:?}", self.params); |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
83 |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
84 self.tick(ctx); |
594
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
85 } |
632
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
86 } |
594
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
87 |
632
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
88 impl Receive<Tick> for Fridge { |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
89 type Msg = FridgeMsg; |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
90 fn receive(&mut self, |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
91 ctx: &Context<Self::Msg>, |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
92 _tick: Tick, |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
93 _sender: Sender) { |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
94 self.tick(ctx); |
594
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
95 } |
592 | 96 } |
97 | |
621 | 98 enum FridgeControl { |
99 #[cfg(target_os = "linux")] | |
100 Gpio(Pin), | |
101 Fake, | |
102 } | |
103 | |
620 | 104 impl Drop for Fridge { |
105 fn drop(&mut self) { | |
106 // safety fridge off | |
621 | 107 self.turn(false); |
620 | 108 } |
109 } | |
110 | |
593
bf138339d20a
fiddling with timeouts and closures
Matt Johnston <matt@ucc.asn.au>
parents:
592
diff
changeset
|
111 impl Fridge { |
634 | 112 pub fn new_actor((config, nowait) : (Config, bool)) -> Fridge { |
113 Self::new(config, nowait) | |
114 | |
115 } | |
116 pub fn new(config: Config, nowait: bool) -> Fridge { | |
594
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
117 let mut f = Fridge { |
603
b45b8b4cf0f5
get rid of lazy_static, config is passed around
Matt Johnston <matt@ucc.asn.au>
parents:
601
diff
changeset
|
118 config: config.clone(), |
634 | 119 params: Params::defaults(), |
620 | 120 on: false, |
593
bf138339d20a
fiddling with timeouts and closures
Matt Johnston <matt@ucc.asn.au>
parents:
592
diff
changeset
|
121 temp_wort: None, |
bf138339d20a
fiddling with timeouts and closures
Matt Johnston <matt@ucc.asn.au>
parents:
592
diff
changeset
|
122 temp_fridge: None, |
620 | 123 last_off_time: Instant::now(), |
124 wort_valid_time: Instant::now() - Duration::new(config.FRIDGE_WORT_INVALID_TIME, 100), | |
634 | 125 integrator: StepIntegrator::new(Duration::new(1, 0)), |
126 control: Self::make_control(&config), | |
594
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
127 }; |
620 | 128 |
597 | 129 if nowait { |
609
7bda01659426
not building, paramwaiter work
Matt Johnston <matt@ucc.asn.au>
parents:
606
diff
changeset
|
130 f.last_off_time -= Duration::new(config.FRIDGE_DELAY, 1); |
597 | 131 } |
620 | 132 |
594
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
133 f |
593
bf138339d20a
fiddling with timeouts and closures
Matt Johnston <matt@ucc.asn.au>
parents:
592
diff
changeset
|
134 } |
bf138339d20a
fiddling with timeouts and closures
Matt Johnston <matt@ucc.asn.au>
parents:
592
diff
changeset
|
135 |
621 | 136 #[cfg(target_os = "linux")] |
137 fn make_control(config: &Config) -> FridgeControl { | |
138 let mut pin = Pin(config.FRIDGE_GPIO_PIN); | |
139 // XXX better error handling? | |
140 pin.export().expect("Exporting fridge gpio failed"); | |
141 pin.set_direction(Direction::Low).expect("Fridge gpio direction failed"); | |
142 FridgeControl::Gpio(pin) | |
143 } | |
144 | |
145 #[cfg(not(target_os = "linux"))] | |
634 | 146 fn make_control(_config: &Config) -> FridgeControl { |
621 | 147 FridgeControl::Fake |
148 } | |
149 | |
594
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
150 fn next_wakeup(&self) -> Duration { |
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
151 let millis = 400; |
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
152 let dur = Duration::from_millis(millis); |
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
153 dur |
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
154 } |
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
155 |
606 | 156 |
620 | 157 fn turn_off(&mut self) { |
621 | 158 info!("Turning fridge off"); |
620 | 159 self.turn(false); |
160 } | |
161 | |
162 fn turn_on(&mut self) { | |
621 | 163 info!("Turning fridge on"); |
620 | 164 self.turn(true); |
165 } | |
166 | |
167 fn turn(&mut self, on: bool) { | |
621 | 168 match self.control { |
169 #[cfg(target_os = "linux")] | |
170 Gpio(pin) => pin.set_value(on as u8), | |
171 FridgeControl::Fake => debug!("fridge turns {}", if on {"on"} else {"off"}), | |
172 } | |
620 | 173 self.on = on; |
174 } | |
175 | |
632
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
176 // Turns the fridge off and on |
620 | 177 fn compare_temperatures(&mut self) { |
178 let fridge_min = self.params.fridge_setpoint - self.params.fridge_range_lower; | |
179 let fridge_max = self.params.fridge_setpoint - self.params.fridge_range_upper; | |
180 let wort_max = self.params.fridge_setpoint + self.params.fridge_difference; | |
181 let off_time = Instant::now() - self.last_off_time; | |
182 | |
183 // Or elsewhere? | |
621 | 184 self.integrator.set_limit(Duration::new(self.params.overshoot_delay, 0)); |
620 | 185 |
186 // Safety to avoid bad things happening to the fridge motor (?) | |
187 // When it turns off don't start up again for at least FRIDGE_DELAY | |
621 | 188 if !self.on && off_time < Duration::new(self.config.FRIDGE_DELAY, 0) { |
189 info!("fridge skipping, too early"); | |
620 | 190 return; |
191 } | |
192 | |
193 if self.params.disabled { | |
194 if self.on { | |
621 | 195 info!("Disabled, turning fridge off"); |
620 | 196 self.turn_off(); |
197 } | |
198 return; | |
199 } | |
200 | |
201 // handle broken wort sensor | |
202 if self.temp_wort.is_none() { | |
203 let invalid_time = Instant::now() - self.wort_valid_time; | |
204 warn!("Invalid wort sensor for {:?} secs", invalid_time); | |
621 | 205 if invalid_time < Duration::new(self.config.FRIDGE_WORT_INVALID_TIME, 0) { |
620 | 206 warn!("Has only been invalid for {:?}, waiting", invalid_time); |
207 return; | |
208 } | |
209 } | |
210 | |
211 if self.temp_fridge.is_none() { | |
212 warn!("Invalid fridge sensor"); | |
213 } | |
214 | |
215 if self.on { | |
216 debug!("fridge is on"); | |
217 let on_time = self.integrator.integrate().as_secs() as f32; | |
621 | 218 let on_ratio = on_time / self.params.overshoot_delay as f32; |
620 | 219 |
621 | 220 let overshoot = self.params.overshoot_factor as f32 * on_ratio; |
221 debug!("on_percent {}, overshoot {}", on_ratio * 100.0, overshoot); | |
620 | 222 |
223 let mut turn_off = false; | |
621 | 224 if self.temp_wort.is_some() && !self.params.nowort { |
225 let t = self.temp_wort.unwrap(); | |
620 | 226 // use the wort temperature |
621 | 227 if t - overshoot < self.params.fridge_setpoint { |
228 info!("wort has cooled enough, {temp}º (overshoot {overshoot}º = {factor} × {percent}%)", | |
620 | 229 temp = t, overshoot = overshoot, |
621 | 230 factor = self.params.overshoot_factor, |
231 percent = on_ratio*100.0); | |
620 | 232 turn_off = true; |
233 } | |
621 | 234 } else if let Some(t) = self.temp_fridge { |
620 | 235 // use the fridge temperature |
236 if t < fridge_min { | |
237 warn!("fridge off fallback, fridge {}, min {}", t, fridge_min); | |
238 if self.temp_wort.is_none() { | |
621 | 239 warn!("wort has been invalid for {:?}", Instant::now() - self.wort_valid_time); |
620 | 240 } |
241 turn_off = true; | |
242 } | |
243 } | |
244 if turn_off { | |
245 self.turn_off(); | |
246 } | |
247 } else { | |
248 debug!("fridge is off. fridge {:?} max {:?}. wort {:?} max {:?}", | |
249 self.temp_fridge, fridge_max, self.temp_wort, wort_max); | |
250 let mut turn_on = false; | |
621 | 251 if self.temp_wort.is_some() && !self.params.nowort { |
620 | 252 // use the wort temperature |
621 | 253 let t = self.temp_wort.unwrap(); |
620 | 254 if t >= wort_max { |
621 | 255 info!("Wort is too hot {}°, max {}°", t, wort_max); |
620 | 256 turn_on = true; |
257 } | |
258 } | |
259 | |
260 if let Some(t) = self.temp_fridge { | |
261 if t >= fridge_max { | |
621 | 262 warn!("fridge too hot fallback, fridge {}°, max {}°", t, fridge_max); |
620 | 263 turn_on = true; |
264 } | |
265 } | |
266 | |
267 if turn_on { | |
268 self.turn_on() | |
269 } | |
270 } | |
271 } | |
272 | |
606 | 273 /// Must be called after every state change. Turns the fridge on/off as required and |
274 /// schedules any future wakeups based on the present (new) state | |
632
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
275 /// Examples of wakeups events are |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
276 /// |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
277 /// * overshoot calculation |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
278 /// * minimum fridge-off time |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
279 /// * invalid wort timeout |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
280 /// All specified in next_wakeup() |
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
281 fn tick(&mut self, |
633 | 282 ctx: &Context<<Self as Actor>::Msg>) { |
594
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
283 debug!("tick"); |
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
284 |
621 | 285 self.compare_temperatures(); |
592 | 286 |
632
bde302def78e
moving to riker, nowhere near yet
Matt Johnston <matt@ucc.asn.au>
parents:
631
diff
changeset
|
287 // Sets the next self-wakeup timeout |
594
aff50ee77252
rust working better now with streams and sinks.
Matt Johnston <matt@ucc.asn.au>
parents:
593
diff
changeset
|
288 let dur = self.next_wakeup(); |
634 | 289 ctx.schedule_once(dur, ctx.myself(), None, Tick); |
593
bf138339d20a
fiddling with timeouts and closures
Matt Johnston <matt@ucc.asn.au>
parents:
592
diff
changeset
|
290 } |
592 | 291 } |