Nareshkumar Rao 7 months ago
parent
commit
771f81a9f6
  1. 6
      growpi.toml
  2. 73
      html/growpi/src/App.vue
  3. 7
      html/growpi/src/main.js
  4. 15
      src/config.rs
  5. 25
      src/control.rs

6
growpi.toml

@ -28,3 +28,9 @@ resistor = "R2"
[water_pump_settings] [water_pump_settings]
grams_per_millisecond = 0.05280999839305878 grams_per_millisecond = 0.05280999839305878
[controller_settings]
temperature_set_point_upper = 35.0
temperature_set_point_lower = 28.0
temperature_loop_mins = 60
soil_loop_hours = 12

73
html/growpi/src/App.vue

@ -1,5 +1,6 @@
<script> <script>
import Button from 'primevue/button'; import Button from 'primevue/button';
import InputNumber from 'primevue/inputnumber';
import ToggleButton from 'primevue/togglebutton'; import ToggleButton from 'primevue/togglebutton';
export default { export default {
data() { data() {
@ -10,9 +11,10 @@ export default {
water_state: false, water_state: false,
water_primed: false, water_primed: false,
fan_state: false, fan_state: false,
pumpAmount: 150,
}; };
}, },
components: { ToggleButton, Button },
components: { ToggleButton, Button, InputNumber },
methods: { methods: {
async updateInfo() { async updateInfo() {
let info = await receiveInfo(); let info = await receiveInfo();
@ -21,15 +23,20 @@ export default {
this.pump_state = to_bool(info.pump_state); this.pump_state = to_bool(info.pump_state);
this.temperature = info.temperature; this.temperature = info.temperature;
this.soil_moisture = info.soil_moisture; this.soil_moisture = info.soil_moisture;
console.log(info);
}, },
async sendSwitch(name, state) { async sendSwitch(name, state) {
await fetch("http://192.168.0.107:2205/switch/" + name + "/" + to_state(state)); await fetch("http://192.168.0.107:2205/switch/" + name + "/" + to_state(state));
await this.updateInfo(); await this.updateInfo();
},
async pumpWater() {
console.log("Pumping: " + this.pumpAmount);
await fetch("http://192.168.0.107:2205/pump/" + this.pumpAmount);
await this.updateInfo();
} }
}, },
created() { created() {
setTimeout(this.updateInfo, 1000);
this.updateInfo();
setInterval(this.updateInfo, 1000);
} }
} }
@ -60,29 +67,75 @@ function to_bool(state) {
</script> </script>
<template> <template>
<h1>GrowPi!</h1> <h1>GrowPi!</h1>
<table>
<table class="main-table">
<tr>
<td>Temperature</td>
<td>
{{ Math.round(temperature * 100) / 100 }}°C
</td>
</tr>
<tr>
<td>Soil Moisture</td>
<td>
{{ Math.round(soil_moisture * 1000) / 10 }}%
</td>
</tr>
<tr> <tr>
<td>Lights</td> <td>Lights</td>
<td> <td>
<ToggleButton :modelValue="light_state" something="hi" @change="sendSwitch('lights', !light_state)" onLabel="On"
offLabel="Off" />
<ToggleButton class="whole-cell" :modelValue="light_state" something="hi"
@change="sendSwitch('lights', !light_state)" onLabel="On" offLabel="Off" />
</td> </td>
</tr> </tr>
<tr> <tr>
<td>Fan</td> <td>Fan</td>
<td> <td>
<ToggleButton :modelValue="fan_state" @change="sendSwitch('fan', !fan_state)" onLabel="On" offLabel="Off" />
<ToggleButton class="whole-cell" :modelValue="fan_state" @change="sendSwitch('fan', !fan_state)" onLabel="On"
offLabel="Off" />
</td> </td>
</tr> </tr>
<tr> <tr>
<td>Pump</td> <td>Pump</td>
<td> <td>
<div class="whole-cell">
<ToggleButton v-model="water_primed" onLabel="Ready" offLabel="Click to Prime" /> <ToggleButton v-model="water_primed" onLabel="Ready" offLabel="Click to Prime" />
<Button @change="sendSwitch('pump', !water_state); water_primed = false;" :disabled="!water_primed"
<Button @click="pumpWater(); water_primed = false;" :disabled="!water_primed && !water_state"
label="Pump Water" /> label="Pump Water" />
{{ water_state ? "Pump active" : "Pump inactive" }}
</div>
<br /><br />
<InputNumber class="whole-cell" v-model="pumpAmount" :allowEmpty="false" inputId="integeronly" suffix=" grams"
:min="100" :max="300" />
</td> </td>
</tr> </tr>
</table> </table>
</template> </template>
<style></style>
<style>
html,
body {
height: 100%;
}
html {
display: table;
margin: auto;
}
body {
display: table-cell;
vertical-align: middle;
}
.main-table {
border-collapse: collapse;
}
.main-table td {
border-style: solid;
padding: 1em;
border-width: 1px;
}
.whole-cell {
width: 100%;
}
</style>

7
html/growpi/src/main.js

@ -1,9 +1,10 @@
import 'primevue/resources/themes/aura-light-green/theme.css'
import 'primevue/resources/themes/aura-dark-green/theme.css'
import { createApp } from 'vue' import { createApp } from 'vue'
import PrimeVue from 'primevue/config' import PrimeVue from 'primevue/config'
import App from './App.vue' import App from './App.vue'
createApp(App).mount('#app')
App.use(PrimeVue)
const app = createApp(App)
app.use(PrimeVue)
app.mount('#app')

15
src/config.rs

@ -44,6 +44,14 @@ pub struct BoardSettings {
pub logic_level: f32, pub logic_level: f32,
} }
#[derive(Serialize, Deserialize)]
pub struct ControllerSettings {
pub temperature_set_point_upper: f32,
pub temperature_set_point_lower: f32,
pub temperature_loop_mins: u64,
pub soil_loop_hours: u64,
}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Configuration { pub struct Configuration {
pub board_settings: BoardSettings, pub board_settings: BoardSettings,
@ -51,6 +59,7 @@ pub struct Configuration {
pub soil_moisture_settings: SoilMoistureSettings, pub soil_moisture_settings: SoilMoistureSettings,
pub thermistor_settings: ThermistorSettings, pub thermistor_settings: ThermistorSettings,
pub water_pump_settings: WaterPumpSettings, pub water_pump_settings: WaterPumpSettings,
pub controller_settings: ControllerSettings,
} }
impl Configuration { impl Configuration {
@ -93,6 +102,12 @@ impl Default for Configuration {
water_pump_settings: WaterPumpSettings { water_pump_settings: WaterPumpSettings {
grams_per_millisecond: 0.05281, grams_per_millisecond: 0.05281,
}, },
controller_settings: ControllerSettings {
temperature_set_point_upper: 35.,
temperature_set_point_lower: 28.,
temperature_loop_mins: 60,
soil_loop_hours: 12,
},
} }
} }
} }

25
src/control.rs

@ -12,24 +12,41 @@ use crate::{
async fn temperature_control(program_state: ProgramStateShared) -> GenericResult<()> { async fn temperature_control(program_state: ProgramStateShared) -> GenericResult<()> {
let mut program_state = program_state.lock().map_err(lock_err)?; let mut program_state = program_state.lock().map_err(lock_err)?;
let config = &program_state.config.controller_settings;
let current_temperature = sensors::get_temperature(&program_state.config)?; let current_temperature = sensors::get_temperature(&program_state.config)?;
if current_temperature > 28. {
if current_temperature > config.temperature_set_point_upper {
actuators::switch_fan(crate::io::RelaySwitchState::On, &mut program_state)?; actuators::switch_fan(crate::io::RelaySwitchState::On, &mut program_state)?;
} else {
} else if current_temperature < config.temperature_set_point_lower {
actuators::switch_fan(crate::io::RelaySwitchState::Off, &mut program_state)?; actuators::switch_fan(crate::io::RelaySwitchState::Off, &mut program_state)?;
} }
Ok(()) Ok(())
} }
async fn temperature_control_loop(program_state: ProgramStateShared) { async fn temperature_control_loop(program_state: ProgramStateShared) {
let loop_duration = program_state
.lock()
.map(|program_state| {
program_state
.config
.controller_settings
.temperature_loop_mins
})
.unwrap_or(1);
loop { loop {
let _ = temperature_control(program_state.clone()).await; let _ = temperature_control(program_state.clone()).await;
tokio::time::sleep(Duration::from_mins(1)).await;
tokio::time::sleep(Duration::from_mins(loop_duration)).await;
} }
} }
async fn soil_moisture_control_loop(program_state: ProgramStateShared) { async fn soil_moisture_control_loop(program_state: ProgramStateShared) {
let loop_duration = program_state
.lock()
.map(|program_state| program_state.config.controller_settings.soil_loop_hours)
.unwrap_or(1);
loop { loop {
tokio::time::sleep(Duration::from_days(1)).await;
tokio::time::sleep(Duration::from_hours(loop_duration)).await;
} }
} }

Loading…
Cancel
Save