3 Commits

32 changed files with 2240 additions and 29031 deletions

View File

@@ -15,7 +15,6 @@
"vias": 1.0, "vias": 1.0,
"zones": 0.6 "zones": 0.6
}, },
"prototype_zone_fills": false,
"selection_filter": { "selection_filter": {
"dimensions": true, "dimensions": true,
"footprints": true, "footprints": true,
@@ -54,7 +53,6 @@
"zone_display_mode": 1 "zone_display_mode": 1
}, },
"git": { "git": {
"integration_disabled": false,
"repo_type": "", "repo_type": "",
"repo_username": "", "repo_username": "",
"ssh_key": "" "ssh_key": ""
@@ -107,7 +105,6 @@
"filter_text": "", "filter_text": "",
"group_by_constraint": false, "group_by_constraint": false,
"group_by_netclass": false, "group_by_netclass": false,
"show_time_domain_details": false,
"show_unconnected_nets": false, "show_unconnected_nets": false,
"show_zero_pad_nets": false, "show_zero_pad_nets": false,
"sort_ascending": true, "sort_ascending": true,
@@ -118,7 +115,6 @@
"files": [] "files": []
}, },
"schematic": { "schematic": {
"hierarchy_collapsed": [],
"selection_filter": { "selection_filter": {
"graphics": true, "graphics": true,
"images": true, "images": true,
@@ -126,7 +122,6 @@
"lockedItems": false, "lockedItems": false,
"otherItems": true, "otherItems": true,
"pins": true, "pins": true,
"ruleAreas": true,
"symbols": true, "symbols": true,
"text": true, "text": true,
"wires": true "wires": true

View File

@@ -3,8 +3,6 @@
"3dviewports": [], "3dviewports": [],
"design_settings": { "design_settings": {
"defaults": { "defaults": {
"apply_defaults_to_fp_barcodes": false,
"apply_defaults_to_fp_dimensions": false,
"apply_defaults_to_fp_fields": false, "apply_defaults_to_fp_fields": false,
"apply_defaults_to_fp_shapes": false, "apply_defaults_to_fp_shapes": false,
"apply_defaults_to_fp_text": false, "apply_defaults_to_fp_text": false,
@@ -84,7 +82,6 @@
"extra_footprint": "warning", "extra_footprint": "warning",
"footprint": "error", "footprint": "error",
"footprint_filters_mismatch": "ignore", "footprint_filters_mismatch": "ignore",
"footprint_symbol_field_mismatch": "warning",
"footprint_symbol_mismatch": "warning", "footprint_symbol_mismatch": "warning",
"footprint_type_mismatch": "ignore", "footprint_type_mismatch": "ignore",
"hole_clearance": "error", "hole_clearance": "error",
@@ -102,7 +99,6 @@
"mirrored_text_on_front_layer": "warning", "mirrored_text_on_front_layer": "warning",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",
"missing_footprint": "warning", "missing_footprint": "warning",
"missing_tuning_profile": "warning",
"net_conflict": "warning", "net_conflict": "warning",
"nonmirrored_text_on_back_layer": "warning", "nonmirrored_text_on_back_layer": "warning",
"npth_inside_courtyard": "ignore", "npth_inside_courtyard": "ignore",
@@ -122,12 +118,9 @@
"too_many_vias": "error", "too_many_vias": "error",
"track_angle": "error", "track_angle": "error",
"track_dangling": "warning", "track_dangling": "warning",
"track_not_centered_on_via": "ignore",
"track_on_post_machined_layer": "error",
"track_segment_length": "error", "track_segment_length": "error",
"track_width": "error", "track_width": "error",
"tracks_crossing": "error", "tracks_crossing": "error",
"tuning_profile_track_geometries": "ignore",
"unconnected_items": "error", "unconnected_items": "error",
"unresolved_variable": "error", "unresolved_variable": "error",
"via_dangling": "warning", "via_dangling": "warning",
@@ -242,28 +235,17 @@
"zones_allow_external_fillets": false "zones_allow_external_fillets": false
}, },
"ipc2581": { "ipc2581": {
"bom_rev": "",
"dist": "", "dist": "",
"distpn": "", "distpn": "",
"internal_id": "", "internal_id": "",
"mfg": "", "mfg": "",
"mpn": "", "mpn": ""
"sch_revision": ""
}, },
"layer_pairs": [], "layer_pairs": [],
"layer_presets": [], "layer_presets": [],
"viewports": [] "viewports": []
}, },
"boards": [], "boards": [],
"component_class_settings": {
"assignments": [],
"meta": {
"version": 0
},
"sheet_component_classes": {
"enabled": false
}
},
"cvpcb": { "cvpcb": {
"equivalence_files": [] "equivalence_files": []
}, },
@@ -512,14 +494,13 @@
"priority": 2147483647, "priority": 2147483647,
"schematic_color": "rgba(0, 0, 0, 0.000)", "schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.2, "track_width": 0.2,
"tuning_profile": "",
"via_diameter": 0.6, "via_diameter": 0.6,
"via_drill": 0.3, "via_drill": 0.3,
"wire_width": 6 "wire_width": 6
} }
], ],
"meta": { "meta": {
"version": 5 "version": 4
}, },
"net_colors": null, "net_colors": null,
"netclass_assignments": null, "netclass_assignments": null,
@@ -702,7 +683,6 @@
"sort_asc": true, "sort_asc": true,
"sort_field": "Reference" "sort_field": "Reference"
}, },
"bus_aliases": {},
"connection_grid_size": 50.0, "connection_grid_size": 50.0,
"drawing": { "drawing": {
"dashed_lines_dash_length_ratio": 12.0, "dashed_lines_dash_length_ratio": 12.0,
@@ -741,14 +721,7 @@
"spice_save_all_dissipations": false, "spice_save_all_dissipations": false,
"spice_save_all_voltages": false, "spice_save_all_voltages": false,
"subpart_first_id": 65, "subpart_first_id": 65,
"subpart_id_separator": 0, "subpart_id_separator": 0
"top_level_sheets": [
{
"filename": "MPPT.kicad_sch",
"name": "MPPT",
"uuid": "00000000-0000-0000-0000-000000000000"
}
]
}, },
"sheets": [ "sheets": [
[ [
@@ -756,11 +729,5 @@
"Root" "Root"
] ]
], ],
"text_variables": {}, "text_variables": {}
"tuning_profiles": {
"meta": {
"version": 0
},
"tuning_profiles_impedance_geometric": []
}
} }

View File

@@ -15,7 +15,6 @@
"vias": 1.0, "vias": 1.0,
"zones": 0.6 "zones": 0.6
}, },
"prototype_zone_fills": false,
"ratsnest_display_mode": 0, "ratsnest_display_mode": 0,
"selection_filter": { "selection_filter": {
"dimensions": true, "dimensions": true,
@@ -55,7 +54,6 @@
"zone_display_mode": 1 "zone_display_mode": 1
}, },
"git": { "git": {
"integration_disabled": false,
"repo_password": "", "repo_password": "",
"repo_type": "", "repo_type": "",
"repo_username": "", "repo_username": "",
@@ -115,7 +113,6 @@
"filter_text": "", "filter_text": "",
"group_by_constraint": false, "group_by_constraint": false,
"group_by_netclass": false, "group_by_netclass": false,
"show_time_domain_details": false,
"show_unconnected_nets": false, "show_unconnected_nets": false,
"show_zero_pad_nets": false, "show_zero_pad_nets": false,
"sort_ascending": true, "sort_ascending": true,
@@ -126,7 +123,6 @@
"files": [] "files": []
}, },
"schematic": { "schematic": {
"hierarchy_collapsed": [],
"selection_filter": { "selection_filter": {
"graphics": true, "graphics": true,
"images": true, "images": true,
@@ -134,7 +130,6 @@
"lockedItems": false, "lockedItems": false,
"otherItems": true, "otherItems": true,
"pins": true, "pins": true,
"ruleAreas": true,
"symbols": true, "symbols": true,
"text": true, "text": true,
"wires": true "wires": true

View File

@@ -3,8 +3,6 @@
"3dviewports": [], "3dviewports": [],
"design_settings": { "design_settings": {
"defaults": { "defaults": {
"apply_defaults_to_fp_barcodes": false,
"apply_defaults_to_fp_dimensions": false,
"apply_defaults_to_fp_fields": false, "apply_defaults_to_fp_fields": false,
"apply_defaults_to_fp_shapes": false, "apply_defaults_to_fp_shapes": false,
"apply_defaults_to_fp_text": false, "apply_defaults_to_fp_text": false,
@@ -80,7 +78,6 @@
"extra_footprint": "warning", "extra_footprint": "warning",
"footprint": "error", "footprint": "error",
"footprint_filters_mismatch": "ignore", "footprint_filters_mismatch": "ignore",
"footprint_symbol_field_mismatch": "warning",
"footprint_symbol_mismatch": "warning", "footprint_symbol_mismatch": "warning",
"footprint_type_mismatch": "warning", "footprint_type_mismatch": "warning",
"hole_clearance": "error", "hole_clearance": "error",
@@ -99,7 +96,6 @@
"mirrored_text_on_front_layer": "warning", "mirrored_text_on_front_layer": "warning",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",
"missing_footprint": "warning", "missing_footprint": "warning",
"missing_tuning_profile": "warning",
"net_conflict": "warning", "net_conflict": "warning",
"nonmirrored_text_on_back_layer": "warning", "nonmirrored_text_on_back_layer": "warning",
"npth_inside_courtyard": "ignore", "npth_inside_courtyard": "ignore",
@@ -119,12 +115,9 @@
"too_many_vias": "error", "too_many_vias": "error",
"track_angle": "error", "track_angle": "error",
"track_dangling": "warning", "track_dangling": "warning",
"track_not_centered_on_via": "ignore",
"track_on_post_machined_layer": "error",
"track_segment_length": "error", "track_segment_length": "error",
"track_width": "error", "track_width": "error",
"tracks_crossing": "error", "tracks_crossing": "error",
"tuning_profile_track_geometries": "ignore",
"unconnected_items": "error", "unconnected_items": "error",
"unresolved_variable": "error", "unresolved_variable": "error",
"via_dangling": "warning", "via_dangling": "warning",
@@ -249,28 +242,17 @@
"zones_use_no_outline": true "zones_use_no_outline": true
}, },
"ipc2581": { "ipc2581": {
"bom_rev": "",
"dist": "", "dist": "",
"distpn": "", "distpn": "",
"internal_id": "", "internal_id": "",
"mfg": "", "mfg": "",
"mpn": "", "mpn": ""
"sch_revision": ""
}, },
"layer_pairs": [], "layer_pairs": [],
"layer_presets": [], "layer_presets": [],
"viewports": [] "viewports": []
}, },
"boards": [], "boards": [],
"component_class_settings": {
"assignments": [],
"meta": {
"version": 0
},
"sheet_component_classes": {
"enabled": false
}
},
"cvpcb": { "cvpcb": {
"equivalence_files": [] "equivalence_files": []
}, },
@@ -461,14 +443,11 @@
"duplicate_sheet_names": "error", "duplicate_sheet_names": "error",
"endpoint_off_grid": "ignore", "endpoint_off_grid": "ignore",
"extra_units": "error", "extra_units": "error",
"field_name_whitespace": "warning",
"footprint_filter": "ignore", "footprint_filter": "ignore",
"footprint_link_issues": "warning", "footprint_link_issues": "warning",
"four_way_junction": "ignore", "four_way_junction": "ignore",
"global_label_dangling": "warning", "global_label_dangling": "warning",
"ground_pin_not_ground": "warning",
"hier_label_mismatch": "error", "hier_label_mismatch": "error",
"isolated_pin_label": "warning",
"label_dangling": "error", "label_dangling": "error",
"label_multiple_wires": "warning", "label_multiple_wires": "warning",
"lib_symbol_issues": "warning", "lib_symbol_issues": "warning",
@@ -491,7 +470,6 @@
"similar_power": "warning", "similar_power": "warning",
"simulation_model_issue": "ignore", "simulation_model_issue": "ignore",
"single_global_label": "warning", "single_global_label": "warning",
"stacked_pin_name": "warning",
"unannotated": "error", "unannotated": "error",
"unconnected_wire_endpoint": "warning", "unconnected_wire_endpoint": "warning",
"undefined_netclass": "error", "undefined_netclass": "error",
@@ -524,7 +502,6 @@
"priority": 2147483647, "priority": 2147483647,
"schematic_color": "rgba(0, 0, 0, 0.000)", "schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 1.2, "track_width": 1.2,
"tuning_profile": "",
"via_diameter": 0.8, "via_diameter": 0.8,
"via_drill": 0.4, "via_drill": 0.4,
"wire_width": 6 "wire_width": 6
@@ -543,7 +520,6 @@
"priority": 0, "priority": 0,
"schematic_color": "rgb(255, 4, 6)", "schematic_color": "rgb(255, 4, 6)",
"track_width": 1.0, "track_width": 1.0,
"tuning_profile": "",
"via_diameter": 0.8, "via_diameter": 0.8,
"via_drill": 0.4, "via_drill": 0.4,
"wire_width": 12 "wire_width": 12
@@ -562,7 +538,6 @@
"priority": 1, "priority": 1,
"schematic_color": "rgb(255, 153, 0)", "schematic_color": "rgb(255, 153, 0)",
"track_width": 0.2, "track_width": 0.2,
"tuning_profile": "",
"via_diameter": 0.8, "via_diameter": 0.8,
"via_drill": 0.4, "via_drill": 0.4,
"wire_width": 12 "wire_width": 12
@@ -581,7 +556,6 @@
"priority": 2, "priority": 2,
"schematic_color": "rgb(81, 255, 3)", "schematic_color": "rgb(81, 255, 3)",
"track_width": 1.2, "track_width": 1.2,
"tuning_profile": "",
"via_diameter": 0.8, "via_diameter": 0.8,
"via_drill": 0.4, "via_drill": 0.4,
"wire_width": 12 "wire_width": 12
@@ -600,7 +574,6 @@
"priority": 3, "priority": 3,
"schematic_color": "rgb(130, 130, 130)", "schematic_color": "rgb(130, 130, 130)",
"track_width": 1.2, "track_width": 1.2,
"tuning_profile": "",
"via_diameter": 0.8, "via_diameter": 0.8,
"via_drill": 0.4, "via_drill": 0.4,
"wire_width": 12 "wire_width": 12
@@ -619,14 +592,13 @@
"priority": 4, "priority": 4,
"schematic_color": "rgb(0, 0, 0)", "schematic_color": "rgb(0, 0, 0)",
"track_width": 0.5, "track_width": 0.5,
"tuning_profile": "",
"via_diameter": 0.8, "via_diameter": 0.8,
"via_drill": 0.4, "via_drill": 0.4,
"wire_width": 12 "wire_width": 12
} }
], ],
"meta": { "meta": {
"version": 5 "version": 4
}, },
"net_colors": null, "net_colors": null,
"netclass_assignments": null, "netclass_assignments": null,
@@ -1105,10 +1077,6 @@
}, },
"schematic": { "schematic": {
"annotate_start_num": 0, "annotate_start_num": 0,
"annotation": {
"method": 0,
"sort_order": 0
},
"bom_export_filename": "PlantCtrlESP32.csv", "bom_export_filename": "PlantCtrlESP32.csv",
"bom_fmt_presets": [], "bom_fmt_presets": [],
"bom_fmt_settings": { "bom_fmt_settings": {
@@ -1288,7 +1256,6 @@
"sort_asc": true, "sort_asc": true,
"sort_field": "LCSC_PART_NUMBER" "sort_field": "LCSC_PART_NUMBER"
}, },
"bus_aliases": {},
"connection_grid_size": 50.0, "connection_grid_size": 50.0,
"drawing": { "drawing": {
"dashed_lines_dash_length_ratio": 12.0, "dashed_lines_dash_length_ratio": 12.0,
@@ -1296,7 +1263,6 @@
"default_line_thickness": 6.0, "default_line_thickness": 6.0,
"default_text_size": 50.0, "default_text_size": 50.0,
"field_names": [], "field_names": [],
"hop_over_size_choice": 0,
"intersheets_ref_own_page": false, "intersheets_ref_own_page": false,
"intersheets_ref_prefix": "", "intersheets_ref_prefix": "",
"intersheets_ref_short": false, "intersheets_ref_short": false,
@@ -1329,7 +1295,6 @@
}, },
"page_layout_descr_file": "", "page_layout_descr_file": "",
"plot_directory": "/tmp/", "plot_directory": "/tmp/",
"reuse_designators": true,
"space_save_all_events": true, "space_save_all_events": true,
"spice_adjust_passive_values": false, "spice_adjust_passive_values": false,
"spice_current_sheet_as_root": false, "spice_current_sheet_as_root": false,
@@ -1339,16 +1304,7 @@
"spice_save_all_dissipations": false, "spice_save_all_dissipations": false,
"spice_save_all_voltages": false, "spice_save_all_voltages": false,
"subpart_first_id": 65, "subpart_first_id": 65,
"subpart_id_separator": 0, "subpart_id_separator": 0
"top_level_sheets": [
{
"filename": "PlantCtrlESP32.kicad_sch",
"name": "PlantCtrlESP32",
"uuid": "00000000-0000-0000-0000-000000000000"
}
],
"used_designators": "",
"variants": []
}, },
"sheets": [ "sheets": [
[ [
@@ -1356,11 +1312,5 @@
"Root" "Root"
] ]
], ],
"text_variables": {}, "text_variables": {}
"tuning_profiles": {
"meta": {
"version": 0
},
"tuning_profiles_impedance_geometric": []
}
} }

