Commit Graph
37 Commits
Author SHA1 Message Date
Claude 5fb7ff09a3 Add nightly moon-track timelapse and monthly moon-phase composites
Two new jobs operate on the SUNRISE_CAM, sharing three Python helpers
(moon_phase, moon_detect, moon_composite) and one cached lunar texture:

- moon-track.sh: nightly batch detects the moon in each east frame,
  crops a 480x480 box around it, stitches into an mp4 that holds the
  moon roughly centred while clouds and stars drift past.

- moon-phase-monthly.sh: daily check that runs whichever phase composite
  is due that day. Handles full moon (posts D+3), first quarter (D+2,
  best-effort due to daytime-only geometry from east), and third quarter
  (D+2). Picks the frame closest in time to the exact phase moment that
  meets quality / altitude / illumination thresholds, then composites
  the cached lunar texture into it -- sky/halo/parallactic-angle/timing
  real from east, surface detail borrowed from the reference image.

Honest-by-design: a 38-px white blob from a wide-field IP camera cannot
be enhanced into crater detail by software. The composite makes the
borrowing explicit and constrains everything else (when, where, sky,
orientation) to match what east actually saw.

install.sh now downloads the skyfield ephemeris (de421.bsp) and the
default lunar reference (Wikipedia CC BY-SA full-moon photo) on first
run. Both can be overridden via .env.

https://claude.ai/code/session_015PBVDESC3KLMbq1LpA6qLn
2026-04-30 11:40:11 +00:00
Claude 5810ab0194 Trim weather-tag vocabulary to audio-relevant precipitation only
Drops clear/cloudy/fog/windy and the wind-speed override — those
conditions sound the same on the recordings, so they don't earn a tag.
Also renames "rainshower" → "rainstorm" and rebalances the rain
mapping so 503/504/522 (extreme + heavy showers) get the storm tag.

Final vocabulary: thunderstorm, rain, rainstorm, snow, snowstorm.
Anything else falls through to the un-tagged filename.
2026-04-29 18:55:59 +00:00
Claude 9e1087f875 Tag ambient audio chunks with current OpenWeather conditions
Adds weather-tag.sh, a small failure-safe helper that queries OpenWeather's
free "Current weather" endpoint and prints one tag from a fixed vocabulary
(thunderstorm, rain, rainshower, snow, snowstorm, fog, windy, cloudy, clear)
or nothing on any failure.

ambient-record.sh calls it just before each 30-minute chunk so the filename
reflects conditions at the moment of capture, e.g.
  east-08-30-00-thunderstorm.m4a
  east-12-00-00-clear.m4a
A foggy dawn no longer mislabels the sunny afternoon files.

Off by default. Enable with WEATHER_ENABLED=true and an
OPENWEATHER_API_KEY entry in .env; missing key / API error / disabled
toggle all fall through to the un-tagged filename, never blocking the
recorder.
2026-04-29 18:40:27 +00:00
Outis a1e1713111 Enable audio capture and notifications in config 2026-04-23 09:46:13 -04:00
Claude 98dcf23687 4-seasons: replace size-rejection with 1MB fast-skip for grey filter
File size can't reliably reject bad frames (200KB can be good or bad).
Remove SEASONS_MIN_FRAME_BYTES.  Instead, the grey/green uniform-colour
filter (SEASONS_GREY_STDDEV_MIN) now skips the expensive ImageMagick
check for files above SEASONS_LARGE_FRAME_BYTES (default 1 MB) since
those are always good.  Only sub-1MB files get the content check, making
the filter practical on days with 40k+ images.

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-23 02:34:26 +00:00
Claude 9d34240ac0 sky-cam.conf: comment out grey filter — must be explicitly enabled
The SEASONS_GREY_STDDEV_MIN and SEASONS_GREY_DARK_FLOOR settings are
now commented out so the filter is fully inert by default and requires
a deliberate edit to activate.

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-22 16:22:25 +00:00
Claude ec8eb7aebf 4-seasons: protect night frames from grey filter with brightness floor
A stddev-only filter would wrongly drop near-black night frames.
Now only skips a frame when BOTH stddev < GREY_MIN AND mean brightness
> GREY_DARK_FLOOR (default 30/255).  Night frames are dark so they
always pass; bad-signal grey frames are mid-bright so they are caught.

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-22 16:17:22 +00:00
Claude 4aeee6b3d5 4-seasons: validate JPEGs with ffprobe, add optional grey-frame filter
The previous size check caught empty files but not corrupt JPEGs with
a partial header (common first frame after a camera reconnect).
Replace with ffprobe codec detection — if ffprobe can't identify a
video stream in the file it's skipped with a clear "corrupt" message.

