remove: eliminate MoistureSensorState::Disabled, simplify moisture sensor processing, refactor pump logic, and clean up redundant/unnecessary code
This commit is contained in:
@@ -323,13 +323,12 @@ impl From<sntpc::Error> for FatError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<BmsProtocolError> for FatError {
|
||||||
impl From<BmsProtocolError> for FatError{
|
|
||||||
fn from(value: BmsProtocolError) -> Self {
|
fn from(value: BmsProtocolError) -> Self {
|
||||||
match value {
|
match value {
|
||||||
BmsProtocolError::I2cCommunicationError => {
|
BmsProtocolError::I2cCommunicationError => FatError::String {
|
||||||
FatError::String{error: "I2C communication error".to_string()}
|
error: "I2C communication error".to_string(),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
use crate::hal::Box;
|
|
||||||
use crate::fat_error::{FatError, FatResult};
|
use crate::fat_error::{FatError, FatResult};
|
||||||
|
use crate::hal::Box;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice;
|
use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice;
|
||||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
use esp_hal::i2c::master::I2c;
|
use esp_hal::i2c::master::I2c;
|
||||||
use esp_hal::Blocking;
|
use esp_hal::Blocking;
|
||||||
use lib_bms_protocol::{BatteryState as bstate, BmsReadable, Config, FirmwareVersion, ProtocolVersion};
|
use lib_bms_protocol::{
|
||||||
|
BatteryState as bstate, BmsReadable, Config, FirmwareVersion, ProtocolVersion,
|
||||||
|
};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
@@ -59,18 +61,17 @@ impl BatteryInteraction for NoBatteryMonitor {
|
|||||||
pub struct WchI2cSlave {}
|
pub struct WchI2cSlave {}
|
||||||
|
|
||||||
pub struct WCHI2CSlave<'a> {
|
pub struct WCHI2CSlave<'a> {
|
||||||
pub(crate) i2c: I2cDevice<'a, CriticalSectionRawMutex, I2c<'a, Blocking>>
|
pub(crate) i2c: I2cDevice<'a, CriticalSectionRawMutex, I2c<'a, Blocking>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
impl BatteryInteraction for WCHI2CSlave<'_> {
|
impl BatteryInteraction for WCHI2CSlave<'_> {
|
||||||
|
|
||||||
|
|
||||||
async fn get_state(&mut self) -> FatResult<BatteryState> {
|
async fn get_state(&mut self) -> FatResult<BatteryState> {
|
||||||
let state = bstate::read_from_i2c(&mut self.i2c)?;
|
let state = bstate::read_from_i2c(&mut self.i2c)?;
|
||||||
let config = Config::read_from_i2c(&mut self.i2c)?;
|
let config = Config::read_from_i2c(&mut self.i2c)?;
|
||||||
|
|
||||||
let state_of_charge = (state.remaining_capacity_mah * 100 / state.lifetime_capacity_mah) as u8;
|
let state_of_charge =
|
||||||
|
(state.remaining_capacity_mah * 100 / state.lifetime_capacity_mah) as u8;
|
||||||
let state_of_health = state.lifetime_capacity_mah / config.capacity_mah * 100;
|
let state_of_health = state.lifetime_capacity_mah / config.capacity_mah * 100;
|
||||||
|
|
||||||
Ok(BatteryState::Info(BatteryInfo {
|
Ok(BatteryState::Info(BatteryInfo {
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ use embedded_storage::nor_flash::{check_erase, NorFlash, ReadNorFlash};
|
|||||||
use esp_bootloader_esp_idf::ota::OtaImageState::Valid;
|
use esp_bootloader_esp_idf::ota::OtaImageState::Valid;
|
||||||
use esp_bootloader_esp_idf::ota::{Ota, OtaImageState};
|
use esp_bootloader_esp_idf::ota::{Ota, OtaImageState};
|
||||||
use esp_bootloader_esp_idf::partitions::{AppPartitionSubType, FlashRegion};
|
use esp_bootloader_esp_idf::partitions::{AppPartitionSubType, FlashRegion};
|
||||||
use esp_hal::Blocking;
|
|
||||||
use esp_hal::gpio::{Input, RtcPinWithResistors};
|
use esp_hal::gpio::{Input, RtcPinWithResistors};
|
||||||
use esp_hal::rng::Rng;
|
use esp_hal::rng::Rng;
|
||||||
use esp_hal::rtc_cntl::{
|
use esp_hal::rtc_cntl::{
|
||||||
@@ -34,6 +33,7 @@ use esp_hal::rtc_cntl::{
|
|||||||
};
|
};
|
||||||
use esp_hal::system::software_reset;
|
use esp_hal::system::software_reset;
|
||||||
use esp_hal::uart::Uart;
|
use esp_hal::uart::Uart;
|
||||||
|
use esp_hal::Blocking;
|
||||||
use esp_println::println;
|
use esp_println::println;
|
||||||
use esp_radio::wifi::{
|
use esp_radio::wifi::{
|
||||||
AccessPointConfig, AccessPointInfo, AuthMethod, ClientConfig, ModeConfig, ScanConfig,
|
AccessPointConfig, AccessPointInfo, AuthMethod, ClientConfig, ModeConfig, ScanConfig,
|
||||||
@@ -155,7 +155,6 @@ macro_rules! mk_static {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Esp<'_> {
|
impl Esp<'_> {
|
||||||
|
|
||||||
pub(crate) async fn read_serial_line(&mut self) -> FatResult<Option<alloc::string::String>> {
|
pub(crate) async fn read_serial_line(&mut self) -> FatResult<Option<alloc::string::String>> {
|
||||||
let mut buf = [0u8; 1];
|
let mut buf = [0u8; 1];
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
@@ -171,7 +170,7 @@ impl Esp<'_> {
|
|||||||
}
|
}
|
||||||
line.push(c);
|
line.push(c);
|
||||||
}
|
}
|
||||||
Err(error ) => {
|
Err(error) => {
|
||||||
if line.is_empty() {
|
if line.is_empty() {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
use esp_hal::uart::Config as UartConfig;
|
||||||
use lib_bms_protocol::BmsReadable;
|
use lib_bms_protocol::BmsReadable;
|
||||||
use esp_hal::uart::{Config as UartConfig};
|
|
||||||
pub(crate) mod battery;
|
pub(crate) mod battery;
|
||||||
// mod can_api; // replaced by external canapi crate
|
// mod can_api; // replaced by external canapi crate
|
||||||
pub mod esp;
|
pub mod esp;
|
||||||
@@ -9,7 +9,6 @@ mod shared_flash;
|
|||||||
mod v4_hal;
|
mod v4_hal;
|
||||||
mod water;
|
mod water;
|
||||||
|
|
||||||
use lib_bms_protocol::ProtocolVersion;
|
|
||||||
use crate::alloc::string::ToString;
|
use crate::alloc::string::ToString;
|
||||||
use crate::hal::rtc::{DS3231Module, RTCModuleInteraction};
|
use crate::hal::rtc::{DS3231Module, RTCModuleInteraction};
|
||||||
use esp_hal::peripherals::Peripherals;
|
use esp_hal::peripherals::Peripherals;
|
||||||
@@ -36,6 +35,7 @@ use esp_hal::peripherals::GPIO6;
|
|||||||
use esp_hal::peripherals::GPIO7;
|
use esp_hal::peripherals::GPIO7;
|
||||||
use esp_hal::peripherals::GPIO8;
|
use esp_hal::peripherals::GPIO8;
|
||||||
use esp_hal::peripherals::TWAI0;
|
use esp_hal::peripherals::TWAI0;
|
||||||
|
use lib_bms_protocol::ProtocolVersion;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bail,
|
bail,
|
||||||
@@ -73,7 +73,7 @@ use esp_hal::gpio::{Input, InputConfig, Pull};
|
|||||||
use measurements::{Current, Voltage};
|
use measurements::{Current, Voltage};
|
||||||
|
|
||||||
use crate::fat_error::{ContextExt, FatError, FatResult};
|
use crate::fat_error::{ContextExt, FatError, FatResult};
|
||||||
use crate::hal::battery::{WCHI2CSlave};
|
use crate::hal::battery::WCHI2CSlave;
|
||||||
use crate::hal::little_fs2storage_adapter::LittleFs2Filesystem;
|
use crate::hal::little_fs2storage_adapter::LittleFs2Filesystem;
|
||||||
use crate::hal::water::TankSensor;
|
use crate::hal::water::TankSensor;
|
||||||
use crate::log::LOG_ACCESS;
|
use crate::log::LOG_ACCESS;
|
||||||
@@ -93,8 +93,8 @@ use esp_hal::rtc_cntl::{Rtc, SocResetReason};
|
|||||||
use esp_hal::system::reset_reason;
|
use esp_hal::system::reset_reason;
|
||||||
use esp_hal::time::Rate;
|
use esp_hal::time::Rate;
|
||||||
use esp_hal::timer::timg::TimerGroup;
|
use esp_hal::timer::timg::TimerGroup;
|
||||||
use esp_hal::Blocking;
|
|
||||||
use esp_hal::uart::Uart;
|
use esp_hal::uart::Uart;
|
||||||
|
use esp_hal::Blocking;
|
||||||
use esp_radio::{init, Controller};
|
use esp_radio::{init, Controller};
|
||||||
use esp_storage::FlashStorage;
|
use esp_storage::FlashStorage;
|
||||||
use littlefs2::fs::{Allocation, Filesystem as lfs2Filesystem};
|
use littlefs2::fs::{Allocation, Filesystem as lfs2Filesystem};
|
||||||
@@ -141,7 +141,6 @@ pub struct HAL<'a> {
|
|||||||
pub struct DetectionRequest {
|
pub struct DetectionRequest {
|
||||||
pub sensorsa: [Sensor; PLANT_COUNT],
|
pub sensorsa: [Sensor; PLANT_COUNT],
|
||||||
pub sensorsb: [Sensor; PLANT_COUNT],
|
pub sensorsb: [Sensor; PLANT_COUNT],
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
@@ -169,9 +168,7 @@ pub trait BoardInteraction<'a> {
|
|||||||
async fn can_power(&mut self, state: bool) -> FatResult<()>;
|
async fn can_power(&mut self, state: bool) -> FatResult<()>;
|
||||||
|
|
||||||
// Return JSON string with autodetected sensors per plant. Default: not supported.
|
// Return JSON string with autodetected sensors per plant. Default: not supported.
|
||||||
async fn detect_sensors(&mut self, request: Detection) -> FatResult<Detection> {
|
async fn detect_sensors(&mut self, request: Detection) -> FatResult<Detection>;
|
||||||
bail!("Autodetection is only available on v4 HAL with CAN bus");
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn progress(&mut self, counter: u32) {
|
async fn progress(&mut self, counter: u32) {
|
||||||
// Indicate progress is active to suppress default wait_infinity blinking
|
// Indicate progress is active to suppress default wait_infinity blinking
|
||||||
@@ -401,8 +398,8 @@ impl PlantHal {
|
|||||||
lfs2Filesystem::mount(alloc, lfs2filesystem).expect("Could not mount lfs2 filesystem"),
|
lfs2Filesystem::mount(alloc, lfs2filesystem).expect("Could not mount lfs2 filesystem"),
|
||||||
));
|
));
|
||||||
|
|
||||||
let uart0 = Uart::new(peripherals.UART0, UartConfig::default())
|
let uart0 =
|
||||||
.map_err(|_| FatError::String {
|
Uart::new(peripherals.UART0, UartConfig::default()).map_err(|_| FatError::String {
|
||||||
error: "Uart creation failed".to_string(),
|
error: "Uart creation failed".to_string(),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@@ -421,7 +418,7 @@ impl PlantHal {
|
|||||||
current: running,
|
current: running,
|
||||||
slot0_state: state_0,
|
slot0_state: state_0,
|
||||||
slot1_state: state_1,
|
slot1_state: state_1,
|
||||||
uart0
|
uart0,
|
||||||
};
|
};
|
||||||
|
|
||||||
//init,reset rtc memory depending on cause
|
//init,reset rtc memory depending on cause
|
||||||
@@ -553,7 +550,7 @@ impl PlantHal {
|
|||||||
//BoardVersion::V4 => {
|
//BoardVersion::V4 => {
|
||||||
v4_hal::create_v4(free_pins, esp, config, battery_interaction, rtc_module)
|
v4_hal::create_v4(free_pins, esp, config, battery_interaction, rtc_module)
|
||||||
.await?;
|
.await?;
|
||||||
//}
|
//}
|
||||||
//};
|
//};
|
||||||
|
|
||||||
HAL { board_hal }
|
HAL { board_hal }
|
||||||
@@ -571,9 +568,14 @@ impl PlantHal {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
HAL {
|
HAL {
|
||||||
board_hal: v4_hal::create_v4(free_pins, esp, PlantControllerConfig::default(),
|
board_hal: v4_hal::create_v4(
|
||||||
Box::new(NoBatteryMonitor {}), rtc_module)
|
free_pins,
|
||||||
.await?
|
esp,
|
||||||
|
PlantControllerConfig::default(),
|
||||||
|
Box::new(NoBatteryMonitor {}),
|
||||||
|
rtc_module,
|
||||||
|
)
|
||||||
|
.await?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -699,4 +701,3 @@ pub struct DetectionSensorResult {
|
|||||||
sensor_a: bool,
|
sensor_a: bool,
|
||||||
sensor_b: bool,
|
sensor_b: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use crate::hal::{
|
|||||||
};
|
};
|
||||||
use crate::log::{LogMessage, LOG_ACCESS};
|
use crate::log::{LogMessage, LOG_ACCESS};
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::string::{ToString};
|
use alloc::string::ToString;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use canapi::id::{classify, plant_id, MessageKind, IDENTIFY_CMD_OFFSET};
|
use canapi::id::{classify, plant_id, MessageKind, IDENTIFY_CMD_OFFSET};
|
||||||
use canapi::SensorSlot;
|
use canapi::SensorSlot;
|
||||||
@@ -133,10 +133,9 @@ pub struct V4<'a> {
|
|||||||
|
|
||||||
extra1: Output<'a>,
|
extra1: Output<'a>,
|
||||||
extra2: Output<'a>,
|
extra2: Output<'a>,
|
||||||
twai_config: Option<TwaiConfiguration<'static, Blocking>>
|
twai_config: Option<TwaiConfiguration<'static, Blocking>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(crate) async fn create_v4(
|
pub(crate) async fn create_v4(
|
||||||
peripherals: FreePeripherals<'static>,
|
peripherals: FreePeripherals<'static>,
|
||||||
esp: Esp<'static>,
|
esp: Esp<'static>,
|
||||||
@@ -263,12 +262,11 @@ pub(crate) async fn create_v4(
|
|||||||
extra1,
|
extra1,
|
||||||
extra2,
|
extra2,
|
||||||
can_power,
|
can_power,
|
||||||
twai_config
|
twai_config,
|
||||||
};
|
};
|
||||||
Ok(Box::new(v))
|
Ok(Box::new(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
impl<'a> BoardInteraction<'a> for V4<'a> {
|
impl<'a> BoardInteraction<'a> for V4<'a> {
|
||||||
fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError> {
|
fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError> {
|
||||||
@@ -395,11 +393,18 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
|
|||||||
if !detect {
|
if !detect {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let target =
|
let target = StandardId::new(plant_id(
|
||||||
StandardId::new(plant_id(IDENTIFY_CMD_OFFSET, sensor.into(), (plant +1) as u16))
|
IDENTIFY_CMD_OFFSET,
|
||||||
.context(">> Could not create address for sensor! (plant: {}) <<")?;
|
sensor.into(),
|
||||||
|
(plant + 1) as u16,
|
||||||
|
))
|
||||||
|
.context(">> Could not create address for sensor! (plant: {}) <<")?;
|
||||||
let can_buffer = [0_u8; 0];
|
let can_buffer = [0_u8; 0];
|
||||||
info!("Sending test message to plant {} sensor {sensor:?} with id {}", plant +1, target.as_raw());
|
info!(
|
||||||
|
"Sending test message to plant {} sensor {sensor:?} with id {}",
|
||||||
|
plant + 1,
|
||||||
|
target.as_raw()
|
||||||
|
);
|
||||||
if let Some(frame) = EspTwaiFrame::new(target, &can_buffer) {
|
if let Some(frame) = EspTwaiFrame::new(target, &can_buffer) {
|
||||||
// Try a few times; we intentionally ignore rx here and rely on stub logic
|
// Try a few times; we intentionally ignore rx here and rely on stub logic
|
||||||
let resu = twai
|
let resu = twai
|
||||||
@@ -407,12 +412,12 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
|
|||||||
.with_timeout(Duration::from_millis(3000))
|
.with_timeout(Duration::from_millis(3000))
|
||||||
.await;
|
.await;
|
||||||
match resu {
|
match resu {
|
||||||
Ok(_) => {
|
Ok(_) => {}
|
||||||
}
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
info!(
|
info!(
|
||||||
"Error sending test message to plant {} sensor {sensor:?}: {err:?}", plant +1
|
"Error sending test message to plant {} sensor {sensor:?}: {err:?}",
|
||||||
);
|
plant + 1
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -426,20 +431,17 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
|
|||||||
.with_timeout(Duration::from_millis(3000))
|
.with_timeout(Duration::from_millis(3000))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
|
||||||
let config = twai.stop().into_blocking();
|
let config = twai.stop().into_blocking();
|
||||||
self.twai_config.replace(config);
|
self.twai_config.replace(config);
|
||||||
|
|
||||||
self.can_power.set_low();
|
self.can_power.set_low();
|
||||||
|
|
||||||
|
|
||||||
let result = moistures.into();
|
let result = moistures.into();
|
||||||
|
|
||||||
info!("Autodetection result: {result:?}");
|
info!("Autodetection result: {result:?}");
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async fn general_fault(&mut self, enable: bool) {
|
async fn general_fault(&mut self, enable: bool) {
|
||||||
hold_disable(23);
|
hold_disable(23);
|
||||||
self.general_fault.set_level(enable.into());
|
self.general_fault.set_level(enable.into());
|
||||||
@@ -482,7 +484,7 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
|
|||||||
LOG_ACCESS
|
LOG_ACCESS
|
||||||
.lock()
|
.lock()
|
||||||
.await
|
.await
|
||||||
.log(LogMessage::TestSensor, a, b, &(plant+1).to_string(), "")
|
.log(LogMessage::TestSensor, a, b, &(plant + 1).to_string(), "")
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
Timer::after_millis(10).await;
|
Timer::after_millis(10).await;
|
||||||
@@ -511,7 +513,6 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async fn wait_for_can_measurements(
|
async fn wait_for_can_measurements(
|
||||||
as_async: &mut Twai<'_, Async>,
|
as_async: &mut Twai<'_, Async>,
|
||||||
moistures: &mut Moistures,
|
moistures: &mut Moistures,
|
||||||
@@ -538,10 +539,12 @@ async fn wait_for_can_measurements(
|
|||||||
let frequency = u32::from_be_bytes(bytes);
|
let frequency = u32::from_be_bytes(bytes);
|
||||||
match sensor {
|
match sensor {
|
||||||
SensorSlot::A => {
|
SensorSlot::A => {
|
||||||
moistures.sensor_a_hz[plant-1] = Some(frequency as f32);
|
moistures.sensor_a_hz[plant - 1] =
|
||||||
|
Some(frequency as f32);
|
||||||
}
|
}
|
||||||
SensorSlot::B => {
|
SensorSlot::B => {
|
||||||
moistures.sensor_b_hz[plant-1] = Some(frequency as f32);
|
moistures.sensor_b_hz[plant - 1] =
|
||||||
|
Some(frequency as f32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ use ::log::{error, info, warn};
|
|||||||
use alloc::borrow::ToOwned;
|
use alloc::borrow::ToOwned;
|
||||||
use alloc::string::{String, ToString};
|
use alloc::string::{String, ToString};
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use alloc::{format, vec};
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use alloc::{format, vec};
|
||||||
use chrono::{DateTime, Datelike, Timelike, Utc};
|
use chrono::{DateTime, Datelike, Timelike, Utc};
|
||||||
use chrono_tz::Tz::{self, UTC};
|
use chrono_tz::Tz::{self, UTC};
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
@@ -501,16 +501,17 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
|
|||||||
|
|
||||||
info!("state of charg");
|
info!("state of charg");
|
||||||
let is_day = board.board_hal.is_day();
|
let is_day = board.board_hal.is_day();
|
||||||
let battery_state = board.board_hal.get_battery_monitor().get_state().await.unwrap_or(BatteryState::Unknown);
|
let battery_state = board
|
||||||
|
.board_hal
|
||||||
|
.get_battery_monitor()
|
||||||
|
.get_state()
|
||||||
|
.await
|
||||||
|
.unwrap_or(BatteryState::Unknown);
|
||||||
info!("Battery state is {battery_state:?}");
|
info!("Battery state is {battery_state:?}");
|
||||||
|
|
||||||
let state_of_charge = match &battery_state {
|
let state_of_charge = match &battery_state {
|
||||||
BatteryState::Unknown => {
|
BatteryState::Unknown => 0,
|
||||||
0
|
BatteryState::Info(data) => data.state_of_charge,
|
||||||
}
|
|
||||||
BatteryState::Info(data) => {
|
|
||||||
data.state_of_charge
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut light_state = LightState {
|
let mut light_state = LightState {
|
||||||
@@ -529,22 +530,10 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
|
|||||||
board.board_hal.get_config().night_lamp.night_lamp_hour_end,
|
board.board_hal.get_config().night_lamp.night_lamp_hour_end,
|
||||||
);
|
);
|
||||||
|
|
||||||
if state_of_charge
|
if state_of_charge < board.board_hal.get_config().night_lamp.low_soc_cutoff {
|
||||||
< board
|
|
||||||
.board_hal
|
|
||||||
.get_config()
|
|
||||||
.night_lamp
|
|
||||||
.low_soc_cutoff
|
|
||||||
{
|
|
||||||
board.board_hal.get_esp().set_low_voltage_in_cycle();
|
board.board_hal.get_esp().set_low_voltage_in_cycle();
|
||||||
info!("Set low voltage in cycle");
|
info!("Set low voltage in cycle");
|
||||||
} else if state_of_charge
|
} else if state_of_charge > board.board_hal.get_config().night_lamp.low_soc_restore {
|
||||||
> board
|
|
||||||
.board_hal
|
|
||||||
.get_config()
|
|
||||||
.night_lamp
|
|
||||||
.low_soc_restore
|
|
||||||
{
|
|
||||||
board.board_hal.get_esp().clear_low_voltage_in_cycle();
|
board.board_hal.get_esp().clear_low_voltage_in_cycle();
|
||||||
info!("Clear low voltage in cycle");
|
info!("Clear low voltage in cycle");
|
||||||
}
|
}
|
||||||
@@ -652,17 +641,23 @@ pub async fn do_secure_pump(
|
|||||||
plant_config: &PlantConfig,
|
plant_config: &PlantConfig,
|
||||||
dry_run: bool,
|
dry_run: bool,
|
||||||
) -> FatResult<PumpResult> {
|
) -> FatResult<PumpResult> {
|
||||||
let mut current_collector = vec![0_u16; plant_config.pump_time_s.into()];
|
const STARTUP_IGNORE_MS: u32 = 500;
|
||||||
let mut flow_collector = vec![0_i16; plant_config.pump_time_s.into()];
|
const STARTUP_ABORT_CURRENT_MA: u16 = 1500;
|
||||||
|
|
||||||
|
let steps_in_50ms = plant_config.pump_time_s as usize * 20;
|
||||||
|
|
||||||
|
let mut current_collector = vec![0_u16; steps_in_50ms];
|
||||||
|
let mut flow_collector = vec![0_i16; steps_in_50ms];
|
||||||
let mut error = false;
|
let mut error = false;
|
||||||
let mut first_error = true;
|
let mut first_error = true;
|
||||||
let mut pump_time_s = 0;
|
let mut pump_time_ms: u32 = 0;
|
||||||
|
|
||||||
if !dry_run {
|
if !dry_run {
|
||||||
board.board_hal.get_tank_sensor()?.reset_flow_meter();
|
board.board_hal.get_tank_sensor()?.reset_flow_meter();
|
||||||
board.board_hal.get_tank_sensor()?.start_flow_meter();
|
board.board_hal.get_tank_sensor()?.start_flow_meter();
|
||||||
board.board_hal.pump(plant_id, true).await?;
|
board.board_hal.pump(plant_id, true).await?;
|
||||||
Timer::after_millis(10).await;
|
|
||||||
for step in 0..plant_config.pump_time_s as usize {
|
for step in 0..steps_in_50ms {
|
||||||
let flow_value = board.board_hal.get_tank_sensor()?.get_flow_meter_value();
|
let flow_value = board.board_hal.get_tank_sensor()?.get_flow_meter_value();
|
||||||
flow_collector[step] = flow_value;
|
flow_collector[step] = flow_value;
|
||||||
let flow_value_ml = flow_value as f32 * board.board_hal.get_config().tank.ml_per_pulse;
|
let flow_value_ml = flow_value as f32 * board.board_hal.get_config().tank.ml_per_pulse;
|
||||||
@@ -682,7 +677,20 @@ pub async fn do_secure_pump(
|
|||||||
let current_ma = current.as_milliamperes() as u16;
|
let current_ma = current.as_milliamperes() as u16;
|
||||||
current_collector[step] = current_ma;
|
current_collector[step] = current_ma;
|
||||||
let high_current = current_ma > plant_config.max_pump_current_ma;
|
let high_current = current_ma > plant_config.max_pump_current_ma;
|
||||||
if high_current && first_error {
|
if pump_time_ms < STARTUP_IGNORE_MS
|
||||||
|
&& high_current
|
||||||
|
&& current_ma > STARTUP_ABORT_CURRENT_MA
|
||||||
|
{
|
||||||
|
log(
|
||||||
|
LogMessage::PumpOverCurrent,
|
||||||
|
plant_id as u32 + 1,
|
||||||
|
current_ma as u32,
|
||||||
|
plant_config.max_pump_current_ma.to_string().as_str(),
|
||||||
|
step.to_string().as_str(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
error = true;
|
||||||
|
} else if high_current && first_error {
|
||||||
log(
|
log(
|
||||||
LogMessage::PumpOverCurrent,
|
LogMessage::PumpOverCurrent,
|
||||||
plant_id as u32 + 1,
|
plant_id as u32 + 1,
|
||||||
@@ -732,12 +740,14 @@ pub async fn do_secure_pump(
|
|||||||
error = true;
|
error = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
//e.g., v3 without a sensor ends here, do not spam
|
error!("Error getting pump current: {err}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Timer::after_millis(1000).await;
|
|
||||||
pump_time_s += 1;
|
//todo calcualte dynamically to offset time for stuff
|
||||||
|
Timer::after_millis(50).await;
|
||||||
|
pump_time_ms += 50;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
board.board_hal.get_tank_sensor()?.stop_flow_meter();
|
board.board_hal.get_tank_sensor()?.stop_flow_meter();
|
||||||
@@ -751,14 +761,14 @@ pub async fn do_secure_pump(
|
|||||||
min_current_ma: current_collector[0],
|
min_current_ma: current_collector[0],
|
||||||
flow_value_ml,
|
flow_value_ml,
|
||||||
flow_value_count: final_flow_value,
|
flow_value_count: final_flow_value,
|
||||||
pump_time_s,
|
pump_time_s: (pump_time_ms / 1000) as u16,
|
||||||
error,
|
error,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update_charge_indicator(
|
async fn update_charge_indicator(
|
||||||
board: &mut MutexGuard<'static, CriticalSectionRawMutex, HAL<'static>>,
|
board: &mut MutexGuard<'static, CriticalSectionRawMutex, HAL<'static>>,
|
||||||
) -> FatResult<()>{
|
) -> FatResult<()> {
|
||||||
//FIXME add config and code to allow power supply mode, in this case this is a nop
|
//FIXME add config and code to allow power supply mode, in this case this is a nop
|
||||||
//we have mppt controller, ask it for charging current
|
//we have mppt controller, ask it for charging current
|
||||||
let current = board.board_hal.get_mptt_current().await?;
|
let current = board.board_hal.get_mptt_current().await?;
|
||||||
@@ -766,10 +776,9 @@ async fn update_charge_indicator(
|
|||||||
.board_hal
|
.board_hal
|
||||||
.set_charge_indicator(current.as_milliamperes() > 20_f64)
|
.set_charge_indicator(current.as_milliamperes() > 20_f64)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async fn publish_tank_state(
|
async fn publish_tank_state(
|
||||||
board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'static>>,
|
board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'static>>,
|
||||||
tank_state: &TankState,
|
tank_state: &TankState,
|
||||||
@@ -949,11 +958,7 @@ async fn publish_mppt_state(
|
|||||||
async fn publish_battery_state(
|
async fn publish_battery_state(
|
||||||
board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'static>>,
|
board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'static>>,
|
||||||
) -> () {
|
) -> () {
|
||||||
let state = board
|
let state = board.board_hal.get_battery_monitor().get_state().await;
|
||||||
.board_hal
|
|
||||||
.get_battery_monitor()
|
|
||||||
.get_state()
|
|
||||||
.await;
|
|
||||||
let value = match state {
|
let value = match state {
|
||||||
Ok(state) => {
|
Ok(state) => {
|
||||||
let json = serde_json::to_string(&state).unwrap().to_owned();
|
let json = serde_json::to_string(&state).unwrap().to_owned();
|
||||||
@@ -986,7 +991,7 @@ async fn wait_infinity(
|
|||||||
loop {
|
loop {
|
||||||
{
|
{
|
||||||
let mut board = BOARD_ACCESS.get().await.lock().await;
|
let mut board = BOARD_ACCESS.get().await.lock().await;
|
||||||
match update_charge_indicator(&mut board).await{
|
match update_charge_indicator(&mut board).await {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
if !suppress_further_mppt_error {
|
if !suppress_further_mppt_error {
|
||||||
@@ -1069,35 +1074,38 @@ async fn wait_infinity(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_serial_config(board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'_>>, serial_config_receive: &AtomicBool, reboot_now: &AtomicBool) -> FatResult<()> {
|
async fn handle_serial_config(
|
||||||
|
board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'_>>,
|
||||||
|
serial_config_receive: &AtomicBool,
|
||||||
|
reboot_now: &AtomicBool,
|
||||||
|
) -> FatResult<()> {
|
||||||
match board.board_hal.get_esp().read_serial_line().await {
|
match board.board_hal.get_esp().read_serial_line().await {
|
||||||
Ok(serial_line) => {
|
Ok(serial_line) => match serial_line {
|
||||||
match serial_line {
|
None => Ok(()),
|
||||||
None => {
|
Some(line) => {
|
||||||
|
if serial_config_receive.load(Ordering::Relaxed) {
|
||||||
|
let ll = line.as_str();
|
||||||
|
let config: PlantControllerConfig = serde_json::from_str(ll)?;
|
||||||
|
board
|
||||||
|
.board_hal
|
||||||
|
.get_esp()
|
||||||
|
.save_config(Vec::from(ll.as_bytes()))
|
||||||
|
.await?;
|
||||||
|
board.board_hal.set_config(config);
|
||||||
|
serial_config_receive.store(false, Ordering::Relaxed);
|
||||||
|
info!("Config received, rebooting");
|
||||||
|
board.board_hal.get_esp().set_restart_to_conf(false);
|
||||||
|
reboot_now.store(true, Ordering::Relaxed);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
if line == "automation:streamconfig" {
|
||||||
|
serial_config_receive.store(true, Ordering::Relaxed);
|
||||||
|
info!("streamconfig:recieving");
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Some(line) => {
|
|
||||||
if serial_config_receive.load(Ordering::Relaxed) {
|
|
||||||
let ll = line.as_str();
|
|
||||||
let config: PlantControllerConfig = serde_json::from_str(ll)?;
|
|
||||||
board.board_hal.get_esp().save_config(Vec::from(ll.as_bytes())).await?;
|
|
||||||
board.board_hal.set_config(config);
|
|
||||||
serial_config_receive.store(false, Ordering::Relaxed);
|
|
||||||
info!("Config received, rebooting");
|
|
||||||
board.board_hal.get_esp().set_restart_to_conf(false);
|
|
||||||
reboot_now.store(true, Ordering::Relaxed);
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
if line == "automation:streamconfig" {
|
|
||||||
serial_config_receive.store(true, Ordering::Relaxed);
|
|
||||||
info!("streamconfig:recieving");
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
error!("Error reading serial line");
|
error!("Error reading serial line");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ pub enum MoistureSensorError {
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize)]
|
#[derive(Debug, PartialEq, Serialize)]
|
||||||
pub enum MoistureSensorState {
|
pub enum MoistureSensorState {
|
||||||
Disabled,
|
|
||||||
MoistureValue { raw_hz: f32, moisture_percent: f32 },
|
MoistureValue { raw_hz: f32, moisture_percent: f32 },
|
||||||
SensorError(MoistureSensorError),
|
SensorError(MoistureSensorError),
|
||||||
}
|
}
|
||||||
@@ -117,12 +116,11 @@ impl PlantState {
|
|||||||
plant_id: usize,
|
plant_id: usize,
|
||||||
board: &mut HAL<'_>,
|
board: &mut HAL<'_>,
|
||||||
) -> Self {
|
) -> 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];
|
let raw = moistures.sensor_a_hz[plant_id];
|
||||||
match raw {
|
match raw {
|
||||||
None => {
|
None => MoistureSensorState::SensorError(MoistureSensorError::NoMessage),
|
||||||
MoistureSensorState::SensorError(MoistureSensorError::NoMessage)
|
|
||||||
}
|
|
||||||
Some(raw) => {
|
Some(raw) => {
|
||||||
match map_range_moisture(
|
match map_range_moisture(
|
||||||
raw,
|
raw,
|
||||||
@@ -141,17 +139,15 @@ impl PlantState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}; // else {
|
}; // else {
|
||||||
// MoistureSensorState::Disabled
|
// 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];
|
let raw = moistures.sensor_b_hz[plant_id];
|
||||||
match raw {
|
match raw {
|
||||||
None => {
|
None => MoistureSensorState::SensorError(MoistureSensorError::NoMessage),
|
||||||
MoistureSensorState::SensorError(MoistureSensorError::NoMessage)
|
|
||||||
}
|
|
||||||
Some(raw) => {
|
Some(raw) => {
|
||||||
match map_range_moisture(
|
match map_range_moisture(
|
||||||
raw,
|
raw,
|
||||||
@@ -171,8 +167,8 @@ impl PlantState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}; // else {
|
}; // else {
|
||||||
// MoistureSensorState::Disabled
|
// MoistureSensorState::Disabled
|
||||||
//};
|
//};
|
||||||
|
|
||||||
let previous_pump = board.board_hal.get_esp().last_pump_time(plant_id);
|
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);
|
let consecutive_pump_count = board.board_hal.get_esp().consecutive_pump_count(plant_id);
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ where
|
|||||||
plant_state.push(PlantState::read_hardware_state(moistures, i, &mut board).await);
|
plant_state.push(PlantState::read_hardware_state(moistures, i, &mut board).await);
|
||||||
}
|
}
|
||||||
let a = Vec::from_iter(plant_state.iter().map(|s| match &s.sensor_a {
|
let a = Vec::from_iter(plant_state.iter().map(|s| match &s.sensor_a {
|
||||||
MoistureSensorState::Disabled => "disabled".to_string(),
|
|
||||||
MoistureSensorState::MoistureValue {
|
MoistureSensorState::MoistureValue {
|
||||||
raw_hz,
|
raw_hz,
|
||||||
moisture_percent,
|
moisture_percent,
|
||||||
@@ -53,7 +52,6 @@ where
|
|||||||
MoistureSensorState::SensorError(err) => format!("{err:?}"),
|
MoistureSensorState::SensorError(err) => format!("{err:?}"),
|
||||||
}));
|
}));
|
||||||
let b = Vec::from_iter(plant_state.iter().map(|s| match &s.sensor_b {
|
let b = Vec::from_iter(plant_state.iter().map(|s| match &s.sensor_b {
|
||||||
MoistureSensorState::Disabled => "disabled".to_string(),
|
|
||||||
MoistureSensorState::MoistureValue {
|
MoistureSensorState::MoistureValue {
|
||||||
raw_hz,
|
raw_hz,
|
||||||
moisture_percent,
|
moisture_percent,
|
||||||
@@ -128,11 +126,7 @@ pub(crate) async fn get_battery_state<T, const N: usize>(
|
|||||||
_request: &mut Connection<'_, T, N>,
|
_request: &mut Connection<'_, T, N>,
|
||||||
) -> FatResult<Option<String>> {
|
) -> FatResult<Option<String>> {
|
||||||
let mut board = BOARD_ACCESS.get().await.lock().await;
|
let mut board = BOARD_ACCESS.get().await.lock().await;
|
||||||
let battery_state = board
|
let battery_state = board.board_hal.get_battery_monitor().get_state().await?;
|
||||||
.board_hal
|
|
||||||
.get_battery_monitor()
|
|
||||||
.get_state()
|
|
||||||
.await?;
|
|
||||||
Ok(Some(serde_json::to_string(&battery_state)?))
|
Ok(Some(serde_json::to_string(&battery_state)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,10 @@ use crate::webserver::get_json::{
|
|||||||
use crate::webserver::get_log::get_log;
|
use crate::webserver::get_log::get_log;
|
||||||
use crate::webserver::get_static::{serve_bundle, serve_favicon, serve_index};
|
use crate::webserver::get_static::{serve_bundle, serve_favicon, serve_index};
|
||||||
use crate::webserver::ota::ota_operations;
|
use crate::webserver::ota::ota_operations;
|
||||||
use crate::webserver::post_json::{board_test, can_power, detect_sensors, night_lamp_test, pump_test, set_config, wifi_scan, write_time};
|
use crate::webserver::post_json::{
|
||||||
|
board_test, can_power, detect_sensors, night_lamp_test, pump_test, set_config, wifi_scan,
|
||||||
|
write_time,
|
||||||
|
};
|
||||||
use crate::{bail, BOARD_ACCESS};
|
use crate::{bail, BOARD_ACCESS};
|
||||||
use alloc::borrow::ToOwned;
|
use alloc::borrow::ToOwned;
|
||||||
use alloc::string::{String, ToString};
|
use alloc::string::{String, ToString};
|
||||||
|
|||||||
@@ -142,9 +142,6 @@ where
|
|||||||
|
|
||||||
board.board_hal.can_power(can_power_request.state).await?;
|
board.board_hal.can_power(can_power_request.state).await?;
|
||||||
let enable = can_power_request.state;
|
let enable = can_power_request.state;
|
||||||
info!(
|
info!("set can power to {enable}");
|
||||||
"set can power to {enable}"
|
|
||||||
);
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user