View File

@@ -15,7 +15,6 @@
"vias": 1.0, "vias": 1.0,
"zones": 0.6 "zones": 0.6
}, },
"prototype_zone_fills": false,
"selection_filter": { "selection_filter": {
"dimensions": true, "dimensions": true,
"footprints": true, "footprints": true,
@@ -54,7 +53,6 @@
"zone_display_mode": 0 "zone_display_mode": 0
}, },
"git": { "git": {
"integration_disabled": false,
"repo_type": "", "repo_type": "",
"repo_username": "", "repo_username": "",
"ssh_key": "" "ssh_key": ""
@@ -107,7 +105,6 @@
"filter_text": "", "filter_text": "",
"group_by_constraint": false, "group_by_constraint": false,
"group_by_netclass": false, "group_by_netclass": false,
"show_time_domain_details": false,
"show_unconnected_nets": false, "show_unconnected_nets": false,
"show_zero_pad_nets": false, "show_zero_pad_nets": false,
"sort_ascending": true, "sort_ascending": true,
@@ -118,7 +115,6 @@
"files": [] "files": []
}, },
"schematic": { "schematic": {
"hierarchy_collapsed": [],
"selection_filter": { "selection_filter": {
"graphics": true, "graphics": true,
"images": true, "images": true,
@@ -126,7 +122,6 @@
"lockedItems": false, "lockedItems": false,
"otherItems": true, "otherItems": true,
"pins": true, "pins": true,
"ruleAreas": true,
"symbols": true, "symbols": true,
"text": true, "text": true,
"wires": true "wires": true

View File

@@ -3,8 +3,6 @@
"3dviewports": [], "3dviewports": [],
"design_settings": { "design_settings": {
"defaults": { "defaults": {
"apply_defaults_to_fp_barcodes": false,
"apply_defaults_to_fp_dimensions": false,
"apply_defaults_to_fp_fields": false, "apply_defaults_to_fp_fields": false,
"apply_defaults_to_fp_shapes": false, "apply_defaults_to_fp_shapes": false,
"apply_defaults_to_fp_text": false, "apply_defaults_to_fp_text": false,
@@ -84,7 +82,6 @@
"extra_footprint": "warning", "extra_footprint": "warning",
"footprint": "error", "footprint": "error",
"footprint_filters_mismatch": "ignore", "footprint_filters_mismatch": "ignore",
"footprint_symbol_field_mismatch": "warning",
"footprint_symbol_mismatch": "warning", "footprint_symbol_mismatch": "warning",
"footprint_type_mismatch": "warning", "footprint_type_mismatch": "warning",
"hole_clearance": "error", "hole_clearance": "error",
@@ -102,7 +99,6 @@
"mirrored_text_on_front_layer": "warning", "mirrored_text_on_front_layer": "warning",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",
"missing_footprint": "warning", "missing_footprint": "warning",
"missing_tuning_profile": "warning",
"net_conflict": "warning", "net_conflict": "warning",
"nonmirrored_text_on_back_layer": "warning", "nonmirrored_text_on_back_layer": "warning",
"npth_inside_courtyard": "ignore", "npth_inside_courtyard": "ignore",
@@ -122,12 +118,9 @@
"too_many_vias": "error", "too_many_vias": "error",
"track_angle": "error", "track_angle": "error",
"track_dangling": "warning", "track_dangling": "warning",
"track_not_centered_on_via": "ignore",
"track_on_post_machined_layer": "error",
"track_segment_length": "error", "track_segment_length": "error",
"track_width": "error", "track_width": "error",
"tracks_crossing": "error", "tracks_crossing": "error",
"tuning_profile_track_geometries": "ignore",
"unconnected_items": "error", "unconnected_items": "error",
"unresolved_variable": "error", "unresolved_variable": "error",
"via_dangling": "warning", "via_dangling": "warning",
@@ -243,28 +236,17 @@
"zones_allow_external_fillets": false "zones_allow_external_fillets": false
}, },
"ipc2581": { "ipc2581": {
"bom_rev": "",
"dist": "", "dist": "",
"distpn": "", "distpn": "",
"internal_id": "", "internal_id": "",
"mfg": "", "mfg": "",
"mpn": "", "mpn": ""
"sch_revision": ""
}, },
"layer_pairs": [], "layer_pairs": [],
"layer_presets": [], "layer_presets": [],
"viewports": [] "viewports": []
}, },
"boards": [], "boards": [],
"component_class_settings": {
"assignments": [],
"meta": {
"version": 0
},
"sheet_component_classes": {
"enabled": false
}
},
"cvpcb": { "cvpcb": {
"equivalence_files": [] "equivalence_files": []
}, },
@@ -513,14 +495,13 @@
"priority": 2147483647, "priority": 2147483647,
"schematic_color": "rgba(0, 0, 0, 0.000)", "schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.2, "track_width": 0.2,
"tuning_profile": "",
"via_diameter": 0.6, "via_diameter": 0.6,
"via_drill": 0.3, "via_drill": 0.3,
"wire_width": 6 "wire_width": 6
} }
], ],
"meta": { "meta": {
"version": 5 "version": 4
}, },
"net_colors": null, "net_colors": null,
"netclass_assignments": null, "netclass_assignments": null,
@@ -648,7 +629,6 @@
"sort_asc": true, "sort_asc": true,
"sort_field": "Reference" "sort_field": "Reference"
}, },
"bus_aliases": {},
"connection_grid_size": 50.0, "connection_grid_size": 50.0,
"drawing": { "drawing": {
"dashed_lines_dash_length_ratio": 12.0, "dashed_lines_dash_length_ratio": 12.0,
@@ -687,14 +667,7 @@
"spice_save_all_dissipations": false, "spice_save_all_dissipations": false,
"spice_save_all_voltages": false, "spice_save_all_voltages": false,
"subpart_first_id": 65, "subpart_first_id": 65,
"subpart_id_separator": 0, "subpart_id_separator": 0
"top_level_sheets": [
{
"filename": "PumpOutput.kicad_sch",
"name": "PumpOutput",
"uuid": "00000000-0000-0000-0000-000000000000"
}
]
}, },
"sheets": [ "sheets": [
[ [
@@ -702,11 +675,5 @@
"Root" "Root"
] ]
], ],
"text_variables": {}, "text_variables": {}
"tuning_profiles": {
"meta": {
"version": 0
},
"tuning_profiles_impedance_geometric": []
}
} }

View File

