Mercurial > templog
comparison rust/src/fridge.rs @ 621:8136a6b99866 rust
make it compile again
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sat, 15 Apr 2017 23:39:23 +0800 |
parents | 8fda564cc46f |
children | efcbe0d3afd6 |
comparison
equal
deleted
inserted
replaced
620:8fda564cc46f | 621:8136a6b99866 |
---|---|
1 extern crate futures; | 1 extern crate futures; |
2 extern crate tokio_core; | 2 extern crate tokio_core; |
3 #[cfg(linux)] | |
3 extern crate sysfs_gpio; | 4 extern crate sysfs_gpio; |
4 | 5 |
5 use std; | 6 use std; |
6 use std::io; | 7 use std::io; |
7 use std::mem; | 8 use std::mem; |
9 use std::time::{Duration,Instant}; | 10 use std::time::{Duration,Instant}; |
10 | 11 |
11 use futures::{Future,future,Sink,Stream}; | 12 use futures::{Future,future,Sink,Stream}; |
12 use tokio_core::reactor::{Timeout,Handle}; | 13 use tokio_core::reactor::{Timeout,Handle}; |
13 use futures::sync::{mpsc}; | 14 use futures::sync::{mpsc}; |
15 | |
16 #[cfg(target_os = "linux")] | |
14 use sysfs_gpio::{Direction, Pin}; | 17 use sysfs_gpio::{Direction, Pin}; |
15 | 18 |
16 use config::Config; | 19 use config::Config; |
17 use params::Params; | 20 use params::Params; |
18 use types::*; | 21 use types::*; |
32 temp_wort: Option<f32>, | 35 temp_wort: Option<f32>, |
33 temp_fridge: Option<f32>, | 36 temp_fridge: Option<f32>, |
34 last_off_time: Instant, | 37 last_off_time: Instant, |
35 wort_valid_time: Instant, | 38 wort_valid_time: Instant, |
36 integrator: StepIntegrator, | 39 integrator: StepIntegrator, |
37 gpio: Pin, | 40 control: FridgeControl, |
38 | 41 |
39 // Timeouts to wake ourselves up again | 42 // Timeouts to wake ourselves up again |
40 handle: Handle, | 43 handle: Handle, |
41 timeout_s: mpsc::Sender<u64>, | 44 timeout_s: mpsc::Sender<u64>, |
42 timeout_r: Option<mpsc::Receiver<u64>>, | 45 timeout_r: Option<mpsc::Receiver<u64>>, |
57 fn poll_complete(&mut self) -> futures::Poll<(), Self::SinkError> { | 60 fn poll_complete(&mut self) -> futures::Poll<(), Self::SinkError> { |
58 Ok(futures::Async::Ready(())) | 61 Ok(futures::Async::Ready(())) |
59 } | 62 } |
60 } | 63 } |
61 | 64 |
65 enum FridgeControl { | |
66 #[cfg(target_os = "linux")] | |
67 Gpio(Pin), | |
68 Fake, | |
69 } | |
70 | |
71 struct TestControl {} | |
72 | |
62 impl Drop for Fridge { | 73 impl Drop for Fridge { |
63 fn drop(&mut self) { | 74 fn drop(&mut self) { |
64 // safety fridge off | 75 // safety fridge off |
65 self.gpio.set_state(0); | 76 self.turn(false); |
66 } | 77 } |
67 } | 78 } |
68 | 79 |
69 impl Fridge { | 80 impl Fridge { |
70 pub fn new(config: &Config, nowait: bool, p: Params, handle: &Handle) -> Fridge { | 81 pub fn new(config: &Config, nowait: bool, p: Params, handle: &Handle) -> Fridge { |
75 on: false, | 86 on: false, |
76 temp_wort: None, | 87 temp_wort: None, |
77 temp_fridge: None, | 88 temp_fridge: None, |
78 last_off_time: Instant::now(), | 89 last_off_time: Instant::now(), |
79 wort_valid_time: Instant::now() - Duration::new(config.FRIDGE_WORT_INVALID_TIME, 100), | 90 wort_valid_time: Instant::now() - Duration::new(config.FRIDGE_WORT_INVALID_TIME, 100), |
80 integrator: StepIntegrator::new(p.overshoot_delay), | 91 integrator: StepIntegrator::new(Duration::new(p.overshoot_delay, 0)), |
81 gpio: Pin::new(config.FRIDGE_GPIO_PIN), | 92 control: Self::make_control(config), |
82 | 93 |
83 handle: handle.clone(), | 94 handle: handle.clone(), |
84 timeout_s: s, | 95 timeout_s: s, |
85 timeout_r: Some(r), | 96 timeout_r: Some(r), |
86 ticker: 0, | 97 ticker: 0, |
88 | 99 |
89 if nowait { | 100 if nowait { |
90 f.last_off_time -= Duration::new(config.FRIDGE_DELAY, 1); | 101 f.last_off_time -= Duration::new(config.FRIDGE_DELAY, 1); |
91 } | 102 } |
92 | 103 |
104 f.tick(); | |
105 | |
106 f | |
107 } | |
108 | |
109 #[cfg(target_os = "linux")] | |
110 fn make_control(config: &Config) -> FridgeControl { | |
111 let mut pin = Pin(config.FRIDGE_GPIO_PIN); | |
93 // XXX better error handling? | 112 // XXX better error handling? |
94 f.gpio.export().expect("Exporting fridge gpio failed"); | 113 pin.export().expect("Exporting fridge gpio failed"); |
95 f.gpio.set_direction(Direction::Low).expect("Fridge gpio direction failed"); | 114 pin.set_direction(Direction::Low).expect("Fridge gpio direction failed"); |
96 | 115 FridgeControl::Gpio(pin) |
97 f.tick(); | 116 } |
98 | 117 |
99 f | 118 #[cfg(not(target_os = "linux"))] |
100 } | 119 fn make_control(config: &Config) -> FridgeControl { |
120 FridgeControl::Fake | |
121 } | |
122 | |
123 | |
101 | 124 |
102 fn next_wakeup(&self) -> Duration { | 125 fn next_wakeup(&self) -> Duration { |
103 let millis = 400; | 126 let millis = 400; |
104 let dur = Duration::from_millis(millis); | 127 let dur = Duration::from_millis(millis); |
105 dur | 128 dur |
121 .map_err(|e| TemplogError::new("wakeups() receive failed")) | 144 .map_err(|e| TemplogError::new("wakeups() receive failed")) |
122 .boxed() | 145 .boxed() |
123 } | 146 } |
124 | 147 |
125 fn turn_off(&mut self) { | 148 fn turn_off(&mut self) { |
126 log!("Turning fridge off"); | 149 info!("Turning fridge off"); |
127 self.turn(false); | 150 self.turn(false); |
128 } | 151 } |
129 | 152 |
130 fn turn_on(&mut self) { | 153 fn turn_on(&mut self) { |
131 log!("Turning fridge on"); | 154 info!("Turning fridge on"); |
132 self.turn(true); | 155 self.turn(true); |
133 } | 156 } |
134 | 157 |
135 fn turn(&mut self, on: bool) { | 158 fn turn(&mut self, on: bool) { |
159 match self.control { | |
160 #[cfg(target_os = "linux")] | |
161 Gpio(pin) => pin.set_value(on as u8), | |
162 FridgeControl::Fake => debug!("fridge turns {}", if on {"on"} else {"off"}), | |
163 } | |
136 self.on = on; | 164 self.on = on; |
137 self.gpio.set_value(on as u8) | |
138 } | 165 } |
139 | 166 |
140 /// Turns the fridge off and on | 167 /// Turns the fridge off and on |
141 fn compare_temperatures(&mut self) { | 168 fn compare_temperatures(&mut self) { |
142 let fridge_min = self.params.fridge_setpoint - self.params.fridge_range_lower; | 169 let fridge_min = self.params.fridge_setpoint - self.params.fridge_range_lower; |
143 let fridge_max = self.params.fridge_setpoint - self.params.fridge_range_upper; | 170 let fridge_max = self.params.fridge_setpoint - self.params.fridge_range_upper; |
144 let wort_max = self.params.fridge_setpoint + self.params.fridge_difference; | 171 let wort_max = self.params.fridge_setpoint + self.params.fridge_difference; |
145 let off_time = Instant::now() - self.last_off_time; | 172 let off_time = Instant::now() - self.last_off_time; |
146 | 173 |
147 // Or elsewhere? | 174 // Or elsewhere? |
148 self.integrator.set_limit(self.params.overshoot_delay); | 175 self.integrator.set_limit(Duration::new(self.params.overshoot_delay, 0)); |
149 | 176 |
150 // Safety to avoid bad things happening to the fridge motor (?) | 177 // Safety to avoid bad things happening to the fridge motor (?) |
151 // When it turns off don't start up again for at least FRIDGE_DELAY | 178 // When it turns off don't start up again for at least FRIDGE_DELAY |
152 if !self.on && off_time < self.config.FRIDGE_DELAY { | 179 if !self.on && off_time < Duration::new(self.config.FRIDGE_DELAY, 0) { |
153 log!("fridge skipping, too early"); | 180 info!("fridge skipping, too early"); |
154 return; | 181 return; |
155 } | 182 } |
156 | 183 |
157 if self.params.disabled { | 184 if self.params.disabled { |
158 if self.on { | 185 if self.on { |
159 log!("Disabled, turning fridge off"); | 186 info!("Disabled, turning fridge off"); |
160 self.turn_off(); | 187 self.turn_off(); |
161 } | 188 } |
162 return; | 189 return; |
163 } | 190 } |
164 | 191 |
165 // handle broken wort sensor | 192 // handle broken wort sensor |
166 if self.temp_wort.is_none() { | 193 if self.temp_wort.is_none() { |
167 let invalid_time = Instant::now() - self.wort_valid_time; | 194 let invalid_time = Instant::now() - self.wort_valid_time; |
168 warn!("Invalid wort sensor for {:?} secs", invalid_time); | 195 warn!("Invalid wort sensor for {:?} secs", invalid_time); |
169 if invalid_time < self.config.FRIDGE_WORT_INVALID_TIME { | 196 if invalid_time < Duration::new(self.config.FRIDGE_WORT_INVALID_TIME, 0) { |
170 warn!("Has only been invalid for {:?}, waiting", invalid_time); | 197 warn!("Has only been invalid for {:?}, waiting", invalid_time); |
171 return; | 198 return; |
172 } | 199 } |
173 } | 200 } |
174 | 201 |
177 } | 204 } |
178 | 205 |
179 if self.on { | 206 if self.on { |
180 debug!("fridge is on"); | 207 debug!("fridge is on"); |
181 let on_time = self.integrator.integrate().as_secs() as f32; | 208 let on_time = self.integrator.integrate().as_secs() as f32; |
182 let on_ratio = on_time / params.overshoot_delay as f32; | 209 let on_ratio = on_time / self.params.overshoot_delay as f32; |
183 | 210 |
184 overshoot = params.overshoot_factor as f32 * on_ratio; | 211 let overshoot = self.params.overshoot_factor as f32 * on_ratio; |
185 debug!("on_time {}, overshoot {}", on_percent, overshoot); | 212 debug!("on_percent {}, overshoot {}", on_ratio * 100.0, overshoot); |
186 | 213 |
187 let mut turn_off = false; | 214 let mut turn_off = false; |
188 if let Some(t) = self.temp_wort && !params.nowort { | 215 if self.temp_wort.is_some() && !self.params.nowort { |
216 let t = self.temp_wort.unwrap(); | |
189 // use the wort temperature | 217 // use the wort temperature |
190 if t - overshoot < params.fridge_setpoint { | 218 if t - overshoot < self.params.fridge_setpoint { |
191 log!("wort has cooled enough, {temp}º (overshoot {overshoot}º = {factor} × {percent}%)", | 219 info!("wort has cooled enough, {temp}º (overshoot {overshoot}º = {factor} × {percent}%)", |
192 temp = t, overshoot = overshoot, | 220 temp = t, overshoot = overshoot, |
193 factor = params.overshoot_factor, | 221 factor = self.params.overshoot_factor, |
194 percent = on_ratio*100); | 222 percent = on_ratio*100.0); |
195 turn_off = true; | 223 turn_off = true; |
196 } | 224 } |
197 } else let if Some(t) = self.temp_fridge { | 225 } else if let Some(t) = self.temp_fridge { |
198 // use the fridge temperature | 226 // use the fridge temperature |
199 if t < fridge_min { | 227 if t < fridge_min { |
200 warn!("fridge off fallback, fridge {}, min {}", t, fridge_min); | 228 warn!("fridge off fallback, fridge {}, min {}", t, fridge_min); |
201 if self.temp_wort.is_none() { | 229 if self.temp_wort.is_none() { |
202 W("wort has been invalid for {:?}", Instant::now() - self.wort_valid_time); | 230 warn!("wort has been invalid for {:?}", Instant::now() - self.wort_valid_time); |
203 } | 231 } |
204 turn_off = true; | 232 turn_off = true; |
205 } | 233 } |
206 } | 234 } |
207 if turn_off { | 235 if turn_off { |
209 } | 237 } |
210 } else { | 238 } else { |
211 debug!("fridge is off. fridge {:?} max {:?}. wort {:?} max {:?}", | 239 debug!("fridge is off. fridge {:?} max {:?}. wort {:?} max {:?}", |
212 self.temp_fridge, fridge_max, self.temp_wort, wort_max); | 240 self.temp_fridge, fridge_max, self.temp_wort, wort_max); |
213 let mut turn_on = false; | 241 let mut turn_on = false; |
214 if let Some(t) = self.temp_wort && !params.nowort { | 242 if self.temp_wort.is_some() && !self.params.nowort { |
215 // use the wort temperature | 243 // use the wort temperature |
244 let t = self.temp_wort.unwrap(); | |
216 if t >= wort_max { | 245 if t >= wort_max { |
217 log!("Wort is too hot {}°, max {}°", t, wort_max); | 246 info!("Wort is too hot {}°, max {}°", t, wort_max); |
218 turn_on = true; | 247 turn_on = true; |
219 } | 248 } |
220 } | 249 } |
221 | 250 |
222 if let Some(t) = self.temp_fridge { | 251 if let Some(t) = self.temp_fridge { |
223 if t >= fridge_max { | 252 if t >= fridge_max { |
224 warn!("fridge too hot fallback, fridge {}°, max {}°", t, fridge_max) | 253 warn!("fridge too hot fallback, fridge {}°, max {}°", t, fridge_max); |
225 turn_on = true; | 254 turn_on = true; |
226 } | 255 } |
227 } | 256 } |
228 | 257 |
229 if turn_on { | 258 if turn_on { |
235 /// Must be called after every state change. Turns the fridge on/off as required and | 264 /// Must be called after every state change. Turns the fridge on/off as required and |
236 /// schedules any future wakeups based on the present (new) state | 265 /// schedules any future wakeups based on the present (new) state |
237 fn tick(&mut self) { | 266 fn tick(&mut self) { |
238 debug!("tick"); | 267 debug!("tick"); |
239 | 268 |
240 self.compare_temperatures() | 269 self.compare_temperatures(); |
241 self.send_next_timeout(); | 270 self.send_next_timeout(); |
242 } | 271 } |
243 | 272 |
244 /// Sets the next self-wakeup timeout | 273 /// Sets the next self-wakeup timeout |
245 fn send_next_timeout(&mut self) { | 274 fn send_next_timeout(&mut self) { |