Compare commits
5 Commits
ef0ec47d92
...
3cc5a0d2bd
| Author | SHA1 | Date | |
|---|---|---|---|
| 3cc5a0d2bd | |||
| 3be585ecbf | |||
| 5b1a945ac3 | |||
| f4e050d413 | |||
| 776db785c4 |
395
Software/MainBoard/rust/Cargo.lock
generated
395
Software/MainBoard/rust/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -316,9 +316,12 @@ impl From<sntpc::Error> for FatError {
|
||||
impl From<BmsProtocolError> for FatError {
|
||||
fn from(value: BmsProtocolError) -> Self {
|
||||
match value {
|
||||
BmsProtocolError::I2cCommunicationError => FatError::String {
|
||||
BmsProtocolError::I2cCommunicationError =>FatError::String {
|
||||
error: "I2C communication error".to_string(),
|
||||
},
|
||||
BmsProtocolError::ChecksumError => FatError::String {
|
||||
error: "BMS checksum error".to_string(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +290,8 @@ impl PlantHal {
|
||||
error: format!("Could not init wifi: {:?}", e),
|
||||
})?;
|
||||
|
||||
let pcnt_module = Pcnt::new(peripherals.PCNT);
|
||||
let mut pcnt_module = Pcnt::new(peripherals.PCNT);
|
||||
pcnt_module.set_interrupt_handler(water::flow_interrupt_handler);
|
||||
|
||||
let free_pins = FreePeripherals {
|
||||
gpio0: peripherals.GPIO0,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use crate::bail;
|
||||
use crate::fat_error::FatError;
|
||||
use crate::hal::{ADC1, TANK_MULTI_SAMPLE};
|
||||
use core::cell::RefCell;
|
||||
use embassy_sync::blocking_mutex::CriticalSectionMutex;
|
||||
use embassy_time::Timer;
|
||||
use esp_hal::analog::adc::{Adc, AdcCalLine, AdcConfig, AdcPin, Attenuation};
|
||||
use esp_hal::delay::Delay;
|
||||
@@ -10,17 +12,21 @@ use esp_hal::pcnt::channel::EdgeMode::{Hold, Increment};
|
||||
use esp_hal::pcnt::unit::Unit;
|
||||
use esp_hal::peripherals::GPIO5;
|
||||
use esp_hal::Async;
|
||||
use esp_println::println;
|
||||
use log::info;
|
||||
use onewire::{ds18b20, Device, DeviceSearch, OneWire, DS18B20};
|
||||
use portable_atomic::{AtomicUsize, Ordering};
|
||||
|
||||
unsafe impl Send for TankSensor<'_> {}
|
||||
|
||||
static FLOW_OVERFLOW_COUNTER: AtomicUsize = AtomicUsize::new(0);
|
||||
static FLOW_UNIT: CriticalSectionMutex<RefCell<Option<Unit<'static, 1>>>> =
|
||||
CriticalSectionMutex::new(RefCell::new(None));
|
||||
|
||||
pub struct TankSensor<'a> {
|
||||
one_wire_bus: OneWire<Flex<'a>>,
|
||||
tank_channel: Adc<'a, ADC1<'a>, Async>,
|
||||
tank_power: Output<'a>,
|
||||
tank_pin: AdcPin<GPIO5<'a>, ADC1<'a>, AdcCalLine<ADC1<'a>>>,
|
||||
flow_counter: Unit<'a, 1>,
|
||||
}
|
||||
|
||||
impl<'a> TankSensor<'a> {
|
||||
@@ -30,7 +36,7 @@ impl<'a> TankSensor<'a> {
|
||||
gpio5: GPIO5<'a>,
|
||||
tank_power: Output<'a>,
|
||||
flow_sensor: Input,
|
||||
pcnt1: Unit<'a, 1>,
|
||||
pcnt1: Unit<'static, 1>,
|
||||
) -> Result<TankSensor<'a>, FatError> {
|
||||
one_wire_pin.apply_output_config(
|
||||
&OutputConfig::default()
|
||||
@@ -55,33 +61,64 @@ impl<'a> TankSensor<'a> {
|
||||
ch0.set_edge_signal(flow_sensor.peripheral_input());
|
||||
ch0.set_input_mode(Hold, Increment);
|
||||
ch0.set_ctrl_mode(Keep, Keep);
|
||||
|
||||
pcnt1.listen();
|
||||
|
||||
FLOW_UNIT.lock(|refcell| {
|
||||
refcell.borrow_mut().replace(pcnt1);
|
||||
});
|
||||
|
||||
Ok(TankSensor {
|
||||
one_wire_bus,
|
||||
tank_channel,
|
||||
tank_power,
|
||||
tank_pin,
|
||||
flow_counter: pcnt1,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn reset_flow_meter(&mut self) {
|
||||
self.flow_counter.pause();
|
||||
self.flow_counter.clear();
|
||||
FLOW_OVERFLOW_COUNTER.store(0, Ordering::SeqCst);
|
||||
FLOW_UNIT.lock(|refcell| {
|
||||
if let Some(unit) = refcell.borrow_mut().as_mut() {
|
||||
unit.pause();
|
||||
unit.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn start_flow_meter(&mut self) {
|
||||
self.flow_counter.resume();
|
||||
FLOW_UNIT.lock(|refcell| {
|
||||
if let Some(unit) = refcell.borrow_mut().as_mut() {
|
||||
unit.resume();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn get_flow_meter_value(&mut self) -> i16 {
|
||||
self.flow_counter.value()
|
||||
FLOW_UNIT.lock(|refcell| {
|
||||
refcell.borrow_mut().as_mut().map_or(0, |unit| unit.value())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn stop_flow_meter(&mut self) -> i16 {
|
||||
self.flow_counter.pause();
|
||||
self.get_flow_meter_value()
|
||||
FLOW_UNIT.lock(|refcell| {
|
||||
let mut borrowed = refcell.borrow_mut();
|
||||
if let Some(unit) = borrowed.as_mut() {
|
||||
let val = unit.value();
|
||||
unit.pause();
|
||||
val
|
||||
} else {
|
||||
0
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_full_flow_count(&self) -> u32 {
|
||||
let current = FLOW_UNIT.lock(|refcell| {
|
||||
refcell.borrow().as_ref().map_or(0, |unit| unit.value() as u32)
|
||||
});
|
||||
let overflowed = FLOW_OVERFLOW_COUNTER.load(Ordering::SeqCst) as u32;
|
||||
overflowed * (i16::MAX.wrapping_add(1) as u32) + current
|
||||
}
|
||||
|
||||
pub async fn water_temperature_c(&mut self) -> Result<f32, FatError> {
|
||||
@@ -90,9 +127,9 @@ impl<'a> TankSensor<'a> {
|
||||
let mut delay = Delay::new();
|
||||
|
||||
let presence = self.one_wire_bus.reset(&mut delay)?;
|
||||
println!("OneWire: reset presence pulse = {}", presence);
|
||||
info!("OneWire: reset presence pulse = {}", presence);
|
||||
if !presence {
|
||||
println!("OneWire: no device responded to reset — check pull-up resistor and wiring");
|
||||
info!("OneWire: no device responded to reset — check pull-up resistor and wiring");
|
||||
}
|
||||
|
||||
let mut search = DeviceSearch::new();
|
||||
@@ -100,7 +137,7 @@ impl<'a> TankSensor<'a> {
|
||||
let mut devices_found = 0u8;
|
||||
while let Some(device) = self.one_wire_bus.search_next(&mut search, &mut delay)? {
|
||||
devices_found += 1;
|
||||
println!(
|
||||
info!(
|
||||
"OneWire: found device #{} family=0x{:02X} addr={:02X?}",
|
||||
devices_found, device.address[0], device.address
|
||||
);
|
||||
@@ -108,16 +145,16 @@ impl<'a> TankSensor<'a> {
|
||||
water_temp_sensor = Some(device);
|
||||
break;
|
||||
} else {
|
||||
println!("OneWire: skipping device — not a DS18B20 (family 0x{:02X} != 0x{:02X})", device.address[0], ds18b20::FAMILY_CODE);
|
||||
info!("OneWire: skipping device — not a DS18B20 (family 0x{:02X} != 0x{:02X})", device.address[0], ds18b20::FAMILY_CODE);
|
||||
}
|
||||
}
|
||||
if devices_found == 0 {
|
||||
println!("OneWire: search found zero devices on the bus");
|
||||
info!("OneWire: search found zero devices on the bus");
|
||||
}
|
||||
|
||||
match water_temp_sensor {
|
||||
Some(device) => {
|
||||
println!("Found one wire device: {:?}", device);
|
||||
info!("Found one wire device: {:?}", device);
|
||||
let mut water_temp_sensor = DS18B20::new(device)?;
|
||||
|
||||
let water_temp: Result<f32, FatError> = loop {
|
||||
@@ -126,11 +163,11 @@ impl<'a> TankSensor<'a> {
|
||||
.await;
|
||||
match &temp {
|
||||
Ok(res) => {
|
||||
println!("Water temp is {}", res);
|
||||
info!("Water temp is {}", res);
|
||||
break temp;
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Could not get water temp {} attempt {}", err, attempt)
|
||||
info!("Could not get water temp {} attempt {}", err, attempt)
|
||||
}
|
||||
}
|
||||
if attempt == 5 {
|
||||
@@ -178,3 +215,18 @@ impl<'a> TankSensor<'a> {
|
||||
Ok(median_mv / 1000.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[esp_hal::handler]
|
||||
pub fn flow_interrupt_handler() {
|
||||
FLOW_UNIT.lock(|refcell| {
|
||||
if let Some(unit) = refcell.borrow_mut().as_mut() {
|
||||
if unit.interrupt_is_set() {
|
||||
let events = unit.events();
|
||||
if events.high_limit {
|
||||
FLOW_OVERFLOW_COUNTER.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
unit.reset_interrupt();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
|
||||
let reboot_now = Arc::new(AtomicBool::new(false));
|
||||
println!("starting webserver");
|
||||
|
||||
let _ = http_server(reboot_now.clone(), stack);
|
||||
spawner.spawn(http_server(reboot_now.clone(), stack)?);
|
||||
wait_infinity(board, WaitType::MissingConfig, reboot_now.clone(), UTC).await;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,39 +3,55 @@ title: "BatteryManagement"
|
||||
date: 2025-01-27
|
||||
draft: false
|
||||
description: "a description"
|
||||
tags: ["battery", "bq34z100"]
|
||||
tags: ["battery", "bms"]
|
||||
---
|
||||
# Battery Management Module
|
||||
The project contains an additional companion board (Fuel Gauge), with a bq34z100 battery management IC.
|
||||
|
||||
It allows to track the health and charge for an external battery and is supposed to be soldered directly to the battery.
|
||||
The MainBoard contains a connector for power, and additionally a two-pin I2C bus to communicate with the Battery Management module.
|
||||
The PlantCtrl system uses an external **Battery Management System (BMS)** board that connects to the MainBoard. This module monitors battery voltage, current, and health metrics and communicates with the ESP32-C6 via I2C.
|
||||
|
||||
<!-- TODO: Add photo of the new modular Battery Management board -->
|
||||
|
||||
# Setup
|
||||
{{< alert >}}
|
||||
A protected Battery is required. There is only a very simplistic output voltage adjustment for the MPPT system and no charge termination. It is expected that the battery itself protects against overcharging and deep discharges!
|
||||
The open-bms is a custom battery management board designed for this project. It uses a CH32V203 microcontroller to handle battery monitoring and protection. The older bq34z100-based battery management board is deprecated and located in the `__Legay_Unused` folder.
|
||||
{{< /alert >}}
|
||||
* BatteryManagement is purely optional, but recommended for solar power.
|
||||
* If available it will be used for an extended low power deep sleep in case of critical charge.
|
||||
* If available it will also be used, to reduce the nightlight, if the charge drops to a predefined level, so the nightlight cannot drain to much battery
|
||||
* If available, all relevant battery metrics will be published via mqtt
|
||||
|
||||
Currently the setup requires a custom Ev2400 flasher and the properitary windows software from texas instruments.
|
||||
{{< alert >}}
|
||||
Before soldering to the battery
|
||||
{{< /alert >}}
|
||||
1. The voltage devider high side must be bridged, while being connected to the computer and being supplied with around 4.2 V from the battery solder leads.
|
||||
2. Then the data/register for low voltage flash write protection should be set to 0V, as else with the voltage divider and no further configuration, the IC will refuse all write requests.
|
||||
3. After this the supplied golden image can be used, it will setup the battery for 6Ah and a 4S lifepo. Different values can be adjusted after this to the users liking.
|
||||
## Hardware
|
||||
|
||||
The Battery Management Board features:
|
||||
* CH32V203 RISC-V microcontroller for battery monitoring
|
||||
* I2C interface for communication with the MainBoard
|
||||
* Battery voltage and current sensing
|
||||
|
||||
{{< alert >}}
|
||||
The main board, does not care or process any of the charge discharge limits that can be set. Ensure that the battery can supply enough current as well as accept a 2.4A charging current from the MPPT system.
|
||||
The open-bms board does not use the bq34z100 fuel gauge IC. That component was used in an older legacy design now located in the `__Legay_Unused` folder.
|
||||
{{< /alert >}}
|
||||
|
||||
The golden image sets the statups led up, to be in blinky mode. one very long interval means, that the battery is pretty much full. A few very short flashes mean that the battery is nearly empty. No light means, that the battery is in discharge protection and shut down.
|
||||
## Integration with MainBoard
|
||||
|
||||
If the red error led lights, something is wrong with the battery. This can be abnormal voltages or a very low health state.
|
||||
The battery management board:
|
||||
* Connects to the MainBoard via a two-pin I2C bus
|
||||
* Provides power connection to the battery
|
||||
* Reports battery metrics via MQTT (if configured)
|
||||
|
||||
# Todo?
|
||||
If the battery reports that no discharging should occure, report this and then shutdown without using pumps
|
||||
## Usage
|
||||
|
||||
* If available, the system will use battery metrics for deep sleep management when charge is critical
|
||||
* The nightlight can be automatically disabled if battery level drops below a predefined threshold
|
||||
* All battery metrics are published via MQTT when configured
|
||||
* The system includes safety mechanisms to prevent overcharging and deep discharges through the battery's built-in protection circuitry
|
||||
|
||||
## Safety Notes
|
||||
|
||||
{{< alert >}}
|
||||
The system requires a battery with built-in protection circuitry. The MPPT system does not include charge termination or overcharge protection - the battery itself must provide these safety features.
|
||||
{{< /alert >}}
|
||||
|
||||
The CH32V203-based BMS monitors battery health and provides status information but does not control the charge/discharge limits. Ensure your battery can handle the maximum charging current from the MPPT system (up to 2.4A).
|
||||
|
||||
## Setup
|
||||
|
||||
1. **Connect Battery:** Connect your protected battery to the BMS board
|
||||
2. **_connect MainBoard:** Connect the Battery Management Board to the MainBoard via the I2C bus connector
|
||||
3. **Power On:** Power on the system and verify communication via MQTT
|
||||
|
||||
## Status Indicators
|
||||
|
||||
The BMS board includes status LEDs, they behave like every normal powerbank (1-5 lights, animted if charging)
|
||||
@@ -65,13 +65,9 @@ Software and Hardware may fail: It is your responsibility to ensure that a stuck
|
||||
{{< /alert >}}
|
||||
|
||||
|
||||
# Todo
|
||||
## Flow Sensor
|
||||
There is a input for a flow sensor, currently it is not used as the software is missing.
|
||||
* Allow monitoring if pumps are actually moving water
|
||||
* Allow to set limits for how much ml are allowed additinally to the current time limit per watering run
|
||||
|
||||
|
||||
|
||||
Currently it cannot be set how two sensor should be interpreted and they are only averaged. More complex functions would be nice here, eg. allowing a user settable interpolation (0.8*a+0.2*b)/2 and Min(a,b) as well as max(a,b)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@ tags: ["esp32", "hardware"]
|
||||
<img src="pcb_back.png" class="grid-w50" />
|
||||
{{< /gallery >}}
|
||||
|
||||
<!-- TODO: Add new screenshots of the modular PCB setup -->
|
||||
|
||||
{{< gitea server="https://git.mannheim.ccc.de/" repo="C3MA/PlantCtrl" >}}
|
||||
|
||||
## Modular Design
|
||||
@@ -27,17 +25,25 @@ The system now consists of a **MainBoard** which acts as the controller and seve
|
||||
* **Fully Open Source:** Designed in KiCad
|
||||
|
||||
## Available Modules
|
||||
* **MPPT Charger:** Efficient solar charging for batteries.
|
||||
* **Pump Driver:** High-current outputs for pumps and valves.
|
||||
* **Sensor Interface:** Support for multiple moisture sensors.
|
||||
* **Light Controller:** For LED nightlights or growth lights.
|
||||
* **MPPT Charger:** Efficient solar charging for batteries using CN3795.
|
||||
* **Pump Driver:** High-current outputs (up to 3A) for pumps and valves.
|
||||
* **Sensor Module:** CAN bus-based moisture sensors using CH32V203 microcontroller.
|
||||
* **Battery Management:** External BMS board with CH32V203 for battery monitoring.
|
||||
* **Light Controller:** For LED nightlights or growth lights using AP63200.
|
||||
|
||||
## Sensor Module (CAN bus)
|
||||
The standard sensor module features its own **CH32V203 RISC-V microcontroller**, which handles the measurement of soil moisture and communicates the results back to the MainBoard via the CAN bus.
|
||||
|
||||
* **Capacity:** Supports up to 16 sensors (typically 8 plants with an A and B sensor each).
|
||||
* **Reliability:** Digital communication via CAN bus ensures data integrity even over longer cable runs and in electrically noisy environments.
|
||||
* **Addressing:** The A sensor is always used; the B sensor is optional and suggested for larger planters to provide a better average of the soil moisture.
|
||||
|
||||
## Capabilities
|
||||
* **Moisture Sensors:** Supports multiple capacitive or resistive sensors via expansion modules.
|
||||
* **Moisture Sensors:** Supports multiple capacitive or resistive sensors via CAN bus-based Sensor Modules.
|
||||
* **Pumps/Valves:** Support for multiple independent watering zones.
|
||||
* **Power:**
|
||||
* Solar powered with MPPT
|
||||
* Battery powered with optional Battery Management (Fuel Gauge)
|
||||
* Battery powered with optional Battery Management System (BMS)
|
||||
* Can also be used with a standard power supply (7-24V)
|
||||
* **Efficient Power:** Use of high-efficiency DC-DC converters for 3.3V and peripherals.
|
||||
|
||||
|
||||
@@ -6,9 +6,12 @@ description: "a description"
|
||||
tags: ["firmeware", "upload"]
|
||||
---
|
||||
# From Source
|
||||
|
||||
The PlantCtrl firmware is written in Rust for the ESP32-C6 RISC-V microcontroller.
|
||||
|
||||
## Preconditions
|
||||
* **Rust:** Current version of `rustup`.
|
||||
* **ESP32 Toolchain:** `espup` installed and configured.
|
||||
* **ESP32 Toolchain:** `espup` installed and configured for ESP32-C6.
|
||||
* **espflash:** Installed via `cargo install espflash`.
|
||||
* **Node.js:** `npm` installed (for the web interface).
|
||||
|
||||
@@ -37,10 +40,8 @@ You can use the provided bash scripts to automate the build and flash process:
|
||||
You can also update the firmware wirelessly if the system is already running and connected to your network.
|
||||
|
||||
1. Generate the OTA binary:
|
||||
```bash
|
||||
cargo build --release
|
||||
```
|
||||
2. The binary will be at `target/riscv32imac-unknown-none-elf/release/plant-ctrl2`.
|
||||
**`./image.sh`**
|
||||
2. The binary will be `image.bin`.
|
||||
3. Open the PlantCtrl web interface in your browser.
|
||||
4. Navigate to the **OTA** section.
|
||||
5. Upload the `plant-ctrl2` file.
|
||||
|
||||
@@ -6,23 +6,26 @@ description: "a description"
|
||||
tags: ["mqtt", "esp"]
|
||||
---
|
||||
# MQTT
|
||||
A configured MQTT server will receive statistical and status data from the controller.
|
||||
|
||||
The PlantCtrl firmware publishes comprehensive status and telemetry data via MQTT when configured. The system uses the **mcutie** crate for Home Assistant integration and standard MQTT topics.
|
||||
|
||||
### Topics
|
||||
|
||||
| Topic | Example | Description |
|
||||
|-------|---------|-------------|
|
||||
| `firmware/address` | `192.168.1.2` | IP address in station mode |
|
||||
| `firmware/state` | `VersionInfo { ... }` | Debug information about the current firmware and OTA slots |
|
||||
| `firmware/state` | `{...}` | Debug information about the current firmware and OTA slots |
|
||||
| `firmware/last_online` | `2025-01-22T08:56:46.664+01:00` | Last time the board was online |
|
||||
| `state` | `online` | Current state of the controller |
|
||||
| `mppt` | `{"current_ma":1200,"voltage_ma":18500}` | MPPT charging metrics |
|
||||
| `battery` | `{"Info":{"voltage_milli_volt":12860,"average_current_milli_ampere":-16,...}}` | Battery health and charge data |
|
||||
| `water` | `{"enough_water":true,"warn_level":false,"left_ml":1337,...}` | Water tank status |
|
||||
| `plant{1-8}` | `{"sensor_a":...,"sensor_b":...,"mode":"TargetMoisture",...}` | Detailed status for each plant slot |
|
||||
| `pump{1-8}` | `{"enabled":true,"pump_ineffective":false,...}` | Metrics for the last pump activity |
|
||||
| `mppt` | `{"current_ma":1200,"voltage_ma":18500}` | MPPT charging metrics (current and voltage from solar panel) |
|
||||
| `battery` | `{"Info":{"voltage_milli_volt":12860,"state_of_charge":95,...}}` | Battery health and charge data from the BMS |
|
||||
| `water` | `{"enough_water":true,"warn_level":false,"left_ml":1337,...}` | Water tank status (level, temperature, frozen detection) |
|
||||
| `plant{1-8}` | `{"sensor_a":...,"sensor_b":...,"mode":"TargetMoisture",...}` | Detailed status for each plant slot including moisture sensors |
|
||||
| `pump{1-8}` | `{"enabled":true,"median_current_ma":500,...}` | Metrics for each pump output |
|
||||
| `light` | `{"enabled":true,"active":true,...}` | Night light status |
|
||||
| `deepsleep` | `night 1h` | Why and how long the ESP will sleep |
|
||||
| `deepsleep` | `night 1h` | Reason and duration of deep sleep |
|
||||
|
||||
Note: The batteries `average_current_milli_ampere` field uses a placeholder value (1337) and should be updated with actual current sensor readings when available.
|
||||
|
||||
### Data Structures
|
||||
|
||||
@@ -39,14 +42,15 @@ Contains a debug dump of the `VersionInfo` struct:
|
||||
- `voltage_ma`: Solar panel voltage in mV
|
||||
|
||||
#### Battery (`battery`)
|
||||
Can be `"Unknown"` or an `Info` object:
|
||||
- `voltage_milli_volt`: Battery voltage
|
||||
- `average_current_milli_ampere`: Current draw/charge
|
||||
- `design_milli_ampere_hour`: Battery capacity
|
||||
- `remaining_milli_ampere_hour`: Remaining capacity
|
||||
Can be `"Unknown"` or an `Info` object. The battery data comes from a custom BMS (Battery Management System) board that uses the CH32V203 microcontroller with I2C communication.
|
||||
|
||||
- `voltage_milli_volt`: Battery voltage in millivolts
|
||||
- `average_current_milli_ampere`: Current draw/charge in milliamperes (placeholder: 1337)
|
||||
- `design_milli_ampere_hour`: Battery design capacity in milliampere-hours
|
||||
- `remaining_milli_ampere_hour`: Remaining capacity in milliampere-hours
|
||||
- `state_of_charge`: Charge percentage (0-100)
|
||||
- `state_of_health`: Health percentage (0-100)
|
||||
- `temperature`: Temperature in degrees Celsius
|
||||
- `state_of_health`: Health percentage (0-100) based onLifetime capacity vs design capacity
|
||||
- `temperature`: Battery temperature in degrees Celsius
|
||||
|
||||
#### Water (`water`)
|
||||
- `enough_water`: Boolean, true if level is above empty threshold
|
||||
|
||||
@@ -6,9 +6,9 @@ description: "How to compile the project"
|
||||
tags: ["clone", "compile"]
|
||||
---
|
||||
# Preconditions:
|
||||
* **Rust:** `rustup` installed.
|
||||
* **ESP32 Toolchain:** `espup` installed.
|
||||
* **Build Utilities:** `ldproxy` and `espflash` installed.
|
||||
* **Rust:** `rustup` installed with the Rust toolchain.
|
||||
* **ESP32 Toolchain:** `espup` installed for ESP32 support.
|
||||
* **Build Utilities:** `ldproxy` and `espflash` installed via cargo.
|
||||
* **Node.js:** `npm` installed (for the web interface).
|
||||
|
||||
# Cloning the Repository
|
||||
@@ -19,24 +19,16 @@ cd PlantCtrl/Software/MainBoard/rust
|
||||
```
|
||||
|
||||
# Toolchain Setup
|
||||
1. **Install Rust:** If not already done, visit [rustup.rs](https://rustup.rs/).
|
||||
2. **Install ldproxy:**
|
||||
|
||||
The project uses Rust with ESP32-C6 support. The toolchain setup involves installing the necessary components:
|
||||
|
||||
1. **Rust Toolchain:**
|
||||
```bash
|
||||
cargo install ldproxy
|
||||
```
|
||||
3. **Install espup:**
|
||||
```bash
|
||||
cargo install espup
|
||||
```
|
||||
4. **Install ESP toolchain:**
|
||||
```bash
|
||||
espup install
|
||||
```
|
||||
5. **Install espflash:**
|
||||
```bash
|
||||
cargo install espflash
|
||||
rustup toolchain install stable
|
||||
rustup default stable
|
||||
```
|
||||
|
||||
|
||||
# Building the Web Interface
|
||||
The configuration website is built using TypeScript and Webpack, then embedded into the Rust binary.
|
||||
```bash
|
||||
@@ -46,14 +38,7 @@ npx webpack
|
||||
cd ..
|
||||
```
|
||||
|
||||
# Compiling the Firmware
|
||||
Build the project using Cargo:
|
||||
```bash
|
||||
cargo build --release
|
||||
```
|
||||
The resulting binary will be located in `target/riscv32imac-unknown-none-elf/release/plant-ctrl2`.
|
||||
|
||||
# Using Build Scripts
|
||||
# Compiling the Firmware using Build Scripts
|
||||
To simplify the process, several bash scripts are provided in the `Software/MainBoard/rust` directory:
|
||||
|
||||
* **`image_build.sh`**: Automatically builds the web interface, compiles the Rust firmware in release mode, and creates a flashable `image.bin`.
|
||||
|
||||
Reference in New Issue
Block a user