@@ -15,7 +15,6 @@
"vias": 1.0, "vias": 1.0,
"zones": 0.6 "zones": 0.6
}, },
"prototype_zone_fills": false,
"selection_filter": { "selection_filter": {
"dimensions": true, "dimensions": true,
"footprints": true, "footprints": true,
@@ -55,7 +54,6 @@
"zone_display_mode": 0 "zone_display_mode": 0
}, },
"git": { "git": {
"integration_disabled": false,
"repo_type": "", "repo_type": "",
"repo_username": "", "repo_username": "",
"ssh_key": "" "ssh_key": ""
@@ -108,7 +106,6 @@
"filter_text": "", "filter_text": "",
"group_by_constraint": false, "group_by_constraint": false,
"group_by_netclass": false, "group_by_netclass": false,
"show_time_domain_details": false,
"show_unconnected_nets": false, "show_unconnected_nets": false,
"show_zero_pad_nets": false, "show_zero_pad_nets": false,
"sort_ascending": true, "sort_ascending": true,
@@ -119,7 +116,6 @@
"files": [] "files": []
}, },
"schematic": { "schematic": {
"hierarchy_collapsed": [],
"selection_filter": { "selection_filter": {
"graphics": true, "graphics": true,
"images": true, "images": true,
@@ -127,7 +123,6 @@
"lockedItems": false, "lockedItems": false,
"otherItems": true, "otherItems": true,
"pins": true, "pins": true,
"ruleAreas": true,
"symbols": true, "symbols": true,
"text": true, "text": true,
"wires": true "wires": true

View File

@@ -3,8 +3,6 @@
"3dviewports": [], "3dviewports": [],
"design_settings": { "design_settings": {
"defaults": { "defaults": {
"apply_defaults_to_fp_barcodes": false,
"apply_defaults_to_fp_dimensions": false,
"apply_defaults_to_fp_fields": false, "apply_defaults_to_fp_fields": false,
"apply_defaults_to_fp_shapes": false, "apply_defaults_to_fp_shapes": false,
"apply_defaults_to_fp_text": false, "apply_defaults_to_fp_text": false,
@@ -79,7 +77,6 @@
"extra_footprint": "warning", "extra_footprint": "warning",
"footprint": "error", "footprint": "error",
"footprint_filters_mismatch": "warning", "footprint_filters_mismatch": "warning",
"footprint_symbol_field_mismatch": "warning",
"footprint_symbol_mismatch": "warning", "footprint_symbol_mismatch": "warning",
"footprint_type_mismatch": "warning", "footprint_type_mismatch": "warning",
"hole_clearance": "error", "hole_clearance": "error",
@@ -97,7 +94,6 @@
"mirrored_text_on_front_layer": "warning", "mirrored_text_on_front_layer": "warning",
"missing_courtyard": "warning", "missing_courtyard": "warning",
"missing_footprint": "warning", "missing_footprint": "warning",
"missing_tuning_profile": "warning",
"net_conflict": "warning", "net_conflict": "warning",
"nonmirrored_text_on_back_layer": "warning", "nonmirrored_text_on_back_layer": "warning",
"npth_inside_courtyard": "warning", "npth_inside_courtyard": "warning",
@@ -117,12 +113,9 @@
"too_many_vias": "error", "too_many_vias": "error",
"track_angle": "error", "track_angle": "error",
"track_dangling": "warning", "track_dangling": "warning",
"track_not_centered_on_via": "ignore",
"track_on_post_machined_layer": "error",
"track_segment_length": "error", "track_segment_length": "error",
"track_width": "error", "track_width": "error",
"tracks_crossing": "error", "tracks_crossing": "error",
"tuning_profile_track_geometries": "ignore",
"unconnected_items": "error", "unconnected_items": "error",
"unresolved_variable": "error", "unresolved_variable": "error",
"via_dangling": "warning", "via_dangling": "warning",
@@ -234,28 +227,17 @@
"zones_allow_external_fillets": false "zones_allow_external_fillets": false
}, },
"ipc2581": { "ipc2581": {
"bom_rev": "",
"dist": "", "dist": "",
"distpn": "", "distpn": "",
"internal_id": "", "internal_id": "",
"mfg": "", "mfg": "",
"mpn": "", "mpn": ""
"sch_revision": ""
}, },
"layer_pairs": [], "layer_pairs": [],
"layer_presets": [], "layer_presets": [],
"viewports": [] "viewports": []
}, },
"boards": [], "boards": [],
"component_class_settings": {
"assignments": [],
"meta": {
"version": 0
},
"sheet_component_classes": {
"enabled": false
}
},
"cvpcb": { "cvpcb": {
"equivalence_files": [] "equivalence_files": []
}, },
@@ -504,14 +486,13 @@
"priority": 2147483647, "priority": 2147483647,
"schematic_color": "rgba(0, 0, 0, 0.000)", "schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.2, "track_width": 0.2,
"tuning_profile": "",
"via_diameter": 0.6, "via_diameter": 0.6,
"via_drill": 0.3, "via_drill": 0.3,
"wire_width": 6 "wire_width": 6
} }
], ],
"meta": { "meta": {
"version": 5 "version": 4
}, },
"net_colors": null, "net_colors": null,
"netclass_assignments": null, "netclass_assignments": null,
@@ -880,7 +861,6 @@
"sort_asc": true, "sort_asc": true,
"sort_field": "Reference" "sort_field": "Reference"
}, },
"bus_aliases": {},
"connection_grid_size": 50.0, "connection_grid_size": 50.0,
"drawing": { "drawing": {
"dashed_lines_dash_length_ratio": 12.0, "dashed_lines_dash_length_ratio": 12.0,
@@ -919,14 +899,7 @@
"spice_save_all_dissipations": false, "spice_save_all_dissipations": false,
"spice_save_all_voltages": false, "spice_save_all_voltages": false,
"subpart_first_id": 65, "subpart_first_id": 65,
"subpart_id_separator": 0, "subpart_id_separator": 0
"top_level_sheets": [
{
"filename": "sensor.kicad_sch",
"name": "sensor",
"uuid": "00000000-0000-0000-0000-000000000000"
}
]
}, },
"sheets": [ "sheets": [
[ [
@@ -934,11 +907,5 @@
"Root" "Root"
] ]
], ],
"text_variables": {}, "text_variables": {}
"tuning_profiles": {
"meta": {
"version": 0
},
"tuning_profiles_impedance_geometric": []
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
"board": { "board": {
"active_layer": 0, "active_layer": 0,
"active_layer_preset": "", "active_layer_preset": "",
"auto_track_width": false, "auto_track_width": true,
"hidden_netclasses": [], "hidden_netclasses": [],
"hidden_nets": [], "hidden_nets": [],
"high_contrast_mode": 0, "high_contrast_mode": 0,
@@ -15,7 +15,6 @@
"vias": 1.0, "vias": 1.0,
"zones": 0.6 "zones": 0.6
}, },
"prototype_zone_fills": false,
"selection_filter": { "selection_filter": {
"dimensions": true, "dimensions": true,
"footprints": true, "footprints": true,
@@ -55,7 +54,6 @@
"zone_display_mode": 0 "zone_display_mode": 0
}, },
"git": { "git": {
"integration_disabled": false,
"repo_type": "", "repo_type": "",
"repo_username": "", "repo_username": "",
"ssh_key": "" "ssh_key": ""
@@ -65,30 +63,8 @@
"version": 5 "version": 5
}, },
"net_inspector_panel": { "net_inspector_panel": {
"col_hidden": [ "col_hidden": [],
false, "col_order": [],
false,
false,
false,
false,
false,
false,
false,
false,
false
],
"col_order": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9
],
"col_widths": [], "col_widths": [],
"custom_group_rules": [], "custom_group_rules": [],
"expanded_rows": [], "expanded_rows": [],
@@ -97,7 +73,6 @@
"filter_text": "", "filter_text": "",
"group_by_constraint": false, "group_by_constraint": false,
"group_by_netclass": false, "group_by_netclass": false,
"show_time_domain_details": false,
"show_unconnected_nets": false, "show_unconnected_nets": false,
"show_zero_pad_nets": false, "show_zero_pad_nets": false,
"sort_ascending": true, "sort_ascending": true,
@@ -108,7 +83,6 @@
"files": [] "files": []
}, },
"schematic": { "schematic": {
"hierarchy_collapsed": [],
"selection_filter": { "selection_filter": {
"graphics": true, "graphics": true,
"images": true, "images": true,
@@ -116,7 +90,6 @@
"lockedItems": false, "lockedItems": false,
"otherItems": true, "otherItems": true,
"pins": true, "pins": true,
"ruleAreas": true,
"symbols": true, "symbols": true,
"text": true, "text": true,
"wires": true "wires": true

View File

@@ -2,262 +2,25 @@
"board": { "board": {
"3dviewports": [], "3dviewports": [],
"design_settings": { "design_settings": {
"defaults": { "defaults": {},
"apply_defaults_to_fp_barcodes": false, "diff_pair_dimensions": [],
"apply_defaults_to_fp_dimensions": false,
"apply_defaults_to_fp_fields": false,
"apply_defaults_to_fp_shapes": false,
"apply_defaults_to_fp_text": false,
"board_outline_line_width": 0.05,
"copper_line_width": 0.2,
"copper_text_italic": false,
"copper_text_size_h": 1.5,
"copper_text_size_v": 1.5,
"copper_text_thickness": 0.3,
"copper_text_upright": false,
"courtyard_line_width": 0.05,
"dimension_precision": 4,
"dimension_units": 3,
"dimensions": {
"arrow_length": 1270000,
"extension_offset": 500000,
"keep_text_aligned": true,
"suppress_zeroes": true,
"text_position": 0,
"units_format": 0
},
"fab_line_width": 0.1,
"fab_text_italic": false,
"fab_text_size_h": 1.0,
"fab_text_size_v": 1.0,
"fab_text_thickness": 0.15,
"fab_text_upright": false,
"other_line_width": 0.1,
"other_text_italic": false,
"other_text_size_h": 1.0,
"other_text_size_v": 1.0,
"other_text_thickness": 0.15,
"other_text_upright": false,
"pads": {
"drill": 0.8,
"height": 1.27,
"width": 2.54
},
"silk_line_width": 0.1,
"silk_text_italic": false,
"silk_text_size_h": 1.0,
"silk_text_size_v": 1.0,
"silk_text_thickness": 0.1,
"silk_text_upright": false,
"zones": {
"min_clearance": 0.5
}
},
"diff_pair_dimensions": [
{
"gap": 0.0,
"via_gap": 0.0,
"width": 0.0
}
],
"drc_exclusions": [], "drc_exclusions": [],
"meta": { "rules": {},
"version": 2 "track_widths": [],
}, "via_dimensions": []
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"connection_width": "warning",
"copper_edge_clearance": "error",
"copper_sliver": "warning",
"courtyards_overlap": "error",
"creepage": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint": "error",
"footprint_filters_mismatch": "ignore",
"footprint_symbol_field_mismatch": "warning",
"footprint_symbol_mismatch": "warning",
"footprint_type_mismatch": "ignore",
"hole_clearance": "error",
"hole_to_hole": "warning",
"holes_co_located": "warning",
"invalid_outline": "error",
"isolated_copper": "warning",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"lib_footprint_issues": "warning",
"lib_footprint_mismatch": "warning",
"malformed_courtyard": "error",
"microvia_drill_out_of_range": "error",
"mirrored_text_on_front_layer": "warning",
"missing_courtyard": "ignore",
"missing_footprint": "warning",
"missing_tuning_profile": "warning",
"net_conflict": "warning",
"nonmirrored_text_on_back_layer": "warning",
"npth_inside_courtyard": "error",
"padstack": "warning",
"pth_inside_courtyard": "error",
"shorting_items": "error",
"silk_edge_clearance": "ignore",
"silk_over_copper": "warning",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"solder_mask_bridge": "error",
"starved_thermal": "error",
"text_height": "warning",
"text_on_edge_cuts": "error",
"text_thickness": "warning",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_angle": "error",
"track_dangling": "warning",
"track_not_centered_on_via": "ignore",
"track_on_post_machined_layer": "error",
"track_segment_length": "error",
"track_width": "error",
"tracks_crossing": "error",
"tuning_profile_track_geometries": "ignore",
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
"zones_intersect": "error"
},
"rules": {
"max_error": 0.005,
"min_clearance": 0.0,
"min_connection": 0.0,
"min_copper_edge_clearance": 0.5,
"min_groove_width": 0.0,
"min_hole_clearance": 0.25,
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.2,
"min_microvia_drill": 0.1,
"min_resolved_spokes": 2,
"min_silk_clearance": 0.0,
"min_text_height": 0.8,
"min_text_thickness": 0.08,
"min_through_hole_diameter": 0.3,
"min_track_width": 0.2,
"min_via_annular_width": 0.1,
"min_via_diameter": 0.5,
"solder_mask_to_copper_clearance": 0.005,
"use_height_for_length_calcs": true
},
"teardrop_options": [
{
"td_onpthpad": true,
"td_onroundshapesonly": false,
"td_onsmdpad": true,
"td_ontrackend": false,
"td_onvia": true
}
],
"teardrop_parameters": [
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_round_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_rect_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_track_end",
"td_width_to_size_filter_ratio": 0.9
}
],
"track_widths": [
0.0,
0.2,
0.5,
1.0,
2.0,
5.0
],
"tuning_pattern_settings": {
"diff_pair_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 1.0
},
"diff_pair_skew_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
},
"single_track_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
}
},
"via_dimensions": [
{
"diameter": 0.0,
"drill": 0.0
}
],
"zones_allow_external_fillets": false
}, },
"ipc2581": { "ipc2581": {
"bom_rev": "",
"dist": "", "dist": "",
"distpn": "", "distpn": "",
"internal_id": "", "internal_id": "",
"mfg": "", "mfg": "",
"mpn": "", "mpn": ""
"sch_revision": ""
}, },
"layer_pairs": [], "layer_pairs": [],
"layer_presets": [], "layer_presets": [],
"viewports": [] "viewports": []
}, },
"boards": [], "boards": [],
"component_class_settings": {
"assignments": [],
"meta": {
"version": 0
},
"sheet_component_classes": {
"enabled": false
}
},
"cvpcb": { "cvpcb": {
"equivalence_files": [] "equivalence_files": []
}, },
@@ -447,14 +210,11 @@
"duplicate_sheet_names": "error", "duplicate_sheet_names": "error",
"endpoint_off_grid": "warning", "endpoint_off_grid": "warning",
"extra_units": "error", "extra_units": "error",
"field_name_whitespace": "warning",
"footprint_filter": "ignore", "footprint_filter": "ignore",
"footprint_link_issues": "warning", "footprint_link_issues": "warning",
"four_way_junction": "ignore", "four_way_junction": "ignore",
"global_label_dangling": "warning", "global_label_dangling": "warning",
"ground_pin_not_ground": "warning",
"hier_label_mismatch": "error", "hier_label_mismatch": "error",
"isolated_pin_label": "warning",
"label_dangling": "error", "label_dangling": "error",
"label_multiple_wires": "warning", "label_multiple_wires": "warning",
"lib_symbol_issues": "warning", "lib_symbol_issues": "warning",
@@ -477,7 +237,6 @@
"similar_power": "warning", "similar_power": "warning",
"simulation_model_issue": "ignore", "simulation_model_issue": "ignore",
"single_global_label": "ignore", "single_global_label": "ignore",
"stacked_pin_name": "warning",
"unannotated": "error", "unannotated": "error",
"unconnected_wire_endpoint": "warning", "unconnected_wire_endpoint": "warning",
"undefined_netclass": "error", "undefined_netclass": "error",
@@ -510,14 +269,13 @@
"priority": 2147483647, "priority": 2147483647,
"schematic_color": "rgba(0, 0, 0, 0.000)", "schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.2, "track_width": 0.2,
"tuning_profile": "",
"via_diameter": 0.6, "via_diameter": 0.6,
"via_drill": 0.3, "via_drill": 0.3,
"wire_width": 6 "wire_width": 6
} }
], ],
"meta": { "meta": {
"version": 5 "version": 4
}, },
"net_colors": null, "net_colors": null,
"netclass_assignments": null, "netclass_assignments": null,
@@ -539,10 +297,6 @@
}, },
"schematic": { "schematic": {
"annotate_start_num": 0, "annotate_start_num": 0,
"annotation": {
"method": 0,
"sort_order": 0
},
"bom_export_filename": "${PROJECTNAME}.csv", "bom_export_filename": "${PROJECTNAME}.csv",
"bom_fmt_presets": [], "bom_fmt_presets": [],
"bom_fmt_settings": { "bom_fmt_settings": {
@@ -605,298 +359,15 @@
"label": "Datasheet", "label": "Datasheet",
"name": "Datasheet", "name": "Datasheet",
"show": true "show": true
},
{
"group_by": false,
"label": "Actuator/Cap Color",
"name": "Actuator/Cap Color",
"show": false
},
{
"group_by": false,
"label": "Attrition Qty",
"name": "Attrition Qty",
"show": false
},
{
"group_by": false,
"label": "Capacitance",
"name": "Capacitance",
"show": false
},
{
"group_by": false,
"label": "Category",
"name": "Category",
"show": false
},
{
"group_by": false,
"label": "Circuit",
"name": "Circuit",
"show": false
},
{
"group_by": false,
"label": "Class",
"name": "Class",
"show": false
},
{
"group_by": false,
"label": "Contact Current",
"name": "Contact Current",
"show": false
},
{
"group_by": false,
"label": "Diode Configuration",
"name": "Diode Configuration",
"show": false
},
{
"group_by": false,
"label": "Field5",
"name": "Field5",
"show": false
},
{
"group_by": false,
"label": "Forward Voltage (Vf@If)",
"name": "Forward Voltage (Vf@If)",
"show": false
},
{
"group_by": false,
"label": "Insulation Resistance",
"name": "Insulation Resistance",
"show": false
},
{
"group_by": false,
"label": "LCSC",
"name": "LCSC",
"show": false
},
{
"group_by": false,
"label": "LCSC_PART_NUMBER",
"name": "LCSC_PART_NUMBER",
"show": false
},
{
"group_by": false,
"label": "Manufacturer",
"name": "Manufacturer",
"show": false
},
{
"group_by": false,
"label": "Mechanical Life",
"name": "Mechanical Life",
"show": false
},
{
"group_by": false,
"label": "Minimum Qty",
"name": "Minimum Qty",
"show": false
},
{
"group_by": false,
"label": "Mounting Style",
"name": "Mounting Style",
"show": false
},
{
"group_by": false,
"label": "Operating Force",
"name": "Operating Force",
"show": false
},
{
"group_by": false,
"label": "Operating Temperature",
"name": "Operating Temperature",
"show": false
},
{
"group_by": false,
"label": "Operating Temperature Range",
"name": "Operating Temperature Range",
"show": false
},
{
"group_by": false,
"label": "Overload Voltage (Max)",
"name": "Overload Voltage (Max)",
"show": false
},
{
"group_by": false,
"label": "Part",
"name": "Part",
"show": false
},
{
"group_by": false,
"label": "Pin Style",
"name": "Pin Style",
"show": false
},
{
"group_by": false,
"label": "Power(Watts)",
"name": "Power(Watts)",
"show": false
},
{
"group_by": false,
"label": "Price",
"name": "Price",
"show": false
},
{
"group_by": false,
"label": "Process",
"name": "Process",
"show": false
},
{
"group_by": false,
"label": "Rectified Current",
"name": "Rectified Current",
"show": false
},
{
"group_by": false,
"label": "Resistance",
"name": "Resistance",
"show": false
},
{
"group_by": false,
"label": "Reverse Leakage Current",
"name": "Reverse Leakage Current",
"show": false
},
{
"group_by": false,
"label": "Reverse Voltage (Vr)",
"name": "Reverse Voltage (Vr)",
"show": false
},
{
"group_by": false,
"label": "Sim.Device",
"name": "Sim.Device",
"show": false
},
{
"group_by": false,
"label": "Sim.Pins",
"name": "Sim.Pins",
"show": false
},
{
"group_by": false,
"label": "Sim.Type",
"name": "Sim.Type",
"show": false
},
{
"group_by": false,
"label": "Stock",
"name": "Stock",
"show": false
},
{
"group_by": false,
"label": "Strike Gundam",
"name": "Strike Gundam",
"show": false
},
{
"group_by": false,
"label": "Switch Height",
"name": "Switch Height",
"show": false
},
{
"group_by": false,
"label": "Switch Length",
"name": "Switch Length",
"show": false
},
{
"group_by": false,
"label": "Switch Width",
"name": "Switch Width",
"show": false
},
{
"group_by": false,
"label": "Temperature Coefficient",
"name": "Temperature Coefficient",
"show": false
},
{
"group_by": false,
"label": "Tolerance",
"name": "Tolerance",
"show": false
},
{
"group_by": false,
"label": "Type",
"name": "Type",
"show": false
},
{
"group_by": false,
"label": "Voltage Rated",
"name": "Voltage Rated",
"show": false
},
{
"group_by": false,
"label": "Voltage Rating (Dc)",
"name": "Voltage Rating (Dc)",
"show": false
},
{
"group_by": false,
"label": "With Lamp",
"name": "With Lamp",
"show": false
},
{
"group_by": false,
"label": "Actuator Style",
"name": "Actuator Style",
"show": false
},
{
"group_by": false,
"label": "Description",
"name": "Description",
"show": false
},
{
"group_by": false,
"label": "#",
"name": "${ITEM_NUMBER}",
"show": false
} }
], ],
"filter_string": "", "filter_string": "",
"group_symbols": true, "group_symbols": true,
"include_excluded_from_bom": true, "include_excluded_from_bom": true,
"name": "", "name": "Default Editing",
"sort_asc": true, "sort_asc": true,
"sort_field": "Reference" "sort_field": "Reference"
}, },
"bus_aliases": {},
"connection_grid_size": 50.0, "connection_grid_size": 50.0,
"drawing": { "drawing": {
"dashed_lines_dash_length_ratio": 12.0, "dashed_lines_dash_length_ratio": 12.0,
@@ -904,7 +375,6 @@
"default_line_thickness": 6.0, "default_line_thickness": 6.0,
"default_text_size": 50.0, "default_text_size": 50.0,
"field_names": [], "field_names": [],
"hop_over_size_choice": 0,
"intersheets_ref_own_page": false, "intersheets_ref_own_page": false,
"intersheets_ref_prefix": "", "intersheets_ref_prefix": "",
"intersheets_ref_short": false, "intersheets_ref_short": false,
@@ -928,7 +398,6 @@
"net_format_name": "", "net_format_name": "",
"page_layout_descr_file": "", "page_layout_descr_file": "",
"plot_directory": "", "plot_directory": "",
"reuse_designators": true,
"space_save_all_events": true, "space_save_all_events": true,
"spice_current_sheet_as_root": false, "spice_current_sheet_as_root": false,
"spice_external_command": "spice \"%I\"", "spice_external_command": "spice \"%I\"",
@@ -937,28 +406,13 @@
"spice_save_all_dissipations": false, "spice_save_all_dissipations": false,
"spice_save_all_voltages": false, "spice_save_all_voltages": false,
"subpart_first_id": 65, "subpart_first_id": 65,
"subpart_id_separator": 0, "subpart_id_separator": 0
"top_level_sheets": [
{
"filename": "bms.kicad_sch",
"name": "bms",
"uuid": "7972d0e7-2611-420d-b298-ef8307db6186"
}
],
"used_designators": "",
"variants": []
}, },
"sheets": [ "sheets": [
[ [
"7972d0e7-2611-420d-b298-ef8307db6186", "7972d0e7-2611-420d-b298-ef8307db6186",
"bms" "Root"
] ]
], ],
"text_variables": {}, "text_variables": {}
"tuning_profiles": {
"meta": {
"version": 0
},
"tuning_profiles_impedance_geometric": []
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
{"ARCHIVE_NAME": "", "EXTRA_LAYERS": "", "ALL_ACTIVE_LAYERS": false, "EXTEND_EDGE_CUT": false, "ALTERNATIVE_EDGE_CUT": false, "AUTO TRANSLATE": true, "AUTO FILL": true, "EXCLUDE DNP": false, "OPEN BROWSER": true, "NO_BACKUP_OPT": false}

View File

@@ -1,337 +0,0 @@
(footprint "AMASS_XT30UPB+DATA-M_1x02_P5.0mm_Vertical"
(version 20240108)
(generator "pcbnew")
(generator_version "8.0")
(layer "F.Cu")
(descr "Connector XT30 Vertical PCB Male, https://www.tme.eu/en/Document/4acc913878197f8c2e30d4b8cdc47230/XT30UPB%20SPEC.pdf")
(tags "RC Connector XT30")
(property "Reference" "REF**"
(at 2.5 -4 0)
(layer "F.SilkS")
(uuid "f7510d54-dcb1-4c3b-b842-cd250a98370c")
(effects
(font
(size 1 1)
(thickness 0.15)
)
)
)
(property "Value" "AMASS_XT30UPB+DATA-M_1x02_P5.0mm_Vertical"
(at 2.5 4 0)
(layer "F.Fab")
(uuid "c5a8a60c-4ea1-4401-a30c-34d36be61c07")
(effects
(font
(size 1 1)
(thickness 0.15)
)
)
)
(property "Footprint" ""
(at 0 0 0)
(unlocked yes)
(layer "F.Fab")
(hide yes)
(uuid "8fb27306-c085-4316-b554-4ba9be794054")
(effects
(font
(size 1.27 1.27)
(thickness 0.15)
)
)
)
(property "Datasheet" ""
(at 0 0 0)
(unlocked yes)
(layer "F.Fab")
(hide yes)
(uuid "74b71861-05d2-4229-8e81-25952aaaef7e")
(effects
(font
(size 1.27 1.27)
(thickness 0.15)
)
)
)
(property "Description" ""
(at 0 0 0)
(unlocked yes)
(layer "F.Fab")
(hide yes)
(uuid "a1d16ecc-7e64-48c4-b772-a9255380960d")
(effects
(font
(size 1.27 1.27)
(thickness 0.15)
)
)
)
(attr through_hole)
(fp_line
(start -2.71 -1.41)
(end -2.71 1.41)
(stroke
(width 0.12)
(type solid)
)
(layer "F.SilkS")
(uuid "e96c6ad2-9ca6-4df1-b35b-76e090d7ff4e")
)
(fp_line
(start -2.71 -1.41)
(end -1.01 -2.71)
(stroke
(width 0.12)
(type solid)
)
(layer "F.SilkS")
(uuid "0784d204-0a48-4a2b-8085-50e1ff7a1493")
)
(fp_line
(start -2.71 1.41)
(end -1.01 2.71)
(stroke
(width 0.12)
(type solid)
)
(layer "F.SilkS")
(uuid "db750970-e424-4a8e-a882-20a90baabffc")
)
(fp_line
(start -1.01 -2.71)
(end 7.71 -2.71)
(stroke
(width 0.12)
(type solid)
)
(layer "F.SilkS")
(uuid "9f23420e-db87-438c-a708-676a0616966e")
)
(fp_line
(start -1.01 2.71)
(end 7.71 2.71)
(stroke
(width 0.12)
(type solid)
)
(layer "F.SilkS")
(uuid "2ba574e3-9de5-4d7d-9777-e19e6fa702e7")
)
(fp_line
(start 7.71 -2.71)
(end 7.71 2.71)
(stroke
(width 0.12)
(type solid)
)
(layer "F.SilkS")
(uuid "2018cc6b-6115-4763-8b7c-54b60affbda7")
)
(fp_rect
(start -6.3 -2.71)
(end 7.71 2.7)
(stroke
(width 0.1)
(type default)
)
(fill none)
(layer "F.SilkS")
(uuid "11aac399-c862-4b67-9828-087abeea5b1b")
)
(fp_line
(start -3.1 -1.8)
(end -3.1 1.8)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "06ae69d8-1372-4524-8b1a-27a2f062f1c5")
)
(fp_line
(start -3.1 -1.8)
(end -1.4 -3.1)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "ae869a92-c688-4f2b-82ca-0578106a035a")
)
(fp_line
(start -3.1 1.8)
(end -1.4 3.1)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "cac6d927-6ba1-4095-825b-f94ee0d7abe9")
)
(fp_line
(start -1.4 -3.1)
(end 8.1 -3.1)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "fb4fa373-5492-4717-a9fe-7b69f4c53ba0")
)
(fp_line
(start -1.4 3.1)
(end 8.1 3.1)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "70296c77-546d-44a2-b5d3-e6dc58cf713b")
)
(fp_line
(start 8.1 -3.1)
(end 8.1 3.1)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "64764a09-de32-4f35-b54a-17e44810370f")
)
(fp_line
(start -2.6 -1.3)
(end -2.6 1.3)
(stroke
(width 0.1)
(type solid)
)
(layer "F.Fab")
(uuid "8d7ee7cb-5dda-453f-aa9a-6420c87f1b8e")
)
(fp_line
(start -2.6 -1.3)
(end -0.9 -2.6)
(stroke
(width 0.1)
(type solid)
)
(layer "F.Fab")
(uuid "2fa3ad90-36bb-4374-95ed-e44e50c7e385")
)
(fp_line
(start -2.6 1.3)
(end -0.9 2.6)
(stroke
(width 0.1)
(type solid)
)
(layer "F.Fab")
(uuid "2e4f8556-ffc2-4791-91da-e68c3513337e")
)
(fp_line
(start -0.9 -2.6)
(end 7.6 -2.6)
(stroke
(width 0.1)
(type solid)
)
(layer "F.Fab")
(uuid "cb9cd8af-1997-41db-b9fe-8982960ac6db")
)
(fp_line
(start -0.9 2.6)
(end 7.6 2.6)
(stroke
(width 0.1)
(type solid)
)
(layer "F.Fab")
(uuid "ea8a6c02-e974-4677-a854-a0891c323245")
)
(fp_line
(start 7.6 -2.6)
(end 7.6 2.6)
(stroke
(width 0.1)
(type solid)
)
(layer "F.Fab")
(uuid "c66f305c-0d56-4591-bc02-23252ad20321")
)
(fp_text user "-"
(at -4 0 0)
(layer "F.SilkS")
(uuid "c119570a-6846-48dc-9422-0b5665ab2df6")
(effects
(font
(size 1.5 1.5)
(thickness 0.15)
)
)
)
(fp_text user "+"
(at 9 0 0)
(layer "F.SilkS")
(uuid "d6ab678c-47f7-47e0-869b-ef3b9dbd1ba9")
(effects
(font
(size 1.5 1.5)
(thickness 0.15)
)
)
)
(fp_text user "${REFERENCE}"
(at 2.5 0 0)
(layer "F.Fab")
(uuid "a70efd12-1491-4664-ae98-5b2b7f52a502")
(effects
(font
(size 1 1)
(thickness 0.15)
)
)
)
(pad "1" thru_hole rect
(at 0 0)
(size 3 3)
(drill 1.8)
(layers "*.Cu" "*.Mask")
(remove_unused_layers no)
(uuid "3a0f3b23-814b-4df9-a02c-3d9fed9e23c9")
)
(pad "2" thru_hole circle
(at 5 0)
(size 3 3)
(drill 1.8)
(layers "*.Cu" "*.Mask")
(remove_unused_layers no)
(uuid "d897d74a-a13b-47cf-9806-eb8a75fe8d08")
)
(pad "3" thru_hole circle
(at -3.9 -1)
(size 1.524 1.524)
(drill 1)
(layers "*.Cu" "*.Mask")
(remove_unused_layers no)
(uuid "02a8c3fc-d75c-47a4-a907-f9191ff19e2c")
)
(pad "4" thru_hole circle
(at -3.9 1)
(size 1.524 1.524)
(drill 1)
(layers "*.Cu" "*.Mask")
(remove_unused_layers no)
(uuid "2000b5b8-f7c9-40a8-9010-65c16d2aefce")
)
(model "${KICAD8_3DMODEL_DIR}/Connector_AMASS.3dshapes/AMASS_XT30UPB-M_1x02_P5.0mm_Vertical.wrl"
(offset
(xyz 0 0 0)
)
(scale
(xyz 1 1 1)
)
(rotate
(xyz 0 0 0)
)
)
)

