fajr-watch/README.md

9 KiB
Raw Permalink Blame History

fajr-watch

License: MIT

A turnkey Raspberry Pi appliance that observes dawn and dusk, measures the exact solar depression angle at the moment of true Fajr and Isha, and uploads the data for prayer time calibration research.

Flash an SD card, connect a camera, plug in power. The station runs unattended, captures the twilight horizon every 10 seconds, detects when dawn begins and dusk ends using multi-channel brightness analysis, computes the solar depression angle at that moment, and uploads the result.

Why

Every Islamic prayer time algorithm uses a fixed depression angle (15, 18, or 20 degrees depending on convention). Nobody has measured whether those numbers are actually correct across different latitudes, seasons, and atmospheric conditions. This project collects that data.

The output feeds pray-calc-ml, which trains the Dynamic Prayer Calculation algorithm used by pray-calc.

Hardware

Component Model Cost
Computer Raspberry Pi 4B (2GB+) $45
Camera ZWO ASI224MC (or Pi HQ Camera) $50-180
Lens 1.8mm C-mount fisheye 180 FOV $35
Power 30W solar + 30Ah LiFePO4 + controller $120
Enclosure PVC housing + 9" acrylic dome $60
GPS U-blox NEO-6M (for precise timestamps) $10

Total: ~$320-465 per station. Full bill of materials and assembly guide in docs/hardware.

Hardware Requirements (Phase 1 — BLE Appliance)

Phase 1 is a compact indoor alarm appliance that uses a TSL2591 ambient light sensor to detect true Fajr and Isha via the solar depression angle, then triggers a buzzer. It pairs with a companion iOS/Android app over BLE for configuration.

