Skip to content

Commit e4c7fe4

Browse files
committed
docs: new README with Groveland context, live chart auto-update
1 parent 1b255e3 commit e4c7fe4

2 files changed

Lines changed: 74 additions & 116 deletions

File tree

.github/workflows/chase.yml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Streamchaser
1+
name: Streamchaser
22

33
on:
44
schedule:
@@ -10,6 +10,8 @@ jobs:
1010
name: Fetch - Chart - Post
1111
runs-on: ubuntu-latest
1212
timeout-minutes: 12
13+
permissions:
14+
contents: write
1315

1416
env:
1517
USGS_STATION_ID: "11284400"
@@ -42,7 +44,18 @@ jobs:
4244
BLUESKY_APP_PASSWORD: ${{ secrets.BLUESKY_APP_PASSWORD }}
4345
run: python -m streamchaser
4446

45-
- name: Save chart image
47+
- name: Update chart in repo
48+
if: success()
49+
run: |
50+
mkdir -p chart
51+
cp /tmp/streamchaser_*.png chart/latest.png
52+
git config user.name "streamchaser-bot"
53+
git config user.email "bot@streamchaser"
54+
git add chart/latest.png
55+
git diff --staged --quiet || git commit -m "chore: update chart [skip ci]"
56+
git push
57+
58+
- name: Save chart artifact
4659
if: always()
4760
uses: actions/upload-artifact@v4
4861
with:

README.md

Lines changed: 59 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -2,59 +2,66 @@
22

