Open source · Ma'ale Adumim, Israel

dudbot λ

A serverless smart water boiler that reads the sun, respects the Shabbat, and runs the electric backup for exactly as long as needed. Zero idle time. Zero waste. $0.00/month.

✓ $0.00 / month ☀️ Solar-aware CSEI ✡ Shabbat & Chag safe
See the code
50L ⚡ ARM64 λ
$0.00
per month, forever
~180
Lambda invocations / month
6
smart contextual rules
How it works

Weather in. Hot water out.

Every afternoon at 16:00 (14:00 on Fridays), a single Lambda invocation fetches the day's weather, calculates how much solar energy the water heater actually got, and schedules exactly the right amount of electric backup — all without a server running 24/7.

☀️
Weather fetch
Open-Meteo gives solar radiation, temps, wind for Ma'ale Adumim
🧮
CSEI score
Five solar factors score the day 0–6.5; deficit drives minutes
📅
Shabbat check
Hebcal API confirms candle/havdalah times and caps accordingly
EventBridge
Two one-time rules scheduled: boiler ON and boiler OFF
📱
Telegram
Full plan sent to your phone before anything physically happens
EventBridge (16:00 daily / 14:00 on Fri) └─ action: "calculate" → Lambda fetches weather, runs CSEI, checks Shabbat ├─ schedules action: "on", minutes: N (fires in ~1 min) ├─ schedules action: "on", minutes: M (Phase 2, evening) — if family mode └─ sends 📊 plan → Telegram EventBridge (one-time, self-deleting) └─ action: "on", minutes: N → boiler ON, schedules "off", sends 🔥 Telegram EventBridge (one-time, self-deleting) └─ action: "off" → boiler OFF, sends 🔴 Telegram No polling. No always-on server. Zero idle Lambda invocations.
The Algorithm

CSEI — Composite Solar Efficiency Index

Five weather factors combine into a single 0–6.5 score. A perfect sunny day in winter scores ~6.5 — the solar collector does almost all the work. A cloudy rainy day scores ~1. The delta from 6.5 is the deficit the electric element needs to cover.

☀️
Sun Efficiency
Average solar radiation 10:00–15:00 vs. the theoretical 850 W/m² peak. The backbone of the score.
📊
Stability Factor
% of solar hours above 600 W/m². Even a high average isn't useful if clouds chop the radiation into useless bursts.
💨
Wind Factor
High wind strips heat from the collector even on a sunny day. A gentle breeze is neutral; a Sharav squall costs minutes.
🌙
Night Factor
Cold overnight minimum = more heat already lost before the sun rises. Minus 5°C nights need more recovery time.
🌡️
Thermal Gain
Temperature rise from 9am to 2pm is a proxy for daytime heat accumulation — a slow cold day stays cold even when sunny.
6.5
max CSEI
CSEI
today's score
=
deficit
solar shortfall
(deficit / 6.5) × 120
raw minutes needed
Smart Decisions

It knows when not to run.

Turning the boiler on isn't always the right call. dudbot has a set of contextual rules that adapt heating to the real situation — not just the forecast.

☀️
Hot day? Skip it.
If the CSEI algorithm calculates fewer than 15 minutes of backup needed, the boiler stays off entirely. Not worth the thermal shock for 8 minutes. You get a Telegram explaining exactly why.
First run only
🛁
Post-kids full reheat
By the time the adults shower (21:00), the kids have drained the tank. Phase 2 uses a full independent reheat budget — not just a proportional slice of what was calculated at 16:00.
Phase 2 logic
🗓️
Season-aware ceiling
The maximum heating time drops as the year warms. Deep winter allows 120 min; spring drops to 70. The algorithm never over-heats on a cold but ultimately manageable April day.
Auto monthly
Boiler finishes on time
Phase 2 is scheduled so the boiler finishes exactly when the adults need it — no waiting around. Phase 1 finishes with a small buffer before the kids' shower to account for pipe heat loss.
Heat-loss aware
🔄
Shabbat recovery
When Shabbat blocks the 16:00 run, an EventBridge rule fires 2 minutes after tzait. Full two-phase logic applies — you get hot water for Motzei Shabbat showers regardless.
Auto post-tzait
🔒
Hard safety guard
Every boiler-on action checks is_forbidden(now) regardless of how it arrived. A stale EventBridge rule can never cause chilul Shabbat — physically impossible.
Last line of defence
dudbot notifications · what a typical day looks like
🤖
📊 Phase 1: ON 16:01 +32 min (off ~16:33) · Phase 2: ON 20:28 +32 min (off ~21:00)

CSEI 3.8 → deficit 2.7 → 38 min raw + 10 correction
Demand: 4 children (17:30) + 2 adults (21:00) → 58% share Phase 1 / ×1.00 post-kids Phase 2
32 min Phase 1 · 32 min Phase 2
📅 ז׳ בסיון תשפ״ו | Not Shabbat/chag
16:00
🤖
☀️ No heating needed today
Only 9 min calculated — not worth running the boiler for less than 15 min.
CSEI 6.1 → deficit 0.4 → 9 min · Great solar day!
16:00 · sunny day example
🤖
Saturday 16:00
Shabbat & Yom Tov

