Files
sky-cam/README.md
T

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.mp4year-end-join.sh still 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 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