351 lines
8.6 KiB
Markdown
351 lines
8.6 KiB
Markdown
# Bambuddy InvenTree Sync
|
|
|
|
Sidecar service for syncing successful Bambuddy print archives into InvenTree stock.
|
|
|
|
The service runs as a separate Docker container. It does not modify Bambuddy or InvenTree source code. Bambuddy is used as the print-history source, while InvenTree remains the stock-control system of record.
|
|
|
|
## What It Does
|
|
|
|
For each successful Bambuddy archive, the service:
|
|
|
|
- finds or creates an InvenTree `Part`;
|
|
- creates one InvenTree `StockItem` for the Bambuddy archive;
|
|
- writes `Weight` and `PrintTime` part parameters when those templates exist in InvenTree;
|
|
- uploads the Bambuddy archive thumbnail to the InvenTree part image;
|
|
- writes an InvenTree part URL back into Bambuddy archive `external_url`;
|
|
- stores sync state in SQLite to prevent duplicate stock items.
|
|
|
|
Failed, stopped, running, or still-printing archives are skipped when `SYNC_SUCCESS_ONLY=true`.
|
|
|
|
## Data Flow
|
|
|
|
```text
|
|
Bambuddy Archives
|
|
|
|
|
| webhook or polling
|
|
v
|
|
bambuddy-inventree-sync
|
|
|
|
|
| InvenTree API
|
|
v
|
|
Part + StockItem + Parameters + Image
|
|
|
|
|
| Bambuddy API
|
|
v
|
|
Archive external_url -> InvenTree Part page
|
|
```
|
|
|
|
## InvenTree Mapping
|
|
|
|
| Bambuddy data | InvenTree target |
|
|
| --- | --- |
|
|
| archive/model identity | `Part` |
|
|
| successful print archive | `StockItem` |
|
|
| target category | `Part.category` |
|
|
| target storage | `StockItem.location` |
|
|
| archive id | `StockItem.batch = bambuddy-<archive_id>` |
|
|
| filament weight | `Part` parameter `Weight` |
|
|
| print time | `Part` parameter `PrintTime` |
|
|
| archive thumbnail | `Part.image` |
|
|
| InvenTree part page | Bambuddy `external_url` |
|
|
|
|
## Duplicate Protection
|
|
|
|
The service is idempotent:
|
|
|
|
- each Bambuddy archive ID is stored in `data/sync.sqlite3`;
|
|
- each `StockItem` gets batch `bambuddy-<archive_id>`;
|
|
- rerunning backfill does not create duplicate stock items;
|
|
- repeat prints of the same file/model reuse the same `Part` and create new `StockItem` rows.
|
|
|
|
The `Part` identity key is controlled by:
|
|
|
|
```env
|
|
PART_KEY_FIELDS=content_hash,filename,print_name,name
|
|
```
|
|
|
|
The generated key becomes an InvenTree IPN:
|
|
|
|
```text
|
|
BMB-<first-12-sha1-chars>
|
|
```
|
|
|
|
## Delete Policy
|
|
|
|
If an archive is deleted in Bambuddy after it was synced, the corresponding InvenTree data is not deleted.
|
|
|
|
This is intentional. InvenTree is the inventory record, and deleting print history in Bambuddy should not silently remove stock records. The synced `Part`, `StockItem`, parameters, and image remain in InvenTree.
|
|
|
|
## Requirements
|
|
|
|
- Docker with Linux containers enabled.
|
|
- Network access from the sync container to Bambuddy API and InvenTree API.
|
|
- Bambuddy API key.
|
|
- InvenTree API token.
|
|
- Existing InvenTree part category ID.
|
|
- Existing InvenTree stock location ID.
|
|
- Optional InvenTree parameter templates: `Weight` and `PrintTime`.
|
|
|
|
On Windows Server 2022, verify Docker with:
|
|
|
|
```powershell
|
|
docker run --rm hello-world
|
|
docker run --rm python:3.12-slim python --version
|
|
```
|
|
|
|
## Docker Deployment
|
|
|
|
Clone the repository:
|
|
|
|
```powershell
|
|
git clone https://git.tcom.space/tcom/Lab8DATAPROCESSOR.git
|
|
cd Lab8DATAPROCESSOR
|
|
```
|
|
|
|
Create the runtime config:
|
|
|
|
```powershell
|
|
Copy-Item .env.example .env
|
|
notepad .env
|
|
```
|
|
|
|
Start the service:
|
|
|
|
```powershell
|
|
docker compose up -d --build
|
|
```
|
|
|
|
View logs:
|
|
|
|
```powershell
|
|
docker compose logs --tail=100
|
|
```
|
|
|
|
Stop the service:
|
|
|
|
```powershell
|
|
docker compose down
|
|
```
|
|
|
|
Update to the latest version:
|
|
|
|
```powershell
|
|
git pull
|
|
docker compose up -d --build
|
|
```
|
|
|
|
## Configuration
|
|
|
|
Example `.env`:
|
|
|
|
```env
|
|
BAMBUDDY_BASE_URL=http://192.168.1.5:8000/api/v1
|
|
BAMBUDDY_API_KEY=replace-with-bambuddy-api-key
|
|
|
|
INVENTREE_BASE_URL=http://192.168.0.3:1337
|
|
INVENTREE_WEB_URL=
|
|
INVENTREE_TOKEN=replace-with-inventree-token
|
|
INVENTREE_PART_CATEGORY_ID=26
|
|
INVENTREE_STOCK_LOCATION_ID=98
|
|
|
|
SERVICE_API_TOKEN=change-me
|
|
WEBHOOK_SHARED_SECRET=
|
|
|
|
SYNC_SUCCESS_ONLY=true
|
|
SYNC_PART_IMAGES=true
|
|
OVERWRITE_PART_IMAGES=false
|
|
SYNC_ARCHIVE_EXTERNAL_LINK=true
|
|
OVERWRITE_ARCHIVE_EXTERNAL_LINK=false
|
|
|
|
DEFAULT_STOCK_QUANTITY=1
|
|
INVENTREE_STOCK_STATUS=10
|
|
PART_IPN_PREFIX=BMB
|
|
PART_KEY_FIELDS=content_hash,filename,print_name,name
|
|
|
|
BACKFILL_PAGE_SIZE=50
|
|
POLL_INTERVAL_SECONDS=300
|
|
SYNC_ON_STARTUP=false
|
|
HTTP_TIMEOUT_SECONDS=30
|
|
DATA_DIR=/data
|
|
```
|
|
|
|
Do not commit `.env`. It contains API tokens and is ignored by git.
|
|
|
|
## Important Settings
|
|
|
|
`BAMBUDDY_BASE_URL`
|
|
: Bambuddy API base URL. Use `/api/v1`.
|
|
|
|
`INVENTREE_BASE_URL`
|
|
: InvenTree root URL or `/api` URL. The service normalizes it internally.
|
|
|
|
`INVENTREE_WEB_URL`
|
|
: Browser-facing InvenTree URL for Bambuddy external links. If empty, `INVENTREE_BASE_URL` is used.
|
|
|
|
`INVENTREE_PART_CATEGORY_ID`
|
|
: Existing InvenTree category where auto-created printed parts are placed.
|
|
|
|
`INVENTREE_STOCK_LOCATION_ID`
|
|
: Existing InvenTree stock location where printed stock items are placed.
|
|
|
|
`SYNC_SUCCESS_ONLY`
|
|
: When `true`, only successful/completed prints are imported.
|
|
|
|
`POLL_INTERVAL_SECONDS`
|
|
: Enables automatic periodic backfill. `300` means every 5 minutes. `0` disables polling.
|
|
|
|
`SYNC_PART_IMAGES`
|
|
: Downloads Bambuddy thumbnail and uploads it to InvenTree `Part.image`.
|
|
|
|
`OVERWRITE_PART_IMAGES`
|
|
: When `false`, manually set InvenTree part images are preserved.
|
|
|
|
`SYNC_ARCHIVE_EXTERNAL_LINK`
|
|
: Writes the InvenTree part page URL into Bambuddy `external_url`.
|
|
|
|
`OVERWRITE_ARCHIVE_EXTERNAL_LINK`
|
|
: When `false`, existing non-InvenTree external links in Bambuddy are preserved.
|
|
|
|
## InvenTree IDs
|
|
|
|
Use numeric IDs for target category and stock location. You can find them from the InvenTree UI URL or API.
|
|
|
|
Example:
|
|
|
|
```powershell
|
|
curl.exe -H "Authorization: Token YOUR_TOKEN" http://192.168.0.3:1337/api/part/category/26/
|
|
curl.exe -H "Authorization: Token YOUR_TOKEN" http://192.168.0.3:1337/api/stock/location/98/
|
|
```
|
|
|
|
Current known example:
|
|
|
|
```env
|
|
INVENTREE_PART_CATEGORY_ID=26
|
|
INVENTREE_STOCK_LOCATION_ID=98
|
|
```
|
|
|
|
## Validate Connectivity
|
|
|
|
After the container starts:
|
|
|
|
```powershell
|
|
curl.exe http://localhost:8088/health
|
|
curl.exe -H "X-Service-Token: change-me" http://localhost:8088/validate
|
|
```
|
|
|
|
Expected result:
|
|
|
|
- `/health` returns `status: ok`;
|
|
- `/validate` confirms Bambuddy, InvenTree category, and InvenTree location are reachable.
|
|
|
|
## Initial Backfill
|
|
|
|
Test one successful archive first:
|
|
|
|
```powershell
|
|
curl.exe -X POST -H "X-Service-Token: change-me" "http://localhost:8088/sync/backfill?max_archives=1"
|
|
```
|
|
|
|
Run full backfill:
|
|
|
|
```powershell
|
|
curl.exe -X POST -H "X-Service-Token: change-me" http://localhost:8088/sync/backfill
|
|
```
|
|
|
|
Check status:
|
|
|
|
```powershell
|
|
curl.exe -H "X-Service-Token: change-me" http://localhost:8088/sync/status
|
|
```
|
|
|
|
When `SYNC_SUCCESS_ONLY=true`, still-printing or failed archives are skipped and do not consume `max_archives`.
|
|
|
|
## Automatic Operation
|
|
|
|
Recommended production mode:
|
|
|
|
```env
|
|
SYNC_SUCCESS_ONLY=true
|
|
POLL_INTERVAL_SECONDS=300
|
|
SYNC_ON_STARTUP=false
|
|
```
|
|
|
|
This makes the service check Bambuddy every 5 minutes and import all newly completed prints.
|
|
|
|
For near-real-time syncing, also configure a Bambuddy webhook:
|
|
|
|
```text
|
|
http://WINDOWS-SERVER-IP:8088/webhooks/bambuddy
|
|
```
|
|
|
|
Use the `print_complete` event. If `WEBHOOK_SHARED_SECRET` is set, Bambuddy must send:
|
|
|
|
```text
|
|
X-Sync-Secret: your-secret
|
|
```
|
|
|
|
Running both webhook and polling is recommended. Webhook gives fast sync, polling catches missed events after restarts or temporary failures.
|
|
|
|
## Manual Sync
|
|
|
|
Sync one archive:
|
|
|
|
```powershell
|
|
curl.exe -X POST -H "X-Service-Token: change-me" http://localhost:8088/sync/archive/11
|
|
```
|
|
|
|
Force re-sync one archive:
|
|
|
|
```powershell
|
|
curl.exe -X POST -H "X-Service-Token: change-me" "http://localhost:8088/sync/archive/11?force=true"
|
|
```
|
|
|
|
Force sync is useful after changing image, parameter, or external link behavior.
|
|
|
|
## API Endpoints
|
|
|
|
```text
|
|
GET /health
|
|
GET /validate
|
|
GET /sync/status
|
|
POST /sync/archive/{archive_id}
|
|
POST /sync/backfill
|
|
POST /webhooks/bambuddy
|
|
```
|
|
|
|
Manual sync endpoints require `X-Service-Token` when `SERVICE_API_TOKEN` is set.
|
|
|
|
## Troubleshooting
|
|
|
|
View recent logs:
|
|
|
|
```powershell
|
|
docker compose logs --tail=100
|
|
```
|
|
|
|
Rebuild after pulling code changes:
|
|
|
|
```powershell
|
|
git pull
|
|
docker compose up -d --build
|
|
```
|
|
|
|
Common issues:
|
|
|
|
- `401` from service endpoints: missing or wrong `X-Service-Token`.
|
|
- `401` from Bambuddy: wrong `BAMBUDDY_API_KEY`.
|
|
- `401` from InvenTree: wrong `INVENTREE_TOKEN`.
|
|
- InvenTree `description` length errors: update to the latest service version; descriptions are capped at 250 characters.
|
|
- No items imported: check if Bambuddy archives are still `printing` or `failed`.
|
|
- Duplicate protection prevents repeated imports: use `force=true` only when you want to refresh parameters/images/links for an existing archive.
|
|
|
|
## Backups
|
|
|
|
Persistent sync state is stored in:
|
|
|
|
```text
|
|
./data/sync.sqlite3
|
|
```
|
|
|
|
Back up the `data` directory together with `.env` if you move the service to another server.
|