Built for a Jewish home.

Four different day types, four different behaviours. Every edge case handled — including Shabbat ending directly into Yom Tov.

🕯️ Shabbat/Chag timeline
Friday 14:00
Calculate (single phase)
All household members combined. No Phase 2 scheduled. Minutes capped before candle lighting.
Friday ~14:01
🔥 Boiler ON
Heats for the full family — enough for afternoon baths and the evening.
Friday ~15:30
🔴 Boiler OFF
Always finishes before candle lighting. Shabbat is safe.
Friday ~18:00
🕯️ Shabbat begins
No Lambda invocations until havdalah. EventBridge rules are gone.
Saturday 16:00
⏸️ Skipped
is_forbidden() blocks the run. Telegram notified. One-time rule scheduled for tzait + 2 min.
Saturday ~19:32
🌟 Post-tzait run
EventBridge one-time rule fires. Normal two-phase heating runs for Motzei Shabbat showers.
📅 Day type guide
Erev Shabbat / Erev Chag
Runs at 14:00. Single phase — all household members combined, shower times ignored. Capped before candle lighting. The 16:00 trigger silently skips.
Shabbat / Yom Tov
16:00 trigger fires but should_run_now() returns False. Telegram skip notice sent. One-time EventBridge rule created for tzait + 2 min.
Post-tzait (Motzei)
Deferred run fires after havdalah. Full two-phase logic applies. force_single_phase = False — shower times matter again.
Shabbat → Yom Tov
Edge case: when havdalah transitions directly into a new Chag, can_run_post_tzait() checks is_forbidden(now) — returns False immediately. Boiler stays off. Last day of Chag handles post-tzait normally.
🛡️ Hard safety guard
Every action: "on" invocation checks is_forbidden(now) before touching the boiler — regardless of how it arrived. A stale rule can never cause chilul Shabbat.
Family Mode

Two phases. Smart budgeting.

Set HOUSEHOLD to a JSON array of your family groups. Phase 1 heats proportionally for early showers. Phase 2 runs a full independent reheat for adults — because by then, the kids have drained the tank and it needs a proper recovery.

14:0015:0016:00 17:0018:0019:00 20:0021:0022:00
👶 4 children
+31 min
🚿 17:30
👨‍👩 2 adults
+32 min
🚿 21:00
🕯️ Erev Shabbat
single phase only — Phase 2 blocked
🕯️ ~18:10
Phase 1 — children (58% of CSEI budget)
Phase 2 — adults (full independent reheat)
Shower time marker
Phase 1 — proportional

4 children × 0.7 = 2.8 units
2 adults × 1.0 = 2.0 units
Total = 4.8 units

Phase 1 share: 2.8 ÷ 4.8 = 58% of today's budget
Phase 2 — full reheat

Kids have drained the tank by 21:00.
Adults can't rely on a fractional slice.

Phase 2 budget: 2.0 ÷ 2 (baseline) = ×1.00 — same as heating solo
Cost

From $5/month to $0.00/month.

The original dudbot ran on an EC2 instance that sat idle 23 hours a day. Lambda charges per 100ms of actual work. The math is brutal in the best possible way.

Before — EC2 / Lightsail
$5
per month, whether you use it or not
  • Lightsail nano$5.00
  • Always-on process24/7 idle
  • Manual deploysSSH + Docker
After — Lambda + EventBridge
$0.00
per month, permanently in free tier
  • Lambda~180 req / month vs 1M free
  • EventBridge~180 rules vs 14M free
  • ECR~250MB vs 500MB free
  • S3 state<1MB vs 5GB free
  • CloudWatch<10MB vs 5GB free
Annual savings over Lightsail
$60.00 / year
Every service stays comfortably within AWS permanent free tiers. This isn't a 12-month free tier — it's free forever at this usage level.
AWS Free Tier

Every service. Permanently free.

Service Monthly usage Free tier limit Cost
AWS Lambda ~180 invocations · ~900 GB-sec 1M requests · 400K GB-sec $0.00 ✓
EventBridge Scheduler ~180 one-time rules 14M invocations / month $0.00 ✓
Amazon ECR ~250 MB container image 500 MB / month $0.00 ✓
Amazon S3 < 1 MB state files 5 GB storage $0.00 ✓
CloudWatch Logs < 10 MB / month 5 GB ingestion $0.00 ✓
Built with

Zero-dependency stack.

No Kubernetes. No ECS. No RDS. Just Lambda, EventBridge, and a few API calls to services that were free to begin with.

λ
AWS Lambda
arm64 container, 512MB, 2 min timeout
EventBridge Scheduler
One-time self-deleting rules for on/off events
🗃️
Amazon S3
State bucket: last decision, OAuth token, flags
📦
Amazon ECR
Container registry with lifecycle auto-cleanup
☀️
Open-Meteo
Free weather & solar radiation API (no key needed)
✡️
Hebcal API
Free Jewish calendar: candle lighting & havdalah times
📱
Telegram Bot
Outbound-only notifications to your phone
🐍
Python 3.12
Minimal deps: requests, boto3, zoneinfo
🏗️
Terraform
All infra as code — one apply to provision everything