Initial commit

This commit is contained in:
Mustafa KURU
2026-05-03 23:47:54 +03:00
commit 1dac1749bf
74 changed files with 6697 additions and 0 deletions
+107
View File
@@ -0,0 +1,107 @@
# HACS Publishing Checklist
This repository is a HACS `integration` because it installs a Home Assistant
custom integration under `custom_components/elegoo_spaghetti_detection`.
It is not a HACS `plugin`/Dashboard item. Dashboard plugins are JavaScript
frontend assets, usually installed from `dist/`.
## Current HACS Requirements
For a custom integration repository:
- The repository must be public and hosted on GitHub.
- The repository must have a clear GitHub description.
- The repository must have GitHub topics.
- GitHub issues must be enabled.
- The repository must have a README that explains how to use the integration.
- `hacs.json` must exist in the repository root and contain at least `name`.
- There must be only one integration directory under `custom_components/`.
- All files required for the integration itself must be inside
`custom_components/elegoo_spaghetti_detection/`.
- The integration `manifest.json` must define at least:
- `domain`
- `documentation`
- `issue_tracker`
- `codeowners`
- `name`
- `version`
- The integration must provide brand assets. This repo includes:
- `custom_components/elegoo_spaghetti_detection/brand/icon.png`
- `custom_components/elegoo_spaghetti_detection/brand/logo.png`
- If submitted as a default HACS repository, these GitHub Actions must pass:
- HACS Action with `category: integration`
- Hassfest
- A full GitHub release is required before submitting to `hacs/default`. A tag
alone is not enough.
## Default Store Submission
To request inclusion in the default HACS store:
1. Confirm the repository can be added manually as a HACS custom repository.
2. Confirm HACS Action passes without errors or ignored checks.
3. Confirm Hassfest passes.
4. Create a full GitHub release, for example `v1.0.0`.
5. Fork `hacs/default`.
6. Add `hepter/ha-elegoo-spaghetti-detection` alphabetically to the
`integration` file.
7. Open a PR from a branch in the fork. Do not submit the PR from an
organization account, because the PR must be editable.
HACS default repository reviews can take months. Until it is accepted, users can
install this repo through HACS as a custom repository.
## Repository Metadata To Set On GitHub
These were set on GitHub on 2026-05-01. Verify them before opening a HACS
default PR:
- Description:
- `Elegoo FDM printer spaghetti detection for Home Assistant with a local Obico ML server`
- Topics:
- `home-assistant`
- `hacs`
- `hacs-integration`
- `custom-integration`
- `elegoo`
- `fdm`
- `3d-printer`
- `spaghetti-detection`
- `obico`
- Issues:
- Enabled
## Workflows In This Repo
- `.github/workflows/validate.yaml`
- Runs `hacs/action@main` with `category: integration`.
- `.github/workflows/hassfest.yaml`
- Runs `home-assistant/actions/hassfest@master`.
- `.github/workflows/ci.yaml`
- Runs basic JSON, Python syntax, and YAML validation.
- `.github/dependabot.yml`
- Keeps GitHub Actions versions current.
## Release Notes
For the first HACS-ready release:
- Use a SemVer tag such as `v1.0.0`.
- Ensure `custom_components/elegoo_spaghetti_detection/manifest.json`
contains the matching version without the leading `v`, for example `1.0.0`.
- Publish a full GitHub release after workflows pass.
## References
- HACS publish general requirements:
- https://hacs.xyz/docs/publish/start/
- HACS integration requirements:
- https://hacs.xyz/docs/publish/integration/
- HACS default repository inclusion:
- https://hacs.xyz/docs/publish/include/
- HACS validation action:
- https://hacs.xyz/docs/publish/action/
- Home Assistant integration manifest:
- https://developers.home-assistant.io/docs/creating_integration_manifest/
- Local custom integration brand assets:
- https://developers.home-assistant.io/blog/2026/02/24/brands-proxy-api
+67
View File
@@ -0,0 +1,67 @@
# Automation Examples
The integration only detects failures and emits entities/events. Printer actions
use your own Home Assistant entities directly.
Example Elegoo CC2 entities used by the templates:
```text
button.elegoo_centauri_carbon2_pause_print
button.elegoo_centauri_carbon2_resume_print
button.elegoo_centauri_carbon2_stop_print
camera.elegoo_centauri_carbon2_chamber_camera
sensor.elegoo_centauri_carbon2_print_status
```
Your entity IDs may differ if your printer/device name differs.
## Included Examples
- [Notify only](../examples/notify_only.yaml)
- [Actionable mobile notification with pause/stop/resume](../examples/actionable_notification.yaml)
- [Confidence-based pause/stop](../examples/smart_pause_stop_by_confidence.yaml)
- [Manual test notification](../examples/manual_test_notification.yaml)
## Event Data
Use `elegoo_spaghetti_detection_detected` for notifications and printer
actions. When a print status sensor is configured, scheduled detected events are
sent once per active print window to avoid repeated pause/notify loops. Use
`elegoo_spaghetti_detection_result` only when you intentionally want every
detection result, including clear and warning checks.
These two events are intentionally different:
| Event | When it fires | Use for notifications/actions? |
| --- | --- | --- |
| `elegoo_spaghetti_detection_detected` | Only when a failure is detected and the active print window has not already emitted one detected event. | Yes. Use this for Pushbullet, mobile notifications, pause, and stop automations. |
| `elegoo_spaghetti_detection_result` | Every completed detection check, including clear, warning, and repeated detected checks. | Usually no. Use it only for logging, dashboards, or advanced automations that implement their own throttling. |
If an automation sends notifications from
`elegoo_spaghetti_detection_result`, it can still notify repeatedly every
detection interval. The included notification and pause/stop examples use
`elegoo_spaghetti_detection_detected` to avoid that.
Use these fields in templates:
```text
trigger.event.data.confidence
trigger.event.data.raw_score
trigger.event.data.detected
trigger.event.data.detections
trigger.event.data.image_url
trigger.event.data.printer_state
trigger.event.data.status
trigger.event.data.last_error
```
Confidence is a number between `0` and `1`. For notification text:
```jinja
{{ (trigger.event.data.confidence | float(0) * 100) | round(1) }}%
```
The `image_url` field is the exact camera snapshot URL the ML server checked.
Mobile notifications can use it as an image attachment. If your phone is away
from the LAN, make sure the `Home Assistant Host` you configured is reachable
from that phone, or use a notification-only message without the image.
+124
View File
@@ -0,0 +1,124 @@
# Configuration
Open:
```text
Settings -> Devices & services -> Add integration -> Elegoo Spaghetti Detection
```
![Elegoo Spaghetti Detection setup form](images/config-flow-add-hub.png)
The setup form creates one detector. Add another detector for another camera.
Existing detector settings are reused as defaults to reduce repeated server
entry.
## Fields
| Field | Notes |
| --- | --- |
| `Detector name` | Display name for this camera/detector. |
| `Entity prefix` | Stable entity ID prefix, for example `elegoo_spaghetti_detection` or `elegoo_cc2_left`. |
| `Home Assistant Host` | URL reachable by the ML server. For Docker on another LAN host, prefer the HA LAN URL, for example `http://192.168.1.90:8123`. Do not use `homeassistant.local` unless the Docker host can resolve mDNS. |
| `Obico ML API Host` | Base URL of this project's ML server, for example `http://192.168.1.100:3333`. Do not enter `/hc/` or `/p/`. |
| `Obico ML API Auth Token` | Must match `ML_API_TOKEN` / `obico_api_secret` configured on the ML server. |
| `Camera` | Any HA camera entity. Example: `camera.elegoo_centauri_carbon2_chamber_camera`. Your device name may differ. |
| `Direct snapshot URL` | Optional. Leave empty to use the selected camera's HA camera proxy image. Use this only for unusual camera integrations. |
| `Print status sensor` | Optional but recommended. Example: `sensor.elegoo_centauri_carbon2_print_status`. Scheduled detection runs only when this entity is in an active print state. For Elegoo-style entity names, a matching `sensor.<printer>_current_status` is used automatically as an extra guard; you do not select it separately. |
| `Active print states` | Comma-separated states that mean printing. For Elegoo CC2, `printing` is usually enough. You can use `printing,printing_recovery`. |
| `Chamber light` | Optional. Example: `light.elegoo_centauri_carbon2_chamber_light`. |
| `Light control` | `Do not control light`, `Turn on before detection and leave on`, or `Restore previous state after detection`. Restore mode only turns the light off again when it was off before this detection cycle. |
| `Light settle delay` | Seconds to wait after the integration turns on an off light before taking the snapshot. Default is `3`; useful for camera exposure/focus. |
| `Run scheduled detection without print status` | Keep off unless this detector is camera-only and has no print status entity. |
| `Detection interval` | Seconds between scheduled checks while the print status is active. Examples: `600` for 10 minutes, `900` for 15 minutes. |
| `Sensitivity` | High, normal, low, or custom thresholds. |
| `Warning/Failure threshold` | Used when sensitivity is `Custom thresholds`. |
| `Detected event cooldown` | Minimum seconds between detected events. Default is `900` seconds. Scheduled checks with a print status sensor use the active print window limit instead, so this is mainly a fallback for camera-only setups and manual testing. |
## Print-State Guarding
The setup form asks for one status entity: `Print status sensor`.
For Elegoo printers, select the `print_status` entity:
```text
sensor.elegoo_centauri_carbon2_print_status
```
If the selected entity ends with `_print_status`, the integration automatically
checks for a sibling `_current_status` entity:
```text
sensor.elegoo_centauri_carbon2_current_status
```
There is no separate field for `current_status`. It is an automatic fallback
guard. Scheduled detection runs only when the selected `print_status` is active
and the inferred `current_status`, when present, is also active.
Example:
```text
print_status = printing
current_status = idle
result: scheduled detection does not run
```
This protects against printer/integration states where `print_status` remains
`printing` during homing, idle, or other non-print movement states.
## Repeated Notification Guarding
When a `Print status sensor` is selected, scheduled detection emits at most one
`elegoo_spaghetti_detection_detected` event while the printer remains in one of
the configured `Active print states`. If the selected status sensor or the
automatic `current_status` guard leaves the active states and later returns to
an active state, a new failure can emit one new detected event.
This is separate from the fallback guard above. The fallback guard decides
whether scheduled detection should run. The repeated-notification guard decides
whether a detected result should fire another notification/action event.
## Example Elegoo CC2 Values
These are examples from one `elegoo-homeassistant` install. Your entity IDs may
change if the Home Assistant device name differs.
```text
Entity prefix: elegoo_spaghetti_detection
Home Assistant Host: http://192.168.1.90:8123
Obico ML API Host: http://192.168.1.100:3333
Obico ML API Auth Token: obico_api_secret
Camera: camera.elegoo_centauri_carbon2_chamber_camera
Print status sensor: sensor.elegoo_centauri_carbon2_print_status
Active print states: printing
Chamber light: light.elegoo_centauri_carbon2_chamber_light
Light control: Restore previous state after detection
Light settle delay: 3
```
With restore mode, a scheduled check does this:
```text
light was off -> turn on -> wait -> snapshot/detect -> turn off
light was on -> snapshot/detect -> keep on
```
## Created Entities
With prefix `elegoo_spaghetti_detection`, the integration creates:
```text
binary_sensor.elegoo_spaghetti_detection_spaghetti_detected
sensor.elegoo_spaghetti_detection_confidence
sensor.elegoo_spaghetti_detection_raw_score
sensor.elegoo_spaghetti_detection_detections
sensor.elegoo_spaghetti_detection_status
sensor.elegoo_spaghetti_detection_last_error
sensor.elegoo_spaghetti_detection_last_run
sensor.elegoo_spaghetti_detection_next_run
button.elegoo_spaghetti_detection_test_spaghetti_detection
button.elegoo_spaghetti_detection_reset_detection_state
```
Press `Test Spaghetti Detection` to run one check immediately from the current
camera image, even if the printer is not printing.
+109
View File
@@ -0,0 +1,109 @@
# Dashboard Examples
These examples create a small Home Assistant dashboard section for one
spaghetti detector.
Replace entity IDs if your detector prefix, camera, printer, or automation names
are different. The examples use:
```text
camera.elegoo_centauri_carbon2_chamber_camera
sensor.elegoo_centauri_carbon2_print_status
sensor.elegoo_spaghetti_detection_status
sensor.elegoo_spaghetti_detection_next_run
sensor.elegoo_spaghetti_detection_last_run
sensor.elegoo_spaghetti_detection_last_error
sensor.elegoo_spaghetti_detection_confidence
sensor.elegoo_spaghetti_detection_raw_score
sensor.elegoo_spaghetti_detection_detections
binary_sensor.elegoo_spaghetti_detection_spaghetti_detected
button.elegoo_spaghetti_detection_test_spaghetti_detection
button.elegoo_spaghetti_detection_reset_detection_state
```
The enhanced example also references this placeholder automation:
```text
automation.elegoo_cc2_spaghetti_pause_and_notify
```
Replace it with your own notification or pause automation entity.
The toggle card in `dashboard_hacs.yaml` is only a placeholder until you make
that replacement.
## Status Labels
The dashboard examples render raw detector states as user-facing English labels:
| Raw state | Dashboard label |
| --- | --- |
| `clear` | Clear |
| `detected` | Failure detected |
| `warning` | Warning |
| `checking` | Checking |
| `waiting_for_print` | Waiting for print |
| `status_unavailable` | Print status unavailable |
| `busy` | Busy |
| `error` | Error |
| `idle` | Idle |
This avoids a mixed display where Home Assistant shows an unknown printer state
while the detector correctly reports `waiting_for_print`.
## Core Home Assistant Example
Use this when you do not want extra Lovelace dependencies:
- [examples/dashboard_core.yaml](../examples/dashboard_core.yaml)
It uses only built-in cards:
- `picture-entity`
- `markdown`
- `gauge`
- `conditional`
- `button`
- `entities`
## Enhanced HACS Example
Use this when custom Lovelace cards are allowed:
- [examples/dashboard_hacs.yaml](../examples/dashboard_hacs.yaml)
Idle state:
![Enhanced dashboard idle state](images/dashboard-hacs-waiting-for-print.png)
Detected failure state:
![Enhanced dashboard detected failure](images/dashboard-hacs-detected.png)
Recommended custom cards:
- `custom:button-card`
- `custom:mushroom-template-card`
- `card_mod`
Install those through HACS before pasting the enhanced YAML. The enhanced
version adds a compact status panel, better visual states, responsive metric
tiles, and an alert card when spaghetti is detected.
## Next Scheduled Check
The integration exposes:
```text
sensor.<prefix>_next_run
```
For the default prefix this is:
```text
sensor.elegoo_spaghetti_detection_next_run
```
The value is updated when the integration starts and every time the scheduled
interval fires. It represents the next scheduled interval tick. If the print
status is not active, the detector still waits at that tick and keeps the status
as `waiting_for_print`.
Binary file not shown.

