Utilities Estimator — API
TL;DR
- POST /v1/utilities/estimate — address | lat/lon | zip | attribute overrides → {inputs_used, per-input sources, usage breakdown, monthly/annual by fuel, provider (+PTC), alternatives, confidence, disclaimers}. GET /v1/utilities/providers?county_fips|zip. GET /healthz.
- Resolution ladder: exact normalized address → zip+street → fuzzy prefix → nearest parcel ≤150 m → attribute/zip fallback → state averages; user overrides always win and are labeled user_override.
- Demo transcript (port 8096, then stopped): Lyndhurst merged home $274.54/mo high-confidence; Montclair 1907 oil $490.07; MOD-IV-only Manalapan $278.94 medium; propane override $393.13. Not deployed — intended target api.commutingcost.com (Krishna's call).
- 25 pytest tests green against PostgreSQL (never SQLite), ruff clean; pure-python model (stdlib math only) + asyncpg; config via COMMUTE_DSN env.
- Open for Krishna: deploy host/port, CJMLS RESO Heating field in reso_etl, GSMLS/NJMLS for full-Jersey coverage, usaddress upgrade if fuzzy match must beat 68.5%, Census key for ACS county fuel priors.
Home Utilities Cost Estimator API
Per-home monthly/annual utility costs (electric, natural gas, heating oil, propane) for any
US home — highest accuracy in NJ, where inputs are auto-derived from the 2.54M-home
nj_home_attributes backbone (MOD-IV assessment roll + county assessor sqft + CJMLS).
Model + data docs: MODEL.md. Rate layer: ../ENERGY.md.
energy/api/
├── app.py ← FastAPI service (async, Pydantic models)
├── db.py ← asyncpg queries: resolution, rates, prices, alternatives
├── model.py ← pure-python usage model (RECS-2020-calibrated)
├── coefficients.py ← AUTO-GENERATED fits (calibrate_recs.py)
├── calibrate_recs.py ← regenerates coefficients from data/recs2020_public_v7.csv
├── etl_nj_attributes.py ← builds commute.nj_home_attributes from geo DBs
├── addressing.py ← shared address/municipality normalizer
├── tests/ ← pytest (25 tests; API tests hit PostgreSQL, never SQLite)
└── MODEL.md ← variables, calibration, validation
Run (demo)
cd /home/krish/gpu-pilot/energy/api
.venv/bin/uvicorn app:app --host 127.0.0.1 --port 8096
# config: COMMUTE_DSN (default postgresql://krish@172.26.1.152:5433/commute)
Not deployed anywhere — intended production target is api.commutingcost.com integration (host/port/systemd = Krishna's call).
Endpoints
POST /v1/utilities/estimate
Body — any of: {"address": "..."}", {"lat":.., "lon":..}, {"zip": "07071"}, plus an
optional attributes override block (sqft, year_built, occupants, beds, heating_fuel,
water_heater_fuel, home_type, has_ac, room_ac). Precedence: overrides > resolved home >
defaults ladder. Every input's provenance comes back in sources.
curl -s -X POST http://127.0.0.1:8096/v1/utilities/estimate \
-H 'Content-Type: application/json' \
-d '{"address": "121 Summit Ave, Lyndhurst, NJ 07071"}'
curl -s -X POST http://127.0.0.1:8096/v1/utilities/estimate \
-H 'Content-Type: application/json' \
-d '{"zip": "07071", "attributes": {"sqft": 2400, "year_built": 2005,
"beds": 4, "heating_fuel": "propane"}}'
GET /v1/utilities/providers?county_fips=34013 | ?zip=07042
Serving utilities for the county: EIA-861 bundled residential ¢/kWh, customers, NJ BGS price-to-compare, retail-choice status.
GET /healthz
Demo transcript (2026-06-12, port 8096)
$ curl -s http://127.0.0.1:8096/healthz
{"ok":true,"nj_home_attributes":2540595}
== POST /v1/utilities/estimate {"address": "121 Summit Ave, Lyndhurst, NJ 07071"}
match: exact_address | source: merged | confidence: high
usage: 8150 kWh | 825 therms | 0 gal oil | 0 gal propane
monthly: {"electric": 172.35, "gas": 102.19, "oil": 0.0, "propane": 0.0, "total": 274.54}
provider: Public Service Elec & Gas Co 24.64 c/kWh | ptc: 10.938
alternatives: [{"provider": "Public Service Elec & Gas Co", "rate_cents_kwh": 20.417,
"vs_provider": "Rockland Electric Co", "benchmark_basis": "in-county",
"savings_usd_yr": 51.0, "electric_choice": true}]
== POST /v1/utilities/estimate {"address": "23 Grenada Place, Montclair, NJ 07042"}
match: exact_address | source: merged | confidence: high
usage: 9313 kWh | 0 therms | 604 gal oil | 0 gal propane
monthly: {"electric": 196.23, "gas": 0.0, "oil": 293.85, "propane": 0.0, "total": 490.07}
provider: Public Service Elec & Gas Co 24.64 c/kWh | ptc: 10.938
alternatives: [{"provider": "Jersey Central Power & Lt Co", "rate_cents_kwh": 15.647,
"vs_provider": "Public Service Elec & Gas Co", "benchmark_basis": "in-county",
"savings_usd_yr": 444.0, "electric_choice": true}]
== POST /v1/utilities/estimate {"address": "72 Old Queens Blvd, Manalapan, NJ"}
match: exact_address | source: modiv | confidence: medium
usage: 8533 kWh | 794 therms | 0 gal oil | 0 gal propane
monthly: {"electric": 180.21, "gas": 98.73, "oil": 0.0, "propane": 0.0, "total": 278.94}
provider: Public Service Elec & Gas Co 24.64 c/kWh | ptc: 10.938
alternatives: [{"provider": "Jersey Central Power & Lt Co", ... "savings_usd_yr": 407.0}]
== POST /v1/utilities/estimate {"zip": "07071", "attributes": {"sqft": 2400,
"year_built": 2005, "beds": 4, "heating_fuel": "propane"}}
match: None | source: None | confidence: high
usage: 9877 kWh | 0 therms | 0 gal oil | 582 gal propane
monthly: {"electric": 207.81, "gas": 0.0, "oil": 0.0, "propane": 185.32, "total": 393.13}
provider: Public Service Elec & Gas Co 24.64 c/kWh | ptc: 10.938
$ curl -s 'http://127.0.0.1:8096/v1/utilities/providers?zip=07042'
county: 34013 Essex
Public Service Elec & Gas Co 20.417 c/kWh, ptc: 10.938, choice: true
Jersey Central Power & Lt Co 15.647 c/kWh, ptc: 11.327, choice: true
Rebuild / refresh
.venv/bin/python calibrate_recs.py # refit on new RECS vintage -> coefficients.py
.venv/bin/python etl_nj_attributes.py # rebuild nj_home_attributes (idempotent truncate+load, ~75 s)
.venv/bin/python -m pytest tests/ -q # 25 tests (PostgreSQL)
.venv/bin/ruff check . && .venv/bin/ruff format --check .
Open items (Krishna)
- Deploy target/port for production (suggest behind api.commutingcost.com nginx; demo used 8096).
- reso_etl: map CJMLS RESO
Heating/Coolingfields — lifts heating-fuel coverage from 2.4% (remarks regex) to ~100% of listings. - GSMLS + NJMLS feeds for full-Jersey MLS coverage (CJMLS is Central-Jersey-centric; Bergen/Essex homes resolve via MOD-IV only today).
- Address normalization: stdlib normalizer is deliberate (zero deps);
usaddress(ML parser) is the upgrade if fuzzy match rate needs to climb above 68.5%. - Census API key for ACS B25040 county/tract heating-fuel priors.
- Forward-looking prices: PSE&G BGS 2026 PTC is loaded; gas supply (BGSS) and oil futures are not.