proceed with bq34z100 extraction

This commit is contained in:
2024-02-02 21:35:04 +01:00
parent 541f7e4471
commit 060a1cc32d
11 changed files with 1371 additions and 1439 deletions

View File

@@ -1,12 +1,9 @@
//mod config;
use bit_field::BitField;
use embedded_hal::blocking::i2c::Operation;
use embedded_svc::wifi::{
AccessPointConfiguration, AccessPointInfo, AuthMethod, ClientConfiguration, Configuration,
};
use esp_idf_hal::i2c::{I2cConfig, I2cDriver, APBTickType};
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::ExactlyOnce;
@@ -14,7 +11,7 @@ use esp_idf_svc::mqtt::client::{EspMqttClient, MqttClientConfiguration};
use esp_idf_svc::nvs::EspDefaultNvsPartition;
use esp_idf_svc::wifi::config::{ScanConfig, ScanType};
use esp_idf_svc::wifi::EspWifi;
use measurements::{Measurement, Temperature};
use measurements::Temperature;
use plant_ctrl2::sipo::ShiftRegister40;
use anyhow::anyhow;
@@ -34,7 +31,7 @@ use ds18b20::Ds18b20;
use embedded_hal::digital::v2::OutputPin;
use esp_idf_hal::adc::{attenuation, AdcChannelDriver, AdcDriver};
use esp_idf_hal::delay::Delay;
use esp_idf_hal::gpio::{AnyInputPin, Gpio39, Gpio4, Level, PinDriver, Pull, InputOutput};
use esp_idf_hal::gpio::{AnyInputPin, Gpio39, Gpio4, InputOutput, Level, PinDriver, Pull};
use esp_idf_hal::pcnt::{
PcntChannel, PcntChannelConfig, PcntControlMode, PcntCountMode, PcntDriver, PinIndex,
};
@@ -42,12 +39,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::{vTaskDelay, EspError, esp};
use esp_idf_sys::{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;
use crate::bq34z100::{Bq34z100g1Driver, Bq34z100g1};
pub const PLANT_COUNT: usize = 8;
const PINS_PER_PLANT: usize = 5;
@@ -61,6 +58,8 @@ const SPIFFS_PARTITION_NAME: &str = "storage";
const WIFI_CONFIG_FILE: &str = "/spiffs/wifi.cfg";
const CONFIG_FILE: &str = "/spiffs/config.cfg";
const TANK_MULTI_SAMPLE: usize = 11;
#[link_section = ".rtc.data"]
static mut LAST_WATERING_TIMESTAMP: [i64; PLANT_COUNT] = [0; PLANT_COUNT];
#[link_section = ".rtc.data"]
@@ -137,7 +136,7 @@ pub trait PlantCtrlBoardInteraction {
fn is_day(&self) -> bool;
fn water_temperature_c(&mut self) -> Result<f32>;
fn tank_sensor_mv(&mut self) -> Result<u16>;
fn tank_sensor_percent(&mut self) -> Result<u16>;
fn set_low_voltage_in_cycle(&mut self);
fn clear_low_voltage_in_cycle(&mut self);
@@ -202,7 +201,11 @@ pub struct PlantCtrlBoard<'a> {
impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
fn battery_state(&mut self) -> Result<BatteryState> {
Ok(BatteryState::default())
let state = BatteryState {
..Default::default()
};
Ok(state)
}
fn is_day(&self) -> bool {
@@ -236,17 +239,45 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
if sensor_data.temperature == 85_f32 {
bail!("Ds18b20 dummy temperature returned");
}
Ok(sensor_data.temperature/10_f32)
Ok(sensor_data.temperature / 10_f32)
}
fn tank_sensor_mv(&mut self) -> Result<u16> {
fn tank_sensor_percent(&mut self) -> Result<u16> {
let delay = Delay::new_default();
self.tank_power.set_high()?;
//let stabilize
delay.delay_ms(100);
let value = self.tank_driver.read(&mut self.tank_channel)?;
self.tank_power.set_low()?;
Ok(value)
unsafe {
vTaskDelay(100);
}
let mut store = [0_u16; TANK_MULTI_SAMPLE];
for multisample in 0..TANK_MULTI_SAMPLE {
let value = self.tank_driver.read(&mut self.tank_channel)?;
store[multisample] = value;
}
store.sort();
let median = store[6] as f32 / 1000_f32;
let config_open_voltage_mv = 3.0;
if config_open_voltage_mv < median {
self.tank_power.set_low()?;
bail!(
"Tank sensor missing, open loop voltage {} on tank sensor input {}",
config_open_voltage_mv,
median
);
}
let r2 = median * 50.0 / (3.3 - median);
let mut percent = r2 / 190_f32 * 100_f32;
percent = percent.clamp(0.0, 100.0);
let quantizised = quantize_to_next_5_percent(percent as f64) as u16;
println!(
"Tank sensor raw {} percent {} quantized {}",
median, percent, quantizised
);
return Ok(quantizised);
}
fn set_low_voltage_in_cycle(&mut self) {
@@ -258,7 +289,9 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
}
fn light(&mut self, enable: bool) -> Result<()> {
unsafe { gpio_hold_dis(self.light.pin()) };
self.light.set_state(enable.into())?;
unsafe { gpio_hold_en(self.light.pin()) };
Ok(())
}
@@ -667,40 +700,69 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
}
}
fn print_battery(
battery_driver: &mut Bq34z100g1Driver<I2cDriver, Delay>,
) -> Result<(), Bq34Z100Error<I2cError>> {
let fwversion = battery_driver.fw_version()?;
println!("fw version is {}", fwversion);
let design_capacity = battery_driver.design_capacity()?;
println!("Design Capacity {}", design_capacity);
if design_capacity == 1000 {
println!("Still stock configuring battery, readouts are likely to be wrong!");
}
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 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()?;
println!("ChemId: {} Current voltage {} and current {} with charge {}% and temp {} CVolt: {} CCur {}", chem_id, voltage, current, state, temp_c, charge_voltage, charge_current);
return Result::Ok(());
}
impl CreatePlantHal<'_> for PlantHal {
fn create() -> Result<Mutex<PlantCtrlBoard<'static>>> {
let peripherals = Peripherals::take()?;
let i2c = peripherals.i2c1;
let config = I2cConfig::new()
.scl_enable_pullup(false)
.sda_enable_pullup(false)
.baudrate(10_u32.kHz().into());
.scl_enable_pullup(false)
.sda_enable_pullup(false)
.baudrate(10_u32.kHz().into());
let scl = peripherals.pins.gpio16;
let sda = peripherals.pins.gpio17;
let driver = I2cDriver::new(i2c, sda, scl, &config).unwrap();
let i2c_port = driver.port();
let mut battery_driver :Bq34z100g1Driver<I2cDriver, Delay> = Bq34z100g1Driver{
i2c :driver,
//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,
delay: Delay::new_default(),
flash_block_data : [0;32],
};
flash_block_data: [0; 32],
};
let mut clock = PinDriver::input_output(peripherals.pins.gpio21)?;
clock.set_pull(Pull::Floating);
clock.set_pull(Pull::Floating).unwrap();
let mut latch = PinDriver::input_output(peripherals.pins.gpio22)?;
latch.set_pull(Pull::Floating);
latch.set_pull(Pull::Floating).unwrap();
let mut data = PinDriver::input_output(peripherals.pins.gpio19)?;
data.set_pull(Pull::Floating);
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.gpio4)?;
one_wire_pin.set_pull(Pull::Floating);
one_wire_pin.set_pull(Pull::Floating).unwrap();
//TODO make to none if not possible to init
//init,reset rtc memory depending on cause
@@ -765,12 +827,15 @@ 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 tank_driver =
AdcDriver::new(peripherals.adc1, &esp_idf_hal::adc::config::Config::new())?;
let adc_config = esp_idf_hal::adc::config::Config {
resolution: esp_idf_hal::adc::config::Resolution::Resolution12Bit,
calibration: true,
};
let tank_driver = AdcDriver::new(peripherals.adc1, &adc_config)?;
let tank_channel: AdcChannelDriver<'_, { attenuation::DB_11 }, Gpio39> =
AdcChannelDriver::new(peripherals.pins.gpio39)?;
@@ -779,8 +844,10 @@ impl CreatePlantHal<'_> for PlantHal {
let mut boot_button = PinDriver::input(peripherals.pins.gpio0)?;
boot_button.set_pull(Pull::Floating)?;
let mut light = PinDriver::input_output(peripherals.pins.gpio26)?;
light.set_pull(Pull::Floating)?;
light.set_pull(Pull::Floating).unwrap();
let mut main_pump = PinDriver::input_output(peripherals.pins.gpio23)?;
main_pump.set_pull(Pull::Floating)?;
main_pump.set_low()?;
@@ -794,143 +861,10 @@ impl CreatePlantHal<'_> for PlantHal {
println!("After stuff");
esp!(unsafe { esp_idf_sys::i2c_set_timeout(i2c_port, 1048000) }).unwrap();
let fwversion = battery_driver.fw_version();
println!("fw version is {}", fwversion);
let design_capacity = battery_driver.design_capacity();
println!("Design Capacity {}", design_capacity);
if(design_capacity == 1000){
println!("Still stock configuring battery");
let status = print_battery(&mut battery_driver);
if status.is_err() {
println!("Error communicating with battery!! {:?}", status.err());
}
//battery_driver.update_design_capacity(5999);
//let mut success = battery_driver.update_design_capacity(6000);
//if (!success){
// bail!("Error updating capacity");
//}
//success = battery_driver.update_q_max(6000);
//if (!success){
// bail!("Error updating max q");
//}
//let energy = 25600;
//success = battery_driver.update_design_energy(energy, 3);
//if (!success){
// bail!("Error updating design energy");
//}
//success = battery_driver.update_cell_charge_voltage_range(3650,3650,3650);
//if (!success){
// bail!("Error updating cell charge voltage");
//}
//success = battery_driver.update_number_of_series_cells(4);
//if (!success){
// bail!("Error updating number of series");
//}
//charge termination here
// //RESCAP CAL_EN SCALED RSVD VOLTSEL IWAKE RSNS1 RSNS0
// //RFACTSTEP SLEEP RMFCC NiDT NiDV QPCCLEAR GNDSEL TEMPS
// let mut conf: u16 = 0;
// //RESCAP
// conf.set_bit(15, true);
// //CAL_EN
// conf.set_bit(14, true);
// //SCALED
// conf.set_bit(13, false);
// //RSVD
// conf.set_bit(12, false);
// //VOLTSEL
// conf.set_bit(11, true);
// //IWAKE
// conf.set_bit(10, false);
// //RSNS1
// conf.set_bit(9, false);
// //RSNS0
// conf.set_bit(8, true);
// //RFACTSTEP
// conf.set_bit(7, true);
// //SLEEP
// conf.set_bit(6, true);
// //RMFCC
// conf.set_bit(5, true);
// //NiDT
// conf.set_bit(4, false);
// //NiDV
// conf.set_bit(3, false);
// //QPCCLEAR
// conf.set_bit(2, false);
// //GNDSEL
// conf.set_bit(1, true);
// //TEMPS
// conf.set_bit(0, false);
// let mut success = battery_driver.update_pack_configuration(conf);
// if (!success){
// bail!("Error updating pack config");
// }
// let mut success = battery_driver.update_charge_termination_parameters(100, 25, 100, 40, 99, 95, 100, 96);
// if (!success){
// bail!("Error updating pack config");
// }
//calibration here
//println!("Cc offset");
//battery_driver.calibrate_cc_offset();
//println!("board offset");
//battery_driver.calibrate_board_offset();
//println!("voltage divider");
//battery_driver.calibrate_voltage_divider(15000.0, 4);
//battery_driver.calibrate_sense_resistor(1530);
//let mut data = 0_u8;
//data.set_bit(0, true); //led mode
//data.set_bit(1, false); // led mode
//data.set_bit(2, false); //led mode
//data.set_bit(3, true); //led always on
//battery_driver.set_led_mode(data);
//battery_driver.unsealed();
battery_driver.it_enable();
loop {
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 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();
println!("ChemId: {} Current voltage {} and current {} with charge {}% and temp {} CVolt: {} CCur {}", chem_id, voltage, current, state, temp_c, charge_voltage, charge_current);
unsafe{
vTaskDelay(1000);
}
}
let rv = Mutex::new(PlantCtrlBoard {
shift_register,
last_watering_timestamp,
@@ -952,3 +886,21 @@ impl CreatePlantHal<'_> for PlantHal {
Ok(rv)
}
}
fn quantize_to_next_5_percent(value: f64) -> i32 {
// Multiply by 100 to work with integer values
let multiplied_value = (value * 100.0).round() as i32;
// Calculate the remainder when divided by 5
let remainder = multiplied_value % 5;
// If the remainder is greater than or equal to half of 5, round up to the next 5%
let rounded_value = if remainder >= 2 {
multiplied_value + (5 - remainder)
} else {
multiplied_value - remainder
};
// Divide by 100 to get back to a float
rounded_value / 100
}