After

Width:  |  Height:  |  Size: 715 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

+43
View File
@@ -0,0 +1,43 @@
# Installation
## HACS Custom Repository
This repository is a HACS `integration`. It is not a dashboard card or Lovelace
plugin.
Until it is accepted into the default HACS store, add it manually:
1. Open Home Assistant.
2. Open `HACS`.
3. Open the three-dot menu.
4. Choose `Custom repositories`.
5. Repository:
```text
https://github.com/hepter/ha-elegoo-spaghetti-detection
```
6. Category: `Integration`.
7. Install `Elegoo Spaghetti Detection`.
8. Restart Home Assistant.
## Manual Install
Copy:
```text
custom_components/elegoo_spaghetti_detection
```
to:
```text
/config/custom_components/elegoo_spaghetti_detection
```
Restart Home Assistant.
## ML Server
The integration needs the local ML server before setup can complete. See
[ML server and logs](ml-server.md).
+96
View File
@@ -0,0 +1,96 @@
# ML Server And Logs
The ML server listens on port `3333` and exposes the Obico/TSD model used for
failure detection.
## Standalone Docker Compose
```bash
git clone https://github.com/hepter/ha-elegoo-spaghetti-detection.git
cd ha-elegoo-spaghetti-detection
docker compose up -d
```
Default URL:
```text
http://<server-ip>:3333
```
Default token:
```text
obico_api_secret
```
Change `ML_API_TOKEN` before exposing this service outside a trusted local
network.
## Runtime Endpoints
| Endpoint | Auth | Purpose |
| --- | --- | --- |
| `/` | no | Small browser status page and recent redacted requests. |
| `/hc/` | no | Health check, returns `ok`. |
| `/api/status` | no | JSON status, model backend, threshold, request count. |
| `/api/logs?token=<token>` | yes | Recent request logs. Image query tokens are not shown in the dashboard. |
| `/debug/image?img=<url>&token=<token>` | yes | Fetch and decode a camera image without running inference. Used by setup validation. |
| `/p/?img=<url>` | yes | Prediction endpoint used by Home Assistant. |
The token can be passed as either:
```text
Authorization: Bearer <token>
```
or, for browser debugging only:
```text
?token=<token>
```
## CPU/GPU Behavior
The server is CPU-first by default:
```text
ML_USE_GPU=false
ML_MODEL_BACKEND=onnx
GUNICORN_TIMEOUT=120
GUNICORN_WORKERS=1
```
This avoids slow CUDA probing and gunicorn worker timeouts on machines without a
working NVIDIA runtime. Enable GPU only when Docker has working NVIDIA support:
```text
ML_USE_GPU=true
```
## Logs
Docker:
```bash
docker logs -f ha_elegoo_spaghetti_detection
```
Recent in-app request log:
```bash
curl "http://<server-ip>:3333/api/logs?token=obico_api_secret"
```
Health and model backend:
```bash
curl "http://<server-ip>:3333/api/status"
```
When testing a camera URL by hand, URL-encode the image URL:
```bash
curl --get "http://<server-ip>:3333/debug/image" \
--data-urlencode "img=http://homeassistant.local:8123/api/camera_proxy/camera.example?token=..." \
--data-urlencode "token=obico_api_secret"
```
+145
View File
@@ -0,0 +1,145 @@
# Troubleshooting
## Setup Fails On ML Health
Use the ML server base URL, not a specific endpoint:
```text
http://192.168.1.100:3333
```
Do not enter:
```text
http://192.168.1.100:3333/hc/
http://192.168.1.100:3333/p/
```
Check:
```bash
curl "http://192.168.1.100:3333/hc/"
```
The browser dashboard is also useful:
```text
http://192.168.1.100:3333/
```
## Setup Fails On Camera Image Fetch
The ML server must be able to fetch the Home Assistant camera image URL.
Common cause:
```text
http://homeassistant.local:8123
```
works from a browser but not from a Docker container because mDNS is not
resolved there.
Use a LAN IP URL reachable by the ML server:
```text
http://192.168.1.90:8123
```
You can test only image fetch/decode without running the model:
```bash
curl --get "http://192.168.1.100:3333/debug/image" \
--data-urlencode "img=http://192.168.1.90:8123/api/camera_proxy/camera.example?token=..." \
--data-urlencode "token=obico_api_secret"
```
## Camera Entity Does Not Provide An Image
Some camera integrations expose stream-only entities or changed entity IDs after
updates. Set `Direct snapshot URL` if the selected camera has no `entity_picture`
attribute, or update the detector options after the camera entity ID changes.
## Multiple Detectors
Each config entry has a separate detector runtime and entity prefix. The Home
Assistant side supports multiple cameras.
The ML server is intentionally single-worker by default. The integration
serializes ML calls so multiple detectors do not hit the single worker at the
same instant. If you have a stronger host and many cameras, increase
`GUNICORN_WORKERS` carefully.
## CUDA Or Worker Timeout
The server defaults to CPU mode:
```text
ML_USE_GPU=false
GUNICORN_TIMEOUT=120
```
Only enable GPU when Docker has a working NVIDIA runtime. If you see CUDA driver
errors, keep GPU disabled.
## Detection Looks Too Quiet
Open the ML server dashboard:
```text
http://<server-ip>:3333/
```
Or check recent request logs:
```bash
curl "http://<server-ip>:3333/api/logs?token=obico_api_secret"
```
You can also press the `Test Spaghetti Detection` button in Home Assistant.
## Scheduled Detection Runs While Printer Is Idle
Scheduled detection is gated by `Print status sensor` unless
`Run scheduled detection without print status` is enabled.
Check these options first:
```text
Print status sensor: sensor.elegoo_centauri_carbon2_print_status
Active print states: printing
Run scheduled detection without print status: off
```
If the status sensor is `idle`, `complete`, `paused`, `unknown`, or
`unavailable`, the scheduled interval should wait and the detector status should
show `waiting_for_print` or `status_unavailable`.
For Elegoo-style entity names, a selected
`sensor.<printer>_print_status` automatically uses
`sensor.<printer>_current_status` as a second guard when that entity exists. If
`print_status` is `printing` but `current_status` is `idle`, `homing`, or
another non-active state, scheduled detection waits and `last_run` does not
advance.
The `Test Spaghetti Detection` button and the `run_detection` service with
`force: true` always run one manual check, even when the printer is not
printing.
## Notifications Repeat Every Interval
Notification, pause, and stop automations should trigger on:
```text
elegoo_spaghetti_detection_detected
```
Do not use this event for normal notifications:
```text
elegoo_spaghetti_detection_result
```
The result event fires after every completed detection check, including repeated
detected checks. The detected event is limited to one scheduled failure event
per active print window when a print status sensor is configured.