initial file browser work
This commit is contained in:
parent
8218c4b9a6
commit
9f249af430
@ -87,7 +87,7 @@ eeprom24x = "0.7.2"
|
|||||||
#esp-idf-sys = { git = "https://github.com/esp-rs/esp-idf-sys.git" }
|
#esp-idf-sys = { git = "https://github.com/esp-rs/esp-idf-sys.git" }
|
||||||
#esp-idf-svc = { git = "https://github.com/esp-rs/esp-idf-svc.git" }
|
#esp-idf-svc = { git = "https://github.com/esp-rs/esp-idf-svc.git" }
|
||||||
ds323x = { git = "https://github.com/empirephoenix/ds323x-rs.git" }
|
ds323x = { git = "https://github.com/empirephoenix/ds323x-rs.git" }
|
||||||
bq34z100 = { path = "../../bq34z100_rust" }
|
#bq34z100 = { path = "../../bq34z100_rust" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
embuild = "0.32.0"
|
embuild = "0.32.0"
|
||||||
|
@ -26,8 +26,10 @@ use plant_ctrl2::sipo::ShiftRegister40;
|
|||||||
|
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
use anyhow::{bail, Ok, Result};
|
use anyhow::{bail, Ok, Result};
|
||||||
|
use serde::Serialize;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::fs::File;
|
use std::fs::{self, DirEntry, File};
|
||||||
|
use std::io::{Read, Write};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
@ -60,6 +62,7 @@ const REPEAT_MOIST_MEASURE: usize = 1;
|
|||||||
|
|
||||||
const SPIFFS_PARTITION_NAME: &str = "storage";
|
const SPIFFS_PARTITION_NAME: &str = "storage";
|
||||||
const CONFIG_FILE: &str = "/spiffs/config.cfg";
|
const CONFIG_FILE: &str = "/spiffs/config.cfg";
|
||||||
|
const BASE_PATH: &str = "/spiffs";
|
||||||
|
|
||||||
const TANK_MULTI_SAMPLE: usize = 11;
|
const TANK_MULTI_SAMPLE: usize = 11;
|
||||||
|
|
||||||
@ -165,7 +168,34 @@ pub struct PlantCtrlBoard<'a> {
|
|||||||
>,
|
>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Debug)]
|
||||||
|
pub struct FileInfo{
|
||||||
|
filename:String,
|
||||||
|
size:usize
|
||||||
|
}
|
||||||
|
|
||||||
impl PlantCtrlBoard<'_> {
|
impl PlantCtrlBoard<'_> {
|
||||||
|
pub fn list_files(&self) -> Result<Vec<FileInfo>> {
|
||||||
|
let spiffs = Path::new(BASE_PATH);
|
||||||
|
let list = fs::read_dir(spiffs).unwrap().map(|dir| {
|
||||||
|
let file = dir.unwrap();
|
||||||
|
FileInfo{
|
||||||
|
filename: file.file_name().into_string().unwrap(),
|
||||||
|
size: file.metadata().unwrap().len() as usize
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Ok(list.collect());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_file_handle(&self, filename:String, write:bool) -> Result<File> {
|
||||||
|
let filepath = Path::new(BASE_PATH).join(Path::new(&filename));
|
||||||
|
return Ok(if write {
|
||||||
|
File::create(filepath)?
|
||||||
|
} else {
|
||||||
|
File::open(filepath)?
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_day(&self) -> bool {
|
pub fn is_day(&self) -> bool {
|
||||||
self.solar_is_day.get_level().into()
|
self.solar_is_day.get_level().into()
|
||||||
}
|
}
|
||||||
|
@ -2,17 +2,17 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
io::{BufRead, Read, Write},
|
io::{BufRead, Read, Seek, Write},
|
||||||
str::from_utf8,
|
str::from_utf8,
|
||||||
sync::{atomic::AtomicBool, Arc},
|
sync::{atomic::AtomicBool, Arc},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{espota::OtaUpdate, map_range_moisture, plant_hal::PLANT_COUNT, BOARD_ACCESS};
|
use crate::{espota::OtaUpdate, map_range_moisture, plant_hal::{FileInfo, PLANT_COUNT}, BOARD_ACCESS};
|
||||||
use chrono::DateTime;
|
use chrono::DateTime;
|
||||||
use core::result::Result::Ok;
|
use core::result::Result::Ok;
|
||||||
use embedded_svc::http::Method;
|
use embedded_svc::http::{Method, Query};
|
||||||
use esp_idf_hal::delay::Delay;
|
use esp_idf_hal::{delay::Delay, io::Write};
|
||||||
use esp_idf_svc::http::server::{Configuration, EspHttpConnection, EspHttpServer, Request};
|
use esp_idf_svc::{fs, http::server::{Configuration, EspHttpConnection, EspHttpServer, Request}};
|
||||||
use heapless::String;
|
use heapless::String;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -23,6 +23,11 @@ struct SSIDList<'a> {
|
|||||||
ssids: Vec<&'a String<32>>,
|
ssids: Vec<&'a String<32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Debug)]
|
||||||
|
struct FileList {
|
||||||
|
file: Vec<FileInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
struct VersionInfo<'a> {
|
struct VersionInfo<'a> {
|
||||||
git_hash: &'a str,
|
git_hash: &'a str,
|
||||||
@ -170,6 +175,15 @@ fn wifi_scan(
|
|||||||
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 board = BOARD_ACCESS.lock().unwrap();
|
||||||
|
let result = board.list_files()?;
|
||||||
|
let file_list_json = serde_json::to_string(&FileList { file: result })?;
|
||||||
|
return anyhow::Ok(Some(file_list_json));
|
||||||
|
}
|
||||||
|
|
||||||
fn ota(
|
fn ota(
|
||||||
request: &mut Request<&mut EspHttpConnection>,
|
request: &mut Request<&mut EspHttpConnection>,
|
||||||
) -> Result<Option<std::string::String>, anyhow::Error> {
|
) -> Result<Option<std::string::String>, anyhow::Error> {
|
||||||
@ -252,10 +266,96 @@ pub fn httpd(_reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
server
|
server
|
||||||
.fn_handler("/set_config", Method::Post, move |mut request| {
|
.fn_handler("/set_config", Method::Post, move |request| {
|
||||||
handle_error_to500(request, set_config)
|
handle_error_to500(request, set_config)
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
server
|
||||||
|
.fn_handler("/list_files", Method::Get, move |request| {
|
||||||
|
handle_error_to500(request, list_files)
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
server
|
||||||
|
.fn_handler("/get_file", Method::Get, move |request| {
|
||||||
|
let filename:String = request.uri().magic_here().get("filename");
|
||||||
|
let file_handle = BOARD_ACCESS.lock().unwrap().get_file_handle(filename);
|
||||||
|
match file_handle {
|
||||||
|
Ok(file_handle) => {
|
||||||
|
let mut response = request.into_ok_response()?;
|
||||||
|
const BUFFER_SIZE: usize = 512;
|
||||||
|
let mut buffer: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
|
||||||
|
let mut total_read: usize = 0;
|
||||||
|
loop {
|
||||||
|
let read = file_handle.read(&mut buffer)?;
|
||||||
|
total_read += read;
|
||||||
|
println!("sending {read} bytes of {total_read} for file {filename}");
|
||||||
|
let to_write = &buffer[0..read];
|
||||||
|
response.write(to_write)?;
|
||||||
|
println!("wrote {read} bytes of {total_read} for file {filename}");
|
||||||
|
if read == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response.flush()?;
|
||||||
|
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
//todo set headers here for filename to be error
|
||||||
|
let error_text = err.to_string();
|
||||||
|
println!("error handling get file {}", error_text);
|
||||||
|
request
|
||||||
|
.into_status_response(500)?
|
||||||
|
.write(error_text.as_bytes())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
anyhow::Ok(())
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
server
|
||||||
|
.fn_handler("/put_file", Method::Post, move |request| {
|
||||||
|
let filename:String = request.uri().magic_here().get("filename");
|
||||||
|
let file_handle = BOARD_ACCESS.lock().unwrap().get_file_handle(filename);
|
||||||
|
match file_handle {
|
||||||
|
Ok(file_handle) => {
|
||||||
|
const BUFFER_SIZE: usize = 512;
|
||||||
|
let mut buffer: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
|
||||||
|
let mut total_read: usize = 0;
|
||||||
|
loop {
|
||||||
|
let read = request.read(&mut buffer)?;
|
||||||
|
total_read += read;
|
||||||
|
println!("sending {read} bytes of {total_read} for upload {filename}");
|
||||||
|
let to_write = &buffer[0..read];
|
||||||
|
file_handle.write(to_write)?;
|
||||||
|
println!("wrote {read} bytes of {total_read} for upload {filename}");
|
||||||
|
if read == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request.into_ok_response().unwrap().write(format!("saved {total_read} bytes").as_bytes());
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
//todo set headers here for filename to be error
|
||||||
|
let error_text = err.to_string();
|
||||||
|
println!("error handling get file {}", error_text);
|
||||||
|
request
|
||||||
|
.into_status_response(500)?
|
||||||
|
.write(error_text.as_bytes())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
anyhow::Ok(())
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
server
|
||||||
|
.fn_handler("/get_file", Method::Post, move |request| {
|
||||||
|
handle_error_to500(request, set_config)
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
server
|
||||||
|
.fn_handler("/put_file", Method::Post, move |request| {
|
||||||
|
handle_error_to500(request, set_config)
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
server
|
server
|
||||||
.fn_handler("/flashbattery", Method::Post, move |mut request| {
|
.fn_handler("/flashbattery", Method::Post, move |mut request| {
|
||||||
|
|
||||||
@ -327,14 +427,12 @@ pub fn httpd(_reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
|
|||||||
server
|
server
|
||||||
.fn_handler("/", Method::Get, move |request| {
|
.fn_handler("/", Method::Get, move |request| {
|
||||||
let mut response = request.into_ok_response()?;
|
let mut response = request.into_ok_response()?;
|
||||||
response.write(include_bytes!("config.html"))?;
|
response.write(include_bytes!("config.html"))?;let mut buf = [0_u8; 3072];
|
||||||
anyhow::Ok(())
|
let read = request.read(&mut buf)?;
|
||||||
})
|
let actual_data = &buf[0..read];
|
||||||
.unwrap();
|
println!("Raw data {}", from_utf8(actual_data).unwrap());
|
||||||
server
|
let config: Config = serde_json::from_slice(actual_data)?;
|
||||||
.fn_handler("/bundle.js", Method::Get, |request| {
|
|
||||||
request
|
|
||||||
.into_ok_response()?
|
|
||||||
.write(include_bytes!("bundle.js"))?;
|
.write(include_bytes!("bundle.js"))?;
|
||||||
anyhow::Ok(())
|
anyhow::Ok(())
|
||||||
})
|
})
|
||||||
@ -345,6 +443,7 @@ pub fn httpd(_reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
|
|||||||
.into_ok_response()?
|
.into_ok_response()?
|
||||||
.write(include_bytes!("favicon.ico"))?;
|
.write(include_bytes!("favicon.ico"))?;
|
||||||
anyhow::Ok(())
|
anyhow::Ok(())
|
||||||
|
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
server
|
server
|
||||||
|
Loading…
Reference in New Issue
Block a user