Component Model Adafruit Price AliExpress Price
MCU Raspberry Pi Zero 2 W $19.05 (Adafruit #5291)
Light sensor TSL2591 HDR Digital Light $6.95 (Adafruit #1980) ~$4.50
RTC DS3231 Precision RTC STEMMA QT $13.95 (Adafruit #5188) ~$2.00
GPS (optional) Ultimate GPS PA1616S $29.95 (Adafruit #746) ~$8.00
Power PowerBoost 1000C + LiPo 2000 mAh $32.45 (two items) ~$8 (TP4056 + 18650)
Buzzer Piezo PS1240 passive $1.50 (Adafruit #160) ~$0.50
Enclosure Hammond 1593KBK 100×60×25 mm ~$6.95 (Digi-Key) ~$3.00

Adafruit prototype total (no GPS): ~$97. AliExpress production total (ESP32 + no GPS): ~$28.

Full bill of materials with supplier alternatives, lead time notes, and ordering sequence: .github/docs/hardware/BOM.md

Quick Start

1. Flash the SD card

Download the latest fajr-watch image from Releases, or build your own:

# On any Linux/macOS machine
git clone https://github.com/acamarata/fajr-watch.git
cd fajr-watch
./scripts/provision/build-image.sh

Flash the resulting .img to a 32GB+ SD card using Raspberry Pi Imager or dd.

2. Configure your station

Before first boot, edit config/station.yaml on the SD card's boot partition:

station:
  id: "conneaut-oh-01"
  lat: 41.95
  lng: -80.55
  elevation_m: 175
  horizon: "lake"        # lake, ocean, flat, hills, mountain
  environment: "suburban" # dark, rural, suburban, urban
  host: "Aric Camarata"
  contact: "email@example.com"

camera:
  type: "zwo_asi224"     # zwo_asi224, zwo_asi462, pi_hq, pi_cam3
  lens_mm: 1.8
  orientation: "east"    # east, west, allsky

network:
  wifi_ssid: "YourNetwork"
  wifi_password: "YourPassword"
  upload_url: "https://api.fajr.watch/upload"

capture:
  interval_s: 10         # seconds between frames during twilight
  twilight_margin_deg: 5 # start capturing at sun depression + this margin
  raw_format: true       # capture RAW (recommended) or JPEG

3. Boot and forget

Insert the SD card, connect the camera, apply power. The station:

  1. Connects to WiFi
  2. Syncs time via GPS (or NTP fallback)
  3. Computes tonight's twilight windows from its coordinates
  4. Sleeps until the twilight window begins
  5. Captures frames every 10 seconds during the window
  6. Runs the detection algorithm on the captured sequence
  7. Uploads the result: (date, lat, lng, elevation, depression_angle, confidence, metadata)
  8. Sleeps until the next twilight window

Status LED blinks green when healthy, amber when capturing, red on error.

How Detection Works

The station does not use a fixed brightness threshold. It detects the physical signature of Fajr Sadiq (true dawn):

  1. Horizon ROI extraction. Isolates the eastern horizon band (azimuth centered on true east, elevation -2 to +15 degrees).

  2. Multi-channel tracking. Measures R, G, B brightness separately in the horizon ROI every 10 seconds.

  3. Color ratio analysis. Computes the color index (R-B)/(R+B) over time. Before dawn, scattered zodiacal light is warm (positive ratio). True dawn produces a neutral white band (ratio approaches zero).

  4. Temporal derivative. The rate of brightness change dB/dt in the east ROI peaks at a specific moment during the twilight transition. The inflection point marks the onset of sustained brightening.

  5. Solar depression lookup. At the detected moment, computes the exact solar depression angle using PyEphem with the station's GPS coordinates and UTC timestamp.

  6. Confidence scoring. Rejects nights with clouds (detected via spatial variance in the ROI), moon interference, or insufficient data.

The same process runs in reverse for Isha (western horizon, brightness decreasing, white glow disappearing).

Output Format

Each twilight event produces one record:

{
  "station_id": "conneaut-oh-01",
  "date": "2026-06-21",
  "prayer": "fajr",
  "utc_time": "2026-06-21T09:12:34Z",
  "solar_depression_deg": 14.23,
  "confidence": 0.92,
  "lat": 41.95,
  "lng": -80.55,
  "elevation_m": 175,
  "environment": "suburban",
  "horizon": "lake",
  "camera": "zwo_asi224",
  "sky_quality_mpsas": 19.4,
  "moon_alt_deg": -12.3,
  "cloud_score": 0.08,
  "color_index_at_detection": 0.02,
  "brightness_curve_hash": "sha256:..."
}

Project Structure

fajr-watch/
├── src/
│   ├── capture/         # Camera control, frame acquisition
│   ├── detect/          # Dawn/dusk detection algorithm
│   ├── upload/          # Data upload to pray-calc-ml
│   └── calibrate/       # Flat-field, dark frame, photometric calibration
├── config/
│   └── station.example.yaml
├── scripts/
│   └── provision/       # OS image build, first-boot setup
├── .github/
│   ├── docs/
│   │   ├── hardware/    # BOM, assembly, wiring diagrams
│   │   └── hosting/     # Volunteer host guide, site selection
│   └── workflows/       # CI
├── .gitignore
├── README.md
└── LICENSE

Contributing Data

Want to host a station? We provide the hardware (camera + Pi + enclosure + solar panel) and you provide a mounting location with a clear eastern or western horizon. Dark sky sites are ideal, but suburban and urban sites are also valuable for measuring the light pollution offset.

See the Host Guide for requirements and how to sign up.

Development Phases

fajr-watch is in active development. The work breaks into three phases.

Phase 1 — Hardware Prototype (current): Bench prototype using a Raspberry Pi Zero 2W, TSL2591 ambient light sensor (I2C, 0.1-88,000 lux range), and DS3231 real-time clock. Power from USB-C mains with an 18650 LiPo backup. The device advertises a BLE GATT service so a companion app can configure location and read sighting history. Target hardware cost under $60. Estimated 2 weeks of build and validation work.

Phase 2 — Firmware: Full Python 3.11+ firmware on RPi OS Lite. The main loop polls the TSL2591 every 60 seconds, computes the solar depression angle via the nrel-spa algorithm, and fires an alarm (GPIO PWM buzzer) when the angle crosses the configured threshold — defaulting to -18 degrees for Fajr. Configuration (location, depression threshold, alarm duration) is written via BLE from the companion app and persisted across reboots. The last 20 sighting events are readable via BLE. Estimated 3 weeks.

Phase 3 — Companion App: React Native (Expo SDK) app for iOS and Android. Four screens: BLE scan and pair, settings (location and threshold configuration), sighting history, and manual test trigger. The app communicates over BLE and requires no background permissions — the device runs standalone once configured. Estimated 4 weeks.

License

MIT