Files
sky-cam/sky-cam.conf
T
Claude 7486916f9f Sunrise time overlay; systemd upload separation; bug fixes
daily_sunrise_video.sh:
- Fixed: was using undefined \$MOVIES_DIR (now \$BASE_DIR/movies)
- Fixed: sunrise_overlay.py was called but never existed — would fail daily
- Fixed: speed-adjust step had no explicit codec (-c:v libx264 missing)
- New: sunrise time overlaid as stacked vertical characters on the right
  side using ffmpeg drawtext — no Python/Pillow dependency
- New: upload removed from script; now triggered by systemd OnSuccess=
- Combines speed-adjust and overlay into one ffmpeg pass (was two)
- SUNRISE_OVERLAY_OPACITY from conf controls transparency

install.sh:
- sky-cam-sunrise.service gains OnSuccess=sky-cam-sunrise-upload.service
  so upload only runs when video creation succeeds, with separate log
- New sky-cam-sunrise-upload.service runs sunrise2mm.py

sunrise2mm.py: add shebang + chmod +x so systemd ExecStart= calls it directly

sky-cam.conf: add SUNRISE_OVERLAY_OPACITY=0.45

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-19 16:35:33 +00:00

266 lines
14 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================================
# sky-cam.conf — master configuration for all sky-cam scripts
# =============================================================================
#
# This is the ONLY file you need to edit. After editing, run:
#
# ./install.sh # installs systemd timers (no root needed)
# ./install.sh --system # system-wide install (requires sudo)
#
# Re-run install.sh any time this file changes.
#
# -----------------------------------------------------------------------------
# MANUAL SYSTEMD SETUP (if you prefer not to use install.sh)
# -----------------------------------------------------------------------------
# After editing this file, generate the unit files:
#
# mkdir -p ~/.config/systemd/user
# cp systemd/*.service systemd/*.timer ~/.config/systemd/user/
#
# Then edit ExecStart= in each .service file to match your SCRIPT_DIR, then:
#
# systemctl --user daemon-reload
# systemctl --user enable --now sky-cam-sunrise.timer
# systemctl --user enable --now sky-cam-seasons-sunrise.timer
# systemctl --user enable --now sky-cam-fullday-sunrise.timer
# # one sky-cam-seasons-<cam>.timer and sky-cam-fullday-<cam>.timer per camera
#
# Check status:
# systemctl --user list-timers 'sky-cam-*'
# journalctl --user -u sky-cam-seasons-sunrise.service -f
#
# System-wide (replace --user with no flag, prepend sudo):
# sudo cp systemd/*.service systemd/*.timer /etc/systemd/system/
# sudo systemctl daemon-reload && sudo systemctl enable --now sky-cam-*.timer
#
# -----------------------------------------------------------------------------
# SCRIPT MAP — what each file does and when it runs
# -----------------------------------------------------------------------------
#
# You run / schedule:
# daily_sunrise_video.sh — daily at SCHEDULE_SUNRISE (via systemd, SUNRISE_CAM only)
# grabs images around sunrise, makes a short video,
# uploads it to Mattermost
#
# 4-seasons.sh <cam> — daily at SCHEDULE_SEASONS_<cam> (via systemd, per camera)
# makes yesterday's daily clip sized to its share
# of the matching Vivaldi movement's music duration;
# on the last day of a movement, auto-triggers
# montage-mvt.sh
#
# fullday-video.sh <cam> — daily at SCHEDULE_FULLDAY_<cam> (via systemd, per camera)
# full-day timelapse at fixed fps; deletes videos
# older than RETENTION_DAYS automatically
#
# install.sh — run once at setup, and again if this file changes
# generates and installs systemd units from conf
#
# stitch-cameras.py — run manually when needed
# stitches north + sunrise into a panorama
# usage: python3 stitch-cameras.py north.jpg sunrise.jpg prefix [focal]
#
# Auto-triggered (do not run directly):
# montage-mvt.sh — called by 4-seasons.sh on last day of each movement
# concatenates all daily clips for the movement,
# speed-adjusts to match music, overlays attribution,
# sends completion notification; on last Autumn
# movement also triggers year-end-join.sh
#
# year-end-join.sh — called by montage-mvt.sh at end of Autumn Mvt 3
# concatenates all 12 movement montages into one
# Four Seasons year video, sends notification
#
# Helpers (called by the scripts above, not run directly):
# notify.sh — sends notifications via ntfy / email / Mattermost
# season_info.py — outputs astronomical season/movement/year for a date
# sunrise.py — outputs today's sunrise time (used by daily_sunrise_video)
# sunrise2mm.py — uploads the sunrise video to Mattermost
# sunrise_overlay.py — burns a timestamp overlay onto the sunrise video
#
# -----------------------------------------------------------------------------
# FILE DEPENDENCIES — who calls whom, and what to update if you rename a file
# -----------------------------------------------------------------------------
#
# sky-cam.conf (this file)
# ← sourced by every .sh script; read by sunrise.py, sunrise2mm.py
# → if renamed: update the 'source' line at the top of ALL scripts
# (don't rename it — just edit it in place)
#
# install.sh
# ← run manually; reads this conf
# → if renamed: update the note at the top of this conf file only
# generates → systemd unit files (sky-cam-*.service / .timer)
# and sky-cam-notify-failure@.service
#
# daily_sunrise_video.sh
# ← called by systemd sky-cam-sunrise.timer (SCHEDULE_SUNRISE)
# → if renamed: update install.sh (write_service call ~line 70)
# then re-run install.sh to regenerate the unit
# calls → sunrise.py, sunrise_overlay.py, sunrise2mm.py
#
# 4-seasons.sh
# ← called by systemd sky-cam-seasons-<cam>.timer (SCHEDULE_SEASONS_<cam>)
# → if renamed: update install.sh (write_service call ~line 85)
# then re-run install.sh
# calls → season_info.py, montage-mvt.sh
#
# fullday-video.sh
# ← called by systemd sky-cam-fullday-<cam>.timer (SCHEDULE_FULLDAY_<cam>)
# → if renamed: update install.sh (write_service call ~line 93)
# then re-run install.sh
#
# montage-mvt.sh
# ← called by 4-seasons.sh on the last day of each movement
# → if renamed: update 4-seasons.sh (the exec line near the bottom)
# calls → season_info.py, notify.sh, year-end-join.sh
#
# year-end-join.sh
# ← called by montage-mvt.sh at end of Autumn Mvt 3
# → if renamed: update montage-mvt.sh (the exec line at the bottom)
# calls → notify.sh
#
# notify.sh
# ← called by montage-mvt.sh, year-end-join.sh
# also referenced in install.sh for the OnFailure= failure template
# → if renamed: update montage-mvt.sh, year-end-join.sh, install.sh
#
# season_info.py
# ← called by 4-seasons.sh and montage-mvt.sh
# → if renamed: update 4-seasons.sh and montage-mvt.sh (the eval lines)
#
# sunrise.py
# ← called by daily_sunrise_video.sh
# → if renamed: update daily_sunrise_video.sh
#
# sunrise_overlay.py
# ← called by daily_sunrise_video.sh
# → if renamed: update daily_sunrise_video.sh
#
# sunrise2mm.py
# ← called by daily_sunrise_video.sh
# → if renamed: update daily_sunrise_video.sh
#
# stitch-cameras.py
# ← run manually only; no script calls it
# → safe to rename with no other changes needed
#
# =============================================================================
# ── Install location ──────────────────────────────────────────────────────────
# Full path to the directory containing this file and all the scripts.
SCRIPT_DIR=/home/motion/drives/local-2tb/sunrise-scripts
# ── Storage ───────────────────────────────────────────────────────────────────
BASE_DIR=/home/motion/drives/local-2tb
MOVIES_DIR=$BASE_DIR/movies # override if videos live on a different drive
MUSIC_DIR=/home/motion/drives/local-2tb/music/4 Seasons
# ── Location & timezone ───────────────────────────────────────────────────────
# Used by sunrise.py to calculate sunrise time each day.
#
# To find your coordinates:
# Google Maps — right-click your location → the first item shown is "lat, lon"
# Or: maps.google.com, drop a pin, coordinates appear in the URL and sidebar
#
# TIMEZONE must be a valid IANA name. Look yours up at:
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
# (use the value in the "TZ identifier" column, e.g. America/Chicago)
#
LATITUDE=25.0000
LONGITUDE=-38.0000
TIMEZONE=America/New_York
# ── Cameras ───────────────────────────────────────────────────────────────────
# List every camera name here (space-separated inside the parentheses).
# Each name becomes a subfolder under BASE_DIR (images) and BASE_DIR/movies.
# To add a camera: add its name here, add its schedules below, re-run install.sh.
#
CAMERAS=(sunrise) # e.g. CAMERAS=(sunrise north west)
SUNRISE_CAM=sunrise # which camera faces east (gets the sunrise video job)
# ── Schedules ─────────────────────────────────────────────────────────────────
# SCHEDULE_SUNRISE when to run daily_sunrise_video.sh (SUNRISE_CAM only)
# SCHEDULE_SEASONS_<cam> when to run 4-seasons.sh for each camera
# SCHEDULE_FULLDAY_<cam> when to run fullday-video.sh for each camera
#
# Times are HH:MM:SS (24-hour). Space cameras at least 30 min apart.
# install.sh reads these and generates one systemd timer per camera per job.
#
SCHEDULE_SUNRISE=09:00:00
SCHEDULE_SEASONS_sunrise=01:00:00
SCHEDULE_FULLDAY_sunrise=02:00:00
# Uncomment and fill in for each camera you add to CAMERAS above:
#SCHEDULE_SEASONS_north=01:30:00
#SCHEDULE_FULLDAY_north=02:30:00
#
#SCHEDULE_SEASONS_west=02:00:00
#SCHEDULE_FULLDAY_west=03:00:00
# ── Sunrise video tuning ──────────────────────────────────────────────────────
# How many minutes before/after sunrise to include in the daily clip.
SUNRISE_PRE_MIN=70
SUNRISE_POST_MIN=10
# Target duration (seconds) for the speed-adjusted sunrise video.
SUNRISE_TARGET_SECS=10
# Opacity of the sunrise-time overlay (0.0 = invisible, 1.0 = fully opaque).
SUNRISE_OVERLAY_OPACITY=0.45
# ── Full-day timelapse tuning ─────────────────────────────────────────────────
FULLDAY_FPS=5 # frame rate of the timelapse video
RETENTION_DAYS=10 # delete full-day videos older than this many days
# ── Video encoding quality ────────────────────────────────────────────────────
# FFmpeg CRF: lower = higher quality / larger files. Typical range 1830.
# 18 ≈ visually lossless 23 = ffmpeg default 28 = smaller/lower
# Different scripts use different defaults by design — intermediate/draft
# encodings use a higher CRF (smaller files, quality less critical), while
# final "polished" outputs use a lower CRF for better quality.
# Each is independent — changing one does NOT change the others.
#
CRF_SUNRISE=28 # daily_sunrise_video.sh — daily Mattermost upload
CRF_FULLDAY=28 # fullday-video.sh — full-day timelapse
CRF_SEASONS_RAW=28 # 4-seasons.sh — raw concat before speed-adjust
CRF_SEASONS_FINAL=26 # 4-seasons.sh — final daily clip (goes into montage)
CRF_MONTAGE=26 # montage-mvt.sh — concat and speed-adjust and final
AUDIO_BITRATE=192k # montage-mvt.sh — music track on movement montages
# ── Montage attribution overlay ───────────────────────────────────────────────
# A translucent bar across the top of each movement montage, naming the
# music source ("The Four Seasons — Antonio Vivaldi ...").
# Appears for MONTAGE_ATTR_DUR seconds from the start, with ATTR_FADE-second
# fade in and fade out. FADE_DUR controls the video/audio fade in/out at
# the very start and very end of the montage.
#
MONTAGE_FADE_DUR=2.0 # video + audio fade in/out (seconds)
MONTAGE_ATTR_DUR=6 # attribution overlay total duration (seconds)
MONTAGE_ATTR_FADE=1 # attribution fade-in and fade-out length (seconds)
# ── Mattermost — daily sunrise upload ─────────────────────────────────────────
mattermost_url=https://your-mattermost-server.example.com
access_token=your-access-token-here
channel_id=your-daily-upload-channel-id-here
# ── Notifications — montage / year-end complete + any job failure ─────────────
# Notifications fire when a movement montage or the year video finishes,
# and via systemd OnFailure= if any daily job fails.
# Uncomment and configure one or more methods to enable.
# ntfy — push notifications, zero signup for self-hosted or free cloud tier:
# Self-hosted: https://docs.ntfy.sh/install/
# Cloud: pick any topic name at ntfy.sh (no account needed)
#NTFY_ENABLED=true
#NTFY_URL=https://ntfy.sh/your-topic-here
# Email — requires the 'mail' command (package: mailutils or s-nail).
# Configure outbound SMTP via /etc/ssmtp/ssmtp.conf or msmtp.
#EMAIL_ENABLED=true
#EMAIL_TO=you@example.com
#EMAIL_FROM=skycam@localhost
# Mattermost text post — reuses mattermost_url and access_token above.
# Can be the same daily channel or a separate admin/private channel.
#MM_NOTIFY_ENABLED=true
#MM_NOTIFY_CHANNEL_ID=your-notify-channel-id-here