cleanup main and network state handling
This commit is contained in:
parent
4f4d15e4a4
commit
3fe9aaeb6f
331
rust/src/main.rs
331
rust/src/main.rs
@ -2,9 +2,9 @@ use std::{
|
|||||||
fmt::Display,
|
fmt::Display,
|
||||||
sync::{atomic::AtomicBool, Arc, Mutex},
|
sync::{atomic::AtomicBool, Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
use std::sync::MutexGuard;
|
||||||
use anyhow::{bail, Result};
|
use anyhow::bail;
|
||||||
use chrono::{DateTime, Datelike, Timelike};
|
use chrono::{DateTime, Datelike, Timelike, Utc};
|
||||||
use chrono_tz::Tz;
|
use chrono_tz::Tz;
|
||||||
use chrono_tz::Tz::UTC;
|
use chrono_tz::Tz::UTC;
|
||||||
use esp_idf_hal::delay::Delay;
|
use esp_idf_hal::delay::Delay;
|
||||||
@ -20,14 +20,12 @@ use log::{log, LogMessage};
|
|||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use plant_hal::{PlantCtrlBoard, PlantHal, PLANT_COUNT};
|
use plant_hal::{PlantCtrlBoard, PlantHal, PLANT_COUNT};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{config::PlantControllerConfig, webserver::webserver::httpd};
|
use crate::{config::PlantControllerConfig, webserver::webserver::httpd};
|
||||||
mod config;
|
mod config;
|
||||||
mod log;
|
mod log;
|
||||||
pub mod plant_hal;
|
pub mod plant_hal;
|
||||||
mod plant_state;
|
mod plant_state;
|
||||||
mod tank;
|
mod tank;
|
||||||
pub mod util;
|
|
||||||
|
|
||||||
use plant_state::PlantState;
|
use plant_state::PlantState;
|
||||||
use tank::*;
|
use tank::*;
|
||||||
@ -71,6 +69,13 @@ struct LightState {
|
|||||||
is_day: bool,
|
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)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
/// humidity sensor error
|
/// humidity sensor error
|
||||||
enum SensorError {
|
enum SensorError {
|
||||||
@ -79,7 +84,21 @@ enum SensorError {
|
|||||||
OpenCircuit { hz: f32, min: f32 },
|
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
|
// 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
|
// 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();
|
esp_idf_svc::sys::link_patches();
|
||||||
@ -145,7 +164,7 @@ fn safe_main() -> Result<()> {
|
|||||||
"",
|
"",
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut cur = board
|
let cur = board
|
||||||
.get_rtc_time()
|
.get_rtc_time()
|
||||||
.or_else(|err| {
|
.or_else(|err| {
|
||||||
println!("rtc module error: {:?}", 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");
|
println!("attempting to connect wifi");
|
||||||
let mut ip_address: Option<String> = None;
|
let network_mode = if config.network.ssid.is_some() {
|
||||||
if config.network.ssid.is_some() {
|
try_connect_wifi_sntp_mqtt(&mut board, &config)
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
println!("No wifi configured");
|
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!");
|
println!("Could not connect to station and config mode forced, switching to ap mode!");
|
||||||
match board.wifi_ap(Some(config.network.ap_ssid.clone())) {
|
match board.wifi_ap(Some(config.network.ap_ssid.clone())) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
@ -288,36 +267,17 @@ fn safe_main() -> Result<()> {
|
|||||||
timezone_time
|
timezone_time
|
||||||
);
|
);
|
||||||
|
|
||||||
if mqtt {
|
if let NetworkMode::WIFI { ref ip_address, .. } = network_mode {
|
||||||
let ip_string = ip_address.unwrap_or("N/A".to_owned());
|
publish_firmware_info(version, address, ota_state_string, &mut board, &config, &ip_address, timezone_time);
|
||||||
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());
|
|
||||||
|
|
||||||
publish_battery_state(&mut board, &config);
|
publish_battery_state(&mut board, &config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
log(
|
log(
|
||||||
LogMessage::StartupInfo,
|
LogMessage::StartupInfo,
|
||||||
wifi as u32,
|
matches!(network_mode, NetworkMode::WIFI { .. }) as u32,
|
||||||
sntp as u32,
|
matches!(network_mode, NetworkMode::WIFI { sntp: SntpMode::SYNC { .. }, .. }) as u32,
|
||||||
&mqtt.to_string(),
|
matches!(network_mode, NetworkMode::WIFI { mqtt: true, .. }).to_string().as_str(),
|
||||||
"",
|
"",
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -369,54 +329,18 @@ fn safe_main() -> Result<()> {
|
|||||||
|
|
||||||
let mut water_frozen = false;
|
let mut water_frozen = false;
|
||||||
|
|
||||||
//multisample should be moved to water_temperature_c
|
let water_temp = obtain_tank_temperature(&mut board);
|
||||||
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;
|
|
||||||
};
|
|
||||||
if let Ok(res) = water_temp {
|
if let Ok(res) = water_temp {
|
||||||
if res < WATER_FROZEN_THRESH {
|
if res < WATER_FROZEN_THRESH {
|
||||||
water_frozen = true;
|
water_frozen = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match serde_json::to_string(&tank_state.as_mqtt_info(&config.tank, water_temp)) {
|
publish_tank_state(&mut board, &config, &tank_state, &water_temp);
|
||||||
Ok(state) => {
|
|
||||||
let _ = board.mqtt_publish(&config, "/water", state.as_bytes());
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
println!("Error publishing tankstate {}", err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let plantstate: [PlantState; PLANT_COUNT] =
|
let plantstate: [PlantState; PLANT_COUNT] =
|
||||||
core::array::from_fn(|i| PlantState::read_hardware_state(i, &mut board, &config.plants[i]));
|
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() {
|
publish_plant_states(&mut board, &config, &timezone_time, &plantstate);
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let pump_required = plantstate
|
let pump_required = plantstate
|
||||||
.iter()
|
.iter()
|
||||||
@ -426,24 +350,24 @@ fn safe_main() -> Result<()> {
|
|||||||
if pump_required {
|
if pump_required {
|
||||||
log(LogMessage::EnableMain, dry_run as u32, 0, "", "");
|
log(LogMessage::EnableMain, dry_run as u32, 0, "", "");
|
||||||
if !dry_run {
|
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() {
|
for (plant_id, (state, plant_config)) in plantstate.iter().zip(&config.plants).enumerate() {
|
||||||
if state.needs_to_be_watered(plant_config, &timezone_time) {
|
if state.needs_to_be_watered(plant_config, &timezone_time) {
|
||||||
let pump_count = board.consecutive_pump_count(plant_id) + 1;
|
let pump_count = board.consecutive_pump_count(plant_id) + 1;
|
||||||
board.store_consecutive_pump_count(plant_id, pump_count);
|
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 {
|
let pump_ineffective = pump_count > plant_config.max_consecutive_pump_count as u32;
|
||||||
// log(
|
if pump_ineffective {
|
||||||
// log::LogMessage::ConsecutivePumpCountLimit,
|
log(
|
||||||
// state.consecutive_pump_count as u32,
|
LogMessage::ConsecutivePumpCountLimit,
|
||||||
// plant_config.max_consecutive_pump_count as u32,
|
pump_count as u32,
|
||||||
// &plant.to_string(),
|
plant_config.max_consecutive_pump_count as u32,
|
||||||
// "",
|
&(plant_id+1).to_string(),
|
||||||
// );
|
"",
|
||||||
// state.not_effective = true;
|
);
|
||||||
// board.fault(plant, true);
|
board.fault(plant_id, true);
|
||||||
//}
|
}
|
||||||
log(
|
log(
|
||||||
LogMessage::PumpPlant,
|
LogMessage::PumpPlant,
|
||||||
(plant_id + 1) as u32,
|
(plant_id + 1) as u32,
|
||||||
@ -454,17 +378,25 @@ fn safe_main() -> Result<()> {
|
|||||||
board.store_last_pump_time(plant_id, cur);
|
board.store_last_pump_time(plant_id, cur);
|
||||||
board.last_pump_time(plant_id);
|
board.last_pump_time(plant_id);
|
||||||
//state.active = true;
|
//state.active = true;
|
||||||
|
|
||||||
|
pump_info(&mut board, &config, plant_id, true, pump_ineffective);
|
||||||
|
|
||||||
if !dry_run {
|
if !dry_run {
|
||||||
board.pump(plant_id, true)?;
|
board.pump(plant_id, true)?;
|
||||||
Delay::new_default().delay_ms(1000 * plant_config.pump_time_s as u32);
|
Delay::new_default().delay_ms(1000 * plant_config.pump_time_s as u32);
|
||||||
board.pump(plant_id, false)?;
|
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) {
|
} else if !state.pump_in_timeout(plant_config, &timezone_time) {
|
||||||
// plant does not need to be watered and is not in timeout
|
// plant does not need to be watered and is not in timeout
|
||||||
// -> reset consecutive pump count
|
// -> reset consecutive pump count
|
||||||
board.store_consecutive_pump_count(plant_id, 0);
|
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();
|
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);
|
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(
|
fn publish_battery_state(
|
||||||
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
|
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
|
||||||
config: &PlantControllerConfig,
|
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 {
|
match value {
|
||||||
Ok(v) => v.to_string(),
|
Ok(v) => v.to_string(),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@ -690,4 +759,4 @@ struct VersionInfo {
|
|||||||
git_hash: String,
|
git_hash: String,
|
||||||
build_time: String,
|
build_time: String,
|
||||||
partition: String,
|
partition: String,
|
||||||
}
|
}
|
@ -119,7 +119,7 @@ impl TankState {
|
|||||||
pub fn as_mqtt_info(
|
pub fn as_mqtt_info(
|
||||||
&self,
|
&self,
|
||||||
config: &TankConfig,
|
config: &TankConfig,
|
||||||
water_temp: Result<f32, anyhow::Error>,
|
water_temp: &anyhow::Result<f32>,
|
||||||
) -> TankInfo {
|
) -> TankInfo {
|
||||||
let mut tank_err: Option<TankError> = None;
|
let mut tank_err: Option<TankError> = None;
|
||||||
let left_ml = match self.left_ml(config) {
|
let left_ml = match self.left_ml(config) {
|
||||||
@ -151,7 +151,7 @@ impl TankState {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.is_ok_and(|temp| *temp < WATER_FROZEN_THRESH),
|
.is_ok_and(|temp| *temp < WATER_FROZEN_THRESH),
|
||||||
water_temp: water_temp.as_ref().copied().ok(),
|
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,
|
percent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
determine_tank_state, get_version, log::LogMessage, plant_hal::PLANT_COUNT,
|
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 anyhow::bail;
|
||||||
use chrono::DateTime;
|
use chrono::DateTime;
|
||||||
@ -273,7 +273,7 @@ fn tank_info(
|
|||||||
//should be multsampled
|
//should be multsampled
|
||||||
let water_temp = board.water_temperature_c();
|
let water_temp = board.water_temperature_c();
|
||||||
Ok(Some(serde_json::to_string(
|
Ok(Some(serde_json::to_string(
|
||||||
&tank_info.as_mqtt_info(&config.tank, water_temp),
|
&tank_info.as_mqtt_info(&config.tank, &water_temp),
|
||||||
)?))
|
)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user