Also adds SEASONS_GREY_STDDEV_MIN (default 0 = off): when enabled,
frames with near-zero pixel standard deviation (uniform grey = bad
RTSP signal) are silently dropped before encoding.

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-22 16:07:29 +00:00
Claude 11d4630197 Restructure audio into AUDIO_DIR with per-camera retention
New AUDIO_DIR variable (like BASE_DIR/MOVIES_DIR) is the root for all
audio recordings.  Set in .env to put audio on a separate drive.

Directory layout:
  AUDIO_DIR/<cam>/YYYY-MM-DD/HH-MM-SS.m4a        — ambient recordings
  AUDIO_DIR/sunrise/<cam>/YYYY-MM-DD/sunrise-audio.m4a — sunrise clips

sky-cam.conf:
- Add AUDIO_DIR="${AUDIO_DIR:-$BASE_DIR/audio}" in storage section
- Remove AMBIENT_DIR (replaced by AUDIO_DIR)
- Add SUNRISE_AUDIO_RETENTION_DAYS=7 (sunrise clips kept separately from ambient)
- Add per-camera ambient retention examples:
    AMBIENT_RETENTION_DAYS_south=60  (keep bird recordings longer)

ambient-record.sh:
- Use AUDIO_DIR instead of AMBIENT_DIR
- Per-camera retention: AMBIENT_RETENTION_DAYS_<cam> overrides global default

sunrise-audio-capture.sh:
- Save clips to AUDIO_DIR/sunrise/<cam>/<date>/sunrise-audio.m4a
- Rolling retention of sunrise clips (SUNRISE_AUDIO_RETENTION_DAYS)

daily_sunrise_video.sh:
- Look for cam_audio in new AUDIO_DIR/sunrise path first, fall back to
  old BASE_DIR path so existing recordings keep working

install.sh:
- Pre-create AUDIO_DIR/<cam> and AUDIO_DIR/sunrise/<SUNRISE_CAM> dirs
- Add AUDIO_DIR to .env.example storage section

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-22 14:43:05 +00:00
Claude a63a42ee46 Add Demoio directory for test videos with 8-day retention; capture gap warning
daily_sunrise_video.sh:
- Test output now saves to DEMO_DIR/<cam>/ (default: MOVIES_DIR/demoio/<cam>/)
  instead of the production sunrise-only directory
- After each test run, deletes test files older than DEMO_RETENTION_DAYS (8)
- Production mode: warns if the last selected frame is >3 intervals before
  the window end, which indicates the capture service had a gap near sunrise:
    WARNING: last frame is 20min 0s before window end — capture gap near sunrise
             Check: systemctl --user status sky-cam-capture-east.service

sky-cam.conf: add DEMO_DIR and DEMO_RETENTION_DAYS settings

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-22 14:23:30 +00:00
Claude 1cf51eaa26 Auto-delete old unpinned sunrise posts from Mattermost after each upload
sunrise2mm.py: after a successful upload, scan the channel and delete any
post older than MM_SUNRISE_RETENTION_DAYS that is not pinned and has a file
attachment. Pinned posts are always preserved regardless of age.

