Inspiration
In coastal Bangladesh and the Mekong Delta, millions of people drink from wells the sea is slowly creeping into. A well that’s fine in January can be too salty to drink by March, and you can’t taste it until it’s already bad. Testing means a lab trip or test strips that run out. We wanted something cheap that tells you, right now, whether the water is okay.
What it does
Saltline is a module that slides onto a hand pump or water line and checks the salt level of the water passing through. Two stainless steel screws act as the electrodes, and a thermistor corrects the reading for temperature. The module shows an estimated sodium level in mg/L and updates an LED with the status. This then sends it over to our web server which gives a dashboard view of everything that’s going on. The servo then blocks the water so that saltwater doesn’t contaminate the freshwater supply. Every two seconds it sends a reading to our live dashboard at saltline.surf, which shows history and exports CSV. A Raspberry Pi sits between the sensor and the internet. It keeps its own local dashboard and CSV running, so the module keeps working and logging with no internet. When the connection returns, the Pi sends everything it missed, in order.
How we built it
Sensor. An Arduino Uno R3 reads the electrode pair as a voltage divider against a known resistor, which gives the cell resistance. We convert that to conductivity, normalize it to 25 °C using the thermistor on A5, and map it to sodium in mg/L. The Arduino also drives the status LED on D10, and the servo on D2. Connectivity. The Arduino has no Wi-Fi, so the raspberry pi acts as its access point. The Arduino’s data output connects to the pi’s USB port, and the Pi posts JSON to the dashboard using the internet. The Pi relay. A Python service (Flask, waitress, SQLite) runs on the Pi as a systemd unit. It answers the Arduino in about 5 ms (4.6 ms measured), so the sensor never waits on the internet or on TLS. Each reading goes into a SQLite outbox, and a background thread forwards it over HTTPS to saltline.surf, oldest first, with retries and backoff. Malformed payloads are marked dead instead of blocking the queue. Delivery is at-least-once, because we decided a duplicate reading is better than a lost one. Website. The relay forwards to saltline.surf, which stores readings in Supabase and serves the dashboard. A reading shows up on the site about 1.4 s after it reaches the Pi. Testing. The relay has 19 automated tests. We simulated an outage by pausing forwarding: 20 readings queued, drained in order on resume, none lost. The queue also survives a relay restart. We also wrote a calibration fitter that estimates the cell constant from known-concentration points. It recovers the constant exactly on synthetic data. [Add: did you run a real calibration with salt solutions? If so, give the cell constant and the solutions you used.] The physical build is 3D-printed parts plus PVC pipe and tubing from Home Depot.
Challenges we ran into
Time. Once we settled on an idea, we had to go get parts. The nearest Micro Center was 40 minutes away, and by the time the team got back it was 10 pm, so we worked late into the night. Getting the sensor online. We went in expecting to use an ESP32 for Wi-Fi, but we knew the Arduino’s pin layout better and were short on time, so we built on the Arduino. It has no Wi-Fi, so it took a lot of cable wrangling before we realized the Arduino had to be physically wired to the Pi, with one cable carrying both power and data. The Pi then does the networking. [If you want, add one line that an ESP32 is the obvious next step for a wireless module.] Data formats. We parallelized the work early and never standardized a format, so merging sensor, relay, and website meant everything disagreed. The worst offenders were small: measured values must be nested inside a probe object, and a decimal in seq or rssi crashed the server with a 500 instead of a clean error. We ended up writing an API contract and having the relay pass bodies through unchanged. Timestamps. During an outage, buffered readings land on the website at delivery time, not capture time, because the site stamps its own receipt time. The relay already supports sending the original timestamp. The website side is written but not merged.
…
Accomplishments that we're proud of
Getting the actual hardware all done was our biggest accomplishment. We turned two screws and a $10 microcontroller into a real salinity sensor, calibrated it ourselves, and made the result readable at a glance. The whole thing costs under $40 and needs no test strips or chemicals. All four of us had never done this kind of hardware work before, and we had to learn on the fly while dealing with lots of errors we’ve never even seen before. Apparently a flickering light means the raspberry pi booted correctly? We thought that meant something was wrong for the longest time.
What we learned
How conductivity works, why electrodes drift, and how much temperature skews a reading. Calibration is half the project. Put a buffer between a flaky network and a device that must keep measuring. Agreeing on a data format early is what lets hardware and software people build at the same time.
What's next for Saltline
Validate readings against lab tests of real well water. Conductivity counts all salts, not just sodium, so our mg/L figure is an estimate. Go wireless: an ESP32 or LoRa link to replace the cable, since many wells have no Wi-Fi, plus a way to keep the screws clean over months. Make the valve fully automatic, diverting salty water away from a drinking tank. [Adjust to match what the servo does now.] A floating buoy version with shallow and deep probes to catch salt rising from below. The relay and website already support it, but we cut it from this build and haven’t tested it. A Pi-run hotspot so the system works with no existing network.
Log in or sign up for Devpost to join the conversation.