logging and pcb adjustment

This commit is contained in:
Empire 2025-02-14 23:50:19 +01:00
parent 1741bb0b53
commit aad1dbd458
15 changed files with 389 additions and 119 deletions

View File

@ -1,6 +1,6 @@
{
"board": {
"active_layer": 37,
"active_layer": 31,
"active_layer_preset": "",
"auto_track_width": false,
"hidden_netclasses": [],

View File

@ -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

View File

@ -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
View 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,
}

View File

@ -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);

View File

@ -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)
}
@ -317,9 +302,7 @@ impl PlantCtrlBoard<'_> {
bail!("Size limit reached header is {}, but firest page is only {}",encoded.len(), page_size)
}
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 {

View File

@ -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
View 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
View 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
View 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
View 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.
![blowfish logo](https://github.com/nunocoracao/blowfish_template/blob/main/logo.png?raw=true)

BIN
website/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

20
website/package.json Normal file
View 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
View File

@ -0,0 +1,5 @@
#!/bin/bash
git submodule update --remote --merge
git add *
git commit -m "updated theme"
git push