2023-11-20 01:46:19 +01:00
|
|
|
use chrono::Utc;
|
|
|
|
use embedded_hal::digital::v1_compat::OldOutputPin;
|
|
|
|
use esp_idf_hal::adc::config::Config;
|
|
|
|
use esp_idf_hal::adc::{AdcDriver, AdcChannelDriver, attenuation};
|
2023-11-20 02:24:14 +01:00
|
|
|
use esp_idf_hal::reset::ResetReason;
|
2023-11-20 01:46:19 +01:00
|
|
|
use shift_register_driver::sipo::{ShiftRegister24, ShiftRegisterPin};
|
|
|
|
use esp_idf_hal::gpio::PinDriver;
|
|
|
|
use esp_idf_hal::prelude::Peripherals;
|
|
|
|
|
|
|
|
const PLANT_COUNT:usize = 8;
|
|
|
|
#[link_section = ".rtc.data"]
|
|
|
|
static mut LAST_WATERING_TIMESTAMP: [u64; PLANT_COUNT] = [0; PLANT_COUNT];
|
|
|
|
#[link_section = ".rtc.data"]
|
|
|
|
static mut CONSECUTIVE_WATERING_PLANT: [u64; PLANT_COUNT] = [0; PLANT_COUNT];
|
|
|
|
#[link_section = ".rtc.data"]
|
|
|
|
static mut LOW_VOLTAGE_DETECTED:bool = false;
|
|
|
|
|
|
|
|
struct BatteryState {
|
|
|
|
state_charge_percent: u8,
|
|
|
|
max_error_percent: u8,
|
|
|
|
remaining_milli_ampere_hour: u32,
|
|
|
|
max_milli_ampere_hour: u32,
|
|
|
|
design_milli_ampere_hour:u32,
|
|
|
|
voltage_milli_volt: u16,
|
|
|
|
average_current_milli_ampere: u16,
|
|
|
|
temperature_tenth_kelvin: u32,
|
|
|
|
average_time_to_empty_minute: u16,
|
|
|
|
average_time_to_full_minute: u16,
|
|
|
|
average_discharge_power_cycle_milli_watt: u16,
|
|
|
|
cycle_count: u16,
|
|
|
|
state_health_percent: u8
|
|
|
|
}
|
|
|
|
trait PlantCtrlBoardInteraction{
|
2023-11-20 02:24:14 +01:00
|
|
|
fn battery_state(&self,) -> BatteryState;
|
2023-11-20 01:46:19 +01:00
|
|
|
|
2023-11-20 02:24:14 +01:00
|
|
|
fn is_day(&self,) -> bool;
|
|
|
|
fn water_temperature_c(&self,) -> u16;
|
|
|
|
fn tank_sensor_mv(&self,) -> u16;
|
2023-11-20 01:46:19 +01:00
|
|
|
|
2023-11-20 02:24:14 +01:00
|
|
|
fn set_low_voltage_in_cycle(&self,);
|
|
|
|
fn clear_low_voltage_in_cycle(&self,);
|
|
|
|
fn low_voltage_in_cycle(&self) -> bool;
|
|
|
|
fn any_pump(&self, enabled:bool);
|
2023-11-20 01:46:19 +01:00
|
|
|
|
|
|
|
//keep state during deepsleep
|
2023-11-20 02:24:14 +01:00
|
|
|
fn light(&self,enable:bool);
|
|
|
|
|
|
|
|
fn plant_count(&self,) -> i8;
|
|
|
|
fn measure_moisture_b_hz(&self,plant:i8) -> i16;
|
|
|
|
fn measure_moisture_a_hz(&self,plant:i8) -> i16;
|
|
|
|
fn measure_moisture_p_hz(&self,plant:i8) -> i16;
|
|
|
|
fn pump(&self,plant:i8, enable:bool);
|
|
|
|
fn last_pump_time(&self,plant:i8) -> chrono::DateTime<Utc>;
|
|
|
|
fn store_last_pump_time(&self,plant:i8, time: chrono::DateTime<Utc>);
|
|
|
|
fn store_consecutive_pump_count(&self,plant:i8, count:i16);
|
|
|
|
fn consecutive_pump_count(&self,plant:i8) -> i16;
|
2023-11-20 01:46:19 +01:00
|
|
|
|
|
|
|
//keep state during deepsleep
|
2023-11-20 02:24:14 +01:00
|
|
|
fn fault(&self,plant:i8, enable:bool);
|
2023-11-20 01:46:19 +01:00
|
|
|
|
|
|
|
fn default() -> Self;
|
|
|
|
}
|
|
|
|
|
|
|
|
trait Plant{
|
|
|
|
fn setPump(pump:bool);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
struct PlantHal<'d>{
|
|
|
|
pump:ShiftRegisterPin<'d>
|
|
|
|
}
|
|
|
|
|
|
|
|
struct PlantCtrlBoard{
|
|
|
|
dummy:i32
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PlantCtrlBoardInteraction for PlantCtrlBoard {
|
|
|
|
fn default() -> Self {
|
|
|
|
let peripherals = Peripherals::take().unwrap();
|
|
|
|
|
|
|
|
let mut adc = AdcDriver::new(peripherals.adc1, &Config::new().calibration(true)).unwrap();
|
|
|
|
let mut adc_pin: esp_idf_hal::adc::AdcChannelDriver<{ attenuation::DB_11 }, _> = AdcChannelDriver::new(peripherals.pins.gpio39).unwrap();
|
|
|
|
let analog_value = adc.read(&mut adc_pin);
|
|
|
|
|
|
|
|
let clock = OldOutputPin::from(PinDriver::output(peripherals.pins.gpio21).unwrap());
|
|
|
|
let latch = OldOutputPin::from(PinDriver::output(peripherals.pins.gpio22).unwrap());
|
|
|
|
let data = OldOutputPin::from(PinDriver::output(peripherals.pins.gpio19).unwrap());
|
|
|
|
|
|
|
|
|
|
|
|
let shift_register = ShiftRegister24::new(clock, latch, data);
|
|
|
|
let registerOutput = shift_register.decompose();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Self { dummy: 12 }
|
|
|
|
}
|
|
|
|
|
2023-11-20 02:24:14 +01:00
|
|
|
fn battery_state(&self,) -> BatteryState {
|
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_day(&self,) -> bool {
|
2023-11-20 01:46:19 +01:00
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
2023-11-20 02:24:14 +01:00
|
|
|
fn water_temperature_c(&self,) -> u16 {
|
2023-11-20 01:46:19 +01:00
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
2023-11-20 02:24:14 +01:00
|
|
|
fn tank_sensor_mv(&self,) -> u16 {
|
2023-11-20 01:46:19 +01:00
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
2023-11-20 02:24:14 +01:00
|
|
|
fn set_low_voltage_in_cycle(&self,) {
|
|
|
|
unsafe {
|
|
|
|
LOW_VOLTAGE_DETECTED = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn clear_low_voltage_in_cycle(&self,) {
|
|
|
|
unsafe {
|
|
|
|
LOW_VOLTAGE_DETECTED = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn light(&self,enable:bool) {
|
2023-11-20 01:46:19 +01:00
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
2023-11-20 02:24:14 +01:00
|
|
|
fn plant_count(&self,) -> i8 {
|
2023-11-20 01:46:19 +01:00
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
2023-11-20 02:24:14 +01:00
|
|
|
fn measure_moisture_b_hz(&self,plant:i8) -> i16 {
|
2023-11-20 01:46:19 +01:00
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
2023-11-20 02:24:14 +01:00
|
|
|
fn measure_moisture_a_hz(&self,plant:i8) -> i16 {
|
2023-11-20 01:46:19 +01:00
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
2023-11-20 02:24:14 +01:00
|
|
|
fn measure_moisture_p_hz(&self,plant:i8) -> i16 {
|
2023-11-20 01:46:19 +01:00
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
2023-11-20 02:24:14 +01:00
|
|
|
fn pump(&self,plant:i8, enable:bool) {
|
2023-11-20 01:46:19 +01:00
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
2023-11-20 02:24:14 +01:00
|
|
|
fn last_pump_time(&self,plant:i8) -> chrono::DateTime<Utc> {
|
2023-11-20 01:46:19 +01:00
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
2023-11-20 02:24:14 +01:00
|
|
|
fn store_last_pump_time(&self,plant:i8, time: chrono::DateTime<Utc>) {
|
2023-11-20 01:46:19 +01:00
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
2023-11-20 02:24:14 +01:00
|
|
|
fn store_consecutive_pump_count(&self,plant:i8, count:i16) {
|
2023-11-20 01:46:19 +01:00
|
|
|
todo!()
|
|
|
|
}
|
2023-11-20 02:24:14 +01:00
|
|
|
|
|
|
|
fn consecutive_pump_count(&self,plant:i8) -> i16 {
|
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fault(&self,plant:i8, enable:bool) {
|
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn low_voltage_in_cycle(&self) -> bool {
|
|
|
|
unsafe {
|
|
|
|
return LOW_VOLTAGE_DETECTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-11-20 01:46:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
|
|
|
// 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();
|
|
|
|
|
|
|
|
// Bind the log crate to the ESP Logging facilities
|
|
|
|
esp_idf_svc::log::EspLogger::initialize_default();
|
|
|
|
|
|
|
|
log::info!("Hello, world!");
|
|
|
|
|
|
|
|
|
2023-11-20 02:24:14 +01:00
|
|
|
let reasons = ResetReason::get();
|
|
|
|
//init,reset rtc memory depending on cause
|
|
|
|
|
2023-11-20 01:46:19 +01:00
|
|
|
let board = PlantCtrlBoard::default();
|
|
|
|
|
2023-11-20 02:24:14 +01:00
|
|
|
//check if we know the time current > 2020
|
|
|
|
//if failed assume its 1.1.1970
|
|
|
|
//12:00 if solar reports day
|
|
|
|
//00:00 if solar repors night
|
|
|
|
|
|
|
|
//check if we have a config file
|
|
|
|
// if not found or parsing error -> error very fast blink general fault
|
|
|
|
//if this happens after a firmeware upgrade (check image state), mark as invalid
|
|
|
|
//blink general fault error_reading_config_after_upgrade, reboot after
|
|
|
|
// open accesspoint with webserver for wlan mqtt setup
|
|
|
|
//blink general fault error_no_config_after_upgrade
|
|
|
|
//once config is set store it and reboot
|
|
|
|
|
|
|
|
//is tank sensor enabled in config?
|
|
|
|
//measure tank level (without wifi due to interference)
|
|
|
|
//if not possible value, blink general fault error_tank_sensor_fault
|
|
|
|
//set general fault persistent
|
|
|
|
//set tank sensor state to fault
|
|
|
|
|
|
|
|
|
|
|
|
//try connect wifi and do mqtt roundtrip
|
|
|
|
// if no wifi, set general fault persistent
|
|
|
|
//if no mqtt, set general fault persistent
|
|
|
|
|
|
|
|
//measure each plant moisture
|
|
|
|
//check which plants need to be watered
|
|
|
|
//()
|
|
|
|
|
|
|
|
//if tank sensor is enabled
|
|
|
|
//if tank sensor fault abort if config require is set
|
|
|
|
//check if water is > minimum allowed || fault
|
|
|
|
//if not, set all plants requiring water to persistent fault
|
|
|
|
// pump water for first plant update last water timestamp
|
|
|
|
// wait for config time per plant
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-11-20 01:46:19 +01:00
|
|
|
}
|
2023-11-20 02:24:14 +01:00
|
|
|
|
|
|
|
//error codes
|
|
|
|
//error_reading_config_after_upgrade
|
|
|
|
//error_no_config_after_upgrade
|
|
|
|
//error_tank_sensor_fault
|