Automate the tedious process of manually entering parts into the Formula Student Germany Bill of Material (BOM) tool β so you can focus on building fast cars.
| Feature | Description |
|---|---|
| Bulk Upload | Reads your BOM Excel and uploads every part automatically |
| Duplicate Detection | Scrapes the existing BOM table before uploading β running it twice is safe |
| Smart Assembly Matching | Maps common names like "brake caliper" β Calipers automatically |
| Row Filtering | Skips example rows, empty rows, π’ green (already done), and π΄ red (do not upload) |
| Test Mode | Limits uploads to the first N parts so you can verify before going all-in |
| Configurable | .env file for credentials, team ID, system filter, and more |
| Audit Log | Every action is logged to bom_log.txt with timestamps |
git clone https://github.com/Woonderpipe/fsg-bom-automation.git
cd fsg-bom-automationCreate a virtual environment and activate it:
python -m venv .venv
# Windows
.\.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activateThen
pip install -r requirements.txt
playwright install chromium# macOS / Linux
cp .env.example .env
# Windows PowerShell
copy .env.example .envEdit .env with your FSG credentials and team ID:
# Make sure to at least set these, before running the script!
FSG_USERNAME=your_username
FSG_PASSWORD=your_password
TEAM_ID=YOUR_TEAM_ID
TEST_MODE=true
DRY_RUN=true
# More info on each and more variables is in the .env file itself.π Finding your Team ID: Open your BOM page on the FSG website. The URL looks like:
https://www.formulastudent.de/teams/fse/details/bom/tid/YOUR_TEAM_IDYourTEAM_IDis the number at the end β359in this example.
Place your .xlsx BOM files in the BOMs/ folder:
Tip
For best results, use the provided BOM_Example_EFRxx.xlsx as a starting point. Make sure to follow the required column headers and formatting (or edit the script if your format is different).
project/
βββ BOMs/
β βββ BOM_BR_MyTeam.xlsx
β βββ BOM_SU_MyTeam.xlsx
β βββ BOM_Example_EFRxx.xlsx
β βββ ...
βββ main.py
βββ .env
βββ ...
python main.pyThe script will:
- Let you pick an Excel file
- Show you which systems are in the file
- Open a browser, log you in, and start uploading (or simulate if
DRY_RUN=true) - Print a summary of what was uploaded, skipped, or failed
Your Excel file should have these column headers (case-insensitive):
| Column | Required | Description |
|---|---|---|
system |
β | System code: AT, BR, DT, ET, FR, LV, MS, ST, SU, WT |
assembly |
β | Assembly name (e.g. Brake Pads, Calipers) |
part |
β | Part name (free text) |
part_quantity |
β | Quantity (number) |
make o. buy |
β | m for make, b for buy |
part_comments |
β | Comments (free text) |
| Code | Full Name |
|---|---|
AT |
Autonomous System |
BR |
Brake System |
DT |
Drivetrain |
ET |
Engine and Tractive System |
FR |
Chassis and Body |
LV |
Grounded Low Voltage System |
MS |
Miscellaneous Fit and Finish |
ST |
Steering System |
SU |
Suspension System |
WT |
Wheels, Wheel Bearings and Tires |
The script reads the background colour of the first few cells in each row (up to the first 5 columns). It supports common hex formats and also recognizes close shades of green and red.
| Colour | Behaviour |
|---|---|
| π’ Green-like | Skipped β already uploaded |
| π΄ Red-like | Skipped β do not upload |
| β¬ No colour | Processed normally |
Use a green-like fill to mark rows as already uploaded, or a red-like fill to exclude rows from processing.
The FSG website has fixed assembly names. If your Excel uses a slightly different name, the script remaps it automatically:
| Excel Name | β FSG Dropdown |
|---|---|
brake caliper |
Calipers |
reservoir / reservoire |
Brake Master Cylinder |
fitting screw / bolts |
Fasteners |
brake disc / brake disk |
Brake Discs |
damper |
Dampers |
tire / tyre |
Tires |
| ... and many more |
You can add your own mappings by editing
BOMs/config.yaml.
Before uploading, the script reads existing parts from the FSG website BOM table and compares each candidate row to the scraped site data.
- The comparison is based primarily on normalized part names.
- If both Excel and site rows include assembly names, the match also checks normalized assembly names.
- If a duplicate is detected, the row is logged as
SKIPand not uploaded. - Running the script again will avoid re-uploading parts already present on the site.
Every run appends to bom_log.txt:
[2026-04-08 21:11:02] [INFO] Found 358 existing parts on the website.
[2026-04-08 21:11:05] [OK] Row 12: β 'Caliper front'
[2026-04-08 21:11:07] [OK] Row 13: β 'Caliper rear'
[2026-04-08 21:11:10] [SKIP] Row 14: Duplicate β 'Washer M5' already exists
[2026-04-08 21:12:36] [ERROR] Row 38: β 'tape' β Timeout 5000ms exceeded.
[2026-04-08 21:13:19] [INFO] Done in 137.2s β 35 uploaded / 3 duplicates / 1 failed
| Problem | Solution |
|---|---|
| Login fails | The browser will still open β log in manually, navigate to the BOM page, then press Enter |
| "Assembly not found" | Add a mapping to BOMs/config.yaml |
| Timeout errors | Can happen if the FSG server is slow. Re-run β duplicates are safe |
| Column not found | Ensure your Excel headers match: system, assembly, part |
| No Excel files found | Place .xlsx files in the BOMs/ folder |
| Other Issues or Bugs or Improvement Ideas | Feel free to make a Pull Request or contact Sharbel from ELBFLORACE e.V. |
If you discover a security issue, please open a GitHub issue or pull request. See SECURITY.md for details.
MIT β use it, share it, improve it. Built with π§‘ by Sharbel from ELBFLORACE e.V.
Note
Note to FSG: If you're seeing this β please consider adding a CSV/bulk import feature to the CCBOM tool natively. Every team spends hours on manual data entry that could be automated. We built this tool out of necessity, but a first-party solution would be far better for the entire community. π
