logging and pcb adjustment
This commit is contained in:
parent
1741bb0b53
commit
aad1dbd458
@ -1,6 +1,6 @@
|
||||
{
|
||||
"board": {
|
||||
"active_layer": 37,
|
||||
"active_layer": 31,
|
||||
"active_layer_preset": "",
|
||||
"auto_track_width": false,
|
||||
"hidden_netclasses": [],
|
||||
|
@ -17378,6 +17378,16 @@
|
||||
)
|
||||
(uuid "3279e749-d62b-45dc-920c-a4d4fc61f21f")
|
||||
)
|
||||
(text "use around 33k for 17.1v\nbe aware limit is 6v on input pin!"
|
||||
(exclude_from_sim no)
|
||||
(at 387.096 525.526 0)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
)
|
||||
)
|
||||
(uuid "3455ce77-4a9f-487a-85c9-d8775331bede")
|
||||
)
|
||||
(text "WaterTemp"
|
||||
(exclude_from_sim no)
|
||||
(at 74.93 194.31 0)
|
||||
|
File diff suppressed because one or more lines are too long
@ -28,7 +28,9 @@ command = [
|
||||
"save-image",
|
||||
"--chip",
|
||||
"esp32c6",
|
||||
"image.bin"
|
||||
"image.bin",
|
||||
"--partition-table",
|
||||
"partitions.csv"
|
||||
]
|
||||
|
||||
|
||||
@ -66,7 +68,7 @@ once_cell = "1.19.0"
|
||||
anyhow = { version = "1.0.75", features = ["std", "backtrace"] }
|
||||
average = { version = "0.14.1" , features = ["std"] }
|
||||
bit_field = "0.10.2"
|
||||
strum = { version = "0.26.1", features = ["derive"] }
|
||||
strum = { version = "0.27.0", features = ["derive"] }
|
||||
measurements = "0.11.0"
|
||||
schemars = "0.8.16"
|
||||
|
||||
@ -82,6 +84,8 @@ url = "2.5.3"
|
||||
crc = "3.2.1"
|
||||
bincode = "1.3.3"
|
||||
ringbuffer = "0.15.0"
|
||||
text-template = "0.1.0"
|
||||
strum_macros = "0.27.0"
|
||||
|
||||
|
||||
[patch.crates-io]
|
||||
|
143
rust/src/log/mod.rs
Normal file
143
rust/src/log/mod.rs
Normal file
@ -0,0 +1,143 @@
|
||||
use std::{collections::HashMap, sync::Mutex};
|
||||
use strum_macros::IntoStaticStr;
|
||||
|
||||
use esp_idf_svc::systime::EspSystemTime;
|
||||
use once_cell::sync::Lazy;
|
||||
use ringbuffer::{ConstGenericRingBuffer, RingBuffer};
|
||||
use text_template::Template;
|
||||
|
||||
const TXT_SHORT_LENGTH:usize = 8;
|
||||
const TXT_LONG_LENGTH:usize = 32;
|
||||
|
||||
const BUFFER_SIZE:usize = 210;
|
||||
|
||||
#[link_section = ".rtc.data"]
|
||||
static mut BUFFER:ConstGenericRingBuffer::<LogEntry, BUFFER_SIZE> = ConstGenericRingBuffer::<LogEntry, BUFFER_SIZE>::new();
|
||||
|
||||
static BUFFER_ACCESS: Lazy<Mutex<&mut ConstGenericRingBuffer::<LogEntry, BUFFER_SIZE>>> = Lazy::new(|| unsafe { Mutex::new(&mut BUFFER) });
|
||||
|
||||
|
||||
pub struct LogEntry {
|
||||
pub timestamp: u64,
|
||||
pub message_id: u32,
|
||||
pub a: u32,
|
||||
pub b: u32,
|
||||
pub txt_short: heapless::String<TXT_SHORT_LENGTH>,
|
||||
pub txt_long: heapless::String<TXT_LONG_LENGTH>
|
||||
}
|
||||
|
||||
pub fn init(){
|
||||
unsafe {
|
||||
BUFFER = ConstGenericRingBuffer::<LogEntry, BUFFER_SIZE>::new();
|
||||
};
|
||||
let mut access = BUFFER_ACCESS.lock().unwrap();
|
||||
access.drain().for_each(|_| {});
|
||||
}
|
||||
|
||||
fn limit_length <const LIMIT:usize> (input: &str, target: &mut heapless::String<LIMIT>){
|
||||
for char in input.chars() {
|
||||
match target.push(char) {
|
||||
Ok(_) => {}, //continue adding chars
|
||||
Err(_) => {
|
||||
//clear space for two asci chars
|
||||
while target.len()+2 >= LIMIT {
|
||||
target.pop().unwrap();
|
||||
}
|
||||
//add .. to shortened strings
|
||||
target.push('.').unwrap();
|
||||
target.push('.').unwrap();
|
||||
return;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log(message_key: LogMessage, number_a: u32, number_b: u32, txt_short:&str, txt_long:&str){
|
||||
let mut txt_short_stack:heapless::String<TXT_SHORT_LENGTH> = heapless::String::new();
|
||||
let mut txt_long_stack:heapless::String<TXT_LONG_LENGTH> = heapless::String::new();
|
||||
|
||||
limit_length(txt_short, &mut txt_short_stack);
|
||||
limit_length(txt_long, &mut txt_long_stack);
|
||||
|
||||
let time = EspSystemTime {}.now().as_millis() as u64;
|
||||
|
||||
let template_string:&str = message_key.into();
|
||||
|
||||
|
||||
let mut values: HashMap<&str, &str> = HashMap::new();
|
||||
let number_a_str = number_a.to_string();
|
||||
let number_b_str = number_b.to_string();
|
||||
|
||||
values.insert("number_a", &number_a_str);
|
||||
values.insert("number_b", &number_b_str);
|
||||
values.insert("txt_short", txt_short);
|
||||
values.insert("txt_long", txt_long);
|
||||
|
||||
let template = Template::from(template_string);
|
||||
let serial_entry = template.fill_in(&values);
|
||||
|
||||
println!("{serial_entry}");
|
||||
|
||||
|
||||
let entry = LogEntry{
|
||||
timestamp: time,
|
||||
message_id: 1,
|
||||
a: number_a,
|
||||
b: number_b,
|
||||
txt_short: txt_short_stack,
|
||||
txt_long: txt_long_stack,
|
||||
};
|
||||
|
||||
|
||||
let mut buffer = BUFFER_ACCESS.lock().unwrap();
|
||||
buffer.push(entry);
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn within_limit() {
|
||||
let test = "12345678";
|
||||
|
||||
let mut txt_short_stack:heapless::String<TXT_SHORT_LENGTH> = heapless::String::new();
|
||||
let mut txt_long_stack:heapless::String<TXT_LONG_LENGTH> = heapless::String::new();
|
||||
limit_length(test, &mut txt_short_stack);
|
||||
limit_length(test, &mut txt_long_stack);
|
||||
|
||||
assert_eq!(txt_short_stack.as_str(), test);
|
||||
assert_eq!(txt_long_stack.as_str(), test);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(IntoStaticStr)]
|
||||
pub enum LogMessage {
|
||||
#[strum(serialize = "Reset due to {{txt_long}} requires rtc clear {{a}} and force config mode {{b}}")]
|
||||
reset_reason,
|
||||
#[strum(serialize = "Current restart to conf mode {{a}}")]
|
||||
restart_to_config,
|
||||
#[strum(serialize = "Current low voltage detection is {{a}}")]
|
||||
low_voltage,
|
||||
#[strum(serialize = "Error communicating with battery!! {{txt_long}}")]
|
||||
battery_communication_error,
|
||||
#[strum(serialize = "Tank sensor raw {{a}} percent {{b}}")]
|
||||
sensor_tank_raw,
|
||||
#[strum(serialize = "raw measure unscaled {{a}} hz {{b}}, plant {{txt_short}} sensor {{txt_long}}")]
|
||||
raw_measure,
|
||||
#[strum(serialize = "IP info: {{txt_long}}")]
|
||||
wifi_info,
|
||||
#[strum(serialize = "Plant:{{txt_short}} a:{{a}} b:{{b}}")]
|
||||
test_sensor,
|
||||
#[strum(serialize = "Stay alive topic is {{txt_long}}")]
|
||||
stay_alive,
|
||||
#[strum(serialize = "Connecting mqtt {{txt_short}} with id {{txt_long}}")]
|
||||
mqtt_info,
|
||||
#[strum(serialize = "Received stay alive with value {{txt_short}}")]
|
||||
mqtt_stay_alive_rec,
|
||||
#[strum(serialize = "Unknown topic recieved {{txt_long}}")]
|
||||
unknown_topic,
|
||||
}
|
@ -3,7 +3,7 @@ use std::{
|
||||
sync::{atomic::AtomicBool, Arc, Mutex},
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{bail, Result};
|
||||
use chrono::{DateTime, Datelike, TimeDelta, Timelike, Utc};
|
||||
use chrono_tz::{Europe::Berlin, Tz};
|
||||
|
||||
@ -22,7 +22,6 @@ use esp_idf_sys::{
|
||||
esp_ota_img_states_t_ESP_OTA_IMG_VALID,
|
||||
vTaskDelay
|
||||
};
|
||||
use log::error;
|
||||
use once_cell::sync::Lazy;
|
||||
use plant_hal::{PlantCtrlBoard, PlantHal, PLANT_COUNT};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -32,10 +31,12 @@ use crate::{
|
||||
espota::{mark_app_valid, rollback_and_reboot},
|
||||
webserver::webserver::httpd,
|
||||
};
|
||||
mod log;
|
||||
mod config;
|
||||
pub mod espota;
|
||||
pub mod plant_hal;
|
||||
|
||||
|
||||
const TIME_ZONE: Tz = Berlin;
|
||||
|
||||
const MOIST_SENSOR_MAX_FREQUENCY: u32 = 250000; // 60kHz (500Hz margin)
|
||||
@ -72,9 +73,9 @@ struct LightState {
|
||||
#[derive(Debug, PartialEq, Default)]
|
||||
struct PlantState {
|
||||
a: Option<u8>,
|
||||
a_raw: Option<i32>,
|
||||
a_raw: Option<u32>,
|
||||
b: Option<u8>,
|
||||
b_raw: Option<i32>,
|
||||
b_raw: Option<u32>,
|
||||
consecutive_pump_count: u32,
|
||||
after_p: Option<u8>,
|
||||
do_water: bool,
|
||||
@ -142,14 +143,14 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
esp_idf_svc::log::EspLogger::initialize_default();
|
||||
|
||||
if esp_idf_sys::CONFIG_MAIN_TASK_STACK_SIZE < 25000 {
|
||||
error!(
|
||||
bail!(
|
||||
"stack too small: {} bail!",
|
||||
esp_idf_sys::CONFIG_MAIN_TASK_STACK_SIZE
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
log::info!("Startup Rust");
|
||||
println!("Startup Rust");
|
||||
|
||||
let mut to_config = false;
|
||||
|
||||
@ -186,6 +187,7 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
};
|
||||
println!("{}", ota_state_string);
|
||||
|
||||
|
||||
println!("Board hal init");
|
||||
let mut board: std::sync::MutexGuard<'_, PlantCtrlBoard<'_>> = BOARD_ACCESS.lock().unwrap();
|
||||
board.general_fault(false);
|
||||
@ -207,7 +209,7 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
match time {
|
||||
Ok(cur) => cur,
|
||||
Err(err) => {
|
||||
log::error!("time error {}", err);
|
||||
bail!("time error {}", err);
|
||||
DateTime::from_timestamp_millis(0).unwrap()
|
||||
}
|
||||
}
|
||||
@ -284,7 +286,7 @@ fn safe_main() -> anyhow::Result<()> {
|
||||
ip_address = Some(ip_info.ip.to_string());
|
||||
wifi = true;
|
||||
|
||||
match board.sntp(1000 * 5) {
|
||||
match board.sntp(1000 * 10) {
|
||||
Ok(new_time) => {
|
||||
println!("Using time from sntp");
|
||||
let _ = board.set_rtc_time(&new_time);
|
||||
|
@ -2,6 +2,7 @@ use bq34z100::{Bq34Z100Error, Bq34z100g1, Bq34z100g1Driver};
|
||||
|
||||
use chrono_tz::Tz;
|
||||
use ds323x::{DateTimeAccess, Ds323x};
|
||||
use crate::log::{init, LogMessage};
|
||||
|
||||
use eeprom24x::{Eeprom24x, Eeprom24xTrait, SlaveAddr};
|
||||
use embedded_hal_bus::i2c::MutexDevice;
|
||||
@ -22,6 +23,7 @@ use esp_idf_svc::mqtt::client::{EspMqttClient, LwtConfiguration, MqttClientConfi
|
||||
use esp_idf_svc::nvs::EspDefaultNvsPartition;
|
||||
use esp_idf_svc::wifi::config::{ScanConfig, ScanType};
|
||||
use esp_idf_svc::wifi::EspWifi;
|
||||
use log::logger;
|
||||
use measurements::Temperature;
|
||||
use once_cell::sync::Lazy;
|
||||
use plant_ctrl2::sipo::ShiftRegister40;
|
||||
@ -46,7 +48,7 @@ use std::time::Duration;
|
||||
|
||||
use embedded_hal::digital::OutputPin;
|
||||
use esp_idf_hal::delay::Delay;
|
||||
use esp_idf_hal::gpio::{AnyInputPin, Gpio18, Gpio5, Gpio7, Gpio8, IOPin, InputOutput, Level, PinDriver, Pull};
|
||||
use esp_idf_hal::gpio::{AnyInputPin, Gpio18, Gpio5, IOPin, InputOutput, Level, PinDriver, Pull};
|
||||
use esp_idf_hal::pcnt::{
|
||||
PcntChannel, PcntChannelConfig, PcntControlMode, PcntCountMode, PcntDriver, PinIndex,
|
||||
};
|
||||
@ -54,11 +56,12 @@ use esp_idf_hal::prelude::Peripherals;
|
||||
use esp_idf_hal::reset::ResetReason;
|
||||
use esp_idf_svc::sntp::{self, SyncStatus};
|
||||
use esp_idf_svc::systime::EspSystemTime;
|
||||
use esp_idf_sys::{esp, esp_spiffs_check, gpio_hold_dis, gpio_hold_en, vTaskDelay, EspError};
|
||||
use esp_idf_sys::{gpio_hold_dis, gpio_hold_en, vTaskDelay, EspError};
|
||||
use one_wire_bus::OneWire;
|
||||
|
||||
use crate::config::{self, PlantControllerConfig};
|
||||
use crate::espota::mark_app_valid;
|
||||
use crate::log::log;
|
||||
use crate::{plant_hal, to_string, STAY_ALIVE};
|
||||
|
||||
//Only support for 8 right now!
|
||||
@ -80,14 +83,15 @@ const PUMP5_BIT: usize = 5;
|
||||
const PUMP6_BIT: usize = 6;
|
||||
const PUMP7_BIT: usize = 7;
|
||||
|
||||
|
||||
const MS_0: usize = 8;
|
||||
const MS_4: usize = 9;
|
||||
const MS_2: usize = 10;
|
||||
const MS_3: usize = 11;
|
||||
const SENSOR_ON: usize = 12;
|
||||
const MS_1: usize = 13;
|
||||
//unused 14
|
||||
//unused 15
|
||||
const CHARGING: usize = 14;
|
||||
const AWAKE: usize = 15;
|
||||
|
||||
const FAULT_3: usize = 16;
|
||||
const FAULT_8: usize = 17;
|
||||
@ -128,10 +132,6 @@ static mut LOW_VOLTAGE_DETECTED: bool = false;
|
||||
#[link_section = ".rtc.data"]
|
||||
static mut RESTART_TO_CONF: bool = false;
|
||||
|
||||
const BUFFER_SIZE:usize = 120;
|
||||
const ENTRY_SIZE:usize = 120;
|
||||
#[link_section = ".rtc.data"]
|
||||
static mut BUFFER:ConstGenericRingBuffer::<heapless::String<ENTRY_SIZE>, BUFFER_SIZE> = ConstGenericRingBuffer::<heapless::String<ENTRY_SIZE>, BUFFER_SIZE>::new();
|
||||
|
||||
|
||||
pub struct FileSystemSizeInfo {
|
||||
@ -266,9 +266,7 @@ impl PlantCtrlBoard<'_> {
|
||||
OkStd(_) => {},
|
||||
Err(err) => bail!("Error reading eeprom header {:?}", err),
|
||||
};
|
||||
println!("Raw header is {:?} with size {}", header_page_buffer , store);
|
||||
let header:BackupHeader = bincode::deserialize(&header_page_buffer)?;
|
||||
println!("Reading eeprom header {header:?}");
|
||||
|
||||
let data_start_address = 1*self.eeprom.page_size() as u32;
|
||||
let mut data_buffer = vec![0_u8; header.size];
|
||||
@ -282,19 +280,6 @@ impl PlantCtrlBoard<'_> {
|
||||
bail!("Invalid checksum, got {} but expected {}", checksum, header.crc16 );
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let value = heapless::String::try_from("dummy").unwrap();
|
||||
BUFFER.push(value);
|
||||
}
|
||||
unsafe {
|
||||
for entry in BUFFER.iter() {
|
||||
let test = entry.as_bytes().to_owned();
|
||||
for p in test {
|
||||
data_buffer.push(p);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Ok(data_buffer)
|
||||
}
|
||||
|
||||
@ -318,8 +303,6 @@ impl PlantCtrlBoard<'_> {
|
||||
}
|
||||
let as_u8:&[u8] = &encoded;
|
||||
|
||||
println!("Raw header is {:?} with size {}", as_u8 , as_u8.len());
|
||||
|
||||
match self.eeprom.write_page(0, as_u8) {
|
||||
OkStd(_) => {},
|
||||
Err(err) => bail!("Error writing eeprom {:?}", err),
|
||||
@ -375,13 +358,11 @@ impl PlantCtrlBoard<'_> {
|
||||
let mut iter_error = None;
|
||||
let mut result = Vec::new();
|
||||
|
||||
println!("Filename {filename}");
|
||||
let filepath = Path::new(BASE_PATH);
|
||||
let read_dir = fs::read_dir(filepath);
|
||||
match read_dir {
|
||||
OkStd(read_dir) => {
|
||||
for item in read_dir {
|
||||
println!("start loop");
|
||||
match item {
|
||||
OkStd(file) => {
|
||||
let f = FileInfo {
|
||||
@ -392,7 +373,6 @@ impl PlantCtrlBoard<'_> {
|
||||
.unwrap_or_default()
|
||||
as usize,
|
||||
};
|
||||
println!("fileinfo {f:?}");
|
||||
result.push(f);
|
||||
}
|
||||
Err(err) => {
|
||||
@ -503,8 +483,8 @@ impl PlantCtrlBoard<'_> {
|
||||
let r2 = median * 50.0 / (3.3 - median);
|
||||
let mut percent = r2 / 190_f32 * 100_f32;
|
||||
percent = percent.clamp(0.0, 100.0);
|
||||
log(LogMessage::sensor_tank_raw, median as u32, percent as u32, "","");
|
||||
|
||||
println!("Tank sensor raw {} percent {}", median, percent);
|
||||
return Ok(percent as u16);
|
||||
}
|
||||
|
||||
@ -620,7 +600,7 @@ impl PlantCtrlBoard<'_> {
|
||||
self.time()
|
||||
}
|
||||
|
||||
pub fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> Result<i32> {
|
||||
pub fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> Result<u32> {
|
||||
let sensor_channel = match sensor {
|
||||
Sensor::A => match plant {
|
||||
0 => SENSOR_A_1,
|
||||
@ -646,7 +626,7 @@ impl PlantCtrlBoard<'_> {
|
||||
},
|
||||
};
|
||||
|
||||
let mut results = [0; REPEAT_MOIST_MEASURE];
|
||||
let mut results = [0_u32; REPEAT_MOIST_MEASURE];
|
||||
for repeat in 0..REPEAT_MOIST_MEASURE {
|
||||
self.signal_counter.counter_pause()?;
|
||||
self.signal_counter.counter_clear()?;
|
||||
@ -675,13 +655,9 @@ impl PlantCtrlBoard<'_> {
|
||||
.unwrap();
|
||||
delay.delay_ms(10);
|
||||
let unscaled = self.signal_counter.get_counter_value()? as i32;
|
||||
let hz = (unscaled as f32 * factor) as i32;
|
||||
println!(
|
||||
"raw measure unscaled {} hz {}, plant {} sensor {:?}",
|
||||
unscaled, hz, plant, sensor
|
||||
);
|
||||
let hz = (unscaled as f32 * factor) as u32;
|
||||
log(LogMessage::raw_measure, unscaled as u32, hz as u32, &plant.to_string(), &format!("{sensor:?}"));
|
||||
results[repeat] = hz;
|
||||
//println!("Measuring {:?} @ {} with {}", sensor, plant, hz);
|
||||
}
|
||||
results.sort();
|
||||
|
||||
@ -745,7 +721,6 @@ impl PlantCtrlBoard<'_> {
|
||||
let delay = Delay::new_default();
|
||||
let mut counter = 0_u32;
|
||||
while !self.wifi_driver.is_connected()? {
|
||||
println!("Waiting for station connection");
|
||||
delay.delay_ms(250);
|
||||
counter += 250;
|
||||
if counter > max_wait {
|
||||
@ -758,7 +733,6 @@ impl PlantCtrlBoard<'_> {
|
||||
println!("Should be connected now");
|
||||
|
||||
while !self.wifi_driver.is_up()? {
|
||||
println!("Waiting for network being up");
|
||||
delay.delay_ms(250);
|
||||
counter += 250;
|
||||
if counter > max_wait {
|
||||
@ -770,7 +744,7 @@ impl PlantCtrlBoard<'_> {
|
||||
}
|
||||
//update freertos registers ;)
|
||||
let address = self.wifi_driver.sta_netif().get_ip_info()?;
|
||||
println!("IP info: {:?}", address);
|
||||
log(LogMessage::wifi_info, 0 ,0,"", &format!("{address:?}"));
|
||||
Ok(address)
|
||||
}
|
||||
|
||||
@ -908,9 +882,16 @@ impl PlantCtrlBoard<'_> {
|
||||
for plant in 0..PLANT_COUNT {
|
||||
let a = self.measure_moisture_hz(plant, plant_hal::Sensor::A);
|
||||
let b = self.measure_moisture_hz(plant, plant_hal::Sensor::B);
|
||||
print!("P:{} a:{:?} b:{:?}", plant, a, b)
|
||||
let aa = match a {
|
||||
OkStd(a) => a as u32,
|
||||
Err(_) => u32::MAX
|
||||
};
|
||||
let bb = match b {
|
||||
OkStd(b) => b as u32,
|
||||
Err(_) => u32::MAX
|
||||
};
|
||||
log(LogMessage::test_sensor, aa ,bb,&plant.to_string(), "");
|
||||
}
|
||||
println!();
|
||||
Delay::new_default().delay_ms(10);
|
||||
Ok(())
|
||||
}
|
||||
@ -958,18 +939,15 @@ impl PlantCtrlBoard<'_> {
|
||||
let round_trip_ok = Arc::new(AtomicBool::new(false));
|
||||
let round_trip_topic = format!("{}/internal/roundtrip", base_topic);
|
||||
let stay_alive_topic = format!("{}/stay_alive", base_topic);
|
||||
println!("Stay alive topic is {}", stay_alive_topic);
|
||||
log(LogMessage::stay_alive, 0 ,0,"", &stay_alive_topic);
|
||||
|
||||
let mqtt_connected_event_received_copy = mqtt_connected_event_received.clone();
|
||||
let mqtt_connected_event_ok_copy = mqtt_connected_event_ok.clone();
|
||||
let stay_alive_topic_copy = stay_alive_topic.clone();
|
||||
let round_trip_topic_copy = round_trip_topic.clone();
|
||||
let round_trip_ok_copy = round_trip_ok.clone();
|
||||
println!(
|
||||
"Connecting mqtt {} with id {}",
|
||||
mqtt_url,
|
||||
mqtt_client_config.client_id.unwrap_or("not set")
|
||||
);
|
||||
let client_id = mqtt_client_config.client_id.unwrap_or("not set");
|
||||
log(LogMessage::mqtt_info, 0 ,0,client_id, &mqtt_url);
|
||||
let mut client = EspMqttClient::new_cb(&mqtt_url, &mqtt_client_config, move |event| {
|
||||
let payload = event.payload();
|
||||
match payload {
|
||||
@ -987,10 +965,10 @@ impl PlantCtrlBoard<'_> {
|
||||
} else if topic.eq(stay_alive_topic_copy.as_str()) {
|
||||
let value =
|
||||
data.eq_ignore_ascii_case("true") || data.eq_ignore_ascii_case("1");
|
||||
println!("Received stay alive with value {}", value);
|
||||
log(LogMessage::mqtt_stay_alive_rec, 0 ,0,&data, "");
|
||||
STAY_ALIVE.store(value, std::sync::atomic::Ordering::Relaxed);
|
||||
} else {
|
||||
println!("Unknown topic recieved {}", topic);
|
||||
log(LogMessage::unknown_topic, 0 ,0,"", &topic);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1327,6 +1305,38 @@ impl PlantHal {
|
||||
pub fn create() -> Result<Mutex<PlantCtrlBoard<'static>>> {
|
||||
let peripherals = Peripherals::take()?;
|
||||
|
||||
let mut clock = PinDriver::input_output(peripherals.pins.gpio15.downgrade())?;
|
||||
clock.set_pull(Pull::Floating).unwrap();
|
||||
let mut latch = PinDriver::input_output(peripherals.pins.gpio3.downgrade())?;
|
||||
latch.set_pull(Pull::Floating).unwrap();
|
||||
let mut data = PinDriver::input_output(peripherals.pins.gpio23.downgrade())?;
|
||||
data.set_pull(Pull::Floating).unwrap();
|
||||
let shift_register = ShiftRegister40::new(clock.into(), latch.into(), data.into());
|
||||
//disable all
|
||||
for mut pin in shift_register.decompose() {
|
||||
pin.set_low().unwrap();
|
||||
}
|
||||
|
||||
let awake = &mut shift_register.decompose()[AWAKE];
|
||||
awake.set_high()?;
|
||||
|
||||
|
||||
let charging = &mut shift_register.decompose()[CHARGING];
|
||||
charging.set_high()?;
|
||||
|
||||
let ms0 = &mut shift_register.decompose()[MS_0];
|
||||
ms0.set_low()?;
|
||||
let ms1 = &mut shift_register.decompose()[MS_1];
|
||||
ms1.set_low()?;
|
||||
let ms2 = &mut shift_register.decompose()[MS_2];
|
||||
ms2.set_low()?;
|
||||
let ms3 = &mut shift_register.decompose()[MS_3];
|
||||
ms3.set_low()?;
|
||||
|
||||
let ms4 = &mut shift_register.decompose()[MS_4];
|
||||
ms4.set_high()?;
|
||||
|
||||
|
||||
println!("Init battery driver");
|
||||
let mut battery_driver = Bq34z100g1Driver {
|
||||
i2c: MutexDevice::new(&I2C_DRIVER),
|
||||
@ -1345,6 +1355,10 @@ impl PlantHal {
|
||||
)
|
||||
};
|
||||
|
||||
let mut one_wire_pin = PinDriver::input_output_od(peripherals.pins.gpio18)?;
|
||||
one_wire_pin.set_pull(Pull::Floating).unwrap();
|
||||
|
||||
|
||||
let rtc_time = rtc.datetime();
|
||||
match rtc_time {
|
||||
OkStd(tt) => {
|
||||
@ -1363,33 +1377,6 @@ impl PlantHal {
|
||||
}
|
||||
}
|
||||
|
||||
let mut clock = PinDriver::input_output(peripherals.pins.gpio15.downgrade())?;
|
||||
clock.set_pull(Pull::Floating).unwrap();
|
||||
let mut latch = PinDriver::input_output(peripherals.pins.gpio3.downgrade())?;
|
||||
latch.set_pull(Pull::Floating).unwrap();
|
||||
let mut data = PinDriver::input_output(peripherals.pins.gpio23.downgrade())?;
|
||||
data.set_pull(Pull::Floating).unwrap();
|
||||
let shift_register = ShiftRegister40::new(clock.into(), latch.into(), data.into());
|
||||
for mut pin in shift_register.decompose() {
|
||||
pin.set_low().unwrap();
|
||||
}
|
||||
|
||||
let mut one_wire_pin = PinDriver::input_output_od(peripherals.pins.gpio18)?;
|
||||
one_wire_pin.set_pull(Pull::Floating).unwrap();
|
||||
|
||||
//disable all
|
||||
let ms0 = &mut shift_register.decompose()[MS_0];
|
||||
ms0.set_low()?;
|
||||
let ms1 = &mut shift_register.decompose()[MS_1];
|
||||
ms1.set_low()?;
|
||||
let ms2 = &mut shift_register.decompose()[MS_2];
|
||||
ms2.set_low()?;
|
||||
let ms3 = &mut shift_register.decompose()[MS_3];
|
||||
ms3.set_low()?;
|
||||
|
||||
let ms4 = &mut shift_register.decompose()[MS_4];
|
||||
ms4.set_high()?;
|
||||
|
||||
//init,reset rtc memory depending on cause
|
||||
let mut init_rtc_store: bool = false;
|
||||
let mut to_config_mode: bool = false;
|
||||
@ -1430,13 +1417,13 @@ impl PlantHal {
|
||||
init_rtc_store = true
|
||||
},
|
||||
};
|
||||
println!("Reset due to {:?} requires rtc clear {} and force config mode {}", reasons, init_rtc_store, to_config_mode);
|
||||
log(LogMessage::reset_reason, init_rtc_store as u32, to_config_mode as u32, "",&format!("{reasons:?}"));
|
||||
if init_rtc_store {
|
||||
unsafe {
|
||||
LAST_WATERING_TIMESTAMP = [0; PLANT_COUNT];
|
||||
CONSECUTIVE_WATERING_PLANT = [0; PLANT_COUNT];
|
||||
LOW_VOLTAGE_DETECTED = false;
|
||||
BUFFER = ConstGenericRingBuffer::<heapless::String<ENTRY_SIZE>, BUFFER_SIZE>::new();
|
||||
crate::log::init();
|
||||
RESTART_TO_CONF = to_config_mode;
|
||||
};
|
||||
} else {
|
||||
@ -1444,12 +1431,8 @@ impl PlantHal {
|
||||
if to_config_mode{
|
||||
RESTART_TO_CONF = true;
|
||||
}
|
||||
println!("Current restart to conf mode{:?}", RESTART_TO_CONF);
|
||||
|
||||
println!(
|
||||
"Current low voltage detection is {:?}",
|
||||
LOW_VOLTAGE_DETECTED
|
||||
);
|
||||
log(LogMessage::restart_to_config, RESTART_TO_CONF as u32, 0, "","");
|
||||
log(LogMessage::low_voltage, LOW_VOLTAGE_DETECTED as u32, 0, "","");
|
||||
for i in 0..PLANT_COUNT {
|
||||
println!(
|
||||
"LAST_WATERING_TIMESTAMP[{}] = UTC {}",
|
||||
@ -1473,8 +1456,6 @@ impl PlantHal {
|
||||
Option::<AnyInputPin>::None,
|
||||
)?;
|
||||
|
||||
println!("Channel config start");
|
||||
|
||||
counter_unit1.channel_config(
|
||||
PcntChannel::Channel0,
|
||||
PinIndex::Pin0,
|
||||
@ -1489,8 +1470,6 @@ impl PlantHal {
|
||||
},
|
||||
)?;
|
||||
|
||||
println!("Wifi start");
|
||||
|
||||
let sys_loop = EspSystemEventLoop::take()?;
|
||||
let nvs = EspDefaultNvsPartition::take()?;
|
||||
let wifi_driver = EspWifi::new(peripherals.modem, sys_loop, Some(nvs))?;
|
||||
@ -1525,15 +1504,15 @@ impl PlantHal {
|
||||
let one_wire_bus = OneWire::new(one_wire_pin)
|
||||
.map_err(|err| -> anyhow::Error { anyhow!("Missing attribute: {:?}", err) })?;
|
||||
|
||||
println!("After stuff");
|
||||
|
||||
let status = print_battery(&mut battery_driver);
|
||||
if status.is_err() {
|
||||
println!("Error communicating with battery!! {:?}", status.err());
|
||||
} else {
|
||||
println!("Managed to comunnicate with battery");
|
||||
}
|
||||
match status {
|
||||
OkStd(_) => {
|
||||
|
||||
},
|
||||
Err(err) => {
|
||||
log(LogMessage::battery_communication_error, 0 as u32, 0, "",&format!("{err:?})"));
|
||||
},
|
||||
}
|
||||
let shift_register_enable_invert = PinDriver::output(peripherals.pins.gpio21.downgrade())?;
|
||||
|
||||
let rv = Mutex::new(PlantCtrlBoard {
|
||||
|
@ -9,6 +9,7 @@ use crate::{
|
||||
};
|
||||
use anyhow::bail;
|
||||
use chrono::DateTime;
|
||||
use esp_idf_sys::{esp_set_time_from_rtc, settimeofday, timeval, vTaskDelay};
|
||||
use core::result::Result::Ok;
|
||||
use embedded_svc::http::Method;
|
||||
use esp_idf_hal::delay::Delay;
|
||||
@ -24,11 +25,6 @@ struct SSIDList<'a> {
|
||||
ssids: Vec<&'a String<32>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
struct FileList {
|
||||
file: Vec<FileInfo>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
struct LoadData<'a> {
|
||||
rtc: &'a str,
|
||||
@ -64,6 +60,12 @@ fn write_time(
|
||||
let time: SetTime = serde_json::from_slice(&actual_data)?;
|
||||
let parsed = DateTime::parse_from_rfc3339(time.time).map_err(|err| anyhow::anyhow!(err))?;
|
||||
let mut board = BOARD_ACCESS.lock().unwrap();
|
||||
|
||||
let now = timeval {
|
||||
tv_sec: parsed.to_utc().timestamp(),
|
||||
tv_usec: 0
|
||||
};
|
||||
unsafe { settimeofday(&now, core::ptr::null_mut()) };
|
||||
board.set_rtc_time(&parsed.to_utc())?;
|
||||
anyhow::Ok(None)
|
||||
}
|
||||
@ -440,6 +442,8 @@ pub fn httpd(reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
unsafe { vTaskDelay(1) };
|
||||
|
||||
let reboot_now_for_exit = reboot_now.clone();
|
||||
server
|
||||
.fn_handler("/exit", Method::Post, move |_| {
|
||||
@ -462,19 +466,16 @@ pub fn httpd(reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
|
||||
let mut buffer: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
|
||||
let mut total_read: usize = 0;
|
||||
loop {
|
||||
unsafe { vTaskDelay(1) };
|
||||
let read = std::io::Read::read(&mut file_handle, &mut buffer)?;
|
||||
total_read += read;
|
||||
println!(
|
||||
"sending {read} bytes of {total_read} for file {}",
|
||||
&filename
|
||||
);
|
||||
let to_write = &buffer[0..read];
|
||||
response.write(to_write)?;
|
||||
println!("wrote {read} bytes of {total_read} for file {filename}");
|
||||
if read == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
println!("wrote {total_read} for file {filename}");
|
||||
drop(file_handle);
|
||||
response.flush()?;
|
||||
}
|
||||
@ -588,6 +589,7 @@ pub fn httpd(reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
unsafe { vTaskDelay(1) };
|
||||
server
|
||||
.fn_handler("/", Method::Get, move |request| {
|
||||
let mut response = request.into_ok_response()?;
|
||||
|
74
website/.github/workflows/pages.yml
vendored
Normal file
74
website/.github/workflows/pages.yml
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
# Sample workflow for building and deploying a Hugo site to GitHub Pages
|
||||
name: Blowfish Docs Deploy
|
||||
|
||||
on:
|
||||
# Runs on pushes targeting the default branch
|
||||
push:
|
||||
branches: ["main"]
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
# Allow one concurrent deployment
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: true
|
||||
|
||||
# Default to bash
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
# Build job
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Hugo setup
|
||||
uses: peaceiris/actions-hugo@v2.6.0
|
||||
with:
|
||||
hugo-version: 0.140.2
|
||||
extended: true
|
||||
env:
|
||||
ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true'
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true # Fetch Hugo themes (true OR recursive)
|
||||
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
|
||||
|
||||
- name: Setup Pages
|
||||
id: pages
|
||||
uses: actions/configure-pages@v2
|
||||
|
||||
- name: Build with Hugo
|
||||
env:
|
||||
# For maximum backward compatibility with Hugo modules
|
||||
HUGO_ENVIRONMENT: production
|
||||
HUGO_ENV: production
|
||||
run: |
|
||||
hugo --minify -d ./public --baseURL https://nunocoracao.github.io/blowfish_template/
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v1
|
||||
with:
|
||||
path: ./public
|
||||
|
||||
# Deployment job
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: https://nunocoracao.github.io/blowfish_template/
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v1
|
4
website/.gitmodules
vendored
Normal file
4
website/.gitmodules
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
[submodule "themes/blowfish"]
|
||||
path = themes/blowfish
|
||||
url = https://github.com/nunocoracao/blowfish.git
|
||||
branch = main
|
21
website/LICENSE
Normal file
21
website/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Nuno Coração
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
6
website/README.md
Normal file
6
website/README.md
Normal file
@ -0,0 +1,6 @@
|
||||
# Blowfish Template
|
||||
This is a template for the Blowfish Hugo Theme. Feel free to use this repo as a quick way to get started with Blowfish. Please visit [Blowfish's main website](https://github.com/nunocoracao/blowfish) to read the complete documentation.
|
||||
|
||||
The template was built using the [Git option](https://nunocoracao.github.io/blowfish/docs/installation/#install-using-git) from Blowfish's installations instructions.
|
||||
|
||||

|
BIN
website/logo.png
Normal file
BIN
website/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 98 KiB |
20
website/package.json
Normal file
20
website/package.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "blowfish_template",
|
||||
"version": "1.0.0",
|
||||
"description": "Blowfish Template",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"dev": "hugo server --minify -D -E -F"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/nunocoracao/blowfish_template.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nunocoracao/blowfish_template/issues"
|
||||
},
|
||||
"homepage": "https://github.com/nunocoracao/blowfish_template#readme"
|
||||
}
|
5
website/update.sh
Normal file
5
website/update.sh
Normal file
@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
git submodule update --remote --merge
|
||||
git add *
|
||||
git commit -m "updated theme"
|
||||
git push
|
Loading…
x
Reference in New Issue
Block a user