wifi config file handling added
This commit is contained in:
parent
e43538ec8a
commit
5d6871250e
@ -74,6 +74,7 @@ one-wire-bus = "0.1.1"
|
|||||||
anyhow = { version = "1.0.75", features = ["std", "backtrace"] }
|
anyhow = { version = "1.0.75", features = ["std", "backtrace"] }
|
||||||
schemars = "0.8.16"
|
schemars = "0.8.16"
|
||||||
heapless = { version = "0.8.0", features = ["serde"] }
|
heapless = { version = "0.8.0", features = ["serde"] }
|
||||||
|
serde_json = "1.0.108"
|
||||||
#?bq34z100 required
|
#?bq34z100 required
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
use crate::PLANT_COUNT;
|
use crate::PLANT_COUNT;
|
||||||
pub struct Config {
|
|
||||||
ssid: heapless::String<32>,
|
|
||||||
password: Option<heapless::String<64>>,
|
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct Config {
|
||||||
tank_sensor_enabled: bool,
|
tank_sensor_enabled: bool,
|
||||||
tank_full_ml: u32,
|
tank_full_ml: u32,
|
||||||
tank_warn_percent: u8,
|
tank_warn_percent: u8,
|
||||||
@ -19,6 +21,16 @@ pub struct Config {
|
|||||||
night_lamp_hour_start: u8,
|
night_lamp_hour_start: u8,
|
||||||
night_lamp_hour_end: u8,
|
night_lamp_hour_end: u8,
|
||||||
night_lamp_only_when_dark: u8
|
night_lamp_only_when_dark: u8
|
||||||
|
}
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WifiConfig {
|
||||||
|
pub ssid: heapless::String<32>,
|
||||||
|
pub password: Option<heapless::String<64>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for WifiConfig {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "({}, ****)", self.ssid)
|
||||||
|
}
|
||||||
}
|
}
|
370
rust/src/main.rs
370
rust/src/main.rs
@ -2,6 +2,7 @@ use std::{
|
|||||||
ffi::CString,
|
ffi::CString,
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{Read, Write},
|
io::{Read, Write},
|
||||||
|
mem,
|
||||||
str::from_utf8,
|
str::from_utf8,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -11,14 +12,39 @@ use anyhow::{Context, Result};
|
|||||||
use chrono_tz::Europe::Berlin;
|
use chrono_tz::Europe::Berlin;
|
||||||
use esp_idf_hal::delay::Delay;
|
use esp_idf_hal::delay::Delay;
|
||||||
use esp_idf_svc::http::server::EspHttpServer;
|
use esp_idf_svc::http::server::EspHttpServer;
|
||||||
use plant_hal::{CreatePlantHal, PlantCtrlBoardInteraction, PlantHal, PLANT_COUNT};
|
use esp_idf_sys::{esp_restart, vTaskDelay, TickType_t};
|
||||||
|
use heapless::String;
|
||||||
|
use plant_hal::{CreatePlantHal, PlantCtrlBoard, PlantCtrlBoardInteraction, PlantHal, PLANT_COUNT};
|
||||||
use webserver::webserver::httpd;
|
use webserver::webserver::httpd;
|
||||||
|
|
||||||
|
use crate::config::{Config, WifiConfig};
|
||||||
mod config;
|
mod config;
|
||||||
pub mod plant_hal;
|
pub mod plant_hal;
|
||||||
mod webserver {
|
mod webserver {
|
||||||
pub mod webserver;
|
pub mod webserver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
enum OnlineMode {
|
||||||
|
Offline,
|
||||||
|
Wifi,
|
||||||
|
SnTp,
|
||||||
|
Mqtt,
|
||||||
|
MqttRoundtrip
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait_infinity(board: &mut PlantCtrlBoard<'_>) {
|
||||||
|
loop {
|
||||||
|
unsafe {
|
||||||
|
//do not trigger watchdog
|
||||||
|
board.general_fault(true);
|
||||||
|
vTaskDelay(500_u32);
|
||||||
|
board.general_fault(false);
|
||||||
|
vTaskDelay(500_u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> 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
|
||||||
@ -32,184 +58,202 @@ fn main() -> Result<()> {
|
|||||||
let git_hash = env!("VERGEN_GIT_DESCRIBE");
|
let git_hash = env!("VERGEN_GIT_DESCRIBE");
|
||||||
println!("Version useing git has {}", git_hash);
|
println!("Version useing git has {}", git_hash);
|
||||||
|
|
||||||
|
println!("Board hal init");
|
||||||
let mut board = PlantHal::create()?;
|
let mut board = PlantHal::create()?;
|
||||||
|
println!("Mounting filesystem");
|
||||||
|
board.mountFileSystem()?;
|
||||||
|
let free_space = board.fileSystemSize()?;
|
||||||
|
println!(
|
||||||
|
"Mounted, total space {} used {} free {}",
|
||||||
|
free_space.total_size, free_space.used_size, free_space.free_size
|
||||||
|
);
|
||||||
|
|
||||||
println!("Board hal init");
|
let time = board.time();
|
||||||
|
let mut cur = match time {
|
||||||
|
Ok(cur) => cur,
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("time error {}", err);
|
||||||
|
NaiveDateTime::from_timestamp_millis(0).unwrap().and_utc()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//check if we know the time current > 2020
|
||||||
|
if cur.year() < 2020 {
|
||||||
|
if board.is_day() {
|
||||||
|
//assume TZ safe times ;)
|
||||||
|
cur = *cur.with_hour(15).get_or_insert(cur);
|
||||||
|
} else {
|
||||||
|
cur = *cur.with_hour(3).get_or_insert(cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let time = board.time();
|
println!("cur is {}", cur);
|
||||||
let mut cur = match time {
|
|
||||||
Ok(cur) => cur,
|
if board.is_config_reset() {
|
||||||
Err(err) => {
|
println!("Reset config is pressed, waiting 5s");
|
||||||
log::error!("time error {}", err);
|
Delay::new_default().delay_ms(5000);
|
||||||
NaiveDateTime::from_timestamp_millis(0).unwrap().and_utc()
|
if board.is_config_reset() {
|
||||||
}
|
println!("Reset config is still pressed, deleting configs and reboot");
|
||||||
};
|
match board.remove_configs() {
|
||||||
//check if we know the time current > 2020
|
Ok(_) => {
|
||||||
if cur.year() < 2020 {
|
println!("Removed config files, restarting");
|
||||||
if board.is_day() {
|
unsafe {
|
||||||
//assume TZ safe times ;)
|
esp_restart();
|
||||||
cur = *cur.with_hour(15).get_or_insert(cur);
|
}
|
||||||
} else {
|
}
|
||||||
cur = *cur.with_hour(3).get_or_insert(cur);
|
Err(err) => {
|
||||||
|
println!("Could not remove config files, system borked {}", err);
|
||||||
|
//terminate main app and freeze
|
||||||
|
wait_infinity(&mut board);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
println!("cur is {}", cur);
|
let mut online_mode = OnlineMode::Offline;
|
||||||
|
let wifi_conf = board.get_wifi();
|
||||||
|
let wifi: WifiConfig;
|
||||||
|
match wifi_conf{
|
||||||
|
Ok(conf) => {
|
||||||
|
wifi = conf;
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
println!("Missing wifi config, entering initial config mode {}", err);
|
||||||
|
//config upload will trigger reboot!
|
||||||
|
let _webserver = httpd(true);
|
||||||
|
wait_infinity(&mut board);
|
||||||
|
//how to do this better?
|
||||||
|
let ssid: String<32> = String::try_from("").unwrap();
|
||||||
|
wifi = WifiConfig { ssid : ssid, password : None};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//continous/interrupt?
|
|
||||||
//check if boot button is pressed, if longer than 5s delete config and reboot into config mode
|
|
||||||
|
|
||||||
|
|
||||||
let config = board.get_config();
|
|
||||||
match config {
|
|
||||||
Ok(conf) => {
|
|
||||||
|
|
||||||
},
|
|
||||||
Err(err) => {
|
|
||||||
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// let proceed = config.unwrap();
|
// let proceed = config.unwrap();
|
||||||
|
|
||||||
//check if we have a config file
|
//check if we have a config file
|
||||||
// if not found or parsing error -> error very fast blink general fault
|
// 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
|
//if this happens after a firmeware upgrade (check image state), mark as invalid
|
||||||
//blink general fault error_reading_config_after_upgrade, reboot after
|
//blink general fault error_reading_config_after_upgrade, reboot after
|
||||||
// open accesspoint with webserver for wlan mqtt setup
|
// open accesspoint with webserver for wlan mqtt setup
|
||||||
//blink general fault error_no_config_after_upgrade
|
//blink general fault error_no_config_after_upgrade
|
||||||
//once config is set store it and reboot
|
//once config is set store it and reboot
|
||||||
|
|
||||||
//if proceed.tank_sensor_enabled() {
|
//if proceed.tank_sensor_enabled() {
|
||||||
|
|
||||||
//}
|
//}
|
||||||
//is tank sensor enabled in config?
|
//is tank sensor enabled in config?
|
||||||
//measure tank level (without wifi due to interference)
|
//measure tank level (without wifi due to interference)
|
||||||
//TODO this should be a result// detect invalid measurement value
|
//TODO this should be a result// detect invalid measurement value
|
||||||
let tank_value = board.tank_sensor_mv();
|
let tank_value = board.tank_sensor_mv();
|
||||||
match tank_value {
|
match tank_value {
|
||||||
Ok(tank_raw) => {
|
Ok(tank_raw) => {
|
||||||
println!("Tank sensor returned {}", tank_raw);
|
println!("Tank sensor returned {}", tank_raw);
|
||||||
},
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
//if not possible value, blink general fault error_tank_sensor_fault
|
//if not possible value, blink general fault error_tank_sensor_fault
|
||||||
board.general_fault(true);
|
board.general_fault(true);
|
||||||
//set general fault persistent
|
//set general fault persistent
|
||||||
//set tank sensor state to fault
|
//set tank sensor state to fault
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//measure each plant moisture
|
||||||
|
let mut initial_measurements_a: [i32; PLANT_COUNT] = [0; PLANT_COUNT];
|
||||||
|
let mut initial_measurements_b: [i32; PLANT_COUNT] = [0; PLANT_COUNT];
|
||||||
|
let mut initial_measurements_p: [i32; PLANT_COUNT] = [0; PLANT_COUNT];
|
||||||
|
for plant in 0..PLANT_COUNT {
|
||||||
|
initial_measurements_a[plant] = board.measure_moisture_hz(plant, plant_hal::Sensor::A)?;
|
||||||
|
initial_measurements_b[plant] = board.measure_moisture_hz(plant, plant_hal::Sensor::B)?;
|
||||||
|
initial_measurements_p[plant] =
|
||||||
|
board.measure_moisture_hz(plant, plant_hal::Sensor::PUMP)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("attempting to connect wifi");
|
||||||
|
match board.wifi(&wifi.ssid, wifi.password.as_deref(), 10000) {
|
||||||
|
Ok(_) => {
|
||||||
|
online_mode = OnlineMode::Wifi;
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
println!("Offline mode");
|
||||||
|
board.general_fault(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if online_mode == OnlineMode::Wifi {
|
||||||
|
match board.sntp(1000 * 120) {
|
||||||
|
Ok(new_time) => {
|
||||||
|
cur = new_time;
|
||||||
|
online_mode = OnlineMode::SnTp;
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
println!("sntp error: {}", err);
|
||||||
|
board.general_fault(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//measure each plant moisture
|
|
||||||
let mut initial_measurements_a: [i32;PLANT_COUNT] = [0;PLANT_COUNT];
|
|
||||||
let mut initial_measurements_b: [i32;PLANT_COUNT] = [0;PLANT_COUNT];
|
|
||||||
let mut initial_measurements_p: [i32;PLANT_COUNT] = [0;PLANT_COUNT];
|
|
||||||
for plant in 0..PLANT_COUNT {
|
|
||||||
initial_measurements_a[plant] = board.measure_moisture_hz(plant, plant_hal::Sensor::A)?;
|
|
||||||
initial_measurements_b[plant] = board.measure_moisture_hz(plant, plant_hal::Sensor::B)?;
|
|
||||||
initial_measurements_p[plant] = board.measure_moisture_hz(plant, plant_hal::Sensor::PUMP)?;
|
|
||||||
}
|
}
|
||||||
|
println!("Running logic at utc {}", cur);
|
||||||
//match board.wifi("C3MA", Some("chaosimquadrat"), 10000) {
|
let europe_time = cur.with_timezone(&Berlin);
|
||||||
// Ok(_) => println!("online mode"),
|
println!("Running logic at europe/berlin {}", europe_time);
|
||||||
// Err(_) => {
|
|
||||||
|
|
||||||
// println!("Offline mode");
|
|
||||||
//},
|
|
||||||
//}
|
|
||||||
//try connect wifi and do mqtt roundtrip
|
|
||||||
// if no wifi, set general fault persistent
|
|
||||||
//if no mqtt, set general fault persistent
|
|
||||||
|
|
||||||
let mut total_size = 0;
|
|
||||||
let mut used_size = 0;
|
|
||||||
unsafe {
|
|
||||||
let base_path = CString::new("/spiffs")?;
|
|
||||||
let storage = CString::new("storage")?;
|
|
||||||
|
|
||||||
let conf = esp_idf_sys::esp_vfs_spiffs_conf_t {
|
|
||||||
base_path: base_path.as_ptr(),
|
|
||||||
partition_label: storage.as_ptr(),
|
|
||||||
max_files: 5,
|
|
||||||
format_if_mount_failed: true,
|
|
||||||
};
|
|
||||||
esp_idf_sys::esp!(esp_idf_sys::esp_vfs_spiffs_register(&conf))?;
|
|
||||||
|
|
||||||
esp_idf_sys::esp!(esp_idf_sys::esp_spiffs_info(storage.as_ptr(),&mut total_size,&mut used_size))?;
|
|
||||||
}
|
}
|
||||||
println!("Total spiffs size is {}, used size is {}", total_size, used_size);
|
|
||||||
println!("writing");
|
|
||||||
let mut config_file = File::create("/spiffs/config.cfg")?;
|
|
||||||
config_file.write_all("test stuff".as_bytes())?;
|
|
||||||
config_file.flush()?;
|
|
||||||
println!("Reading");
|
|
||||||
let mut cfg = File::open("/spiffs/config.cfg")?;
|
|
||||||
let mut data: [u8; 512] = [0; 512];
|
|
||||||
let read = cfg.read(&mut data)?;
|
|
||||||
println!("Read file {}", from_utf8(&data[0..read])?);
|
|
||||||
|
|
||||||
/*
|
if(online_mode == OnlineMode::SnTp){
|
||||||
match board.sntp(1000 * 120) {
|
//mqtt here
|
||||||
Ok(new_time) => cur = new_time,
|
}
|
||||||
Err(err) => {
|
if(online_mode == OnlineMode::Mqtt){
|
||||||
println!("sntp error: {}", err);
|
//mqtt roundtrip here
|
||||||
|
}
|
||||||
|
//TODO configmode webserver logic here
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
|
||||||
|
//if config battery mode
|
||||||
|
//read battery level
|
||||||
|
//if not possible set general fault persistent, but do continue
|
||||||
|
//else
|
||||||
|
//assume 12v and max capacity
|
||||||
|
|
||||||
|
//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
|
||||||
|
|
||||||
|
//for each plant
|
||||||
|
//check if moisture is < target
|
||||||
|
//state += dry
|
||||||
|
//check if in cooldown
|
||||||
|
//state += cooldown
|
||||||
|
//check if consecutive pumps > limit
|
||||||
|
//state += notworking
|
||||||
|
//set plant fault persistent
|
||||||
|
|
||||||
|
//pump one cycle
|
||||||
|
// set last pump time to now
|
||||||
|
//during pump state += active
|
||||||
|
//after pump check if Pump moisture value is increased by config delta x
|
||||||
|
// state -= active
|
||||||
|
// state += cooldown
|
||||||
|
// if not set plant error persistent fault
|
||||||
|
// state += notworking
|
||||||
|
//set consecutive pumps+=1
|
||||||
|
|
||||||
|
//check if during light time
|
||||||
|
//lightstate += out of worktime
|
||||||
|
//check battery level
|
||||||
|
//lightstate += battery empty
|
||||||
|
//check solar level if config requires
|
||||||
|
//lightstate += stillday
|
||||||
|
//if no preventing lightstate, enable light
|
||||||
|
//lightstate = active
|
||||||
|
|
||||||
|
//keep webserver in scope
|
||||||
|
let webserver = httpd(true);
|
||||||
|
let delay = Delay::new_default();
|
||||||
|
loop {
|
||||||
|
//let freertos do shit
|
||||||
|
delay.delay_ms(1001);
|
||||||
}
|
}
|
||||||
}
|
*/
|
||||||
println!("Running logic at utc {}", cur);
|
//deepsleep here?
|
||||||
let europe_time = cur.with_timezone(&Berlin);
|
|
||||||
println!("Running logic at europe/berlin {}", europe_time);
|
|
||||||
|
|
||||||
//if config battery mode
|
|
||||||
//read battery level
|
|
||||||
//if not possible set general fault persistent, but do continue
|
|
||||||
//else
|
|
||||||
//assume 12v and max capacity
|
|
||||||
|
|
||||||
//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
|
|
||||||
|
|
||||||
//for each plant
|
|
||||||
//check if moisture is < target
|
|
||||||
//state += dry
|
|
||||||
//check if in cooldown
|
|
||||||
//state += cooldown
|
|
||||||
//check if consecutive pumps > limit
|
|
||||||
//state += notworking
|
|
||||||
//set plant fault persistent
|
|
||||||
|
|
||||||
//pump one cycle
|
|
||||||
// set last pump time to now
|
|
||||||
//during pump state += active
|
|
||||||
//after pump check if Pump moisture value is increased by config delta x
|
|
||||||
// state -= active
|
|
||||||
// state += cooldown
|
|
||||||
// if not set plant error persistent fault
|
|
||||||
// state += notworking
|
|
||||||
//set consecutive pumps+=1
|
|
||||||
|
|
||||||
//check if during light time
|
|
||||||
//lightstate += out of worktime
|
|
||||||
//check battery level
|
|
||||||
//lightstate += battery empty
|
|
||||||
//check solar level if config requires
|
|
||||||
//lightstate += stillday
|
|
||||||
//if no preventing lightstate, enable light
|
|
||||||
//lightstate = active
|
|
||||||
|
|
||||||
//keep webserver in scope
|
|
||||||
let webserver = httpd(true);
|
|
||||||
let delay = Delay::new_default();
|
|
||||||
loop {
|
|
||||||
//let freertos do shit
|
|
||||||
delay.delay_ms(1001);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
//mod config;
|
//mod config;
|
||||||
|
|
||||||
use embedded_svc::wifi::{Configuration, ClientConfiguration, AuthMethod};
|
use embedded_svc::wifi::{Configuration, ClientConfiguration, AuthMethod, Wifi};
|
||||||
use esp_idf_svc::eventloop::EspSystemEventLoop;
|
use esp_idf_svc::eventloop::EspSystemEventLoop;
|
||||||
use esp_idf_svc::nvs::EspDefaultNvsPartition;
|
use esp_idf_svc::nvs::EspDefaultNvsPartition;
|
||||||
use esp_idf_svc::wifi::EspWifi;
|
use esp_idf_svc::wifi::EspWifi;
|
||||||
|
|
||||||
|
use std::ffi::CString;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::{Read, BufReader};
|
||||||
|
use std::path::Path;
|
||||||
|
use std::str::from_utf8;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use anyhow::{Context, Result, bail, Ok};
|
use anyhow::{Context, Result, bail, Ok};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
@ -25,10 +28,11 @@ use esp_idf_svc::systime::EspSystemTime;
|
|||||||
use esp_idf_sys::EspError;
|
use esp_idf_sys::EspError;
|
||||||
use one_wire_bus::OneWire;
|
use one_wire_bus::OneWire;
|
||||||
use shift_register_driver::sipo::ShiftRegister40;
|
use shift_register_driver::sipo::ShiftRegister40;
|
||||||
use esp_idf_hal::gpio::{PinDriver, Gpio39, Gpio4, AnyInputPin};
|
use esp_idf_hal::gpio::{PinDriver, Gpio39, Gpio4, AnyInputPin, Level};
|
||||||
use esp_idf_hal::prelude::Peripherals;
|
use esp_idf_hal::prelude::Peripherals;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::config;
|
use crate::config::{self, WifiConfig};
|
||||||
|
|
||||||
pub const PLANT_COUNT:usize = 8;
|
pub const PLANT_COUNT:usize = 8;
|
||||||
const PINS_PER_PLANT:usize = 5;
|
const PINS_PER_PLANT:usize = 5;
|
||||||
@ -38,6 +42,9 @@ const PLANT_MOIST_PUMP_OFFSET:usize = 2;
|
|||||||
const PLANT_MOIST_B_OFFSET:usize = 3;
|
const PLANT_MOIST_B_OFFSET:usize = 3;
|
||||||
const PLANT_MOIST_A_OFFSET:usize = 4;
|
const PLANT_MOIST_A_OFFSET:usize = 4;
|
||||||
|
|
||||||
|
const SPIFFS_PARTITION_NAME: &str = "storage";
|
||||||
|
const WIFI_CONFIG_FILE: &str = "/spiffs/wifi.cfg";
|
||||||
|
const CONFIG_FILE: &str = "/spiffs/config.cfg";
|
||||||
|
|
||||||
|
|
||||||
#[link_section = ".rtc.data"]
|
#[link_section = ".rtc.data"]
|
||||||
@ -64,6 +71,12 @@ pub struct BatteryState {
|
|||||||
state_health_percent: u8
|
state_health_percent: u8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct FileSystemSizeInfo{
|
||||||
|
pub total_size: usize,
|
||||||
|
pub used_size: usize,
|
||||||
|
pub free_size: usize
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Sensor{
|
pub enum Sensor{
|
||||||
A,
|
A,
|
||||||
@ -74,6 +87,8 @@ pub trait PlantCtrlBoardInteraction{
|
|||||||
fn time(&mut self) -> Result<chrono::DateTime<Utc>>;
|
fn time(&mut self) -> Result<chrono::DateTime<Utc>>;
|
||||||
fn wifi(&mut self, ssid:&str, password:Option<&str>, max_wait:u32) -> Result<()>;
|
fn wifi(&mut self, ssid:&str, password:Option<&str>, max_wait:u32) -> Result<()>;
|
||||||
fn sntp(&mut self, max_wait:u32) -> Result<chrono::DateTime<Utc>>;
|
fn sntp(&mut self, max_wait:u32) -> Result<chrono::DateTime<Utc>>;
|
||||||
|
fn mountFileSystem(&mut self) -> Result<()>;
|
||||||
|
fn fileSystemSize(&mut self) -> Result<FileSystemSizeInfo>;
|
||||||
|
|
||||||
fn battery_state(&mut self) -> Result<BatteryState>;
|
fn battery_state(&mut self) -> Result<BatteryState>;
|
||||||
|
|
||||||
@ -101,7 +116,12 @@ pub trait PlantCtrlBoardInteraction{
|
|||||||
//keep state during deepsleep
|
//keep state during deepsleep
|
||||||
fn fault(&self,plant:usize, enable:bool);
|
fn fault(&self,plant:usize, enable:bool);
|
||||||
|
|
||||||
|
//config
|
||||||
|
fn is_config_reset(&mut self) -> bool;
|
||||||
|
fn remove_configs(&mut self) -> Result<()>;
|
||||||
fn get_config(&mut self) -> Result<config::Config>;
|
fn get_config(&mut self) -> Result<config::Config>;
|
||||||
|
fn get_wifi(&mut self) -> Result<config::WifiConfig>;
|
||||||
|
fn set_wifi(&mut self, wifi: &WifiConfig) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CreatePlantHal<'a> {
|
pub trait CreatePlantHal<'a> {
|
||||||
@ -199,6 +219,7 @@ impl CreatePlantHal<'_> for PlantHal{
|
|||||||
let tank_driver = AdcDriver::new(peripherals.adc1, &Config::new())?;
|
let tank_driver = AdcDriver::new(peripherals.adc1, &Config::new())?;
|
||||||
let tank_channel: AdcChannelDriver<'_, {attenuation::DB_11}, Gpio39> = AdcChannelDriver::new(peripherals.pins.gpio39)?;
|
let tank_channel: AdcChannelDriver<'_, {attenuation::DB_11}, Gpio39> = AdcChannelDriver::new(peripherals.pins.gpio39)?;
|
||||||
let solar_is_day = PinDriver::input(peripherals.pins.gpio25)?;
|
let solar_is_day = PinDriver::input(peripherals.pins.gpio25)?;
|
||||||
|
let boot_button = PinDriver::input(peripherals.pins.gpio0)?;
|
||||||
let light = PinDriver::output(peripherals.pins.gpio26)?;
|
let light = PinDriver::output(peripherals.pins.gpio26)?;
|
||||||
let main_pump = PinDriver::output(peripherals.pins.gpio23)?;
|
let main_pump = PinDriver::output(peripherals.pins.gpio23)?;
|
||||||
let tank_power = PinDriver::output(peripherals.pins.gpio27)?;
|
let tank_power = PinDriver::output(peripherals.pins.gpio27)?;
|
||||||
@ -215,6 +236,7 @@ impl CreatePlantHal<'_> for PlantHal{
|
|||||||
tank_driver : tank_driver,
|
tank_driver : tank_driver,
|
||||||
tank_channel: tank_channel,
|
tank_channel: tank_channel,
|
||||||
solar_is_day : solar_is_day,
|
solar_is_day : solar_is_day,
|
||||||
|
boot_button : boot_button,
|
||||||
light: light,
|
light: light,
|
||||||
main_pump: main_pump,
|
main_pump: main_pump,
|
||||||
tank_power: tank_power,
|
tank_power: tank_power,
|
||||||
@ -235,6 +257,7 @@ pub struct PlantCtrlBoard<'a>{
|
|||||||
tank_driver: AdcDriver<'a, esp_idf_hal::adc::ADC1>,
|
tank_driver: AdcDriver<'a, esp_idf_hal::adc::ADC1>,
|
||||||
tank_channel: esp_idf_hal::adc::AdcChannelDriver<'a, { attenuation::DB_11 }, Gpio39 >,
|
tank_channel: esp_idf_hal::adc::AdcChannelDriver<'a, { attenuation::DB_11 }, Gpio39 >,
|
||||||
solar_is_day: PinDriver<'a, esp_idf_hal::gpio::Gpio25, esp_idf_hal::gpio::Input>,
|
solar_is_day: PinDriver<'a, esp_idf_hal::gpio::Gpio25, esp_idf_hal::gpio::Input>,
|
||||||
|
boot_button: PinDriver<'a, esp_idf_hal::gpio::Gpio0, esp_idf_hal::gpio::Input>,
|
||||||
signal_counter: PcntDriver<'a>,
|
signal_counter: PcntDriver<'a>,
|
||||||
light: PinDriver<'a, esp_idf_hal::gpio::Gpio26, esp_idf_hal::gpio::Output>,
|
light: PinDriver<'a, esp_idf_hal::gpio::Gpio26, esp_idf_hal::gpio::Output>,
|
||||||
main_pump: PinDriver<'a, esp_idf_hal::gpio::Gpio23, esp_idf_hal::gpio::Output>,
|
main_pump: PinDriver<'a, esp_idf_hal::gpio::Gpio23, esp_idf_hal::gpio::Output>,
|
||||||
@ -445,12 +468,72 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_config(&mut self) -> Result<config::Config> {
|
fn mountFileSystem(&mut self) -> Result<()> {
|
||||||
let config_file = File::open("config.cfg")?;
|
let base_path = CString::new("/spiffs")?;
|
||||||
//serde_json::from_str(&data);
|
let storage = CString::new(SPIFFS_PARTITION_NAME)?;
|
||||||
bail!("Not implemented");
|
let conf = esp_idf_sys::esp_vfs_spiffs_conf_t {
|
||||||
|
base_path: base_path.as_ptr(),
|
||||||
|
partition_label: storage.as_ptr(),
|
||||||
|
max_files: 2,
|
||||||
|
format_if_mount_failed: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
esp_idf_sys::esp!(esp_idf_sys::esp_vfs_spiffs_register(&conf))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fileSystemSize(&mut self) -> Result<FileSystemSizeInfo> {
|
||||||
|
let storage = CString::new(SPIFFS_PARTITION_NAME)?;
|
||||||
|
let mut total_size = 0;
|
||||||
|
let mut used_size = 0;
|
||||||
|
unsafe {
|
||||||
|
esp_idf_sys::esp!(esp_idf_sys::esp_spiffs_info(storage.as_ptr(),&mut total_size,&mut used_size))?;
|
||||||
|
}
|
||||||
|
return Ok(FileSystemSizeInfo{total_size, used_size, free_size : total_size - used_size});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_config_reset(&mut self) -> bool {
|
||||||
|
return self.boot_button.get_level() == Level::Low;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_configs(&mut self) -> Result<()> {
|
||||||
|
let wifi_config = Path::new(WIFI_CONFIG_FILE);
|
||||||
|
if wifi_config.exists() {
|
||||||
|
println!("Removing wifi config");
|
||||||
|
std::fs::remove_file(wifi_config)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let config = Path::new(CONFIG_FILE);
|
||||||
|
if config.exists() {
|
||||||
|
println!("Removing config");
|
||||||
|
std::fs::remove_file(config)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_wifi(&mut self) -> Result<config::WifiConfig> {
|
||||||
|
let cfg = File::open(WIFI_CONFIG_FILE)?;
|
||||||
|
let config: WifiConfig = serde_json::from_reader(cfg)?;
|
||||||
|
return Ok(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_wifi(&mut self, wifi: &WifiConfig ) -> Result<()> {
|
||||||
|
let mut cfg = File::create(WIFI_CONFIG_FILE)?;
|
||||||
|
serde_json::to_writer(&mut cfg, &wifi)?;
|
||||||
|
println!("Wrote wifi config {}", wifi);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_config(&mut self) -> Result<config::Config> {
|
||||||
|
let mut cfg = File::open(CONFIG_FILE)?;
|
||||||
|
let mut data: [u8; 512] = [0; 512];
|
||||||
|
let read = cfg.read(&mut data)?;
|
||||||
|
println!("Read file {}", from_utf8(&data[0..read])?);
|
||||||
|
|
||||||
|
|
||||||
|
bail!("todo")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user