Inspiration
Households in southern Ontario throw out an average of 2.4 kg of food every week, and food makes up about 35% of everything in a typical household's garbage. Roughly 60% of that is avoidable. All of it goes straight to landfill with no benefit to anyone. So what if there were an easy way to reuse that waste in a way that is motivating, engaging, and actually benefits you? You could compost it, which is great except that almost nobody knows how. How can you tell what is wet, dry, or working? The answers lie inside the bin. Similar solutions exist, but the feedback loop is boring and the cycle is repetitive, so nothing keeps people engaged.
So why not use proven methods to keep people engaged, with gamified concepts and app structures that already work like Strava and Duolingo? That idea became Calmpost.
What it does
Calmpost uses two moisture sensors at the top and bottom of the bin, a temperature sensor in the soil, and a CO₂ sensor to read your compost's activity. These sensors produce a reading once every second, which is sent to the database and displayed on the user's account.
To give those readings context, a camera inside the bin scans items as they go in. The items are sent to Gemini to interpret, and the results go back to the backend, so composting gets tracked automatically. Want to know more about your bin's activity? Ask Trunc, the in-app assistant built on Gemini, which reads your bin's current state and tells you what to add next.
To keep people engaged, Calmpost gives your bin a health score from 0 to 100 and explains the reasons behind that score. Alongside that are social and game features such as leaderboards, XP that rewards care rather than volume, profiles, following, groups, collectables, and other elements that make a game worth coming back to.
How we built
Calmpost runs an Arduino UNO R4 connected to two moisture sensors, a temperature sensor and a CO₂ sensor, which send their data over a USB serial bridge to a FastAPI backend and into Tiger Data. Gemini handles vision and text generation, and the results are served to the Flutter app.
A major decision was how Gemini provides reasoning. Every verdict comes from a deterministic rules engine, and Gemini's job is to read that engine's output and phrase it for the current context. The rules always win over Gemini for two reasons. Firstly, in case Gemini is down Calmpost falls back to the rules, so the user still learns what to add next given the bin's current contents. Secondly, forcing the rules to always win ensures the app suggestions stay where we want them to without possible mistakes.
Tiger Data does more than store readings too. Sensor data lives in a hypertable, and the charts are built from continuous aggregates that roll readings into 15-minute and daily buckets, so a full day of history is one fast query instead of thousands of rows. Leaderboards work the same way. XP is an append-only ledger, and a weekly board is a time-bucketed query over it, which means the weekly reset needs no reset job at all and only uses a different time window. Raw readings are kept for 90 days and camera photos for 30 days.
The multiplayer side is built on the same idea. Accounts, follows, private groups, invites and cheers live in eight tables in the backend, and the client only ever holds a session token, so everything shared is stored server side and nothing can be faked from a phone. No score is ever stored. A leaderboard is a live query over the same append-only XP ledger that drives the single player game, filtered to the people in that group and the time window being shown. Because of that, a user's weekly rank, their all time rank and their position in three different groups are all the same data read five different ways, and the weekly board resets on its own when the window moves. Accounts are private by default, follows need approving, and invite codes expire after seven days, so joining a friend's leaderboard never exposes anything the owner did not agree to share.
Challenges we ran into
We ran into problems on both the software and hardware sides.
First, a temperature and a moisture sensor were not reporting. We initially thought they were not calibrated correctly, which turned out to be true for the moisture sensor. Our first hardware demo only had one moisture probe, so the second one never got its in-water calibration and was running on defaults. We found the two probes reading 474 and 495 while sitting side by side in the same air, a gap of 21 counts, so each probe needed its own calibration curve instead of a copy of the other's.
For the temperature sensor we suspected software, but the firmware was reading the second probe correctly and reporting null because nothing answered on that pin. Investigating the sensor itself turned up connection problems, and while trying to fix them the sensor short circuited, overheated and broke. We dropped the second temperature sensor and restructured the UI to adjust for these problems.
The second major problem was getting the Android emulator running to test how the systems fit together. We first thought our connection issue was WiFi, since we were getting 401 errors, but switching to a hotspot did not help. We found that the API key was missing from the build, and the app was reporting an authentication failure using network wording, which sent us chasing the wrong problem.
The emulator itself fought us in three more ways. 'flutter doctor --android-licenses' has been retired by Google and now silently does nothing, so the license warning never cleared no matter how many times we ran it. The Android SDK was missing 'platforms;android-35', which one of our Flutter plugins required. And one build failed with an error message whose entire content was 25.0.3, which turned out to be the JDK version that Android Studio bundles and that the Android Gradle Plugin refuses to use.
Accomplishments that we're proud of
We built a full mobile app that degrades instead of breaking. When Gemini is unavailable or the user hits their quota, the rules engine answers instead and the app keeps working. We proved this by accident during the build when we exhausted our Gemini quota and the app carried on giving correct advice.
The app constantly polls the sensors, sending readings to a cloud database every second and refreshing in the app every three seconds. It feels instantaneous, to the point where you can put your hand over a sensor and see the effect almost immediately. The backend keeps 90 days of sensor history, so every bin has a charted past rather than only a live number.
Every answer the app gives is explainable. Each verdict is stored alongside the sensor snapshot it was based on, so when the same scrap gets a different answer on a different day, we can show exactly why.
What we learned
For some of us this was the first time using a database, working with hardware, or building a mobile app. We can take all of that into future hackathons and personal projects.
We also learned that wrong data is worse than no data. When the bottom layer had no history of its own, showing the top probe's history under a "bottom layer" label would have been misleading, so we left the chart empty and explained why. We applied the same rule when the temperature sensor broke, changing the UI to say "not measured" instead of filling the gap with something plausible.
Second, avoid building a GPT wrapper. Trunc started as a chatbot you could ask anything, prompted through JSON to only answer compost questions. That made the app feel less polished and pulled away from Trunc's real job, which was a quick tap that tells you what to do next. So we narrowed Trunc to answer from the bin's contents and sensor data, which kept the polish and made the answers specific to your bin.
Third, integration cost us far more time than logic did. Almost none of our lost hours went on algorithms. They went on JDK versions, missing SDK components, PATH problems, ports still held by processes we had forgotten about, and API keys. Next time we would get one thread running end to end on the first day before building anything on top of it.
What's next for Calmpost
Getting the second temperature sensor working as intended is the natural next step, giving us a real heat map across both layers. Adding a light inside the bin would also make the camera far more reliable. One approach is detecting when the lid closes, then switching on a light so the camera can capture what was added.
Outside the technical side, getting more people testing the app would polish it well beyond our own hours of use. It would also let us show readings spread over weeks instead of a single evening, which is when compost data gets interesting, because you can watch a batch heat up, peak, and cool over its full cycle.


Log in or sign up for Devpost to join the conversation.