config stuff
This commit is contained in:
parent
bfcf5e150c
commit
8218c4b9a6
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"board": {
|
"board": {
|
||||||
"active_layer": 2,
|
"active_layer": 31,
|
||||||
"active_layer_preset": "",
|
"active_layer_preset": "",
|
||||||
"auto_track_width": false,
|
"auto_track_width": false,
|
||||||
"hidden_netclasses": [],
|
"hidden_netclasses": [],
|
||||||
|
@ -51,7 +51,8 @@ mod webserver {
|
|||||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
enum WaitType {
|
enum WaitType {
|
||||||
MissingConfig,
|
MissingConfig,
|
||||||
Config,
|
ConfigButton,
|
||||||
|
MqttConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
|
||||||
@ -345,7 +346,7 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
drop(board);
|
drop(board);
|
||||||
let reboot_now = Arc::new(AtomicBool::new(false));
|
let reboot_now = Arc::new(AtomicBool::new(false));
|
||||||
let _webserver = httpd(reboot_now.clone());
|
let _webserver = httpd(reboot_now.clone());
|
||||||
wait_infinity(WaitType::Config, reboot_now.clone());
|
wait_infinity(WaitType::ConfigButton, reboot_now.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let tank_state = determine_tank_state(&mut board, &config);
|
let tank_state = determine_tank_state(&mut board, &config);
|
||||||
@ -528,7 +529,7 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
drop(board);
|
drop(board);
|
||||||
let reboot_now = Arc::new(AtomicBool::new(false));
|
let reboot_now = Arc::new(AtomicBool::new(false));
|
||||||
let _webserver = httpd(reboot_now.clone());
|
let _webserver = httpd(reboot_now.clone());
|
||||||
wait_infinity(WaitType::Config, reboot_now.clone());
|
wait_infinity(WaitType::MqttConfig, reboot_now.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe { esp_deep_sleep(1000 * 1000 * 60 * deep_sleep_duration_minutes as u64) };
|
unsafe { esp_deep_sleep(1000 * 1000 * 60 * deep_sleep_duration_minutes as u64) };
|
||||||
@ -895,7 +896,8 @@ fn update_plant_state(
|
|||||||
fn wait_infinity(wait_type: WaitType, reboot_now: Arc<AtomicBool>) -> ! {
|
fn wait_infinity(wait_type: WaitType, reboot_now: Arc<AtomicBool>) -> ! {
|
||||||
let delay = match wait_type {
|
let delay = match wait_type {
|
||||||
WaitType::MissingConfig => 500_u32,
|
WaitType::MissingConfig => 500_u32,
|
||||||
WaitType::Config => 100_u32,
|
WaitType::ConfigButton => 100_u32,
|
||||||
|
WaitType::MqttConfig => 200_u32,
|
||||||
};
|
};
|
||||||
let mut led_count = 8;
|
let mut led_count = 8;
|
||||||
loop {
|
loop {
|
||||||
@ -919,7 +921,8 @@ fn wait_infinity(wait_type: WaitType, reboot_now: Arc<AtomicBool>) -> ! {
|
|||||||
vTaskDelay(delay);
|
vTaskDelay(delay);
|
||||||
match wait_type {
|
match wait_type {
|
||||||
WaitType::MissingConfig => {}
|
WaitType::MissingConfig => {}
|
||||||
WaitType::Config => {
|
WaitType::ConfigButton => {}
|
||||||
|
WaitType::MqttConfig => {
|
||||||
if !STAY_ALIVE.load(std::sync::atomic::Ordering::Relaxed) {
|
if !STAY_ALIVE.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
reboot_now.store(true, std::sync::atomic::Ordering::Relaxed);
|
reboot_now.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ use crate::{plant_hal, STAY_ALIVE};
|
|||||||
|
|
||||||
//Only support for 8 right now!
|
//Only support for 8 right now!
|
||||||
pub const PLANT_COUNT: usize = 8;
|
pub const PLANT_COUNT: usize = 8;
|
||||||
const REPEAT_MOIST_MEASURE: usize = 3;
|
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";
|
||||||
@ -387,7 +387,7 @@ impl PlantCtrlBoard<'_> {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let delay = Delay::new_default();
|
let delay = Delay::new_default();
|
||||||
let measurement = 10;
|
let measurement = 5000;
|
||||||
let factor = 1000 as f32 / measurement as f32;
|
let factor = 1000 as f32 / measurement as f32;
|
||||||
|
|
||||||
//give some time to stabilize
|
//give some time to stabilize
|
||||||
@ -402,6 +402,7 @@ impl PlantCtrlBoard<'_> {
|
|||||||
delay.delay_ms(10);
|
delay.delay_ms(10);
|
||||||
let unscaled = self.signal_counter.get_counter_value()? as i32;
|
let unscaled = self.signal_counter.get_counter_value()? as i32;
|
||||||
let hz = (unscaled as f32 * factor) as i32;
|
let hz = (unscaled as f32 * factor) as i32;
|
||||||
|
println!("raw measure unscaled {} hz {}, plant {} sensor {:?}",unscaled, hz, plant, sensor);
|
||||||
results[repeat] = hz;
|
results[repeat] = hz;
|
||||||
//println!("Measuring {:?} @ {} with {}", sensor, plant, hz);
|
//println!("Measuring {:?} @ {} with {}", sensor, plant, hz);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,14 @@
|
|||||||
<div id="firmware_buildtime">Buildtime loading</div>
|
<div id="firmware_buildtime">Buildtime loading</div>
|
||||||
<div id="firmware_githash">Build githash loading</div>
|
<div id="firmware_githash">Build githash loading</div>
|
||||||
</div>
|
</div>
|
||||||
|
<h2>Time</h2>
|
||||||
|
<div>
|
||||||
|
<div id="esp_time">Esp time</div>
|
||||||
|
<div id="rtc_time">Rtc time</div>
|
||||||
|
<div id="browser_time">Rtc time</div>
|
||||||
|
<div>Store Browser time into esp and rtc</div>
|
||||||
|
<input type="button" id="time_upload" value="write">
|
||||||
|
</div>
|
||||||
|
|
||||||
<h2>firmeware OTA v3</h2>
|
<h2>firmeware OTA v3</h2>
|
||||||
|
|
||||||
|
@ -7,11 +7,12 @@ use std::{
|
|||||||
sync::{atomic::AtomicBool, Arc},
|
sync::{atomic::AtomicBool, Arc},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{espota::OtaUpdate, BOARD_ACCESS};
|
use crate::{espota::OtaUpdate, map_range_moisture, plant_hal::PLANT_COUNT, BOARD_ACCESS};
|
||||||
|
use chrono::DateTime;
|
||||||
use core::result::Result::Ok;
|
use core::result::Result::Ok;
|
||||||
use embedded_svc::http::Method;
|
use embedded_svc::http::Method;
|
||||||
use esp_idf_hal::delay::Delay;
|
use esp_idf_hal::delay::Delay;
|
||||||
use esp_idf_svc::http::server::{Configuration, EspHttpServer};
|
use esp_idf_svc::http::server::{Configuration, EspHttpConnection, EspHttpServer, Request};
|
||||||
use heapless::String;
|
use heapless::String;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -28,12 +29,180 @@ struct VersionInfo<'a> {
|
|||||||
build_time: &'a str,
|
build_time: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Debug)]
|
||||||
|
struct LoadData<'a> {
|
||||||
|
rtc: &'a str,
|
||||||
|
native: &'a str,
|
||||||
|
moisture_a: Vec<u8>,
|
||||||
|
moisture_b: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
struct SetTime<'a> {
|
||||||
|
time: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||||
pub struct TestPump {
|
pub struct TestPump {
|
||||||
pump: usize,
|
pump: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn httpd(reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
|
fn write_time(
|
||||||
|
request: &mut Request<&mut EspHttpConnection>,
|
||||||
|
) -> Result<Option<std::string::String>, anyhow::Error> {
|
||||||
|
let mut buf = [0_u8; 3072];
|
||||||
|
let read = request.read(&mut buf)?;
|
||||||
|
let actual_data = &buf[0..read];
|
||||||
|
println!("Raw data {}", from_utf8(actual_data)?);
|
||||||
|
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().unwrap();
|
||||||
|
board.set_rtc_time(&parsed.to_utc())?;
|
||||||
|
anyhow::Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_data(
|
||||||
|
_request: &mut Request<&mut EspHttpConnection>,
|
||||||
|
) -> Result<Option<std::string::String>, anyhow::Error> {
|
||||||
|
let mut board = BOARD_ACCESS.lock().unwrap();
|
||||||
|
let native = board
|
||||||
|
.time()
|
||||||
|
.and_then(|t| Ok(t.to_rfc3339()))
|
||||||
|
.unwrap_or("error".to_string());
|
||||||
|
let rtc = board
|
||||||
|
.get_rtc_time()
|
||||||
|
.and_then(|t| Ok(t.to_rfc3339()))
|
||||||
|
.unwrap_or("error".to_string());
|
||||||
|
|
||||||
|
let mut a: Vec<u8> = Vec::new();
|
||||||
|
let mut b: Vec<u8> = Vec::new();
|
||||||
|
for plant in 0..2 {
|
||||||
|
let a_hz = board.measure_moisture_hz(plant, crate::plant_hal::Sensor::A)?;
|
||||||
|
let b_hz = board.measure_moisture_hz(plant, crate::plant_hal::Sensor::B)?;
|
||||||
|
let a_pct = map_range_moisture(a_hz as f32);
|
||||||
|
|
||||||
|
match a_pct {
|
||||||
|
Ok(result) => {
|
||||||
|
a.push(result);
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
a.push(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let b_pct = map_range_moisture(b_hz as f32);
|
||||||
|
match b_pct {
|
||||||
|
Ok(result) => {
|
||||||
|
b.push(result);
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
b.push(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let data = LoadData {
|
||||||
|
rtc: rtc.as_str(),
|
||||||
|
native: native.as_str(),
|
||||||
|
moisture_a: a,
|
||||||
|
moisture_b: b
|
||||||
|
};
|
||||||
|
let json = serde_json::to_string(&data)?;
|
||||||
|
|
||||||
|
anyhow::Ok(Some(json))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_config(
|
||||||
|
_request: &mut Request<&mut EspHttpConnection>,
|
||||||
|
) -> Result<Option<std::string::String>, anyhow::Error> {
|
||||||
|
let mut board = BOARD_ACCESS.lock().unwrap();
|
||||||
|
let json = match board.get_config() {
|
||||||
|
Ok(config) => serde_json::to_string(&config)?,
|
||||||
|
Err(_) => serde_json::to_string(&Config::default())?,
|
||||||
|
};
|
||||||
|
anyhow::Ok(Some(json))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_config(
|
||||||
|
request: &mut Request<&mut EspHttpConnection>,
|
||||||
|
) -> Result<Option<std::string::String>, anyhow::Error> {
|
||||||
|
let mut buf = [0_u8; 3072];
|
||||||
|
let read = request.read(&mut buf)?;
|
||||||
|
let actual_data = &buf[0..read];
|
||||||
|
println!("Raw data {}", from_utf8(actual_data).unwrap());
|
||||||
|
let config: Config = serde_json::from_slice(actual_data)?;
|
||||||
|
let mut board = BOARD_ACCESS.lock().unwrap();
|
||||||
|
board.set_config(&config)?;
|
||||||
|
anyhow::Ok(Some("saved".to_owned()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_version(
|
||||||
|
_request: &mut Request<&mut EspHttpConnection>,
|
||||||
|
) -> Result<Option<std::string::String>, anyhow::Error> {
|
||||||
|
let version_info = VersionInfo {
|
||||||
|
git_hash: env!("VERGEN_GIT_DESCRIBE"),
|
||||||
|
build_time: env!("VERGEN_BUILD_TIMESTAMP"),
|
||||||
|
};
|
||||||
|
anyhow::Ok(Some(serde_json::to_string(&version_info)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pump_test(
|
||||||
|
request: &mut Request<&mut EspHttpConnection>,
|
||||||
|
) -> Result<Option<std::string::String>, anyhow::Error> {
|
||||||
|
let mut buf = [0_u8; 3072];
|
||||||
|
let read = request.read(&mut buf)?;
|
||||||
|
let pump_test: TestPump = serde_json::from_slice(&buf[0..read])?;
|
||||||
|
let mut board = BOARD_ACCESS.lock().unwrap();
|
||||||
|
board.test_pump(pump_test.pump)?;
|
||||||
|
anyhow::Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wifi_scan(
|
||||||
|
_request: &mut Request<&mut EspHttpConnection>,
|
||||||
|
) -> Result<Option<std::string::String>, anyhow::Error> {
|
||||||
|
let mut board = BOARD_ACCESS.lock().unwrap();
|
||||||
|
let scan_result = board.wifi_scan()?;
|
||||||
|
let mut ssids: Vec<&String<32>> = Vec::new();
|
||||||
|
scan_result.iter().for_each(|s| ssids.push(&s.ssid));
|
||||||
|
let ssid_json = serde_json::to_string(&SSIDList { ssids })?;
|
||||||
|
println!("Sending ssid list {}", &ssid_json);
|
||||||
|
anyhow::Ok(Some(ssid_json))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ota(
|
||||||
|
request: &mut Request<&mut EspHttpConnection>,
|
||||||
|
) -> Result<Option<std::string::String>, anyhow::Error> {
|
||||||
|
let mut ota = OtaUpdate::begin()?;
|
||||||
|
println!("start ota");
|
||||||
|
|
||||||
|
//having a larger buffer is not really faster, requires more stack and prevents the progress bar from working ;)
|
||||||
|
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!("received {read} bytes ota {total_read}");
|
||||||
|
let to_write = &buffer[0..read];
|
||||||
|
|
||||||
|
ota.write(to_write)?;
|
||||||
|
println!("wrote {read} bytes ota {total_read}");
|
||||||
|
if read == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("finish ota");
|
||||||
|
let partition = ota.raw_partition();
|
||||||
|
println!("finalizing and changing boot partition to {partition:?}");
|
||||||
|
|
||||||
|
let mut finalizer = ota.finalize()?;
|
||||||
|
println!("changing boot partition");
|
||||||
|
finalizer.set_as_boot_partition()?;
|
||||||
|
finalizer.restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn httpd(_reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
|
||||||
let server_config = Configuration {
|
let server_config = Configuration {
|
||||||
stack_size: 32768,
|
stack_size: 32768,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -42,121 +211,49 @@ pub fn httpd(reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
|
|||||||
Box::new(EspHttpServer::new(&server_config).unwrap());
|
Box::new(EspHttpServer::new(&server_config).unwrap());
|
||||||
server
|
server
|
||||||
.fn_handler("/version", Method::Get, |request| {
|
.fn_handler("/version", Method::Get, |request| {
|
||||||
let mut response = request.into_ok_response()?;
|
handle_error_to500(request, get_version)
|
||||||
let git_hash = env!("VERGEN_GIT_DESCRIBE");
|
})
|
||||||
let build_time = env!("VERGEN_BUILD_TIMESTAMP");
|
.unwrap();
|
||||||
let version_info = VersionInfo {
|
|
||||||
git_hash,
|
server
|
||||||
build_time,
|
.fn_handler("/data", Method::Get, |request| {
|
||||||
};
|
handle_error_to500(request, get_data)
|
||||||
let version_info_json = serde_json::to_string(&version_info)?;
|
|
||||||
response.write(version_info_json.as_bytes())?;
|
|
||||||
anyhow::Ok(())
|
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
server
|
server
|
||||||
.fn_handler("/bundle.js", Method::Get, |request| {
|
.fn_handler("/time", Method::Post, |request| {
|
||||||
let mut response = request.into_ok_response()?;
|
handle_error_to500(request, write_time)
|
||||||
response.write(include_bytes!("bundle.js"))?;
|
|
||||||
anyhow::Ok(())
|
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
server
|
server
|
||||||
.fn_handler("/favicon.ico", Method::Get, |request| {
|
.fn_handler("/pumptest", Method::Post, |request| {
|
||||||
let mut response = request.into_ok_response()?;
|
handle_error_to500(request, pump_test)
|
||||||
response.write(include_bytes!("favicon.ico"))?;
|
|
||||||
anyhow::Ok(())
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
server
|
|
||||||
.fn_handler("/ota", Method::Post, |mut request| {
|
|
||||||
let ota = OtaUpdate::begin();
|
|
||||||
if ota.is_err() {
|
|
||||||
let error_text = ota.unwrap_err().to_string();
|
|
||||||
request
|
|
||||||
.into_status_response(500)?
|
|
||||||
.write(error_text.as_bytes())?;
|
|
||||||
return anyhow::Ok(());
|
|
||||||
}
|
|
||||||
let mut ota = ota.unwrap();
|
|
||||||
println!("start ota");
|
|
||||||
|
|
||||||
//having a larger buffer is not really faster, requires more stack and prevents the progress bar from working ;)
|
|
||||||
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).unwrap();
|
|
||||||
total_read += read;
|
|
||||||
println!("received {read} bytes ota {total_read}");
|
|
||||||
let to_write = &buffer[0..read];
|
|
||||||
|
|
||||||
let write_result = ota.write(to_write);
|
|
||||||
if write_result.is_err() {
|
|
||||||
let error_text = write_result.unwrap_err().to_string();
|
|
||||||
request
|
|
||||||
.into_status_response(500)?
|
|
||||||
.write(error_text.as_bytes())?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
println!("wrote {read} bytes ota {total_read}");
|
|
||||||
if read == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!("finish ota");
|
|
||||||
let partition = ota.raw_partition();
|
|
||||||
println!("finalizing and changing boot partition to {partition:?}");
|
|
||||||
|
|
||||||
let finalizer = ota.finalize();
|
|
||||||
if finalizer.is_err() {
|
|
||||||
let error_text = finalizer.err().unwrap().to_string();
|
|
||||||
request
|
|
||||||
.into_status_response(500)?
|
|
||||||
.write(error_text.as_bytes())?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
let mut finalizer = finalizer.unwrap();
|
|
||||||
|
|
||||||
println!("changing boot partition");
|
|
||||||
finalizer.set_as_boot_partition().unwrap();
|
|
||||||
finalizer.restart();
|
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
server
|
server
|
||||||
.fn_handler("/boardtest", Method::Post, move |_| {
|
.fn_handler("/boardtest", Method::Post, move |_| {
|
||||||
let mut board = BOARD_ACCESS.lock().unwrap();
|
BOARD_ACCESS.lock().unwrap().test()
|
||||||
board.test()?;
|
|
||||||
anyhow::Ok(())
|
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
server
|
server
|
||||||
.fn_handler("/pumptest", Method::Post, |mut request| {
|
.fn_handler("/wifiscan", Method::Post, move |request| {
|
||||||
let mut buf = [0_u8; 3072];
|
handle_error_to500(request, wifi_scan)
|
||||||
let read = request.read(&mut buf);
|
})
|
||||||
if read.is_err() {
|
.unwrap();
|
||||||
let error_text = read.unwrap_err().to_string();
|
server
|
||||||
println!("Could not parse testrequest {}", error_text);
|
.fn_handler("/ota", Method::Post, |mut request| {
|
||||||
request
|
handle_error_to500(request, ota)
|
||||||
.into_status_response(500)?
|
})
|
||||||
.write(error_text.as_bytes())?;
|
.unwrap();
|
||||||
return anyhow::Ok(());
|
server
|
||||||
}
|
.fn_handler("/get_config", Method::Get, move |request| {
|
||||||
let actual_data = &buf[0..read.unwrap()];
|
handle_error_to500(request, get_config)
|
||||||
println!("Raw data {}", from_utf8(actual_data).unwrap());
|
})
|
||||||
let pump_test: Result<TestPump, serde_json::Error> =
|
.unwrap();
|
||||||
serde_json::from_slice(actual_data);
|
|
||||||
if pump_test.is_err() {
|
server
|
||||||
let error_text = pump_test.unwrap_err().to_string();
|
.fn_handler("/set_config", Method::Post, move |mut request| {
|
||||||
println!("Could not parse TestPump {}", error_text);
|
handle_error_to500(request, set_config)
|
||||||
request
|
|
||||||
.into_status_response(500)?
|
|
||||||
.write(error_text.as_bytes())?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
let mut board = BOARD_ACCESS.lock().unwrap();
|
|
||||||
board.test_pump(pump_test.unwrap().pump)?;
|
|
||||||
anyhow::Ok(())
|
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
server
|
server
|
||||||
@ -227,25 +324,6 @@ pub fn httpd(reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
|
|||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
server
|
|
||||||
.fn_handler("/wifiscan", Method::Post, move |request| {
|
|
||||||
let mut response = request.into_ok_response()?;
|
|
||||||
let mut board = BOARD_ACCESS.lock().unwrap();
|
|
||||||
match board.wifi_scan() {
|
|
||||||
Err(error) => {
|
|
||||||
response.write(format!("Error scanning wifi: {}", error).as_bytes())?;
|
|
||||||
}
|
|
||||||
Ok(scan_result) => {
|
|
||||||
let mut ssids: Vec<&String<32>> = Vec::new();
|
|
||||||
scan_result.iter().for_each(|s| ssids.push(&s.ssid));
|
|
||||||
let ssid_json = serde_json::to_string(&SSIDList { ssids })?;
|
|
||||||
println!("Sending ssid list {}", &ssid_json);
|
|
||||||
response.write(ssid_json.as_bytes())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
anyhow::Ok(())
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
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()?;
|
||||||
@ -253,55 +331,49 @@ pub fn httpd(reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
|
|||||||
anyhow::Ok(())
|
anyhow::Ok(())
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
server
|
server
|
||||||
.fn_handler("/get_config", Method::Get, move |request| {
|
.fn_handler("/bundle.js", Method::Get, |request| {
|
||||||
let mut response = request.into_ok_response()?;
|
request
|
||||||
let mut board = BOARD_ACCESS.lock().unwrap();
|
.into_ok_response()?
|
||||||
match board.get_config() {
|
.write(include_bytes!("bundle.js"))?;
|
||||||
Ok(config) => {
|
|
||||||
let config_json = serde_json::to_string(&config)?;
|
|
||||||
response.write(config_json.as_bytes())?;
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
let config_json = serde_json::to_string(&Config::default())?;
|
|
||||||
response.write(config_json.as_bytes())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
anyhow::Ok(())
|
anyhow::Ok(())
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
server
|
server
|
||||||
.fn_handler("/set_config", Method::Post, move |mut request| {
|
.fn_handler("/favicon.ico", Method::Get, |request| {
|
||||||
let mut buf = [0_u8; 3072];
|
request
|
||||||
let read = request.read(&mut buf);
|
.into_ok_response()?
|
||||||
if read.is_err() {
|
.write(include_bytes!("favicon.ico"))?;
|
||||||
let error_text = read.unwrap_err().to_string();
|
anyhow::Ok(())
|
||||||
println!("Could not parse config {}", error_text);
|
|
||||||
request
|
|
||||||
.into_status_response(500)?
|
|
||||||
.write(error_text.as_bytes())?;
|
|
||||||
return anyhow::Ok(());
|
|
||||||
}
|
|
||||||
let actual_data = &buf[0..read.unwrap()];
|
|
||||||
println!("Raw data {}", from_utf8(actual_data).unwrap());
|
|
||||||
let config: Result<Config, serde_json::Error> = serde_json::from_slice(actual_data);
|
|
||||||
if config.is_err() {
|
|
||||||
let error_text = config.unwrap_err().to_string();
|
|
||||||
println!("Could not parse config {}", error_text);
|
|
||||||
request
|
|
||||||
.into_status_response(500)?
|
|
||||||
.write(error_text.as_bytes())?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
let mut board = BOARD_ACCESS.lock().unwrap();
|
|
||||||
board.set_config(&config.unwrap())?;
|
|
||||||
let mut response = request.into_status_response(202)?;
|
|
||||||
response.write("saved".as_bytes())?;
|
|
||||||
reboot_now.store(true, std::sync::atomic::Ordering::Relaxed);
|
|
||||||
Ok(())
|
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
server
|
server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type AnyhowHandler =
|
||||||
|
fn(&mut Request<&mut EspHttpConnection>) -> Result<Option<std::string::String>, anyhow::Error>;
|
||||||
|
fn handle_error_to500(
|
||||||
|
mut request: Request<&mut EspHttpConnection>,
|
||||||
|
chain: AnyhowHandler,
|
||||||
|
) -> Result<(), anyhow::Error> {
|
||||||
|
let error = chain(&mut request);
|
||||||
|
match error {
|
||||||
|
Ok(answer) => match answer {
|
||||||
|
Some(json) => {
|
||||||
|
let mut response = request.into_ok_response()?;
|
||||||
|
response.write(json.as_bytes())?;
|
||||||
|
response.flush()?;
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
let error_text = err.to_string();
|
||||||
|
println!("error handling process {}", error_text);
|
||||||
|
request
|
||||||
|
.into_status_response(500)?
|
||||||
|
.write(error_text.as_bytes())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return anyhow::Ok(());
|
||||||
|
}
|
@ -35,6 +35,17 @@ interface TestPump{
|
|||||||
pump: number
|
pump: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SetTime{
|
||||||
|
time: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetData{
|
||||||
|
rtc: string,
|
||||||
|
native: string,
|
||||||
|
moisture_a: [number],
|
||||||
|
moisture_b: [number],
|
||||||
|
}
|
||||||
|
|
||||||
let plants = document.getElementById("plants") as HTMLInputElement;
|
let plants = document.getElementById("plants") as HTMLInputElement;
|
||||||
|
|
||||||
let scanWifiBtn = document.getElementById("scan") as HTMLButtonElement;
|
let scanWifiBtn = document.getElementById("scan") as HTMLButtonElement;
|
||||||
@ -42,6 +53,56 @@ if(scanWifiBtn){
|
|||||||
scanWifiBtn.onclick = scanWifi;
|
scanWifiBtn.onclick = scanWifi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let esp_time = document.getElementById("esp_time") as HTMLDivElement;
|
||||||
|
let rtc_time = document.getElementById("rtc_time") as HTMLDivElement;
|
||||||
|
let browser_time = document.getElementById("browser_time") as HTMLDivElement;
|
||||||
|
let sync = document.getElementById("time_upload") as HTMLButtonElement;
|
||||||
|
sync.onclick = setTime
|
||||||
|
|
||||||
|
function setTime(){
|
||||||
|
var value: SetTime = {
|
||||||
|
time : new Date().toISOString()
|
||||||
|
}
|
||||||
|
var pretty = JSON.stringify(value, undefined, 1);
|
||||||
|
fetch("/time", {
|
||||||
|
method :"POST",
|
||||||
|
body: pretty
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTime(){
|
||||||
|
fetch("/data")
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(json => json as GetData)
|
||||||
|
.then(time => {
|
||||||
|
esp_time.innerText = time.native;
|
||||||
|
rtc_time.innerText = time.rtc;
|
||||||
|
var date = new Date();
|
||||||
|
browser_time.innerText = date.toISOString();
|
||||||
|
|
||||||
|
|
||||||
|
time.moisture_a.forEach((a, index) => {
|
||||||
|
var id = "plant_" + index + "_moisture_a";
|
||||||
|
console.log("id is " + id + "index is " + index)
|
||||||
|
var target = document.getElementById(id) as HTMLDivElement;
|
||||||
|
target.innerText = a+"";
|
||||||
|
})
|
||||||
|
time.moisture_b.forEach((b, index) => {
|
||||||
|
var id = "plant_" + index + "_moisture_b";
|
||||||
|
var target = document.getElementById(id) as HTMLDivElement;
|
||||||
|
target.innerText = b+"";
|
||||||
|
})
|
||||||
|
|
||||||
|
setTimeout(updateTime,1000);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error);
|
||||||
|
setTimeout(updateTime,10000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setTimeout(updateTime,1000);
|
||||||
|
|
||||||
|
|
||||||
export function scanWifi(){
|
export function scanWifi(){
|
||||||
var scanButton = (document.getElementById("scan") as HTMLButtonElement);
|
var scanButton = (document.getElementById("scan") as HTMLButtonElement);
|
||||||
scanButton.disabled = true;
|
scanButton.disabled = true;
|
||||||
@ -154,6 +215,16 @@ let fromWrapper = (() => {
|
|||||||
};
|
};
|
||||||
holder.appendChild(testButton);
|
holder.appendChild(testButton);
|
||||||
|
|
||||||
|
let moisture_a = document.createElement("div");
|
||||||
|
moisture_a.innerText = "N/A";
|
||||||
|
moisture_a.id = "plant_" + i + "_moisture_a";
|
||||||
|
holder.appendChild(moisture_a);
|
||||||
|
|
||||||
|
let moisture_b = document.createElement("div");
|
||||||
|
moisture_b.innerText = "N/A";
|
||||||
|
moisture_b.id = "plant_" + i + "_moisture_b";
|
||||||
|
holder.appendChild(moisture_b);
|
||||||
|
|
||||||
let br = document.createElement("br");
|
let br = document.createElement("br");
|
||||||
holder.appendChild(br);
|
holder.appendChild(br);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user