Skip to content

Multipixelone/roomieorder

Repository files navigation

roomieorder

Build License Python Nix

A self-hosted Python service that turns a Home Assistant dashboard button into an automatic order — logged to Google Sheets and notified via Telegram. No confirm step; roommates are trusted.

Each item can declare two sources: Costco is tried first, falling back to Amazon when Costco is sold out, not carried, or over its price ceiling.

note: drives real Costco/Amazon checkout via Playwright. brittle by nature, against the stores' ToS, and requires a persistent logged-in browser profile per store. Costco fronts the site with Akamai bot detection, which is far more aggressive than most retailers' — the automation may be blocked outright.

Architecture

Two decoupled halves joined by a SQLite queue:

HA dashboard button → script.order_<item> → POST /reorder {item_key}
   validate + guards + enqueue → queue row (status=pending)

worker loop drains queue → Playwright buys → scrape order # + total
   → append to Google Sheet → Telegram notify

Intake is always-on; execution needs a live graphical session. Requests sit in the queue if the desktop is asleep and drain on wake.

Commands

Configuration

catalog.json maps item keys to shared fields (title, quantity, cooldown) plus a costco block (item number + URL) and/or an amazon block (ASIN + URL), each with its own expected price and price ceiling. Costco is tried first; Amazon is the fallback. At least one source is required. An optional owner field marks an item as one roommate's personal buy — the order is still placed for real, but the Sheets status column logs ordered for <owner> instead of placed so the shared log separates personal orders from shared-household ones. See examples/catalog.json and examples/env.example for the full schema.

Safety rails

  • DRY_RUN flag — stops before the final click; default true until you've confirmed each item reaches the review page cleanly
  • Double-tap guard — same item within 60 s is ignored
  • Per-item cooldowncooldown_days from the catalog
  • Price ceiling — per-source; on Costco an over-ceiling price falls back to Amazon, on the last store it aborts and alerts
  • Out-of-stock fallback — Costco sold out / not carried / not found falls back to the item's Amazon source
  • Daily spend cap — global $ ceiling per rolling 24 h; pauses worker and alerts on breach
  • Challenge detection — CAPTCHA / OTP pages halt the worker and ping you with a screenshot rather than looping

Health monitoring

  • Heartbeat — set ROOMIEORDER_HEARTBEAT_URL and the worker pings it on a timer (ROOMIEORDER_HEARTBEAT_INTERVAL_SECONDS, default 300). A wedged worker thread stops the pings and your monitor alerts — works with hosted Healthchecks.io or a self-hosted open-source instance, Uptime Kuma push, etc. Empty disables it.
  • Session freshness — set ROOMIEORDER_SESSION_CHECK_HOURS and the worker periodically relaunches each store profile read-only and notifies you if it's logged out, before a real order fails at the sign-in wall. Default 3; 0 disables it.
    • Activity gate — the probe opens a headed Chrome window, so when it's due it waits until you're away rather than stealing focus mid-game / mid-work. Any of these defers it (and it fires within ~5s of clearing — the interval timer only advances on a probe that runs):
      • ROOMIEORDER_SESSION_CHECK_WINDOW — only probe inside a local-time window, e.g. 03:00-08:00 (wrap past midnight allowed, 22:00-06:00). Empty (default) = any time. A malformed value fails the service at startup.
      • ROOMIEORDER_SESSION_CHECK_SKIP_GAMEMODE (default true) — skip while a game runs under gamemode, detected by ROOMIEORDER_SESSION_CHECK_GAMEMODE_CMD (default gamemoded -s); stdout containing is active defers.
      • ROOMIEORDER_SESSION_CHECK_IDLE_MINUTES (default 0 = off) — require this many idle minutes first. Wayland/Hyprland has no universal idle query, so the idle seconds come from ROOMIEORDER_SESSION_CHECK_IDLE_CMD (it must print idle seconds); with a threshold set but no/failed command the probe defers rather than risk popping a window.
    • roomieorder doctor prints an activity line with the live verdict so you can confirm detection works on your box.

Home Assistant integration

Each staple item gets a button card on the HA dashboard that calls a rest_command pointing at POST /reorder:

rest_command:
  roomieorder_reorder:
    url: "http://localhost:8723/reorder"
    method: POST
    content_type: "application/json"
    payload: '{"item_key": "{{ item_key }}"}'

script:
  order_paper_towels:
    sequence:
      - service: rest_command.roomieorder_reorder
        data: { item_key: "paper_towels" }

Google Sheets logging

Each order attempt appends a row: timestamp | item_key | title | provider | product_id | qty | unit_price | order_total | order_id | status | requester | notes

statusplaced | dry_run | skipped_cooldown | skipped_debounce | price_blocked | spend_capped | unavailable | needs_review | failed | challenge | blocked.

Requires a Google Cloud service account JSON with editor access on the target sheet.

State, backup & restore

All durable state lives under the configured paths (the systemd StateDirectory in the deployment):

  • ROOMIEORDER_DB (data/state.sqlite) — the queue, order history, spend accounting, and worker-pause flag. Back it up with the WAL checkpointed (sqlite3 state.sqlite ".backup backup.sqlite").
  • ROOMIEORDER_PROFILE_DIR (data/profile/{costco,amazon}) — the per-store browser profiles holding the signed-in sessions. These are what roomieorder login populates; restoring them avoids re-logging-in. Keep them private (they contain live auth cookies).
  • ROOMIEORDER_SHOTS_DIR (data/shots) — screenshots / DOM dumps; safe to discard (auto-pruned, see prune-shots).

To migrate to a new host, copy the DB and the profile dir; the catalog and env config come from your deployment.

Development

nix flake check
nix build .#packages.x86_64-linux.default

About

order things on Amazon from HASS

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors