Refactor async logging to synchronous; improve error handling consistency across modules.
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
[connection]
|
||||
format = "EspIdf"
|
||||
|
||||
[[usb_device]]
|
||||
vid = "303a"
|
||||
pid = "1001"
|
||||
[idf_format_args]
|
||||
|
||||
[flash]
|
||||
size = "16MB"
|
||||
|
||||
@@ -607,16 +607,14 @@ impl Esp<'_> {
|
||||
0,
|
||||
"",
|
||||
"",
|
||||
)
|
||||
.await;
|
||||
);
|
||||
log(
|
||||
LogMessage::LowVoltage,
|
||||
LOW_VOLTAGE_DETECTED as u32,
|
||||
0,
|
||||
"",
|
||||
"",
|
||||
)
|
||||
.await;
|
||||
);
|
||||
// is executed before main, no other code will alter these values during printing
|
||||
#[allow(static_mut_refs)]
|
||||
for (i, time) in LAST_WATERING_TIMESTAMP.iter().enumerate() {
|
||||
@@ -695,9 +693,9 @@ impl Esp<'_> {
|
||||
))?;
|
||||
spawner.spawn(mqtt_runner(task))?;
|
||||
|
||||
log(LogMessage::StayAlive, 0, 0, "", &stay_alive_topic).await;
|
||||
log(LogMessage::StayAlive, 0, 0, "", &stay_alive_topic);
|
||||
|
||||
log(LogMessage::MqttInfo, 0, 0, "", mqtt_url).await;
|
||||
log(LogMessage::MqttInfo, 0, 0, "", mqtt_url);
|
||||
|
||||
let mqtt_timeout = 15000;
|
||||
let res = async {
|
||||
@@ -839,10 +837,10 @@ async fn mqtt_incoming_task(
|
||||
true => 1,
|
||||
false => 0,
|
||||
};
|
||||
log(LogMessage::MqttStayAliveRec, a, 0, "", "").await;
|
||||
log(LogMessage::MqttStayAliveRec, a, 0, "", "");
|
||||
MQTT_STAY_ALIVE.store(value, Ordering::Relaxed);
|
||||
} else {
|
||||
log(LogMessage::UnknownTopic, 0, 0, "", &topic).await;
|
||||
log(LogMessage::UnknownTopic, 0, 0, "", &topic);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -85,14 +85,13 @@ use esp_alloc as _;
|
||||
use esp_backtrace as _;
|
||||
use esp_bootloader_esp_idf::ota::{Ota, OtaImageState};
|
||||
use esp_hal::delay::Delay;
|
||||
use esp_hal::i2c::master::{BusTimeout, Config, FsmTimeout, I2c, SoftwareTimeout};
|
||||
use esp_hal::i2c::master::{BusTimeout, Config, FsmTimeout, I2c};
|
||||
use esp_hal::interrupt::software::SoftwareInterruptControl;
|
||||
use esp_hal::pcnt::unit::Unit;
|
||||
use esp_hal::pcnt::Pcnt;
|
||||
use esp_hal::rng::Rng;
|
||||
use esp_hal::rtc_cntl::{Rtc, SocResetReason};
|
||||
use esp_hal::system::reset_reason;
|
||||
use esp_hal::time::Rate;
|
||||
use esp_hal::timer::timg::{MwdtStage, TimerGroup, Wdt};
|
||||
use esp_hal::uart::Uart;
|
||||
use esp_hal::Blocking;
|
||||
@@ -255,7 +254,8 @@ impl PlantHal {
|
||||
esp_alloc::heap_allocator!(size: 64 * 1024);
|
||||
esp_alloc::heap_allocator!(#[link_section = ".dram2_uninit"] size: 64000);
|
||||
|
||||
let rtc_peripheral: Rtc = Rtc::new(peripherals.LPWR);
|
||||
let mut rtc_peripheral: Rtc = Rtc::new(peripherals.LPWR);
|
||||
rtc_peripheral.rwdt.disable();
|
||||
|
||||
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
||||
let sw_int = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
|
||||
@@ -469,8 +469,7 @@ impl PlantHal {
|
||||
to_config_mode as u32,
|
||||
"",
|
||||
&format!("{reasons:?}"),
|
||||
)
|
||||
.await;
|
||||
);
|
||||
|
||||
esp.init_rtc_deepsleep_memory(init_rtc_store, to_config_mode)
|
||||
.await;
|
||||
@@ -575,8 +574,7 @@ impl PlantHal {
|
||||
0,
|
||||
"",
|
||||
&err.to_string(),
|
||||
)
|
||||
.await;
|
||||
);
|
||||
HAL {
|
||||
board_hal: v4_hal::create_v4(
|
||||
free_pins,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::hal::Box;
|
||||
use crate::fat_error::FatResult;
|
||||
use crate::hal::Box;
|
||||
use async_trait::async_trait;
|
||||
use bincode::{Decode, Encode};
|
||||
use chrono::{DateTime, Utc};
|
||||
@@ -26,7 +26,7 @@ pub trait RTCModuleInteraction {
|
||||
async fn set_rtc_time(&mut self, time: &DateTime<Utc>) -> FatResult<()>;
|
||||
|
||||
fn write(&mut self, offset: u32, data: &[u8]) -> FatResult<()>;
|
||||
fn read(&mut self, offset:u32, data: &mut [u8]) -> FatResult<()>;
|
||||
fn read(&mut self, offset: u32, data: &mut [u8]) -> FatResult<()>;
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Encode, Decode)]
|
||||
@@ -67,7 +67,7 @@ impl RTCModuleInteraction for DS3231Module {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read(&mut self, offset:u32, data: &mut [u8]) -> FatResult<()> {
|
||||
fn read(&mut self, offset: u32, data: &mut [u8]) -> FatResult<()> {
|
||||
self.storage.read(offset, data)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -136,9 +136,7 @@ impl SavegameManager {
|
||||
let slot = self.storage.scan()?;
|
||||
match slot {
|
||||
None => Ok(None),
|
||||
Some(slot) => {
|
||||
self.load_slot(slot.idx)
|
||||
}
|
||||
Some(slot) => self.load_slot(slot.idx),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -350,8 +350,7 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
|
||||
}
|
||||
Some(pump_ina) => {
|
||||
let raw = pump_ina.shunt_voltage()?;
|
||||
let shunt_voltage =
|
||||
Voltage::from_microvolts(raw.shunt_voltage_uv().abs() as f64);
|
||||
let shunt_voltage = Voltage::from_microvolts(raw.shunt_voltage_uv().abs() as f64);
|
||||
let shut_value = Resistance::from_ohms(0.05_f64);
|
||||
let current = shunt_voltage.as_volts() / shut_value.as_ohms();
|
||||
Ok(Current::from_amperes(current))
|
||||
@@ -516,8 +515,7 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
|
||||
for plant in 0..PLANT_COUNT {
|
||||
let a = moisture.sensor_a_hz[plant].unwrap_or(0.0) as u32;
|
||||
let b = moisture.sensor_b_hz[plant].unwrap_or(0.0) as u32;
|
||||
log(LogMessage::TestSensor, a, b, &(plant + 1).to_string(), "")
|
||||
.await;
|
||||
log(LogMessage::TestSensor, a, b, &(plant + 1).to_string(), "");
|
||||
}
|
||||
Timer::after_millis(10).await;
|
||||
Ok(())
|
||||
|
||||
@@ -3,7 +3,7 @@ use alloc::vec::Vec;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::blocking_mutex::Mutex as BlockingMutex;
|
||||
use embassy_sync::mutex::Mutex;
|
||||
use log::{LevelFilter, Log, Metadata, Record};
|
||||
use log::{error, LevelFilter, Log, Metadata, Record};
|
||||
|
||||
pub struct InterceptorLogger {
|
||||
// Async mutex for start/stop capture from async context
|
||||
@@ -34,9 +34,13 @@ impl InterceptorLogger {
|
||||
}
|
||||
|
||||
pub fn init(&'static self) {
|
||||
log::set_logger(self)
|
||||
.map(|()| log::set_max_level(LevelFilter::Info))
|
||||
.unwrap();
|
||||
match log::set_logger(self)
|
||||
.map(|()| log::set_max_level(LevelFilter::Info)) {
|
||||
Ok(()) => {}
|
||||
Err(e) => {
|
||||
error!("Logger already set: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -115,28 +115,25 @@ impl From<LogEntryInner> for LogEntry {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn log(
|
||||
message_key: LogMessage,
|
||||
number_a: u32,
|
||||
number_b: u32,
|
||||
txt_short: &str,
|
||||
txt_long: &str,
|
||||
) {
|
||||
pub fn log(message_key: LogMessage, number_a: u32, number_b: u32, txt_short: &str, txt_long: &str) {
|
||||
let mut txt_short_stack: heapless::String<TXT_SHORT_LENGTH> = heapless::String::new();
|
||||
let mut txt_long_stack: heapless::String<TXT_LONG_LENGTH> = heapless::String::new();
|
||||
|
||||
limit_length(txt_short, &mut txt_short_stack);
|
||||
limit_length(txt_long, &mut txt_long_stack);
|
||||
|
||||
LOG_CHANNEL
|
||||
.send(LogRequest {
|
||||
message_key,
|
||||
number_a,
|
||||
number_b,
|
||||
txt_short: txt_short_stack,
|
||||
txt_long: txt_long_stack,
|
||||
})
|
||||
.await;
|
||||
match LOG_CHANNEL.try_send(LogRequest {
|
||||
message_key,
|
||||
number_a,
|
||||
number_b,
|
||||
txt_short: txt_short_stack,
|
||||
txt_long: txt_long_stack,
|
||||
}) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {
|
||||
warn!("Log channel full, dropping log entry");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LogArray {
|
||||
@@ -316,6 +313,10 @@ pub enum LogMessage {
|
||||
PumpMissingSensorCurrent,
|
||||
#[strum(serialize = "MPPT Current sensor could not be reached")]
|
||||
MPPTError,
|
||||
#[strum(
|
||||
serialize = "Trace: a: ${number_a} b: ${number_b} txt_s ${txt_short} long ${txt_long}"
|
||||
)]
|
||||
Trace,
|
||||
#[strum(serialize = "Parsing error reading message")]
|
||||
UnknownMessage,
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ use embassy_sync::once_lock::OnceLock;
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
use esp_hal::rom::ets_delay_us;
|
||||
use esp_hal::system::software_reset;
|
||||
use esp_println::{logger, println};
|
||||
use esp_println::println;
|
||||
use hal::battery::BatteryState;
|
||||
use log::LogMessage;
|
||||
use option_lock::OptionLock;
|
||||
@@ -185,7 +185,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
|
||||
//check if we know the time current > 2020 (plausibility checks, this code is newer than 2020)
|
||||
if cur.year() < 2020 {
|
||||
to_config = true;
|
||||
log(LogMessage::YearInplausibleForceConfig, 0, 0, "", "").await;
|
||||
log(LogMessage::YearInplausibleForceConfig, 0, 0, "", "");
|
||||
}
|
||||
info!("cur is {cur}");
|
||||
match update_charge_indicator(&mut board).await {
|
||||
@@ -193,12 +193,12 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
|
||||
Err(error) => {
|
||||
board.board_hal.general_fault(true).await;
|
||||
error!("Error updating charge indicator: {error}");
|
||||
log(LogMessage::MPPTError, 0, 0, "", "").await;
|
||||
log(LogMessage::MPPTError, 0, 0, "", "");
|
||||
let _ = board.board_hal.set_charge_indicator(false).await;
|
||||
}
|
||||
}
|
||||
if board.board_hal.get_esp().get_restart_to_conf() {
|
||||
log(LogMessage::ConfigModeSoftwareOverride, 0, 0, "", "").await;
|
||||
log(LogMessage::ConfigModeSoftwareOverride, 0, 0, "", "");
|
||||
for _i in 0..2 {
|
||||
board.board_hal.general_fault(true).await;
|
||||
Timer::after_millis(100).await;
|
||||
@@ -210,7 +210,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
|
||||
board.board_hal.get_esp().set_restart_to_conf(false);
|
||||
} else if board.board_hal.get_esp().mode_override_pressed() {
|
||||
board.board_hal.general_fault(true).await;
|
||||
log(LogMessage::ConfigModeButtonOverride, 0, 0, "", "").await;
|
||||
log(LogMessage::ConfigModeButtonOverride, 0, 0, "", "");
|
||||
for _i in 0..5 {
|
||||
board.board_hal.general_fault(true).await;
|
||||
Timer::after_millis(100).await;
|
||||
@@ -308,8 +308,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
|
||||
.to_string()
|
||||
.as_str(),
|
||||
"",
|
||||
)
|
||||
.await;
|
||||
);
|
||||
|
||||
if to_config {
|
||||
//check if client or ap mode and init Wi-Fi
|
||||
@@ -324,7 +323,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
|
||||
}
|
||||
wait_infinity(board, WaitType::ConfigButton, reboot_now.clone()).await;
|
||||
} else {
|
||||
log(LogMessage::NormalRun, 0, 0, "", "").await;
|
||||
log(LogMessage::NormalRun, 0, 0, "", "");
|
||||
}
|
||||
|
||||
let dry_run = MQTT_STAY_ALIVE.load(Ordering::Relaxed);
|
||||
@@ -335,28 +334,22 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
|
||||
if let Some(err) = tank_state.got_error(&board.board_hal.get_config().tank) {
|
||||
match err {
|
||||
TankError::SensorDisabled => { /* unreachable */ }
|
||||
TankError::SensorMissing(raw_value_mv) => {
|
||||
log(
|
||||
LogMessage::TankSensorMissing,
|
||||
raw_value_mv as u32,
|
||||
0,
|
||||
"",
|
||||
"",
|
||||
)
|
||||
.await
|
||||
}
|
||||
TankError::SensorValueError { value, min, max } => {
|
||||
log(
|
||||
LogMessage::TankSensorValueRangeError,
|
||||
min as u32,
|
||||
max as u32,
|
||||
&format!("{value}"),
|
||||
"",
|
||||
)
|
||||
.await
|
||||
}
|
||||
TankError::SensorMissing(raw_value_mv) => log(
|
||||
LogMessage::TankSensorMissing,
|
||||
raw_value_mv as u32,
|
||||
0,
|
||||
"",
|
||||
"",
|
||||
),
|
||||
TankError::SensorValueError { value, min, max } => log(
|
||||
LogMessage::TankSensorValueRangeError,
|
||||
min as u32,
|
||||
max as u32,
|
||||
&format!("{value}"),
|
||||
"",
|
||||
),
|
||||
TankError::BoardError(err) => {
|
||||
log(LogMessage::TankSensorBoardError, 0, 0, "", &err.to_string()).await
|
||||
log(LogMessage::TankSensorBoardError, 0, 0, "", &err.to_string())
|
||||
}
|
||||
}
|
||||
// disabled cannot trigger this because of wrapping if is_enabled
|
||||
@@ -365,7 +358,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
|
||||
.warn_level(&board.board_hal.get_config().tank)
|
||||
.is_ok_and(|warn| warn)
|
||||
{
|
||||
log(LogMessage::TankWaterLevelLow, 0, 0, "", "").await;
|
||||
log(LogMessage::TankWaterLevelLow, 0, 0, "", "");
|
||||
board.board_hal.general_fault(true).await;
|
||||
}
|
||||
}
|
||||
@@ -414,7 +407,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
|
||||
.any(|(it, conf)| it.needs_to_be_watered(conf, &timezone_time))
|
||||
&& !water_frozen;
|
||||
if pump_required {
|
||||
log(LogMessage::EnableMain, dry_run as u32, 0, "", "").await;
|
||||
log(LogMessage::EnableMain, dry_run as u32, 0, "", "");
|
||||
for (plant_id, (state, plant_config)) in plantstate
|
||||
.iter()
|
||||
.zip(&board.board_hal.get_config().plants.clone())
|
||||
@@ -435,8 +428,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
|
||||
plant_config.max_consecutive_pump_count as u32,
|
||||
&(plant_id + 1).to_string(),
|
||||
"",
|
||||
)
|
||||
.await;
|
||||
);
|
||||
board.board_hal.fault(plant_id, true).await?;
|
||||
}
|
||||
log(
|
||||
@@ -445,8 +437,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
|
||||
plant_config.pump_time_s as u32,
|
||||
&dry_run.to_string(),
|
||||
"",
|
||||
)
|
||||
.await;
|
||||
);
|
||||
board
|
||||
.board_hal
|
||||
.get_esp()
|
||||
@@ -677,8 +668,7 @@ pub async fn do_secure_pump(
|
||||
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(
|
||||
@@ -687,8 +677,7 @@ pub async fn do_secure_pump(
|
||||
current_ma as u32,
|
||||
plant_config.max_pump_current_ma.to_string().as_str(),
|
||||
step.to_string().as_str(),
|
||||
)
|
||||
.await;
|
||||
);
|
||||
board.board_hal.general_fault(true).await;
|
||||
board.board_hal.fault(plant_id, true).await?;
|
||||
if !plant_config.ignore_current_error {
|
||||
@@ -705,8 +694,7 @@ pub async fn do_secure_pump(
|
||||
current_ma as u32,
|
||||
plant_config.min_pump_current_ma.to_string().as_str(),
|
||||
step.to_string().as_str(),
|
||||
)
|
||||
.await;
|
||||
);
|
||||
board.board_hal.general_fault(true).await;
|
||||
board.board_hal.fault(plant_id, true).await?;
|
||||
if !plant_config.ignore_current_error {
|
||||
@@ -725,8 +713,7 @@ pub async fn do_secure_pump(
|
||||
0,
|
||||
"",
|
||||
"",
|
||||
)
|
||||
.await;
|
||||
);
|
||||
error = true;
|
||||
break;
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use bincode::{Decode, Encode};
|
||||
use crate::hal::Moistures;
|
||||
use crate::{config::PlantConfig, hal::HAL, in_time_range};
|
||||
use bincode::{Decode, Encode};
|
||||
use chrono::{DateTime, TimeDelta, Utc};
|
||||
use chrono_tz::Tz;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -123,9 +123,7 @@ pub(crate) async fn get_config<T, const N: usize>(
|
||||
let mut board = BOARD_ACCESS.get().await.lock().await;
|
||||
let json = match saveidx {
|
||||
None => serde_json::to_string(board.board_hal.get_config())?,
|
||||
Some(idx) => {
|
||||
board.board_hal.get_esp().load_config_slot(idx).await?
|
||||
}
|
||||
Some(idx) => board.board_hal.get_esp().load_config_slot(idx).await?,
|
||||
};
|
||||
Ok(Some(json))
|
||||
}
|
||||
@@ -174,7 +172,12 @@ pub(crate) async fn get_time<T, const N: usize>(
|
||||
},
|
||||
};
|
||||
|
||||
let native = board.board_hal.get_time().await.with_timezone(&tz).to_rfc3339();
|
||||
let native = board
|
||||
.board_hal
|
||||
.get_time()
|
||||
.await
|
||||
.with_timezone(&tz)
|
||||
.to_rfc3339();
|
||||
|
||||
let rtc = match board.board_hal.get_rtc_module().get_rtc_time().await {
|
||||
Ok(time) => time.with_timezone(&tz).to_rfc3339(),
|
||||
|
||||
@@ -47,28 +47,26 @@ export class Controller {
|
||||
});
|
||||
}
|
||||
|
||||
loadLogLocaleConfig() {
|
||||
return fetch(PUBLIC_URL + "/log_localization")
|
||||
.then(response => response.json())
|
||||
.then(json => json as LogLocalisation)
|
||||
.then(loglocale => {
|
||||
controller.logView.setLogLocalisation(loglocale)
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
async loadLogLocaleConfig() {
|
||||
try {
|
||||
const response = await fetch(PUBLIC_URL + "/log_localization");
|
||||
const json = await response.json();
|
||||
const loglocale = json as LogLocalisation;
|
||||
controller.logView.setLogLocalisation(loglocale);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
loadLog() {
|
||||
return fetch(PUBLIC_URL + "/log")
|
||||
.then(response => response.json())
|
||||
.then(json => json as LogArray)
|
||||
.then(logs => {
|
||||
controller.logView.setLog(logs)
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
async loadLog() {
|
||||
try {
|
||||
const response = await fetch(PUBLIC_URL + "/log");
|
||||
const json = await response.json();
|
||||
const logs = json as LogArray;
|
||||
controller.logView.setLog(logs);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
async getBackupInfo(): Promise<void> {
|
||||
@@ -241,11 +239,11 @@ export class Controller {
|
||||
return response.status
|
||||
})
|
||||
.then(status => {
|
||||
controller.progressview.removeProgress("set_config");
|
||||
if (status == 200) {
|
||||
controller.progressview.removeProgress("set_config");
|
||||
setTimeout(() => {
|
||||
controller.downloadConfig().then(r => {
|
||||
controller.updateSaveList().then(r => {
|
||||
controller.downloadConfig().then(() => {
|
||||
controller.updateSaveList().then(() => {
|
||||
});
|
||||
});
|
||||
}, 250)
|
||||
@@ -669,7 +667,7 @@ async function executeTasksSequentially() {
|
||||
}
|
||||
}
|
||||
|
||||
executeTasksSequentially().then(r => {
|
||||
executeTasksSequentially().then(() => {
|
||||
controller.progressview.removeProgress("initial")
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user