sky-cam.conf: add MM_SUNRISE_RETENTION_DAYS=8 (independent of the local
disk SUNRISE_RETENTION_DAYS so the two retentions can differ).

Also modernises sunrise2mm.py: uses the same ${VAR:-default} aware
read_config as sunrise.py, consistent error handling, cleaner structure.

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-22 14:09:27 +00:00
Claude 3c50e5dad2 Clarify .env vs sky-cam.conf split for toggles and private values
Rule is now consistent throughout:
- *_ENABLED flags are plain true/false in sky-cam.conf — flip them there
- Private values (URLs, credentials, location) go in .env only

sky-cam.conf:
- NTFY_ENABLED, EMAIL_ENABLED, MM_NOTIFY_ENABLED are now plain false (not
  using the ${VAR:-} pattern, which implied they could go in .env)
- NTFY_URL, EMAIL_TO, EMAIL_FROM, MM_NOTIFY_CHANNEL_ID use ${VAR:-} pattern
  so they are set in .env
- LATITUDE/LONGITUDE comment clarified with example .env lines

install.sh .env.example: updated notification comment to match

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-22 13:56:58 +00:00
Claude 74a74570fc Move location/music/ntfy config to .env; add paths to notifications
sky-cam.conf:
- MUSIC_DIR now uses override pattern (MUSIC_DIR="${MUSIC_DIR:-$SCRIPT_DIR/music}")
  so the real path can be set in .env without hardcoding it
- LATITUDE/LONGITUDE use override pattern; set real coords in .env to keep
  location private and out of git
- NTFY_URL now uses override pattern with empty default; set in .env
- NTFY_ENABLED moved out of comments into active config with false default

sunrise.py:
- Reads .env after sky-cam.conf so .env values override (same source order
  as sky-cam.conf itself)
- Handles ${VAR:-default} bash syntax when parsing sky-cam.conf values

All completion notifications now include the full output file path so you
can tell at a glance where the file landed:
- daily_sunrise_video.sh: "filename — Xs, sunrise at HH:MM | /full/path"
- 4-seasons.sh: "filename — Xs | /full/path"
- montage-mvt.sh: "filename | checks | /full/path | verify: ..."
- year-end-join.sh: "filename — Xmin | /full/path" (also adds [cam] to title)

install.sh .env.example now includes LATITUDE, LONGITUDE, MUSIC_DIR, NTFY_URL

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-22 13:30:02 +00:00
Claude dbdd59677f Per-camera capture interval; ambient recorder; fix 4-seasons one-frame bug
Per-camera capture interval:
  CAPTURE_INTERVAL_<cam> in sky-cam.conf overrides the global value for
  a specific camera.  capture.sh and 4-seasons.sh both respect it.
  Example: south at 30s saves storage; north at 5s gives smoother motion.

4-seasons.sh one-frame bug fix:
  Same root cause as the sunrise scripts — concat list had no 'duration'
  entries, collapsing all JPEG frames to timestamp 0.  Fixed by writing
  'duration INTERVAL' per frame.  Added fps=25 to the speed-adjust step
  so the VFR source resamples to a standard frame rate.

ambient-record.sh (new):
  Continuous AAC recorder for natural sounds (birds, rain, wind).
  Saves AMBIENT_CHUNK_SECS chunks to AMBIENT_DIR/<cam>/YYYY-MM-DD/HH-MM-SS.m4a.
  Reconnects automatically on stream failure.  Rolling retention via
  AMBIENT_RETENTION_DAYS.  Enabled by setting AMBIENT_ENABLED=true and
  listing cameras in AMBIENT_CAMS in sky-cam.conf, then re-running install.sh.

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-21 21:08:10 +00:00
Claude 0ccfb2dae0 Add MONTAGE_MUSIC_LOOPS per-movement music loop multiplier
Short adagio movements (Summer Mvt 2 at 107s, Winter Mvt 2 at 132s, etc.)
compress each day to only 3-5 seconds of screen time at 1×.  Looping the
music N times multiplies the per-day target duration proportionally so the
footage is less aggressively sped up and more watchable.

