adust pcb to new 3.3 software improvements
This commit is contained in:
@@ -10,11 +10,7 @@ use chrono_tz::{Europe::Berlin, Tz};
|
||||
use config::Mode;
|
||||
use esp_idf_hal::delay::Delay;
|
||||
use esp_idf_sys::{
|
||||
esp_deep_sleep, esp_ota_get_app_partition_count, esp_ota_get_running_partition,
|
||||
esp_ota_get_state_partition, esp_ota_img_states_t, esp_ota_img_states_t_ESP_OTA_IMG_ABORTED,
|
||||
esp_ota_img_states_t_ESP_OTA_IMG_INVALID, esp_ota_img_states_t_ESP_OTA_IMG_NEW,
|
||||
esp_ota_img_states_t_ESP_OTA_IMG_PENDING_VERIFY, esp_ota_img_states_t_ESP_OTA_IMG_UNDEFINED,
|
||||
esp_ota_img_states_t_ESP_OTA_IMG_VALID, esp_restart, vTaskDelay, CONFIG_FREERTOS_HZ,
|
||||
esp_deep_sleep, esp_ota_get_app_partition_count, esp_ota_get_running_partition, esp_ota_get_state_partition, esp_ota_img_states_t, esp_ota_img_states_t_ESP_OTA_IMG_ABORTED, esp_ota_img_states_t_ESP_OTA_IMG_INVALID, esp_ota_img_states_t_ESP_OTA_IMG_NEW, esp_ota_img_states_t_ESP_OTA_IMG_PENDING_VERIFY, esp_ota_img_states_t_ESP_OTA_IMG_UNDEFINED, esp_ota_img_states_t_ESP_OTA_IMG_VALID, esp_restart, esp_sleep_enable_ext1_wakeup, esp_sleep_ext1_wakeup_mode_t_ESP_EXT1_WAKEUP_ANY_LOW, vTaskDelay, CONFIG_FREERTOS_HZ
|
||||
};
|
||||
use log::error;
|
||||
use once_cell::sync::Lazy;
|
||||
@@ -126,16 +122,6 @@ struct PlantStateMQTT<'a> {
|
||||
last_pump: &'a str,
|
||||
next_pump: &'a str,
|
||||
}
|
||||
#[derive(Serialize)]
|
||||
struct BatteryState<'a> {
|
||||
voltage_milli_volt: &'a str,
|
||||
current_milli_ampere: &'a str,
|
||||
cycle_count: &'a str,
|
||||
design_milli_ampere: &'a str,
|
||||
remaining_milli_ampere: &'a str,
|
||||
state_of_charge: &'a str,
|
||||
state_of_health: &'a str,
|
||||
}
|
||||
|
||||
fn safe_main() -> anyhow::Result<()> {
|
||||
// It is necessary to call this function once. Otherwise some patches to the runtime
|
||||
@@ -155,15 +141,16 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
|
||||
log::info!("Startup Rust");
|
||||
|
||||
let git_hash = env!("VERGEN_GIT_DESCRIBE");
|
||||
let build_timestamp = env!("VERGEN_BUILD_TIMESTAMP");
|
||||
let mut to_config = false;
|
||||
|
||||
let version = get_version();
|
||||
println!(
|
||||
"Version useing git has {} build on {}",
|
||||
git_hash, build_timestamp
|
||||
version.git_hash, version.build_time
|
||||
);
|
||||
|
||||
let count = unsafe { esp_ota_get_app_partition_count() };
|
||||
println!("Partit ion count is {}", count);
|
||||
println!("Partition count is {}", count);
|
||||
let mut ota_state: esp_ota_img_states_t = 0;
|
||||
let running_partition = unsafe { esp_ota_get_running_partition() };
|
||||
let address = unsafe { (*running_partition).address };
|
||||
@@ -192,6 +179,7 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
println!("Board hal init");
|
||||
let mut board: std::sync::MutexGuard<'_, PlantCtrlBoard<'_>> = BOARD_ACCESS.lock().unwrap();
|
||||
board.general_fault(false);
|
||||
|
||||
println!("Mounting filesystem");
|
||||
board.mount_file_system()?;
|
||||
let free_space = board.file_system_size()?;
|
||||
@@ -232,8 +220,18 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
|
||||
println!("cur is {}", cur);
|
||||
|
||||
let mut to_config = false;
|
||||
if board.is_mode_override() {
|
||||
if board.get_restart_to_conf() {
|
||||
println!("config mode software override");
|
||||
for _i in 0..2 {
|
||||
board.general_fault(true);
|
||||
Delay::new_default().delay_ms(100);
|
||||
board.general_fault(false);
|
||||
Delay::new_default().delay_ms(100);
|
||||
}
|
||||
to_config = true;
|
||||
board.general_fault(true);
|
||||
board.set_restart_to_conf(false);
|
||||
} else if board.is_mode_override() {
|
||||
board.general_fault(true);
|
||||
println!("config mode override is pressed, waiting 5s");
|
||||
for _i in 0..5 {
|
||||
@@ -244,11 +242,15 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
}
|
||||
|
||||
if board.is_mode_override() {
|
||||
board.general_fault(true);
|
||||
to_config = true;
|
||||
} else {
|
||||
board.general_fault(false);
|
||||
}
|
||||
} else {
|
||||
println!("No config override start detected");
|
||||
}
|
||||
|
||||
|
||||
let config: PlantControllerConfig;
|
||||
match board.get_config() {
|
||||
@@ -293,7 +295,7 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
board.general_fault(true);
|
||||
}
|
||||
}
|
||||
if (config.network.mqtt_url.is_some()) {
|
||||
if config.network.mqtt_url.is_some() {
|
||||
match board.mqtt(&config) {
|
||||
Ok(_) => {
|
||||
println!("Mqtt connection ready");
|
||||
@@ -338,8 +340,12 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
if mqtt {
|
||||
let ip_string = ip_address.unwrap_or("N/A".to_owned());
|
||||
let _ = board.mqtt_publish(&config, "/firmware/address", ip_string.as_bytes());
|
||||
let _ = board.mqtt_publish(&config, "/firmware/githash", git_hash.as_bytes());
|
||||
let _ = board.mqtt_publish(&config, "/firmware/buildtime", build_timestamp.as_bytes());
|
||||
let _ = board.mqtt_publish(&config, "/firmware/githash", version.git_hash.as_bytes());
|
||||
let _ = board.mqtt_publish(
|
||||
&config,
|
||||
"/firmware/buildtime",
|
||||
version.build_time.as_bytes(),
|
||||
);
|
||||
let _ = board.mqtt_publish(
|
||||
&config,
|
||||
"/firmware/last_online",
|
||||
@@ -425,6 +431,7 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
);
|
||||
|
||||
let stay_alive_mqtt = STAY_ALIVE.load(std::sync::atomic::Ordering::Relaxed);
|
||||
|
||||
let stay_alive = stay_alive_mqtt;
|
||||
println!("Check stay alive, current state is {}", stay_alive);
|
||||
|
||||
@@ -550,23 +557,17 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
let _webserver = httpd(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_sleep_enable_ext1_wakeup(0b10u64, esp_sleep_ext1_wakeup_mode_t_ESP_EXT1_WAKEUP_ANY_LOW);
|
||||
esp_deep_sleep(1000 * 1000 * 60 * deep_sleep_duration_minutes as u64)
|
||||
};
|
||||
}
|
||||
|
||||
fn publish_battery_state(
|
||||
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
|
||||
config: &PlantControllerConfig,
|
||||
) {
|
||||
let bat = BatteryState {
|
||||
voltage_milli_volt: &to_string(&board.voltage_milli_volt()),
|
||||
current_milli_ampere: &to_string(&board.average_current_milli_ampere()),
|
||||
cycle_count: &to_string(&board.cycle_count()),
|
||||
design_milli_ampere: &to_string(&board.design_milli_ampere_hour()),
|
||||
remaining_milli_ampere: &to_string(&board.remaining_milli_ampere_hour()),
|
||||
state_of_charge: &to_string(&board.state_charge_percent()),
|
||||
state_of_health: &to_string(&board.state_health_percent()),
|
||||
};
|
||||
let bat = board.get_battery_state();
|
||||
match serde_json::to_string(&bat) {
|
||||
Ok(state) => {
|
||||
let _ = board.mqtt_publish(&config, "/battery", state.as_bytes());
|
||||
@@ -1005,7 +1006,7 @@ fn sensor_to_string(value: &Option<u8>, error: &Option<SensorError>, enabled: bo
|
||||
};
|
||||
}
|
||||
|
||||
fn to_string<T: Display>(value: &Result<T>) -> String {
|
||||
fn to_string<T: Display>(value: Result<T>) -> String {
|
||||
return match value {
|
||||
Ok(v) => v.to_string(),
|
||||
Err(err) => {
|
||||
@@ -1054,3 +1055,19 @@ fn in_time_range(cur: &DateTime<Tz>, start: u8, end: u8) -> bool {
|
||||
return curhour > start || curhour < end;
|
||||
}
|
||||
}
|
||||
|
||||
fn get_version() -> VersionInfo {
|
||||
let branch = env!("VERGEN_GIT_BRANCH").to_owned();
|
||||
let hash = &env!("VERGEN_GIT_SHA")[0..8];
|
||||
|
||||
return VersionInfo {
|
||||
git_hash: (branch + "@" + hash),
|
||||
build_time: env!("VERGEN_BUILD_TIMESTAMP").to_owned(),
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
struct VersionInfo {
|
||||
git_hash: String,
|
||||
build_time: String,
|
||||
}
|
||||
|
@@ -53,7 +53,7 @@ use esp_idf_sys::{esp, esp_spiffs_check, gpio_hold_dis, gpio_hold_en, vTaskDelay
|
||||
use one_wire_bus::OneWire;
|
||||
|
||||
use crate::config::{self, PlantControllerConfig};
|
||||
use crate::{plant_hal, STAY_ALIVE};
|
||||
use crate::{plant_hal, to_string, STAY_ALIVE};
|
||||
|
||||
//Only support for 8 right now!
|
||||
pub const PLANT_COUNT: usize = 8;
|
||||
@@ -117,6 +117,9 @@ 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;
|
||||
|
||||
pub struct FileSystemSizeInfo {
|
||||
pub total_size: usize,
|
||||
pub used_size: usize,
|
||||
@@ -180,7 +183,33 @@ pub struct FileList {
|
||||
iter_error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct BatteryState {
|
||||
voltage_milli_volt: String,
|
||||
current_milli_ampere: String,
|
||||
cycle_count: String,
|
||||
design_milli_ampere: String,
|
||||
remaining_milli_ampere: String,
|
||||
state_of_charge: String,
|
||||
state_of_health: String,
|
||||
temperature: String,
|
||||
}
|
||||
|
||||
impl PlantCtrlBoard<'_> {
|
||||
pub fn get_battery_state(&mut self) -> BatteryState {
|
||||
let bat = BatteryState {
|
||||
voltage_milli_volt: to_string(self.voltage_milli_volt()),
|
||||
current_milli_ampere: to_string(self.average_current_milli_ampere()),
|
||||
cycle_count: to_string(self.cycle_count()),
|
||||
design_milli_ampere: to_string(self.design_milli_ampere_hour()),
|
||||
remaining_milli_ampere: to_string(self.remaining_milli_ampere_hour()),
|
||||
state_of_charge: to_string(self.state_charge_percent()),
|
||||
state_of_health: to_string(self.state_health_percent()),
|
||||
temperature: to_string(self.bat_temperature()),
|
||||
};
|
||||
return bat;
|
||||
}
|
||||
|
||||
pub fn list_files(&self, filename: &str) -> FileList {
|
||||
let storage = CString::new(SPIFFS_PARTITION_NAME).unwrap();
|
||||
let error = unsafe {
|
||||
@@ -956,6 +985,16 @@ impl PlantCtrlBoard<'_> {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_restart_to_conf(&mut self) -> bool {
|
||||
return unsafe { RESTART_TO_CONF };
|
||||
}
|
||||
|
||||
pub fn set_restart_to_conf(&mut self, to_conf: bool) {
|
||||
unsafe {
|
||||
RESTART_TO_CONF = to_conf;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn state_charge_percent(&mut self) -> Result<u8> {
|
||||
match self.battery_driver.state_of_charge() {
|
||||
OkStd(r) => Ok(r),
|
||||
@@ -1012,6 +1051,13 @@ impl PlantCtrlBoard<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bat_temperature(&mut self) -> Result<u16> {
|
||||
match self.battery_driver.temperature() {
|
||||
OkStd(r) => Ok(r as u16),
|
||||
Err(err) => bail!("Error reading Temperature {:?}", err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flash_bq34_z100(&mut self, line: &str, dryrun: bool) -> Result<()> {
|
||||
match self.battery_driver.write_flash_stream_i2c(line, dryrun) {
|
||||
OkStd(r) => Ok(r),
|
||||
@@ -1193,32 +1239,60 @@ impl PlantHal {
|
||||
ms4.set_high()?;
|
||||
|
||||
//init,reset rtc memory depending on cause
|
||||
let mut init_rtc_store: bool = false;
|
||||
let mut to_config_mode: bool = false;
|
||||
let reasons = ResetReason::get();
|
||||
let reset_store = match reasons {
|
||||
ResetReason::Software => false,
|
||||
ResetReason::ExternalPin => false,
|
||||
ResetReason::Watchdog => true,
|
||||
ResetReason::Sdio => true,
|
||||
ResetReason::Panic => true,
|
||||
ResetReason::InterruptWatchdog => true,
|
||||
ResetReason::PowerOn => true,
|
||||
ResetReason::Unknown => true,
|
||||
ResetReason::Brownout => true,
|
||||
ResetReason::TaskWatchdog => true,
|
||||
ResetReason::DeepSleep => false,
|
||||
ResetReason::USBPeripheral => true,
|
||||
ResetReason::JTAG => true,
|
||||
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
|
||||
},
|
||||
};
|
||||
if reset_store {
|
||||
println!("Clear and reinit RTC store");
|
||||
println!("Reset due to {:?} requires rtc clear {} and force config mode {}", reasons, init_rtc_store, to_config_mode);
|
||||
if init_rtc_store {
|
||||
unsafe {
|
||||
LAST_WATERING_TIMESTAMP = [0; PLANT_COUNT];
|
||||
CONSECUTIVE_WATERING_PLANT = [0; PLANT_COUNT];
|
||||
LOW_VOLTAGE_DETECTED = false;
|
||||
RESTART_TO_CONF = to_config_mode;
|
||||
};
|
||||
} else {
|
||||
println!("Keeping RTC store");
|
||||
unsafe {
|
||||
if to_config_mode{
|
||||
RESTART_TO_CONF = true;
|
||||
}
|
||||
println!("Current restart to conf mode{:?}", RESTART_TO_CONF);
|
||||
|
||||
println!(
|
||||
"Current low voltage detection is {:?}",
|
||||
LOW_VOLTAGE_DETECTED
|
||||
|
2050
rust/src/webserver/bootstrap-grid.css
vendored
Normal file
2050
rust/src/webserver/bootstrap-grid.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,9 @@ use std::{
|
||||
sync::{atomic::AtomicBool, Arc},
|
||||
};
|
||||
|
||||
use crate::{espota::OtaUpdate, map_range_moisture, plant_hal::FileInfo, BOARD_ACCESS};
|
||||
use crate::{
|
||||
espota::OtaUpdate, get_version, map_range_moisture, plant_hal::FileInfo, BOARD_ACCESS,
|
||||
};
|
||||
use anyhow::bail;
|
||||
use chrono::DateTime;
|
||||
use core::result::Result::Ok;
|
||||
@@ -29,12 +31,6 @@ struct FileList {
|
||||
file: Vec<FileInfo>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
struct VersionInfo<'a> {
|
||||
git_hash: &'a str,
|
||||
build_time: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
struct LoadData<'a> {
|
||||
rtc: &'a str,
|
||||
@@ -158,17 +154,19 @@ fn set_config(
|
||||
anyhow::Ok(Some("saved".to_owned()))
|
||||
}
|
||||
|
||||
fn get_version(
|
||||
fn get_battery_state(
|
||||
_request: &mut Request<&mut EspHttpConnection>,
|
||||
) -> Result<Option<std::string::String>, anyhow::Error> {
|
||||
let branch = env!("VERGEN_GIT_BRANCH").to_owned();
|
||||
let hash = &env!("VERGEN_GIT_SHA")[0..8];
|
||||
|
||||
let version_info: VersionInfo<'_> = VersionInfo {
|
||||
git_hash: &(branch + "@" + hash),
|
||||
build_time: env!("VERGEN_BUILD_TIMESTAMP"),
|
||||
};
|
||||
anyhow::Ok(Some(serde_json::to_string(&version_info)?))
|
||||
let mut board = BOARD_ACCESS.lock().unwrap();
|
||||
let battery_state = board.get_battery_state();
|
||||
let battery_json = serde_json::to_string(&battery_state)?;
|
||||
anyhow::Ok(Some(battery_json))
|
||||
}
|
||||
|
||||
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(
|
||||
@@ -296,10 +294,14 @@ pub fn httpd(_reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
|
||||
Box::new(EspHttpServer::new(&server_config).unwrap());
|
||||
server
|
||||
.fn_handler("/version", Method::Get, |request| {
|
||||
handle_error_to500(request, get_version)
|
||||
handle_error_to500(request, get_version_web)
|
||||
})
|
||||
.unwrap();
|
||||
server
|
||||
.fn_handler("/battery", Method::Get, |request| {
|
||||
handle_error_to500(request, get_battery_state)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
server
|
||||
.fn_handler("/time", Method::Get, |request| {
|
||||
handle_error_to500(request, get_data)
|
||||
@@ -505,13 +507,13 @@ pub fn httpd(_reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
|
||||
})
|
||||
.unwrap();
|
||||
server
|
||||
.fn_handler("/bootstrap-grid.css", Method::Get, |request| {
|
||||
request
|
||||
.into_ok_response()?
|
||||
.write(include_bytes!("bootstrap-grid.css"))?;
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
.fn_handler("/bootstrap-grid.css", Method::Get, |request| {
|
||||
request
|
||||
.into_ok_response()?
|
||||
.write(include_bytes!("bootstrap-grid.css"))?;
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
server
|
||||
}
|
||||
|
||||
@@ -522,7 +524,7 @@ fn cors_response(
|
||||
) -> Result<(), anyhow::Error> {
|
||||
let headers = [
|
||||
("Access-Control-Allow-Origin", "*"),
|
||||
("Access-Control-Allow-Headers", "*")
|
||||
("Access-Control-Allow-Headers", "*"),
|
||||
];
|
||||
let mut response = request.into_response(status, None, &headers)?;
|
||||
response.write(body.as_bytes())?;
|
||||
|
Reference in New Issue
Block a user