5.6 KiB
5.6 KiB
sky-cam
Automated sky / timelapse camera scripts that produce:
- Daily sunrise clip — a 10-second speed-adjusted video of the sunrise window, uploaded to Mattermost each morning
- Four Seasons timelapse — daily clips sized to each Vivaldi movement's music duration, assembled automatically into per-movement montages (with music + attribution overlay) and a full-year video
- Full-day timelapse — a fixed-fps timelapse of every image captured that day, kept for a configurable retention window
Prerequisites
| Dependency | Notes |
|---|---|
ffmpeg + ffprobe |
Encoding and duration probing |
python3 |
ephem package for sunrise calculation, requests for Mattermost upload |
bc |
Shell arithmetic (floating-point speed factors) |
fontconfig (fc-match) |
Font detection for overlays — optional, falls back to hardcoded paths |
| Camera software | e.g. motion — writes JPEG images named HH-MM-SS.jpg into BASE_DIR/<cam>/<YYYY-MM-DD>/ |
| Vivaldi Four Seasons audio | 12 MP3 files named so that *Spring*Mvt*1*, *Summer*Mvt*2*, etc. match with find -iname |
Install Python dependencies:
pip3 install ephem requests
Quick start
1. Download
bash <(curl -fsSL https://raw.githubusercontent.com/outis1one/sky-cam/main/bootstrap.sh)
cd sky-cam
Or with a custom install directory:
curl -fsSL https://raw.githubusercontent.com/outis1one/sky-cam/main/bootstrap.sh | bash -s -- /opt/sky-cam
cd /opt/sky-cam
2. Configure
$EDITOR sky-cam.conf
Minimum settings to fill in (everything else has sensible defaults):
| Setting | What it is |
|---|---|
SCRIPT_DIR |
Full path to this directory |
BASE_DIR |
Root where camera images live (BASE_DIR/<cam>/<date>/<HH-MM-SS>.jpg) |
MOVIES_DIR |
Where finished videos are written (default: BASE_DIR/movies) |
MUSIC_DIR |
Directory containing the 12 Vivaldi Four Seasons audio files |
CAMERAS |
Space-separated list of camera names, e.g. (sunrise north) |
SUNRISE_CAM |
Which camera faces east and gets the sunrise job |
LATITUDE / LONGITUDE / TIMEZONE |
Your location for sunrise calculation |
mattermost_url / access_token / channel_id |
Mattermost upload credentials |
3. Install systemd timers
./install.sh # user-level timers (~/.config/systemd/user), no root needed
# or
./install.sh --system # system-wide (/etc/systemd/system), requires sudo
Re-run install.sh any time sky-cam.conf changes.
4. Verify
systemctl --user list-timers 'sky-cam-*'
journalctl --user -u sky-cam-sunrise.service -f
How it works
Camera writes JPEGs
│
├─ daily_sunrise_video.sh (runs at SCHEDULE_SUNRISE)
│ Step 1: encode raw video from sunrise-window JPEGs
│ Step 2: speed-adjust to SUNRISE_TARGET_SECS → saved permanently
│ Step 3: burn sunrise time overlay → final video
│ OnSuccess → sunrise2mm.py uploads to Mattermost
│
├─ 4-seasons.sh <cam> (runs at SCHEDULE_SEASONS_<cam>, processes yesterday)
│ Step 1: encode all of yesterday's JPEGs into raw video
│ Step 2: speed-adjust to music_duration / days_in_movement
│ Last day of movement → triggers montage-mvt.sh
│ Step 1: concatenate all daily clips
│ Step 2: speed-adjust to exactly match music → saved permanently
│ Step 3: mix music + fades + attribution overlay → Montage.mp4
│ Last movement of Autumn → triggers year-end-join.sh
│
└─ fullday-video.sh <cam> (runs at SCHEDULE_FULLDAY_<cam>, processes yesterday)
Encode all of yesterday's JPEGs at FULLDAY_FPS
Delete videos older than RETENTION_DAYS
Resilience
Each pipeline saves an intermediate file before the step most likely to fail, so a partial failure leaves a recoverable artifact:
- Sunrise: if the overlay (step 3) fails, the speed-only video is promoted to the upload target — the upload still happens and you get a notification of the overlay failure
- Montage: if music + overlay (step 3) fails, the speed-adjusted silent video is promoted to
*-Montage.mp4—year-end-join.shstill includes the movement and you get a warning notification
Notifications
notify.sh sends alerts through any combination of:
| Channel | Config key(s) |
|---|---|
| ntfy | NTFY_ENABLED=true, NTFY_URL=https://ntfy.sh/your-topic |
EMAIL_ENABLED=true, EMAIL_TO=you@example.com |
|
| Mattermost text post | MM_NOTIFY_ENABLED=true, MM_NOTIFY_CHANNEL_ID=<channel-id> |
You receive notifications for:
- Sunrise: video ready, upload success/failure, overlay failure
- Each daily seasons clip saved
- Montage complete (or degraded if audio/overlay failed)
- Year-end Four Seasons video complete
- Any step failure, with the surviving file path named
Manual operations
Re-run today's sunrise (e.g. after fixing a font issue):
./daily_sunrise_video.sh
Re-run a daily seasons clip for a specific date:
./4-seasons.sh <cam> # reprocesses yesterday
Rebuild a movement montage (e.g. to retry audio after a failure):
./montage-mvt.sh # uses today's movement
./montage-mvt.sh 2025-06-15 sunrise # use a specific reference date + camera
Rebuild the year-end video:
./year-end-join.sh 2025 sunrise
Check logs:
journalctl --user -u sky-cam-sunrise.service
journalctl --user -u sky-cam-seasons-sunrise.service
journalctl --user -u sky-cam-fullday-sunrise.service