diff --git a/sky-cam.conf b/sky-cam.conf index 12a433a..85df032 100644 --- a/sky-cam.conf +++ b/sky-cam.conf @@ -1,43 +1,124 @@ -# sky-cam.conf — single config for all sky-cam scripts and Python helpers. +# ============================================================================= +# sky-cam.conf — master configuration for all sky-cam scripts +# ============================================================================= # -# Bash scripts source this file: -# source "$(dirname "$(realpath "$0")")/sky-cam.conf" +# This is the ONLY file you need to edit. After editing, run: # -# Python reads it with key=value parsing (same format, quotes stripped). +# ./install.sh # installs systemd timers (no root needed) +# ./install.sh --system # system-wide install (requires sudo) # -# Fill in every value below, then run ./install.sh to deploy systemd timers. -# You should not need to edit any other file. +# 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 # 09:00 daily +# systemctl --user enable --now sky-cam-4seasons.timer # 01:00 daily +# systemctl --user enable --now sky-cam-fullday.timer # 02:00 daily +# +# Check status: +# systemctl --user list-timers 'sky-cam-*' +# journalctl --user -u sky-cam-4seasons.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: +# sunrise_video.10s.sh — daily at 09:00 (via systemd) +# grabs today's sunrise images, makes a 10-second +# video, uploads it to Mattermost +# +# 4-seasons.sh — daily at 01:00 (via systemd) +# 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 — daily at 02:00 (via systemd) +# full-day timelapse at fixed fps; deletes files +# older than 10 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 sunrise_video) +# sunrise2mm.py — uploads the sunrise video to Mattermost +# +# ============================================================================= # ── Install location ────────────────────────────────────────────────────────── -# Full path to the directory containing this conf file and all the scripts. +# Full path to the directory containing this file and all the scripts. SCRIPT_DIR=/home/motion/drives/local-2tb/sunrise-scripts -# Camera name — used as the subfolder name under BASE_DIR and BASE_DIR/movies. -# E.g. "sunrise" → images at $BASE_DIR/sunrise/YYYY-MM-DD/, videos at $BASE_DIR/movies/sunrise/ +# Camera name — subfolder under BASE_DIR (images) and BASE_DIR/movies (videos). +# E.g. "sunrise" → images: $BASE_DIR/sunrise/YYYY-MM-DD/ videos: $BASE_DIR/movies/sunrise/ CAM_NAME=sunrise # ── Storage ─────────────────────────────────────────────────────────────────── BASE_DIR=/home/motion/drives/local-2tb MUSIC_DIR=/home/motion/drives/local-2tb/music/4 Seasons -# ── Timezone (IANA name) ────────────────────────────────────────────────────── +# ── Location & timezone ─────────────────────────────────────────────────────── +# Used by sunrise.py to calculate sunrise time each day. +# TIMEZONE must be a valid IANA name: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones +LATITUDE=38.123456 +LONGITUDE=-97.654321 TIMEZONE=America/New_York -# ── Mattermost — daily sunrise upload ──────────────────────────────────────── +# ── 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 + job failure ─────────────────── -# ntfy: https://ntfy.sh (cloud) or self-hosted. +# ── Notifications — montage / year-end complete + any job failure ───────────── +# Notifications fire when a movement montage or the year video finishes. +# They also fire automatically via systemd OnFailure= if any daily job fails. +# Enable one or more methods below. + +# ntfy — push notifications, zero signup required for self-hosted: +# https://docs.ntfy.sh/install/ +# or use the free cloud tier at ntfy.sh (pick any topic name) NTFY_ENABLED=false NTFY_URL=https://ntfy.sh/your-topic-here -# Email: requires the 'mail' command (mailutils / s-nail). +# Email — requires the 'mail' command on the system (package: mailutils or s-nail). +# For outbound SMTP configure /etc/ssmtp/ssmtp.conf or msmtp. EMAIL_ENABLED=false EMAIL_TO=you@example.com EMAIL_FROM=skycam@localhost -# Mattermost text post (can be same or different channel from daily upload). +# Mattermost text post — reuses the URL and token above, but posts to this +# channel (can be the same daily channel or a separate private/admin channel). MM_NOTIFY_ENABLED=false MM_NOTIFY_CHANNEL_ID=your-notify-channel-id-here diff --git a/sunrise.py b/sunrise.py index 4841655..2646b44 100644 --- a/sunrise.py +++ b/sunrise.py @@ -1,47 +1,30 @@ -#from suntime import Sun -#from datetime import datetime, timedelta -#import pytz - -#latitude = YOUR_LATITUDE -#longitude = YOUR_LONGITUDE - - - - - -#sun = Sun(latitude, longitude) -#tz = pytz.timezone(timezone) - -# Get yesterday's date and time -#yesterday = datetime.now(tz) - timedelta(days=1) -#sunrise_time = sun.get_sunrise_time(yesterday).astimezone(tz) - -# Print the sunrise time -#print(sunrise_time.strftime('%Y-%m-%d %H:%M:%S')) - - - -from datetime import datetime, timedelta +from datetime import datetime +import pathlib import pytz from suntime import Sun -# Example coordinates (e.g., New York City) -latitude = re.dacted -longitude = re.dacted +# Locate sky-cam.conf next to this script (works regardless of cwd). +_here = pathlib.Path(__file__).resolve().parent +def _read_conf(path): + conf = {} + with open(path) as f: + for line in f: + line = line.strip() + if line and not line.startswith('#') and '=' in line: + k, v = line.split('=', 1) + conf[k.strip()] = v.strip() + return conf -# Define the timezone -tz = pytz.timezone('America/New_York') +conf = _read_conf(_here / 'sky-cam.conf') + +latitude = float(conf['LATITUDE']) +longitude = float(conf['LONGITUDE']) +tz = pytz.timezone(conf['TIMEZONE']) -# Create a Sun object with the given latitude and longitude sun = Sun(latitude, longitude) - -# Get today's date and time in the desired timezone now = datetime.now(tz) - -# Get today's sunrise time in UTC and convert it to the desired timezone sunrise_utc = sun.get_sunrise_time(now) sunrise_time = sunrise_utc.astimezone(tz) -# Print the sunrise time in the desired format print(sunrise_time.strftime('%Y-%m-%d %H:%M:%S'))