View File

@@ -1,4 +0,0 @@
(fp_lib_table
(version 7)
(lib (name "amass") (type "KiCad") (uri "${KIPRJMOD}/footprints/amass") (options "") (descr ""))
)

View File

@@ -115,7 +115,7 @@ littlefs2-core = "0.1.2"
# Serialization / codecs # Serialization / codecs
serde = { version = "1.0.228", features = ["derive", "alloc"], default-features = false } serde = { version = "1.0.228", features = ["derive", "alloc"], default-features = false }
serde_json = { version = "1.0.145", default-features = false, features = ["alloc"] } serde_json = { version = "1.0.145", default-features = false, features = ["alloc"] }
bincode = { version = "2.0.1", default-features = false, features = ["derive"] } bincode = { version = "2.0.1", default-features = false, features = ["derive", "alloc"] }
# Time and time zones # Time and time zones
chrono = { version = "0.4.42", default-features = false, features = ["iana-time-zone", "alloc", "serde"] } chrono = { version = "0.4.42", default-features = false, features = ["iana-time-zone", "alloc", "serde"] }
@@ -136,6 +136,7 @@ measurements = "0.11.1"
# Project-specific # Project-specific
mcutie = { version = "0.3.0", default-features = false, features = ["log", "homeassistant"] } mcutie = { version = "0.3.0", default-features = false, features = ["log", "homeassistant"] }
no-panic = "0.1.36"
[patch.crates-io] [patch.crates-io]
mcutie = { git = 'https://github.com/empirephoenix/mcutie.git' } mcutie = { git = 'https://github.com/empirephoenix/mcutie.git' }

