Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 35 additions & 152 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,152 +1,35 @@
# <img alt="logo" src="static/logo.png" height="36" /> OpenSpoolMan
Use any filament like Bambu filaments with automatic recognition and filament usage updates in your AMS!

No need for cloud or any special hardware, just your phone and some NFC tags!

Similar functionality to https://github.com/spuder/OpenSpool using only your phone, server and NFC tags integrated with SpoolMan

Everything works locally without cloud access, you can use scripts/init_bambulab.py script to access your PRINTER_ID and PRINTER_CODE if it is not available on your printer.

Docker: https://ghcr.io/drndos/openspoolman

### News
- 0.1.3 - 22.12.2024 - Added manual assignment for empty slots
- 0.1.4 - 09.02.2025 - Bugfixes, issue fixing WIP
- 0.1.7 - 17.04.2025 - https://github.com/drndos/openspoolman/releases/tag/v0.1.7
- 0.1.8 - 20.04.2025 - https://github.com/drndos/openspoolman/releases/tag/v0.1.8

### Main features

<table>
<tbody>
<tr>
<td><b>Information about your AMS</b></td>
<td><b>Fill tray directly from overview</b></td>
<td><b>Print history</b></td>
</tr>
<tr>
<td><img alt="Information about your AMS" src="docs/img/info.PNG" width="250"/></td>
<td><img alt="Fill tray directly from overview" src="docs/img/fill_tray.PNG" width="250"/></td>
<td><img alt="Print history" src="docs/img/print_history.PNG" width="250"/></td>
<tr>
<td><b>Assign NFC tags to your spools in SpoolMan</b></td>
<td><b>Write the URL of the Spool detail to NFC tag directly from the browser</b></td>
<td></td>
</tr>
<td><img alt="Assign NFC tags to your spools in SpoolMan" src="docs/img/assign_nfc.jpeg" width="250"/></td>
<td><img alt="NFC write success" src="docs/img/nfc_write_success.jpeg" width="250"/></td>
<td></td>
</tr>
<tr>
<td colspan="2"><b>Bring Phone close to the NFC tag and open the spool detail</b></td>
<td><b>Pick the AMS slot where you want the spool to be loaded</b></td>
</tr>
<tr>
<td><img alt="Open NFC link" src="docs/img/open_link.jpeg" width="250"/></td>
<td><img alt="Spool info" src="docs/img/spool_info.jpeg" width="250"/></td>
<td><img alt="Pick tray" src="docs/img/pick_tray.jpeg" width="250"/></td>
</tr>
<tr>
<td><b>Automatically track the usage of your filaments based on the slicer estimates in SpoolMan</b></td>
<td><b>Track Bambu filaments without additional NFC Tags</b></td>
<td><b>Resolve issues with few clicks (soon)</b></td>
</tr>
<tr>
<td><img alt="Slicer estimate" src="docs/img/slicer_estimate.jpg" width="250"/></td>
<td><img alt="Bambu filament usgae tracking" src="docs/img/bambu_tracking.jpg" width="250"/></td>
<td><img alt="Resolve issues" src="docs/img/resolve_issues.jpeg" width="250"/></td>
</tr>
</tbody>
</table>

### Seeded demo & screenshots
- Export a live snapshot first (default path `data/live_snapshot.json`) with `python scripts/export_live_snapshot.py --output data/live_snapshot.json`. Snapshot-based runs expect this file and will warn if it is missing.
- Load the snapshot-backed test data with `OPENSPOOLMAN_TEST_DATA=1` or `--test-data` on the screenshot helper; override the snapshot path via `OPENSPOOLMAN_TEST_SNAPSHOT` or `--snapshot` when needed.
- Install the core app dependencies via `pip install -r requirements.txt`. Only install the screenshot extras when regenerating docs: `pip install -r requirements-screenshots.txt` followed by `python -m playwright install chromium`.
- Provide your own print-history database (default path `data/demo.db`) or override with `OPENSPOOLMAN_PRINT_HISTORY_DB=/path/to/history.db` or `--print-history-db` when using the screenshot helper.
- Configure which routes and devices get captured via `scripts/screenshot_config.json` (supports per-target or per-screenshot `max_height`, device-specific viewports, and automatic device-prefixed filenames). Override or extend it with `--config <path>` and target specific devices with `--devices desktop,mobile` when you run the generator.
- Run `python scripts/generate_screenshots.py` to start the app in snapshot-backed test mode, open the configured routes in headless Chromium, and refresh the images under `docs/img/` (or another folder via `--output-dir`). Screenshots default to the viewport height unless a per-target/device `max_height` is set (or `full_page: true`), and `--max-height` provides a config-wide fallback.
- Pass `--color-scheme dark` (or set `color_scheme` in the config) to capture pages in dark mode; omit it to follow the default auto/light behavior.
- To generate pictures from real printer/Spoolman data, run the generator in live mode to start the current app against your configured devices (`python scripts/generate_screenshots.py --mode live --live-readonly`). If you truly need to target a remote instance, pass `--base-url http://<host>:<port>`. Environment variables (`OPENSPOOLMAN_TEST_DATA=1 OPENSPOOLMAN_TEST_SNAPSHOT=data/live_snapshot.json` or `OPENSPOOLMAN_LIVE_READONLY=1`) work as alternatives. When live data is used or captured, the app and scripts automatically load `config.env` from the repository root (if present) so credentials and URLs are available even when running tools from subfolders.
- The script can be called in CI after UI changes to automatically regenerate and version the example screenshots.
- For unit tests, you can reuse the same seeded dataset without environment variables: add `--use-seeded-data` to your pytest command for auto-mocking, request the `seeded_data_overrides` fixture in a test, or wrap your test body in `with test_data.apply_test_overrides(): ...`.
- To generate documentation screenshots inside pytest, run `pytest -m screenshots --generate-screenshots` (optionally pass `--screenshot-output <dir>`, `--screenshot-mode live`, `--screenshot-devices <list>`, or `--screenshot-config <path>`); the test will spin up Flask in seeded mode by default and reuse the same capture logic as `scripts/generate_screenshots.py`.

### What you need:
- Android Phone with Chrome web browser or iPhone (manual process much more complicated if using NFC Tags)
- Server to run OpenSpoolMan with https (optional when not using NFC Tags) that is reachable from your Phone and can reach both SpoolMan and Bambu Lab printer on the network
- Active Bambu Lab Account or PRINTER_ID and PRINTER_CODE on your printer
- Bambu Lab printer https://eu.store.bambulab.com/collections/3d-printer
- SpoolMan installed https://github.com/Donkie/Spoolman
- NFC Tags (optional) https://eu.store.bambulab.com/en-sk/collections/nfc/products/nfc-tag-with-adhesive https://www.aliexpress.com/item/1005006332360160.html

