Inspiration
In August 2026, WHYY reported that more than half of Pennsylvania's waterways are unsafe for part of the year because of fecal bacteria. Philadelphia runs combined sewers: when it rains, sewage overflows into the rivers. People kayak, fish, and take boat tours on the Delaware at Penn's Landing, but nobody can answer a simple question: is it safe today? An E. coli lab culture takes 18 to 24 hours, so by the time a result exists, the day is over. PhillyRiverCast answers that question for one non-tidal stretch of the Schuylkill, using relationships fit to 1998–2000 data. The tidal Delaware, the busiest waterfront in the city, has nothing.
What it does
AquaSentinel is a virtual water-quality sensor for the Center City reach of the tidal Delaware. Every hour it estimates whether E. coli is likely above the 235 CFU/100 mL recreational single-sample limit and flags the reach Safe or Unsafe. It publishes that one estimate three ways:
- A live public dashboard with the current reading, history, and a map of nearby sewer outfalls.
- An agent-ready layer:
/api/statusJSON,llms.txt, JSON-LD, and a read-only MCP server, so a person's own AI assistant can answer "is it safe to kayak right now?" from the same stored reading. - Standards-based FHIR R4 to a (fictional, stubbed) regional public-health agency: an Observation built on the official HL7-EU OneAquaHealth Implementation Guide, marked preliminary and estimated so it is never mistaken for a lab result, plus a Flag that is active while Unsafe and goes inactive only after 48 continuous hours of Safe.
How we built it
Python 3.11, FastAPI, SQLite, scikit-learn, pandas, httpx, and the official MCP Python SDK, deployed on Render. A scheduler pulls at the top of every hour from the USGS Penn's Landing gauge (01467200), NWS hourly rainfall at KPHL (Open-Meteo as fallback), and the Philadelphia Water Department's CSOcast sewer-outfall feed. DRBC near-shore E. coli samples were used offline to train and validate the model.
Deterministic code decides the status, not the predictive model.
- A rainfall rule decides: at least 2.5 mm over the two previous days means Unsafe.
- A sewer-overflow rule can only raise the status, never lower it: a fresh overflow report within 5 km in the past 72 hours.
- A random forest on the gauge's temperature, conductance, dissolved oxygen, and pH reports how strongly it agrees with the rule.
The system fails closed: if rainfall data can't be obtained, the status goes "unavailable" rather than showing an all-clear it doesn't have.
Challenges we ran into
Labels are scarce. After joining 20 years of DRBC samples to the gauge and rainfall, the validation set is 69 sampled days, 30 of them unsafe. On that set the rainfall rule (F1 0.64) beat the random forest (F1 0.56), so we made the rule decide and kept the model for agreement only, instead of shipping the more impressive-sounding option. Rainfall records have gaps, the USGS water-quality sensors sometimes go quiet while flow keeps reporting, and many CSOcast outfalls report no data. Each of these needed an explicit, visible fallback.
Accomplishments that we're proud of
A deployed, live sensor for a reach no one covers; one stored reading that the dashboard, API, MCP server, and FHIR delivery all report identically (tested); fail-closed behavior throughout; and an honest account of where the model falls short.
What we learned
With a few dozen positive samples, a transparent rule is the honest choice, and saying so is stronger than overclaiming. Publishing for agents (MCP, llms.txt) is cheap and makes public data far more reachable than a color on a web page.
What's next for AquaSentinel
- A sampling coordinator that asks the agency for a confirmatory water sample when the rule and model disagree, feeding lab results back as new training labels so the system learns where it is unsure.
- A reader agent that extends the agent-ready pattern to other water-advisory sites.
- Portability: the method transfers to any reach with a continuous gauge, from Trenton to Chester.
- Proposing the alert profile upstream to the OneAquaHealth IG.
Built With
- fastapi
- fhir
- httpx
- mcp
- pandas
- python
- render
- scikit-learn
- sqlite
Log in or sign up for Devpost to join the conversation.