get log to work, make time accessible

This commit is contained in:
Empire 2025-09-20 11:31:51 +02:00
parent 584d6df2d0
commit c94f5bdb45
6 changed files with 334 additions and 212 deletions

View File

@ -133,16 +133,11 @@ serde = { version = "1.0.219", features = ["derive", "alloc"], default-features
serde_json = { version = "1.0.143", default-features = false, features = ["alloc"] }
#timezone
chrono = { version = "0.4.42", default-features = false, features = ["iana-time-zone", "alloc", "serde"] }
chrono-tz = { version = "0.10.4", default-features = false, features = ["filter-by-regex"] }
eeprom24x = "0.7.2"
#url = "2.5.3"
crc = "3.2.1"
bincode = { version = "2.0.1", default-features = false, features = ["alloc", "serde"] }
ringbuffer = "0.15.0"
strum_macros = "0.27.0"
#esp-ota = { version = "0.2.2", features = ["log"] }
unit-enum = "1.4.1"
pca9535 = { version = "2.0.0" }
ina219 = { version = "0.2.0" }
@ -157,10 +152,10 @@ edge-dhcp = "0.6.0"
edge-nal = "0.5.0"
edge-nal-embassy = "0.6.0"
static_cell = "2.1.1"
cfg-if = "1.0.3"
edge-http = { version = "0.6.1", features = ["log"] }
littlefs2 = { version = "0.6.1", features = ["c-stubs", "alloc"] }
littlefs2-core = "0.1.1"
bytemuck = { version = "1.23.2", features = ["derive", "min_const_generics", "pod_saturating", "extern_crate_alloc"] }
[patch.crates-io]

View File

@ -1,9 +1,9 @@
use crate::config::{NetworkConfig, PlantControllerConfig};
use crate::hal::{GW_IP_ADDR_ENV, PLANT_COUNT};
use crate::log::{log, LogMessage};
use crate::hal::{GW_IP_ADDR_ENV, PLANT_COUNT, TIME_ACCESS};
use crate::log::{ LogArray, LogMessage, LOG_ACCESS};
use crate::STAY_ALIVE;
use anyhow::{anyhow, bail, Context};
use chrono::{DateTime, Utc};
use chrono::{DateTime, FixedOffset, Utc};
use serde::Serialize;
use crate::hal::little_fs2storage_adapter::LittleFs2Filesystem;
@ -13,12 +13,10 @@ use alloc::{format, string::String, vec::Vec};
use core::marker::PhantomData;
use core::net::{IpAddr, Ipv4Addr};
use core::str::FromStr;
use embassy_executor::{SendSpawner, Spawner};
use embassy_net::tcp::TcpSocket;
use embassy_net::{IpListenEndpoint, Ipv4Cidr, Runner, Stack, StackResources, StaticConfigV4};
use embassy_executor::{Spawner};
use embassy_net::{Ipv4Cidr, Runner, Stack, StackResources, StaticConfigV4};
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::mutex::Mutex;
use embassy_sync::rwlock::TryLockError;
use embassy_time::{Duration, Instant, Timer};
use embedded_storage::nor_flash::ReadNorFlash;
use embedded_storage::Storage;
@ -26,25 +24,27 @@ use esp_bootloader_esp_idf::ota::{Ota, OtaImageState, Slot};
use esp_bootloader_esp_idf::partitions::{Error, FlashRegion, PartitionEntry, PartitionTable};
use esp_hal::gpio::Input;
use esp_hal::rng::Rng;
use esp_hal::rtc_cntl::Rtc;
use esp_hal::rtc_cntl::sleep::RtcSleepConfig;
use esp_println::{print, println};
use esp_hal::system::software_reset;
use esp_println::{println};
use esp_storage::FlashStorage;
use esp_wifi::wifi::{
AccessPointConfiguration, AccessPointInfo, Configuration, Interfaces, ScanConfig,
ScanTypeConfig, WifiController, WifiDevice, WifiEvent, WifiState,
ScanTypeConfig, WifiController, WifiDevice,
};
use littlefs2::fs::Filesystem;
use littlefs2_core::{DynFile, FileType, OpenSeekFrom, Path, PathBuf, SeekFrom};
use log::{info, warn};
use littlefs2_core::{DynFile, FileType, PathBuf, SeekFrom};
use log::{info};
#[link_section = ".rtc.data"]
#[esp_hal::ram(rtc_fast, persistent)]
static mut LAST_WATERING_TIMESTAMP: [i64; PLANT_COUNT] = [0; PLANT_COUNT];
#[link_section = ".rtc.data"]
#[esp_hal::ram(rtc_fast, persistent)]
static mut CONSECUTIVE_WATERING_PLANT: [u32; PLANT_COUNT] = [0; PLANT_COUNT];
#[link_section = ".rtc.data"]
static mut LOW_VOLTAGE_DETECTED: bool = false;
#[link_section = ".rtc.data"]
static mut RESTART_TO_CONF: bool = false;
#[esp_hal::ram(rtc_fast, persistent)]
static mut LOW_VOLTAGE_DETECTED: i8 = 0;
#[esp_hal::ram(rtc_fast, persistent)]
static mut RESTART_TO_CONF: i8 = 0;
static CONFIG_FILE: &str = "config.json";
@ -239,10 +239,6 @@ impl Esp<'_> {
bail!("not implemented")
}
pub(crate) fn time(&mut self) -> DateTime<Utc> {
let wall_clock = Instant::now().as_millis() + self.wall_clock_offset;
DateTime::from_timestamp_millis(wall_clock as i64).unwrap()
}
pub(crate) async fn wifi_scan(&mut self) -> anyhow::Result<Vec<AccessPointInfo>> {
info!("start wifi scan");
@ -277,17 +273,17 @@ impl Esp<'_> {
}
pub(crate) fn set_low_voltage_in_cycle(&mut self) {
unsafe {
LOW_VOLTAGE_DETECTED = true;
LOW_VOLTAGE_DETECTED = 1;
}
}
pub(crate) fn clear_low_voltage_in_cycle(&mut self) {
unsafe {
LOW_VOLTAGE_DETECTED = false;
LOW_VOLTAGE_DETECTED = 1;
}
}
pub(crate) fn low_voltage_in_cycle(&mut self) -> bool {
unsafe { LOW_VOLTAGE_DETECTED }
unsafe { LOW_VOLTAGE_DETECTED == 1 }
}
pub(crate) fn store_consecutive_pump_count(&mut self, plant: usize, count: u32) {
unsafe {
@ -298,11 +294,15 @@ impl Esp<'_> {
unsafe { CONSECUTIVE_WATERING_PLANT[plant] }
}
pub(crate) fn get_restart_to_conf(&mut self) -> bool {
unsafe { RESTART_TO_CONF }
unsafe { RESTART_TO_CONF == 1}
}
pub(crate) fn set_restart_to_conf(&mut self, to_conf: bool) {
unsafe {
RESTART_TO_CONF = to_conf;
if to_conf {
RESTART_TO_CONF = 1;
} else {
RESTART_TO_CONF = 0;
}
}
}
@ -374,10 +374,9 @@ impl Esp<'_> {
//unsafe {
// //allow early wakeup by pressing the boot button
if duration_in_ms == 0 {
loop {
info!("todo reboot")
}
software_reset();
} else {
loop {
info!("todo deepsleep")
}
@ -547,31 +546,34 @@ impl Esp<'_> {
unsafe {
LAST_WATERING_TIMESTAMP = [0; PLANT_COUNT];
CONSECUTIVE_WATERING_PLANT = [0; PLANT_COUNT];
LOW_VOLTAGE_DETECTED = false;
crate::log::init().await;
RESTART_TO_CONF = to_config_mode;
LOW_VOLTAGE_DETECTED = 0;
if to_config_mode {
RESTART_TO_CONF = 1
} else {
RESTART_TO_CONF = 0;
}
};
} else {
unsafe {
if to_config_mode {
RESTART_TO_CONF = true;
RESTART_TO_CONF = 1;
}
log(
LOG_ACCESS.lock().await.log(
LogMessage::RestartToConfig,
RESTART_TO_CONF as u32,
0,
"",
"",
)
.await;
log(
).await
;
LOG_ACCESS.lock().await.log(
LogMessage::LowVoltage,
LOW_VOLTAGE_DETECTED as u32,
0,
"",
"",
)
.await;
).await
;
for i in 0..PLANT_COUNT {
log::info!(
"LAST_WATERING_TIMESTAMP[{}] = UTC {}",

View File

@ -18,13 +18,15 @@ use crate::{
battery::{BatteryInteraction, NoBatteryMonitor},
esp::Esp,
},
log::{log, LogMessage},
log::{LogMessage},
};
use alloc::boxed::Box;
use alloc::format;
use alloc::sync::Arc;
use core::cell::OnceCell;
use anyhow::{bail, Ok, Result};
use async_trait::async_trait;
use chrono::{DateTime, FixedOffset, Utc};
use embassy_executor::Spawner;
//use battery::BQ34Z100G1;
//use bq34z100::Bq34z100g1Driver;
@ -38,16 +40,22 @@ use measurements::{Current, Voltage};
use crate::hal::little_fs2storage_adapter::LittleFs2Filesystem;
use embassy_sync::mutex::Mutex;
use embassy_sync::once_lock::OnceLock;
use esp_alloc as _;
use esp_backtrace as _;
use esp_bootloader_esp_idf::ota::Slot;
use esp_hal::rng::Rng;
use esp_hal::rtc_cntl::{Rtc, SocResetReason};
use esp_hal::system::reset_reason;
use esp_hal::timer::timg::TimerGroup;
use esp_storage::FlashStorage;
use esp_wifi::{init, EspWifiController};
use littlefs2::fs::{Allocation, Filesystem as lfs2Filesystem};
use littlefs2::object_safe::DynStorage;
use log::{info, warn};
use crate::log::{LogArray, LOG_ACCESS};
pub static TIME_ACCESS: OnceLock<Rtc> = OnceLock::new();
//Only support for 8 right now!
pub const PLANT_COUNT: usize = 8;
@ -181,6 +189,13 @@ impl PlantHal {
esp_alloc::heap_allocator!(size: 64 * 1024);
esp_alloc::heap_allocator!(#[link_section = ".dram2_uninit"] size: 64000);
let rtc: Rtc = Rtc::new(peripherals.LPWR);
match(TIME_ACCESS.init(rtc)){
Result::Ok(_) => {}
Err(_) => {}
}
let systimer = SystemTimer::new(peripherals.SYSTIMER);
let boot_button = Input::new(
@ -335,36 +350,78 @@ impl PlantHal {
//init,reset rtc memory depending on cause
let mut init_rtc_store: bool = false;
let mut to_config_mode: bool = false;
let reasons = "";
// let reasons = ResetReason::get();
// match reasons {
// ResetReason::Software => {}
// ResetReason::ExternalPin => {}
// ResetReason::Watchdog => {
// init_rtc_store = true;
// }
// ResetReason::Sdio => init_rtc_store = true,
// ResetReason::Panic => init_rtc_store = true,
// ResetReason::InterruptWatchdog => init_rtc_store = true,
// ResetReason::PowerOn => init_rtc_store = true,
// ResetReason::Unknown => init_rtc_store = true,
// ResetReason::Brownout => init_rtc_store = true,
// ResetReason::TaskWatchdog => init_rtc_store = true,
// ResetReason::DeepSleep => {}
// ResetReason::USBPeripheral => {
// init_rtc_store = true;
// to_config_mode = true;
// }
// ResetReason::JTAG => init_rtc_store = true,
// };
log(
let reasons = match reset_reason() {
None => {
"unknown"
}
Some(reason) => {
match reason {
SocResetReason::ChipPowerOn => {
"power on"
}
SocResetReason::CoreSw => {
"software reset"
}
SocResetReason::CoreDeepSleep => {
"deep sleep"
}
SocResetReason::CoreSDIO => {
"sdio reset"
}
SocResetReason::CoreMwdt0 => {
"Watchdog Main"
}
SocResetReason::CoreMwdt1 => {
"Watchdog 1"
}
SocResetReason::CoreRtcWdt => {
"Watchdog RTC"
}
SocResetReason::Cpu0Mwdt0 => {
"Watchdog MCpu0"
}
SocResetReason::Cpu0Sw => {
"software reset cpu0"
}
SocResetReason::Cpu0RtcWdt => {
init_rtc_store = true;
"Watchdog RTC cpu0"
}
SocResetReason::SysBrownOut => {
"sys brown out"
}
SocResetReason::SysRtcWdt => {
"Watchdog Sys rtc"
}
SocResetReason::Cpu0Mwdt1 => {
"cpu0 mwdt1"
}
SocResetReason::SysSuperWdt => {
"Watchdog Super"
}
SocResetReason::CoreEfuseCrc => {
"core efuse crc"
}
SocResetReason::CoreUsbUart => {
to_config_mode = true;
"core usb uart"
}
SocResetReason::CoreUsbJtag => {
"core usb jtag"
}
SocResetReason::Cpu0JtagCpu => {
"cpu0 jtag cpu"
}
}
}
};
LOG_ACCESS.lock().await.log(
LogMessage::ResetReason,
init_rtc_store as u32,
to_config_mode as u32,
"",
&format!("{reasons:?}"),
)
.await;
).await;
esp.init_rtc_deepsleep_memory(init_rtc_store, to_config_mode)
.await;
@ -430,32 +487,32 @@ impl PlantHal {
}
};
let board_hal: Box<dyn BoardInteraction + Send> = match config.hardware.board {
BoardVersion::INITIAL => {
let board_hal: Box<dyn BoardInteraction + Send> = //match config.hardware.board {
//BoardVersion::INITIAL => {
initial_hal::create_initial_board(free_pins, config, esp)?
}
;
//}
// BoardVersion::V3 => {
// v3_hal::create_v3(free_pins, esp, config, battery_interaction, rtc_module)?
// }
// BoardVersion::V4 => {
// v4_hal::create_v4(free_pins, esp, config, battery_interaction, rtc_module)?
// }
_ => {
todo!()
}
};
//BoardVersion::V4 => {
// v4_hal::create_v4(free_pins, esp, config, battery_interaction, rtc_module)?
//}
//_ => {
// todo!()
//}
//};
HAL { board_hal }
}
Err(err) => {
log(
LOG_ACCESS.lock().await.log(
LogMessage::ConfigModeMissingConfig,
0,
0,
"",
&err.to_string(),
)
.await;
).await;
HAL {
board_hal: initial_hal::create_initial_board(
free_pins,
@ -469,3 +526,12 @@ impl PlantHal {
Ok(Mutex::new(hal))
}
}
pub async fn esp_time() -> DateTime<Utc> {
DateTime::from_timestamp_micros(TIME_ACCESS.get().await.current_time_us() as i64).unwrap()
}
pub async fn esp_set_time(time: DateTime<FixedOffset>) {
TIME_ACCESS.get().await.set_current_time_us(time.timestamp_micros() as u64);
}

View File

@ -1,47 +1,122 @@
use crate::vec;
use alloc::string::ToString;
use alloc::vec::Vec;
use bytemuck::{AnyBitPattern, Contiguous, Pod, Zeroable};
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::lazy_lock::LazyLock;
use embassy_sync::mutex::Mutex;
use embassy_time::Instant;
use esp_println::println;
use esp_hal::Persistable;
use log::info;
use serde::Serialize;
use strum_macros::IntoStaticStr;
use ringbuffer::{ConstGenericRingBuffer, RingBuffer};
use unit_enum::UnitEnum;
use crate::hal::TIME_ACCESS;
#[esp_hal::ram(rtc_fast, persistent)]
static mut LOG_ARRAY: LogArray = LogArray {
buffer: [LogEntryInner { timestamp: 0, message_id: 0, a: 0, b: 0, txt_short: [0;TXT_SHORT_LENGTH], txt_long: [0;TXT_LONG_LENGTH] }; 256],
head: 0,
};
pub static LOG_ACCESS: Mutex<CriticalSectionRawMutex, LogArray> = Mutex::new(unsafe { LOG_ARRAY });
const TXT_SHORT_LENGTH: usize = 8;
const TXT_LONG_LENGTH: usize = 32;
const BUFFER_SIZE: usize = 220;
#[link_section = ".rtc.data"]
static mut BUFFER: ConstGenericRingBuffer<LogEntry, BUFFER_SIZE> =
ConstGenericRingBuffer::<LogEntry, BUFFER_SIZE>::new();
#[allow(static_mut_refs)]
static BUFFER_ACCESS: LazyLock<
Mutex<CriticalSectionRawMutex, &mut ConstGenericRingBuffer<LogEntry, BUFFER_SIZE>>,
> = LazyLock::new(|| unsafe { Mutex::new(&mut BUFFER) });
#[derive(Debug, Clone, Copy, AnyBitPattern)]
#[repr(C)]
pub struct LogArray{
buffer: [LogEntryInner; (u8::MAX_VALUE as usize) +1],
head: u8
}
#[derive(Serialize, Debug, Clone)]
unsafe impl Persistable for LogArray {}
unsafe impl Zeroable for LogEntryInner {}
unsafe impl Pod for LogEntryInner{}
#[derive(Debug, Clone, Copy)]
struct LogEntryInner {
pub timestamp: u64,
pub message_id: u16,
pub a: u32,
pub b: u32,
pub txt_short: [u8; TXT_SHORT_LENGTH],
pub txt_long: [u8; TXT_LONG_LENGTH],
}
#[derive(Serialize)]
pub struct LogEntry {
pub timestamp: u64,
pub message_id: u16,
pub a: u32,
pub b: u32,
pub txt_short: heapless::String<TXT_SHORT_LENGTH>,
pub txt_long: heapless::String<TXT_LONG_LENGTH>,
pub txt_short: alloc::string::String,
pub txt_long: alloc::string::String,
}
pub async fn init() {
unsafe {
BUFFER = ConstGenericRingBuffer::<LogEntry, BUFFER_SIZE>::new();
};
let mut access = BUFFER_ACCESS.get().lock().await;
access.drain().for_each(|_| {});
impl From<LogEntryInner> for LogEntry {
fn from(value: LogEntryInner) -> Self {
LogEntry{
timestamp: value.timestamp,
message_id: value.message_id,
a: value.a,
b: value.b,
txt_short: alloc::string::String::from_utf8_lossy_owned(value.txt_short.to_vec()),
txt_long: alloc::string::String::from_utf8_lossy_owned(value.txt_long.to_vec()),
}
}
}
impl LogArray {
pub fn get(&mut self) -> Vec<LogEntry> {
let mut rv: Vec<LogEntry> = Vec::new();
let mut index = self.head.wrapping_sub(1);
for _ in 0..self.buffer.len() {
let entry = self.buffer[index as usize];
if (entry.message_id as usize) != LogMessage::Empty.ordinal() {
rv.push(entry.into());
}
index = index.wrapping_sub(1);
}
rv
}
pub async fn log(
&mut self,
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);
let time = TIME_ACCESS.get().await.current_time_us()/1000;
let ordinal = message_key.ordinal() as u16;
let template: &str = message_key.into();
let mut template_string = template.to_string();
template_string = template_string.replace("${number_a}", number_a.to_string().as_str());
template_string = template_string.replace("${number_b}", number_b.to_string().as_str());
template_string = template_string.replace("${txt_long}", txt_long);
template_string = template_string.replace("${txt_short}", txt_short);
info!("{}", template_string);
let to_modify = &mut self.buffer[self.head as usize];
to_modify.timestamp = time;
to_modify.message_id = ordinal;
to_modify.a = number_a;
to_modify.b = number_b;
to_modify.txt_short.clone_from_slice(&txt_short_stack.as_bytes());
to_modify.txt_long.clone_from_slice(&txt_long_stack.as_bytes());
self.head = self.head.wrapping_add(1);
}
}
fn limit_length<const LIMIT: usize>(input: &str, target: &mut heapless::String<LIMIT>) {
@ -60,60 +135,19 @@ fn limit_length<const LIMIT: usize>(input: &str, target: &mut heapless::String<L
}
}
}
}
pub async fn get_log() -> Vec<LogEntry> {
let buffer = BUFFER_ACCESS.get().lock().await;
let mut read_copy = Vec::new();
for entry in buffer.iter() {
let copy = entry.clone();
read_copy.push(copy);
while target.len() < LIMIT {
target.push(' ').unwrap();
}
drop(buffer);
read_copy
}
pub async 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);
//TODO
let time = Instant::now().as_secs();
// let time = EspSystemTime {}.now().as_millis() as u64;
//
let ordinal = message_key.ordinal() as u16;
let template: &str = message_key.into();
let mut template_string = template.to_string();
template_string = template_string.replace("${number_a}", number_a.to_string().as_str());
template_string = template_string.replace("${number_b}", number_b.to_string().as_str());
template_string = template_string.replace("${txt_long}", txt_long);
template_string = template_string.replace("${txt_short}", txt_short);
info!("LOG: {} : {}", time, template_string);
let entry = LogEntry {
timestamp: time,
message_id: ordinal,
a: number_a,
b: number_b,
txt_short: txt_short_stack,
txt_long: txt_long_stack,
};
let mut buffer = BUFFER_ACCESS.get().lock().await;
buffer.push(entry);
}
#[derive(IntoStaticStr, Serialize, PartialEq, Eq, PartialOrd, Ord, Clone, UnitEnum)]
pub enum LogMessage {
#[strum(
serialize = ""
)]
Empty,
#[strum(
serialize = "Reset due to ${txt_long} requires rtc clear ${number_a} and force config mode ${number_b}"
)]

View File

@ -1,6 +1,7 @@
#![no_std]
#![no_main]
#![feature(never_type)]
#![feature(string_from_utf8_lossy_owned)]
#![deny(
clippy::mem_forget,
reason = "mem::forget is generally not safe to do with esp_hal types, especially those \
@ -35,9 +36,11 @@ use esp_hal::rom::ets_delay_us;
use esp_hal::system::software_reset;
use esp_println::{logger, println};
use hal::battery::BatteryState;
use log::{log, LogMessage};
use log::{ LogMessage};
use plant_state::PlantState;
use serde::{Deserialize, Serialize};
use crate::hal::esp_time;
use crate::log::LOG_ACCESS;
#[no_mangle]
extern "C" fn custom_halt() -> ! {
@ -180,6 +183,7 @@ async fn safe_main(spawner: Spawner) -> anyhow::Result<()> {
let _ota_state_string = "unknown";
board.board_hal.general_fault(false).await;
let time = esp_time().await;
let cur = board
.board_hal
.get_rtc_module()
@ -188,19 +192,19 @@ async fn safe_main(spawner: Spawner) -> anyhow::Result<()> {
.or_else(|err| {
info!("rtc module error: {:?}", err);
board.board_hal.general_fault(true);
anyhow::Ok(board.board_hal.get_esp().time())
anyhow::Ok(time)
})?;
//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_ACCESS.lock().await.log(LogMessage::YearInplausibleForceConfig, 0, 0, "", "").await;
}
info!("cur is {}", cur);
update_charge_indicator(&mut board).await;
println!("faul led3");
if board.board_hal.get_esp().get_restart_to_conf() {
log(LogMessage::ConfigModeSoftwareOverride, 0, 0, "", "").await;
LOG_ACCESS.lock().await.log(LogMessage::ConfigModeSoftwareOverride, 0, 0, "", "").await;
for _i in 0..2 {
board.board_hal.general_fault(true).await;
Timer::after_millis(100).await;
@ -212,7 +216,7 @@ async fn safe_main(spawner: Spawner) -> anyhow::Result<()> {
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_ACCESS.lock().await.log(LogMessage::ConfigModeButtonOverride, 0, 0, "", "").await;
for _i in 0..5 {
board.board_hal.general_fault(true).await;
Timer::after_millis(100).await;
@ -293,7 +297,7 @@ async fn safe_main(spawner: Spawner) -> anyhow::Result<()> {
let _ = publish_mppt_state(&mut board).await;
}
log(
LOG_ACCESS.lock().await.log(
LogMessage::StartupInfo,
matches!(network_mode, NetworkMode::WIFI { .. }) as u32,
matches!(
@ -307,8 +311,8 @@ async fn safe_main(spawner: Spawner) -> anyhow::Result<()> {
.to_string()
.as_str(),
"",
)
.await;
).await
;
if to_config {
//check if client or ap mode and init Wi-Fi
@ -319,7 +323,7 @@ async fn safe_main(spawner: Spawner) -> anyhow::Result<()> {
let board = BOARD_ACCESS.get().await.lock().await;
wait_infinity(board, WaitType::ConfigButton, reboot_now.clone()).await;
} else {
log(LogMessage::NormalRun, 0, 0, "", "").await;
LOG_ACCESS.lock().await.log(LogMessage::NormalRun, 0, 0, "", "").await;
}
let _dry_run = false;
@ -658,14 +662,14 @@ pub async fn do_secure_pump(
let high_current = current_ma > plant_config.max_pump_current_ma;
if high_current {
if first_error {
log(
LOG_ACCESS.lock().await.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;
).await
;
board.board_hal.general_fault(true).await;
board.board_hal.fault(plant_id, true).await?;
if !plant_config.ignore_current_error {
@ -678,14 +682,14 @@ pub async fn do_secure_pump(
let low_current = current_ma < plant_config.min_pump_current_ma;
if low_current {
if first_error {
log(
LOG_ACCESS.lock().await.log(
LogMessage::PumpOpenLoopCurrent,
plant_id as u32 + 1,
current_ma as u32,
plant_config.min_pump_current_ma.to_string().as_str(),
step.to_string().as_str(),
)
.await;
).await
;
board.board_hal.general_fault(true).await;
board.board_hal.fault(plant_id, true).await?;
if !plant_config.ignore_current_error {
@ -699,14 +703,14 @@ pub async fn do_secure_pump(
Err(err) => {
if !plant_config.ignore_current_error {
info!("Error getting pump current: {}", err);
log(
LOG_ACCESS.lock().await.log(
LogMessage::PumpMissingSensorCurrent,
plant_id as u32,
0,
"",
"",
)
.await;
).await
;
error = true;
break;
} else {
@ -1058,7 +1062,7 @@ async fn wait_infinity(
.lock()
.await
.board_hal
.deep_sleep(1);
.deep_sleep(0).await;
}
}
}

View File

@ -3,29 +3,30 @@
use crate::config::PlantControllerConfig;
use crate::{get_version, log::LogMessage, BOARD_ACCESS};
use alloc::borrow::ToOwned;
use alloc::fmt::format;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::sync::Arc;
use alloc::vec::Vec;
use anyhow::bail;
use anyhow::{bail};
use core::fmt::{Debug, Display};
use core::net::{IpAddr, Ipv4Addr, SocketAddr};
use core::result::Result::Ok;
use core::str::from_utf8;
use core::sync::atomic::{AtomicBool, Ordering};
use chrono::DateTime;
use edge_http::io::server::{Connection, Handler, Server};
use edge_http::io::Error;
use edge_http::Method;
use edge_nal::{TcpBind, TcpSplit};
use edge_nal::{TcpBind};
use edge_nal_embassy::{Tcp, TcpBuffers};
use embassy_net::Stack;
use embassy_time::Instant;
use embedded_io_async::{Read, Write};
use esp_println::println;
use littlefs2_core::Path;
use log::info;
use serde::{Deserialize, Serialize};
use crate::hal::{esp_set_time, esp_time};
use crate::log::{LOG_ACCESS};
#[derive(Serialize, Debug)]
struct SSIDList {
@ -72,25 +73,6 @@ pub struct NightLampCommand {
active: bool,
}
//
// fn write_time(
// request: &mut Request<&mut EspHttpConnection>,
// ) -> Result<Option<std::string::String>, anyhow::Error> {
// let actual_data = read_up_to_bytes_from_request(request, None)?;
// let time: SetTime = serde_json::from_slice(&actual_data)?;
// let parsed = DateTime::parse_from_rfc3339(time.time).map_err(|err| anyhow::anyhow!(err))?;
// let mut board = BOARD_ACCESS.lock().expect("board access");
//
// let now = timeval {
// tv_sec: parsed.to_utc().timestamp(),
// tv_usec: 0,
// };
// unsafe { settimeofday(&now, core::ptr::null_mut()) };
// board
// .board_hal
// .get_rtc_module()
// .set_rtc_time(&parsed.to_utc())?;
// anyhow::Ok(None)
// }
//
//
@ -430,12 +412,10 @@ impl Handler for HttpHandler {
conn.write_all(include_bytes!("bundle.js")).await?;
Some(200)
}
"/reboot" => {
let mut board = BOARD_ACCESS.get().await.lock().await;
board.board_hal.get_esp().set_restart_to_conf(true);
self.reboot_now.store(true, Ordering::Relaxed);
"/log" => {
let buf = get_log(conn).await;
Some(200)
}
},
&_ => {
let json = match path {
"/version" => Some(get_version_web(conn).await),
@ -445,7 +425,6 @@ impl Handler for HttpHandler {
"/get_config" => Some(get_config(conn).await),
"/files" => Some(list_files(conn).await),
"/log_localization" => Some(get_log_localization_config(conn).await),
"/log" => Some(get_log(conn).await),
"/wifiscan" => Some(wifi_scan(conn).await),
_ => None,
};
@ -459,6 +438,13 @@ impl Handler for HttpHandler {
let json = match path {
"/wifiscan" => Some(wifi_scan(conn).await),
"/set_config" => Some(set_config(conn).await),
"/time" => Some(write_time(conn).await),
"/reboot" => {
let mut board = BOARD_ACCESS.get().await.lock().await;
board.board_hal.get_esp().set_restart_to_conf(true);
self.reboot_now.store(true, Ordering::Relaxed);
Some(Ok(None))
}
_ => None,
};
match json {
@ -568,6 +554,20 @@ impl Handler for HttpHandler {
// })
// .unwrap();
async fn write_time<T, const N: usize>(
request: &mut Connection<'_, T, N>,
) -> Result<Option<String>, anyhow::Error>
where
T: Read + Write
{
let actual_data = read_up_to_bytes_from_request(request, None).await?;
let time: SetTime = serde_json::from_slice(&actual_data)?;
let parsed = DateTime::parse_from_rfc3339(time.time).unwrap();
esp_set_time(parsed).await;
anyhow::Ok(None)
}
async fn set_config<T, const N: usize>(
request: &mut Connection<'_, T, N>,
) -> Result<Option<String>, anyhow::Error>
@ -633,10 +633,30 @@ async fn wifi_scan<T, const N: usize>(
}
async fn get_log<T, const N: usize>(
_request: &mut Connection<'_, T, N>,
) -> Result<Option<String>, anyhow::Error> {
let output = crate::log::get_log().await;
anyhow::Ok(Some(serde_json::to_string(&output)?))
conn: &mut Connection<'_, T, N>,
) -> anyhow::Result<()>
where
T: Read + Write,{
let log = LOG_ACCESS.lock().await.get();
conn.initiate_response(
200,
Some("OK"),
&[("Content-Type", "text/javascript")],
)
.await
.unwrap();
conn.write_all("[".as_bytes()).await.unwrap();
let mut append = false;
for entry in log {
if append {
conn.write_all(",".as_bytes()).await.unwrap();
}
append = true;
let json = serde_json::to_string(&entry)?;
conn.write_all(json.as_bytes()).await.unwrap();
}
conn.write_all("]".as_bytes()).await.unwrap();
Ok(())
}
async fn get_log_localization_config<T, const N: usize>(
@ -698,16 +718,17 @@ async fn get_time<T, const N: usize>(
) -> Result<Option<String>, anyhow::Error> {
let mut board = BOARD_ACCESS.get().await.lock().await;
//TODO do not fail if rtc module is missing
let native = board.board_hal.get_esp().time().to_rfc3339();
let rtc = board
.board_hal
.get_rtc_module()
.get_rtc_time()
.await?
.to_rfc3339();
let native = esp_time().await.to_rfc3339();
let rtc = "todo";
// board
// .board_hal
// .get_rtc_module()
// .get_rtc_time()
// .await?
// .to_rfc3339();
let data = LoadData {
rtc: rtc.as_str(),
rtc,
native: native.as_str(),
};
let json = serde_json::to_string(&data)?;