more stack for json, more json for mqtt
This commit is contained in:
parent
b57eb2513c
commit
4d92e0c2a6
@ -1,5 +1,5 @@
|
|||||||
# Rust often needs a bit of an extra main task stack size compared to C (the default is 3K)
|
# Rust often needs a bit of an extra main task stack size compared to C (the default is 3K)
|
||||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=25000
|
CONFIG_ESP_MAIN_TASK_STACK_SIZE=50000
|
||||||
|
|
||||||
# Use this to set FreeRTOS kernel tick frequency to 1000 Hz (100 Hz by default).
|
# Use this to set FreeRTOS kernel tick frequency to 1000 Hz (100 Hz by default).
|
||||||
# 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).
|
||||||
|
292
rust/src/main.rs
292
rust/src/main.rs
@ -46,7 +46,7 @@ mod webserver {
|
|||||||
pub mod webserver;
|
pub mod webserver;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
enum OnlineMode {
|
enum OnlineMode {
|
||||||
Offline,
|
Offline,
|
||||||
Wifi,
|
Wifi,
|
||||||
@ -54,7 +54,7 @@ enum OnlineMode {
|
|||||||
Online,
|
Online,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
enum WaitType {
|
enum WaitType {
|
||||||
InitialConfig,
|
InitialConfig,
|
||||||
FlashError,
|
FlashError,
|
||||||
@ -62,7 +62,7 @@ enum WaitType {
|
|||||||
StayAlive,
|
StayAlive,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Default)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
|
||||||
struct LightState {
|
struct LightState {
|
||||||
active: bool,
|
active: bool,
|
||||||
out_of_work_hour: bool,
|
out_of_work_hour: bool,
|
||||||
@ -70,7 +70,7 @@ struct LightState {
|
|||||||
is_day: bool,
|
is_day: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Default)]
|
#[derive(Debug, PartialEq, Default)]
|
||||||
struct PlantState {
|
struct PlantState {
|
||||||
a: Option<u8>,
|
a: Option<u8>,
|
||||||
b: Option<u8>,
|
b: Option<u8>,
|
||||||
@ -91,14 +91,14 @@ struct PlantState {
|
|||||||
next_pump: Option<DateTime<Tz>>,
|
next_pump: Option<DateTime<Tz>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
enum SensorError {
|
enum SensorError {
|
||||||
Unknown,
|
Unknown,
|
||||||
ShortCircuit { hz: f32, max: f32 },
|
ShortCircuit { hz: f32, max: f32 },
|
||||||
OpenCircuit { hz: f32, min: f32 },
|
OpenCircuit { hz: f32, min: f32 },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Default)]
|
#[derive(Debug, PartialEq, Default)]
|
||||||
struct TankState {
|
struct TankState {
|
||||||
enough_water: bool,
|
enough_water: bool,
|
||||||
warn_level: bool,
|
warn_level: bool,
|
||||||
@ -113,7 +113,7 @@ struct TankStateMQTT {
|
|||||||
left_ml: u32,
|
left_ml: u32,
|
||||||
sensor_error: bool,
|
sensor_error: bool,
|
||||||
raw: u16,
|
raw: u16,
|
||||||
water_frozen: String
|
water_frozen: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
@ -365,13 +365,13 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tank_state = determine_tank_state(&mut board, &config);
|
let tank_state = determine_tank_state(&mut board, &config);
|
||||||
let mut tank_state_mqtt = TankStateMQTT{
|
let mut tank_state_mqtt = TankStateMQTT {
|
||||||
enough_water : tank_state.enough_water,
|
enough_water: tank_state.enough_water,
|
||||||
left_ml : tank_state.left_ml,
|
left_ml: tank_state.left_ml,
|
||||||
warn_level : tank_state.warn_level,
|
warn_level: tank_state.warn_level,
|
||||||
sensor_error: tank_state.sensor_error,
|
sensor_error: tank_state.sensor_error,
|
||||||
raw: tank_state.raw,
|
raw: tank_state.raw,
|
||||||
water_frozen: "".to_owned()
|
water_frozen: "".to_owned(),
|
||||||
};
|
};
|
||||||
let mut water_frozen = false;
|
let mut water_frozen = false;
|
||||||
|
|
||||||
@ -396,9 +396,7 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
tank_state_mqtt.water_frozen = water_frozen.to_string();
|
tank_state_mqtt.water_frozen = water_frozen.to_string();
|
||||||
}
|
}
|
||||||
None => {
|
None => tank_state_mqtt.water_frozen = "tank sensor error".to_owned(),
|
||||||
tank_state_mqtt.water_frozen = "tank sensor error".to_owned()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if online_mode == OnlineMode::Online {
|
if online_mode == OnlineMode::Online {
|
||||||
@ -412,9 +410,9 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut plantstate = [PlantState {
|
let mut plantstate: [PlantState; PLANT_COUNT] = core::array::from_fn(|_| PlantState {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}; PLANT_COUNT];
|
});
|
||||||
let plant_to_pump = determine_next_plant(
|
let plant_to_pump = determine_next_plant(
|
||||||
&mut plantstate,
|
&mut plantstate,
|
||||||
europe_time,
|
europe_time,
|
||||||
@ -426,12 +424,7 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
let stay_alive = STAY_ALIVE.load(std::sync::atomic::Ordering::Relaxed);
|
let stay_alive = STAY_ALIVE.load(std::sync::atomic::Ordering::Relaxed);
|
||||||
println!("Check stay alive, current state is {}", stay_alive);
|
println!("Check stay alive, current state is {}", stay_alive);
|
||||||
if stay_alive {
|
|
||||||
drop(board);
|
|
||||||
let reboot_now = Arc::new(AtomicBool::new(false));
|
|
||||||
let _webserver = httpd(reboot_now.clone());
|
|
||||||
wait_infinity(WaitType::StayAlive, reboot_now.clone());
|
|
||||||
}
|
|
||||||
let mut did_pump = false;
|
let mut did_pump = false;
|
||||||
match plant_to_pump {
|
match plant_to_pump {
|
||||||
Some(plant) => {
|
Some(plant) => {
|
||||||
@ -461,6 +454,7 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
"Trying to pump for {}s with pump {} now",
|
"Trying to pump for {}s with pump {} now",
|
||||||
plant_config.pump_time_s, plant
|
plant_config.pump_time_s, plant
|
||||||
);
|
);
|
||||||
|
if !stay_alive {
|
||||||
did_pump = true;
|
did_pump = true;
|
||||||
board.any_pump(true)?;
|
board.any_pump(true)?;
|
||||||
board.store_last_pump_time(plant, cur);
|
board.store_last_pump_time(plant, cur);
|
||||||
@ -469,7 +463,7 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
state.active = true;
|
state.active = true;
|
||||||
for _ in 0..plant_config.pump_time_s {
|
for _ in 0..plant_config.pump_time_s {
|
||||||
unsafe { vTaskDelay(CONFIG_FREERTOS_HZ) };
|
unsafe { vTaskDelay(CONFIG_FREERTOS_HZ) };
|
||||||
let p_live_topic = format!("/plant{}/p live", plant + 1);
|
let p_live_topic = format!("/plant{} p live", plant + 1);
|
||||||
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,
|
||||||
@ -478,17 +472,20 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(
|
||||||
&config,
|
&config,
|
||||||
&p_live_topic,
|
&p_live_topic,
|
||||||
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(&config, &p_live_topic, "disabled".as_bytes());
|
let _ =
|
||||||
|
board.mqtt_publish(&config, &p_live_topic, "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,
|
||||||
@ -522,7 +519,7 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
let is_day = board.is_day();
|
let is_day = board.is_day();
|
||||||
light_state.is_day = 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,
|
||||||
config.night_lamp_hour_end,
|
config.night_lamp_hour_end,
|
||||||
);
|
);
|
||||||
@ -604,16 +601,14 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
//is deep sleep
|
//is deep sleep
|
||||||
mark_app_valid();
|
mark_app_valid();
|
||||||
|
|
||||||
unsafe { esp_deep_sleep(1000 * 1000 * 60 * deep_sleep_duration_minutes as u64) };
|
if stay_alive {
|
||||||
}
|
drop(board);
|
||||||
|
let reboot_now = Arc::new(AtomicBool::new(false));
|
||||||
fn to_string<T: Display>(value: Result<T>) -> String {
|
let _webserver = httpd(reboot_now.clone());
|
||||||
return match value {
|
wait_infinity(WaitType::StayAlive, reboot_now.clone());
|
||||||
Ok(v) => v.to_string(),
|
|
||||||
Err(err) => {
|
|
||||||
format!("{:?}", err)
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
unsafe { esp_deep_sleep(1000 * 1000 * 60 * deep_sleep_duration_minutes as u64) };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn publish_battery_state(
|
fn publish_battery_state(
|
||||||
@ -621,13 +616,13 @@ fn publish_battery_state(
|
|||||||
config: &Config,
|
config: &Config,
|
||||||
) {
|
) {
|
||||||
let bat = BatteryState {
|
let bat = BatteryState {
|
||||||
voltage_milli_volt: &to_string(board.voltage_milli_volt()),
|
voltage_milli_volt: &to_string(&board.voltage_milli_volt()),
|
||||||
current_milli_ampere: &to_string(board.average_current_milli_ampere()),
|
current_milli_ampere: &to_string(&board.average_current_milli_ampere()),
|
||||||
cycle_count: &to_string(board.cycle_count()),
|
cycle_count: &to_string(&board.cycle_count()),
|
||||||
design_milli_ampere: &to_string(board.design_milli_ampere_hour()),
|
design_milli_ampere: &to_string(&board.design_milli_ampere_hour()),
|
||||||
remaining_milli_ampere: &to_string(board.remaining_milli_ampere_hour()),
|
remaining_milli_ampere: &to_string(&board.remaining_milli_ampere_hour()),
|
||||||
state_of_charge: &to_string(board.state_charge_percent()),
|
state_of_charge: &to_string(&board.state_charge_percent()),
|
||||||
state_of_health: &to_string(board.state_health_percent()),
|
state_of_health: &to_string(&board.state_health_percent()),
|
||||||
};
|
};
|
||||||
match serde_json::to_string(&bat) {
|
match serde_json::to_string(&bat) {
|
||||||
Ok(state) => {
|
Ok(state) => {
|
||||||
@ -701,54 +696,6 @@ fn determine_tank_state(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_range(from_range: (f32, f32), s: f32) -> anyhow::Result<f32> {
|
|
||||||
if s < from_range.0 {
|
|
||||||
anyhow::bail!(
|
|
||||||
"Value out of range, min {} but current is {}",
|
|
||||||
from_range.0,
|
|
||||||
s
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if s > from_range.1 {
|
|
||||||
anyhow::bail!(
|
|
||||||
"Value out of range, max {} but current is {}",
|
|
||||||
from_range.1,
|
|
||||||
s
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return Ok(TO.0 + (s - from_range.0) * (TO.1 - TO.0) / (from_range.1 - from_range.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn map_range_moisture(s: f32) -> Result<u8, SensorError> {
|
|
||||||
if s < FROM.0 {
|
|
||||||
return Err(SensorError::OpenCircuit { hz: s, min: FROM.0 });
|
|
||||||
}
|
|
||||||
if s > FROM.1 {
|
|
||||||
return Err(SensorError::ShortCircuit { hz: s, max: FROM.1 });
|
|
||||||
}
|
|
||||||
let tmp = TO.0 + (s - FROM.0) * (TO.1 - TO.0) / (FROM.1 - FROM.0);
|
|
||||||
|
|
||||||
return Ok(tmp as u8);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn in_time_range(cur: DateTime<Tz>, start: u8, end: u8) -> bool {
|
|
||||||
let curhour = cur.hour() as u8;
|
|
||||||
//eg 10-14
|
|
||||||
if start < end {
|
|
||||||
return curhour > start && curhour < end;
|
|
||||||
} else {
|
|
||||||
//eg 20-05
|
|
||||||
return curhour > start || curhour < end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn option_to_string(value: Option<u8>) -> String {
|
|
||||||
match value {
|
|
||||||
Some(v) => v.to_string(),
|
|
||||||
None => "Error".to_owned(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn determine_state_target_moisture_for_plant(
|
fn determine_state_target_moisture_for_plant(
|
||||||
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
|
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
|
||||||
plant: usize,
|
plant: usize,
|
||||||
@ -761,7 +708,20 @@ fn determine_state_target_moisture_for_plant(
|
|||||||
if plant_config.mode == Mode::OFF {
|
if plant_config.mode == Mode::OFF {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
match board.measure_moisture_hz(plant, plant_hal::Sensor::A) {
|
||||||
|
Ok(a) => {
|
||||||
|
let mapped = map_range_moisture(a as f32);
|
||||||
|
match mapped {
|
||||||
|
Ok(result) => state.a = Some(result),
|
||||||
|
Err(err) => {
|
||||||
|
state.sensor_error_a = Some(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
state.sensor_error_a = Some(SensorError::Unknown);
|
||||||
|
}
|
||||||
|
}
|
||||||
if plant_config.sensor_b {
|
if plant_config.sensor_b {
|
||||||
match board.measure_moisture_hz(plant, plant_hal::Sensor::B) {
|
match board.measure_moisture_hz(plant, plant_hal::Sensor::B) {
|
||||||
Ok(b) => {
|
Ok(b) => {
|
||||||
@ -813,7 +773,7 @@ fn determine_state_target_moisture_for_plant(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !in_time_range(
|
if !in_time_range(
|
||||||
cur,
|
&cur,
|
||||||
plant_config.pump_hour_start,
|
plant_config.pump_hour_start,
|
||||||
plant_config.pump_hour_end,
|
plant_config.pump_hour_end,
|
||||||
) {
|
) {
|
||||||
@ -883,7 +843,7 @@ fn determine_state_timer_and_deadzone_for_plant(
|
|||||||
state.cooldown = true;
|
state.cooldown = true;
|
||||||
}
|
}
|
||||||
if !in_time_range(
|
if !in_time_range(
|
||||||
cur,
|
&cur,
|
||||||
plant_config.pump_hour_start,
|
plant_config.pump_hour_start,
|
||||||
plant_config.pump_hour_end,
|
plant_config.pump_hour_end,
|
||||||
) {
|
) {
|
||||||
@ -976,13 +936,17 @@ fn update_plant_state(
|
|||||||
let mode = format!("{:?}", plant_config.mode);
|
let mode = format!("{:?}", plant_config.mode);
|
||||||
|
|
||||||
let plant_dto = PlantStateMQTT {
|
let plant_dto = PlantStateMQTT {
|
||||||
p_start: &sensor_to_string(state.p, state.sensor_error_p, plant_config.sensor_p),
|
p_start: &sensor_to_string(&state.p, &state.sensor_error_p, plant_config.sensor_p),
|
||||||
p_end: &sensor_to_string(state.after_p, state.sensor_error_p, plant_config.sensor_p),
|
p_end: &sensor_to_string(&state.after_p, &state.sensor_error_p, plant_config.sensor_p),
|
||||||
a: &sensor_to_string(state.a, state.sensor_error_a, true),
|
a: &sensor_to_string(
|
||||||
b: &sensor_to_string(state.b, state.sensor_error_b, plant_config.sensor_b),
|
&state.a,
|
||||||
|
&state.sensor_error_a,
|
||||||
|
plant_config.mode != Mode::OFF,
|
||||||
|
),
|
||||||
|
b: &sensor_to_string(&state.b, &state.sensor_error_b, plant_config.sensor_b),
|
||||||
active: state.active,
|
active: state.active,
|
||||||
mode: &mode,
|
mode: &mode,
|
||||||
last_pump: &&time_to_string_utc(board.last_pump_time(plant)),
|
last_pump: &time_to_string_utc(board.last_pump_time(plant)),
|
||||||
next_pump: &time_to_string(state.next_pump),
|
next_pump: &time_to_string(state.next_pump),
|
||||||
consecutive_pump_count: state.consecutive_pump_count,
|
consecutive_pump_count: state.consecutive_pump_count,
|
||||||
cooldown: state.cooldown,
|
cooldown: state.cooldown,
|
||||||
@ -996,6 +960,8 @@ fn update_plant_state(
|
|||||||
Ok(state) => {
|
Ok(state) => {
|
||||||
let plant_topic = format!("/plant{}", plant + 1);
|
let plant_topic = format!("/plant{}", plant + 1);
|
||||||
let _ = board.mqtt_publish(&config, &plant_topic, state.as_bytes());
|
let _ = board.mqtt_publish(&config, &plant_topic, state.as_bytes());
|
||||||
|
//reduce speed as else messages will be dropped
|
||||||
|
Delay::new_default().delay_ms(200);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("Error publishing lightstate {}", err);
|
println!("Error publishing lightstate {}", err);
|
||||||
@ -1004,39 +970,6 @@ fn update_plant_state(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn time_to_string_utc(value_option: Option<DateTime<Utc>>) -> String {
|
|
||||||
let converted = value_option.and_then(|utc| Some(utc.with_timezone(&Berlin)));
|
|
||||||
return time_to_string(converted);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn time_to_string(value_option: Option<DateTime<Tz>>) -> String {
|
|
||||||
match value_option {
|
|
||||||
Some(value) => {
|
|
||||||
let europe_time = value.with_timezone(&Berlin);
|
|
||||||
if europe_time.year() > 2023 {
|
|
||||||
return europe_time.to_rfc3339();
|
|
||||||
} else {
|
|
||||||
return "smtp error".to_owned();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => return "N/A".to_owned(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sensor_to_string(value: Option<u8>, error: Option<SensorError>, enabled: bool) -> String {
|
|
||||||
if enabled {
|
|
||||||
match error {
|
|
||||||
Some(error) => return format!("{:?}", error),
|
|
||||||
None => match value {
|
|
||||||
Some(v) => return v.to_string(),
|
|
||||||
None => return "Error".to_owned(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return "disabled".to_owned();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
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::InitialConfig => 250_u32,
|
WaitType::InitialConfig => 250_u32,
|
||||||
@ -1091,7 +1024,94 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//error codes
|
|
||||||
//error_reading_config_after_upgrade
|
fn time_to_string_utc(value_option: Option<DateTime<Utc>>) -> String {
|
||||||
//error_no_config_after_upgrade
|
let converted = value_option.and_then(|utc| Some(utc.with_timezone(&Berlin)));
|
||||||
//error_tank_sensor_fault
|
return time_to_string(converted);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn time_to_string(value_option: Option<DateTime<Tz>>) -> String {
|
||||||
|
match value_option {
|
||||||
|
Some(value) => {
|
||||||
|
let europe_time = value.with_timezone(&Berlin);
|
||||||
|
if europe_time.year() > 2023 {
|
||||||
|
return europe_time.to_rfc3339();
|
||||||
|
} else {
|
||||||
|
//initial value of 0 in rtc memory
|
||||||
|
return "N/A".to_owned();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => return "N/A".to_owned(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sensor_to_string(value: &Option<u8>, error: &Option<SensorError>, enabled: bool) -> String {
|
||||||
|
if enabled {
|
||||||
|
match error {
|
||||||
|
Some(error) => return format!("{:?}", error),
|
||||||
|
None => match value {
|
||||||
|
Some(v) => return v.to_string(),
|
||||||
|
None => return "Error".to_owned(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return "disabled".to_owned();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_string<T: Display>(value: &Result<T>) -> String {
|
||||||
|
return match value {
|
||||||
|
Ok(v) => v.to_string(),
|
||||||
|
Err(err) => {
|
||||||
|
format!("{:?}", err)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_range(from_range: (f32, f32), s: f32) -> anyhow::Result<f32> {
|
||||||
|
if s < from_range.0 {
|
||||||
|
anyhow::bail!(
|
||||||
|
"Value out of range, min {} but current is {}",
|
||||||
|
from_range.0,
|
||||||
|
s
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if s > from_range.1 {
|
||||||
|
anyhow::bail!(
|
||||||
|
"Value out of range, max {} but current is {}",
|
||||||
|
from_range.1,
|
||||||
|
s
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Ok(TO.0 + (s - from_range.0) * (TO.1 - TO.0) / (from_range.1 - from_range.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_range_moisture(s: f32) -> Result<u8, SensorError> {
|
||||||
|
if s < FROM.0 {
|
||||||
|
return Err(SensorError::OpenCircuit { hz: s, min: FROM.0 });
|
||||||
|
}
|
||||||
|
if s > FROM.1 {
|
||||||
|
return Err(SensorError::ShortCircuit { hz: s, max: FROM.1 });
|
||||||
|
}
|
||||||
|
let tmp = TO.0 + (s - FROM.0) * (TO.1 - TO.0) / (FROM.1 - FROM.0);
|
||||||
|
|
||||||
|
return Ok(tmp as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn in_time_range(cur: &DateTime<Tz>, start: u8, end: u8) -> bool {
|
||||||
|
let curhour = cur.hour() as u8;
|
||||||
|
//eg 10-14
|
||||||
|
if start < end {
|
||||||
|
return curhour > start && curhour < end;
|
||||||
|
} else {
|
||||||
|
//eg 20-05
|
||||||
|
return curhour > start || curhour < end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn option_to_string(value: &Option<u8>) -> String {
|
||||||
|
match value {
|
||||||
|
Some(v) => v.to_string(),
|
||||||
|
None => "Error".to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -17,7 +17,7 @@ use esp_idf_svc::mqtt::client::{EspMqttClient, LwtConfiguration, MqttClientConfi
|
|||||||
use esp_idf_svc::nvs::EspDefaultNvsPartition;
|
use esp_idf_svc::nvs::EspDefaultNvsPartition;
|
||||||
use esp_idf_svc::wifi::config::{ScanConfig, ScanType};
|
use esp_idf_svc::wifi::config::{ScanConfig, ScanType};
|
||||||
use esp_idf_svc::wifi::EspWifi;
|
use esp_idf_svc::wifi::EspWifi;
|
||||||
use measurements::{Frequency, Temperature};
|
use measurements::Temperature;
|
||||||
use plant_ctrl2::sipo::ShiftRegister40;
|
use plant_ctrl2::sipo::ShiftRegister40;
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
Loading…
Reference in New Issue
Block a user