The water-bill projector code is open source
When I wrote about projecting my water bill a few days back, some asked "where's the code?" So I cleaned it up and put it on GitHub.
Repo: github.com/mr-sk/water-bill-projector
The original was a personal script with my meter ID, my rate schedule, and my credentials baked in. Making it public meant pulling all of that out and turning it into something you can point at your own meter. The rate tiers, the billing-cycle day, the sprinkler schedule and the timezone are now config at the top of one file and the README walks through filling them in from your own water bill.
A few things I generalized:
- No secrets. Your Eye on Water login lives in a local
.envthat never gets committed and the pulled meter data stays out of the repo. - No assumptions about your setup. The rate schedule ships as an example you replace. If you don't run sprinklers, set the schedule to empty and that whole section drops out of the report cleanly.
- It runs anywhere. The nightly agent that reads the report and posts it to Discord is optional. The scripts run fine from a plain cron job.
How it's put together
Two Python scripts and a wrapper:
pull_usage.pyauthenticates to Eye on Water through thepyonwaterclient and pulls about 90 days of hourly readings intodata/as CSV and JSON. The meter reports a cumulative lifetime total, so usage is the difference between consecutive readings.water-report.pyreads those readings, prices them against your tiered schedule, projects the full-cycle bill with a confidence band, checks the sprinkler window, and prints a plain-text report.water-report.shruns both: refresh, then report.
Running it is three lines:
cp .env.example .env # your Eye on Water login
pip install -r requirements.txt
./water-report.sh # pull the data, print the report
Everything you tune lives in one config block at the top of water-report.py:
# rates from your bill; 1 CGL = 100 gallons, tiers are cumulative for the month
RATE_TIERS = [(10, 0.7118), (30, 0.7472), (36, 0.9690), (float("inf"), 1.0172)]
SERVICE_CHARGE = 18.83 # flat monthly charge
BILLING_CYCLE_START_DAY = 21 # many utilities don't bill on the 1st
SPRINKLER_DAYS = {0, 2, 4} # Mon/Wed/Fri; use set() if you don't irrigate
Timezone is set with WATER_TZ (defaults to America/New_York), and WATER_CSV
can point the report at a specific meter file. The README has a full walkthrough for
reading your rate tiers off a bill, including the conversions if your meter isn't in
gallons.
The nightly run
On my setup this fires once a night from an
OpenClaw cron (0 21 * * *). It runs the
script, and a local model on a Mac Studio (served through Apple's MLX) reads the
report and posts a short summary to Discord. No usage data leaves the machine. That
agent layer is optional. The scripts are plain Python, so a one-line cron
entry does the job if you'd rather skip it.
It works with any utility on the Eye on Water platform (mine is Liberty). If yours bills in different units the conversion and the rate math are the parts to adjust and the README covers that.
If you point it at your own meter I'd like to hear how it goes. You can reach me at sk@skheavyindustries.com