refactor: create mqtt module with core MQTT statics and tasks

This commit is contained in:
2026-05-10 02:34:16 +02:00
parent b0f8bcc9da
commit a02b84d732
3 changed files with 284 additions and 300 deletions

View File

@@ -14,10 +14,10 @@
esp_bootloader_esp_idf::esp_app_desc!();
use esp_backtrace as _;
use crate::hal::PROGRESS_ACTIVE;
use crate::config::{NetworkConfig, PlantConfig, PlantControllerConfig};
use crate::fat_error::FatResult;
use crate::hal::esp::MQTT_STAY_ALIVE;
use crate::hal::PROGRESS_ACTIVE;
use crate::log::log;
use crate::tank::{determine_tank_state, TankError, TankState, WATER_FROZEN_THRESH};
use crate::webserver::http_server;
@@ -67,6 +67,7 @@ mod config;
mod fat_error;
mod hal;
mod log;
mod mqtt;
mod plant_state;
mod tank;
mod webserver;
@@ -329,7 +330,9 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
log(LogMessage::NormalRun, 0, 0, "", "");
}
let dry_run = MQTT_STAY_ALIVE.load(Ordering::Relaxed);
// if stay alive is true then the hardware will determine state and pretend to do all actions with logging
// this is to help debug what the hardware would do with the current settings applied
let dry_run = mqtt::is_stay_alive();
let tank_state = determine_tank_state(&mut board).await;
@@ -643,11 +646,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
match &serde_json::to_string(&light_state) {
Ok(state) => {
let _ = board
.board_hal
.get_esp()
.mqtt_publish("/light", state)
.await;
let _ = mqtt::publish("/light", state).await;
}
Err(err) => {
info!("Error publishing lightstate {err}");
@@ -657,39 +656,24 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
let deep_sleep_duration_minutes: u32 =
// if battery soc is unknown assume battery has enough change
if matches!(battery_state, BatteryState::Info(data) if data.state_of_charge < 10) {
let _ = board
.board_hal
.get_esp()
.mqtt_publish("/deepsleep", "low Volt 12h").await;
let _ = mqtt::publish("/deepsleep", "low Volt 12h").await;
12 * 60
} else if is_day {
let _ = board
.board_hal
.get_esp()
.mqtt_publish("/deepsleep", "normal 20m").await;
let _ = mqtt::publish("/deepsleep", "normal 20m").await;
20
} else {
let _ = board
.board_hal
.get_esp()
.mqtt_publish("/deepsleep", "night 1h").await;
let _ = mqtt::publish("/deepsleep", "night 1h").await;
60
};
let _ = board
.board_hal
.get_esp()
.mqtt_publish("/state", "sleep")
.await;
info!("Go to sleep for {deep_sleep_duration_minutes} minutes");
let _ = mqtt::publish("/state", "sleep").await;
//determine next event
//is light out of work trigger soon?
//is battery low ??
//is deep sleep
let stay_alive = MQTT_STAY_ALIVE.load(Ordering::Relaxed);
info!("Check stay alive, current state is {stay_alive}");
let stay_alive = mqtt::is_stay_alive();
info!("Check stay alive, current state is {}", stay_alive);
if stay_alive {
let reboot_now = Arc::new(AtomicBool::new(false));
@@ -930,11 +914,7 @@ async fn publish_tank_state(
let state = serde_json::to_string(
&tank_state.as_mqtt_info(&board.board_hal.get_config().tank, &water_temp),
)?;
board
.board_hal
.get_esp()
.mqtt_publish("/water", &state)
.await;
let _ = mqtt::publish("/water", &*state).await;
Ok(())
}
@@ -950,11 +930,7 @@ async fn publish_plant_states(
{
let state = serde_json::to_string(&plant_state.to_mqtt_info(plant_conf, timezone_time))?;
let plant_topic = format!("/plant{}", plant_id + 1);
let _ = board
.board_hal
.get_esp()
.mqtt_publish(&plant_topic, &state)
.await;
let _ = mqtt::publish(&plant_topic, &state).await;
}
Ok(())
}
@@ -965,13 +941,12 @@ async fn publish_firmware_info(
ip_address: &str,
timezone_time: &str,
) {
let esp = board.board_hal.get_esp();
esp.mqtt_publish("/firmware/address", ip_address).await;
esp.mqtt_publish("/firmware/state", format!("{:?}", &version).as_str())
mqtt::publish("/firmware/address", ip_address).await;
mqtt::publish("/firmware/state", format!("{:?}", &version).as_str())
.await;
esp.mqtt_publish("/firmware/last_online", timezone_time)
mqtt::publish("/firmware/last_online", timezone_time)
.await;
esp.mqtt_publish("/state", "online").await;
mqtt::publish("/state", "online").await;
}
macro_rules! mk_static {
($t:ty,$val:expr) => {{
@@ -1011,12 +986,7 @@ async fn try_connect_wifi_sntp_mqtt(
let mqtt_connected = if board.board_hal.get_config().network.mqtt_url.is_some() {
let nw_config = board.board_hal.get_config().network.clone();
let nw_config = mk_static!(NetworkConfig, nw_config);
match board
.board_hal
.get_esp()
.mqtt(nw_config, stack, spawner)
.await
{
match mqtt::mqtt_init(nw_config, stack, spawner).await {
Ok(_) => {
info!("Mqtt connection ready");
true
@@ -1077,11 +1047,7 @@ async fn pump_info(
match serde_json::to_string(&pump_info) {
Ok(state) => {
board
.board_hal
.get_esp()
.mqtt_publish(&pump_topic, &state)
.await;
let _ = mqtt::publish(&pump_topic, &state).await;
}
Err(err) => {
warn!("Error publishing pump state {err}");
@@ -1099,11 +1065,7 @@ async fn publish_mppt_state(
voltage_ma: voltage.as_millivolts() as u32,
};
if let Ok(serialized_solar_state_bytes) = serde_json::to_string(&solar_state) {
board
.board_hal
.get_esp()
.mqtt_publish("/mppt", &serialized_solar_state_bytes)
.await;
let _ = mqtt::publish("/mppt", &serialized_solar_state_bytes).await;
}
Ok(())
}
@@ -1120,11 +1082,7 @@ async fn publish_battery_state(
Err(_) => "error".to_owned(),
};
{
let _ = board
.board_hal
.get_esp()
.mqtt_publish("/battery", &value)
.await;
let _ = mqtt::publish("/battery", &*value).await;
}
Ok(())
}
@@ -1229,9 +1187,8 @@ async fn wait_infinity(
let cur = board.board_hal.get_time().await;
let timezone_time = cur.with_timezone(&timezone);
let esp = board.board_hal.get_esp();
esp.mqtt_publish("/state", "config").await;
esp.mqtt_publish("/firmware/last_online", &timezone_time.to_rfc3339())
mqtt::publish("/state", "config").await;
mqtt::publish("/firmware/last_online", &timezone_time.to_rfc3339())
.await;
last_mqtt_update = Some(now);
}
@@ -1285,7 +1242,7 @@ async fn wait_infinity(
hal::PlantHal::feed_watchdog();
if wait_type == WaitType::MqttConfig && !MQTT_STAY_ALIVE.load(Ordering::Relaxed) {
if wait_type == WaitType::MqttConfig && !mqtt::is_stay_alive() {
reboot_now.store(true, Ordering::Relaxed);
}
if reboot_now.load(Ordering::Relaxed) {