Compare commits

..

No commits in common. "b238fc4c1404d244c54b893fd0c3bec0ee35e7af" and "3fe9aaeb6f3e8b040c2501712975a1d58007f284" have entirely different histories.

9 changed files with 496 additions and 825 deletions

View File

@ -88,10 +88,6 @@ text-template = "0.1.0"
strum_macros = "0.27.0" strum_macros = "0.27.0"
esp-ota = { version = "0.2.2", features = ["log"] } esp-ota = { version = "0.2.2", features = ["log"] }
unit-enum = "1.4.1" unit-enum = "1.4.1"
ambassador = "0.4.1"
tca9535 = "0.1.0"
tca9539 = "0.2.1"
pca9535 = "2.0.0"
[patch.crates-io] [patch.crates-io]

View File

@ -1,4 +1,8 @@
use crate::{config::PlantControllerConfig, webserver::webserver::httpd}; use std::{
fmt::Display,
sync::{atomic::AtomicBool, Arc, Mutex},
};
use std::sync::MutexGuard;
use anyhow::bail; use anyhow::bail;
use chrono::{DateTime, Datelike, Timelike, Utc}; use chrono::{DateTime, Datelike, Timelike, Utc};
use chrono_tz::Tz; use chrono_tz::Tz;
@ -14,24 +18,19 @@ use esp_idf_sys::{
use esp_ota::{mark_app_valid, rollback_and_reboot}; use esp_ota::{mark_app_valid, rollback_and_reboot};
use log::{log, LogMessage}; use log::{log, LogMessage};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use plant_hal::{EspHal, PlantHalFactory, PLANT_COUNT}; use plant_hal::{PlantCtrlBoard, PlantHal, PLANT_COUNT};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::MutexGuard; use crate::{config::PlantControllerConfig, webserver::webserver::httpd};
use std::{
fmt::Display,
sync::{atomic::AtomicBool, Arc, Mutex},
};
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;
use crate::plant_hal::{BoardV3X, SpecificBoard};
use plant_state::PlantState; use plant_state::PlantState;
use tank::*; use tank::*;
pub static BOARD_ACCESS: Lazy<Mutex<Box<dyn SpecificBoard + Send>>> = Lazy::new(|| PlantHalFactory::create_v3().unwrap()); pub static BOARD_ACCESS: Lazy<Mutex<PlantCtrlBoard>> = Lazy::new(|| PlantHal::create().unwrap());
pub static STAY_ALIVE: Lazy<AtomicBool> = Lazy::new(|| AtomicBool::new(false)); pub static STAY_ALIVE: Lazy<AtomicBool> = Lazy::new(|| AtomicBool::new(false));
mod webserver { mod webserver {
@ -151,7 +150,7 @@ fn safe_main() -> anyhow::Result<()> {
}; };
log(LogMessage::PartitionState, 0, 0, "", ota_state_string); log(LogMessage::PartitionState, 0, 0, "", ota_state_string);
let mut board: std::sync::MutexGuard<'_, BoardV3X> = BOARD_ACCESS.lock().unwrap(); let mut board: std::sync::MutexGuard<'_, PlantCtrlBoard<'_>> = BOARD_ACCESS.lock().unwrap();
board.general_fault(false); board.general_fault(false);
log(LogMessage::MountingFilesystem, 0, 0, "", ""); log(LogMessage::MountingFilesystem, 0, 0, "", "");
@ -485,7 +484,7 @@ fn safe_main() -> anyhow::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<EspHal<BoardV3X>>) -> anyhow::Result<f32> { fn obtain_tank_temperature(board: &mut MutexGuard<PlantCtrlBoard>) -> anyhow::Result<f32> {
//multisample should be moved to water_temperature_c //multisample should be moved to water_temperature_c
let mut attempt = 1; let mut attempt = 1;
let water_temp: Result<f32, anyhow::Error> = loop { let water_temp: Result<f32, anyhow::Error> = loop {
@ -507,7 +506,7 @@ fn obtain_tank_temperature(board: &mut MutexGuard<EspHal<BoardV3X>>) -> anyhow::
water_temp water_temp
} }
fn publish_tank_state(board: &mut MutexGuard<BoardV3X>, config: &PlantControllerConfig, tank_state: &TankState, water_temp: &anyhow::Result<f32>) { 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)) { match serde_json::to_string(&tank_state.as_mqtt_info(&config.tank, water_temp)) {
Ok(state) => { Ok(state) => {
let _ = board.mqtt_publish(&config, "/water", state.as_bytes()); let _ = board.mqtt_publish(&config, "/water", state.as_bytes());
@ -518,7 +517,7 @@ fn publish_tank_state(board: &mut MutexGuard<BoardV3X>, config: &PlantController
}; };
} }
fn publish_plant_states(board: &mut MutexGuard<EspHal<BoardV3X>>, config: &PlantControllerConfig, timezone_time: &DateTime<Tz>, plantstate: &[PlantState; 8]) { 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() { 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)) { match serde_json::to_string(&plant_state.to_mqtt_info(plant_conf, &timezone_time)) {
Ok(state) => { Ok(state) => {
@ -534,7 +533,7 @@ fn publish_plant_states(board: &mut MutexGuard<EspHal<BoardV3X>>, config: &Plant
} }
} }
fn publish_firmware_info(version: VersionInfo, address: u32, ota_state_string: &str, board: &mut MutexGuard<EspHal<BoardV3X>>, config: &PlantControllerConfig, ip_address: &String, timezone_time: DateTime<Tz>) { 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/address", ip_address.as_bytes());
let _ = board.mqtt_publish(&config, "/firmware/githash", version.git_hash.as_bytes()); let _ = board.mqtt_publish(&config, "/firmware/githash", version.git_hash.as_bytes());
let _ = board.mqtt_publish( let _ = board.mqtt_publish(
@ -556,7 +555,7 @@ fn publish_firmware_info(version: VersionInfo, address: u32, ota_state_string: &
let _ = board.mqtt_publish(&config, "/state", "online".as_bytes()); let _ = board.mqtt_publish(&config, "/state", "online".as_bytes());
} }
fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard<EspHal<BoardV3X>>, config: &PlantControllerConfig) -> NetworkMode{ fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard<PlantCtrlBoard>, config: &PlantControllerConfig) -> NetworkMode{
match board.wifi( match board.wifi(
config.network.ssid.clone().unwrap(), config.network.ssid.clone().unwrap(),
config.network.password.clone(), config.network.password.clone(),
@ -604,7 +603,7 @@ fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard<EspHal<BoardV3X>>, config:
} }
//TODO clean this up? better state //TODO clean this up? better state
fn pump_info(board: &mut MutexGuard<EspHal>, config: &PlantControllerConfig, plant_id: usize, pump_active: bool, pump_ineffective: bool) { fn pump_info(board: &mut MutexGuard<PlantCtrlBoard>, config: &PlantControllerConfig, plant_id: usize, pump_active: bool, pump_ineffective: bool) {
let pump_info = PumpInfo { let pump_info = PumpInfo {
enabled: pump_active, enabled: pump_active,
pump_ineffective pump_ineffective
@ -623,7 +622,7 @@ fn pump_info(board: &mut MutexGuard<EspHal>, config: &PlantControllerConfig, pla
} }
fn publish_battery_state( fn publish_battery_state(
board: &mut std::sync::MutexGuard<'_, EspHal<'_>>, board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
config: &PlantControllerConfig, config: &PlantControllerConfig,
) { ) {
let bat = board.get_battery_state(); let bat = board.get_battery_state();

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,6 @@ use chrono_tz::Tz;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{config::PlantConfig, in_time_range, plant_hal}; use crate::{config::PlantConfig, in_time_range, plant_hal};
use crate::plant_hal::{BoardV3X, SpecificBoard};
const MOIST_SENSOR_MAX_FREQUENCY: f32 = 7500.; // 60kHz (500Hz margin) const MOIST_SENSOR_MAX_FREQUENCY: f32 = 7500.; // 60kHz (500Hz margin)
const MOIST_SENSOR_MIN_FREQUENCY: f32 = 150.; // this is really, really dry, think like cactus levels const MOIST_SENSOR_MIN_FREQUENCY: f32 = 150.; // this is really, really dry, think like cactus levels
@ -114,7 +113,7 @@ fn map_range_moisture(
impl PlantState { impl PlantState {
pub fn read_hardware_state( pub fn read_hardware_state(
plant_id: usize, plant_id: usize,
board: &mut plant_hal::EspHal<BoardV3X>, board: &mut plant_hal::PlantCtrlBoard,
config: &PlantConfig, config: &PlantConfig,
) -> Self { ) -> Self {
let sensor_a = if config.sensor_a { let sensor_a = if config.sensor_a {

View File

@ -1,7 +1,9 @@
use serde::Serialize; use serde::Serialize;
use crate::plant_hal::{EspHal, SpecificBoard}; use crate::{
use crate::config::{PlantControllerConfig, TankConfig}; config::{PlantControllerConfig, TankConfig},
plant_hal::PlantCtrlBoard,
};
const OPEN_TANK_VOLTAGE: f32 = 3.0; const OPEN_TANK_VOLTAGE: f32 = 3.0;
pub const WATER_FROZEN_THRESH: f32 = 4.0; pub const WATER_FROZEN_THRESH: f32 = 4.0;
@ -156,7 +158,7 @@ impl TankState {
} }
pub fn determine_tank_state( pub fn determine_tank_state(
board: &mut std::sync::MutexGuard<'_, EspHal<'_>>, board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
config: &PlantControllerConfig, config: &PlantControllerConfig,
) -> TankState { ) -> TankState {
if config.tank.tank_sensor_enabled { if config.tank.tank_sensor_enabled {

View File

@ -21,7 +21,6 @@ use std::{
use url::Url; use url::Url;
use crate::config::PlantControllerConfig; use crate::config::PlantControllerConfig;
use crate::plant_hal::SpecificBoard;
use crate::plant_state::MoistureSensorState; use crate::plant_state::MoistureSensorState;
#[derive(Serialize, Debug)] #[derive(Serialize, Debug)]
@ -116,7 +115,7 @@ fn get_live_moisture(
_request: &mut Request<&mut EspHttpConnection>, _request: &mut Request<&mut EspHttpConnection>,
) -> Result<Option<std::string::String>, anyhow::Error> { ) -> Result<Option<std::string::String>, anyhow::Error> {
let mut board = BOARD_ACCESS.lock().unwrap(); let mut board = BOARD_ACCESS.lock().unwrap();
let config = board.get_config().unwrap_or(PlantControllerConfig::default()); let config = board.get_config().unwrap();
let plant_state = Vec::from_iter( let plant_state = Vec::from_iter(
(0..PLANT_COUNT).map(|i| PlantState::read_hardware_state(i, &mut board, &config.plants[i])), (0..PLANT_COUNT).map(|i| PlantState::read_hardware_state(i, &mut board, &config.plants[i])),

View File

@ -279,21 +279,6 @@ export class Controller {
}) })
} }
selfTest() {
controller.progressview.addIndeterminate("boardtest", "Self test running");
fetch(PUBLIC_URL + "/boardtest", {
method: "POST"
})
.then(response => response.text())
.then(
_ => {
controller.progressview.removeProgress("boardtest");
}
)
}
testPlant(plantId: number) { testPlant(plantId: number) {
let counter = 0 let counter = 0
let limit = 30 let limit = 30
@ -481,7 +466,6 @@ export class Controller {
controller.exit(); controller.exit();
} }
} }
} }
const controller = new Controller(); const controller = new Controller();
controller.progressview.removeProgress("rebooting"); controller.progressview.removeProgress("rebooting");

View File

@ -5,7 +5,6 @@ export class OTAView {
readonly firmware_buildtime: HTMLDivElement; readonly firmware_buildtime: HTMLDivElement;
readonly firmware_githash: HTMLDivElement; readonly firmware_githash: HTMLDivElement;
readonly firmware_partition: HTMLDivElement; readonly firmware_partition: HTMLDivElement;
readonly test: HTMLButtonElement;
constructor(controller: Controller) { constructor(controller: Controller) {
(document.getElementById("firmwareview") as HTMLElement).innerHTML = require("./ota.html") (document.getElementById("firmwareview") as HTMLElement).innerHTML = require("./ota.html")
@ -13,7 +12,7 @@ export class OTAView {
this.firmware_buildtime = document.getElementById("firmware_buildtime") as HTMLDivElement; this.firmware_buildtime = document.getElementById("firmware_buildtime") as HTMLDivElement;
this.firmware_githash = document.getElementById("firmware_githash") as HTMLDivElement; this.firmware_githash = document.getElementById("firmware_githash") as HTMLDivElement;
this.firmware_partition = document.getElementById("firmware_partition") as HTMLDivElement; this.firmware_partition = document.getElementById("firmware_partition") as HTMLDivElement;
this.test = document.getElementById("test") as HTMLButtonElement;
const file = document.getElementById("firmware_file") as HTMLInputElement; const file = document.getElementById("firmware_file") as HTMLInputElement;
this.file1Upload = file this.file1Upload = file
@ -25,10 +24,6 @@ export class OTAView {
} }
controller.uploadNewFirmware(selectedFile); controller.uploadNewFirmware(selectedFile);
}; };
this.test.onclick = () => {
controller.selfTest()
}
} }
setVersion(versionInfo: VersionInfo) { setVersion(versionInfo: VersionInfo) {

@ -1 +1 @@
Subproject commit 1d21656d5efcf6a6b247245d057bf553f3209f39 Subproject commit 26d1205439b460bee960fd4c29f3c5c20948875f