diff --git a/.idea/PlantCtrl.iml b/.idea/PlantCtrl.iml
new file mode 100644
index 0000000..6102194
--- /dev/null
+++ b/.idea/PlantCtrl.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..03d9549
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..ebf4dc3
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/prettier.xml b/.idea/prettier.xml
new file mode 100644
index 0000000..b0c1c68
--- /dev/null
+++ b/.idea/prettier.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..b762460
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Hardware/Controller/MPPT/MPPT.kicad_pro b/Hardware/Controller/MPPT/MPPT.kicad_pro
index a113e86..e8e4e58 100644
--- a/Hardware/Controller/MPPT/MPPT.kicad_pro
+++ b/Hardware/Controller/MPPT/MPPT.kicad_pro
@@ -50,7 +50,23 @@
"silk_text_thickness": 0.1,
"silk_text_upright": false,
"zones": {
- "min_clearance": 0.5
+ "border_display_style": 2,
+ "border_hatch_pitch": 0.5,
+ "corner_radius": 0.0,
+ "corner_smoothing": 0,
+ "fill_mode": 0,
+ "hatch_gap": 1.5,
+ "hatch_orientation": 0.0,
+ "hatch_smoothing_level": 0,
+ "hatch_smoothing_value": 0.1,
+ "hatch_thickness": 1.0,
+ "min_clearance": 0.5,
+ "min_island_area": 10.0,
+ "min_thickness": 0.25,
+ "pad_connection": 1,
+ "remove_islands": 0,
+ "thermal_relief_gap": 0.5,
+ "thermal_relief_spoke_width": 0.5
}
},
"diff_pair_dimensions": [
@@ -453,11 +469,14 @@
"duplicate_sheet_names": "error",
"endpoint_off_grid": "warning",
"extra_units": "error",
+ "field_name_whitespace": "warning",
"footprint_filter": "ignore",
"footprint_link_issues": "warning",
"four_way_junction": "ignore",
"global_label_dangling": "warning",
+ "ground_pin_not_ground": "warning",
"hier_label_mismatch": "error",
+ "isolated_pin_label": "warning",
"label_dangling": "error",
"label_multiple_wires": "warning",
"lib_symbol_issues": "warning",
@@ -480,6 +499,7 @@
"similar_power": "warning",
"simulation_model_issue": "ignore",
"single_global_label": "ignore",
+ "stacked_pin_name": "warning",
"unannotated": "error",
"unconnected_wire_endpoint": "warning",
"undefined_netclass": "error",
@@ -541,6 +561,10 @@
},
"schematic": {
"annotate_start_num": 0,
+ "annotation": {
+ "method": 0,
+ "sort_order": 0
+ },
"bom_export_filename": "${PROJECTNAME}.csv",
"bom_fmt_presets": [],
"bom_fmt_settings": {
@@ -710,6 +734,7 @@
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
+ "hop_over_size_choice": 0,
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
@@ -733,6 +758,7 @@
"net_format_name": "",
"page_layout_descr_file": "",
"plot_directory": "",
+ "reuse_designators": true,
"space_save_all_events": true,
"spice_current_sheet_as_root": false,
"spice_external_command": "spice \"%I\"",
@@ -748,7 +774,9 @@
"name": "MPPT",
"uuid": "00000000-0000-0000-0000-000000000000"
}
- ]
+ ],
+ "used_designators": "",
+ "variants": []
},
"sheets": [
[
diff --git a/Hardware/Controller/MainBoard/PlantCtrlESP32.kicad_pro b/Hardware/Controller/MainBoard/PlantCtrlESP32.kicad_pro
index 89af5e9..763233b 100644
--- a/Hardware/Controller/MainBoard/PlantCtrlESP32.kicad_pro
+++ b/Hardware/Controller/MainBoard/PlantCtrlESP32.kicad_pro
@@ -50,7 +50,23 @@
"silk_text_thickness": 0.15,
"silk_text_upright": false,
"zones": {
- "min_clearance": 0.0
+ "border_display_style": 2,
+ "border_hatch_pitch": 0.5,
+ "corner_radius": 0.0,
+ "corner_smoothing": 0,
+ "fill_mode": 0,
+ "hatch_gap": 1.5,
+ "hatch_orientation": 0.0,
+ "hatch_smoothing_level": 0,
+ "hatch_smoothing_value": 0.1,
+ "hatch_thickness": 1.0,
+ "min_clearance": 0.0,
+ "min_island_area": 10.0,
+ "min_thickness": 0.25,
+ "pad_connection": 1,
+ "remove_islands": 0,
+ "thermal_relief_gap": 0.5,
+ "thermal_relief_spoke_width": 0.5
}
},
"diff_pair_dimensions": [
diff --git a/Software/MainBoard/rust/src/log/mod.rs b/Software/MainBoard/rust/src/log/mod.rs
index a1df0dd..c50318d 100644
--- a/Software/MainBoard/rust/src/log/mod.rs
+++ b/Software/MainBoard/rust/src/log/mod.rs
@@ -321,6 +321,10 @@ pub enum LogMessage {
serialize = "Trace: a: ${number_a} b: ${number_b} txt_s ${txt_short} long ${txt_long}"
)]
Trace,
+ #[strum(
+ serialize = "Pump insufficient flow, pump: ${number_a} measured ${number_b} ml, minimum is ${txt_short} ml"
+ )]
+ PumpInsufficientFlow,
#[strum(serialize = "Parsing error reading message")]
UnknownMessage,
#[strum(serialize = "Going to deep sleep for ${number_a} minutes")]
diff --git a/Software/MainBoard/rust/src/main.rs b/Software/MainBoard/rust/src/main.rs
index a695115..dc64e13 100644
--- a/Software/MainBoard/rust/src/main.rs
+++ b/Software/MainBoard/rust/src/main.rs
@@ -478,6 +478,17 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
state.flow_value_ml,
)
.await;
+ if !dry_run && state.flow_value_ml < MIN_PUMP_FLOW_ML {
+ log(
+ LogMessage::PumpInsufficientFlow,
+ (plant_id + 1) as u32,
+ state.flow_value_ml as u32,
+ &(MIN_PUMP_FLOW_ML as u32).to_string(),
+ "",
+ );
+ board.board_hal.general_fault(true).await;
+ board.board_hal.fault(plant_id, true).await?;
+ }
}
Err(err) => {
mqtt::pump_info(
@@ -700,6 +711,8 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
}
}
+const MIN_PUMP_FLOW_ML: f32 = 200.0;
+
pub async fn do_secure_pump(
board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'_>>,
plant_id: usize,
diff --git a/Software/MainBoard/rust/src_webpack/src/api.ts b/Software/MainBoard/rust/src_webpack/src/api.ts
index 34307f4..6f6e5ea 100644
--- a/Software/MainBoard/rust/src_webpack/src/api.ts
+++ b/Software/MainBoard/rust/src_webpack/src/api.ts
@@ -36,10 +36,10 @@ export interface BackupHeader {
export interface NetworkConfig {
ap_ssid: string,
- ssid: string,
- password: string,
- mqtt_url: string,
- base_topic: string,
+ ssid: string | null,
+ password: string | null,
+ mqtt_url: string | null,
+ base_topic: string | null,
mqtt_user: string | null,
mqtt_password: string | null,
max_wait: number
diff --git a/Software/MainBoard/rust/src_webpack/src/main.ts b/Software/MainBoard/rust/src_webpack/src/main.ts
index 32ac3c2..7eea1e6 100644
--- a/Software/MainBoard/rust/src_webpack/src/main.ts
+++ b/Software/MainBoard/rust/src_webpack/src/main.ts
@@ -246,8 +246,11 @@ export class Controller {
const response = await fetch(PUBLIC_URL + "/get_config");
const loaded = await response.json();
const currentConfig = loaded as PlantControllerConfig;
- controller.setInitialConfig(currentConfig);
controller.setConfig(currentConfig);
+ // Store the config after the UI round-trip so null fields that the UI
+ // normalises (e.g. null → "" → null, null timezone → "UTC") are
+ // represented consistently and don't trigger a false dirty flag.
+ controller.setInitialConfig(controller.getConfig());
//sync json view initially
controller.configChanged();
controller.progressview.removeProgress("get_config");
diff --git a/Software/MainBoard/rust/src_webpack/src/network.ts b/Software/MainBoard/rust/src_webpack/src/network.ts
index 74d7f6b..ea0aced 100644
--- a/Software/MainBoard/rust/src_webpack/src/network.ts
+++ b/Software/MainBoard/rust/src_webpack/src/network.ts
@@ -102,25 +102,25 @@ export class NetworkConfigView {
setConfig(network: NetworkConfig) {
this.ap_ssid.value = network.ap_ssid;
- this.ssid.value = network.ssid;
- this.password.value = network.password;
- this.mqtt_url.value = network.mqtt_url;
- this.base_topic.value = network.base_topic;
+ this.ssid.value = network.ssid ?? "";
+ this.password.value = network.password ?? "";
+ this.mqtt_url.value = network.mqtt_url ?? "";
+ this.base_topic.value = network.base_topic ?? "";
this.mqtt_user.value = network.mqtt_user ?? "";
this.mqtt_password.value = network.mqtt_password ?? "";
this.max_wait.value = network.max_wait.toString();
}
-
+
getConfig(): NetworkConfig {
return {
max_wait: +this.max_wait.value,
ap_ssid: this.ap_ssid.value,
- ssid: this.ssid.value ?? null,
- password: this.password.value ?? null,
- mqtt_url: this.mqtt_url.value ?? null,
- mqtt_user: this.mqtt_user.value ? this.mqtt_user.value : null,
- mqtt_password: this.mqtt_password.value ? this.mqtt_password.value : null,
- base_topic: this.base_topic.value ?? null
+ ssid: this.ssid.value || null,
+ password: this.password.value || null,
+ mqtt_url: this.mqtt_url.value || null,
+ mqtt_user: this.mqtt_user.value || null,
+ mqtt_password: this.mqtt_password.value || null,
+ base_topic: this.base_topic.value || null
}
}
}
diff --git a/rust/.idea/rust.iml b/rust/.idea/rust.iml
new file mode 100644
index 0000000..6102194
--- /dev/null
+++ b/rust/.idea/rust.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file