mqtt now uses more json to reduce message count
This commit is contained in:
parent
27858948e5
commit
3f98a321fc
497
rust/src/main.rs
497
rust/src/main.rs
@ -1,8 +1,13 @@
|
|||||||
use std::sync::{atomic::AtomicBool, Arc, Mutex};
|
use std::{
|
||||||
|
fmt::Display,
|
||||||
|
sync::{atomic::AtomicBool, Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
use chrono::{DateTime, Datelike, TimeDelta, Timelike};
|
use anyhow::Result;
|
||||||
|
use chrono::{DateTime, Datelike, TimeDelta, Timelike, Utc};
|
||||||
use chrono_tz::{Europe::Berlin, Tz};
|
use chrono_tz::{Europe::Berlin, Tz};
|
||||||
|
|
||||||
|
use config::Mode;
|
||||||
use esp_idf_hal::delay::Delay;
|
use esp_idf_hal::delay::Delay;
|
||||||
use esp_idf_sys::{
|
use esp_idf_sys::{
|
||||||
esp_deep_sleep, esp_ota_get_app_partition_count, esp_ota_get_running_partition,
|
esp_deep_sleep, esp_ota_get_app_partition_count, esp_ota_get_running_partition,
|
||||||
@ -73,7 +78,6 @@ struct PlantState {
|
|||||||
consecutive_pump_count: u32,
|
consecutive_pump_count: u32,
|
||||||
after_p: Option<u8>,
|
after_p: Option<u8>,
|
||||||
do_water: bool,
|
do_water: bool,
|
||||||
frozen: bool,
|
|
||||||
dry: bool,
|
dry: bool,
|
||||||
active: bool,
|
active: bool,
|
||||||
pump_error: bool,
|
pump_error: bool,
|
||||||
@ -102,6 +106,33 @@ struct TankState {
|
|||||||
sensor_error: bool,
|
sensor_error: bool,
|
||||||
raw: u16,
|
raw: u16,
|
||||||
}
|
}
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct PlantStateMQTT<'a> {
|
||||||
|
a: &'a str,
|
||||||
|
b: &'a str,
|
||||||
|
p_start: &'a str,
|
||||||
|
p_end: &'a str,
|
||||||
|
mode: &'a str,
|
||||||
|
consecutive_pump_count: u32,
|
||||||
|
dry: bool,
|
||||||
|
active: bool,
|
||||||
|
pump_error: bool,
|
||||||
|
not_effective: bool,
|
||||||
|
cooldown: bool,
|
||||||
|
out_of_work_hour: bool,
|
||||||
|
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<()> {
|
fn safe_main() -> anyhow::Result<()> {
|
||||||
// It is necessary to call this function once. Otherwise some patches to the runtime
|
// It is necessary to call this function once. Otherwise some patches to the runtime
|
||||||
@ -325,27 +356,14 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
let tank_state = determine_tank_state(&mut board, &config);
|
let tank_state = determine_tank_state(&mut board, &config);
|
||||||
if online_mode == OnlineMode::Online {
|
if online_mode == OnlineMode::Online {
|
||||||
if tank_state.sensor_error {
|
match serde_json::to_string(&tank_state) {
|
||||||
let _ = board.mqtt_publish(&config, "/water/ml", "error".to_string().as_bytes());
|
Ok(state) => {
|
||||||
} else {
|
let _ = board.mqtt_publish(&config, "/water", state.as_bytes());
|
||||||
let _ = board.mqtt_publish(
|
}
|
||||||
&config,
|
Err(err) => {
|
||||||
"/water/ml",
|
println!("Error publishing lightstate {}", err);
|
||||||
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/low_warning",
|
|
||||||
tank_state.warn_level.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;
|
||||||
@ -371,6 +389,11 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
if online_mode == OnlineMode::Online {
|
if online_mode == OnlineMode::Online {
|
||||||
let _ =
|
let _ =
|
||||||
board.mqtt_publish(&config, "/water/temperature", res.to_string().as_bytes());
|
board.mqtt_publish(&config, "/water/temperature", res.to_string().as_bytes());
|
||||||
|
let _ = board.mqtt_publish(
|
||||||
|
&config,
|
||||||
|
"/water/frozen",
|
||||||
|
water_frozen.to_string().as_bytes(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@ -437,6 +460,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);
|
||||||
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,
|
||||||
@ -444,17 +468,13 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
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(),
|
&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(
|
let _ = board.mqtt_publish(&config, &p_live_topic, "disabled".as_bytes());
|
||||||
&config,
|
|
||||||
format!("/plant{}/Sensor P after", plant + 1).as_str(),
|
|
||||||
"disabled".as_bytes(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -534,7 +554,7 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
if online_mode == OnlineMode::Online {
|
if online_mode == OnlineMode::Online {
|
||||||
match serde_json::to_string(&light_state) {
|
match serde_json::to_string(&light_state) {
|
||||||
Ok(state) => {
|
Ok(state) => {
|
||||||
let _ = board.mqtt_publish(&config, "/light/active", state.as_bytes());
|
let _ = board.mqtt_publish(&config, "/light", state.as_bytes());
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("Error publishing lightstate {}", err);
|
println!("Error publishing lightstate {}", err);
|
||||||
@ -578,120 +598,34 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
unsafe { esp_deep_sleep(1000 * 1000 * 60 * deep_sleep_duration_minutes as u64) };
|
unsafe { esp_deep_sleep(1000 * 1000 * 60 * deep_sleep_duration_minutes as u64) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_string<T: Display>(value: Result<T>) -> String {
|
||||||
|
return match value {
|
||||||
|
Ok(v) => v.to_string(),
|
||||||
|
Err(err) => {
|
||||||
|
format!("{:?}", err)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn publish_battery_state(
|
fn publish_battery_state(
|
||||||
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
|
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
) {
|
) {
|
||||||
match board.voltage_milli_volt() {
|
let bat = BatteryState {
|
||||||
Ok(v) => {
|
voltage_milli_volt: &to_string(board.voltage_milli_volt()),
|
||||||
let _ = board.mqtt_publish(
|
current_milli_ampere: &to_string(board.average_current_milli_ampere()),
|
||||||
&config,
|
cycle_count: &to_string(board.cycle_count()),
|
||||||
"/battery/voltage_milli_volt",
|
design_milli_ampere: &to_string(board.design_milli_ampere_hour()),
|
||||||
v.to_string().as_bytes(),
|
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()),
|
||||||
Err(err) => {
|
|
||||||
let _ = board.mqtt_publish(&config, "/battery/voltage_milli_volt", "-1".as_bytes());
|
|
||||||
let _ = board.mqtt_publish(&config, "/errorlog", format!("{:?}", err).as_bytes());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
match board.average_current_milli_ampere() {
|
match serde_json::to_string(&bat) {
|
||||||
Ok(v) => {
|
Ok(state) => {
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(&config, "/plant/battery", state.as_bytes());
|
||||||
&config,
|
|
||||||
"/battery/average_current_milli_ampere",
|
|
||||||
v.to_string().as_bytes(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let _ = board.mqtt_publish(
|
println!("Error publishing battery_state {}", err);
|
||||||
&config,
|
|
||||||
"/battery/average_current_milli_ampere",
|
|
||||||
"-1".as_bytes(),
|
|
||||||
);
|
|
||||||
let _ = board.mqtt_publish(&config, "/errorlog", format!("{:?}", err).as_bytes());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match board.cycle_count() {
|
|
||||||
Ok(v) => {
|
|
||||||
let _ = board.mqtt_publish(&config, "/battery/cycle_count", v.to_string().as_bytes());
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
let _ = board.mqtt_publish(&config, "/battery/cycle_count", "-1".as_bytes());
|
|
||||||
let _ = board.mqtt_publish(&config, "/errorlog", format!("{:?}", err).as_bytes());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match board.design_milli_ampere_hour() {
|
|
||||||
Ok(v) => {
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
&config,
|
|
||||||
"/battery/design_milli_ampere_hour",
|
|
||||||
v.to_string().as_bytes(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
&config,
|
|
||||||
"/battery/design_milli_ampere_hour",
|
|
||||||
"-1".as_bytes(),
|
|
||||||
);
|
|
||||||
let _ = board.mqtt_publish(&config, "/errorlog", format!("{:?}", err).as_bytes());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match board.max_milli_ampere_hour() {
|
|
||||||
Ok(v) => {
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
&config,
|
|
||||||
"/battery/max_milli_ampere_hour",
|
|
||||||
v.to_string().as_bytes(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
let _ = board.mqtt_publish(&config, "/battery/max_milli_ampere_hour", "-1".as_bytes());
|
|
||||||
let _ = board.mqtt_publish(&config, "/errorlog", format!("{:?}", err).as_bytes());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match board.remaining_milli_ampere_hour() {
|
|
||||||
Ok(v) => {
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
&config,
|
|
||||||
"/battery/remaining_milli_ampere_hour",
|
|
||||||
v.to_string().as_bytes(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
&config,
|
|
||||||
"/battery/remaining_milli_ampere_hour",
|
|
||||||
"-1".as_bytes(),
|
|
||||||
);
|
|
||||||
let _ = board.mqtt_publish(&config, "/errorlog", format!("{:?}", err).as_bytes());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match board.state_charge_percent() {
|
|
||||||
Ok(v) => {
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
&config,
|
|
||||||
"/battery/state_charge_percent",
|
|
||||||
v.to_string().as_bytes(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
let _ = board.mqtt_publish(&config, "/battery/state_charge_percent", "-1".as_bytes());
|
|
||||||
let _ = board.mqtt_publish(&config, "/errorlog", format!("{:?}", err).as_bytes());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match board.state_health_percent() {
|
|
||||||
Ok(v) => {
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
&config,
|
|
||||||
"/battery/state_health_percent",
|
|
||||||
v.to_string().as_bytes(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
let _ = board.mqtt_publish(&config, "/battery/state_health_percent", "-1".as_bytes());
|
|
||||||
let _ = board.mqtt_publish(&config, "/errorlog", format!("{:?}", err).as_bytes());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -750,6 +684,7 @@ fn determine_tank_state(
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
return TankState {
|
return TankState {
|
||||||
|
warn_level: false,
|
||||||
enough_water: true,
|
enough_water: true,
|
||||||
left_ml: 1337,
|
left_ml: 1337,
|
||||||
sensor_error: false,
|
sensor_error: false,
|
||||||
@ -811,24 +746,13 @@ fn determine_state_target_moisture_for_plant(
|
|||||||
state: &mut PlantState,
|
state: &mut PlantState,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
tank_state: &TankState,
|
tank_state: &TankState,
|
||||||
water_frozen: bool,
|
|
||||||
cur: DateTime<Tz>,
|
cur: DateTime<Tz>,
|
||||||
) {
|
) {
|
||||||
let plant_config = &config.plants[plant];
|
let plant_config = &config.plants[plant];
|
||||||
match board.measure_moisture_hz(plant, plant_hal::Sensor::A) {
|
if plant_config.mode == Mode::OFF {
|
||||||
Ok(a) => {
|
return;
|
||||||
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) => {
|
||||||
@ -886,15 +810,8 @@ fn determine_state_target_moisture_for_plant(
|
|||||||
) {
|
) {
|
||||||
state.out_of_work_hour = true;
|
state.out_of_work_hour = true;
|
||||||
}
|
}
|
||||||
if water_frozen {
|
|
||||||
state.frozen = true;
|
|
||||||
}
|
|
||||||
if state.dry && !state.no_water && !state.cooldown && !state.out_of_work_hour {
|
if state.dry && !state.no_water && !state.cooldown && !state.out_of_work_hour {
|
||||||
if water_frozen {
|
state.do_water = true;
|
||||||
state.frozen = true;
|
|
||||||
} else {
|
|
||||||
state.do_water = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -904,7 +821,6 @@ fn determine_state_timer_only_for_plant(
|
|||||||
state: &mut PlantState,
|
state: &mut PlantState,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
tank_state: &TankState,
|
tank_state: &TankState,
|
||||||
water_frozen: bool,
|
|
||||||
cur: DateTime<Tz>,
|
cur: DateTime<Tz>,
|
||||||
) {
|
) {
|
||||||
let plant_config = &config.plants[plant];
|
let plant_config = &config.plants[plant];
|
||||||
@ -919,14 +835,10 @@ fn determine_state_timer_only_for_plant(
|
|||||||
state.next_pump = Some(europe_time);
|
state.next_pump = Some(europe_time);
|
||||||
state.cooldown = true;
|
state.cooldown = true;
|
||||||
} else {
|
} else {
|
||||||
if water_frozen {
|
if tank_state.sensor_error && !config.tank_allow_pumping_if_sensor_error {
|
||||||
state.frozen = true;
|
state.do_water = true;
|
||||||
} else {
|
} else if !tank_state.enough_water {
|
||||||
if tank_state.sensor_error && !config.tank_allow_pumping_if_sensor_error {
|
state.no_water = true;
|
||||||
state.do_water = true;
|
|
||||||
} else if !tank_state.enough_water {
|
|
||||||
state.no_water = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -947,7 +859,6 @@ fn determine_state_timer_and_deadzone_for_plant(
|
|||||||
state: &mut PlantState,
|
state: &mut PlantState,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
tank_state: &TankState,
|
tank_state: &TankState,
|
||||||
water_frozen: bool,
|
|
||||||
cur: DateTime<Tz>,
|
cur: DateTime<Tz>,
|
||||||
) {
|
) {
|
||||||
let plant_config = &config.plants[plant];
|
let plant_config = &config.plants[plant];
|
||||||
@ -970,14 +881,10 @@ fn determine_state_timer_and_deadzone_for_plant(
|
|||||||
state.out_of_work_hour = true;
|
state.out_of_work_hour = true;
|
||||||
}
|
}
|
||||||
if !state.cooldown && !state.out_of_work_hour {
|
if !state.cooldown && !state.out_of_work_hour {
|
||||||
if water_frozen {
|
if tank_state.sensor_error && !config.tank_allow_pumping_if_sensor_error {
|
||||||
state.frozen = true;
|
state.do_water = true;
|
||||||
} else {
|
} else if !tank_state.enough_water {
|
||||||
if tank_state.sensor_error && !config.tank_allow_pumping_if_sensor_error {
|
state.no_water = true;
|
||||||
state.do_water = true;
|
|
||||||
} else if !tank_state.enough_water {
|
|
||||||
state.no_water = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1007,35 +914,15 @@ fn determine_next_plant(
|
|||||||
config::Mode::OFF => {}
|
config::Mode::OFF => {}
|
||||||
config::Mode::TargetMoisture => {
|
config::Mode::TargetMoisture => {
|
||||||
determine_state_target_moisture_for_plant(
|
determine_state_target_moisture_for_plant(
|
||||||
board,
|
board, plant, state, config, tank_state, cur,
|
||||||
plant,
|
|
||||||
state,
|
|
||||||
config,
|
|
||||||
tank_state,
|
|
||||||
water_frozen,
|
|
||||||
cur,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
config::Mode::TimerOnly => {
|
config::Mode::TimerOnly => {
|
||||||
determine_state_timer_only_for_plant(
|
determine_state_timer_only_for_plant(board, plant, state, config, tank_state, cur);
|
||||||
board,
|
|
||||||
plant,
|
|
||||||
state,
|
|
||||||
config,
|
|
||||||
tank_state,
|
|
||||||
water_frozen,
|
|
||||||
cur,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
config::Mode::TimerAndDeadzone => {
|
config::Mode::TimerAndDeadzone => {
|
||||||
determine_state_timer_and_deadzone_for_plant(
|
determine_state_timer_and_deadzone_for_plant(
|
||||||
board,
|
board, plant, state, config, tank_state, cur,
|
||||||
plant,
|
|
||||||
state,
|
|
||||||
config,
|
|
||||||
tank_state,
|
|
||||||
water_frozen,
|
|
||||||
cur,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1058,8 +945,10 @@ fn determine_next_plant(
|
|||||||
"Checking for water plant {} with state {}",
|
"Checking for water plant {} with state {}",
|
||||||
plant, state.do_water
|
plant, state.do_water
|
||||||
);
|
);
|
||||||
if state.do_water {
|
if !water_frozen {
|
||||||
return Some(plant);
|
if state.do_water {
|
||||||
|
return Some(plant);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("No plant needs water");
|
println!("No plant needs water");
|
||||||
@ -1075,158 +964,70 @@ fn update_plant_state(
|
|||||||
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 mode = format!("{:?}", plant_config.mode);
|
||||||
&config,
|
|
||||||
format!("/plant{}/mode", plant + 1).as_str(),
|
|
||||||
match plant_config.mode {
|
|
||||||
config::Mode::OFF => "OFF".as_bytes(),
|
|
||||||
config::Mode::TargetMoisture => "TargetMoisture".as_bytes(),
|
|
||||||
config::Mode::TimerOnly => "TimerOnly".as_bytes(),
|
|
||||||
config::Mode::TimerAndDeadzone => "TimerAndDeadzone".as_bytes(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let last_time = board.last_pump_time(plant);
|
let plant_dto = PlantStateMQTT {
|
||||||
match last_time {
|
p_start: &sensor_to_string(state.p, state.sensor_error_p, plant_config.sensor_p),
|
||||||
Some(last_time) => {
|
p_end: &sensor_to_string(state.after_p, state.sensor_error_p, plant_config.sensor_p),
|
||||||
let europe_time = last_time.with_timezone(&Berlin);
|
a: &sensor_to_string(state.a, state.sensor_error_a, true),
|
||||||
if europe_time.year() > 2023 {
|
b: &sensor_to_string(state.b, state.sensor_error_b, plant_config.sensor_b),
|
||||||
let time = europe_time.to_rfc3339();
|
active: state.active,
|
||||||
let _ = board.mqtt_publish(
|
mode: &mode,
|
||||||
&config,
|
last_pump: &&time_to_string_utc(board.last_pump_time(plant)),
|
||||||
format!("/plant{}/last pump", plant + 1).as_str(),
|
next_pump: &time_to_string(state.next_pump),
|
||||||
time.as_bytes(),
|
consecutive_pump_count: state.consecutive_pump_count,
|
||||||
);
|
cooldown: state.cooldown,
|
||||||
} else {
|
dry: state.dry,
|
||||||
let _ = board.mqtt_publish(
|
not_effective: state.not_effective,
|
||||||
&config,
|
out_of_work_hour: state.out_of_work_hour,
|
||||||
format!("/plant{}/last pump", plant + 1).as_str(),
|
pump_error: state.pump_error,
|
||||||
"N/A".as_bytes(),
|
};
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
&config,
|
|
||||||
format!("/plant{}/last pump", plant + 1).as_str(),
|
|
||||||
"N/A".as_bytes(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match state.next_pump {
|
match serde_json::to_string(&plant_dto) {
|
||||||
Some(next) => {
|
Ok(state) => {
|
||||||
let time = next.to_rfc3339();
|
let plant_topic = format!("/plant{}", plant + 1);
|
||||||
let _ = board.mqtt_publish(
|
let _ = board.mqtt_publish(&config, &plant_topic, state.as_bytes());
|
||||||
&config,
|
|
||||||
format!("/plant{}/next pump", plant + 1).as_str(),
|
|
||||||
time.as_bytes(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
None => {
|
Err(err) => {
|
||||||
let _ = board.mqtt_publish(
|
println!("Error publishing lightstate {}", err);
|
||||||
&config,
|
|
||||||
format!("/plant{}/next pump", plant + 1).as_str(),
|
|
||||||
"N/A".as_bytes(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
config,
|
|
||||||
format!("/plant{}/active", plant + 1).as_str(),
|
|
||||||
state.active.to_string().as_bytes(),
|
|
||||||
);
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
config,
|
|
||||||
format!("/plant{}/Sensor A", plant + 1).as_str(),
|
|
||||||
option_to_string(state.a).as_bytes(),
|
|
||||||
);
|
|
||||||
if plant_config.sensor_b {
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
config,
|
|
||||||
format!("/plant{}/Sensor B", plant + 1).as_str(),
|
|
||||||
option_to_string(state.b).as_bytes(),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
config,
|
|
||||||
format!("/plant{}/Sensor B", plant + 1).as_str(),
|
|
||||||
"disabled".as_bytes(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if plant_config.sensor_p {
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
config,
|
|
||||||
format!("/plant{}/Sensor P before", plant + 1).as_str(),
|
|
||||||
option_to_string(state.p).as_bytes(),
|
|
||||||
);
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
config,
|
|
||||||
format!("/plant{}/Sensor P after", plant + 1).as_str(),
|
|
||||||
option_to_string(state.after_p).as_bytes(),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
config,
|
|
||||||
format!("/plant{}/Sensor P before", plant + 1).as_str(),
|
|
||||||
"disabled".as_bytes(),
|
|
||||||
);
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
config,
|
|
||||||
format!("/plant{}/Sensor P after", plant + 1).as_str(),
|
|
||||||
"disabled".as_bytes(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
config,
|
|
||||||
format!("/plant{}/Should water", plant + 1).as_str(),
|
|
||||||
state.do_water.to_string().as_bytes(),
|
|
||||||
);
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
config,
|
|
||||||
format!("/plant{}/Is frozen", plant + 1).as_str(),
|
|
||||||
state.frozen.to_string().as_bytes(),
|
|
||||||
);
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
config,
|
|
||||||
format!("/plant{}/Is dry", plant + 1).as_str(),
|
|
||||||
state.dry.to_string().as_bytes(),
|
|
||||||
);
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
config,
|
|
||||||
format!("/plant{}/Pump Error", plant + 1).as_str(),
|
|
||||||
state.pump_error.to_string().as_bytes(),
|
|
||||||
);
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
config,
|
|
||||||
format!("/plant{}/Pump Ineffective", plant + 1).as_str(),
|
|
||||||
state.not_effective.to_string().as_bytes(),
|
|
||||||
);
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
config,
|
|
||||||
format!("/plant{}/Is in Cooldown", plant + 1).as_str(),
|
|
||||||
state.cooldown.to_string().as_bytes(),
|
|
||||||
);
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
config,
|
|
||||||
format!("/plant{}/No Water", plant + 1).as_str(),
|
|
||||||
state.no_water.to_string().as_bytes(),
|
|
||||||
);
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
config,
|
|
||||||
format!("/plant{}/Out of Work Hour", plant + 1).as_str(),
|
|
||||||
state.out_of_work_hour.to_string().as_bytes(),
|
|
||||||
);
|
|
||||||
let _ = board.mqtt_publish(
|
|
||||||
config,
|
|
||||||
format!("/plant{}/consecutive pump count", plant + 1).as_str(),
|
|
||||||
state.consecutive_pump_count.to_string().as_bytes(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
@ -803,7 +803,7 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
bail!("No mqtt client, aborting publish");
|
bail!("No mqtt client");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user