Skip to content

Add cook data logging foundation (SQLite history + sessions API)#22

Draft
CamSoper wants to merge 1 commit into
mainfrom
claude/charming-lovelace-705spk
Draft

Add cook data logging foundation (SQLite history + sessions API)#22
CamSoper wants to merge 1 commit into
mainfrom
claude/charming-lovelace-705spk

Conversation

@CamSoper

Copy link
Copy Markdown
Owner

Why

Inferno has strong real-time control (PID hold, fire health/reignition, lid detection, preheat) but nothing was persisted — temps and mode transitions lived in memory and were lost on every inferno-api restart. This PR adds a cook-data logging/persistence layer: the foundation for the features most likely to come next (probe target alarms, done-time/stall prediction, cook history & graphs, CSV export).

The LLM "pitmaster" advisor discussed during planning is intentionally deferred — this is the data foundation only.

What

  • SqliteCookLogStore (Microsoft.Data.Sqlite) — single long-lived connection; journal_mode=WAL + synchronous=NORMAL and batched transactions to minimize SD-card fsyncs; schema applied idempotently on init. A lock serializes access across the logger loop and request threads.
  • CookLogger — background sampling loop mirroring the existing DisplayUpdater/FireMinder pattern. Polls ISmoker.Status ~every 10s and infers cook-session boundaries from mode transitions, so it never touches the safety-critical state machine. Opens a session on entry to a cooking mode, keeps it through the Shutdown cooldown, closes on return to Ready. Resumes an in-progress session (or closes an orphan) after a restart.
  • SessionsControllerGET /api/sessions, GET /api/sessions/active, GET /api/sessions/{id}?from=&to=, GET /api/sessions/{id}/export.csv, POST /api/sessions/{id}/label.
  • Program.cs — store + logger registered as singletons; teardown order on ApplicationStopping is logger → smoker → store → gpio so logging flushes before the smoker tears down.
  • Inferno.Deploy — creates ~/inferno/data on the Pi (outside the publish dirs the deploy replaces, so history survives upgrades) before the api service starts.

Schema

cook_session (id, start/end time, label, peak grill/probe temp, sample_count) and sample (session_id, timestamp, grill/probe temp, mode, setpoint, pvalue, auger/blower/igniter/fire_healthy/preheated), indexed on (session_id, timestamp). v1 omits a discrete event table — per-sample mode reconstructs transitions at 10s resolution.

Testing

  • dotnet build Inferno.sln ✅   dotnet test Inferno.Tests ✅ (90 passing; 28 new)
  • New tests exercise the full store + logger path against a real (in-memory) SQLite DB: session open/close on mode transitions, no double-open across Smoke↔Hold↔Sear, startup resume/orphan handling, status→sample field mapping, batch-flush threshold, force-close + flush on dispose, and peak tracking.
  • The API process itself initializes GPIO/SPI on startup (Pi-only), so it isn't run off-device here — the new code path has no hardware dependency and is covered directly by tests. On-device verification (drive /api/mode, then GET /api/sessions* and the CSV export; restart mid-cook) is listed in the plan.

🤖 Generated with Claude Code

https://claude.ai/code/session_018HrUqCycauyXrhgs3o6KtN


Generated by Claude Code

Records every cook as a session with a time-series of samples, the
foundation for future features (probe alarms, done-time prediction,
history graphs). Nothing was previously persisted — temps and mode were
in-memory only and lost on every restart.

- SqliteCookLogStore: single long-lived connection, WAL + synchronous=NORMAL
  and batched transactions to bound SD-card writes; schema applied on init.
- CookLogger: background loop mirroring DisplayUpdater/FireMinder. Samples
  ISmoker.Status every ~10s and infers session boundaries from mode
  transitions, so it stays fully decoupled from the safety-critical state
  machine. Resumes an in-progress session (or closes an orphan) on restart.
- SessionsController: list / active / detail (time-bounded) / CSV export /
  label endpoints under /api/sessions.
- Program.cs: wire store + logger as singletons; dispose logger -> smoker ->
  store -> gpio so logging flushes before teardown.
- Inferno.Deploy: create ~/inferno/data on the Pi (lives outside the publish
  dirs so history survives upgrades) before the api service starts.
- Tests: 28 new tests covering session open/close on mode transitions,
  startup resume/orphan handling, sample mapping, batching, and peak tracking.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018HrUqCycauyXrhgs3o6KtN
@pulumi

pulumi Bot commented Jun 17, 2026

Copy link
Copy Markdown

🚀 The Update (preview) for CamSoper-org/inferno-deploy/main (at 30df637) was successful.

✨ Neo Code Review

Routine feature deployment adding cook history logging via SQLite. The API rebuild and service restart are expected; the new `ensure-data-dir` step safely pre-creates the data directory. ✅ Low Risk

This PR adds cook session history: a SQLite-backed store, a background polling logger, and REST endpoints for listing/exporting sessions. The infrastructure changes are driven by two things: the API source hash changed (new files/dependencies), triggering the publish-api and restart-api replacements, and the new ensure-data-dir step was added to pre-create ~/inferno/data/ on the Pi before the service starts.

🔵 Info — The ensure-data-dir step runs mkdir -p to create the DB directory outside the publish path, meaning cook history will survive future deployments. The restart-api replacement depends on it, so the service won't start until the directory exists. The DB path defaults to ~/inferno/data/inferno.db but can be overridden via INFERNO_DB_PATH.

🔵 Info — On first deploy, the API will create a fresh SQLite database. If the smoker happens to be mid-cook when the service restarts, CookLogger.ResumeOrReset() will detect no open session in the new DB and begin fresh tracking on the next tick — no cook history will be lost from a DB that didn't previously exist, but any session open at restart time will not be retroactively recorded.

Resource Changes

    Name             Type                    Operation
+-  restart-api      command:remote:Command  replaced
+   ensure-data-dir  command:remote:Command  create
+-  publish-api      command:local:Command   replaced

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.

2 participants