Add flowsensor prototype, add canbus to backplane
This commit is contained in:
@@ -58,6 +58,7 @@ pub struct TankConfig {
|
||||
pub tank_warn_percent: u8,
|
||||
pub tank_empty_percent: u8,
|
||||
pub tank_full_percent: u8,
|
||||
pub ml_per_pulse: f32
|
||||
}
|
||||
impl Default for TankConfig {
|
||||
fn default() -> Self {
|
||||
@@ -68,6 +69,7 @@ impl Default for TankConfig {
|
||||
tank_warn_percent: 40,
|
||||
tank_empty_percent: 5,
|
||||
tank_full_percent: 95,
|
||||
ml_per_pulse: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,6 +112,7 @@ pub struct PlantConfig {
|
||||
pub mode: PlantWateringMode,
|
||||
pub target_moisture: f32,
|
||||
pub pump_time_s: u16,
|
||||
pub pump_limit_ml: u16,
|
||||
pub pump_cooldown_min: u16,
|
||||
pub pump_hour_start: u8,
|
||||
pub pump_hour_end: u8,
|
||||
@@ -129,6 +132,7 @@ impl Default for PlantConfig {
|
||||
mode: PlantWateringMode::OFF,
|
||||
target_moisture: 40.,
|
||||
pump_time_s: 30,
|
||||
pump_limit_ml: 5000,
|
||||
pump_cooldown_min: 60,
|
||||
pump_hour_start: 9,
|
||||
pump_hour_end: 20,
|
||||
|
@@ -47,6 +47,7 @@ use once_cell::sync::Lazy;
|
||||
use std::result::Result::Ok as OkStd;
|
||||
use std::sync::Mutex;
|
||||
use std::time::Duration;
|
||||
use esp_idf_hal::pcnt::PCNT1;
|
||||
|
||||
//Only support for 8 right now!
|
||||
pub const PLANT_COUNT: usize = 8;
|
||||
@@ -154,6 +155,7 @@ pub struct FreePeripherals {
|
||||
pub gpio29: Gpio29,
|
||||
pub gpio30: Gpio30,
|
||||
pub pcnt0: PCNT0,
|
||||
pub pcnt1: PCNT1,
|
||||
pub adc1: ADC1,
|
||||
}
|
||||
|
||||
@@ -186,6 +188,7 @@ impl PlantHal {
|
||||
let free_pins = FreePeripherals {
|
||||
adc1: peripherals.adc1,
|
||||
pcnt0: peripherals.pcnt0,
|
||||
pcnt1: peripherals.pcnt1,
|
||||
gpio0: peripherals.pins.gpio0,
|
||||
gpio1: peripherals.pins.gpio1,
|
||||
gpio2: peripherals.pins.gpio2,
|
||||
|
@@ -124,12 +124,16 @@ pub(crate) fn create_v3(
|
||||
let one_wire_pin = peripherals.gpio18.downgrade();
|
||||
let tank_power_pin = peripherals.gpio11.downgrade();
|
||||
|
||||
let flow_sensor_pin = peripherals.gpio4.downgrade();
|
||||
|
||||
let tank_sensor = TankSensor::create(
|
||||
one_wire_pin,
|
||||
peripherals.adc1,
|
||||
peripherals.gpio5,
|
||||
tank_power_pin,
|
||||
);
|
||||
flow_sensor_pin,
|
||||
peripherals.pcnt1
|
||||
)?;
|
||||
|
||||
let mut signal_counter = PcntDriver::new(
|
||||
peripherals.pcnt0,
|
||||
|
@@ -152,13 +152,16 @@ pub(crate) fn create_v4(
|
||||
|
||||
let one_wire_pin = peripherals.gpio18.downgrade();
|
||||
let tank_power_pin = peripherals.gpio11.downgrade();
|
||||
let flow_sensor_pin = peripherals.gpio4.downgrade();
|
||||
|
||||
let tank_sensor = TankSensor::create(
|
||||
one_wire_pin,
|
||||
peripherals.adc1,
|
||||
peripherals.gpio5,
|
||||
tank_power_pin,
|
||||
);
|
||||
flow_sensor_pin,
|
||||
peripherals.pcnt1
|
||||
)?;
|
||||
|
||||
let mut signal_counter = PcntDriver::new(
|
||||
peripherals.pcnt0,
|
||||
|
@@ -5,7 +5,8 @@ use esp_idf_hal::adc::oneshot::config::AdcChannelConfig;
|
||||
use esp_idf_hal::adc::oneshot::{AdcChannelDriver, AdcDriver};
|
||||
use esp_idf_hal::adc::{attenuation, Resolution, ADC1};
|
||||
use esp_idf_hal::delay::Delay;
|
||||
use esp_idf_hal::gpio::{AnyIOPin, Gpio5, InputOutput, PinDriver, Pull};
|
||||
use esp_idf_hal::gpio::{AnyIOPin, AnyInputPin, Gpio5, InputOutput, PinDriver, Pull};
|
||||
use esp_idf_hal::pcnt::{PcntChannel, PcntChannelConfig, PcntControlMode, PcntCountMode, PcntDriver, PinIndex, PCNT1};
|
||||
use esp_idf_sys::EspError;
|
||||
use one_wire_bus::OneWire;
|
||||
|
||||
@@ -13,6 +14,7 @@ pub struct TankSensor<'a> {
|
||||
one_wire_bus: OneWire<PinDriver<'a, AnyIOPin, InputOutput>>,
|
||||
tank_channel: AdcChannelDriver<'a, Gpio5, AdcDriver<'a, ADC1>>,
|
||||
tank_power: PinDriver<'a, AnyIOPin, InputOutput>,
|
||||
flow_counter: PcntDriver<'a>,
|
||||
delay: Delay,
|
||||
}
|
||||
|
||||
@@ -22,7 +24,9 @@ impl<'a> TankSensor<'a> {
|
||||
adc1: ADC1,
|
||||
gpio5: Gpio5,
|
||||
tank_power_pin: AnyIOPin,
|
||||
) -> TankSensor<'a> {
|
||||
flow_sensor_pin: AnyIOPin,
|
||||
pcnt1: PCNT1
|
||||
) -> anyhow::Result<TankSensor<'a>> {
|
||||
let mut one_wire_pin =
|
||||
PinDriver::input_output_od(one_wire_pin).expect("Failed to configure pin");
|
||||
one_wire_pin
|
||||
@@ -47,12 +51,54 @@ impl<'a> TankSensor<'a> {
|
||||
let one_wire_bus =
|
||||
OneWire::new(one_wire_pin).expect("OneWire bus did not pull up after release");
|
||||
|
||||
TankSensor {
|
||||
let mut flow_counter = PcntDriver::new(
|
||||
pcnt1,
|
||||
Some(flow_sensor_pin),
|
||||
Option::<AnyInputPin>::None,
|
||||
Option::<AnyInputPin>::None,
|
||||
Option::<AnyInputPin>::None,
|
||||
)?;
|
||||
|
||||
flow_counter.channel_config(
|
||||
PcntChannel::Channel1,
|
||||
PinIndex::Pin0,
|
||||
PinIndex::Pin1,
|
||||
&PcntChannelConfig {
|
||||
lctrl_mode: PcntControlMode::Keep,
|
||||
hctrl_mode: PcntControlMode::Keep,
|
||||
pos_mode: PcntCountMode::Increment,
|
||||
neg_mode: PcntCountMode::Hold,
|
||||
counter_h_lim: i16::MAX,
|
||||
counter_l_lim: 0,
|
||||
},
|
||||
)?;
|
||||
|
||||
|
||||
Ok(TankSensor {
|
||||
one_wire_bus,
|
||||
tank_channel,
|
||||
tank_power,
|
||||
flow_counter,
|
||||
delay: Default::default(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn reset_flow_meter(&mut self) {
|
||||
self.flow_counter.counter_pause().unwrap();
|
||||
self.flow_counter.counter_clear().unwrap();
|
||||
}
|
||||
|
||||
pub fn start_flow_meter(&mut self) {
|
||||
self.flow_counter.counter_resume().unwrap();
|
||||
}
|
||||
|
||||
pub fn get_flow_meter_value(&mut self) -> i16 {
|
||||
self.flow_counter.get_counter_value().unwrap()
|
||||
}
|
||||
|
||||
pub fn stop_flow_meter(&mut self) -> i16 {
|
||||
self.flow_counter.counter_pause().unwrap();
|
||||
self.get_flow_meter_value()
|
||||
}
|
||||
|
||||
pub fn water_temperature_c(&mut self) -> anyhow::Result<f32> {
|
||||
|
@@ -88,6 +88,9 @@ pub struct PumpResult {
|
||||
max_current_ma: u16,
|
||||
min_current_ma: u16,
|
||||
error: bool,
|
||||
flow_value_ml: f32,
|
||||
flow_value_count: i16,
|
||||
pump_time_s: u16,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
@@ -583,12 +586,26 @@ pub fn do_secure_pump(
|
||||
dry_run: bool,
|
||||
) -> anyhow::Result<PumpResult> {
|
||||
let mut current_collector = vec![0_u16; plant_config.pump_time_s.into()];
|
||||
let mut flow_collector = vec![0_i16; plant_config.pump_time_s.into()];
|
||||
let mut error = false;
|
||||
let mut first_error = true;
|
||||
let mut pump_time_s = 0;
|
||||
if !dry_run {
|
||||
board.board_hal.get_tank_sensor().unwrap().reset_flow_meter();
|
||||
board.board_hal.get_tank_sensor().unwrap().start_flow_meter();
|
||||
board.board_hal.pump(plant_id, true)?;
|
||||
Delay::new_default().delay_ms(2);
|
||||
Delay::new_default().delay_ms(10);
|
||||
for step in 0..plant_config.pump_time_s as usize {
|
||||
let flow_value = board.board_hal.get_tank_sensor().unwrap().get_flow_meter_value();
|
||||
flow_collector[step] = flow_value;
|
||||
let flow_value_ml = flow_value as f32 * board.board_hal.get_config().tank.ml_per_pulse;
|
||||
|
||||
println!("Flow value is {} ml, limit is {} ml raw sensor {}", flow_value_ml, plant_config.pump_limit_ml, flow_value);
|
||||
if flow_value_ml > plant_config.pump_limit_ml as f32 {
|
||||
println!("Flow value is reached, stopping");
|
||||
break;
|
||||
}
|
||||
|
||||
let current = board.board_hal.pump_current(plant_id);
|
||||
match current {
|
||||
Ok(current) => {
|
||||
@@ -651,13 +668,21 @@ pub fn do_secure_pump(
|
||||
}
|
||||
}
|
||||
Delay::new_default().delay_ms(1000);
|
||||
pump_time_s += 1;
|
||||
}
|
||||
}
|
||||
board.board_hal.get_tank_sensor().unwrap().stop_flow_meter();
|
||||
let final_flow_value = board.board_hal.get_tank_sensor().unwrap().get_flow_meter_value();
|
||||
let flow_value_ml = final_flow_value as f32 * board.board_hal.get_config().tank.ml_per_pulse;
|
||||
println!("Final flow value is {} with {} ml", final_flow_value, flow_value_ml);
|
||||
current_collector.sort();
|
||||
Ok(PumpResult {
|
||||
median_current_ma: current_collector[current_collector.len() / 2],
|
||||
max_current_ma: current_collector[current_collector.len() - 1],
|
||||
min_current_ma: current_collector[0],
|
||||
flow_value_ml,
|
||||
flow_value_count: final_flow_value,
|
||||
pump_time_s,
|
||||
error,
|
||||
})
|
||||
}
|
||||
|
@@ -71,6 +71,7 @@ export interface TankConfig {
|
||||
tank_warn_percent: number,
|
||||
tank_empty_percent: number,
|
||||
tank_full_percent: number,
|
||||
ml_per_pulse: number
|
||||
}
|
||||
|
||||
|
||||
@@ -122,6 +123,9 @@ export interface PumpTestResult {
|
||||
median_current_ma: number,
|
||||
max_current_ma: number,
|
||||
min_current_ma: number,
|
||||
flow_value_ml: number,
|
||||
flow_value_count: number,
|
||||
pump_time_s: number,
|
||||
error: boolean,
|
||||
}
|
||||
|
||||
@@ -182,4 +186,4 @@ export interface TankInfo {
|
||||
/// water temperature
|
||||
water_temp: number | null,
|
||||
temp_sensor_error: string | null
|
||||
}
|
||||
}
|
@@ -20,16 +20,16 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.plantTargetEnabledOnly_${plantId}{
|
||||
.plantTargetEnabledOnly_ ${plantId} {
|
||||
}
|
||||
|
||||
.plantPumpEnabledOnly_${plantId}{
|
||||
.plantPumpEnabledOnly_ ${plantId} {
|
||||
}
|
||||
|
||||
.plantSensorEnabledOnly_${plantId}{
|
||||
.plantSensorEnabledOnly_ ${plantId} {
|
||||
}
|
||||
|
||||
.plantHidden_${plantId} {
|
||||
.plantHidden_ ${plantId} {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
@@ -129,8 +129,28 @@
|
||||
<span class="plantsensorvalue" id="plant_${plantId}_moisture_b">not measured</span>
|
||||
</div>
|
||||
<div class="flexcontainer plantPumpEnabledOnly_${plantId}">
|
||||
<div class="plantsensorkey">Test Current</div>
|
||||
<span class="plantsensorvalue" id="plant_${plantId}_pump_current_result">not_tested</span>
|
||||
<div class="plantsensorkey">Max Current</div>
|
||||
<span class="plantsensorvalue" id="plant_${plantId}_pump_test_current_max">not_tested</span>
|
||||
</div>
|
||||
<div class="flexcontainer plantPumpEnabledOnly_${plantId}">
|
||||
<div class="plantsensorkey">Min Current</div>
|
||||
<span class="plantsensorvalue" id="plant_${plantId}_pump_test_current_min">not_tested</span>
|
||||
</div>
|
||||
<div class="flexcontainer plantPumpEnabledOnly_${plantId}">
|
||||
<div class="plantsensorkey">Average</div>
|
||||
<span class="plantsensorvalue" id="plant_${plantId}_pump_test_current_average">not_tested</span>
|
||||
</div>
|
||||
<div class="flexcontainer plantPumpEnabledOnly_${plantId}">
|
||||
<div class="plantsensorkey">Pump Time</div>
|
||||
<span class="plantsensorvalue" id="plant_${plantId}_pump_test_pump_time">not_tested</span>
|
||||
</div>
|
||||
<div class="flexcontainer plantPumpEnabledOnly_${plantId}">
|
||||
<div class="plantsensorkey">Flow ml</div>
|
||||
<span class="plantsensorvalue" id="plant_${plantId}_pump_test_flow_ml">not_tested</span>
|
||||
</div>
|
||||
<div class="flexcontainer plantPumpEnabledOnly_${plantId}">
|
||||
<div class="plantsensorkey">Flow raw</div>
|
||||
<span class="plantsensorvalue" id="plant_${plantId}_pump_test_flow_raw">not_tested</span>
|
||||
</div>
|
||||
|
||||
|
||||
|
@@ -68,12 +68,18 @@ export class PlantView {
|
||||
private readonly mode: HTMLSelectElement;
|
||||
private readonly moistureA: HTMLElement;
|
||||
private readonly moistureB: HTMLElement;
|
||||
private readonly pump_current_result: HTMLElement
|
||||
private readonly maxConsecutivePumpCount: HTMLInputElement;
|
||||
private readonly minPumpCurrentMa: HTMLInputElement;
|
||||
private readonly maxPumpCurrentMa: HTMLInputElement;
|
||||
private readonly ignoreCurrentError: HTMLInputElement;
|
||||
|
||||
private readonly pump_test_current_max: HTMLElement;
|
||||
private readonly pump_test_current_min: HTMLElement;
|
||||
private readonly pump_test_current_average: HTMLElement;
|
||||
private readonly pump_test_pump_time: HTMLElement;
|
||||
private readonly pump_test_flow_ml: HTMLElement;
|
||||
private readonly pump_test_flow_raw: HTMLElement;
|
||||
|
||||
|
||||
constructor(plantId: number, parent: HTMLDivElement, controller: Controller) {
|
||||
this.plantId = plantId;
|
||||
@@ -89,8 +95,13 @@ export class PlantView {
|
||||
|
||||
this.moistureA = document.getElementById("plant_" + plantId + "_moisture_a")! as HTMLElement;
|
||||
this.moistureB = document.getElementById("plant_" + plantId + "_moisture_b")! as HTMLElement;
|
||||
this.pump_current_result = document.getElementById("plant_" + plantId + "_pump_current_result")! as HTMLElement;
|
||||
|
||||
this.pump_test_current_max = document.getElementById("plant_" + plantId + "_pump_test_current_max")! as HTMLElement;
|
||||
this.pump_test_current_min = document.getElementById("plant_" + plantId + "_pump_test_current_min")! as HTMLElement;
|
||||
this.pump_test_current_average = document.getElementById("plant_" + plantId + "_pump_test_current_average")! as HTMLElement;
|
||||
this.pump_test_pump_time = document.getElementById("plant_" + plantId + "_pump_test_pump_time")! as HTMLElement;
|
||||
this.pump_test_flow_ml = document.getElementById("plant_" + plantId + "_pump_test_flow_ml")! as HTMLElement;
|
||||
this.pump_test_flow_raw = document.getElementById("plant_" + plantId + "_pump_test_flow_raw")! as HTMLElement;
|
||||
|
||||
this.testButton = document.getElementById("plant_" + plantId + "_test")! as HTMLButtonElement;
|
||||
this.testButton.onclick = function () {
|
||||
@@ -226,7 +237,14 @@ export class PlantView {
|
||||
}
|
||||
|
||||
setTestResult(result: PumpTestResult) {
|
||||
this.pump_current_result.innerText = "Did abort " + result.error + " median current " + result.median_current_ma + " max current " + result.max_current_ma + " min current " + result.min_current_ma
|
||||
this.pump_test_current_max.innerText = result.max_current_ma.toString()
|
||||
this.pump_test_current_min.innerText = result.min_current_ma.toString()
|
||||
this.pump_test_current_average.innerText = result.median_current_ma.toString()
|
||||
|
||||
this.pump_test_flow_raw.innerText = result.flow_value_count.toString()
|
||||
this.pump_test_flow_ml.innerText = result.flow_value_ml.toString()
|
||||
|
||||
this.pump_test_pump_time.innerText = result.pump_time_s.toString()
|
||||
}
|
||||
|
||||
setMeasurementResult(a: string, b: string) {
|
||||
|
@@ -48,6 +48,10 @@
|
||||
<div class="tankkey">Full at %</div>
|
||||
<input class="tankvalue" type="number" min="0" max="100" id="tank_full_percent">
|
||||
</div>
|
||||
<div class="flexcontainer">
|
||||
<div class="tankkey">Flow Sensor ml per pulse</div>
|
||||
<input class="tankvalue" type="number" min="0" max="1000" step="0.01" id="ml_per_pulse">
|
||||
</div>
|
||||
<button id="tank_update">Update Tank</button>
|
||||
|
||||
|
||||
@@ -82,4 +86,4 @@
|
||||
<div class="flexcontainer">
|
||||
<div class="tankkey">Warn Level</div>
|
||||
<label class="tankvalue" id="tank_measure_warnlevel"></label>
|
||||
</div>
|
||||
</div>
|
@@ -8,6 +8,7 @@ export class TankConfigView {
|
||||
private readonly tank_warn_percent: HTMLInputElement;
|
||||
private readonly tank_sensor_enabled: HTMLInputElement;
|
||||
private readonly tank_allow_pumping_if_sensor_error: HTMLInputElement;
|
||||
private readonly ml_per_pulse: HTMLInputElement;
|
||||
private readonly tank_measure_error: HTMLLabelElement;
|
||||
private readonly tank_measure_ml: HTMLLabelElement;
|
||||
private readonly tank_measure_percent: HTMLLabelElement;
|
||||
@@ -54,6 +55,8 @@ export class TankConfigView {
|
||||
this.tank_sensor_enabled.onchange = controller.configChanged
|
||||
this.tank_allow_pumping_if_sensor_error = document.getElementById("tank_allow_pumping_if_sensor_error") as HTMLInputElement;
|
||||
this.tank_allow_pumping_if_sensor_error.onchange = controller.configChanged
|
||||
this.ml_per_pulse = document.getElementById("ml_per_pulse") as HTMLInputElement;
|
||||
this.ml_per_pulse.onchange = controller.configChanged
|
||||
|
||||
let tank_update = document.getElementById("tank_update") as HTMLInputElement;
|
||||
tank_update.onclick = () => {
|
||||
@@ -141,6 +144,7 @@ export class TankConfigView {
|
||||
this.tank_full_percent.value = String(tank.tank_full_percent)
|
||||
this.tank_sensor_enabled.checked = tank.tank_sensor_enabled
|
||||
this.tank_useable_ml.value = String(tank.tank_useable_ml)
|
||||
this.ml_per_pulse.value = String(tank.ml_per_pulse)
|
||||
}
|
||||
getConfig(): TankConfig {
|
||||
return {
|
||||
@@ -149,7 +153,8 @@ export class TankConfigView {
|
||||
tank_full_percent: this.tank_full_percent.valueAsNumber,
|
||||
tank_sensor_enabled: this.tank_sensor_enabled.checked,
|
||||
tank_useable_ml: this.tank_useable_ml.valueAsNumber,
|
||||
tank_warn_percent: this.tank_warn_percent.valueAsNumber
|
||||
tank_warn_percent: this.tank_warn_percent.valueAsNumber,
|
||||
ml_per_pulse: this.ml_per_pulse.valueAsNumber
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user