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