--- name: weather description: Record a day's high temperature, low temperature, rainfall, growing degree days, solar energy, and freezing exposure in that day's daily note, read from the home weather station. Use whenever the user asks to log, add, backfill, or look up the weather for a date — including when they say only "yesterday's weather" or "add the weather to my daily note", when they ask about growing degree days, GDD, accumulated heat, solar energy, frost or freezing hours, and including the scheduled run that fills in the day that just ended. --- # weather — a day's weather in the daily note Shell the `weather-day` CLI from in this skill's `scripts` directory with the bash tool, then write its values into the daily note's frontmatter. Nothing here needs a key or a login — the station is public. ## Getting the numbers ``` weather-day [YYYY-MM-DD] # no argument: yesterday ``` One JSON object on stdout: ```json { "date": "2026-08-18", "station_id": 173994, "temp_high": 72.3, "temp_low": 54.1, "rainfall": 0.02, "gdd_base50": 11.4, "solar_energy_kwh_m2": 6.83, "observations": 287, "coverage_hours": 23.9 } ``` On a day that went below freezing, two more keys appear between `solar_energy_kwh_m2` and `observations`: ```json "hours_below_freezing": 7.2, "freezing_degree_hours": 31.8, ``` | key | units | what it is | |---|---|---| | `temp_high`, `temp_low` | °F | the day's extremes | | `rainfall` | inches | total for the day | | `gdd_base50` | °F-days | growing degree days, base 50°F | | `solar_energy_kwh_m2` | kWh/m² | total solar energy on a horizontal surface | | `hours_below_freezing` | hours | time spent under 32°F | | `freezing_degree_hours` | °F-hours | how far under 32°F, integrated over that time | **Everything from `date` through `freezing_degree_hours` is a frontmatter key** — copy the values across unchanged rather than reformatting or re-rounding them. `observations` and `coverage_hours` are diagnostics; they stay out of the note. Three of them are written only when they have something to say. **`rainfall` is omitted from the note when it is `0`** — most days here are dry, and a `rainfall: 0` on four notes in five is noise that makes the days it did rain harder to spot. `hours_below_freezing` and `freezing_degree_hours` are omitted by `weather-day` itself on a day that never went below 32°F, so they are simply not there to copy. Either way the key's absence is the record: a dry day, a day with no frost. Note the difference in where the omission happens. `weather-day` always prints `rainfall`, `0` included — that is a measurement, and the CLI reports it. Dropping it is this skill's decision about the note, so do not expect the JSON to be missing it. **`gdd_base50` is one day's accumulation, not a running total.** It is the number you *sum* to answer a question — days from planting to harvest, from transplanting to first bloom, from fruit set to ripe. A single day's value on its own says very little. When the user asks "how many GDD since I planted the tomatoes", add up the `gdd_base50` of each daily note from that date forward; say how many days you summed and flag any in the range that have no value rather than treating a missing day as zero. Any failure exits non-zero with a message on stderr. Report it and stop; do not write a partial or guessed value into the note. That includes the station going quiet mid-day: the totals are integrals over the whole day, so rather than draw a straight line across an hour or more of missing readings, `weather-day` refuses the date outright. There is no partial answer to salvage and nothing to write — say which stretch is missing and leave the note alone. ## Check the coverage before writing `coverage_hours` is the span from the first observation to the last. A full day is ~24 (23 or 25 across a DST change). `observations` is a count, not a duration, and a low-looking one is not by itself a problem: the API answers a day-long range on a 5-minute grid, so a complete day is around 288, not the ~1440 a per-minute feed would give. Judge the day by `coverage_hours`. **If `coverage_hours` is under 20, do not write to the note.** Tell the user the day is only partly covered and give them the numbers to judge. A high or low computed from part of a day looks entirely normal in the frontmatter and stays wrong forever. It usually means the station was offline for a stretch, or the date asked for is today and the day hasn't finished. A hole *inside* the day is a hard failure rather than a low `coverage_hours`, so a number that gets here has no outage longer than an hour in it. What `coverage_hours` still catches is a day the station started or stopped reporting partway through — and for the totals that is worse than for the extremes: `gdd_base50` and `solar_energy_kwh_m2` are missing the hours that never arrived, so they come out low, plausibly, and stay that way in every season sum afterwards. ## Writing it into the note The note is `/daily/.md` — the date exactly as `weather-day` echoed it back, and the absolute path, always. **If the note exists:** add or update only the keys you are writing. Every other key keeps its value and its position, and the body is untouched — the vault syncs live from other devices, so a rewritten note is a sync conflict waiting to happen. Add new keys at the end of the frontmatter block. **If the note does not exist:** create it with just those keys and the date as an H1. ```markdown --- temp_high: 72.3 temp_low: 54.1 rainfall: 0.02 gdd_base50: 11.4 solar_energy_kwh_m2: 6.83 --- # 2026-08-18 ``` A dry day with no frost is the common shape, and has neither `rainfall` nor the freezing pair: ```markdown --- temp_high: 78.1 temp_low: 55.6 gdd_base50: 14.4 solar_energy_kwh_m2: 7.02 --- # 2026-08-19 ``` **Any of those keys you are not writing, delete from the note if it is already there** — `rainfall` when the day was dry, `hours_below_freezing` and `freezing_degree_hours` when it never froze. Absence is the record, so a value left behind from an earlier run reports rain or a frost that did not happen, in exactly the format a real one would take. This is the one case where this skill removes rather than only adds, and it reaches only those three keys — never anything else in the frontmatter. Re-running a date is otherwise safe: the same keys get the same values again. ## Reading it back To answer "what was the weather on X" for a day already recorded, read the note's frontmatter — that is faster than a station call and it is the recorded value. Call `weather-day` when the note has no weather keys yet, or when the user wants the station's answer rather than the note's. **A missing `rainfall` on a note that carries the other weather keys means zero, not unknown.** The same goes for the freezing pair. So when totalling rain over a month or frost hours over a winter, a note with `temp_high` but no `rainfall` is a recorded dry day: count it as `0` and as a day you have data for. Reading it as a gap gets the total right by luck and everything around it wrong — it reports most of a dry July as unmeasured, and sends you re-running `weather-day` over days that were never missing. A note with *none* of the weather keys is the genuinely unrecorded case, and that one is worth saying out loud or filling in before answering. `gdd_base50` is different — it is written on every recorded day, including a `0`. A daily note missing it has not been filled in, and should be reported as a hole rather than summed as zero. ## A different station `STATION_ID` is a constant at the top of the `weather-day` script, in this skill's directory. Changing it needs an image rebuild; say so rather than trying to override it at the command line.