View File

@@ -0,0 +1,2 @@
# This file is used for clippy configuration.
# It shouldn't contain the deny attributes, which belong to the crate root.

View File

@@ -1,17 +1,17 @@
use crate::hal::PLANT_COUNT; use crate::hal::PLANT_COUNT;
use crate::plant_state::PlantWateringMode; use crate::plant_state::PlantWateringMode;
use alloc::string::String; use alloc::string::{String, ToString};
use core::str::FromStr; use bincode::{Decode, Encode};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Encode, Decode)]
#[serde(default)] #[serde(default)]
pub struct NetworkConfig { pub struct NetworkConfig {
pub ap_ssid: heapless::String<32>, pub ap_ssid: String,
pub ssid: Option<heapless::String<32>>, pub ssid: Option<String>,
pub password: Option<heapless::String<64>>, pub password: Option<String>,
pub mqtt_url: Option<String>, pub mqtt_url: Option<String>,
pub base_topic: Option<heapless::String<64>>, pub base_topic: Option<String>,
pub mqtt_user: Option<String>, pub mqtt_user: Option<String>,
pub mqtt_password: Option<String>, pub mqtt_password: Option<String>,
pub max_wait: u32, pub max_wait: u32,
@@ -19,7 +19,7 @@ pub struct NetworkConfig {
impl Default for NetworkConfig { impl Default for NetworkConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
ap_ssid: heapless::String::from_str("PlantCtrl Init").unwrap(), ap_ssid: "PlantCtrl Init".to_string(),
ssid: None, ssid: None,
password: None, password: None,
mqtt_url: None, mqtt_url: None,
@@ -31,7 +31,7 @@ impl Default for NetworkConfig {
} }
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Encode, Decode)]
#[serde(default)] #[serde(default)]
pub struct NightLampConfig { pub struct NightLampConfig {
pub enabled: bool, pub enabled: bool,
@@ -54,7 +54,7 @@ impl Default for NightLampConfig {
} }
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Encode, Decode)]
#[serde(default)] #[serde(default)]
pub struct TankConfig { pub struct TankConfig {
pub tank_sensor_enabled: bool, pub tank_sensor_enabled: bool,
@@ -79,26 +79,26 @@ impl Default for TankConfig {
} }
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, Encode, Decode)]
pub enum BatteryBoardVersion { pub enum BatteryBoardVersion {
#[default] #[default]
Disabled, Disabled,
WchI2cSlave, WchI2cSlave,
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, Encode, Decode)]
pub enum BoardVersion { pub enum BoardVersion {
Initial, Initial,
#[default] #[default]
V4, V4,
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, Encode, Decode)]
pub struct BoardHardware { pub struct BoardHardware {
pub board: BoardVersion, pub board: BoardVersion,
pub battery: BatteryBoardVersion, pub battery: BatteryBoardVersion,
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, Encode, Decode)]
#[serde(default)] #[serde(default)]
pub struct PlantControllerConfig { pub struct PlantControllerConfig {
pub hardware: BoardHardware, pub hardware: BoardHardware,
@@ -109,7 +109,7 @@ pub struct PlantControllerConfig {
pub timezone: Option<String>, pub timezone: Option<String>,
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Encode, Decode)]
#[serde(default)] #[serde(default)]
pub struct PlantConfig { pub struct PlantConfig {
pub mode: PlantWateringMode, pub mode: PlantWateringMode,

View File

@@ -1,5 +1,7 @@
use alloc::format; use alloc::format;
use alloc::string::{String, ToString}; use alloc::string::{String, ToString};
use chrono::format::ParseErrorKind;
use chrono_tz::ParseError;
use core::convert::Infallible; use core::convert::Infallible;
use core::fmt; use core::fmt;
use core::fmt::Debug; use core::fmt::Debug;
@@ -149,6 +151,23 @@ impl<T> ContextExt<T> for Option<T> {
} }
} }
impl<T, E> ContextExt<T> for Result<T, E>
where
E: fmt::Debug,
{
fn context<C>(self, context: C) -> Result<T, FatError>
where
C: AsRef<str>,
{
match self {
Ok(value) => Ok(value),
Err(err) => Err(FatError::String {
error: format!("{}: {:?}", context.as_ref(), err),
}),
}
}
}
impl From<Error<Infallible>> for FatError { impl From<Error<Infallible>> for FatError {
fn from(error: Error<Infallible>) -> Self { fn from(error: Error<Infallible>) -> Self {
FatError::OneWireError { error } FatError::OneWireError { error }
@@ -283,7 +302,7 @@ impl<E: fmt::Debug> From<ShuntVoltageReadError<I2cDeviceError<E>>> for FatError
impl From<Infallible> for FatError { impl From<Infallible> for FatError {
fn from(value: Infallible) -> Self { fn from(value: Infallible) -> Self {
panic!("Infallible error: {:?}", value) match value {}
} }
} }
@@ -336,3 +355,27 @@ impl From<BmsProtocolError> for FatError {
} }
} }
} }
impl From<ParseError> for FatError {
fn from(value: ParseError) -> Self {
FatError::String {
error: format!("Parsing error: {value:?}"),
}
}
}
impl From<ParseErrorKind> for FatError {
fn from(value: ParseErrorKind) -> Self {
FatError::String {
error: format!("Parsing error: {value:?}"),
}
}
}
impl From<chrono::format::ParseError> for FatError {
fn from(value: chrono::format::ParseError) -> Self {
FatError::String {
error: format!("Parsing error: {value:?}"),
}
}
}

View File