33
> *You don't chase the water. You read it.*
44
5-
A GitHub Actions bot that monitors a USGS stream gauge and posts a daily field report — chart and stats — to Twitter/X and Bluesky. Automated. Unattended. Running whether you're watching or not.
5+
Big Creek runs through the hills above Groveland, California — my hometown. It drains the western slope of the Sierra Nevada, feeds Don Pedro Reservoir, and in a wet year it moves. In a dry year it barely whispers. After a storm rolls through, it can go from 6 cfs to 300 cfs in a matter of hours.
6+
7+
This bot watches it so I don't have to.
8+
9+
---
10+
11+
## Latest reading
12+
13+
![Latest chart](chart/latest.png)
14+
15+
*Updated every 6 hours by GitHub Actions. [Live USGS page →](https://waterdata.usgs.gov/monitoring-location/11284400/)*
616

717
---
818

9-
## What it does
19+
## Why this gauge
1020

11-
Every 6 hours (configurable), it pulls real-time streamflow data from the USGS National Water Information System, generates a chart, and posts to social media.
21+
**USGS 11284400 — Big C AB Whites Gulch NR Groveland CA**
1222

13-
**Each post includes:**
23+
Big Creek is the kind of creek that doesn't make the news until it does. It's the creek that runs behind the properties off Ferretti Road, the one that crosses under the highway on the way into town, the one that tells you whether the hills are saturated or bone dry. When the Sierra gets hit by an atmospheric river, Big Creek is where you watch the pulse arrive first.
1424

15-
- Current discharge in cfs with trend direction
16-
- Δ 1-hour and 24-hour change
17-
- 7-day flow record with annotated peak
18-
- Rate of change — accelerating, holding, decelerating
19-
- Flow vs. historical average for this date
20-
- Last-year reference
25+
The gauge has been running since 1969. Fifty-six years of record. Every storm, every drought, every fire year, every flood — it's all in there. The bot plots where today sits against all of it.
26+
27+
Operated in cooperation with [Turlock Irrigation District](https://www.tid.org/), which manages Don Pedro downstream. They care about this number too.
28+
29+
---
30+
31+
## What the chart shows
32+
33+
- **Current flow** in cubic feet per second, with trend direction
34+
- **7-day record** — the full hydrograph with annotated peak
35+
- **Percentile bands** — green band is the normal range (p25–p75) based on 56 years of same-date data
36+
- **Percentile needle** (right edge) — exactly where today's flow falls in the full historical distribution
37+
- **Rate of change** — accelerating, holding, or dropping off
38+
- **vs. long-term mean** — how this day compares to every same-date reading on record
2139

2240
---
2341

2442
## Repo layout
2543

2644
```
2745
streamchaser/
28-
├── .github/
29-
│ └── workflows/
30-
│ └── chase.yml # scheduled action
31-
├── src/
32-
│ └── streamchaser/
33-
│ ├── __init__.py
34-
│ ├── __main__.py # entry point
35-
│ ├── gauge.py # USGS data fetching + stat computation
36-
│ ├── chart.py # chart generation
37-
│ ├── chart_preview.py # local visual test (no API calls)
38-
│ └── poster.py # Twitter/X + Bluesky posting
39-
├── pixi.toml # environment + task runner
40-
├── pixi.lock # reproducible lockfile (commit this)
46+
├── .github/workflows/
47+
│ └── chase.yml # runs every 6 hours
48+
├── chart/
49+
│ └── latest.png # updated by the bot on every run
50+
├── src/streamchaser/
51+
│ ├── __main__.py # orchestration + post text
52+
│ ├── gauge.py # USGS API + stat computation
53+
│ ├── chart.py # matplotlib chart generation
54+
│ ├── chart_preview.py # local test render
55+
│ └── poster.py # Twitter/X + Bluesky
4156
└── README.md
4257
```
4358

4459
---
4560

46-
## Setup
61+
## Setup for another gauge
4762

48-
### 1. Fork and clone
49-
50-
```bash
51-
git clone https://github.com/YOUR_USERNAME/streamchaser.git
52-
cd streamchaser
53-
```
54-
55-
### 2. Configure your station
56-
57-
Open `.github/workflows/chase.yml` and set these three env vars:
63+
1. Fork the repo
64+
2. Edit the three env vars in `chase.yml`:
5865

5966
```yaml
6067
env:
@@ -63,103 +70,41 @@ env:
6370
USGS_HASHTAGS: "#USGS #BigCreek #Groveland"
6471
```
6572
66-
Find your station ID at [waterdata.usgs.gov](https://waterdata.usgs.gov/nwis/rt). Search by state, river, or location — look for a site with parameter `00060` (Discharge).
67-
68-
### 3. Add GitHub Secrets
69-
70-
**Settings → Secrets and variables → Actions → New repository secret**
71-
72-
#### Twitter / X
73-
74-
You need a free [developer account](https://developer.x.com) and an app with **Read + Write** permissions and **OAuth 1.0a** enabled.
75-
76-
| Secret | What it is | Where |
77-
|---|---|---|
78-
| `TWITTER_API_KEY` | Consumer Key | developer.x.com → Your App → Keys & Tokens |
79-
| `TWITTER_API_SECRET` | Consumer Secret | same |
80-
| `TWITTER_ACCESS_TOKEN` | Account Access Token | same → *Access Token & Secret* |
81-
| `TWITTER_ACCESS_SECRET` | Account Access Token Secret | same |
82-
83-
> **Note:** Access tokens are tied to *your account*. The app posts as you. Tokens generated under "Read only" permission won't work — regenerate them after switching to Read + Write.
84-
85-
#### Bluesky
86-
87-
No developer account needed. Just an App Password.
73+
3. Add 6 GitHub secrets (Settings → Secrets → Actions):
8874
89-
| Secret | What it is | Where |
90-
|---|---|---|
91-
| `BLUESKY_HANDLE` | Your handle | e.g. `yourname.bsky.social` |
92-
| `BLUESKY_APP_PASSWORD` | App-specific password | bsky.app → Settings → Privacy & Security → App Passwords → Add App Password |
75+
| Secret | What |
76+
|---|---|
77+
| `TWITTER_API_KEY` | Consumer Key — developer.x.com |
78+
| `TWITTER_API_SECRET` | Consumer Secret |
79+
| `TWITTER_ACCESS_TOKEN` | Access Token (needs Read+Write) |
80+
| `TWITTER_ACCESS_SECRET` | Access Token Secret |
81+
| `BLUESKY_HANDLE` | e.g. `yourname.bsky.social` |
82+
| `BLUESKY_APP_PASSWORD` | bsky.app → Settings → App Passwords |
9383

94-
> **Use an App Password, not your login password.** App Passwords are scoped and revocable.
95-
96-
### 4. Set posting frequency
97-
98-
Edit the cron in `chase.yml`:
99-
100-
```yaml
101-
- cron: '0 */6 * * *' # every 6 hours (default)
102-
# - cron: '0 * * * *' # every hour
103-
# - cron: '0 15 * * *' # once daily — 15:00 UTC / ~8am Pacific
104-
```
105-
106-
### 5. Disable a platform
107-
108-
```yaml
109-
POST_TWITTER: "false"
110-
POST_BLUESKY: "true"
111-
```
84+
4. Run workflow manually once to verify, then let the cron take over.
11285

11386
---
11487

115-
## Local development
116-
117-
Install [Pixi](https://pixi.sh) first:
118-
119-
```bash
120-
curl -fsSL https://pixi.sh/install.sh | bash
121-
```
88+
## Adjust post frequency
12289

123-
Then:
124-
125-
```bash
126-
# Install the environment (first time, or after pixi.toml changes)
127-
pixi install
128-
129-
# Generate a chart from mock data — no API calls, no posting
130-
pixi run chart
131-
# → Chart saved to /tmp/streamchaser_11284400_YYYYMMDD_HHMM.png
132-
133-
# Run the full bot (will post unless you disable platforms)
134-
export POST_TWITTER=false
135-
export POST_BLUESKY=false
136-
pixi run run
90+
```yaml
91+
- cron: '0 */6 * * *' # every 6 hours (default)
92+
- cron: '0 15 * * *' # once daily at 15:00 UTC
93+
- cron: '0 */3 * * *' # every 3 hours during storm season
13794
```
13895

139-
Pixi handles Python version, all dependencies, and task shortcuts in one lockfile. No virtualenv management needed.
140-
141-
---
142-
143-
## Debugging a run
144-
145-
Every GitHub Actions run uploads the generated chart as an artifact (kept 5 days).
146-
147-
**Actions tab → click the run → Artifacts → chart-N**
148-
149-
Download and inspect without needing to scroll your social feed.
150-
15196
---
15297

15398
## Data source
15499

155-
All flow data is fetched from the **USGS Water Services API** — public, no API key required.
100+
USGS National Water Information System — public API, no key required.
156101

157102
- Instantaneous values: `waterservices.usgs.gov/nwis/iv/`
158103
- Historical statistics: `waterservices.usgs.gov/nwis/stat/`
159-
- Parameter `00060` = Discharge (streamflow), cubic feet per second
104+
- Parameter `00060` = Discharge, cubic feet per second
160105

161106
---
162107

163108
## License
164109

165-
MIT
110+
MIT. Watch your own creek.

0 commit comments

Comments
 (0)