From 41431277cf0668b5567a861b3553a8d9f707dc0e Mon Sep 17 00:00:00 2001 From: Nick Date: Fri, 24 Oct 2025 17:18:57 +1100 Subject: [PATCH] More work on the management UI, multi printer is working, temps is sometimes working --- .../.github/copilot-instructions.md | 82 ++++ .../app/__pycache__/__init__.cpython-312.pyc | Bin 117 -> 117 bytes .../app/__pycache__/main.cpython-312.pyc | Bin 4588 -> 16062 bytes Web UI Project/app/config.json | 61 +++ Web UI Project/app/main.py | 419 ++++++++++++++---- .../app/templates/_connect_area.html | 26 -- .../app/templates/_printer_card.html | 34 ++ .../app/templates/_printer_grid.html | 14 + Web UI Project/app/templates/_status.html | 117 +++-- Web UI Project/app/templates/base.html | 14 +- Web UI Project/app/templates/index.html | 77 ++-- Web UI Project/docker-compose.yaml | 4 +- 12 files changed, 679 insertions(+), 169 deletions(-) create mode 100644 Web UI Project/.github/copilot-instructions.md create mode 100644 Web UI Project/app/config.json delete mode 100644 Web UI Project/app/templates/_connect_area.html create mode 100644 Web UI Project/app/templates/_printer_card.html create mode 100644 Web UI Project/app/templates/_printer_grid.html diff --git a/Web UI Project/.github/copilot-instructions.md b/Web UI Project/.github/copilot-instructions.md new file mode 100644 index 0000000..b9db66c --- /dev/null +++ b/Web UI Project/.github/copilot-instructions.md @@ -0,0 +1,82 @@ +# AI Coding Agent Instructions + +## Project Overview +This is a 3D printer management web application that provides a real-time interface for monitoring and controlling a Bambu Labs printer via their API. The project uses FastAPI for the backend, HTMX for dynamic UI updates, and Jinja2 for templating. + +## Architecture + +### Key Components +- **FastAPI Backend** (`app/main.py`): Handles HTTP endpoints and printer communication +- **Templates** (`app/templates/`): Jinja2 templates with HTMX for dynamic updates +- **Static Assets** (`app/static/`): CSS and other static files +- **Docker Configuration**: Containerized deployment with live code reloading + +### Data Flow +1. FastAPI routes handle HTTP requests +2. Printer state is managed through `bambulabs_api` library +3. UI updates via HTMX endpoints returning partial HTML + +## Development Environment + +### Setup +```bash +# Build and start the container +docker compose up --build + +# Development server runs at: +# - HTTP: http://localhost:8000 +# - MQTT: ports 8883 (TLS), 6000 (unencrypted), 990 (WebSocket TLS) +``` + +### Live Development +- Code changes in `app/` are automatically reloaded +- Container mounts local `app/` directory for immediate updates + +## Key Patterns + +### Template Structure +- Base template: `templates/base.html` +- Partial templates prefixed with underscore (e.g., `_status.html`, `_connect_area.html`) +- HTMX used for dynamic content updates + +### State Management +- Connection state tracked in-memory via global variable +- Printer API interactions wrapped in try/except blocks +- Status updates polled every 500ms via HTMX trigger + +### UI Components +- Status panel auto-refreshes using `hx-trigger="every 500ms"` +- Connection state toggles between connect/disconnect UI +- Error handling displayed in status panel + +## Integration Points +- **Bambu Labs API**: Primary integration via `bambulabs_api` package +- **MQTT Communication**: Used for real-time printer updates +- **Configuration File**: Printer connection details stored in `app/config.json`: + ```json + { + "printer": { + "ip": "10.0.2.10", + "access_code": "e0f815a7", + "serial": "00M09A360300272" + } + } + ``` + +## Common Tasks + +### Adding New Printer Data +1. Add new field to `/status` endpoint in `main.py` +2. Update status dictionary in the route handler +3. Add corresponding UI element in `_status.html` template + +### Error Handling +- Wrap printer API calls in try/except blocks +- Return error status through template context +- Display errors in UI using dedicated error states + +## File Reference +- `main.py`: Core application logic and routes +- `templates/_status.html`: Real-time printer status display +- `templates/index.html`: Main page layout and connection UI +- `docker-compose.yaml`: Container configuration and port mappings \ No newline at end of file diff --git a/Web UI Project/app/__pycache__/__init__.cpython-312.pyc b/Web UI Project/app/__pycache__/__init__.cpython-312.pyc index 53d8f04069a0adfc456c19ad580fe8477ae67f5b..9e1b6dc4fbc25a988f688754108e7a4542c479b3 100644 GIT binary patch delta 17 XcmXRdaPaa%TYmCW8c* diff --git a/Web UI Project/app/__pycache__/main.cpython-312.pyc b/Web UI Project/app/__pycache__/main.cpython-312.pyc index 3d5c8ee4cfa977159194337a0bd8921718d4ed21..ecbb8caa90678e3de24012cf0d4c3289242401a2 100644 GIT binary patch literal 16062 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 eC$2w#_4!rL+PUAIz1Q now.date(): + status['finish_time'] = finish_time.strftime("%Y-%m-%d %I:%M %p") # Include date if not today + status['remaining_time'] = str(timedelta(seconds=int(remaining_time))) # stringify values for k in status: @@ -104,7 +370,12 @@ def status(request: Request): except Exception: status[k] = 'N/A' - return templates.TemplateResponse("_status.html", {"request": request, "status": status}) + printer_instance.status = status + return templates.TemplateResponse("_status.html", { + "request": request, + "printer": printer_instance, + "status": status + }) diff --git a/Web UI Project/app/templates/_connect_area.html b/Web UI Project/app/templates/_connect_area.html deleted file mode 100644 index 698db70..0000000 --- a/Web UI Project/app/templates/_connect_area.html +++ /dev/null @@ -1,26 +0,0 @@ -
- {% if connected %} -
- -
- - -
- {% else %} -
- -
- {% endif %} -
diff --git a/Web UI Project/app/templates/_printer_card.html b/Web UI Project/app/templates/_printer_card.html new file mode 100644 index 0000000..e9ba8aa --- /dev/null +++ b/Web UI Project/app/templates/_printer_card.html @@ -0,0 +1,34 @@ +
+

