diff --git a/rust/src/main.rs b/rust/src/main.rs
index e4a6b93..8a0a643 100644
--- a/rust/src/main.rs
+++ b/rust/src/main.rs
@@ -2,9 +2,9 @@ use std::{
     fmt::Display,
     sync::{atomic::AtomicBool, Arc, Mutex},
 };
-
-use anyhow::{bail, Result};
-use chrono::{DateTime, Datelike, Timelike};
+use std::sync::MutexGuard;
+use anyhow::bail;
+use chrono::{DateTime, Datelike, Timelike, Utc};
 use chrono_tz::Tz;
 use chrono_tz::Tz::UTC;
 use esp_idf_hal::delay::Delay;
@@ -20,14 +20,12 @@ use log::{log, LogMessage};
 use once_cell::sync::Lazy;
 use plant_hal::{PlantCtrlBoard, PlantHal, PLANT_COUNT};
 use serde::{Deserialize, Serialize};
-
 use crate::{config::PlantControllerConfig, webserver::webserver::httpd};
 mod config;
 mod log;
 pub mod plant_hal;
 mod plant_state;
 mod tank;
-pub mod util;
 
 use plant_state::PlantState;
 use tank::*;
@@ -71,6 +69,13 @@ struct LightState {
     is_day: bool,
 }
 