- sky-cam.conf: add MONTAGE_MUSIC_LOOPS and per-movement overrides
  (Summer Mvt2=3×, Winter Mvt2=3×, Autumn Mvt2=2×, Summer Mvt3=2×, Spring Mvt2=2×)
- 4-seasons.sh: multiply target_per_clip by loops
- montage-mvt.sh: compute effective_duration, use -stream_loop for audio,
  fix fade_out_start, -t, and post-build duration check
- make-finals.sh: multiply target by loops

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-20 20:11:10 +00:00
Claude a395f9baba Encoding: H.265 final montages, slow preset, sunrise retention
- sky-cam.conf: add ENCODE_PRESET=slow (applied to all encodes);
  split CRF_MONTAGE (intermediates, H.264) from CRF_MONTAGE_FINAL=22
  (archive montage, H.265); add SUNRISE_RETENTION_DAYS=10; improve
  CAPTURE_INTERVAL comment with storage/density table
- montage-mvt.sh: steps 1+2 use preset; step 3 final switches to
  libx265 + CRF_MONTAGE_FINAL + -tag:v hvc1 for broad compatibility
- 4-seasons.sh: both encode steps use ENCODE_PRESET
- daily_sunrise_video.sh: all encode steps use ENCODE_PRESET; rolling
  retention deletes sunrise videos older than SUNRISE_RETENTION_DAYS

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-20 17:27:57 +00:00
Claude ab06c1cc2b Fix MUSIC_DIR path quoting — space in '4 Seasons' broke conf sourcing
https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-20 16:40:55 +00:00
Claude c4fb086f1d Fix bugs found in post-refactor audit
- verify-mvt.sh: remove dead first _info= line (used MVT_START before
  defined); fix JPEG size loop to accumulate bytes correctly and display
  human-readable total; show size in delete confirmation
- montage-mvt.sh: grep -c uses || echo 0 instead of || true to be
  unambiguous about the no-match value under set -e
- capture.sh, capture-watchdog.sh: require camera name arg, remove
  silent SUNRISE_CAM fallback
- migrate-seasons.sh: require --cam arg, error if missing
- README.md, sky-cam.conf: remove stale fullday-video.sh references;
  README pipeline diagram updated to show verify-mvt.sh

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-20 16:34:05 +00:00
Claude 91006bf5f6 sky-cam.conf: clean up schedule comments, west camera placeholder
Remove stale SCHEDULE_FULLDAY comment block; add commented west camera
slot with instructions so enabling it is a one-line uncomment.

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-20 15:59:12 +00:00
Claude b4019ade9d Add north/south cameras, remove fullday, add verify-mvt.sh
- sky-cam.conf: CAMERAS now includes east, north, south with staggered
  SCHEDULE_SEASONS times (01:00, 01:30, 02:00); fullday schedules and
  tuning removed
- install.sh: fullday service/timer generation removed entirely
- fullday-video.sh + systemd units: deleted
- montage-mvt.sh: post-build technical checks (duration drift, video/audio
  stream presence) added; notification now includes check results and the
  exact verify-mvt.sh command to run
- verify-mvt.sh: new interactive CLI for montage review — shows checks,
  plays video, deletes source JPEG folders on approval, or re-runs montage

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-20 15:56:12 +00:00
Claude 3265ed80fd Add per-camera capture watchdog with stall and recovery notifications
capture-watchdog.sh: long-running script that checks the newest JPEG mtime
in each camera's output directory every CAPTURE_STALE_SECS/3 seconds (min 5s).
Sends a stall notification via notify.sh if no new frame has arrived within
CAPTURE_STALE_SECS. Sends a recovery notification once new frames resume.
Only alerts if the camera was previously working (avoids false positives on
first start or overnight before the first frame of the day).

