Skip to content

readings tool: any stored reading at an interval, each row with its time - #63

Merged
robdevops merged 2 commits into
mainfrom
claude/envirobot-next
Nov 9, 2026
Merged

robdevops merged 2 commits into
mainfrom
claude/envirobot-next

Conversation

@robdevops

Copy link
Copy Markdown
Owner
  • "What was the humidity each hour for the last 5 hours" got "the tool can't give me an hour-by-hour table", because weather_history only sends a period's lows and highs. The new readings tool (lib/history.py) returns a row per interval, read straight from ecobot.sqlite.
  • Inputs: a metric (outdoor.humidity, rainfall.rain, air.pm2_5 …), a start, an optional end, and an interval: 1min, 5min, 30min, 1hour, 4hour or 1day.
  • Intervals:
    • An interval a sensor stores is read as it is. Any other is worked out from finer readings, never coarser ones (the air sensor's older hourly history is not split into half hours).
    • Intervals are blocks of local time: an hour runs from :00 to :00, a day from midnight.
    • The exception is 4hour, which follows the station's own 4-hour records. Ecowitt cuts those on UTC hours, so in AEDT they start at 3am, 7am and so on.
  • Rows: means per 30-minute slot, as the charts take them. Gusts give the records' own highest. Rain gives the mm that fell in the interval, with the midnight reset handled. Air particles have glitches removed, as air_quality does. Days come from the day rows, with the times of their lows and highs.
  • Gaps: a gap is a row with no value. Where a period is held only at a coarser interval (or only as day rows), the result says which interval to ask for (fits).
  • Size limit: at most 300 rows a request. A longer request is refused, and the refusal names the finest interval that fits.
  • Metrics offered: only those each sensor has actually sent. The air sensor's own temperature and humidity are offered only when the question names them.
  • Routing (lib/intent.py): "each hour", "every 30 minutes", "every ten minutes", "hourly" and "in 15 minute steps" reach the model, which the prompt points at readings. Before, some of these took a code shortcut to a highs-and-lows summary.
    • A chart of hourly values ("hourly rain chart 7d") is still drawn in code.
    • "miles per hour" and "km/h per hour" are units, not intervals.
  • scripts/show_request.py can run the tool against a file.
  • A review (three reviewers, each finding checked by an agent trying to refute it) confirmed 18 problems in the first commit; the second commit fixes them:
    • Rain at the seam between two resolutions read as a midnight reset: 11.8 mm for an hour that had 1.5 mm.
    • 4-hour records were filed into the wrong blocks.
    • Gusts ignored each record's own highest.
    • The tool suggested a coarser interval when only the latest, still-filling row was empty.
    • Several smaller ones: glitches at the edge of the window, start and end times sent with a time-zone offset, off-by-one row limits, and the metric lookup falling back to another sensor.
  • Checks: pytest passed (1,123 tests, 20 of them for the new tool) and the offline evals passed (92 cases, 2 new). The live evals, which ask the real model, were not run because they need the OpenRouter key.

Generated by Claude Code

… row with its time

"What was the humidity each hour for the last 5 hours" got "the tool can't give me an hour-by-hour table":
weather_history only sends a period's lows and highs. The new `readings` tool (lib/history.py) takes a
metric (outdoor.humidity, rainfall.rain, air.pm2_5 ...), a start, an end and an interval, and returns a
row per interval read straight from ecobot.sqlite:

- every interval for every reading: one the sensor stores is read as it is, any other is worked out from
  its finer readings (never coarser: the air sensor's older hourly history isn't split into half hours);
  intervals are blocks of local time (an hour from :00, four hours from midnight)
- means per 30-minute slot as the charts take them; gusts the highest; rain the mm that fell (the daily
  total's rise, midnight reset included); air particles without glitches, as air_quality has them;
  days from the day rows, with when their extremes happened
- at most 300 rows: a longer request is refused with the finest interval that fits; gaps are rows with
  no value, and a period held only coarser says which interval to ask for
- the metrics offered are what each sensor has sent; the air sensor's own temperature and humidity
  only when the words name them

"each hour", "every 30 minutes", "hourly" no longer take the fast path to a highs-and-lows summary
(intent.INTERVAL); the prompt sends them to readings. scripts/show_request.py runs the tool on a file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WBwHofjb1g9onaYRdLZMbf
…er hints, routing)

The readings tool:
- rain from two resolutions: a coarser reading counts only where no finer one falls in the time it
  covers; their times mean different moments, so the seam read as a midnight reset (11.8 mm for an
  hour that had 1.5)
- 4hour rows are the station's own 4-hour records, cut on UTC hours as Ecowitt cuts them (3am, 7am
  ... in AEDT); a stored reading counts only in an interval that holds all its time, never straddling
- gusts take the records' own highest, not the first gust stored
- "ask for a coarser interval" only for empty rows a coarser reading (or a day row) actually covers,
  never for the interval still filling; an all-empty result with one says to ask again
- an air glitch at the window's edge is judged by the readings just outside it, as air_quality does
- a sensor named is kept ("air.humidity" is the air sensor's own, never outdoor's); a time with an
  offset ("...Z") is moved into local time; the interval offered instead is always one then accepted

Routing (intent): a chart of hourly values is still drawn in code; "miles per hour", "km/h per hour"
are units, not intervals; "every ten minutes", "every half an hour", "in 15 minute steps" and
"highest hourly rain each month" reach the model instead of a highs-and-lows shortcut.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WBwHofjb1g9onaYRdLZMbf
@robdevops
robdevops merged commit 1cfa5de into main Nov 9, 2026
3 checks passed
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