### How to setup:
- Rename config.env.template to config.env or set environment properies and:
- set OPENSPOOLMAN_BASE_URL - that is the URL where OpenSpoolMan will be available on your network. Must be https for NFC write to work. without trailing slash
- set PRINTER_ID - On your printer clicking on Setting -> Device -> Printer SN
- set PRINTER_ACCESS_CODE - On your printer clicking on Setting -> Lan Only Mode -> Access Code (you _don't_ need to enable the LAN Only Mode)
- set PRINTER_IP - On your printer clicking on Setting -> Lan Only Mode -> IP Address (you _don't_ need to enable the LAN Only Mode)
- set SPOOLMAN_BASE_URL - according to your SpoolMan installation without trailing slash
- set AUTO_SPEND - to True if you want for system to track your filament spending (check AUTO_SPEND issues below) default to False
- Run the server (wsgi.py)
- Run Spool Man
- Add following extra Fields to your SpoolMan:
- Filaments
- "type","Type","Choice","Basic","Silk, Basic, High Speed, Matte, Plus, Flexible, Translucent","No"
- "nozzle_temperature","Nozzle Temperature","Integer Range","°C","190 – 230"
- "filament_id","Filament ID", "Text"
- Spools
- "tag","tag","Text"
- "active_tray","Active Tray","Text
- Add your Manufacturers, Filaments and Spools to Spool Man (when adding filament you can try "Import from External" for faster workflow)
- The filament id can be found in the json files in C:\Users\USERNAME\AppData\Roaming\BambuStudio\user\USERID\filament\base
It is the same for each printer and nozzle.
- Open the server base url in browser on your mobile phone
- Optionally add Bambu Lab RFIDs to extra tag on your Bambu Spools so they will be matching. You can get the tag id from logs or from browser in AMS info.

With NFC Tags:
- For non Bambu Lab filaments click on the filament and click Write and hold empty NFC tag to your phone (allow NFC in popup if prompted)
- Attach NFC tag to your filament
- Load filament to your AMS by loading it and then putting your phone near NFC tag and allowing your phone to open the website
- On the website pick the slot you put your filament in

Without NFC Tags:
- Click fill on the tray and select the desired spool
- Done

### Deployment
Run locally in venv by configuring environment properties and running wsgi.py, supports adhoc ssl.

Run in docker by configuring config.env and running compose.yaml, you will need more setup/config to run ssl.

Run in kubernetes using helm chart, where you can configure the ingress with SSL. https://github.com/truecharts/public/blob/master/charts/library/common/values.yaml

### AUTO SPEND - Automatic filament usage based on slicer estimate
You can turn this feature on to automatically update the spool usage in SpoolMan.
This feature is using slicer information about predicted filament weight usage (and in future correlating it with the progress of the printer to compute the estimate of filament used).

This feature has currently following issues/drawbacks:
- Spending on the start of the print
- Not spending according to print process and spending full filament weight even if print fails
- Don't know if it works with LAN mode, since it downloads the 3MF file from cloud
- Not tested with multiple AMS systems
- Not handling the mismatch between the SpoolMan and AMS (if you don't have the Active Tray information correct in spoolman it won't work properly)

### Notes:
- If you change the BASE_URL of this app, you will need to reconfigure all NFC TAGS

### TBD:
- Filament remaining in AMS (I have only AMS lite, if you have AMS we can test together)
- Filament spending based on printing
- TODO: handle situation when the print doesn't finish
- TODO: test with multiple AMS
- Code cleanup
- Video showcase
- Docker compose SSL
- Logs
- TODOs
- Click to resolve issue - WIP
- Reduce the amount of files in docker container
- Cloud service for controlled redirect so you don't have to reconfigure NFC tags
- QR codes
- Add search to list of spools
# <img alt="logo" src="static/logo.png" height="36" /> OpenSpoolMan

Use any filament like Bambu filaments with automatic recognition and filament usage updates in your AMS — no cloud connection required.

![Desktop home view](docs/img/desktop_home.PNG)

## Quick links
- [Feature tour & screenshots](docs/wiki/Features-and-Screenshots.md)
- [Setup guide](docs/wiki/Setup.md)
- [Deployment options](docs/wiki/Deployment.md)
- [Seeded demo & screenshot generation](docs/wiki/Seeded-Demo-and-Screenshots.md)
- [AUTO SPEND notes](docs/wiki/AUTO-SPEND.md)

## Highlights
- NFC-driven workflow to identify, assign, and load spools directly from your phone.
- Automatic usage tracking, including Bambu filaments without extra tags.
- Works locally with your SpoolMan instance and Bambu Lab printers.
- Web app optimized for both desktop and mobile devices.
- Customizable spool sorting for tray views and searches (via `SPOOL_SORTING`).
- Fallback spool assignment after prints when automatic detection fails.

## Compatibility
- Requires a server that can reach both SpoolMan and your Bambu Lab printer.
- NFC features require HTTPS on the server URL and a phone with NFC support.
- SpoolMan fields for filament type, nozzle temperature, filament ID, spool tags, and active trays are expected (see the [setup guide](docs/wiki/Setup.md) for details).

## Release notes
- 0.1.9 — 25.05.2025 — <https://github.com/drndos/openspoolman/releases/tag/v0.1.9>
- 0.1.8 — 20.04.2025 — <https://github.com/drndos/openspoolman/releases/tag/v0.1.8>
- 0.1.7 — 17.04.2025 — <https://github.com/drndos/openspoolman/releases/tag/v0.1.7>
- 0.1.4 — 09.02.2025 — Bug fixes
- 0.1.3 — 22.12.2024 — Added manual assignment for empty slots

## License
[Apache 2.0](LICENSE.txt)
18 changes: 18 additions & 0 deletions docs/wiki/AUTO-SPEND.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# AUTO SPEND

Automatic filament usage updates based on slicer estimates.

## How it works
When enabled (`AUTO_SPEND=True`), OpenSpoolMan reads slicer estimates for filament weight usage and updates the associated spool in SpoolMan. Future updates will correlate usage with printer progress to refine estimates.

## Current limitations
- Spending occurs at the start of the print.
- Spends the full filament weight even if the print fails.
- LAN-only mode may not work because the 3MF file is downloaded from the cloud.
- Not tested with multiple AMS systems.
- Does not handle mismatches between SpoolMan and AMS (if Active Tray information is wrong, results will be incorrect).

## Recommendations
- Keep AUTO SPEND disabled until you verify it fits your workflow.
- Ensure Active Tray information is accurate in SpoolMan before enabling.
- Monitor the first few prints to confirm spending aligns with expectations.
21 changes: 21 additions & 0 deletions docs/wiki/Deployment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Deployment options

Run OpenSpoolMan locally, in Docker, or on Kubernetes.

## Local development
- Install dependencies: `pip install -r requirements.txt`.
- Run the app with your configured environment: `python wsgi.py` (supports ad-hoc SSL).

## Docker
- Configure `config.env` with the required environment variables.
- Build or pull the image: `docker pull ghcr.io/drndos/openspoolman`.
- Start using Docker Compose: `docker compose up` (HTTPS requires additional setup in the compose file).
- Multi-arch images (including arm64) are published with v0.1.9; ensure your platform pulls the matching architecture.

## Kubernetes
- Use the provided Helm chart under `helm/`.
- Configure ingress with SSL; reference <https://github.com/truecharts/public/blob/master/charts/library/common/values.yaml> for common options.

## Notes
- Ensure the container or pod can reach both SpoolMan and your Bambu Lab printer.
- If you change the public base URL, NFC tags must be rewritten.
33 changes: 33 additions & 0 deletions docs/wiki/Features-and-Screenshots.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Features & Screenshots

Explore the core OpenSpoolMan workflows on desktop and mobile.

## AMS overview and tray control
| Overview | Fill tray | Change spool | Print history |
| --- | --- | --- | --- |
| ![Desktop home](../img/desktop_home.PNG) | ![Fill tray from overview](../img/desktop_fill_tray.PNG) | ![Swap spool in a tray](../img/desktop_change_spool.PNG) | ![Review print history](../img/desktop_print_history.PNG) |

## Spool detail and NFC assignment
| Spool info | Assign NFC tag | Write confirmation | Open from tag |
| --- | --- | --- | --- |
| ![Spool detail](../img/desktop_spool_info.jpeg) | ![Assign NFC tag](../img/desktop_assign_nfc.jpeg) | ![NFC write success](../img/nfc_write_success.jpeg) | ![Open NFC link](../img/open_link.jpeg) |

## Mobile experience
| Home | Fill tray | Change spool | Spool info | Assign NFC | Print history |
| --- | --- | --- | --- | --- | --- |
| ![Mobile home](../img/mobile_home.PNG) | ![Mobile fill tray](../img/mobile_fill_tray.PNG) | ![Mobile change spool](../img/mobile_change_spool.PNG) | ![Mobile spool info](../img/mobile_spool_info.jpeg) | ![Mobile assign NFC](../img/mobile_assign_nfc.jpeg) | ![Mobile print history](../img/mobile_print_history.PNG) |

## Automation and issue handling
| Slicer estimate tracking | Bambu filament tracking | Issue resolution |
| --- | --- | --- |
| ![Slicer estimate](../img/slicer_estimate.jpg) | ![Bambu filament tracking](../img/bambu_tracking.jpg) | ![Resolve issues](../img/resolve_issues.jpeg) |

If a spool was not detected during printing, release 0.1.9 lets you assign the correct filament to that print afterwards so usage stays accurate.

## NFC-assisted loading
1. Bring your phone near the tagged spool to open the spool detail.
2. Pick the AMS slot where you want the filament loaded.

| Open NFC link | Pick tray |
| --- | --- |
| ![Open NFC link](../img/open_link.jpeg) | ![Pick tray](../img/pick_tray.jpeg) |
22 changes: 22 additions & 0 deletions docs/wiki/Seeded-Demo-and-Screenshots.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Seeded demo & screenshot generation

Use the seeded dataset to generate documentation screenshots or run tests with predictable data.

## Prepare data
- Export a live snapshot first (default path `data/live_snapshot.json`) with `python scripts/export_live_snapshot.py --output data/live_snapshot.json`. Snapshot-based runs expect this file and will warn if it is missing.
- Provide your own print-history database (default path `data/demo.db`) or override with `OPENSPOOLMAN_PRINT_HISTORY_DB=/path/to/history.db` or `--print-history-db` when using the screenshot helper.

## Install dependencies
- Install the core app dependencies via `pip install -r requirements.txt`.
- Install the screenshot extras only when regenerating docs: `pip install -r requirements-screenshots.txt` followed by `python -m playwright install chromium`.

## Generate screenshots
- Configure which routes and devices get captured via `scripts/screenshot_config.json` (supports per-target or per-screenshot `max_height`, device-specific viewports, and automatic device-prefixed filenames). Override or extend it with `--config <path>` and target specific devices with `--devices desktop,mobile` when you run the generator.
- Run `python scripts/generate_screenshots.py` to start the app in snapshot-backed test mode, open the configured routes in headless Chromium, and refresh the images under `docs/img/` (or another folder via `--output-dir`). Screenshots default to the viewport height unless a per-target/device `max_height` is set (or `full_page: true`); `--max-height` provides a config-wide fallback.
- Pass `--color-scheme dark` (or set `color_scheme` in the config) to capture pages in dark mode; omit it to follow the default auto/light behavior.
- To generate pictures from real printer/SpoolMan data, run the generator in live mode to start the current app against your configured devices: `python scripts/generate_screenshots.py --mode live --live-readonly`. If you need to target a remote instance, pass `--base-url http://<host>:<port>`. Environment variables (`OPENSPOOLMAN_TEST_DATA=1 OPENSPOOLMAN_TEST_SNAPSHOT=data/live_snapshot.json` or `OPENSPOOLMAN_LIVE_READONLY=1`) work as alternatives. When live data is used or captured, the app and scripts automatically load `config.env` from the repository root (if present) so credentials and URLs are available even when running tools from subfolders.
- The script can be called in CI after UI changes to automatically regenerate and version the example screenshots.

## Using seeded data in tests
- For unit tests, reuse the seeded dataset without environment variables: add `--use-seeded-data` to your pytest command for auto-mocking, request the `seeded_data_overrides` fixture in a test, or wrap your test body in `with test_data.apply_test_overrides(): ...`.
- To generate documentation screenshots inside pytest, run `pytest -m screenshots --generate-screenshots` (optionally pass `--screenshot-output <dir>`, `--screenshot-mode live`, `--screenshot-devices <list>`, or `--screenshot-config <path>`); the test will spin up Flask in seeded mode by default and reuse the same capture logic as `scripts/generate_screenshots.py`.
Loading