An offline-first Android app that tracks sunrise, sunset, moon phase, and solar eclipse contact times for your GPS location — built around preparing for the August 12, 2026 total solar eclipse. All astronomical calculations run on-device via an embedded Python/Skyfield engine, with spoken (TTS) countdowns to totality precise to the second.
| Main screen | Drawer |
|---|---|
![]() |
![]() |
Solar & lunar tracking
- Sunrise/sunset, moon phase, and altitude data for the device's current GPS fix
- Per-body altitude precision selector; live countdown to the next event
- Fully offline — calculations run against a bundled JPL DE421 ephemeris, no network required
Eclipse tools
- C1–C4 contact time predictions for any solar eclipse worldwide (Skyfield topocentric search: golden-section maximum + bisection for contact boundaries)
- Dedicated high-precision path for the 2026-08-12 total eclipse using NASA/GSFC's published Besselian elements, cross-checked against reference sources
- "Not in path of totality" alerting when the current location misses the umbra
- Eclipse-day checklist (YAML-backed task list) for on-site prep
Spoken announcements
- Text-to-speech countdowns to sunrise/sunset and to eclipse C1/C2/max/C3, with second-by-second cadence approaching each contact
- Runs from a foreground service that survives screen-off, Doze, and reboot
- Optional Spotify playback sync: music pauses automatically ahead of the C2 audio cue
Hardware integration
- Bluetooth LE heart-rate monitor pairing, live BPM chart during the event
- Device compass pointing toward the sun/moon azimuth
- NTP time sync check, so countdowns stay accurate even with device clock drift
Testing & simulation
- Built-in time-travel simulation dialog to preview any date/time without waiting for the real event
- Kotlin + Jetpack Compose (Material 3) — UI layer
- Chaquopy — embeds a Python 3.13 runtime directly in the APK
- Skyfield 1.54 — astronomical calculations (JPL DE421 ephemeris)
- Android FusedLocationProvider, AlarmManager, TextToSpeech, Bluetooth LE, MediaSession/NotificationListenerService, sensor APIs (compass)
app/src/main/
├── python/solar_calc.py ← Skyfield eclipse/solar-position engine (Chaquopy)
├── java/com/oliware/sunandmoon/
│ ├── MainActivity.kt ← permissions, sensors, Compose host, orchestration
│ ├── SolarService.java ← foreground service: location + scheduling
│ ├── PythonBridge.java ← Chaquopy ↔ Kotlin/Java bridge, ephemeris loading
│ ├── AlarmScheduler.java / AlarmReceiver.java ← AlarmManager-driven TTS triggers
│ ├── EclipseTotalityAnnouncer.java ← C2/max/C3 countdown phrase logic
│ ├── C2AudioSynchronizer.java / SpotifyMediaController.java ← media-session sync
│ ├── HeartRateBleReceiver.java ← BLE heart-rate monitor pairing
│ ├── NtpClient.java ← network time sync check
│ └── ui/
│ ├── main/ ← AppRoot, MainScreen, RightPanel (Compose)
│ ├── components/ ← SunPanel, MoonPanel, EclipsePanel, CompassView, HeartRateChart…
│ ├── dialogs/ ← PermissionsDialog, SimulationDialog, AudioAnchorDialog, BpmPickerDialog
│ ├── drawer/ ← navigation drawer + header buttons
│ └── theme/ ← Oliware design system (Compose theme)
- Android Studio (current stable)
- AGP 9.2.1 / Gradle (see
build.gradle) - A Python 3.13 interpreter on your build machine for Chaquopy — set the path via
buildPythoninapp/build.gradle(chaquopy.defaultConfig.buildPython); it currently points at a local venv path that you'll need to change to your own minSdk31 (Android 12),targetSdk34
The JPL DE421 ephemeris (~17 MB) is excluded from version control. Download
it and place it at app/src/main/assets/de421.bsp:
https://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/de421.bsp
Then build normally — Chaquopy will install skyfield==1.54 into the
embedded Python environment automatically.
| Permission | Why |
|---|---|
ACCESS_FINE_LOCATION / ACCESS_COARSE_LOCATION |
GPS coordinates for solar/eclipse calculation |
BLUETOOTH_SCAN / BLUETOOTH_CONNECT |
Pairing with a BLE heart-rate monitor |
FOREGROUND_SERVICE (+ LOCATION, MEDIA_PLAYBACK) |
Keep tracking/announcements alive in the background |
SCHEDULE_EXACT_ALARM / USE_EXACT_ALARM |
Fire TTS alerts at precise times |
WAKE_LOCK |
Keep the CPU awake during TTS/audio playback |
RECEIVE_BOOT_COMPLETED |
Restart the service after reboot |
POST_NOTIFICATIONS |
Persistent foreground-service notification |
MANAGE_EXTERNAL_STORAGE |
Read the eclipse-day task checklist (YAML) from shared storage |
versionCode is derived automatically from the git commit count
(git rev-list --count HEAD), so it always increments monotonically.
versionName is a manually bumped semver tag (vX.Y.Z) per release.

