diff --git a/Software/MainBoard/rust/src/hal/mod.rs b/Software/MainBoard/rust/src/hal/mod.rs index eb6aa5e..034c018 100644 --- a/Software/MainBoard/rust/src/hal/mod.rs +++ b/Software/MainBoard/rust/src/hal/mod.rs @@ -101,7 +101,7 @@ use littlefs2::fs::{Allocation, Filesystem as lfs2Filesystem}; use littlefs2::object_safe::DynStorage; use log::{error, info, warn}; use portable_atomic::AtomicBool; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use shared_flash::MutexFlashStorage; pub static TIME_ACCESS: OnceLock> = OnceLock::new(); @@ -138,6 +138,12 @@ pub struct HAL<'a> { pub board_hal: Box + Send>, } +pub struct DetectionRequest { + pub sensorsa: [Sensor; PLANT_COUNT], + pub sensorsb: [Sensor; PLANT_COUNT], + +} + #[async_trait(?Send)] pub trait BoardInteraction<'a> { fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError>; @@ -163,7 +169,7 @@ pub trait BoardInteraction<'a> { async fn can_power(&mut self, state: bool) -> FatResult<()>; // Return JSON string with autodetected sensors per plant. Default: not supported. - async fn detect_sensors(&mut self) -> FatResult { + async fn detect_sensors(&mut self, request: Detection) -> FatResult { bail!("Autodetection is only available on v4 HAL with CAN bus"); } @@ -684,12 +690,13 @@ pub struct Moistures { pub sensor_b_hz: [Option; PLANT_COUNT], } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize)] -pub struct DetectionResult { +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)] +pub struct Detection { plant: [DetectionSensorResult; PLANT_COUNT], } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)] pub struct DetectionSensorResult { sensor_a: bool, sensor_b: bool, } + diff --git a/Software/MainBoard/rust/src/hal/v4_hal.rs b/Software/MainBoard/rust/src/hal/v4_hal.rs index e349bb6..1ff4076 100644 --- a/Software/MainBoard/rust/src/hal/v4_hal.rs +++ b/Software/MainBoard/rust/src/hal/v4_hal.rs @@ -6,7 +6,7 @@ use crate::hal::esp::{hold_disable, hold_enable, Esp}; use crate::hal::rtc::RTCModuleInteraction; use crate::hal::water::TankSensor; use crate::hal::{ - BoardInteraction, DetectionResult, FreePeripherals, Moistures, Sensor, I2C_DRIVER, PLANT_COUNT, + BoardInteraction, Detection, FreePeripherals, Moistures, Sensor, I2C_DRIVER, PLANT_COUNT, TIME_ACCESS, }; use crate::log::{LogMessage, LOG_ACCESS}; @@ -375,7 +375,7 @@ impl<'a> BoardInteraction<'a> for V4<'a> { Ok(moistures) } - async fn detect_sensors(&mut self) -> FatResult { + async fn detect_sensors(&mut self, request: Detection) -> FatResult { self.can_power.set_high(); let config = self.twai_config.take().expect("twai config not set"); let mut twai = config.into_async().start(); @@ -385,6 +385,14 @@ impl<'a> BoardInteraction<'a> for V4<'a> { // Send a few test messages per potential sensor node for plant in 0..PLANT_COUNT { for sensor in [Sensor::A, Sensor::B] { + let detect = if sensor == Sensor::A { + request.plant[plant].sensor_a + } else { + request.plant[plant].sensor_b + }; + if !detect { + continue; + } let target = StandardId::new(plant_id(IDENTIFY_CMD_OFFSET, sensor.into(), (plant +1) as u16)) .context(">> Could not create address for sensor! (plant: {}) <<")?; @@ -559,9 +567,9 @@ async fn wait_for_can_measurements( } } -impl From for DetectionResult { +impl From for Detection { fn from(value: Moistures) -> Self { - let mut result = DetectionResult::default(); + let mut result = Detection::default(); for (plant, sensor) in value.sensor_a_hz.iter().enumerate() { result.plant[plant].sensor_a = sensor.is_some(); } diff --git a/Software/MainBoard/rust/src/plant_state.rs b/Software/MainBoard/rust/src/plant_state.rs index 7a7bb59..0e92eee 100644 --- a/Software/MainBoard/rust/src/plant_state.rs +++ b/Software/MainBoard/rust/src/plant_state.rs @@ -117,7 +117,7 @@ impl PlantState { plant_id: usize, board: &mut HAL<'_>, ) -> Self { - let sensor_a = if board.board_hal.get_config().plants[plant_id].sensor_a { + let sensor_a = { //if board.board_hal.get_config().plants[plant_id].sensor_a { let raw = moistures.sensor_a_hz[plant_id]; match raw { None => { @@ -142,11 +142,11 @@ impl PlantState { } } - } else { - MoistureSensorState::Disabled - }; + }; // else { + // MoistureSensorState::Disabled + //}; - let sensor_b = if board.board_hal.get_config().plants[plant_id].sensor_b { + let sensor_b = { //if board.board_hal.get_config().plants[plant_id].sensor_b { let raw = moistures.sensor_b_hz[plant_id]; match raw { None => { @@ -170,9 +170,9 @@ impl PlantState { } } } - } else { - MoistureSensorState::Disabled - }; + }; // else { + // MoistureSensorState::Disabled + //}; let previous_pump = board.board_hal.get_esp().last_pump_time(plant_id); let consecutive_pump_count = board.board_hal.get_esp().consecutive_pump_count(plant_id); diff --git a/Software/MainBoard/rust/src/webserver/mod.rs b/Software/MainBoard/rust/src/webserver/mod.rs index a563688..fc57366 100644 --- a/Software/MainBoard/rust/src/webserver/mod.rs +++ b/Software/MainBoard/rust/src/webserver/mod.rs @@ -104,7 +104,7 @@ impl Handler for HTTPRequestRouter { "/can_power" => Some(can_power(conn).await), "/lamptest" => Some(night_lamp_test(conn).await), "/boardtest" => Some(board_test().await), - "/detect_sensors" => Some(detect_sensors().await), + "/detect_sensors" => Some(detect_sensors(conn).await), "/reboot" => { let mut board = BOARD_ACCESS.get().await.lock().await; board.board_hal.get_esp().set_restart_to_conf(true); diff --git a/Software/MainBoard/rust/src/webserver/post_json.rs b/Software/MainBoard/rust/src/webserver/post_json.rs index df0d1da..e49cac2 100644 --- a/Software/MainBoard/rust/src/webserver/post_json.rs +++ b/Software/MainBoard/rust/src/webserver/post_json.rs @@ -1,6 +1,6 @@ use crate::config::PlantControllerConfig; use crate::fat_error::FatResult; -use crate::hal::esp_set_time; +use crate::hal::{esp_set_time, Detection, DetectionRequest}; use crate::webserver::read_up_to_bytes_from_request; use crate::{do_secure_pump, BOARD_ACCESS}; use alloc::string::{String, ToString}; @@ -55,9 +55,16 @@ pub(crate) async fn board_test() -> FatResult> { Ok(None) } -pub(crate) async fn detect_sensors() -> FatResult> { +pub(crate) async fn detect_sensors( + request: &mut Connection<'_, T, N>, +) -> FatResult> +where + T: Read + Write, +{ + let actual_data = read_up_to_bytes_from_request(request, None).await?; + let detect: Detection = serde_json::from_slice(&actual_data)?; let mut board = BOARD_ACCESS.get().await.lock().await; - let result = board.board_hal.detect_sensors().await?; + let result = board.board_hal.detect_sensors(detect).await?; let json = serde_json::to_string(&result)?; Ok(Some(json)) } diff --git a/Software/MainBoard/rust/src_webpack/src/api.ts b/Software/MainBoard/rust/src_webpack/src/api.ts index 5d985ce..876390b 100644 --- a/Software/MainBoard/rust/src_webpack/src/api.ts +++ b/Software/MainBoard/rust/src_webpack/src/api.ts @@ -182,7 +182,7 @@ export interface DetectionPlant { sensor_b: boolean } -export interface DetectionResult { +export interface Detection { plant: DetectionPlant[] } diff --git a/Software/MainBoard/rust/src_webpack/src/main.ts b/Software/MainBoard/rust/src_webpack/src/main.ts index 7fcbb43..f3dcf9f 100644 --- a/Software/MainBoard/rust/src_webpack/src/main.ts +++ b/Software/MainBoard/rust/src_webpack/src/main.ts @@ -8,7 +8,7 @@ document.body.innerHTML = require('./main.html') as string; import {TimeView} from "./timeview"; -import {PlantViews} from "./plant"; +import {PlantViews, PLANT_COUNT} from "./plant"; import {NetworkConfigView} from "./network"; import {NightLampView} from "./nightlightview"; import {TankConfigView} from "./tankview"; @@ -29,7 +29,7 @@ import { SetTime, SSIDList, TankInfo, TestPump, VersionInfo, - FileList, SolarState, PumpTestResult, DetectionResult, CanPower + FileList, SolarState, PumpTestResult, Detection, CanPower } from "./api"; import {SolarView} from "./solarview"; import {toast} from "./toast"; @@ -361,7 +361,7 @@ export class Controller { ) } - async detectSensors() { + async detectSensors(detection: Detection) { let counter = 0 let limit = 5 controller.progressview.addProgress("detect_sensors", counter / limit * 100, "Detecting sensors " + (limit - counter) + "s") @@ -376,9 +376,11 @@ export class Controller { timerId = setTimeout(updateProgress, 1000); - fetch(PUBLIC_URL + "/detect_sensors", { method: "POST" }) + var pretty = JSON.stringify(detection, undefined, 1); + + fetch(PUBLIC_URL + "/detect_sensors", { method: "POST", body: pretty }) .then(response => response.json()) - .then (json => json as DetectionResult) + .then (json => json as Detection) .then(json => { clearTimeout(timerId); controller.progressview.removeProgress("detect_sensors"); @@ -573,7 +575,15 @@ export class Controller { this.logView = new LogView(this) this.hardwareView = new HardwareConfigView(this) this.detectBtn = document.getElementById("detect_sensors") as HTMLButtonElement - this.detectBtn.onclick = () => { controller.detectSensors(); } + this.detectBtn.onclick = () => { + const detection: Detection = { + plant: Array.from({length: PLANT_COUNT}, () => ({ + sensor_a: true, + sensor_b: true, + })), + }; + controller.detectSensors(detection); + } this.rebootBtn = document.getElementById("reboot") as HTMLButtonElement this.rebootBtn.onclick = () => { controller.reboot(); diff --git a/Software/MainBoard/rust/src_webpack/src/plant.html b/Software/MainBoard/rust/src_webpack/src/plant.html index cd07cc5..f4737fc 100644 --- a/Software/MainBoard/rust/src_webpack/src/plant.html +++ b/Software/MainBoard/rust/src_webpack/src/plant.html @@ -125,6 +125,10 @@
Live:
+
+ + +
Sensor A: not measured diff --git a/Software/MainBoard/rust/src_webpack/src/plant.ts b/Software/MainBoard/rust/src_webpack/src/plant.ts index b1e605e..8f83f1a 100644 --- a/Software/MainBoard/rust/src_webpack/src/plant.ts +++ b/Software/MainBoard/rust/src_webpack/src/plant.ts @@ -1,6 +1,6 @@ -import {DetectionPlant, DetectionResult, PlantConfig, PumpTestResult} from "./api"; +import {DetectionPlant, Detection, PlantConfig, PumpTestResult} from "./api"; -const PLANT_COUNT = 8; +export const PLANT_COUNT = 8; import {Controller} from "./main"; @@ -48,7 +48,7 @@ export class PlantViews { plantView.setTestResult(response) } - applyDetectionResult(json: DetectionResult) { + applyDetectionResult(json: Detection) { for (let i = 0; i < PLANT_COUNT; i++) { var plantResult = json.plant[i]; this.plants[i].setDetectionResult(plantResult); @@ -65,6 +65,8 @@ export class PlantView { private readonly plantDiv: HTMLDivElement; private readonly header: HTMLElement; private readonly testButton: HTMLButtonElement; + private readonly testSensorAButton: HTMLButtonElement; + private readonly testSensorBButton: HTMLButtonElement; private readonly targetMoisture: HTMLInputElement; private readonly minMoisture: HTMLInputElement; private readonly pumpTimeS: HTMLInputElement; @@ -119,6 +121,28 @@ export class PlantView { controller.testPlant(plantId) } + this.testSensorAButton = document.getElementById("plant_" + plantId + "_test_sensor_a")! as HTMLButtonElement; + this.testSensorAButton.onclick = () => { + const detection: Detection = { + plant: Array.from({length: PLANT_COUNT}, (_v, idx) => ({ + sensor_a: idx === plantId, + sensor_b: false, + })), + }; + controller.detectSensors(detection); + }; + + this.testSensorBButton = document.getElementById("plant_" + plantId + "_test_sensor_b")! as HTMLButtonElement; + this.testSensorBButton.onclick = () => { + const detection: Detection = { + plant: Array.from({length: PLANT_COUNT}, (_v, idx) => ({ + sensor_a: false, + sensor_b: idx === plantId, + })), + }; + controller.detectSensors(detection); + }; + this.mode = document.getElementById("plant_" + plantId + "_mode") as HTMLSelectElement this.mode.onchange = function () { controller.configChanged() diff --git a/Software/MainBoard/rust/src_webpack/src/tankview.ts b/Software/MainBoard/rust/src_webpack/src/tankview.ts index 24337ba..37ea517 100644 --- a/Software/MainBoard/rust/src_webpack/src/tankview.ts +++ b/Software/MainBoard/rust/src_webpack/src/tankview.ts @@ -1,5 +1,5 @@ import { Controller } from "./main"; -import {DetectionResult, TankConfig, TankInfo} from "./api"; +import {Detection, TankConfig, TankInfo} from "./api"; export class TankConfigView { private readonly tank_useable_ml: HTMLInputElement;