fix rollback and windows build
This commit is contained in:
parent
57a0971c4b
commit
bfee21796a
@ -12,34 +12,31 @@ fn main() {
|
|||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
println!("Assuming build on windows");
|
println!("Assuming build on windows");
|
||||||
let output = Command::new("cmd")
|
let output = Command::new("cmd")
|
||||||
.arg("/K")
|
.arg("/K")
|
||||||
.arg("npx")
|
.arg("npx")
|
||||||
.arg("webpack")
|
.arg("webpack")
|
||||||
.current_dir("./src_webpack")
|
.current_dir("./src_webpack")
|
||||||
.output()
|
.output()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("status: {}", output.status);
|
println!("status: {}", output.status);
|
||||||
println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
|
println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
|
||||||
println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
|
println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
|
||||||
assert!(output.status.success());
|
assert!(output.status.success());
|
||||||
},
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
println!("Assuming build on linux");
|
println!("Assuming build on linux");
|
||||||
let output = Command::new("bash")
|
let output = Command::new("bash")
|
||||||
.arg("webpack")
|
.arg("webpack")
|
||||||
.current_dir("./src_webpack")
|
.current_dir("./src_webpack")
|
||||||
.output()
|
.output()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("status: {}", output.status);
|
println!("status: {}", output.status);
|
||||||
println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
|
println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
|
||||||
println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
|
println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
|
||||||
assert!(output.status.success());
|
assert!(output.status.success());
|
||||||
},
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
embuild::espidf::sysenv::output();
|
embuild::espidf::sysenv::output();
|
||||||
let _ = EmitBuilder::builder().all_git().emit();
|
let _ = EmitBuilder::builder().all_git().all_build().emit();
|
||||||
}
|
}
|
||||||
|
@ -5,4 +5,4 @@ CONFIG_ESP_MAIN_TASK_STACK_SIZE=20000
|
|||||||
# This allows to use 1 ms granuality for thread sleeps (10 ms by default).
|
# This allows to use 1 ms granuality for thread sleeps (10 ms by default).
|
||||||
CONFIG_FREERTOS_HZ=1000
|
CONFIG_FREERTOS_HZ=1000
|
||||||
|
|
||||||
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=true
|
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
|
@ -60,7 +60,7 @@ pub struct Plant {
|
|||||||
pub pump_hour_start: u8,
|
pub pump_hour_start: u8,
|
||||||
pub pump_hour_end: u8,
|
pub pump_hour_end: u8,
|
||||||
pub sensor_b: bool,
|
pub sensor_b: bool,
|
||||||
pub sensor_p: bool
|
pub sensor_p: bool,
|
||||||
}
|
}
|
||||||
impl Default for Plant {
|
impl Default for Plant {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
@ -71,8 +71,8 @@ impl Default for Plant {
|
|||||||
pump_hour_start: 8,
|
pump_hour_start: 8,
|
||||||
pump_hour_end: 20,
|
pump_hour_end: 20,
|
||||||
mode: Mode::OFF,
|
mode: Mode::OFF,
|
||||||
sensor_b : false,
|
sensor_b: false,
|
||||||
sensor_p : false
|
sensor_p: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
220
rust/src/main.rs
220
rust/src/main.rs
@ -1,15 +1,11 @@
|
|||||||
use std::{
|
use std::sync::{atomic::AtomicBool, Arc, Mutex};
|
||||||
any::Any, env, sync::{atomic::AtomicBool, Arc, Mutex}
|
|
||||||
};
|
|
||||||
|
|
||||||
use chrono::{DateTime, Datelike, Duration, NaiveDateTime, Timelike};
|
use chrono::{DateTime, Datelike, Duration, NaiveDateTime, Timelike};
|
||||||
use chrono_tz::{Europe::Berlin, Tz};
|
use chrono_tz::{Europe::Berlin, Tz};
|
||||||
use config::Plant;
|
|
||||||
use embedded_svc::mqtt;
|
|
||||||
use esp_idf_hal::delay::Delay;
|
use esp_idf_hal::delay::Delay;
|
||||||
use esp_idf_sys::{
|
use esp_idf_sys::{
|
||||||
esp_deep_sleep, esp_restart, gpio_deep_sleep_hold_dis, gpio_deep_sleep_hold_en, vTaskDelay,
|
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, gpio_deep_sleep_hold_dis, gpio_deep_sleep_hold_en, vTaskDelay, CONFIG_FREERTOS_HZ
|
||||||
CONFIG_FREERTOS_HZ,
|
|
||||||
};
|
};
|
||||||
use log::error;
|
use log::error;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
@ -18,7 +14,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{Config, WifiConfig},
|
config::{Config, WifiConfig},
|
||||||
espota::rollback_and_reboot,
|
espota::{mark_app_valid, rollback_and_reboot},
|
||||||
webserver::webserver::{httpd, httpd_initial},
|
webserver::webserver::{httpd, httpd_initial},
|
||||||
};
|
};
|
||||||
mod config;
|
mod config;
|
||||||
@ -83,7 +79,7 @@ struct PlantState {
|
|||||||
sensor_error_b: Option<SensorError>,
|
sensor_error_b: Option<SensorError>,
|
||||||
sensor_error_p: Option<SensorError>,
|
sensor_error_p: Option<SensorError>,
|
||||||
out_of_work_hour: bool,
|
out_of_work_hour: bool,
|
||||||
next_pump: Option<DateTime<Tz>>
|
next_pump: Option<DateTime<Tz>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
|
||||||
@ -120,28 +116,41 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
log::info!("Startup Rust");
|
log::info!("Startup Rust");
|
||||||
|
|
||||||
let git_hash = env!("VERGEN_GIT_DESCRIBE");
|
let git_hash = env!("VERGEN_GIT_DESCRIBE");
|
||||||
println!("Version useing git has {}", git_hash);
|
let build_timestamp = env!("VERGEN_BUILD_TIMESTAMP");
|
||||||
|
println!(
|
||||||
|
"Version useing git has {} build on {}",
|
||||||
|
git_hash, build_timestamp
|
||||||
|
);
|
||||||
|
|
||||||
let partition_state: embedded_svc::ota::SlotState = embedded_svc::ota::SlotState::Unknown;
|
let count = unsafe { esp_ota_get_app_partition_count() };
|
||||||
match esp_idf_svc::ota::EspOta::new() {
|
println!("Partition count is {}", count);
|
||||||
Ok(ota) => {
|
let mut ota_state: esp_ota_img_states_t = 0;
|
||||||
//match ota.get_running_slot(){
|
let running_partition = unsafe { esp_ota_get_running_partition() };
|
||||||
// Ok(slot) => {
|
let address = unsafe {
|
||||||
// partition_state = slot.state;
|
(*running_partition).address
|
||||||
// println!(
|
|
||||||
// "Booting from {} with state {:?}",
|
};
|
||||||
// slot.label, partition_state
|
println!("Partition address is {}", address);
|
||||||
// );
|
|
||||||
//},
|
let ota_state_string = unsafe {
|
||||||
// Err(err) => {
|
esp_ota_get_state_partition(running_partition, &mut ota_state);
|
||||||
// println!("Error getting running slot {}", err);
|
if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_NEW {
|
||||||
// },
|
format!("Partition state is {}", "ESP_OTA_IMG_NEW")
|
||||||
//}
|
} else if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_PENDING_VERIFY {
|
||||||
|
format!("Partition state is {}", "ESP_OTA_IMG_PENDING_VERIFY")
|
||||||
|
} else if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_VALID {
|
||||||
|
format!("Partition state is {}", "ESP_OTA_IMG_VALID")
|
||||||
|
} else if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_INVALID {
|
||||||
|
format!("Partition state is {}", "ESP_OTA_IMG_INVALID")
|
||||||
|
} else if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_ABORTED {
|
||||||
|
format!("Partition state is {}", "ESP_OTA_IMG_ABORTED")
|
||||||
|
} else if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_UNDEFINED {
|
||||||
|
format!("Partition state is {}", "ESP_OTA_IMG_UNDEFINED")
|
||||||
|
} else {
|
||||||
|
format!("Partition state is {}", ota_state)
|
||||||
}
|
}
|
||||||
Err(err) => {
|
};
|
||||||
println!("Error obtaining ota info {}", err);
|
println!("{}", ota_state_string);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Board hal init");
|
println!("Board hal init");
|
||||||
let mut board: std::sync::MutexGuard<'_, PlantCtrlBoard<'_>> = BOARD_ACCESS.lock().unwrap();
|
let mut board: std::sync::MutexGuard<'_, PlantCtrlBoard<'_>> = BOARD_ACCESS.lock().unwrap();
|
||||||
@ -211,13 +220,9 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if board.is_wifi_config_file_existant() {
|
if board.is_wifi_config_file_existant() {
|
||||||
match partition_state {
|
if ota_state == esp_ota_img_states_t_ESP_OTA_IMG_PENDING_VERIFY {
|
||||||
embedded_svc::ota::SlotState::Invalid
|
println!("Config seem to be unparsable after upgrade, reverting");
|
||||||
| embedded_svc::ota::SlotState::Unverified => {
|
rollback_and_reboot()?;
|
||||||
println!("Config seem to be unparsable after upgrade, reverting");
|
|
||||||
rollback_and_reboot()?;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("Missing wifi config, entering initial config mode {}", err);
|
println!("Missing wifi config, entering initial config mode {}", err);
|
||||||
@ -288,15 +293,26 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
if online_mode == OnlineMode::Online {
|
if online_mode == OnlineMode::Online {
|
||||||
let _ = board.mqtt_publish(&config, "/firmware/githash", git_hash.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/last_online", europe_time.to_rfc3339().as_bytes());
|
||||||
|
let _ = board.mqtt_publish(&config, "/firmware/ota_state", ota_state_string.as_bytes());
|
||||||
|
let _ = board.mqtt_publish(&config, "/firmware/partition_address", format!("{:#06x}",address).as_bytes());
|
||||||
let _ = board.mqtt_publish(&config, "/state", "online".as_bytes());
|
let _ = board.mqtt_publish(&config, "/state", "online".as_bytes());
|
||||||
let _ = board.mqtt_publish(&config, "/last_online", europe_time.to_rfc3339().as_bytes());
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
publish_battery_state(&mut board, &config);
|
publish_battery_state(&mut board, &config);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tank_state = determine_tank_state(&mut board, &config);
|
let tank_state = determine_tank_state(&mut board, &config);
|
||||||
|
if online_mode == OnlineMode::Online {
|
||||||
|
if tank_state.sensor_error {
|
||||||
|
let _ = board.mqtt_publish(&config, "/water/ml", "error".to_string().as_bytes());
|
||||||
|
} else {
|
||||||
|
let _ = board.mqtt_publish(&config, "/water/ml", tank_state.left_ml.to_string().as_bytes());
|
||||||
|
let _ = board.mqtt_publish(&config, "/water/enough_water", tank_state.enough_water.to_string().as_bytes());
|
||||||
|
let _ = board.mqtt_publish(&config, "/water/raw", tank_state.raw.to_string().as_bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let mut water_frozen = false;
|
let mut water_frozen = false;
|
||||||
for _attempt in 0..5 {
|
for _attempt in 0..5 {
|
||||||
@ -353,10 +369,9 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
board.store_consecutive_pump_count(plant, consecutive_pump_count);
|
board.store_consecutive_pump_count(plant, consecutive_pump_count);
|
||||||
let plant_config = config.plants[plant];
|
let plant_config = config.plants[plant];
|
||||||
|
|
||||||
|
|
||||||
if plant_config.sensor_p {
|
if plant_config.sensor_p {
|
||||||
match map_range_moisture(
|
match map_range_moisture(
|
||||||
board.measure_moisture_hz(plant, plant_hal::Sensor::PUMP)? as f32
|
board.measure_moisture_hz(plant, plant_hal::Sensor::PUMP)? as f32,
|
||||||
) {
|
) {
|
||||||
Ok(p) => state.p = Some(p),
|
Ok(p) => state.p = Some(p),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@ -376,36 +391,34 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
board.pump(plant, true)?;
|
board.pump(plant, true)?;
|
||||||
board.last_pump_time(plant);
|
board.last_pump_time(plant);
|
||||||
state.active = true;
|
state.active = true;
|
||||||
for t in 0..plant_config.pump_time_s {
|
for _ in 0..plant_config.pump_time_s {
|
||||||
//FIXME do periodic pump test here and state update
|
|
||||||
unsafe { vTaskDelay(CONFIG_FREERTOS_HZ) };
|
unsafe { vTaskDelay(CONFIG_FREERTOS_HZ) };
|
||||||
if plant_config.sensor_p {
|
if plant_config.sensor_p {
|
||||||
let moist = map_range_moisture(
|
let moist = map_range_moisture(
|
||||||
board.measure_moisture_hz(plant, plant_hal::Sensor::PUMP)? as f32);
|
board.measure_moisture_hz(plant, plant_hal::Sensor::PUMP)? as f32,
|
||||||
|
);
|
||||||
if online_mode == OnlineMode::Online {
|
if online_mode == OnlineMode::Online {
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/Sensor P after", plant+1).as_str(),
|
format!("/plant{}/Sensor P after", plant + 1).as_str(),
|
||||||
option_to_string(moist.ok()).as_bytes(),
|
option_to_string(moist.ok()).as_bytes(),
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if online_mode == OnlineMode::Online {
|
if online_mode == OnlineMode::Online {
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/Sensor P after", plant+1).as_str(),
|
format!("/plant{}/Sensor P after", plant + 1).as_str(),
|
||||||
"disabled".as_bytes(),
|
"disabled".as_bytes(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
board.pump(plant, false)?;
|
board.pump(plant, false)?;
|
||||||
if plant_config.sensor_p {
|
if plant_config.sensor_p {
|
||||||
match map_range_moisture(
|
match map_range_moisture(
|
||||||
board.measure_moisture_hz(plant, plant_hal::Sensor::PUMP)? as f32
|
board.measure_moisture_hz(plant, plant_hal::Sensor::PUMP)? as f32,
|
||||||
) {
|
) {
|
||||||
Ok(p) => state.after_p = Some(p),
|
Ok(p) => state.after_p = Some(p),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@ -422,7 +435,6 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
//mqtt sync pump error value
|
//mqtt sync pump error value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
println!("Nothing to do");
|
println!("Nothing to do");
|
||||||
@ -434,7 +446,8 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
let mut light_state = LightState {
|
let mut light_state = LightState {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
light_state.is_day = board.is_day();
|
let is_day = board.is_day();
|
||||||
|
light_state.is_day = is_day;
|
||||||
light_state.out_of_work_hour = !in_time_range(
|
light_state.out_of_work_hour = !in_time_range(
|
||||||
europe_time,
|
europe_time,
|
||||||
config.night_lamp_hour_start,
|
config.night_lamp_hour_start,
|
||||||
@ -489,12 +502,42 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
unsafe { gpio_deep_sleep_hold_dis() };
|
unsafe { gpio_deep_sleep_hold_dis() };
|
||||||
unsafe { gpio_deep_sleep_hold_en() };
|
unsafe { gpio_deep_sleep_hold_en() };
|
||||||
|
|
||||||
|
let deep_sleep_duration_minutes: u32 = if state_of_charge < 10 {
|
||||||
|
if online_mode == OnlineMode::Online {
|
||||||
|
let _ = board.mqtt_publish(
|
||||||
|
&config,
|
||||||
|
"/deepsleep",
|
||||||
|
"Entering low voltage long deep sleep".as_bytes(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
12 * 60
|
||||||
|
} else if is_day {
|
||||||
|
if online_mode == OnlineMode::Online {
|
||||||
|
let _ = board.mqtt_publish(
|
||||||
|
&config,
|
||||||
|
"/deepsleep",
|
||||||
|
"Entering normal mode 20m deep sleep".as_bytes(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
20
|
||||||
|
} else {
|
||||||
|
if online_mode == OnlineMode::Online {
|
||||||
|
let _ = board.mqtt_publish(
|
||||||
|
&config,
|
||||||
|
"/deepsleep",
|
||||||
|
"Entering night mode 1h deep sleep".as_bytes(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
60
|
||||||
|
};
|
||||||
//determine next event
|
//determine next event
|
||||||
//is light out of work trigger soon?
|
//is light out of work trigger soon?
|
||||||
//is battery low ??
|
//is battery low ??
|
||||||
//is deep sleep
|
//is deep sleep
|
||||||
|
|
||||||
unsafe { esp_deep_sleep(1000 * 1000 * 20) };
|
mark_app_valid();
|
||||||
|
|
||||||
|
unsafe { esp_deep_sleep(1000 * 1000 * 60 * deep_sleep_duration_minutes as u64) };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn publish_battery_state(
|
fn publish_battery_state(
|
||||||
@ -770,9 +813,10 @@ fn determine_state_target_moisture_for_plant(
|
|||||||
|
|
||||||
if a_low || b_low {
|
if a_low || b_low {
|
||||||
state.dry = true;
|
state.dry = true;
|
||||||
if tank_state.sensor_error && !config.tank_allow_pumping_if_sensor_error
|
if tank_state.sensor_error && !config.tank_allow_pumping_if_sensor_error {
|
||||||
|| !tank_state.enough_water
|
//ignore is ok
|
||||||
{
|
}
|
||||||
|
else if !tank_state.enough_water {
|
||||||
state.no_water = true;
|
state.no_water = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -900,14 +944,18 @@ fn determine_next_plant(
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_plant_state(plantstate: &mut [PlantState; PLANT_COUNT], board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>, config: &Config){
|
fn update_plant_state(
|
||||||
|
plantstate: &mut [PlantState; PLANT_COUNT],
|
||||||
|
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
|
||||||
|
config: &Config,
|
||||||
|
) {
|
||||||
for plant in 0..PLANT_COUNT {
|
for plant in 0..PLANT_COUNT {
|
||||||
let state = &plantstate[plant];
|
let state = &plantstate[plant];
|
||||||
let plant_config = config.plants[plant];
|
let plant_config = config.plants[plant];
|
||||||
|
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/mode", plant+1).as_str(),
|
format!("/plant{}/mode", plant + 1).as_str(),
|
||||||
match plant_config.mode {
|
match plant_config.mode {
|
||||||
config::Mode::OFF => "OFF".as_bytes(),
|
config::Mode::OFF => "OFF".as_bytes(),
|
||||||
config::Mode::TargetMoisture => "TargetMoisture".as_bytes(),
|
config::Mode::TargetMoisture => "TargetMoisture".as_bytes(),
|
||||||
@ -922,13 +970,13 @@ fn update_plant_state(plantstate: &mut [PlantState; PLANT_COUNT], board: &mut st
|
|||||||
let time = europe_time.to_rfc3339();
|
let time = europe_time.to_rfc3339();
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/last pump", plant+1).as_str(),
|
format!("/plant{}/last pump", plant + 1).as_str(),
|
||||||
time.as_bytes(),
|
time.as_bytes(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/last pump", plant+1).as_str(),
|
format!("/plant{}/last pump", plant + 1).as_str(),
|
||||||
"N/A".as_bytes(),
|
"N/A".as_bytes(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -938,35 +986,34 @@ fn update_plant_state(plantstate: &mut [PlantState; PLANT_COUNT], board: &mut st
|
|||||||
let time = next.to_rfc3339();
|
let time = next.to_rfc3339();
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/next pump", plant+1).as_str(),
|
format!("/plant{}/next pump", plant + 1).as_str(),
|
||||||
time.as_bytes(),
|
time.as_bytes(),
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
None => {
|
None => {
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/next pump", plant+1).as_str(),
|
format!("/plant{}/next pump", plant + 1).as_str(),
|
||||||
"N/A".as_bytes(),
|
"N/A".as_bytes(),
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/Sensor A", plant+1).as_str(),
|
format!("/plant{}/Sensor A", plant + 1).as_str(),
|
||||||
option_to_string(state.a).as_bytes(),
|
option_to_string(state.a).as_bytes(),
|
||||||
);
|
);
|
||||||
if plant_config.sensor_b {
|
if plant_config.sensor_b {
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/Sensor B", plant+1).as_str(),
|
format!("/plant{}/Sensor B", plant + 1).as_str(),
|
||||||
option_to_string(state.b).as_bytes(),
|
option_to_string(state.b).as_bytes(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/Sensor B", plant+1).as_str(),
|
format!("/plant{}/Sensor B", plant + 1).as_str(),
|
||||||
"disabled".as_bytes(),
|
"disabled".as_bytes(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -974,65 +1021,65 @@ fn update_plant_state(plantstate: &mut [PlantState; PLANT_COUNT], board: &mut st
|
|||||||
if plant_config.sensor_p {
|
if plant_config.sensor_p {
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/Sensor P before", plant+1).as_str(),
|
format!("/plant{}/Sensor P before", plant + 1).as_str(),
|
||||||
option_to_string(state.p).as_bytes(),
|
option_to_string(state.p).as_bytes(),
|
||||||
);
|
);
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/Sensor P after", plant+1).as_str(),
|
format!("/plant{}/Sensor P after", plant + 1).as_str(),
|
||||||
option_to_string(state.after_p).as_bytes(),
|
option_to_string(state.after_p).as_bytes(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/Sensor P before", plant+1).as_str(),
|
format!("/plant{}/Sensor P before", plant + 1).as_str(),
|
||||||
"disabled".as_bytes(),
|
"disabled".as_bytes(),
|
||||||
);
|
);
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/Sensor P after", plant+1).as_str(),
|
format!("/plant{}/Sensor P after", plant + 1).as_str(),
|
||||||
"disabled".as_bytes(),
|
"disabled".as_bytes(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/Should water", plant+1).as_str(),
|
format!("/plant{}/Should water", plant + 1).as_str(),
|
||||||
state.do_water.to_string().as_bytes(),
|
state.do_water.to_string().as_bytes(),
|
||||||
);
|
);
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/Is frozen", plant+1).as_str(),
|
format!("/plant{}/Is frozen", plant + 1).as_str(),
|
||||||
state.frozen.to_string().as_bytes(),
|
state.frozen.to_string().as_bytes(),
|
||||||
);
|
);
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/Is dry", plant+1).as_str(),
|
format!("/plant{}/Is dry", plant + 1).as_str(),
|
||||||
state.dry.to_string().as_bytes(),
|
state.dry.to_string().as_bytes(),
|
||||||
);
|
);
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/Pump Error", plant+1).as_str(),
|
format!("/plant{}/Pump Error", plant + 1).as_str(),
|
||||||
state.pump_error.to_string().as_bytes(),
|
state.pump_error.to_string().as_bytes(),
|
||||||
);
|
);
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/Pump Ineffective", plant+1).as_str(),
|
format!("/plant{}/Pump Ineffective", plant + 1).as_str(),
|
||||||
state.not_effective.to_string().as_bytes(),
|
state.not_effective.to_string().as_bytes(),
|
||||||
);
|
);
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/Is in Cooldown", plant+1).as_str(),
|
format!("/plant{}/Is in Cooldown", plant + 1).as_str(),
|
||||||
state.cooldown.to_string().as_bytes(),
|
state.cooldown.to_string().as_bytes(),
|
||||||
);
|
);
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/No Water", plant+1).as_str(),
|
format!("/plant{}/No Water", plant + 1).as_str(),
|
||||||
state.no_water.to_string().as_bytes(),
|
state.no_water.to_string().as_bytes(),
|
||||||
);
|
);
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
format!("/plant{}/Out of Work Hour", plant+1).as_str(),
|
format!("/plant{}/Out of Work Hour", plant + 1).as_str(),
|
||||||
state.out_of_work_hour.to_string().as_bytes(),
|
state.out_of_work_hour.to_string().as_bytes(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1079,7 +1126,18 @@ fn wait_infinity(wait_type: WaitType, reboot_now: Arc<AtomicBool>) -> ! {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let result = safe_main();
|
let result = safe_main();
|
||||||
result.unwrap();
|
match result {
|
||||||
|
Ok(_) => {
|
||||||
|
println!("Main app finished, restarting");
|
||||||
|
unsafe { esp_restart() };
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
println!("Failed main {}", err);
|
||||||
|
let rollback_successful = rollback_and_reboot();
|
||||||
|
println!("Failed to rollback :(");
|
||||||
|
rollback_successful.unwrap();
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//error codes
|
//error codes
|
||||||
//error_reading_config_after_upgrade
|
//error_reading_config_after_upgrade
|
||||||
|
@ -159,7 +159,6 @@ pub struct PlantCtrlBoard<'a> {
|
|||||||
PinDriver<'a, esp_idf_hal::gpio::Gpio22, InputOutput>,
|
PinDriver<'a, esp_idf_hal::gpio::Gpio22, InputOutput>,
|
||||||
PinDriver<'a, esp_idf_hal::gpio::Gpio19, InputOutput>,
|
PinDriver<'a, esp_idf_hal::gpio::Gpio19, InputOutput>,
|
||||||
>,
|
>,
|
||||||
low_voltage_detected: Mutex<bool>,
|
|
||||||
tank_driver: AdcDriver<'a, esp_idf_hal::adc::ADC1>,
|
tank_driver: AdcDriver<'a, esp_idf_hal::adc::ADC1>,
|
||||||
tank_channel: esp_idf_hal::adc::AdcChannelDriver<'a, { attenuation::DB_11 }, Gpio39>,
|
tank_channel: esp_idf_hal::adc::AdcChannelDriver<'a, { attenuation::DB_11 }, Gpio39>,
|
||||||
solar_is_day: PinDriver<'a, esp_idf_hal::gpio::Gpio25, esp_idf_hal::gpio::Input>,
|
solar_is_day: PinDriver<'a, esp_idf_hal::gpio::Gpio25, esp_idf_hal::gpio::Input>,
|
||||||
@ -963,8 +962,6 @@ impl CreatePlantHal<'_> for PlantHal {
|
|||||||
let nvs = EspDefaultNvsPartition::take()?;
|
let nvs = EspDefaultNvsPartition::take()?;
|
||||||
let wifi_driver = EspWifi::new(peripherals.modem, sys_loop, Some(nvs))?;
|
let wifi_driver = EspWifi::new(peripherals.modem, sys_loop, Some(nvs))?;
|
||||||
|
|
||||||
let low_voltage_detected = Mutex::new(unsafe { LOW_VOLTAGE_DETECTED });
|
|
||||||
|
|
||||||
let adc_config = esp_idf_hal::adc::config::Config {
|
let adc_config = esp_idf_hal::adc::config::Config {
|
||||||
resolution: esp_idf_hal::adc::config::Resolution::Resolution12Bit,
|
resolution: esp_idf_hal::adc::config::Resolution::Resolution12Bit,
|
||||||
calibration: true,
|
calibration: true,
|
||||||
@ -1001,7 +998,6 @@ impl CreatePlantHal<'_> for PlantHal {
|
|||||||
}
|
}
|
||||||
let rv = Mutex::new(PlantCtrlBoard {
|
let rv = Mutex::new(PlantCtrlBoard {
|
||||||
shift_register,
|
shift_register,
|
||||||
low_voltage_detected,
|
|
||||||
tank_driver,
|
tank_driver,
|
||||||
tank_channel,
|
tank_channel,
|
||||||
solar_is_day,
|
solar_is_day,
|
||||||
|
Loading…
Reference in New Issue
Block a user