Devlog #4 – SchoolPool
I didn’t have an apple developer account when making this project, so rather than using TestFlight, I had to make an alternative. I set up GitHub Actions to build the app straight from the repo, zip it up, and attach it to a GitHub release automatically every time I push a version tag. Anyone can download that zip, drag it into their own Simulator, and run the real app in a couple minutes.
Devlog #8 – HydraCoaster
V3 IS HERE!!!!
THE PARTY ALWAYS ARRIVES
Shipping a celebration and reliably delivering one turn out to be different problems. V2 marked your once-a-day celebration as used the moment the phone sent the command — so if the coaster rejected it or the reply got lost in the air, the day burned with nothing played, and it never retried. Now the day is only recorded when the coaster confirms the flourish actually ran; a bad or lost reply clears the pending marker and the next qualifying sip simply sends it again.
Crossing 100% away from the coaster counts too. Log a glass at a restaurant, walk in the door, and the celebration fires the moment the coaster reconnects — no waiting for another sip. Amber pulses and ascending chirps, right on cue.
NO MORE VANISHING SIPS
The nastiest bug of the release: the app called itself “connected” the instant Bluetooth linked, before it had discovered where writes actually go. Everything that fires on connect — including the request for sips the coaster logged while your phone was away — hit a not-ready guard and was silently dropped. Offline sips just never backfilled. “Connected” now means ready-to-write, and a failed discovery disconnects for a clean retry. Every phone-free sip lands in your history on the next reconnect, every time.
A RING WITH A PULSE
The Today ring traded flat ink for an angular gradient with a liquid sheen, progress moves on a spring, and the first time it fills each day it does a quick scale pulse and pins a sparkly “goal reached” under the number — the on-phone echo of the coaster’s flourish. The streak flame bounces when your streak grows. The Awards tab got tinted icon circles on the stat tiles, earned badges on accent-washed gradient cards, badge symbols that bounce when unlocked, and a cascading entrance. Turn on Reduce Motion and all of it politely sits still.
PUSH TO PARTY
A Celebration Test button now lives in Settings, right under Buzz Test. Unlike Buzz Test, it respects your Sound and Light toggles, so it exercises the exact path a real goal celebration takes. A checkmark plus silence means your toggles are off — not that something’s broken.
Devlog #3 – SchoolPool
Picked the project back up after a couple of days away and spent the first stretch just untangling repo state — the iOS repo had diverged from GitHub (turns out global GPG signing was making merges silently hang), AdminViewModel had somehow been emptied out with a duplicate copy floating around, and the Firebase service account key wasn’t gitignored. Got all of that reconciled, merged, and pushed, then ran the full test suite: 41 unit tests green. Built and launched the app on the iPhone 16 simulator, re-seeded the demo school and rides, and grabbed fresh screenshots of a living ride feed.
Then I audited every source file for bugs and dead weight, and it turned up something genuinely bad: approving a verification request never actually updated the student’s user doc, so an approved student would stay stuck on the pending screen forever. On top of that, the admin review dashboard was fully built but unreachable — no navigation path led to it at all. Fixed both: approve/reject now flips the request and the user’s status + school in one atomic batch write, and the dashboard now lives in an Admin tab that only appears for school admins.
The backend got a matching rules pass too — school admins can now actually write verification status, ride requests and verification requests are validated against school boundaries, and rating reads are restricted to ride participants so nobody can scrape strangers’ ratings. All validated in the Firebase emulator and committed. Two loose ends for next time: the backend repo has no git remote configured, so those commits only exist on my machine, and the new rules still need a firebase deploy to actually hit production.
Devlog #7 – HydraCoaster
V2 IS HERE!!!!
SMARTER GOALS
Your daily goal can now be computed from weight, height, and activity level instead of picked from a wheel, and it scales up on hot or dry days using the same OpenWeatherMap feed that already drives reminder pacing. The Today ring shows the weather bump as a caption so a bigger goal never looks like a bug. Streaks and badges always judge against your base goal, since past days’ weather isn’t stored — that’s deliberate and documented in the code.
REAL DRINK TRACKING
A 61-drink catalog across 9 categories, each with a hydration factor — water is 1.0, espresso less, beer much less. Log drinks manually with the + button, or reclassify any coaster-detected sip after the fact. Apple Health entries are replaced in place when you reclassify, so Health always agrees with the app.
SLEEP-AWARE QUIET HOURS
The coaster no longer buzzes at 3am. Quiet hours come in three modes: off, manual times, or derived from your Health sleep data — a 14-day median of bedtime and wake, with naps filtered out and a noon-centered median so bedtimes straddling midnight don’t average to lunchtime. The phone converts your local window to UTC and rewrites it to the coaster on every connect and every half-hour weather tick, which means daylight-saving shifts fix themselves within one cycle and the firmware never learns what a timezone is. A reminder suppressed overnight isn’t lost — it fires on the first check after the window ends. Phone-side, notifications defer to fifteen minutes after wake, reminders got a snooze button, and three presets (Gentle, Standard, Persistent) scale how hard the whole system nags.
One casualty: the “Respect Focus” toggle. Apple’s Focus-status entitlement can’t ride on a free personal-team provisioning profile, so the feature is compiled out behind a flag with a note on how to restore it if the project ever gets a paid developer account.
STREAKS, BADGES, AWARDS
A fourth tab. Today’s hydration score, current streak, and longest streak up top; below, ten badges from First Sip to a 30-day streak, a lifetime 50 liters, an early-bird sip before 8am, and a perfect calendar week. Everything is recomputed from sip history on demand — nothing is stored, so the numbers can never drift from the data. A small flame chip appears on Today once you’re two days deep.
DEEPER HISTORY
Week and month chart ranges, a GitHub-style heatmap of the last twelve weday got to goal, a per-category drink breakdown, and CSV export of yourentire sip history from the share button — RFC-4180 quoted, ISO-8601 dates, ready for a spreadsheet.
THEMES AND A WIDGET
Four color themes — Aqua (the original), Sunset, Forest, Mono — plus a light/dark override, all applied live. A home-screen and lock-screen widget shows the progress ring and
streak, updated through an App Group the moment a sip lands.
THE COASTER CELEBRATES WITH YOU
New firmware command: the first time you hit 100% in a day, the coaster pirps with amber LED pulses — deliberately distinct from the reminder alertby both ear and eye. It respects your sound and light preferences, fires once per day, and triggers against the same weather-scaled goal the ring shows.
Devlog #6 – HydraCoaster
Today, I setup HydraCoaster with BLE and made a full-fledged iOS app! The whole reminder system is now onboard: sip detection, automatic zero-drift correction, and self-timed buzz reminders now run on the ESP32 with no computer anywhere. Sips get logged to flash and served over a custom BLE service: live weight streaming, history backfill, time sync, calibration commands, battery. The product build is BLE-only, but a dev build keeps WiFi OTA so reflashing stays cable-free.
The app has a sixty-second onboarding (pair + set a goal), Today screen with a goal ring and live weight, 14-day history chart, Settings with sound/light/reminder toggles, buzz test, notification test, reset data button, and a guided recalibration flow. Sips sync into SwiftData, write to Apple Health with their real timestamps, and the phone mirrors the coaster’s reminder as a local notification.
Devlog #2 – SchoolPool
Spent the session auditing and tightening the SchoolPool backend on the Spark plan. I found that any user could self-grant verified/schoolAdmin/adminSchoolIds at doc-create, and a driver could rewrite any ride field. Plus ratings could target strangers and rideRequests could forge a driverId to push-spam anyone. Also, the school search was fully broken. So I fixed both of them! :P
Devlog #5 – HydraCoaster
Printed and converted to V2 of the hardware enclosure (images not attached)! New CAD has an added cork base, and had to add the hardware for a buzzer as well.
Made HydraCoaster fully wireless! It now streams weight over WiFi (UDP), reflashes over the air, and the USB cable is optional. I also built a notification system: a piezo buzzer plays a three-tone alert (low for hearing loss, mid for loudness, high to beat noise-cancelling), with the onboard LED flashing white in sync.
The server detects sips from weight drops, and buzzes the coaster when you haven’t drunk for too long — 20 min base, shortened in hot/dry weather (OpenWeatherMap), relaxed after a good drinking session. Dashboard got a console showing location/temp/humidity/interval, a test buzz button, and persistent toggles for sound, LED, and reminders.
My portfolio is an airport now! Plain HTML, CSS, and one JS file — no framework, no build step, nothing to npm install. I love the look and feel of this site because it doesn’t feel like too much but I also don’t think that it’s too generic. I’m really happy with how this has turned out!
Cleared for takeoff at guptaronav.github.io/terminalfolio!!
My portfolio is an airport now! Plain HTML, CSS, and one JS file — no framework, no build step, nothing to npm install. I love the look and feel of this site because it doesn’t feel like too much but I also don’t think that it’s too generic. I’m really happy with how this has turned out!
Cleared for takeoff at guptaronav.github.io/terminalfolio!!
Devlog #1 – SchoolPool
Got all ten core features built and the app running on the simulator this week — creating and finding rides, booking seats, live ride status, chat, ratings, trip history, the works. Wired up the Firebase backend too and deployed the security rules and indexes, then seeded a fake school with a handful of rides so the discovery feed actually looks alive instead of empty.
Hit one wall: I’m still on Firebase’s free plan, which won’t let me turn on Cloud Storage, so the student-ID verification upload just errors out — there’s literally no bucket for the photo to land in. The code itself is fine, it just needs me to upgrade the plan. For now I’m skipping verification by flagging my test account as verified directly in the database.
So the whole ride flow is working end to end and looks the way I wanted. The one broken piece is broken for a billing reason, not a code reason, which I’ll take. Next up: upgrade the plan to light up Storage + push notifications, then grab real screenshots for the App Store.
Devlog #4 – HydraCoaster
I tested V1 of the enclosure and created a proof of concept software to test the basic hydration session system. The electronics fit perfectly but the strain gauge is offset and has less accurate readings in this coaster. I also printed the TPU cover on the wrong build plate, causing for small imperfections in the print. I plan to reprint the TPU cover and the outer wall of the coaster to be a bit taller so that there’s more wiggle room for the strain gauge.
The software is measuring values that are really wrong, but the start and end values are equally wrong. This means the session drinking amounts are really right and I’m happy with that for now!
Devlog #3 – HydraCoaster
I designed V1 of the HydraCoaster’s enclosure/case and tried my best to house the electronics as well as possible. I definitely will need future iterations to fix the weight mechanism and also include more features like LEDs, vibration motors, buzzers, etc. I’m really happy with what I’ve got so far and can’t wait to see this through!
Devlog #3 – JSBSim WASM
Built out the full Mission Control and Designer workflow. Replaced the old editorial shell with two routes: a dark Mission Control cockpit and a lighter Designer workspace, with fixed per-surface themes instead of the old shared theme setup. On the simulation side, I added typed telemetry channels for IMU, gyro, GPS, barometer, and kinematics, then wired them into metric tiles, sim controls, a live event stream, telemetry charts, a 3D rocket HUD, GPS trajectory, timeline replay, and JSON/CSV export.
Designer also got a major upgrade. I built the schema-driven editor across all seven tabs, added XML import/download/validation, expanded the Aerodynamics tab, and created a nested JSBSim function editor for property/value/table/math nodes. The editor can now send the current model straight into Mission Control, so changes can be tested without leaving the app.
I also cleaned up a few rough edges: filtered noisy JSBSim boot logs out of the event feed, added proper lifecycle events, and fixed long event messages breaking the layout. The feature work is code-complete. Earlier checks passed, but the final full verification got blocked by a local macOS fileproviderd issue that slowed TypeScript, Vitest, Vite, and git to a crawl. Next step is a fresh typecheck/test/browser pass once that clears.
Devlog #2 – HydraCoaster
I switched from the FSR402s to a proper 1kg Load Cell that has much higher accuracy when connected to an Adafruit NAU7802. After some testing, the load cell returned values with accuracy down to the tenth of a gram. With the right code and design, this is the perfect component for a compact smart coaster!
Devlog #6 – Desktop Wind Tunnel
I decided to start on V2, so I designed a better test chamber that’s 150% of the V1 size and has an L-shaped plexiglass cover for a sleeker design. I also smoothed the interior for better airflow, removing any lips or extrusions that were previously interfering.