Skip to content

Offer the folder input in the Home Assistant app - #35

Merged
NerdyHank merged 3 commits into
mainfrom
folder-mode-in-ha-app
Oct 6, 2026
Merged

NerdyHank merged 3 commits into
mainfrom
folder-mode-in-ha-app

Conversation

@NerdyHank

Copy link
Copy Markdown
Contributor

Closes #31.

The directory watcher has been in the standalone service since 0.23.0, but the app never offered it. Three things were missing, and the third made the other two pointless:

no folder_* options nothing to configure
frigate_url mandatory a Frigate-less setup could not even be saved
/media and /share not mounted no path under them was readable at all

Reported by a user with five Reolink cameras and no Frigate, uploading snapshots to /media over FTP.

What changed

  • frigate_url is now optional. An empty URL means no Frigate — frigate_client already derives enabled from the URL and returns the no-op client, so the gallery, unknown review and history stay usable.
  • map: [media:ro, share:ro]. Read-only: FaceID never changes or deletes what it watches.
  • Eleven folder_* options, written into a folder: block in the generated config.
  • run.sh refuses to start with neither input configured, and warns when folder_path does not exist inside the container — naming the two mounted roots, since a path the app cannot see is the likeliest mistake.
  • In folder mode the camera sensor is announced at startup. The folder has no camera list to query, so the name comes from the configuration. Without it a fresh install shows no sensor until the first recognition and looks dead.

A second defect, found by the new test

cross_risk_margin, self_outlier_ratio and history_keep were offered by the app and read by the service, but run.sh never wrote them into the generated config — settable and inert. Same defect as #24, in three more fields.

tests/test_addon_options.py now checks that every option reaches the generated config, that schema and options cover each other, and that free text goes through the jq encoder rather than being interpolated raw.

Verified

The real run.sh template was evaluated against an options.json carrying quotes in both the MQTT password and the camera name:

frigate.url   = ''                      -> DisabledFrigateAPI
mqtt.password = 'p"w\'x'                 quotes survive
folder.camera = 'front door "1"'
extensions    = ['.jpeg', '.jpg', '.png', '.webp']

The generated YAML parses, and FolderIngest plus frigate_client accept it unchanged.

The reported setup — one file overwritten per motion event — measured and pinned as a test: three overwrites are three recognitions, one index entry. The fingerprint is size and mtime, not the name.

72 tests green.

🤖 Generated with Claude Code

The directory watcher has been in the standalone service since 0.23.0, but the
app never offered it. Three things were missing, and the third made the other
two pointless:

- no folder_* options and no folder block in the generated config
- frigate_url was mandatory, so a Frigate-less setup could not even be saved
- /media and /share were not mounted, so no path under them was readable

Requested in #31 by a user with five Reolink cameras and no Frigate, uploading
snapshots to /media over FTP.

An empty frigate_url now means no Frigate; frigate_client already derives
enabled from the URL and returns the no-op client. run.sh refuses to start with
neither input set, and warns when folder_path is missing inside the container,
naming the two mounted roots - a path the app cannot see is the likeliest
mistake.

In folder mode the camera sensor is announced at startup. The folder has no
camera list to query, so the name comes from the configuration; without it a
fresh install shows no sensor until the first recognition and looks dead.

Also fixes three options that were settable and inert: cross_risk_margin,
self_outlier_ratio and history_keep were read by the service but never written
by run.sh - the same defect as #24, in three more fields. A new test checks
every option reaches the generated config, that schema and defaults cover each
other, and that free text goes through the jq encoder.

Verified by evaluating the real run.sh template against a options.json with
quotes in the password and the camera name: the generated YAML parses, the
quotes survive, and FolderIngest plus frigate_client accept it. The reported
setup - one file overwritten per event - is covered by a test: three overwrites
are three recognitions, one index entry.

72 tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@the-codemole

the-codemole Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

🧪 Automated PR Checks

Profile: python-app · auto-detected · ⚙ Configurable

✅ python-syntax — 5 Python file(s) compile cleanly
✅ ruff — 5 Python file(s) — ruff clean (E9/F)
⚪ json-valid — ⏭️ No JSON files in the diff
✅ diff-size — Diff +449/-8 in 11 files
✅ secret-scan — No plaintext secrets in the added lines
✅ conflict-markers — No merge conflict markers
✅ sensitive-files — No sensitive file types in the diff

hermes-work · branch folder-mode-in-ha-app · base main · What do these checks do?

Comment thread app/mqtt_listener.py Outdated
The folder camera was added after the or-chain had already evaluated
_frigate_cameras(). Harmless in pure folder mode - frigate_enabled is False
there, so the method returns an empty set without touching the network - but
pointless, and in a mixed setup (Frigate on plus folder) it means a network
call with a timeout runs before a name that was already known locally.

Local sources first, Frigate only when nothing is known. The folder camera
still joins the configured ones rather than replacing them, so a setup with
both inputs announces both.

Two tests: Frigate is not queried when the folder name suffices, and is still
queried when nothing else is known.

74 tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
the-codemole[bot]
the-codemole Bot previously approved these changes Oct 6, 2026

@the-codemole the-codemole Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — review complete.

  • Checks: 6 passed, 1 skipped, 0 failed
  • 1 finding(s) addressed, no open threads

Comment thread app/mqtt_listener.py Outdated
@the-codemole
the-codemole Bot dismissed their stale review October 6, 2026 10:33

No longer clean — approval withdrawn.

The previous commit let the folder camera short-circuit the discovery
chain, so a setup running Frigate *and* the folder watcher never queried
Frigate for its camera list and only got one sensor. The folder camera is
now unioned onto the result instead of replacing it, and Frigate is
skipped only when Frigate itself is disabled.

@the-codemole the-codemole Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — review complete.

  • Checks: 6 passed, 1 skipped, 0 failed
  • 1 finding(s) addressed, no open threads

@NerdyHank
NerdyHank merged commit 9db9b24 into main Oct 6, 2026
1 check passed
@NerdyHank
NerdyHank deleted the folder-mode-in-ha-app branch October 6, 2026 11:24
@NerdyHank
NerdyHank restored the folder-mode-in-ha-app branch October 6, 2026 11:25
@NerdyHank
NerdyHank deleted the folder-mode-in-ha-app branch October 6, 2026 11:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: expose folder mode (non-Frigate) in the Home Assistant app

2 participants