more stack for json, more json for mqtt
This commit is contained in:
		| @@ -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; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user