Move the authenticated drift check into the repository as
tools/compat_auth.py, run daily by .github/workflows/compat-auth.yml on the
maintainer's forge only. Credentials come from FH_EMAIL and FH_PASSWORD, the
output is pass/fail labels only because the run log is public, and a failed
run pushes the report to ntfy. Exit 5 means all hold, 10 drift, anything
else that it could not run.
Point compat.yml, tools/compat.py and the docs at it, add a README section,
and cut 0.5.1.
Ship icon, wordmark logo, and a dark-theme logo variant in the
integration's brand/ folder, served locally by Home Assistant 2026.3+
(home-assistant/brands no longer accepts custom integrations). Add the
wordmark to the README and a trademark note to the disclaimer.
The compat badge was red on bookkeeping, not on compatibility: the check passed
16/16 and the run then failed trying to commit the refreshed matrix and open a
PR. That step should never have existed here — GitHub is a read-only mirror of
Gitea, so anything a bot pushes is clobbered by the next sync. It now publishes
the matrix to the run summary and the workflow only needs contents:read, so the
badge means what it says.
The README had grown into an implementation document. Endpoints, markup traps,
the login handshake and the drift-detection design move to docs/internals.md;
what is left is installation, entities, events, the dashboard, requirements and
troubleshooting.
It still claimed a refresh was a single GET; it has been three since
subscriptions and vacation holds were added, and write actions cost more again
because every mutating endpoint needs its tokens fetched first.
Promotes three more markup traps out of commit messages and into the docs:
popups are fragments with no Sign Out control, openPobyup is written with and
without a space after the comma, and a select's id is not its POST field. Each
cost real debugging time and none is guessable from outside.
Notes that every break so far has been silent, which is the argument for the
compatibility checks existing at all.
Rebuilds the README entity docs around the distinction that kept causing
confusion — the produce box is chosen, its contents are read-only, and only
add-ons are a list you edit — and re-exports the dashboard view now running,
including the date labels that stop the to-do list and the totals reading as a
contradiction.
pytest could not even collect: actions.py imports yarl for URL joining, which
Home Assistant ships but a bare CI python does not. The suite passed locally
only because the venv had picked it up as a transitive dependency.
The HACS check wants repository topics, which are GitHub-side metadata and so
cannot come from the canonical Gitea repo; set on the mirror directly.
actions.py covers skip, donate, cart add/remove, subscriptions and vacation
holds. Every mutating endpoint on the site is guarded by rotating per-render
tokens, so each action re-derives them from a live page rather than storing
anything; skip additionally compares the date the server states in its
confirmation against the date it was asked to skip, and refuses on a mismatch.
All actions default to dry_run.
tools/compat.py records what the integration assumes about a site that offers
no API and no stability contract, and CI asserts it daily. Only the
unauthenticated surface is covered: checking the rest would mean putting a
personal account password in public repo secrets.
Each cost line is now an entity rather than an attribute: subtotal, box price,
add-ons, tax and delivery fee, plus a total and free-delivery-remaining for the
open order, a delivery-day sensor, and a binary sensor that turns off at the
cutoff. Entities share a base class and declare a scope, so a description
states only the field it reads.
Also parses the driver tip, Bounty savings and the free-delivery threshold. The
threshold is carried across orders because the progress bar only renders on
carts that have not met it.
Adds LICENSE, hacs.json, a CI workflow, a pre-publish audit script, and a test
that cross-checks every entity's translation_key against both translation
files. Manifest URLs now point at GitHub rather than a private forge.
Add-on rows already carried quantity, unit and extended price; only the name
was exposed. The attribute now renders the full line and a new monetary
sensor reports the add-ons subtotal separately from the box.
The fixture totals were copied from a seven-add-on cart while the fixture
itself had one, so they are now self-consistent and a test asserts that
add-ons plus box price equals the portal's subtotal.
Reads delivery day, next arrival date, both upcoming carts, box contents,
add-ons and order totals from a single /p/dashboard/details fetch. Adds five
sensors and parser tests over a synthetic fixture mirroring the live markup.
Records two portal quirks: every /p/ path returns 200 so signed-in state is
detected by a Sign Out control, and cart-contents-skipped marks the locked
cart rather than a skipped order.
Implements the freshharvest.com two-step login handshake, config flow,
6-hour polling coordinator, and four delivery sensors. Portal page parsing
is not implemented; async_get_next_delivery raises until the account HTML
is mapped against a signed-in session.