adda lot of basic webserver back
This commit is contained in:
parent
049a9d027c
commit
65f6670ca4
@ -83,7 +83,7 @@ esp-println = { version = "0.15.0", features = ["esp32c6", "log-04"] }
|
|||||||
# for more networking protocol support see https://crates.io/crates/edge-net
|
# for more networking protocol support see https://crates.io/crates/edge-net
|
||||||
embassy-executor = { version = "0.7.0", features = [
|
embassy-executor = { version = "0.7.0", features = [
|
||||||
"log",
|
"log",
|
||||||
"task-arena-size-20480",
|
"task-arena-size-262144"
|
||||||
] }
|
] }
|
||||||
embassy-time = { version = "0.5.0", features = ["log"] }
|
embassy-time = { version = "0.5.0", features = ["log"] }
|
||||||
esp-hal-embassy = { version = "0.9.0", features = ["esp32c6", "log-04"] }
|
esp-hal-embassy = { version = "0.9.0", features = ["esp32c6", "log-04"] }
|
||||||
@ -158,6 +158,7 @@ edge-nal = "0.5.0"
|
|||||||
edge-nal-embassy = "0.6.0"
|
edge-nal-embassy = "0.6.0"
|
||||||
static_cell = "2.1.1"
|
static_cell = "2.1.1"
|
||||||
cfg-if = "1.0.3"
|
cfg-if = "1.0.3"
|
||||||
|
edge-http = { version = "0.6.1", features = ["log"] }
|
||||||
|
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::hal::Box;
|
use crate::hal::Box;
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use core::error::Error;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@ -17,6 +18,12 @@ pub trait BatteryInteraction {
|
|||||||
async fn get_battery_state(&mut self) -> Result<BatteryState, BatteryError>;
|
async fn get_battery_state(&mut self) -> Result<BatteryState, BatteryError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<BatteryError> for anyhow::Error {
|
||||||
|
fn from(err: BatteryError) -> Self {
|
||||||
|
anyhow::anyhow!(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub struct BatteryInfo {
|
pub struct BatteryInfo {
|
||||||
pub voltage_milli_volt: u16,
|
pub voltage_milli_volt: u16,
|
||||||
|
@ -76,6 +76,7 @@ pub struct Esp<'a> {
|
|||||||
pub slot: usize,
|
pub slot: usize,
|
||||||
pub next_slot: usize,
|
pub next_slot: usize,
|
||||||
pub ota_state: OtaImageState,
|
pub ota_state: OtaImageState,
|
||||||
|
pub slot_addres: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IpInfo {
|
pub struct IpInfo {
|
||||||
@ -200,7 +201,7 @@ impl Esp<'_> {
|
|||||||
let (stack, runner) = embassy_net::new(
|
let (stack, runner) = embassy_net::new(
|
||||||
device,
|
device,
|
||||||
config,
|
config,
|
||||||
mk_static!(StackResources<3>, StackResources::<3>::new()),
|
mk_static!(StackResources<4>, StackResources::<4>::new()),
|
||||||
seed,
|
seed,
|
||||||
);
|
);
|
||||||
let stack = mk_static!(Stack, stack);
|
let stack = mk_static!(Stack, stack);
|
||||||
|
@ -35,7 +35,9 @@ use embassy_net::{IpListenEndpoint, Ipv4Cidr, Runner, Stack, StackResources, Sta
|
|||||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
use embassy_sync::once_lock::OnceLock;
|
use embassy_sync::once_lock::OnceLock;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use esp_bootloader_esp_idf::partitions::DataPartitionSubType;
|
use esp_bootloader_esp_idf::partitions::{
|
||||||
|
AppPartitionSubType, DataPartitionSubType, PartitionEntry,
|
||||||
|
};
|
||||||
use esp_hal::clock::CpuClock;
|
use esp_hal::clock::CpuClock;
|
||||||
use esp_hal::gpio::{Input, InputConfig, Io, Pull};
|
use esp_hal::gpio::{Input, InputConfig, Io, Pull};
|
||||||
use esp_hal::timer::systimer::SystemTimer;
|
use esp_hal::timer::systimer::SystemTimer;
|
||||||
@ -286,6 +288,23 @@ impl PlantHal {
|
|||||||
println!("current {:?} - next {:?}", current, current.next());
|
println!("current {:?} - next {:?}", current, current.next());
|
||||||
let ota_state = ota.current_ota_state()?;
|
let ota_state = ota.current_ota_state()?;
|
||||||
|
|
||||||
|
let current_app = if current.number() == 0 {
|
||||||
|
pt.find_partition(esp_bootloader_esp_idf::partitions::PartitionType::App(
|
||||||
|
AppPartitionSubType::Ota0,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
pt.find_partition(esp_bootloader_esp_idf::partitions::PartitionType::App(
|
||||||
|
AppPartitionSubType::Ota1,
|
||||||
|
))
|
||||||
|
};
|
||||||
|
let app_address = match current_app {
|
||||||
|
Result::Ok(part) => match part {
|
||||||
|
None => 0,
|
||||||
|
Some(entry) => entry.offset(),
|
||||||
|
},
|
||||||
|
Err(_) => 0,
|
||||||
|
};
|
||||||
|
|
||||||
let mut esp = Esp {
|
let mut esp = Esp {
|
||||||
rng,
|
rng,
|
||||||
controller: Some(controller),
|
controller: Some(controller),
|
||||||
@ -294,6 +313,7 @@ impl PlantHal {
|
|||||||
mqtt_client: None,
|
mqtt_client: None,
|
||||||
storage,
|
storage,
|
||||||
slot: current.number(),
|
slot: current.number(),
|
||||||
|
slot_addres: app_address,
|
||||||
next_slot: current.next().number(),
|
next_slot: current.next().number(),
|
||||||
ota_state,
|
ota_state,
|
||||||
wall_clock_offset: 0,
|
wall_clock_offset: 0,
|
||||||
|
@ -147,15 +147,14 @@ async fn safe_main(spawner: Spawner) -> anyhow::Result<()> {
|
|||||||
info!("Startup Rust");
|
info!("Startup Rust");
|
||||||
|
|
||||||
let mut to_config = false;
|
let mut to_config = false;
|
||||||
|
let mut board = BOARD_ACCESS.get().await.lock().await;
|
||||||
|
|
||||||
let version = get_version();
|
let version = get_version(&mut board).await;
|
||||||
info!(
|
info!(
|
||||||
"Version using git has {} build on {}",
|
"Version using git has {} build on {}",
|
||||||
version.git_hash, version.build_time
|
version.git_hash, version.build_time
|
||||||
);
|
);
|
||||||
|
|
||||||
let _esp = BOARD_ACCESS.get().await.lock().await.board_hal.get_esp();
|
|
||||||
|
|
||||||
//TODO
|
//TODO
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
@ -179,7 +178,7 @@ async fn safe_main(spawner: Spawner) -> anyhow::Result<()> {
|
|||||||
//};
|
//};
|
||||||
//log(LogMessage::PartitionState, 0, 0, "", ota_state_string);
|
//log(LogMessage::PartitionState, 0, 0, "", ota_state_string);
|
||||||
let _ota_state_string = "unknown";
|
let _ota_state_string = "unknown";
|
||||||
let mut board = BOARD_ACCESS.get().await.lock().await;
|
|
||||||
board.board_hal.general_fault(false).await;
|
board.board_hal.general_fault(false).await;
|
||||||
let cur = board
|
let cur = board
|
||||||
.board_hal
|
.board_hal
|
||||||
@ -1117,15 +1116,16 @@ pub fn in_time_range(cur: &DateTime<Tz>, start: u8, end: u8) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_version() -> VersionInfo {
|
async fn get_version(
|
||||||
|
board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'static>>,
|
||||||
|
) -> VersionInfo {
|
||||||
let branch = env!("VERGEN_GIT_BRANCH").to_owned();
|
let branch = env!("VERGEN_GIT_BRANCH").to_owned();
|
||||||
let hash = &env!("VERGEN_GIT_SHA")[0..8];
|
let hash = &env!("VERGEN_GIT_SHA")[0..8];
|
||||||
|
|
||||||
//TODO
|
let board = board.board_hal.get_esp();
|
||||||
//let running_partition = unsafe { esp_ota_get_running_partition() };
|
let ota_slot = board.slot;
|
||||||
let address = 0;
|
let address = board.slot_addres;
|
||||||
//let address = unsafe { (*running_partition).address };
|
let partition = if ota_slot == 0 {
|
||||||
let partition = if address > 100000 {
|
|
||||||
"ota_1 @ "
|
"ota_1 @ "
|
||||||
} else {
|
} else {
|
||||||
"ota_0 @ "
|
"ota_0 @ "
|
||||||
|
@ -6,22 +6,32 @@ use crate::{
|
|||||||
hal::PLANT_COUNT,
|
hal::PLANT_COUNT,
|
||||||
log::LogMessage,
|
log::LogMessage,
|
||||||
plant_state::{MoistureSensorState, PlantState},
|
plant_state::{MoistureSensorState, PlantState},
|
||||||
BOARD_ACCESS,
|
VersionInfo, BOARD_ACCESS,
|
||||||
};
|
};
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::string::String;
|
use alloc::string::{String, ToString};
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use anyhow::{bail, Context};
|
use anyhow::{bail, Context};
|
||||||
use chrono::DateTime;
|
use chrono::DateTime;
|
||||||
|
use core::fmt::{Debug, Display, Pointer};
|
||||||
|
use core::future::Future;
|
||||||
|
use core::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
use core::result::Result::Ok;
|
use core::result::Result::Ok;
|
||||||
use core::sync::atomic::AtomicBool;
|
use core::sync::atomic::AtomicBool;
|
||||||
|
use edge_http::io::server::{Connection, DefaultServer, Handler, Server};
|
||||||
|
use edge_http::io::Error;
|
||||||
|
use edge_http::Method;
|
||||||
|
use edge_nal::TcpBind;
|
||||||
|
use edge_nal_embassy::{Tcp, TcpAccept, TcpBuffers};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_net::tcp::TcpSocket;
|
use embassy_net::tcp::TcpSocket;
|
||||||
use embassy_net::{IpListenEndpoint, Stack};
|
use embassy_net::{IpListenEndpoint, Stack};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Instant, Timer};
|
||||||
|
use embedded_io_async::{Read, Write};
|
||||||
use esp_println::{print, println};
|
use esp_println::{print, println};
|
||||||
use esp_wifi::wifi::WifiController;
|
use esp_wifi::wifi::WifiController;
|
||||||
|
use log::info;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
@ -89,31 +99,7 @@ pub struct NightLampCommand {
|
|||||||
// anyhow::Ok(None)
|
// anyhow::Ok(None)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// fn get_time(
|
|
||||||
// _request: &mut Request<&mut EspHttpConnection>,
|
|
||||||
// ) -> Result<Option<std::string::String>, anyhow::Error> {
|
|
||||||
// let mut board = BOARD_ACCESS.lock().expect("board access");
|
|
||||||
// let native = board
|
|
||||||
// .board_hal
|
|
||||||
// .get_esp()
|
|
||||||
// .time()
|
|
||||||
// .map(|t| t.to_rfc3339())
|
|
||||||
// .unwrap_or("error".to_string());
|
|
||||||
// let rtc = board
|
|
||||||
// .board_hal
|
|
||||||
// .get_rtc_module()
|
|
||||||
// .get_rtc_time()
|
|
||||||
// .map(|t| t.to_rfc3339())
|
|
||||||
// .unwrap_or("error".to_string());
|
|
||||||
//
|
|
||||||
// let data = LoadData {
|
|
||||||
// rtc: rtc.as_str(),
|
|
||||||
// native: native.as_str(),
|
|
||||||
// };
|
|
||||||
// let json = serde_json::to_string(&data)?;
|
|
||||||
//
|
|
||||||
// anyhow::Ok(Some(json))
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// fn get_timezones(
|
// fn get_timezones(
|
||||||
// _request: &mut Request<&mut EspHttpConnection>,
|
// _request: &mut Request<&mut EspHttpConnection>,
|
||||||
@ -231,25 +217,9 @@ pub struct NightLampCommand {
|
|||||||
// anyhow::Ok(Some("saved".to_owned()))
|
// anyhow::Ok(Some("saved".to_owned()))
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// fn get_solar_state(
|
|
||||||
// _request: &mut Request<&mut EspHttpConnection>,
|
|
||||||
// ) -> Result<Option<std::string::String>, anyhow::Error> {
|
|
||||||
// let mut board = BOARD_ACCESS.lock().expect("board access");
|
|
||||||
// let state = SolarState {
|
|
||||||
// mppt_voltage: board.board_hal.get_mptt_voltage()?.as_millivolts() as f32,
|
|
||||||
// mppt_current: board.board_hal.get_mptt_current()?.as_milliamperes() as f32,
|
|
||||||
// is_day: board.board_hal.is_day(),
|
|
||||||
// };
|
|
||||||
// anyhow::Ok(Some(serde_json::to_string(&state)?))
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// fn get_battery_state(
|
|
||||||
// _request: &mut Request<&mut EspHttpConnection>,
|
|
||||||
// ) -> Result<Option<std::string::String>, anyhow::Error> {
|
|
||||||
// let mut board = BOARD_ACCESS.lock().expect("board access");
|
|
||||||
// let battery_state = board.board_hal.get_battery_monitor().get_battery_state();
|
|
||||||
// anyhow::Ok(Some(serde_json::to_string(&battery_state)?))
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// fn get_log(
|
// fn get_log(
|
||||||
// _request: &mut Request<&mut EspHttpConnection>,
|
// _request: &mut Request<&mut EspHttpConnection>,
|
||||||
@ -264,11 +234,7 @@ pub struct NightLampCommand {
|
|||||||
// )?)
|
// )?)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// fn get_version_web(
|
|
||||||
// _request: &mut Request<&mut EspHttpConnection>,
|
|
||||||
// ) -> Result<Option<std::string::String>, anyhow::Error> {
|
|
||||||
// anyhow::Ok(Some(serde_json::to_string(&get_version())?))
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// fn pump_test(
|
// fn pump_test(
|
||||||
// request: &mut Request<&mut EspHttpConnection>,
|
// request: &mut Request<&mut EspHttpConnection>,
|
||||||
@ -323,16 +289,7 @@ pub struct NightLampCommand {
|
|||||||
// anyhow::Ok(Some(ssid_json))
|
// anyhow::Ok(Some(ssid_json))
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// fn list_files(
|
|
||||||
// _request: &mut Request<&mut EspHttpConnection>,
|
|
||||||
// ) -> Result<Option<std::string::String>, anyhow::Error> {
|
|
||||||
// let mut board = BOARD_ACCESS
|
|
||||||
// .lock()
|
|
||||||
// .expect("It should be possible to lock the board for exclusive fs access");
|
|
||||||
// let result = board.board_hal.get_esp().list_files();
|
|
||||||
// let file_list_json = serde_json::to_string(&result)?;
|
|
||||||
// anyhow::Ok(Some(file_list_json))
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// fn ota(
|
// fn ota(
|
||||||
// request: &mut Request<&mut EspHttpConnection>,
|
// request: &mut Request<&mut EspHttpConnection>,
|
||||||
@ -390,82 +347,175 @@ pub struct NightLampCommand {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
#[embassy_executor::task]
|
struct HttpHandler;
|
||||||
pub async fn httpd(reboot_now: Arc<AtomicBool>, stack: Stack<'static>) {
|
|
||||||
let mut rx_buffer = [0; 1536];
|
|
||||||
let mut tx_buffer = [0; 1536];
|
|
||||||
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
|
|
||||||
socket.set_keep_alive(Some(Duration::from_secs(30)));
|
|
||||||
socket.set_timeout(Some(Duration::from_secs(5)));
|
|
||||||
|
|
||||||
loop {
|
impl Handler for HttpHandler {
|
||||||
println!("Wait for connection...");
|
type Error<E>
|
||||||
let r = socket
|
= Error<E>
|
||||||
.accept(IpListenEndpoint {
|
where
|
||||||
addr: None,
|
E: Debug;
|
||||||
port: 8080,
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
println!("Connected...");
|
|
||||||
|
|
||||||
if let Err(e) = r {
|
async fn handle<'a, T, const N: usize>(
|
||||||
println!("connect error: {:?}", e);
|
&self,
|
||||||
continue;
|
_task_id: impl Display + Copy,
|
||||||
}
|
conn: &mut Connection<'a, T, N>,
|
||||||
|
) -> anyhow::Result<(), Self::Error<T::Error>>
|
||||||
|
where
|
||||||
|
T: Read + Write,
|
||||||
|
{
|
||||||
|
let start = Instant::now();
|
||||||
|
let headers = conn.headers()?;
|
||||||
|
|
||||||
use embedded_io_async::Write;
|
let method = headers.method;
|
||||||
|
let path = headers.path;
|
||||||
|
|
||||||
let mut buffer = [0u8; 1024];
|
let status = match method {
|
||||||
let mut pos = 0;
|
Method::Get => match path {
|
||||||
loop {
|
"/favicon.ico" => {
|
||||||
match socket.read(&mut buffer).await {
|
conn.initiate_response(200, Some("OK"), &[("Content-Type", "image/x-icon")])
|
||||||
core::result::Result::Ok(len) => {
|
.await?;
|
||||||
if len == 0 {
|
conn.write_all(include_bytes!("favicon.ico")).await?;
|
||||||
println!("read EOF");
|
Some(200)
|
||||||
break;
|
}
|
||||||
} else {
|
"/" => {
|
||||||
let to_print =
|
conn.initiate_response(200, Some("OK"), &[("Content-Type", "text/html")])
|
||||||
unsafe { core::str::from_utf8_unchecked(&buffer[..(pos + len)]) };
|
.await?;
|
||||||
|
conn.write_all(include_bytes!("index.html")).await?;
|
||||||
if to_print.contains("\r\n\r\n") {
|
Some(200)
|
||||||
print!("{}", to_print);
|
}
|
||||||
println!();
|
"/bundle.js" => {
|
||||||
break;
|
conn.initiate_response(200, Some("OK"), &[("Content-Type", "text/javascript")])
|
||||||
}
|
.await?;
|
||||||
|
conn.write_all(include_bytes!("bundle.js")).await?;
|
||||||
pos += len;
|
Some(200)
|
||||||
|
}
|
||||||
|
&_ => {
|
||||||
|
let json = match path {
|
||||||
|
"/version" => Some(get_version_web(conn).await),
|
||||||
|
"/time" => Some(get_time(conn).await),
|
||||||
|
"/battery" => Some(get_battery_state(conn).await),
|
||||||
|
"/solar" => Some(get_solar_state(conn).await),
|
||||||
|
"/get_config" => Some(get_config(conn).await),
|
||||||
|
"/files" => Some(list_files(conn).await),
|
||||||
|
"/log_localization" => Some(get_log_localization_config(conn).await),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
match json {
|
||||||
|
None => None,
|
||||||
|
Some(json) => Some(handle_json(conn, json).await?),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
},
|
||||||
println!("read error: {:?}", e);
|
Method::Options | Method::Delete | Method::Head | Method::Post | Method::Put => None,
|
||||||
break;
|
_ => None,
|
||||||
}
|
};
|
||||||
};
|
let code = match status {
|
||||||
}
|
None => {
|
||||||
let r = socket
|
conn.initiate_response(404, Some("Not found"), &[]).await?;
|
||||||
.write_all(
|
404
|
||||||
b"HTTP/1.0 200 OK\r\n\r\n\
|
}
|
||||||
<html>\
|
Some(code) => code,
|
||||||
<body>\
|
};
|
||||||
<h1>Hello Rust! Hello esp-wifi!</h1>\
|
|
||||||
</body>\
|
|
||||||
</html>\r\n\
|
|
||||||
",
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
if let Err(e) = r {
|
|
||||||
println!("write error: {:?}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
let r = socket.flush().await;
|
conn.complete().await?;
|
||||||
if let Err(e) = r {
|
let response_time = Instant::now().duration_since(start).as_millis();
|
||||||
println!("flush error: {:?}", e);
|
|
||||||
}
|
info!("\"{method} {path}\" {code} {response_time}ms");
|
||||||
Timer::after_millis(100).await;
|
Ok(())
|
||||||
socket.close();
|
|
||||||
Timer::after_millis(100).await;
|
|
||||||
socket.abort();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_log_localization_config<T, const N: usize>(
|
||||||
|
_request: &mut Connection<'_, T, N>,
|
||||||
|
) -> Result<Option<String>, anyhow::Error> {
|
||||||
|
anyhow::Ok(Some(serde_json::to_string(
|
||||||
|
&LogMessage::to_log_localisation_config(),
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
async fn list_files<T, const N: usize>(
|
||||||
|
_request: &mut Connection<'_, T, N>,
|
||||||
|
) -> Result<Option<String>, anyhow::Error> {
|
||||||
|
let mut board = BOARD_ACCESS.get().await.lock().await;
|
||||||
|
let result = board.board_hal.get_esp().list_files().await;
|
||||||
|
let file_list_json = serde_json::to_string(&result)?;
|
||||||
|
anyhow::Ok(Some(file_list_json))
|
||||||
|
}
|
||||||
|
async fn get_config<T, const N: usize>(
|
||||||
|
_request: &mut Connection<'_, T, N>,
|
||||||
|
) -> Result<Option<String>, anyhow::Error> {
|
||||||
|
let mut board = BOARD_ACCESS.get().await.lock().await;
|
||||||
|
let json = serde_json::to_string(&board.board_hal.get_config())?;
|
||||||
|
anyhow::Ok(Some(json))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_solar_state<T, const N: usize>(
|
||||||
|
_request: &mut Connection<'_, T, N>,
|
||||||
|
) -> Result<Option<String>, anyhow::Error> {
|
||||||
|
let mut board = BOARD_ACCESS.get().await.lock().await;
|
||||||
|
let state = SolarState {
|
||||||
|
mppt_voltage: board.board_hal.get_mptt_voltage().await?.as_millivolts() as f32,
|
||||||
|
mppt_current: board.board_hal.get_mptt_current().await?.as_milliamperes() as f32,
|
||||||
|
is_day: board.board_hal.is_day(),
|
||||||
|
};
|
||||||
|
anyhow::Ok(Some(serde_json::to_string(&state)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_battery_state<T, const N: usize>(
|
||||||
|
_request: &mut Connection<'_, T, N>,
|
||||||
|
) -> Result<Option<String>, anyhow::Error> {
|
||||||
|
let mut board = BOARD_ACCESS.get().await.lock().await;
|
||||||
|
let battery_state = board
|
||||||
|
.board_hal
|
||||||
|
.get_battery_monitor()
|
||||||
|
.get_battery_state()
|
||||||
|
.await?;
|
||||||
|
anyhow::Ok(Some(serde_json::to_string(&battery_state)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_version_web<T, const N: usize>(
|
||||||
|
_request: &mut Connection<'_, T, N>,
|
||||||
|
) -> Result<Option<String>, anyhow::Error> {
|
||||||
|
let mut board = BOARD_ACCESS.get().await.lock().await;
|
||||||
|
anyhow::Ok(Some(serde_json::to_string(&get_version(&mut board).await)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_time<T, const N: usize>(
|
||||||
|
_request: &mut Connection<'_, T, N>,
|
||||||
|
) -> 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 data = LoadData {
|
||||||
|
rtc: rtc.as_str(),
|
||||||
|
native: native.as_str(),
|
||||||
|
};
|
||||||
|
let json = serde_json::to_string(&data)?;
|
||||||
|
|
||||||
|
anyhow::Ok(Some(json))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
pub async fn httpd(reboot_now: Arc<AtomicBool>, stack: Stack<'static>) {
|
||||||
|
let buffer: TcpBuffers<2, 1024, 1024> = TcpBuffers::new();
|
||||||
|
let tcp = Tcp::new(stack, &buffer);
|
||||||
|
let acceptor = tcp
|
||||||
|
.bind(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8080))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut server: Server<2, 512, 10> = Server::new();
|
||||||
|
server
|
||||||
|
.run(Some(5000), acceptor, HttpHandler)
|
||||||
|
.await
|
||||||
|
.expect("TODO: panic message");
|
||||||
|
println!("Wait for connection...");
|
||||||
|
|
||||||
// let server_config = Configuration {
|
// let server_config = Configuration {
|
||||||
// stack_size: 32768,
|
// stack_size: 32768,
|
||||||
@ -805,3 +855,61 @@ pub async fn httpd(reboot_now: Arc<AtomicBool>, stack: Stack<'static>) {
|
|||||||
// log::info!("Raw data {}", from_utf8(&allvec)?);
|
// log::info!("Raw data {}", from_utf8(&allvec)?);
|
||||||
// Ok(allvec)
|
// Ok(allvec)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
async fn handle_json<'a, T, const N: usize>(
|
||||||
|
conn: &mut Connection<'a, T, N>,
|
||||||
|
chain: anyhow::Result<Option<String>>,
|
||||||
|
) -> anyhow::Result<u32, Error<T::Error>>
|
||||||
|
where
|
||||||
|
T: Read + Write,
|
||||||
|
<T as embedded_io_async::ErrorType>::Error: Debug,
|
||||||
|
{
|
||||||
|
match chain {
|
||||||
|
Ok(answer) => match answer {
|
||||||
|
Some(json) => {
|
||||||
|
conn.initiate_response(
|
||||||
|
200,
|
||||||
|
Some("OK"),
|
||||||
|
&[
|
||||||
|
("Access-Control-Allow-Origin", "*"),
|
||||||
|
("Access-Control-Allow-Headers", "*"),
|
||||||
|
("Access-Control-Allow-Methods", "*"),
|
||||||
|
("Content-Type", "application/json"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
conn.write_all(json.as_bytes()).await?;
|
||||||
|
Ok(200)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
conn.initiate_response(
|
||||||
|
200,
|
||||||
|
Some("OK"),
|
||||||
|
&[
|
||||||
|
("Access-Control-Allow-Origin", "*"),
|
||||||
|
("Access-Control-Allow-Headers", "*"),
|
||||||
|
("Access-Control-Allow-Methods", "*"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(200)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
let error_text = err.to_string();
|
||||||
|
info!("error handling process {}", error_text);
|
||||||
|
conn.initiate_response(
|
||||||
|
500,
|
||||||
|
Some("OK"),
|
||||||
|
&[
|
||||||
|
("Access-Control-Allow-Origin", "*"),
|
||||||
|
("Access-Control-Allow-Headers", "*"),
|
||||||
|
("Access-Control-Allow-Methods", "*"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
conn.write_all(error_text.as_bytes()).await?;
|
||||||
|
Ok(500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user