sky-cam.conf: CAPTURE_STALE_SECS=30 added next to CAPTURE_INTERVAL with a
note that it should be at least 2x the interval.

install.sh: generates sky-cam-watchdog-<cam>.service for every camera that
has a RTSP URL configured. The watchdog service starts after and alongside
the capture service, restarts on failure, and is enabled/started with the
same loop as the capture service.

README.md: note about watchdog and journalctl command for its logs.

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-20 01:13:49 +00:00
Claude 64cec6b769 Rename default camera from 'sunrise' to 'east' for compass consistency
Cameras are now named by direction (east, north, south, west) throughout
config defaults, examples, and documentation. The config key SUNRISE_CAM
is unchanged — it still means 'which camera faces east and gets the sunrise
job'. Only the camera instance name value changes from 'sunrise' to 'east'.

sky-cam.conf: CAMERAS=(east), SUNRISE_CAM=east, SCHEDULE_*_east,
example comments updated to show all four compass points.
README.md: all command examples updated (4-seasons.sh east, journalctl
sky-cam-capture-east, etc.) — phenomenon references ('sunrise window',
'sunrise time') left unchanged.
bootstrap.sh: example updated to show compass directions.

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-20 00:53:58 +00:00
Claude 4814c9e158 Audio capture records exactly SUNRISE_TARGET_SECS centred on sunrise
Previously sunrise-audio-capture.sh recorded the entire capture window
(70+ minutes) and daily_sunrise_video.sh sought to the right position with
a complex offset calculation.

Now: record floor(TARGET/2) seconds before sunrise and ceil(TARGET/2) after —
odd second goes to post-sunrise.  The file is exactly SUNRISE_TARGET_SECS long
and already centred, so no offset is needed when mixing.

AUDIO_PRE_BUFFER_MIN removed — it was part of the old whole-window scheme
and is no longer meaningful.

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-20 00:22:35 +00:00
Claude be714affc0 Auto-detect SCRIPT_DIR/BASE_DIR; sunrise waits for capture window; optional overlay
sky-cam.conf:
- SCRIPT_DIR auto-detects from its own location via BASH_SOURCE — no manual
  path entry needed after bootstrap; override still works via environment.
- BASE_DIR defaults to \$SCRIPT_DIR/data; MOVIES_DIR defaults to \$BASE_DIR/movies.
  Override either to point at a drive/mount as before.
- SCHEDULE_SUNRISE changed to 03:00 — the script now waits internally until
  the capture window closes before touching images, so the schedule just needs
  to be early enough, not timed exactly to sunrise.
- Schedule section rewritten to explain what each job does and what day's data
  it processes (SEASONS/FULLDAY always process yesterday).
- SUNRISE_PRE_MIN/POST_MIN comments explain the window and its relationship to
  SUNRISE_TARGET_SECS.
- SUNRISE_OVERLAY_ENABLED=true added; set false to skip the timestamp entirely.

daily_sunrise_video.sh:
- After calculating the capture window, sleep until end_sec+30s if we fired
  before the window finished — guarantees all images are present.
- DT (drawtext filter) is only built when SUNRISE_OVERLAY_ENABLED=true.
- Step 3b skips ffmpeg entirely when overlay is disabled, moving work_video
  directly to final_video (faster, no re-encode).

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-20 00:18:43 +00:00
Claude a1b9ffa8ee Add .env credentials file support; gitignore .env and sunrise-sounds/
sky-cam.conf now sources .env from the same directory at the bottom of the
file, so RTSP URLs, Mattermost tokens, and notification credentials can live
outside version control.  Plaintext credential placeholders removed from conf.

install.sh generates .env.example on every run with the correct CAM_RTSP_*
variable names derived from the CAMERAS list, so users always know exactly
what to put in .env for their specific camera setup.

