fix rtc storage
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
use bq34z100::{Bq34Z100Error, Bq34z100g1, Bq34z100g1Driver};
|
||||
//mod config;
|
||||
use chrono_tz::Europe::Berlin;
|
||||
use embedded_svc::wifi::{
|
||||
AccessPointConfiguration, AccessPointInfo, AuthMethod, ClientConfiguration, Configuration,
|
||||
};
|
||||
|
||||
use esp_idf_hal::i2c::{I2cConfig, I2cDriver, I2cError};
|
||||
use esp_idf_hal::units::FromValueType;
|
||||
use esp_idf_svc::eventloop::EspSystemEventLoop;
|
||||
use esp_idf_svc::mqtt::client::QoS::AtLeastOnce;
|
||||
use esp_idf_svc::mqtt::client::QoS::ExactlyOnce;
|
||||
use esp_idf_svc::mqtt::client::{EspMqttClient, MqttClientConfiguration};
|
||||
use esp_idf_svc::mqtt::client::{EspMqttClient, LwtConfiguration, MqttClientConfiguration};
|
||||
use esp_idf_svc::nvs::EspDefaultNvsPartition;
|
||||
use esp_idf_svc::wifi::config::{ScanConfig, ScanType};
|
||||
use esp_idf_svc::wifi::EspWifi;
|
||||
@@ -16,19 +18,19 @@ use plant_ctrl2::sipo::ShiftRegister40;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use anyhow::{bail, Ok, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ffi::CString;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
|
||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
use ds18b20::Ds18b20;
|
||||
use std::result::Result::Ok as OkStd;
|
||||
use std::str::FromStr;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
|
||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
use ds18b20::Ds18b20;
|
||||
|
||||
use embedded_hal::digital::v2::OutputPin;
|
||||
use embedded_hal::digital::OutputPin;
|
||||
use esp_idf_hal::adc::{attenuation, AdcChannelDriver, AdcDriver};
|
||||
use esp_idf_hal::delay::Delay;
|
||||
use esp_idf_hal::gpio::{AnyInputPin, Gpio39, Gpio4, InputOutput, Level, PinDriver, Pull};
|
||||
@@ -39,10 +41,9 @@ 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::{gpio_hold_dis, gpio_hold_en, vTaskDelay, EspError};
|
||||
use esp_idf_sys::{esp, gpio_hold_dis, gpio_hold_en, vTaskDelay, EspError};
|
||||
use one_wire_bus::OneWire;
|
||||
|
||||
use crate::bq34z100::{Bq34Z100Error, Bq34z100g1, Bq34z100g1Driver};
|
||||
use crate::config::{self, Config, WifiConfig};
|
||||
use crate::STAY_ALIVE;
|
||||
|
||||
@@ -51,8 +52,8 @@ const PINS_PER_PLANT: usize = 5;
|
||||
const PLANT_PUMP_OFFSET: usize = 0;
|
||||
const PLANT_FAULT_OFFSET: usize = 1;
|
||||
const PLANT_MOIST_PUMP_OFFSET: usize = 2;
|
||||
const PLANT_MOIST_B_OFFSET: usize = 3;
|
||||
const PLANT_MOIST_A_OFFSET: usize = 4;
|
||||
const PLANT_MOIST_A_OFFSET: usize = 3;
|
||||
const PLANT_MOIST_B_OFFSET: usize = 4;
|
||||
|
||||
const SPIFFS_PARTITION_NAME: &str = "storage";
|
||||
const WIFI_CONFIG_FILE: &str = "/spiffs/wifi.cfg";
|
||||
@@ -67,43 +68,6 @@ static mut CONSECUTIVE_WATERING_PLANT: [u32; PLANT_COUNT] = [0; PLANT_COUNT];
|
||||
#[link_section = ".rtc.data"]
|
||||
static mut LOW_VOLTAGE_DETECTED: bool = false;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct BatteryState {
|
||||
pub 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,
|
||||
}
|
||||
|
||||
impl Default for BatteryState {
|
||||
fn default() -> Self {
|
||||
BatteryState {
|
||||
state_charge_percent: 50,
|
||||
max_error_percent: 100,
|
||||
remaining_milli_ampere_hour: 100,
|
||||
max_milli_ampere_hour: 200,
|
||||
design_milli_ampere_hour: 200,
|
||||
voltage_milli_volt: 12,
|
||||
average_current_milli_ampere: 50,
|
||||
temperature_tenth_kelvin: 1337,
|
||||
average_time_to_empty_minute: 123,
|
||||
average_time_to_full_minute: 123,
|
||||
average_discharge_power_cycle_milli_watt: 123,
|
||||
cycle_count: 123,
|
||||
state_health_percent: 90,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FileSystemSizeInfo {
|
||||
pub total_size: usize,
|
||||
pub used_size: usize,
|
||||
@@ -125,12 +89,24 @@ pub enum Sensor {
|
||||
}
|
||||
pub trait PlantCtrlBoardInteraction {
|
||||
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: heapless::String<32>,
|
||||
password: Option<heapless::String<64>>,
|
||||
max_wait: u32,
|
||||
) -> Result<()>;
|
||||
fn sntp(&mut self, max_wait: u32) -> Result<chrono::DateTime<Utc>>;
|
||||
fn mount_file_system(&mut self) -> Result<()>;
|
||||
fn file_system_size(&mut self) -> Result<FileSystemSizeInfo>;
|
||||
|
||||
fn battery_state(&mut self) -> Result<BatteryState>;
|
||||
fn state_charge_percent(&mut self) -> Result<u8>;
|
||||
fn remaining_milli_ampere_hour(&mut self) -> Result<u16>;
|
||||
fn max_milli_ampere_hour(&mut self) -> Result<u16>;
|
||||
fn design_milli_ampere_hour(&mut self) -> Result<u16>;
|
||||
fn voltage_milli_volt(&mut self) -> Result<u16>;
|
||||
fn average_current_milli_ampere(&mut self) -> Result<i16>;
|
||||
fn cycle_count(&mut self) -> Result<u16>;
|
||||
fn state_health_percent(&mut self) -> Result<u8>;
|
||||
|
||||
fn general_fault(&mut self, enable: bool);
|
||||
|
||||
@@ -168,6 +144,7 @@ pub trait PlantCtrlBoardInteraction {
|
||||
fn test(&mut self) -> Result<()>;
|
||||
fn is_wifi_config_file_existant(&mut self) -> bool;
|
||||
fn mqtt(&mut self, config: &Config) -> Result<()>;
|
||||
fn mqtt_publish(&mut self, config: &Config, subtopic: &str, message: &[u8]) -> Result<()>;
|
||||
}
|
||||
|
||||
pub trait CreatePlantHal<'a> {
|
||||
@@ -182,8 +159,6 @@ pub struct PlantCtrlBoard<'a> {
|
||||
PinDriver<'a, esp_idf_hal::gpio::Gpio22, InputOutput>,
|
||||
PinDriver<'a, esp_idf_hal::gpio::Gpio19, InputOutput>,
|
||||
>,
|
||||
consecutive_watering_plant: Mutex<[u32; PLANT_COUNT]>,
|
||||
last_watering_timestamp: Mutex<[i64; PLANT_COUNT]>,
|
||||
low_voltage_detected: Mutex<bool>,
|
||||
tank_driver: AdcDriver<'a, esp_idf_hal::adc::ADC1>,
|
||||
tank_channel: esp_idf_hal::adc::AdcChannelDriver<'a, { attenuation::DB_11 }, Gpio39>,
|
||||
@@ -197,17 +172,10 @@ pub struct PlantCtrlBoard<'a> {
|
||||
pub wifi_driver: EspWifi<'a>,
|
||||
one_wire_bus: OneWire<PinDriver<'a, Gpio4, esp_idf_hal::gpio::InputOutput>>,
|
||||
mqtt_client: Option<EspMqttClient<'a>>,
|
||||
battery_driver: Bq34z100g1Driver<I2cDriver<'a>, Delay>,
|
||||
}
|
||||
|
||||
impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
|
||||
fn battery_state(&mut self) -> Result<BatteryState> {
|
||||
let state = BatteryState {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
fn is_day(&self) -> bool {
|
||||
self.solar_is_day.get_level().into()
|
||||
}
|
||||
@@ -281,11 +249,15 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
|
||||
}
|
||||
|
||||
fn set_low_voltage_in_cycle(&mut self) {
|
||||
*self.low_voltage_detected.get_mut().unwrap() = true;
|
||||
unsafe {
|
||||
LOW_VOLTAGE_DETECTED = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_low_voltage_in_cycle(&mut self) {
|
||||
*self.low_voltage_detected.get_mut().unwrap() = false;
|
||||
unsafe {
|
||||
LOW_VOLTAGE_DETECTED = false;
|
||||
}
|
||||
}
|
||||
|
||||
fn light(&mut self, enable: bool) -> Result<()> {
|
||||
@@ -311,15 +283,21 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
|
||||
}
|
||||
|
||||
fn store_last_pump_time(&mut self, plant: usize, time: chrono::DateTime<Utc>) {
|
||||
self.last_watering_timestamp.get_mut().unwrap()[plant] = time.timestamp_millis();
|
||||
unsafe {
|
||||
LAST_WATERING_TIMESTAMP[plant] = time.timestamp_millis();
|
||||
}
|
||||
}
|
||||
|
||||
fn store_consecutive_pump_count(&mut self, plant: usize, count: u32) {
|
||||
self.consecutive_watering_plant.get_mut().unwrap()[plant] = count;
|
||||
unsafe {
|
||||
CONSECUTIVE_WATERING_PLANT[plant] = count;
|
||||
}
|
||||
}
|
||||
|
||||
fn consecutive_pump_count(&mut self, plant: usize) -> u32 {
|
||||
return self.consecutive_watering_plant.get_mut().unwrap()[plant];
|
||||
unsafe {
|
||||
return CONSECUTIVE_WATERING_PLANT[plant];
|
||||
}
|
||||
}
|
||||
|
||||
fn fault(&self, plant: usize, enable: bool) {
|
||||
@@ -330,7 +308,9 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
|
||||
}
|
||||
|
||||
fn low_voltage_in_cycle(&mut self) -> bool {
|
||||
return *self.low_voltage_detected.get_mut().unwrap();
|
||||
unsafe {
|
||||
return LOW_VOLTAGE_DETECTED;
|
||||
}
|
||||
}
|
||||
|
||||
fn any_pump(&mut self, enable: bool) -> Result<()> {
|
||||
@@ -376,7 +356,7 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
|
||||
|
||||
let delay = Delay::new_default();
|
||||
let measurement = 100;
|
||||
let factor = 1000 / 100;
|
||||
let factor = 1000 as f32 / measurement as f32;
|
||||
|
||||
self.shift_register.decompose()[index].set_high().unwrap();
|
||||
//give some time to stabilize
|
||||
@@ -386,7 +366,7 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
|
||||
self.signal_counter.counter_pause()?;
|
||||
self.shift_register.decompose()[index].set_low().unwrap();
|
||||
let unscaled = self.signal_counter.get_counter_value()? as i32;
|
||||
let hz = unscaled * factor;
|
||||
let hz = (unscaled as f32 * factor) as i32;
|
||||
println!("Measuring {:?} @ {} with {}", sensor, plant, hz);
|
||||
Ok(hz)
|
||||
}
|
||||
@@ -397,7 +377,7 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
|
||||
|
||||
fn wifi_ap(&mut self) -> Result<()> {
|
||||
let apconfig = AccessPointConfiguration {
|
||||
ssid: "PlantCtrl".into(),
|
||||
ssid: heapless::String::from_str("PlantCtrl").unwrap(),
|
||||
auth_method: AuthMethod::None,
|
||||
ssid_hidden: false,
|
||||
..Default::default()
|
||||
@@ -409,14 +389,19 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn wifi(&mut self, ssid: &str, password: Option<&str>, max_wait: u32) -> Result<()> {
|
||||
fn wifi(
|
||||
&mut self,
|
||||
ssid: heapless::String<32>,
|
||||
password: Option<heapless::String<64>>,
|
||||
max_wait: u32,
|
||||
) -> Result<()> {
|
||||
match password {
|
||||
Some(pw) => {
|
||||
//TODO expect error due to invalid pw or similar! //call this during configuration and check if works, revert to config mode if not
|
||||
self.wifi_driver.set_configuration(&Configuration::Client(
|
||||
ClientConfiguration {
|
||||
ssid: ssid.into(),
|
||||
password: pw.into(),
|
||||
ssid: ssid,
|
||||
password: pw,
|
||||
..Default::default()
|
||||
},
|
||||
))?;
|
||||
@@ -424,7 +409,7 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
|
||||
None => {
|
||||
self.wifi_driver
|
||||
.set_configuration(&Configuration::Client(ClientConfiguration {
|
||||
ssid: ssid.into(),
|
||||
ssid: ssid,
|
||||
auth_method: AuthMethod::None,
|
||||
..Default::default()
|
||||
}))
|
||||
@@ -439,7 +424,6 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
|
||||
let mut counter = 0_u32;
|
||||
while !self.wifi_driver.is_connected()? {
|
||||
println!("Waiting for station connection");
|
||||
//TODO blink status?
|
||||
delay.delay_ms(250);
|
||||
counter += 250;
|
||||
if counter > max_wait {
|
||||
@@ -539,7 +523,11 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
|
||||
|
||||
fn get_config(&mut self) -> Result<config::Config> {
|
||||
let cfg = File::open(CONFIG_FILE)?;
|
||||
let config: Config = serde_json::from_reader(cfg)?;
|
||||
let mut config: Config = serde_json::from_reader(cfg)?;
|
||||
//remove duplicate end of topic
|
||||
if config.base_topic.ends_with("/") {
|
||||
config.base_topic.pop();
|
||||
}
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
@@ -627,8 +615,15 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
|
||||
}
|
||||
|
||||
fn mqtt(&mut self, config: &Config) -> Result<()> {
|
||||
//FIXME testament
|
||||
let last_will_topic = format!("{}/state", config.base_topic);
|
||||
|
||||
let mqtt_client_config = MqttClientConfiguration {
|
||||
lwt: Some(LwtConfiguration {
|
||||
topic: &last_will_topic,
|
||||
payload: "lost".as_bytes(),
|
||||
qos: AtLeastOnce,
|
||||
retain: true,
|
||||
}),
|
||||
//room for improvement
|
||||
..Default::default()
|
||||
};
|
||||
@@ -643,32 +638,32 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
|
||||
let round_trip_topic_copy = round_trip_topic.clone();
|
||||
let round_trip_ok_copy = round_trip_ok.clone();
|
||||
let mut client =
|
||||
EspMqttClient::new(&config.mqtt_url, &mqtt_client_config, move |handler| {
|
||||
match handler {
|
||||
Err(err) => println!("Ignoring damaged message {}", err),
|
||||
core::result::Result::Ok(event) => {
|
||||
match event {
|
||||
embedded_svc::mqtt::client::Event::Received(msg) => {
|
||||
let data = String::from_utf8_lossy(msg.data());
|
||||
if let Some(topic) = msg.topic() {
|
||||
//todo use enums
|
||||
if topic.eq(round_trip_topic_copy.as_str()) {
|
||||
round_trip_ok_copy
|
||||
.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
} 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);
|
||||
STAY_ALIVE
|
||||
.store(value, std::sync::atomic::Ordering::Relaxed);
|
||||
} else {
|
||||
println!("Unknown topic recieved {}", topic);
|
||||
}
|
||||
}
|
||||
EspMqttClient::new_cb(&config.mqtt_url, &mqtt_client_config, move |event| {
|
||||
let payload = event.payload();
|
||||
match payload {
|
||||
embedded_svc::mqtt::client::EventPayload::Received {
|
||||
id: _,
|
||||
topic,
|
||||
data,
|
||||
details: _,
|
||||
} => {
|
||||
let data = String::from_utf8_lossy(data);
|
||||
if let Some(topic) = topic {
|
||||
//todo use enums
|
||||
if topic.eq(round_trip_topic_copy.as_str()) {
|
||||
round_trip_ok_copy
|
||||
.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
} 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);
|
||||
STAY_ALIVE.store(value, std::sync::atomic::Ordering::Relaxed);
|
||||
} else {
|
||||
println!("Unknown topic recieved {}", topic);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
})?;
|
||||
//subscribe to roundtrip
|
||||
@@ -698,15 +693,111 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
|
||||
}
|
||||
bail!("Mqtt did not complete roundtrip in time");
|
||||
}
|
||||
|
||||
fn mqtt_publish(&mut self, config: &Config, subtopic: &str, message: &[u8]) -> Result<()> {
|
||||
if !subtopic.starts_with("/") {
|
||||
println!("Subtopic without / at start {}", subtopic);
|
||||
bail!("Subtopic without / at start {}", subtopic);
|
||||
}
|
||||
if subtopic.len() > 192 {
|
||||
println!("Subtopic exceeds 192 chars {}", subtopic);
|
||||
bail!("Subtopic exceeds 192 chars {}", subtopic);
|
||||
}
|
||||
if self.mqtt_client.is_none() {
|
||||
println!("Not connected to mqtt");
|
||||
bail!("Not connected to mqtt");
|
||||
}
|
||||
let client = self.mqtt_client.as_mut().unwrap();
|
||||
|
||||
let mut full_topic: heapless::String<256> = heapless::String::new();
|
||||
if full_topic.push_str(&config.base_topic).is_err() {
|
||||
println!("Some error assembling full_topic 1");
|
||||
bail!("Some error assembling full_topic 1")
|
||||
};
|
||||
if full_topic.push_str(subtopic).is_err() {
|
||||
println!("Some error assembling full_topic 2");
|
||||
bail!("Some error assembling full_topic 2")
|
||||
};
|
||||
client.publish(
|
||||
&full_topic,
|
||||
embedded_svc::mqtt::client::QoS::ExactlyOnce,
|
||||
true,
|
||||
message,
|
||||
)?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn state_charge_percent(&mut self) -> Result<u8> {
|
||||
match self.battery_driver.state_of_charge() {
|
||||
OkStd(r) => Ok(r),
|
||||
Err(err) => bail!("Error reading SoC {:?}", err),
|
||||
}
|
||||
}
|
||||
|
||||
fn remaining_milli_ampere_hour(&mut self) -> Result<u16> {
|
||||
match self.battery_driver.remaining_capacity() {
|
||||
OkStd(r) => Ok(r),
|
||||
Err(err) => bail!("Error reading Remaining Capacity {:?}", err),
|
||||
}
|
||||
}
|
||||
|
||||
fn max_milli_ampere_hour(&mut self) -> Result<u16> {
|
||||
match self.battery_driver.full_charge_capacity() {
|
||||
OkStd(r) => Ok(r),
|
||||
Err(err) => bail!("Error reading Full Charge Capacity {:?}", err),
|
||||
}
|
||||
}
|
||||
|
||||
fn design_milli_ampere_hour(&mut self) -> Result<u16> {
|
||||
match self.battery_driver.design_capacity() {
|
||||
OkStd(r) => Ok(r),
|
||||
Err(err) => bail!("Error reading Design Capacity {:?}", err),
|
||||
}
|
||||
}
|
||||
|
||||
fn voltage_milli_volt(&mut self) -> Result<u16> {
|
||||
return match self.battery_driver.voltage() {
|
||||
OkStd(r) => Ok(r),
|
||||
Err(err) => bail!("Error reading voltage {:?}", err),
|
||||
};
|
||||
}
|
||||
|
||||
fn average_current_milli_ampere(&mut self) -> Result<i16> {
|
||||
match self.battery_driver.average_current() {
|
||||
OkStd(r) => Ok(r),
|
||||
Err(err) => bail!("Error reading Average Current {:?}", err),
|
||||
}
|
||||
}
|
||||
|
||||
fn cycle_count(&mut self) -> Result<u16> {
|
||||
match self.battery_driver.cycle_count() {
|
||||
OkStd(r) => Ok(r),
|
||||
Err(err) => bail!("Error reading Cycle Count {:?}", err),
|
||||
}
|
||||
}
|
||||
|
||||
fn state_health_percent(&mut self) -> Result<u8> {
|
||||
match self.battery_driver.state_of_health() {
|
||||
OkStd(r) => Ok(r as u8),
|
||||
Err(err) => bail!("Error reading State of Health {:?}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_battery(
|
||||
battery_driver: &mut Bq34z100g1Driver<I2cDriver, Delay>,
|
||||
) -> Result<(), Bq34Z100Error<I2cError>> {
|
||||
let fwversion = battery_driver.fw_version()?;
|
||||
let fwversion = battery_driver.fw_version().unwrap_or_else(|e| {
|
||||
println!("Firmeware {:?}", e);
|
||||
0
|
||||
});
|
||||
println!("fw version is {}", fwversion);
|
||||
|
||||
let design_capacity = battery_driver.design_capacity()?;
|
||||
let design_capacity = battery_driver.design_capacity().unwrap_or_else(|e| {
|
||||
println!("Design capacity {:?}", e);
|
||||
0
|
||||
});
|
||||
println!("Design Capacity {}", design_capacity);
|
||||
if design_capacity == 1000 {
|
||||
println!("Still stock configuring battery, readouts are likely to be wrong!");
|
||||
@@ -715,15 +806,39 @@ fn print_battery(
|
||||
let flags = battery_driver.get_flags_decoded()?;
|
||||
println!("Flags {:?}", flags);
|
||||
|
||||
let chem_id = battery_driver.chem_id()?;
|
||||
let bat_temp = battery_driver.internal_temperature()?;
|
||||
let chem_id = battery_driver.chem_id().unwrap_or_else(|e| {
|
||||
println!("Chemid {:?}", e);
|
||||
0
|
||||
});
|
||||
|
||||
let bat_temp = battery_driver.internal_temperature().unwrap_or_else(|e| {
|
||||
println!("Bat Temp {:?}", e);
|
||||
0
|
||||
});
|
||||
let temp_c = Temperature::from_kelvin(bat_temp as f64 / 10_f64).as_celsius();
|
||||
let voltage = battery_driver.voltage()?;
|
||||
let current = battery_driver.current()?;
|
||||
let state = battery_driver.state_of_charge()?;
|
||||
let charge_voltage = battery_driver.charge_voltage()?;
|
||||
let charge_current = battery_driver.charge_current()?;
|
||||
let voltage = battery_driver.voltage().unwrap_or_else(|e| {
|
||||
println!("Bat volt {:?}", e);
|
||||
0
|
||||
});
|
||||
let current = battery_driver.current().unwrap_or_else(|e| {
|
||||
println!("Bat current {:?}", e);
|
||||
0
|
||||
});
|
||||
let state = battery_driver.state_of_charge().unwrap_or_else(|e| {
|
||||
println!("Bat Soc {:?}", e);
|
||||
0
|
||||
});
|
||||
let charge_voltage = battery_driver.charge_voltage().unwrap_or_else(|e| {
|
||||
println!("Bat Charge Volt {:?}", e);
|
||||
0
|
||||
});
|
||||
let charge_current = battery_driver.charge_current().unwrap_or_else(|e| {
|
||||
println!("Bat Charge Current {:?}", e);
|
||||
0
|
||||
});
|
||||
println!("ChemId: {} Current voltage {} and current {} with charge {}% and temp {} CVolt: {} CCur {}", chem_id, voltage, current, state, temp_c, charge_voltage, charge_current);
|
||||
let _ = battery_driver.unsealed();
|
||||
let _ = battery_driver.it_enable();
|
||||
return Result::Ok(());
|
||||
}
|
||||
|
||||
@@ -741,8 +856,8 @@ impl CreatePlantHal<'_> for PlantHal {
|
||||
|
||||
let driver = I2cDriver::new(i2c, sda, scl, &config).unwrap();
|
||||
|
||||
//let i2c_port = driver.port();
|
||||
//esp!(unsafe { esp_idf_sys::i2c_set_timeout(i2c_port, 1048000) }).unwrap();
|
||||
let i2c_port = driver.port();
|
||||
esp!(unsafe { esp_idf_sys::i2c_set_timeout(i2c_port, 1048000) }).unwrap();
|
||||
|
||||
let mut battery_driver: Bq34z100g1Driver<I2cDriver, Delay> = Bq34z100g1Driver {
|
||||
i2c: driver,
|
||||
@@ -789,6 +904,30 @@ impl CreatePlantHal<'_> for PlantHal {
|
||||
};
|
||||
} else {
|
||||
println!("Keeping RTC store");
|
||||
unsafe {
|
||||
println!(
|
||||
"Current low voltage detection is {:?}",
|
||||
LOW_VOLTAGE_DETECTED
|
||||
);
|
||||
for i in 0..PLANT_COUNT {
|
||||
let smaller_time = LAST_WATERING_TIMESTAMP[i];
|
||||
let local_time = NaiveDateTime::from_timestamp_millis(smaller_time)
|
||||
.ok_or(anyhow!("could not convert timestamp"))?;
|
||||
let utc_time = local_time.and_utc();
|
||||
let europe_time = utc_time.with_timezone(&Berlin);
|
||||
|
||||
println!(
|
||||
"LAST_WATERING_TIMESTAMP[{}] = {} as europe {}",
|
||||
i, LAST_WATERING_TIMESTAMP[i], europe_time
|
||||
);
|
||||
}
|
||||
for i in 0..PLANT_COUNT {
|
||||
println!(
|
||||
"CONSECUTIVE_WATERING_PLANT[{}] = {}",
|
||||
i, CONSECUTIVE_WATERING_PLANT[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut counter_unit1 = PcntDriver::new(
|
||||
@@ -806,10 +945,10 @@ impl CreatePlantHal<'_> for PlantHal {
|
||||
PinIndex::Pin0,
|
||||
PinIndex::Pin1,
|
||||
&PcntChannelConfig {
|
||||
lctrl_mode: PcntControlMode::Reverse,
|
||||
lctrl_mode: PcntControlMode::Keep,
|
||||
hctrl_mode: PcntControlMode::Keep,
|
||||
pos_mode: PcntCountMode::Decrement,
|
||||
neg_mode: PcntCountMode::Increment,
|
||||
pos_mode: PcntCountMode::Increment,
|
||||
neg_mode: PcntCountMode::Hold,
|
||||
counter_h_lim: i16::MAX,
|
||||
counter_l_lim: 0,
|
||||
},
|
||||
@@ -827,8 +966,6 @@ impl CreatePlantHal<'_> for PlantHal {
|
||||
let nvs = EspDefaultNvsPartition::take()?;
|
||||
let wifi_driver = EspWifi::new(peripherals.modem, sys_loop, Some(nvs))?;
|
||||
|
||||
let last_watering_timestamp = Mutex::new(unsafe { LAST_WATERING_TIMESTAMP });
|
||||
let consecutive_watering_plant = Mutex::new(unsafe { CONSECUTIVE_WATERING_PLANT });
|
||||
let low_voltage_detected = Mutex::new(unsafe { LOW_VOLTAGE_DETECTED });
|
||||
|
||||
let adc_config = esp_idf_hal::adc::config::Config {
|
||||
@@ -867,8 +1004,6 @@ impl CreatePlantHal<'_> for PlantHal {
|
||||
}
|
||||
let rv = Mutex::new(PlantCtrlBoard {
|
||||
shift_register,
|
||||
last_watering_timestamp,
|
||||
consecutive_watering_plant,
|
||||
low_voltage_detected,
|
||||
tank_driver,
|
||||
tank_channel,
|
||||
@@ -882,6 +1017,7 @@ impl CreatePlantHal<'_> for PlantHal {
|
||||
signal_counter: counter_unit1,
|
||||
wifi_driver,
|
||||
mqtt_client: None,
|
||||
battery_driver,
|
||||
});
|
||||
Ok(rv)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user