@@ -314,17 +314,19 @@ impl Esp<'_> {
&mut tx_meta, &mut tx_meta,
&mut tx_buffer, &mut tx_buffer,
); );
socket.bind(123).unwrap(); socket.bind(123).context("Could not bind UDP socket")?;
let context = NtpContext::new(Timestamp::default()); let context = NtpContext::new(Timestamp::default());
let ntp_addrs = stack let ntp_addrs = stack
.dns_query(NTP_SERVER, DnsQueryType::A) .dns_query(NTP_SERVER, DnsQueryType::A)
.await; .await
if ntp_addrs.is_err() { .context("Failed to resolve DNS")?;
bail!("Failed to resolve DNS");
if ntp_addrs.is_empty() {
bail!("No IP addresses found for NTP server");
} }
let ntp = ntp_addrs.unwrap()[0]; let ntp = ntp_addrs[0];
info!("NTP server: {ntp:?}"); info!("NTP server: {ntp:?}");
let mut counter = 0; let mut counter = 0;
@@ -416,9 +418,14 @@ impl Esp<'_> {
Err(_) => "PlantCtrl Emergency Mode".to_string(), Err(_) => "PlantCtrl Emergency Mode".to_string(),
}; };
let device = self.interface_ap.take().unwrap(); let device = self
.interface_ap
.take()
.context("AP interface already taken")?;
let gw_ip_addr_str = "192.168.71.1"; let gw_ip_addr_str = "192.168.71.1";
let gw_ip_addr = Ipv4Addr::from_str(gw_ip_addr_str).expect("failed to parse gateway ip"); let gw_ip_addr = Ipv4Addr::from_str(gw_ip_addr_str).map_err(|_| FatError::String {
error: "failed to parse gateway ip".to_string(),
})?;
let config = embassy_net::Config::ipv4_static(StaticConfigV4 { let config = embassy_net::Config::ipv4_static(StaticConfigV4 {
address: Ipv4Cidr::new(gw_ip_addr, 24), address: Ipv4Cidr::new(gw_ip_addr, 24),
@@ -472,18 +479,17 @@ impl Esp<'_> {
spawner: Spawner, spawner: Spawner,
) -> FatResult<Stack<'static>> { ) -> FatResult<Stack<'static>> {
esp_radio::wifi_set_log_verbose(); esp_radio::wifi_set_log_verbose();
let ssid = network_config.ssid.clone(); let ssid = match &network_config.ssid {
match &ssid {
Some(ssid) => { Some(ssid) => {
if ssid.is_empty() { if ssid.is_empty() {
bail!("Wifi ssid was empty") bail!("Wifi ssid was empty")
} }
ssid.to_string()
} }
None => { None => {
bail!("Wifi ssid was empty") bail!("Wifi ssid was empty")
} }
} };
let ssid = ssid.unwrap().to_string();
info!("attempting to connect wifi {ssid}"); info!("attempting to connect wifi {ssid}");
let password = match network_config.password { let password = match network_config.password {
Some(ref password) => password.to_string(), Some(ref password) => password.to_string(),
@@ -491,7 +497,10 @@ impl Esp<'_> {
}; };
let max_wait = network_config.max_wait; let max_wait = network_config.max_wait;
let device = self.interface_sta.take().unwrap(); let device = self
.interface_sta
.take()
.context("STA interface already taken")?;
let config = embassy_net::Config::dhcpv4(DhcpConfig::default()); let config = embassy_net::Config::dhcpv4(DhcpConfig::default());
let seed = (self.rng.random() as u64) << 32 | self.rng.random() as u64; let seed = (self.rng.random() as u64) << 32 | self.rng.random() as u64;
@@ -596,9 +605,9 @@ impl Esp<'_> {
if let Ok(cur) = self.ota.current_ota_state() { if let Ok(cur) = self.ota.current_ota_state() {
if cur == OtaImageState::PendingVerify { if cur == OtaImageState::PendingVerify {
info!("Marking OTA image as valid"); info!("Marking OTA image as valid");
self.ota if let Err(err) = self.ota.set_current_ota_state(Valid) {
.set_current_ota_state(Valid) error!("Could not set image to valid: {:?}", err);
.expect("Could not set image to valid"); }
} }
} else { } else {
info!("No OTA image to mark as valid"); info!("No OTA image to mark as valid");
@@ -749,11 +758,11 @@ impl Esp<'_> {
let mut builder: McutieBuilder<'_, String, PublishDisplay<String, &str>, 0> = let mut builder: McutieBuilder<'_, String, PublishDisplay<String, &str>, 0> =
McutieBuilder::new(stack, "plant ctrl", mqtt_url); McutieBuilder::new(stack, "plant ctrl", mqtt_url);
if network_config.mqtt_user.is_some() && network_config.mqtt_password.is_some() { if let (Some(mqtt_user), Some(mqtt_password)) = (
builder = builder.with_authentication( network_config.mqtt_user.as_ref(),
network_config.mqtt_user.as_ref().unwrap().as_str(), network_config.mqtt_password.as_ref(),
network_config.mqtt_password.as_ref().unwrap().as_str(), ) {
); builder = builder.with_authentication(mqtt_user, mqtt_password);
info!("With authentification"); info!("With authentification");
} }
@@ -805,11 +814,10 @@ impl Esp<'_> {
Timer::after(Duration::from_millis(100)).await; Timer::after(Duration::from_millis(100)).await;
} }
Topic::General(round_trip_topic.clone()) let _ = Topic::General(round_trip_topic.clone())
.with_display("online_text") .with_display("online_text")
.publish() .publish()
.await .await;
.unwrap();
let timeout = { let timeout = {
let guard = TIME_ACCESS.get().await.lock().await; let guard = TIME_ACCESS.get().await.lock().await;
@@ -971,7 +979,13 @@ async fn run_dhcp(stack: Stack<'static>, gw_ip_addr: &'static str) {
use edge_nal::UdpBind; use edge_nal::UdpBind;
use edge_nal_embassy::{Udp, UdpBuffers}; use edge_nal_embassy::{Udp, UdpBuffers};
let ip = Ipv4Addr::from_str(gw_ip_addr).expect("dhcp task failed to parse gw ip"); let ip = match Ipv4Addr::from_str(gw_ip_addr) {
Ok(ip) => ip,
Err(_) => {
error!("dhcp task failed to parse gw ip");
return;
}
};
let mut buf = [0u8; 1500]; let mut buf = [0u8; 1500];
@@ -979,13 +993,19 @@ async fn run_dhcp(stack: Stack<'static>, gw_ip_addr: &'static str) {
let buffers = UdpBuffers::<3, 1024, 1024, 10>::new(); let buffers = UdpBuffers::<3, 1024, 1024, 10>::new();
let unbound_socket = Udp::new(stack, &buffers); let unbound_socket = Udp::new(stack, &buffers);
let mut bound_socket = unbound_socket let mut bound_socket = match unbound_socket
.bind(SocketAddr::V4(SocketAddrV4::new( .bind(SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::UNSPECIFIED, Ipv4Addr::UNSPECIFIED,
DEFAULT_SERVER_PORT, DEFAULT_SERVER_PORT,
))) )))
.await .await
.unwrap(); {
Ok(s) => s,
Err(e) => {
error!("dhcp task failed to bind socket: {:?}", e);
return;
}
};
loop { loop {
_ = io::server::run( _ = io::server::run(

View File

@@ -10,7 +10,7 @@ mod v4_hal;
mod water; mod water;
use crate::alloc::string::ToString; use crate::alloc::string::ToString;
use crate::hal::rtc::{DS3231Module, RTCModuleInteraction}; use crate::hal::rtc::{BackupHeader, DS3231Module, RTCModuleInteraction};
use esp_hal::peripherals::Peripherals; use esp_hal::peripherals::Peripherals;
use esp_hal::peripherals::ADC1; use esp_hal::peripherals::ADC1;
use esp_hal::peripherals::GPIO0; use esp_hal::peripherals::GPIO0;
@@ -164,6 +164,10 @@ pub trait BoardInteraction<'a> {
async fn get_mptt_current(&mut self) -> FatResult<Current>; async fn get_mptt_current(&mut self) -> FatResult<Current>;
async fn can_power(&mut self, state: bool) -> FatResult<()>; async fn can_power(&mut self, state: bool) -> FatResult<()>;
async fn backup_config(&mut self, config: &PlantControllerConfig) -> FatResult<()>;
async fn read_backup(&mut self) -> FatResult<PlantControllerConfig>;
async fn backup_info(&mut self) -> FatResult<BackupHeader>;
// Return JSON string with autodetected sensors per plant. Default: not supported. // Return JSON string with autodetected sensors per plant. Default: not supported.
async fn detect_sensors(&mut self, _request: Detection) -> FatResult<Detection> { async fn detect_sensors(&mut self, _request: Detection) -> FatResult<Detection> {
bail!("Autodetection is only available on v4 HAL with CAN bus"); bail!("Autodetection is only available on v4 HAL with CAN bus");
@@ -266,12 +270,17 @@ impl PlantHal {
let rng = Rng::new(); let rng = Rng::new();
let esp_wifi_ctrl = &*mk_static!( let esp_wifi_ctrl = &*mk_static!(
Controller<'static>, Controller<'static>,
init().expect("Could not init wifi controller") init().map_err(|e| FatError::String {
error: format!("Could not init wifi controller: {:?}", e)
})?
); );
let (controller, interfaces) = let (controller, interfaces) =
esp_radio::wifi::new(esp_wifi_ctrl, peripherals.WIFI, Default::default()) esp_radio::wifi::new(esp_wifi_ctrl, peripherals.WIFI, Default::default()).map_err(
.expect("Could not init wifi"); |e| FatError::String {
error: format!("Could not init wifi: {:?}", e),
},
)?;
let pcnt_module = Pcnt::new(peripherals.PCNT); let pcnt_module = Pcnt::new(peripherals.PCNT);
@@ -325,7 +334,7 @@ impl PlantHal {
pt.find_partition(esp_bootloader_esp_idf::partitions::PartitionType::Data( pt.find_partition(esp_bootloader_esp_idf::partitions::PartitionType::Data(
DataPartitionSubType::Ota, DataPartitionSubType::Ota,
))? ))?
.expect("No OTA data partition found") .context("No OTA data partition found")?
); );
let ota_data = mk_static!( let ota_data = mk_static!(
@@ -370,7 +379,7 @@ impl PlantHal {
.find_partition(esp_bootloader_esp_idf::partitions::PartitionType::Data( .find_partition(esp_bootloader_esp_idf::partitions::PartitionType::Data(
DataPartitionSubType::LittleFs, DataPartitionSubType::LittleFs,
))? ))?
.expect("Data partition with littlefs not found"); .context("Data partition with littlefs not found")?;
let data_partition = mk_static!(PartitionEntry, data_partition); let data_partition = mk_static!(PartitionEntry, data_partition);
let data = mk_static!( let data = mk_static!(
@@ -394,7 +403,8 @@ impl PlantHal {
#[allow(clippy::arc_with_non_send_sync)] #[allow(clippy::arc_with_non_send_sync)]
let fs = Arc::new(Mutex::new( let fs = Arc::new(Mutex::new(
lfs2Filesystem::mount(alloc, lfs2filesystem).expect("Could not mount lfs2 filesystem"), lfs2Filesystem::mount(alloc, lfs2filesystem)
.context("Could not mount lfs2 filesystem")?,
)); ));
let uart0 = let uart0 =
@@ -488,7 +498,9 @@ impl PlantHal {
RefCell<I2c<Blocking>>, RefCell<I2c<Blocking>>,
> = CriticalSectionMutex::new(RefCell::new(i2c)); > = CriticalSectionMutex::new(RefCell::new(i2c));
I2C_DRIVER.init(i2c_bus).expect("Could not init i2c driver"); I2C_DRIVER.init(i2c_bus).map_err(|_| FatError::String {
error: "Could not init i2c driver".to_string(),
})?;
let i2c_bus = I2C_DRIVER.get().await; let i2c_bus = I2C_DRIVER.get().await;
let rtc_device = I2cDevice::new(i2c_bus); let rtc_device = I2cDevice::new(i2c_bus);
@@ -650,7 +662,7 @@ pub fn next_partition(current: AppPartitionSubType) -> FatResult<AppPartitionSub
pub async fn esp_time() -> DateTime<Utc> { pub async fn esp_time() -> DateTime<Utc> {
let guard = TIME_ACCESS.get().await.lock().await; let guard = TIME_ACCESS.get().await.lock().await;
DateTime::from_timestamp_micros(guard.current_time_us() as i64).unwrap() DateTime::from_timestamp_micros(guard.current_time_us() as i64).unwrap_or(DateTime::UNIX_EPOCH)
} }
pub async fn esp_set_time(time: DateTime<FixedOffset>) -> FatResult<()> { pub async fn esp_set_time(time: DateTime<FixedOffset>) -> FatResult<()> {

View File

@@ -1,8 +1,7 @@
use crate::fat_error::FatResult;
use crate::hal::Box; use crate::hal::Box;
use crate::fat_error::FatResult;
use async_trait::async_trait; use async_trait::async_trait;
use bincode::config::Configuration; use bincode::{Decode, Encode};
use bincode::{config, Decode, Encode};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use ds323x::ic::DS3231; use ds323x::ic::DS3231;
use ds323x::interface::I2cInterface; use ds323x::interface::I2cInterface;
@@ -19,24 +18,21 @@ use esp_hal::Blocking;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub const X25: crc::Crc<u16> = crc::Crc::<u16>::new(&crc::CRC_16_IBM_SDLC); pub const X25: crc::Crc<u16> = crc::Crc::<u16>::new(&crc::CRC_16_IBM_SDLC);
const CONFIG: Configuration = config::standard(); pub const EEPROM_PAGE: usize = 32;
// //
#[async_trait(?Send)] #[async_trait(?Send)]
pub trait RTCModuleInteraction { pub trait RTCModuleInteraction {
async fn get_backup_info(&mut self) -> FatResult<BackupHeader>;
async fn get_backup_config(&mut self, chunk: usize) -> FatResult<([u8; 32], usize, u16)>;
async fn backup_config(&mut self, offset: usize, bytes: &[u8]) -> FatResult<()>;
async fn backup_config_finalize(&mut self, crc: u16, length: usize) -> FatResult<()>;
async fn get_rtc_time(&mut self) -> FatResult<DateTime<Utc>>; async fn get_rtc_time(&mut self) -> FatResult<DateTime<Utc>>;
async fn set_rtc_time(&mut self, time: &DateTime<Utc>) -> FatResult<()>; async fn set_rtc_time(&mut self, time: &DateTime<Utc>) -> FatResult<()>;
fn write(&mut self, offset: u32, data: &[u8]) -> FatResult<()>;
fn read(&mut self, offset:u32, data: &mut [u8]) -> FatResult<()>;
} }
//
const BACKUP_HEADER_MAX_SIZE: usize = 64;
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Encode, Decode)] #[derive(Serialize, Deserialize, PartialEq, Debug, Default, Encode, Decode)]
pub struct BackupHeader { pub struct BackupHeader {
pub timestamp: i64, pub timestamp: i64,
crc16: u16, pub(crate) crc16: u16,
pub size: u16, pub size: u16,
} }
// //
@@ -46,7 +42,7 @@ pub struct DS3231Module {
DS3231, DS3231,
>, >,
pub(crate) storage: eeprom24x::Storage< pub storage: eeprom24x::Storage<
I2cDevice<'static, CriticalSectionRawMutex, I2c<'static, Blocking>>, I2cDevice<'static, CriticalSectionRawMutex, I2c<'static, Blocking>>,
B32, B32,
TwoBytes, TwoBytes,
@@ -57,67 +53,6 @@ pub struct DS3231Module {
#[async_trait(?Send)] #[async_trait(?Send)]
impl RTCModuleInteraction for DS3231Module { impl RTCModuleInteraction for DS3231Module {
async fn get_backup_info(&mut self) -> FatResult<BackupHeader> {
let mut header_page_buffer = [0_u8; BACKUP_HEADER_MAX_SIZE];
self.storage.read(0, &mut header_page_buffer)?;
let (header, len): (BackupHeader, usize) =
bincode::decode_from_slice(&header_page_buffer[..], CONFIG)?;
log::info!("Raw header is {header_page_buffer:?} with size {len}");
Ok(header)
}
async fn get_backup_config(&mut self, chunk: usize) -> FatResult<([u8; 32], usize, u16)> {
let mut header_page_buffer = [0_u8; BACKUP_HEADER_MAX_SIZE];
self.storage.read(0, &mut header_page_buffer)?;
let (header, _header_size): (BackupHeader, usize) =
bincode::decode_from_slice(&header_page_buffer[..], CONFIG)?;
let mut buf = [0_u8; 32];
let offset = chunk * buf.len() + BACKUP_HEADER_MAX_SIZE;
let end: usize = header.size as usize + BACKUP_HEADER_MAX_SIZE;
let current_end = offset + buf.len();
let chunk_size = if current_end > end {
end - offset
} else {
buf.len()
};
if chunk_size == 0 {
Ok((buf, 0, header.crc16))
} else {
self.storage.read(offset as u32, &mut buf)?;
//&buf[..chunk_size];
Ok((buf, chunk_size, header.crc16))
}
}
async fn backup_config(&mut self, offset: usize, bytes: &[u8]) -> FatResult<()> {
//skip header and write after
self.storage
.write((BACKUP_HEADER_MAX_SIZE + offset) as u32, bytes)?;
Ok(())
}
async fn backup_config_finalize(&mut self, crc: u16, length: usize) -> FatResult<()> {
let mut header_page_buffer = [0_u8; BACKUP_HEADER_MAX_SIZE];
let time = self.get_rtc_time().await?.timestamp_millis();
let header = BackupHeader {
crc16: crc,
timestamp: time,
size: length as u16,
};
let config = config::standard();
let encoded = bincode::encode_into_slice(&header, &mut header_page_buffer, config)?;
log::info!("Raw header is {header_page_buffer:?} with size {encoded}");
self.storage.write(0, &header_page_buffer)?;
Ok(())
}
async fn get_rtc_time(&mut self) -> FatResult<DateTime<Utc>> { async fn get_rtc_time(&mut self) -> FatResult<DateTime<Utc>> {
Ok(self.rtc.datetime()?.and_utc()) Ok(self.rtc.datetime()?.and_utc())
} }
@@ -126,4 +61,14 @@ impl RTCModuleInteraction for DS3231Module {
let naive_time = time.naive_utc(); let naive_time = time.naive_utc();
Ok(self.rtc.set_datetime(&naive_time)?) Ok(self.rtc.set_datetime(&naive_time)?)
} }
fn write(&mut self, offset: u32, data: &[u8]) -> FatResult<()> {
self.storage.write(offset, data)?;
Ok(())
}
fn read(&mut self, offset:u32, data: &mut [u8]) -> FatResult<()> {
self.storage.read(offset, data)?;
Ok(())
}
} }

View File

@@ -3,7 +3,7 @@ use crate::config::PlantControllerConfig;
use crate::fat_error::{ContextExt, FatError, FatResult}; use crate::fat_error::{ContextExt, FatError, FatResult};
use crate::hal::battery::BatteryInteraction; use crate::hal::battery::BatteryInteraction;
use crate::hal::esp::{hold_disable, hold_enable, Esp}; use crate::hal::esp::{hold_disable, hold_enable, Esp};
use crate::hal::rtc::RTCModuleInteraction; use crate::hal::rtc::{BackupHeader, RTCModuleInteraction, EEPROM_PAGE, X25};
use crate::hal::water::TankSensor; use crate::hal::water::TankSensor;
use crate::hal::{ use crate::hal::{
BoardInteraction, Detection, FreePeripherals, Moistures, Sensor, I2C_DRIVER, PLANT_COUNT, BoardInteraction, Detection, FreePeripherals, Moistures, Sensor, I2C_DRIVER, PLANT_COUNT,
@@ -13,8 +13,10 @@ use crate::log::{LogMessage, LOG_ACCESS};
use alloc::boxed::Box; use alloc::boxed::Box;
use alloc::string::ToString; use alloc::string::ToString;
use async_trait::async_trait; use async_trait::async_trait;
use bincode::config;
use canapi::id::{classify, plant_id, MessageKind, IDENTIFY_CMD_OFFSET}; use canapi::id::{classify, plant_id, MessageKind, IDENTIFY_CMD_OFFSET};
use canapi::SensorSlot; use canapi::SensorSlot;
use core::cmp::min;
use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_time::{Duration, Timer, WithTimeout}; use embassy_time::{Duration, Timer, WithTimeout};
@@ -30,8 +32,12 @@ use ina219::SyncIna219;
use log::{error, info, warn}; use log::{error, info, warn};
use measurements::Resistance; use measurements::Resistance;
use measurements::{Current, Voltage}; use measurements::{Current, Voltage};
// use no_panic::no_panic;
use pca9535::{GPIOBank, Pca9535Immediate, StandardExpanderInterface}; use pca9535::{GPIOBank, Pca9535Immediate, StandardExpanderInterface};
pub const BACKUP_HEADER_MAX_SIZE: usize = 64;
const CONFIG: config::Configuration = config::standard();
const MPPT_CURRENT_SHUNT_OHMS: f64 = 0.05_f64; const MPPT_CURRENT_SHUNT_OHMS: f64 = 0.05_f64;
const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::Custom(twai::TimingConfig { const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::Custom(twai::TimingConfig {
baud_rate_prescaler: 200, // 40MHz / 200 * 2 = 100 on C6, 100 * 20 = 2000 divisor, 40MHz / 2000 = 20kHz baud_rate_prescaler: 200, // 40MHz / 200 * 2 = 100 on C6, 100 * 20 = 2000 divisor, 40MHz / 2000 = 20kHz
@@ -364,7 +370,7 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
async fn measure_moisture_hz(&mut self) -> FatResult<Moistures> { async fn measure_moisture_hz(&mut self) -> FatResult<Moistures> {
self.can_power.set_high(); self.can_power.set_high();
Timer::after_millis(500).await; Timer::after_millis(500).await;
let config = self.twai_config.take().expect("twai config not set"); let config = self.twai_config.take().context("twai config not set")?;
let mut twai = config.into_async().start(); let mut twai = config.into_async().start();
if twai.is_bus_off() { if twai.is_bus_off() {
@@ -394,7 +400,7 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
async fn detect_sensors(&mut self, request: Detection) -> FatResult<Detection> { async fn detect_sensors(&mut self, request: Detection) -> FatResult<Detection> {
self.can_power.set_high(); self.can_power.set_high();
Timer::after_millis(500).await; Timer::after_millis(500).await;
let config = self.twai_config.take().expect("twai config not set"); let config = self.twai_config.take().context("twai config not set")?;
let mut twai = config.into_async().start(); let mut twai = config.into_async().start();
if twai.is_bus_off() { if twai.is_bus_off() {
@@ -538,6 +544,76 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
} }
Ok(()) Ok(())
} }
async fn backup_config(&mut self, controller_config: &PlantControllerConfig) -> FatResult<()> {
let mut buffer: [u8; 4096 - BACKUP_HEADER_MAX_SIZE] = [0; 4096 - BACKUP_HEADER_MAX_SIZE];
let length = bincode::encode_into_slice(controller_config, &mut buffer, CONFIG)?;
info!("Writing backup config of size {}", length);
let mut checksum = X25.digest();
checksum.update(&buffer[..length]);
let mut header_page_buffer = [0_u8; BACKUP_HEADER_MAX_SIZE];
let time = self.rtc_module.get_rtc_time().await?.timestamp_millis();
let header = BackupHeader {
crc16: checksum.finalize(),
timestamp: time,
size: length as u16,
};
info!("Header is {:?}", header);
bincode::encode_into_slice(&header, &mut header_page_buffer, CONFIG)?;
info!("Header is serialized");
self.get_rtc_module().write(0, &header_page_buffer)?;
info!("Header written");
let mut to_write = length;
let mut chunk: usize = 0;
while to_write > 0 {
self.progress(chunk as u32).await;
let start = chunk * EEPROM_PAGE;
let end = start + min(EEPROM_PAGE, to_write);
let part = &buffer[start..end];
info!(
"Writing chunk {} of size {} to offset {}",
chunk,
part.len(),
start
);
to_write -= part.len();
chunk += 1;
self.get_rtc_module()
.write((BACKUP_HEADER_MAX_SIZE + chunk * EEPROM_PAGE) as u32, part)?;
}
info!("Backup complete");
self.clear_progress().await;
Ok(())
}
async fn read_backup(&mut self) -> FatResult<PlantControllerConfig> {
let info = self.backup_info().await?;
let mut store = alloc::vec![0_u8; info.size as usize];
self.rtc_module
.read(BACKUP_HEADER_MAX_SIZE as u32, store.as_mut_slice())?;
let mut checksum = X25.digest();
checksum.update(&store[..]);
let crc = checksum.finalize();
if crc != info.crc16 {
bail!("CRC mismatch in backup data")
}
let (decoded, _) = bincode::decode_from_slice(&store[..], CONFIG)?;
Ok(decoded)
}
async fn backup_info(&mut self) -> FatResult<BackupHeader> {
let mut header_page_buffer = [0_u8; BACKUP_HEADER_MAX_SIZE];
self.get_rtc_module().read(0, &mut header_page_buffer)?;
info!("Read header page");
let info: Result<(BackupHeader, usize), bincode::error::DecodeError> =
bincode::decode_from_slice(&header_page_buffer[..], CONFIG);
info!("decoding header: {:?}", info);
info.map(|(header, _)| header)
.map_err(|e| FatError::String {
error: "Could not read backup header: ".to_string() + &e.to_string(),
})
}
} }
async fn wait_for_can_measurements( async fn wait_for_can_measurements(

View File

@@ -33,7 +33,8 @@ impl<'a> TankSensor<'a> {
one_wire_pin.apply_output_config(&OutputConfig::default().with_pull(Pull::None)); one_wire_pin.apply_output_config(&OutputConfig::default().with_pull(Pull::None));
let mut adc1_config = AdcConfig::new(); let mut adc1_config = AdcConfig::new();
let tank_pin = adc1_config.enable_pin_with_cal::<_, AdcCalLine<_>>(gpio5, Attenuation::_11dB); let tank_pin =
adc1_config.enable_pin_with_cal::<_, AdcCalLine<_>>(gpio5, Attenuation::_11dB);
let tank_channel = Adc::new(adc1, adc1_config); let tank_channel = Adc::new(adc1, adc1_config);
let one_wire_bus = OneWire::new(one_wire_pin, false); let one_wire_bus = OneWire::new(one_wire_pin, false);
@@ -141,12 +142,17 @@ impl<'a> TankSensor<'a> {
let value = self.tank_channel.read_oneshot(&mut self.tank_pin); let value = self.tank_channel.read_oneshot(&mut self.tank_pin);
//force yield //force yield
Timer::after_millis(10).await; Timer::after_millis(10).await;
*sample = value.unwrap(); match value {
Ok(v) => *sample = v,
Err(e) => {
bail!("ADC Hardware error: {:?}", e);
}
};
} }
self.tank_power.set_low(); self.tank_power.set_low();
store.sort(); store.sort();
let median_mv = store[TANK_MULTI_SAMPLE / 2] as f32; let median_mv = store[TANK_MULTI_SAMPLE / 2] as f32;
Ok(median_mv/1000.0) Ok(median_mv / 1000.0)
} }
} }

View File

@@ -97,7 +97,7 @@ pub async fn log(
impl LogArray { impl LogArray {
pub fn get(&mut self) -> Vec<LogEntry> { pub fn get(&mut self) -> Vec<LogEntry> {
let head: RangedU8<0, MAX_LOG_ARRAY_INDEX> = let head: RangedU8<0, MAX_LOG_ARRAY_INDEX> =
RangedU8::new(self.head).unwrap_or(RangedU8::new(0).unwrap()); RangedU8::new(self.head).unwrap_or(RangedU8::new_saturating(0));
let mut rv: Vec<LogEntry> = Vec::new(); let mut rv: Vec<LogEntry> = Vec::new();
let mut index = head.wrapping_sub(1); let mut index = head.wrapping_sub(1);
@@ -120,7 +120,7 @@ impl LogArray {
txt_long: &str, txt_long: &str,
) { ) {
let mut head: RangedU8<0, MAX_LOG_ARRAY_INDEX> = let mut head: RangedU8<0, MAX_LOG_ARRAY_INDEX> =
RangedU8::new(self.head).unwrap_or(RangedU8::new(0).unwrap()); RangedU8::new(self.head).unwrap_or(RangedU8::new_saturating(0));
let mut txt_short_stack: heapless::String<TXT_SHORT_LENGTH> = heapless::String::new(); let mut txt_short_stack: heapless::String<TXT_SHORT_LENGTH> = heapless::String::new();
let mut txt_long_stack: heapless::String<TXT_LONG_LENGTH> = heapless::String::new(); let mut txt_long_stack: heapless::String<TXT_LONG_LENGTH> = heapless::String::new();
@@ -281,6 +281,8 @@ pub enum LogMessage {
PumpMissingSensorCurrent, PumpMissingSensorCurrent,
#[strum(serialize = "MPPT Current sensor could not be reached")] #[strum(serialize = "MPPT Current sensor could not be reached")]
MPPTError, MPPTError,
#[strum(serialize = "Parsing error reading message")]
UnknownMessage,
} }
#[derive(Serialize)] #[derive(Serialize)]
@@ -301,7 +303,7 @@ impl From<&LogMessage> for MessageTranslation {
impl LogMessage { impl LogMessage {
pub fn log_localisation_config() -> Vec<MessageTranslation> { pub fn log_localisation_config() -> Vec<MessageTranslation> {
Vec::from_iter((0..LogMessage::len()).map(|i| { Vec::from_iter((0..LogMessage::len()).map(|i| {
let msg_type = LogMessage::from_ordinal(i).unwrap(); let msg_type = LogMessage::from_ordinal(i).unwrap_or(LogMessage::UnknownMessage);
(&msg_type).into() (&msg_type).into()
})) }))
} }

View File

@@ -8,6 +8,7 @@
reason = "mem::forget is generally not safe to do with esp_hal types, especially those \ reason = "mem::forget is generally not safe to do with esp_hal types, especially those \
holding buffers for the duration of a data transfer." holding buffers for the duration of a data transfer."
)] )]
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
//TODO insert version here and read it in other parts, also read this for the ota webview //TODO insert version here and read it in other parts, also read this for the ota webview
esp_bootloader_esp_idf::esp_app_desc!(); esp_bootloader_esp_idf::esp_app_desc!();
@@ -39,7 +40,7 @@ use embassy_net::Stack;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::mutex::{Mutex, MutexGuard}; use embassy_sync::mutex::{Mutex, MutexGuard};
use embassy_sync::once_lock::OnceLock; use embassy_sync::once_lock::OnceLock;
use embassy_time::{Duration, Instant, Timer, WithTimeout}; use embassy_time::{Duration, Instant, Timer};
use esp_hal::rom::ets_delay_us; use esp_hal::rom::ets_delay_us;
use esp_hal::system::software_reset; use esp_hal::system::software_reset;
use esp_println::{logger, println}; use esp_println::{logger, println};
@@ -247,7 +248,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
let reboot_now = Arc::new(AtomicBool::new(false)); let reboot_now = Arc::new(AtomicBool::new(false));
println!("starting webserver"); println!("starting webserver");
spawner.spawn(http_server(reboot_now.clone(), stack))?; let _ = http_server(reboot_now.clone(), stack);
wait_infinity(board, WaitType::MissingConfig, reboot_now.clone()).await; wait_infinity(board, WaitType::MissingConfig, reboot_now.clone()).await;
} }
@@ -297,7 +298,9 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
if let NetworkMode::Wifi { ref ip_address, .. } = network_mode { if let NetworkMode::Wifi { ref ip_address, .. } = network_mode {
publish_firmware_info(&mut board, version, ip_address, &timezone_time.to_rfc3339()).await; publish_firmware_info(&mut board, version, ip_address, &timezone_time.to_rfc3339()).await;
publish_battery_state(&mut board).await; publish_battery_state(&mut board).await.unwrap_or_else(|e| {
error!("Error publishing battery state {e}");
});
let _ = publish_mppt_state(&mut board).await; let _ = publish_mppt_state(&mut board).await;
} }
@@ -326,7 +329,12 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
info!("executing config mode override"); info!("executing config mode override");
//config upload will trigger reboot! //config upload will trigger reboot!
let reboot_now = Arc::new(AtomicBool::new(false)); let reboot_now = Arc::new(AtomicBool::new(false));
spawner.spawn(http_server(reboot_now.clone(), stack.take().unwrap()))?; let stack_val = stack.take();
if let Some(s) = stack_val {
spawner.spawn(http_server(reboot_now.clone(), s))?;
} else {
bail!("Network stack missing, hard abort")
}
wait_infinity(board, WaitType::ConfigButton, reboot_now.clone()).await; wait_infinity(board, WaitType::ConfigButton, reboot_now.clone()).await;
} else { } else {
LOG_ACCESS LOG_ACCESS
@@ -406,7 +414,11 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
} }
info!("Water temp is {}", water_temp.as_ref().unwrap_or(&0.)); info!("Water temp is {}", water_temp.as_ref().unwrap_or(&0.));
publish_tank_state(&mut board, &tank_state, water_temp).await; publish_tank_state(&mut board, &tank_state, water_temp)
.await
.unwrap_or_else(|e| {
error!("Error publishing tank state {e}");
});
let moisture = board.board_hal.measure_moisture_hz().await?; let moisture = board.board_hal.measure_moisture_hz().await?;
@@ -421,7 +433,11 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
PlantState::read_hardware_state(moisture, 7, &mut board).await, PlantState::read_hardware_state(moisture, 7, &mut board).await,
]; ];
publish_plant_states(&mut board, &timezone_time.clone(), &plantstate).await; publish_plant_states(&mut board, &timezone_time.clone(), &plantstate)
.await
.unwrap_or_else(|e| {
error!("Error publishing plant states {e}");
});
let pump_required = plantstate let pump_required = plantstate
.iter() .iter()
@@ -625,14 +641,18 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
if stay_alive { if stay_alive {
let reboot_now = Arc::new(AtomicBool::new(false)); let reboot_now = Arc::new(AtomicBool::new(false));
spawner.spawn(http_server(reboot_now.clone(), stack.take().unwrap()))?; if let Some(s) = stack.take() {
spawner.spawn(http_server(reboot_now.clone(), s))?;
wait_infinity(board, WaitType::MqttConfig, reboot_now.clone()).await; wait_infinity(board, WaitType::MqttConfig, reboot_now.clone()).await;
} else {
bail!("Network Stack missing, hard abort");
}
} else { } else {
//TODO wait for all mqtt publishes? //TODO wait for all mqtt publishes?
Timer::after_millis(5000).await; Timer::after_millis(5000).await;
board.board_hal.get_esp().set_restart_to_conf(false); board.board_hal.get_esp().set_restart_to_conf(false);
board let _ = board
.board_hal .board_hal
.deep_sleep(1000 * 1000 * 60 * deep_sleep_duration_minutes as u64) .deep_sleep(1000 * 1000 * 60 * deep_sleep_duration_minutes as u64)
.await; .await;
@@ -801,30 +821,29 @@ async fn publish_tank_state(
board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'static>>, board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'static>>,
tank_state: &TankState, tank_state: &TankState,
water_temp: FatResult<f32>, water_temp: FatResult<f32>,
) { ) -> FatResult<()> {
let state = serde_json::to_string( let state = serde_json::to_string(
&tank_state.as_mqtt_info(&board.board_hal.get_config().tank, &water_temp), &tank_state.as_mqtt_info(&board.board_hal.get_config().tank, &water_temp),
) )?;
.unwrap();
board board
.board_hal .board_hal
.get_esp() .get_esp()
.mqtt_publish("/water", &state) .mqtt_publish("/water", &state)
.await; .await;
Ok(())
} }
async fn publish_plant_states( async fn publish_plant_states(
board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'static>>, board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'static>>,
timezone_time: &DateTime<Tz>, timezone_time: &DateTime<Tz>,
plantstate: &[PlantState; 8], plantstate: &[PlantState; 8],
) { ) -> FatResult<()> {
for (plant_id, (plant_state, plant_conf)) in plantstate for (plant_id, (plant_state, plant_conf)) in plantstate
.iter() .iter()
.zip(&board.board_hal.get_config().plants.clone()) .zip(&board.board_hal.get_config().plants.clone())
.enumerate() .enumerate()
{ {
let state = let state = serde_json::to_string(&plant_state.to_mqtt_info(plant_conf, timezone_time))?;
serde_json::to_string(&plant_state.to_mqtt_info(plant_conf, timezone_time)).unwrap();
let plant_topic = format!("/plant{}", plant_id + 1); let plant_topic = format!("/plant{}", plant_id + 1);
let _ = board let _ = board
.board_hal .board_hal
@@ -832,6 +851,7 @@ async fn publish_plant_states(
.mqtt_publish(&plant_topic, &state) .mqtt_publish(&plant_topic, &state)
.await; .await;
} }
Ok(())
} }
async fn publish_firmware_info( async fn publish_firmware_info(
@@ -983,11 +1003,11 @@ async fn publish_mppt_state(
async fn publish_battery_state( async fn publish_battery_state(
board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'static>>, board: &mut MutexGuard<'_, CriticalSectionRawMutex, HAL<'static>>,
) -> () { ) -> FatResult<()> {
let state = board.board_hal.get_battery_monitor().get_state().await; let state = board.board_hal.get_battery_monitor().get_state().await;
let value = match state { let value = match state {
Ok(state) => { Ok(state) => {
let json = serde_json::to_string(&state).unwrap().to_owned(); let json = serde_json::to_string(&state)?.to_owned();
json.to_owned() json.to_owned()
} }
Err(_) => "error".to_owned(), Err(_) => "error".to_owned(),
@@ -999,6 +1019,7 @@ async fn publish_battery_state(
.mqtt_publish("/battery", &value) .mqtt_publish("/battery", &value)
.await; .await;
} }
Ok(())
} }
async fn wait_infinity( async fn wait_infinity(
@@ -1045,8 +1066,7 @@ async fn wait_infinity(
exit_hold_blink = !exit_hold_blink; exit_hold_blink = !exit_hold_blink;
let progress = core::cmp::min(elapsed, exit_hold_duration); let progress = core::cmp::min(elapsed, exit_hold_duration);
let lit = ((progress.as_millis() as u64 * 8) let lit = ((progress.as_millis() * 8) / exit_hold_duration.as_millis())
/ exit_hold_duration.as_millis() as u64)
.saturating_add(1) .saturating_add(1)
.min(8) as usize; .min(8) as usize;
@@ -1196,6 +1216,8 @@ async fn handle_serial_config(
} }
} }
use embassy_time::WithTimeout;
#[allow(clippy::panic, clippy::unwrap_used, clippy::expect_used)]
#[esp_rtos::main] #[esp_rtos::main]
async fn main(spawner: Spawner) -> ! { async fn main(spawner: Spawner) -> ! {
// intialize embassy // intialize embassy

View File

@@ -1,3 +1,4 @@
use bincode::{Decode, Encode};
use crate::hal::Moistures; use crate::hal::Moistures;
use crate::{config::PlantConfig, hal::HAL, in_time_range}; use crate::{config::PlantConfig, hal::HAL, in_time_range};
use chrono::{DateTime, TimeDelta, Utc}; use chrono::{DateTime, TimeDelta, Utc};
@@ -70,7 +71,7 @@ impl PumpState {
} }
} }
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)] #[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Encode, Decode)]
pub enum PlantWateringMode { pub enum PlantWateringMode {
Off, Off,
TargetMoisture, TargetMoisture,

View File

@@ -158,12 +158,11 @@ pub async fn determine_tank_state(
board: &mut MutexGuard<'static, CriticalSectionRawMutex, HAL<'static>>, board: &mut MutexGuard<'static, CriticalSectionRawMutex, HAL<'static>>,
) -> TankState { ) -> TankState {
if board.board_hal.get_config().tank.tank_sensor_enabled { if board.board_hal.get_config().tank.tank_sensor_enabled {
match board match board.board_hal.get_tank_sensor() {
.board_hal Ok(sensor) => match sensor.tank_sensor_voltage().await {
.get_tank_sensor() Ok(raw_sensor_value_mv) => TankState::Present(raw_sensor_value_mv),
.map(|f| f.tank_sensor_voltage()) Err(err) => TankState::Error(TankError::BoardError(err.to_string())),
{ },
Ok(raw_sensor_value_mv) => TankState::Present(raw_sensor_value_mv.await.unwrap()),
Err(err) => TankState::Error(TankError::BoardError(err.to_string())), Err(err) => TankState::Error(TankError::BoardError(err.to_string())),
} }
} else { } else {

View File

@@ -1,8 +1,7 @@
use crate::fat_error::{FatError, FatResult}; use crate::fat_error::{FatError, FatResult};
use crate::hal::rtc::X25; use crate::webserver::read_up_to_bytes_from_request;
use crate::BOARD_ACCESS; use crate::BOARD_ACCESS;
use alloc::borrow::ToOwned; use alloc::borrow::ToOwned;
use alloc::format;
use alloc::string::{String, ToString}; use alloc::string::{String, ToString};
use chrono::DateTime; use chrono::DateTime;
use edge_http::io::server::Connection; use edge_http::io::server::Connection;
@@ -21,48 +20,9 @@ pub(crate) async fn get_backup_config<T, const N: usize>(
where where
T: Read + Write, T: Read + Write,
{ {
// First pass: verify checksum without sending data
let mut checksum = X25.digest();
let mut chunk = 0_usize;
loop {
let mut board = BOARD_ACCESS.get().await.lock().await; let mut board = BOARD_ACCESS.get().await.lock().await;
board.board_hal.progress(chunk as u32).await; let backup = board.board_hal.read_backup().await?;
let (buf, len, expected_crc) = board
.board_hal
.get_rtc_module()
.get_backup_config(chunk)
.await?;
// Update checksum with the actual data bytes of this chunk
checksum.update(&buf[..len]);
let is_last = len == 0 || len < buf.len();
if is_last {
let actual_crc = checksum.finalize();
if actual_crc != expected_crc {
BOARD_ACCESS
.get()
.await
.lock()
.await
.board_hal
.clear_progress()
.await;
conn.initiate_response(
409,
Some(
format!("Checksum mismatch expected {expected_crc} got {actual_crc}")
.as_str(),
),
&[],
)
.await?;
return Ok(Some(409));
}
break;
}
chunk += 1;
}
// Second pass: stream data // Second pass: stream data
conn.initiate_response( conn.initiate_response(
200, 200,
@@ -75,35 +35,8 @@ where
) )
.await?; .await?;
let mut chunk = 0_usize; conn.write_all(serde_json::to_string(&backup)?.as_bytes())
loop {
let mut board = BOARD_ACCESS.get().await.lock().await;
board.board_hal.progress(chunk as u32).await;
let (buf, len, _expected_crc) = board
.board_hal
.get_rtc_module()
.get_backup_config(chunk)
.await?; .await?;
if len == 0 {
break;
}
conn.write_all(&buf[..len]).await?;
if len < buf.len() {
break;
}
chunk += 1;
}
BOARD_ACCESS
.get()
.await
.lock()
.await
.board_hal
.clear_progress()
.await;
Ok(Some(200)) Ok(Some(200))
} }
@@ -113,49 +46,12 @@ pub(crate) async fn backup_config<T, const N: usize>(
where where
T: Read + Write, T: Read + Write,
{ {
let mut offset = 0_usize; let input = read_up_to_bytes_from_request(conn, Some(4096)).await?;
let mut buf = [0_u8; 32]; info!("Read input with length {}", input.len());
let mut checksum = X25.digest();
let mut counter = 0;
loop {
let to_write = conn.read(&mut buf).await?;
if to_write == 0 {
info!("backup finished");
break;
} else {
let mut board = BOARD_ACCESS.get().await.lock().await; let mut board = BOARD_ACCESS.get().await.lock().await;
board.board_hal.progress(counter).await; let config_to_backup = serde_json::from_slice(&input)?;
info!("Parsed send config to object");
counter += 1; board.board_hal.backup_config(&config_to_backup).await?;
board
.board_hal
.get_rtc_module()
.backup_config(offset, &buf[0..to_write])
.await?;
checksum.update(&buf[0..to_write]);
}
offset += to_write;
}
let mut board = BOARD_ACCESS.get().await.lock().await;
board
.board_hal
.get_rtc_module()
.backup_config_finalize(checksum.finalize(), offset)
.await?;
board.board_hal.clear_progress().await;
conn.initiate_response(
200,
Some("OK"),
&[
("Access-Control-Allow-Origin", "*"),
("Access-Control-Allow-Headers", "*"),
("Access-Control-Allow-Methods", "*"),
],
)
.await?;
Ok(Some("saved".to_owned())) Ok(Some("saved".to_owned()))
} }
@@ -166,10 +62,12 @@ where
T: Read + Write, T: Read + Write,
{ {
let mut board = BOARD_ACCESS.get().await.lock().await; let mut board = BOARD_ACCESS.get().await.lock().await;
let header = board.board_hal.get_rtc_module().get_backup_info().await; let info = board.board_hal.backup_info().await;
let json = match header {
let json = match info {
Ok(h) => { Ok(h) => {
let timestamp = DateTime::from_timestamp_millis(h.timestamp).unwrap(); info!("Got backup info: {:?}", h);
let timestamp = DateTime::from_timestamp_millis(h.timestamp).unwrap_or_default();
let wbh = WebBackupHeader { let wbh = WebBackupHeader {
timestamp: timestamp.to_rfc3339(), timestamp: timestamp.to_rfc3339(),
size: h.size, size: h.size,
@@ -177,6 +75,7 @@ where
serde_json::to_string(&wbh)? serde_json::to_string(&wbh)?
} }
Err(err) => { Err(err) => {
info!("Error getting backup info: {:?}", err);
let wbh = WebBackupHeader { let wbh = WebBackupHeader {
timestamp: err.to_string(), timestamp: err.to_string(),
size: 0, size: 0,

View File

@@ -181,6 +181,7 @@ where
} }
#[embassy_executor::task] #[embassy_executor::task]
#[allow(clippy::panic, clippy::unwrap_used, clippy::expect_used)]
pub async fn http_server(reboot_now: Arc<AtomicBool>, stack: Stack<'static>) { pub async fn http_server(reboot_now: Arc<AtomicBool>, stack: Stack<'static>) {
let buffer: TcpBuffers<2, 1024, 1024> = TcpBuffers::new(); let buffer: TcpBuffers<2, 1024, 1024> = TcpBuffers::new();
let tcp = Tcp::new(stack, &buffer); let tcp = Tcp::new(stack, &buffer);

View File

@@ -108,7 +108,7 @@ where
{ {
let actual_data = read_up_to_bytes_from_request(request, None).await?; let actual_data = read_up_to_bytes_from_request(request, None).await?;
let time: SetTime = serde_json::from_slice(&actual_data)?; let time: SetTime = serde_json::from_slice(&actual_data)?;
let parsed = DateTime::parse_from_rfc3339(time.time).unwrap(); let parsed = DateTime::parse_from_rfc3339(time.time)?;
esp_set_time(parsed).await?; esp_set_time(parsed).await?;
Ok(None) Ok(None)
} }