.gitignore: add .env and sunrise-sounds/ (downloaded audio library).

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-19 23:08:01 +00:00
Claude 9fe0051f70 Add pure-ffmpeg RTSP capture and camera audio for sunrise videos
Removes dependency on MotionEye or any NVR software.  Everything is now
CLI/ffmpeg configured entirely from sky-cam.conf.

capture.sh
  Long-running systemd service (one per camera) that pulls frames from the
  camera's RTSP stream at CAPTURE_INTERVAL seconds, writing HH-MM-SS.jpg
  into BASE_DIR/<cam>/YYYY-MM-DD/.  Restarts at midnight for the new date
  directory; auto-reconnects on camera disconnect.

sunrise-audio-capture.sh
  One-shot service triggered at 03:00.  Waits until (sunrise minus
  SUNRISE_PRE_MIN minus AUDIO_PRE_BUFFER_MIN), then records the RTSP audio
  stream for the full sunrise window.  Output deleted after mixing.

daily_sunrise_video.sh
  Step 3 now mixes in sunrise-audio.m4a when AUDIO_ENABLED=true and the
  file exists.  Audio is centred on actual sunrise time at natural speed
  while the video plays as the sped-up timelapse.  Uses filter_complex
  when audio is present (can't combine -vf with -filter_complex).

install.sh
  Generates sky-cam-capture-<cam>.service for each camera with CAM_RTSP_<cam>
  set, and sky-cam-audio-capture.{service,timer} when AUDIO_ENABLED=true.

sky-cam.conf
  New settings: CAM_RTSP_<cam>, CAPTURE_INTERVAL, AUDIO_ENABLED,
  AUDIO_PRE_BUFFER_MIN, CAPTURE_AUDIO_BITRATE.

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-19 20:59:40 +00:00
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
Claude 6d68010691 Expose encoding quality and overlay durations in sky-cam.conf
Adds six CRF vars, AUDIO_BITRATE, and three MONTAGE_* overlay durations.
Values match previous hardcoded defaults so behavior is unchanged.

The same CRF appeared in several scripts but with intentionally different
values per purpose (28 for draft intermediates, 26 for polished output).
Each script's CRF is now its own variable in conf, so changing one never
silently changes another.

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-19 16:08:14 +00:00
Claude fffb19fd38 Add MOVIES_DIR to conf; remove hardcoded 'movies' subdir
All scripts now use $MOVIES_DIR instead of $BASE_DIR/movies.
Defaults to BASE_DIR/movies but can point to a separate drive.

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-19 16:01:27 +00:00
Claude 46b3a36d0a Add lat/lon source instructions to conf comment
https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-19 11:08:19 +00:00
Claude 6d85fa525a Multi-camera support; schedules in conf; comment out notifications
sky-cam.conf:
- CAMERAS array replaces single CAM_NAME; add a name, add its schedules,
  re-run install.sh — no script editing needed
- SCHEDULE_SUNRISE, SCHEDULE_SEASONS_<cam>, SCHEDULE_FULLDAY_<cam> replace
  hardcoded times in install.sh
- Notification options commented out (uncomment to enable)
- Lat/lon set to mid-Atlantic (25.0, -38.0) as neutral placeholder

install.sh:
- Loops over CAMERAS to generate per-camera sky-cam-seasons-<cam> and
  sky-cam-fullday-<cam> timers with schedules from conf
- Sunrise timer remains a single sky-cam-sunrise unit (SUNRISE_CAM only)

fullday-video.sh, 4-seasons.sh, montage-mvt.sh, year-end-join.sh:
- Each accepts camera name as an argument (systemd passes it via ExecStart)
  and falls back to conf default when run manually without an arg
- Camera name propagates through the full call chain:
  4-seasons → montage-mvt → year-end-join

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-19 11:04:51 +00:00
Claude f8c1b4522d Add file dependency map to sky-cam.conf
Documents who calls whom and exactly which files to update
if any script is renamed — so future-you doesn't have to grep.

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-19 00:59:31 +00:00
Claude 4ca1f579d2 Rename sunrise_video.10s.sh → daily_sunrise_video.sh
Name no longer implies a fixed duration. Updated all references:
install.sh, sky-cam.conf script map, systemd/sky-cam-sunrise.service.

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-19 00:52:24 +00:00
Claude be5735867e Remove all hardcoded deployment values; read from sky-cam.conf
- sunrise_video.10s.sh: use $TIMEZONE (was hardcoded America/New_York),
  $SUNRISE_PRE_MIN/$SUNRISE_POST_MIN for capture window, $SUNRISE_TARGET_SECS
  for output duration (was wrong value 8 in a script named 10s)
- fullday-video.sh: remove hardcoded FULLDAY_FPS/RETENTION_DAYS; both now
  come from sky-cam.conf
- 4-seasons.sh, montage-mvt.sh: export TIMEZONE after sourcing conf so
  season_info.py subprocess picks it up via env rather than falling back
  to its hardcoded America/New_York default
- sky-cam.conf: add SUNRISE_PRE_MIN, SUNRISE_POST_MIN, SUNRISE_TARGET_SECS,
  FULLDAY_FPS, RETENTION_DAYS

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-19 00:14:59 +00:00
Claude 713c44adb3 Add LATITUDE/LONGITUDE to conf; sunrise.py reads coords from conf
sunrise.py now reads LATITUDE, LONGITUDE, and TIMEZONE from sky-cam.conf
instead of hardcoded values, using the same pathlib-based pattern as
sunrise2mm.py.  sky-cam.conf gains a comprehensive header with manual
systemd setup instructions and a full script map for future reference.

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-19 00:09:58 +00:00
Claude 5d3ee97df0 All paths into sky-cam.conf; install.sh generates systemd units
sky-cam.conf
- Add SCRIPT_DIR (install location) and CAM_NAME (camera/folder name)
- These are the only values that change when deploying to a new machine

install.sh (new)
- Sources sky-cam.conf, generates all systemd .service and .timer units
  with correct ExecStart paths, then enables and starts the timers
- Run once after editing sky-cam.conf; run again if paths change
- Supports --system flag for system-wide install

All .sh scripts + sunrise2mm.py
- No hardcoded paths remain
- script_name=$(basename ...) derivation replaced by $CAM_NAME from conf
- sunrise_video.10s.sh now sources sky-cam.conf for BASE_DIR, CAM_NAME,
  and SCRIPT_DIR (replaces all /home/motion/... references)
- sunrise2mm.py builds video path from BASE_DIR + CAM_NAME in conf

systemd/ template files kept as reference but no longer need editing

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-18 21:31:26 +00:00
Claude ac01c05948 Consolidate config into sky-cam.conf; systemd failure notifications
sky-cam.conf (new)
- Single file replaces mattermost_config.txt reference, notify_config.txt,
  and the hardcoded BASE_DIR/MUSIC_DIR/TIMEZONE scattered across scripts
- Bash-sourceable and Python key=value readable (same format)

All .sh scripts
- source sky-cam.conf at startup; BASE_DIR / MUSIC_DIR from config

sunrise2mm.py
- Reads sky-cam.conf relative to script location; no hardcoded path

notify.sh
- Sources sky-cam.conf; Mattermost credentials come from there directly,
  no separate mattermost_config.txt lookup needed

systemd/sky-cam-notify-failure@.service (new)
- Template unit called by OnFailure= in each service
- Sends notification via notify.sh when any sky-cam job fails
- All three .service units now have OnFailure=sky-cam-notify-failure@%n.service

Removed: notify_config.txt, sky-cam.crontab (superseded)

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
2026-04-18 17:11:06 +00:00