Inspiration
every week, i’d wake up sweaty.
in my dorm, we pay for our own aircon. i’ve always been lazy about checking the account balance. the only signal i get that it ran out of money is when the aircon stops working.
so yeah... i wake up sweaty.
i hate waking up sweaty.
with some guidance and a bit of copying network requests, i managed to replicate the aircon website’s functionality inside telegram. now i can: • check my balance • predict when i’m running out • top up before my room turns into a sauna
What it does
A Telegram bot that monitors your NUS aircon credits (EVS2 Consumer Portal) so you never wake up sweaty again. Instead of manually checking the portal, you can:
- Check your balance instantly via Telegram
- Track daily usage with breakdowns and averages
- Predict when you'll run out based on your usage pattern
- Get smart alerts when balance drops below $3, below $1, or < 2 days remain
- Receive daily summaries at 10am SGT with your usage recap
- Top up before it's too late — direct link to the portal Supported residences: RVRC, Acacia College, Pioneer House, and any venue using the cp2evs system. ## How we built it
The Flutter web app at cp2nus.evs.com.sg makes API calls to ore.evs.com.sg. We reverse-engineered the network requests and called the same backend endpoints directly. Key technical decisions:
- Node.js + TypeScript + Telegraf — lightweight, type-safe, no framework bloat
- Native fetch — no axios or extra dependencies
- Bearer token auth — same pattern as the Flutter app (login returns JWT, subsequent requests use Authorization: Bearer)
- Permission workaround — the backend has two permission levels: read (looser) and restrictive (stricter). We discovered get_month_to_date_usage uses read permissions, bypassing the 403 errors we hit on the daily history endpoints.
Architecture:
- evsClient.ts — API client handling auth + all endpoint wrappers
- bot.ts — Telegram command handlers, daily reminder scheduler, conversational onboarding
- storage.ts — Encrypted credential storage (in-memory or persistent)
- config.ts — Environment-based configuration
Challenges we ran into
- Permission denied (403) — The backend's meter_p_reading_daily and usage rank endpoints require list operation permissions that our accounts don't have. We found alternative endpoints that use read permissions instead.
- Flutter is a pain -- Had to look at the network tab multiple times to reverse engineer the APIs
- Multiple hostels use different endpoints - had to have custom behavior to ensure that it worked for different hostels
- kWh vs money accounts Some NUS residences use kWh-credit instead of dollar-based billing. Added fallback handling to detect and support both account types.
- Legacy accounts Some older accounts get 403 on certain endpoints. Added fallback to legacy portal data instead of failing completely.
Accomplishments that we're proud of
- Reverse-engineered a production API without documentation
- Conversational onboarding — new users get guided through credential entry step-by-step with security reassurances
- 2-tier reminder system — smart alerts for threshold warnings + daily summaries for routine check-ins
What we learned
Having a product that solves a real problem beats a project that has no real users. I got DMs from people using my bot asking for help for onboarding,
What's next for NUS Aircon Checker
- Spending analytics — Weekly/monthly trends, usage graphs, cost projections
- Smart predictions — Factor in weekends vs weekdays (usage patterns differ significantly)
- Scheduled top-ups — Integrate with the portal to auto-top-up when balance is low (if the API allows it)
Built With
- node.js
- telegraf
- typescript
Log in or sign up for Devpost to join the conversation.