+#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
+///mqtt stuct to track pump activities
+struct PumpInfo{
+    enabled: bool,
+    pump_ineffective: bool,
+}
+
 #[derive(Serialize, Deserialize, Debug, PartialEq)]
 /// humidity sensor error
 enum SensorError {
@@ -79,7 +84,21 @@ enum SensorError {
     OpenCircuit { hz: f32, min: f32 },
 }
 
-fn safe_main() -> Result<()> {
+#[derive(Serialize, Debug, PartialEq)]
+enum SntpMode {
+    OFFLINE,
+    SYNC{
+        current: DateTime<Utc>
+    }
+}
+
+#[derive(Serialize, Debug, PartialEq)]
+enum NetworkMode{
+    WIFI {sntp: SntpMode, mqtt: bool, ip_address: String},
+    OFFLINE,
+}
+
+fn safe_main() -> anyhow::Result<()> {
     // It is necessary to call this function once. Otherwise, some patches to the runtime
     // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
     esp_idf_svc::sys::link_patches();
@@ -145,7 +164,7 @@ fn safe_main() -> Result<()> {
         "",
     );
 
-    let mut cur = board
+    let cur = board
         .get_rtc_time()
         .or_else(|err| {
             println!("rtc module error: {:?}", err);
@@ -214,55 +233,15 @@ fn safe_main() -> Result<()> {
         }
     };
 
-    let mut wifi = false;
-    let mut mqtt = false;
-    let mut sntp = false;
     println!("attempting to connect wifi");
-    let mut ip_address: Option<String> = None;
-    if config.network.ssid.is_some() {
-        match board.wifi(
-            config.network.ssid.clone().unwrap(),
-            config.network.password.clone(),
-            10000,
-        ) {
-            Ok(ip_info) => {
-                ip_address = Some(ip_info.ip.to_string());
-                wifi = true;
-
-                match board.sntp(1000 * 10) {
-                    Ok(new_time) => {
-                        println!("Using time from sntp");
-                        let _ = board.set_rtc_time(&new_time);
-                        cur = new_time;
-                        sntp = true;
-                    }
-                    Err(err) => {
-                        println!("sntp error: {}", err);
-                        board.general_fault(true);
-                    }
-                }
-                if config.network.mqtt_url.is_some() {
-                    match board.mqtt(&config) {
-                        Ok(_) => {
-                            println!("Mqtt connection ready");
-                            mqtt = true;
-                        }
-                        Err(err) => {
-                            println!("Could not connect mqtt due to {}", err);
-                        }
-                    }
-                }
-            }
-            Err(_) => {
-                println!("Offline mode");
-                board.general_fault(true);
-            }
-        }
+    let network_mode = if config.network.ssid.is_some() {
+        try_connect_wifi_sntp_mqtt(&mut board, &config)
     } else {
         println!("No wifi configured");
-    }
+        NetworkMode::OFFLINE
+    };
 
-    if !wifi && to_config {
+    if matches!(network_mode, NetworkMode::OFFLINE) && to_config {
         println!("Could not connect to station and config mode forced, switching to ap mode!");
         match board.wifi_ap(Some(config.network.ap_ssid.clone())) {
             Ok(_) => {
@@ -288,36 +267,17 @@ fn safe_main() -> Result<()> {
         timezone_time
     );
 
-    if mqtt {
-        let ip_string = ip_address.unwrap_or("N/A".to_owned());
-        let _ = board.mqtt_publish(&config, "/firmware/address", ip_string.as_bytes());
-        let _ = board.mqtt_publish(&config, "/firmware/githash", version.git_hash.as_bytes());
-        let _ = board.mqtt_publish(
-            &config,
-            "/firmware/buildtime",
-            version.build_time.as_bytes(),
-        );
-        let _ = board.mqtt_publish(
-            &config,
-            "/firmware/last_online",
-            timezone_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());
-
+    if let NetworkMode::WIFI { ref ip_address, .. } = network_mode {
+        publish_firmware_info(version, address, ota_state_string, &mut board, &config, &ip_address, timezone_time);
         publish_battery_state(&mut board, &config);
     }
 
+
     log(
         LogMessage::StartupInfo,
-        wifi as u32,
-        sntp as u32,
-        &mqtt.to_string(),
+        matches!(network_mode, NetworkMode::WIFI { .. }) as u32,
+        matches!(network_mode, NetworkMode::WIFI { sntp: SntpMode::SYNC { .. }, .. }) as u32,
+        matches!(network_mode, NetworkMode::WIFI { mqtt: true, .. }).to_string().as_str(),
         "",
     );
 
@@ -369,54 +329,18 @@ fn safe_main() -> Result<()> {
 
     let mut water_frozen = false;
 
-    //multisample should be moved to water_temperature_c
-    let mut attempt = 1;
-    let water_temp: Result<f32, anyhow::Error> = loop {
-        let temp = board.water_temperature_c();
-        match &temp {
-            Ok(res) => {
-                println!("Water temp is {}", res);
-                break temp;
-            }
-            Err(err) => {
-                println!("Could not get water temp {} attempt {}", err, attempt)
-            }
-        }
-        if attempt == 5 {
-            break temp;
-        }
-        attempt += 1;
-    };
+    let water_temp = obtain_tank_temperature(&mut board);
     if let Ok(res) = water_temp {
         if res < WATER_FROZEN_THRESH {
             water_frozen = true;
         }
     }
 
-    match serde_json::to_string(&tank_state.as_mqtt_info(&config.tank, water_temp)) {
-        Ok(state) => {
-            let _ = board.mqtt_publish(&config, "/water", state.as_bytes());
-        }
-        Err(err) => {
-            println!("Error publishing tankstate {}", err);
-        }
-    };
+    publish_tank_state(&mut board, &config, &tank_state, &water_temp);
 
     let plantstate: [PlantState; PLANT_COUNT] =
         core::array::from_fn(|i| PlantState::read_hardware_state(i, &mut board, &config.plants[i]));
-    for (plant_id, (plant_state, plant_conf)) in plantstate.iter().zip(&config.plants).enumerate() {
-        match serde_json::to_string(&plant_state.to_mqtt_info(plant_conf, &timezone_time)) {
-            Ok(state) => {
-                let plant_topic = format!("/plant{}", plant_id + 1);
-                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) => {
-                println!("Error publishing plant state {}", err);
-            }
-        };
-    }
+    publish_plant_states(&mut board, &config, &timezone_time, &plantstate);
 
     let pump_required = plantstate
         .iter()
@@ -426,24 +350,24 @@ fn safe_main() -> Result<()> {
     if pump_required {
         log(LogMessage::EnableMain, dry_run as u32, 0, "", "");
         if !dry_run {
-            board.any_pump(true)?; // what does this do? Does it need to be reset?
+            board.any_pump(true)?; // enables main power output, eg for a central pump with valve setup or a main water valve for the risk affine
         }
         for (plant_id, (state, plant_config)) in plantstate.iter().zip(&config.plants).enumerate() {
             if state.needs_to_be_watered(plant_config, &timezone_time) {
                 let pump_count = board.consecutive_pump_count(plant_id) + 1;
                 board.store_consecutive_pump_count(plant_id, pump_count);
-                //TODO(judge) where to put this?
-                //if state.consecutive_pump_count > plant_config.max_consecutive_pump_count as u32 {
-                //    log(
-                //        log::LogMessage::ConsecutivePumpCountLimit,
-                //        state.consecutive_pump_count as u32,
-                //        plant_config.max_consecutive_pump_count as u32,
-                //        &plant.to_string(),
-                //        "",
-                //    );
-                //    state.not_effective = true;
-                //    board.fault(plant, true);
-                //}
+
+                let pump_ineffective = pump_count > plant_config.max_consecutive_pump_count as u32;
+                if pump_ineffective {
+                    log(
+                        LogMessage::ConsecutivePumpCountLimit,
+                        pump_count as u32,
+                        plant_config.max_consecutive_pump_count as u32,
+                        &(plant_id+1).to_string(),
+                        "",
+                    );
+                    board.fault(plant_id, true);
+                }
                 log(
                     LogMessage::PumpPlant,
                     (plant_id + 1) as u32,
@@ -454,17 +378,25 @@ fn safe_main() -> Result<()> {
                 board.store_last_pump_time(plant_id, cur);
                 board.last_pump_time(plant_id);
                 //state.active = true;
+
+                pump_info(&mut board, &config, plant_id, true, pump_ineffective);
+
                 if !dry_run {
                     board.pump(plant_id, true)?;
                     Delay::new_default().delay_ms(1000 * plant_config.pump_time_s as u32);
                     board.pump(plant_id, false)?;
                 }
+                pump_info(&mut board, &config, plant_id, false, pump_ineffective);
+
             } else if !state.pump_in_timeout(plant_config, &timezone_time) {
                 // plant does not need to be watered and is not in timeout
                 // -> reset consecutive pump count
                 board.store_consecutive_pump_count(plant_id, 0);
             }
         }
+        if !dry_run {
+            board.any_pump(false)?; // disable main power output, eg for a central pump with valve setup or a main water valve for the risk affine
+        }
     }
 
     let is_day = board.is_day();
@@ -552,6 +484,143 @@ fn safe_main() -> Result<()> {
     board.deep_sleep(1000 * 1000 * 60 * deep_sleep_duration_minutes as u64);
 }
 
+fn obtain_tank_temperature(board: &mut MutexGuard<PlantCtrlBoard>) -> anyhow::Result<f32> {
+    //multisample should be moved to water_temperature_c
+    let mut attempt = 1;
+    let water_temp: Result<f32, anyhow::Error> = loop {
+        let temp = board.water_temperature_c();
+        match &temp {
+            Ok(res) => {
+                println!("Water temp is {}", res);
+                break temp;
+            }
+            Err(err) => {
+                println!("Could not get water temp {} attempt {}", err, attempt)
+            }
+        }
+        if attempt == 5 {
+            break temp;
+        }
+        attempt += 1;
+    };
+    water_temp
+}
+
+fn publish_tank_state(board: &mut MutexGuard<PlantCtrlBoard>, config: &PlantControllerConfig, tank_state: &TankState, water_temp: &anyhow::Result<f32>) {
+    match serde_json::to_string(&tank_state.as_mqtt_info(&config.tank, water_temp)) {
+        Ok(state) => {
+            let _ = board.mqtt_publish(&config, "/water", state.as_bytes());
+        }
+        Err(err) => {
+            println!("Error publishing tankstate {}", err);
+        }
+    };
+}
+
+fn publish_plant_states(board: &mut MutexGuard<PlantCtrlBoard>, config: &PlantControllerConfig, timezone_time: &DateTime<Tz>, plantstate: &[PlantState; 8]) {
+    for (plant_id, (plant_state, plant_conf)) in plantstate.iter().zip(&config.plants).enumerate() {
+        match serde_json::to_string(&plant_state.to_mqtt_info(plant_conf, &timezone_time)) {
+            Ok(state) => {
+                let plant_topic = format!("/plant{}", plant_id + 1);
+                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) => {
+                println!("Error publishing plant state {}", err);
+            }
+        };
+    }
+}
+
+fn publish_firmware_info(version: VersionInfo, address: u32, ota_state_string: &str, board: &mut MutexGuard<PlantCtrlBoard>, config: &PlantControllerConfig, ip_address: &String, timezone_time: DateTime<Tz>) {
+    let _ = board.mqtt_publish(&config, "/firmware/address", ip_address.as_bytes());
+    let _ = board.mqtt_publish(&config, "/firmware/githash", version.git_hash.as_bytes());
+    let _ = board.mqtt_publish(
+        &config,
+        "/firmware/buildtime",
+        version.build_time.as_bytes(),
+    );
+    let _ = board.mqtt_publish(
+        &config,
+        "/firmware/last_online",
+        timezone_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());
+}
+
+fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard<PlantCtrlBoard>, config: &PlantControllerConfig) -> NetworkMode{
+    match board.wifi(
+        config.network.ssid.clone().unwrap(),
+        config.network.password.clone(),
+        10000,
+    ) {
+        Ok(ip_info) => {
+            let sntp_mode: SntpMode = match board.sntp(1000 * 10) {
+                Ok(new_time) => {
+                    println!("Using time from sntp");
+                    let _ = board.set_rtc_time(&new_time);
+                    SntpMode::SYNC {current: new_time}
+                }
+                Err(err) => {
+                    println!("sntp error: {}", err);
+                    board.general_fault(true);
+                    SntpMode::OFFLINE
+                }
+            };
+            let mqtt_connected = if let Some(_) = config.network.mqtt_url {
+                match board.mqtt(&config) {
+                    Ok(_) => {
+                        println!("Mqtt connection ready");
+                        true
+                    }
+                    Err(err) => {
+                        println!("Could not connect mqtt due to {}", err);
+                        false
+                    }
+                }
+            } else {
+                false
+            };
+            NetworkMode::WIFI {
+                sntp: sntp_mode,
+                mqtt: mqtt_connected,
+                ip_address: ip_info.ip.to_string()
+            }
+        }
+        Err(_) => {
+            println!("Offline mode");
+            board.general_fault(true);
+            NetworkMode::OFFLINE
+        }
+    }
+}
+
+//TODO clean this up? better state
+fn pump_info(board: &mut MutexGuard<PlantCtrlBoard>, config: &PlantControllerConfig, plant_id: usize, pump_active: bool, pump_ineffective: bool)  {
+    let pump_info = PumpInfo {
+        enabled: pump_active,
+        pump_ineffective
+    };
+    let pump_topic = format!("/pump{}", plant_id + 1);
+    match serde_json::to_string(&pump_info) {
+        Ok(state) => {
+            let _ = board.mqtt_publish(config, &pump_topic, state.as_bytes());
+            //reduce speed as else messages will be dropped
+            Delay::new_default().delay_ms(200);
+        }
+        Err(err) => {
+            println!("Error publishing pump state {}", err);
+        }
+    };
+}
+
 fn publish_battery_state(
     board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
     config: &PlantControllerConfig,
@@ -647,7 +716,7 @@ fn main() {
     }
 }
 
-fn to_string<T: Display>(value: Result<T>) -> String {
+fn to_string<T: Display>(value: anyhow::Result<T>) -> String {
     match value {
         Ok(v) => v.to_string(),
         Err(err) => {
@@ -690,4 +759,4 @@ struct VersionInfo {
     git_hash: String,
     build_time: String,
     partition: String,
-}
+}
\ No newline at end of file
diff --git a/rust/src/tank.rs b/rust/src/tank.rs
index f7c77a2..7c426ef 100644
--- a/rust/src/tank.rs
+++ b/rust/src/tank.rs
@@ -119,7 +119,7 @@ impl TankState {
     pub fn as_mqtt_info(
         &self,
         config: &TankConfig,
-        water_temp: Result<f32, anyhow::Error>,
+        water_temp: &anyhow::Result<f32>,
     ) -> TankInfo {
         let mut tank_err: Option<TankError> = None;
         let left_ml = match self.left_ml(config) {
@@ -151,7 +151,7 @@ impl TankState {
                 .as_ref()
                 .is_ok_and(|temp| *temp < WATER_FROZEN_THRESH),
             water_temp: water_temp.as_ref().copied().ok(),
-            temp_sensor_error: water_temp.err().map(|err| err.to_string()),
+            temp_sensor_error: water_temp.as_ref().err().map(|err| err.to_string()),
             percent,
         }
     }
diff --git a/rust/src/util.rs b/rust/src/util.rs
deleted file mode 100644
index 78f24a5..0000000
--- a/rust/src/util.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-pub trait LimitPrecision {
-    fn to_precision(self, precision: i32) -> Self;
-}
-
-impl LimitPrecision for f32 {
-    fn to_precision(self, precision: i32) -> Self {
-        let factor = 10_f32.powi(precision);
-        (self * factor).round() / factor
-    }
-}
diff --git a/rust/src/webserver/webserver.rs b/rust/src/webserver/webserver.rs
index 39dcce0..ea11f34 100644
--- a/rust/src/webserver/webserver.rs
+++ b/rust/src/webserver/webserver.rs
@@ -2,7 +2,7 @@
 
 use crate::{
     determine_tank_state, get_version, log::LogMessage, plant_hal::PLANT_COUNT,
-    plant_state::PlantState, util::LimitPrecision, BOARD_ACCESS,
+    plant_state::PlantState, BOARD_ACCESS,
 };
 use anyhow::bail;
 use chrono::DateTime;
@@ -273,7 +273,7 @@ fn tank_info(
     //should be multsampled
     let water_temp = board.water_temperature_c();
     Ok(Some(serde_json::to_string(
-        &tank_info.as_mqtt_info(&config.tank, water_temp),
+        &tank_info.as_mqtt_info(&config.tank, &water_temp),
     )?))
 }