{{ printer.name }}

+ + + {% if printer.connected %} +
+ +
+ + +
+
+ {% else %} +
+ +
+ {% endif %} +
\ No newline at end of file diff --git a/Web UI Project/app/templates/_printer_grid.html b/Web UI Project/app/templates/_printer_grid.html new file mode 100644 index 0000000..3f96c92 --- /dev/null +++ b/Web UI Project/app/templates/_printer_grid.html @@ -0,0 +1,14 @@ +
+ {% for printer in printers.values() %} + {% include "_printer_card.html" %} + {% else %} +
+ No printers configured. Check config.json file. +
+ {% endfor %} +
+ + +
+ Total Printers: {{ printers|length }} +
\ No newline at end of file diff --git a/Web UI Project/app/templates/_status.html b/Web UI Project/app/templates/_status.html index 80caa80..34742d7 100644 --- a/Web UI Project/app/templates/_status.html +++ b/Web UI Project/app/templates/_status.html @@ -1,37 +1,104 @@ -
+
{% if status.error %}
Error: {{ status.error }}
+ {% if status.debug_info %} +
+
Printer ID: {{ status.debug_info.id }}
+
Name: {{ status.debug_info.name }}
+
Connected: {{ status.debug_info.connected }}
+
+ {% endif %} {% else %} -
-
-
Current File
-
{{ status.current_file }}
-
-
-
Nozzle Temperature
-
{{ status.nozzle_temp }}
-
-
-
Bed Temperature
-
{{ status.bed_temp }}
+
+ +
+ Current File + {{ status.current_file }}
-
-
Chamber Temperature
-
{{ status.chamber_temp }}
+ + + +
+ Nozzle Temp +
+ {{ status.nozzle_temp|int }} + / +
+ + +
+
-
-
Progress
-
{{ status.percentage }}
+ +
+ Bed Temp +
+ {{ status.bed_temp|int }} + / +
+ + +
+
-
-
Remaining Time
-
{{ status.remaining_time }}
+ +
+ Chamber Temp + {{ status.chamber_temp }}
-
-
Time Done
-
{{ status.finish_time }}
+ +
+ Progress + {{ status.percentage }}
+ +
+ Time Left + {{ status.remaining_time }} +
+ +
+ Est. Done + {{ status.finish_time }} +
+
{% endif %}
diff --git a/Web UI Project/app/templates/base.html b/Web UI Project/app/templates/base.html index 291edd3..64129b5 100644 --- a/Web UI Project/app/templates/base.html +++ b/Web UI Project/app/templates/base.html @@ -10,9 +10,21 @@ + + -
+

X1 Carbon Connection

{% block connect %}{% endblock %}
diff --git a/Web UI Project/app/templates/index.html b/Web UI Project/app/templates/index.html index 2eef3fc..abeb066 100644 --- a/Web UI Project/app/templates/index.html +++ b/Web UI Project/app/templates/index.html @@ -1,52 +1,47 @@ {% extends "base.html" %} {% block connect %} - -
- {% if connected %} +
+ +
-
+
- -
- {% else %} -
- -
- {% endif %} + +
+
+ {% for printer in printers.values() %} +
+ {% include "_printer_card.html" %} +
+ {% else %} +
+ No printers configured. Check config.json file. +
+ {% endfor %} +
+ + +
+ Total Printers: {{ printers|length }} +
+
- -{% endblock %} - -{% block status %} - - - - - + {% endblock %} diff --git a/Web UI Project/docker-compose.yaml b/Web UI Project/docker-compose.yaml index e6a5a1b..aa99db4 100644 --- a/Web UI Project/docker-compose.yaml +++ b/Web UI Project/docker-compose.yaml @@ -1,8 +1,8 @@ services: web: build: . - image: fastapi-htmx:dev - container_name: fastapi-htmx + image: print-manager:dev + container_name: print-manager ports: - "8000:8000" - "8883:8883" # MQTT over TLS