...не привлекая ничьего внимания. Потребуется ZoneMinder, Home Assistant, и пара подручных инструментов.

Несколько лет назад у меня завелось хобби — я начал коллекционировать восходы. Тогда я поселился в доме, из которого открывался широкий вид на небо. Однажды, в очередной раз задержавшись за делами до восхода, я вышел на балкон и восхитился красоте. Записал пару минут на телефон, и на этом успокоился. Но в следующий раз ночью выставил на балкон экшн‑камеру. Так все и завертелось.

Восход — это очень красиво, но не любой. Красоту восходу придают облака, при достаточной плотной, но не сплошной, облачности восход становится уникальным, красивым и завораживающим.

Кадр из самого первого восхода, который я счел достойным коллекции
Кадр из самого первого восхода, который я счел достойным коллекции

Если восход был интересным, получившийся набор видеофайлов я закидывал в видеоредактор, на глаз обрезал начало и конец, склеивал, и ускорял в 100–200 раз. В итоге получался видеоролик на 1–2 минуты. Я скидывал его друзьям, иногда загружал на ютуб.

Довольно быстро стало понятно что дальше так продолжать не может. В этом меня напрягало две вещи:

  • необходимость незадолго до восхода вылезти на балкон, поставить камеру, включить ее, организовать питание;

  • долго возиться с файлами после.

Так как я эталоннейшая сова первый пункт напрягал даже поменьше, т.к. 4 утра для меня это ранний вечер.

Поэтому первый шаг в автоматизации состоял в написании скрипта для склейки и ускорения. То есть с помощью ffmpeg собрать много файлов в один, а потом ускорить его.

в нем ничего особого нету но пусть будет
!#/bin/sh

rm /users/user/sunrise/source/all.txt

for file in /users/user/sunrise/source/*
do 
file2=$(basename $file)
echo "file $file2" >> /users/user/sunrise/source/all.txt
done

cat /users/user/sunrise/source/all.txt

echo -n "Выглядит верно? (y/n) "

read item
case "$item" in
    y|Y) echo "Ввели «y», продолжаем..."
		echo "Продолжаем"
		now=$(date +"%d %m %Y")
		filename="Восход $now.mp4"
		cd /users/user/sunrise/source/
        ffmpeg -f concat -i /users/user/sunrise/source/all.txt -c copy /users/user/sunrise/out/temp.mp4
		ffmpeg -i /users/user/sunrise/out/temp.mp4 -filter_complex "[0:v]setpts=0.005*PTS[v]" -map "[v]" /users/user/sunrise/out/Восход_$(date +"%d-%m-%Y").mp4
		rm /users/user/sunrise/out/temp.mp4
        
        ;;
    n|N) echo "Ввели «n», завершаем..."
        exit 0
        ;;
    *) echo "Ничего не ввели. Выполняем действие по умолчанию..."
        exit 0
        ;;
esac

Потом я задумался об автоматизации записи. Мне не хотелось просто вешать камеру на балкон, чтобы не вызывать ненужных вопросов, поэтому я начал изобретать какую то систему, которая будет высовывать камеру, записывать что надо, а потом прятать ее.

Я разработал сложную систему моторизованного штатива, состоящую из 30 с лишним напечатанных деталей, мотора, управляемой из Home Assistant (далее - HA) четырехканальной релейной платы управления. До сих пор горжусь этой титанической работой. Внутрь конструкции была встроена недорогая управляемая камера высокого разрешения.

ускорено в 10 раз)
ускорено в 10 раз)
моделька

Хотя, если подумать, особо гордиться нечем, так как вся эта конструкция оказалась крайне ненадежной. Камера не была стабилизирована, видео получались плохие. Китайская ноунейм камера хоть и обещала 4K, но давала плохие записи. Механизм подъема/спуска часто заклинивало. На самом то деле недостатки стали понятны еще в процессе разработки, но на тот момент уже было интересно - осилю до конца или нет, так что доделал уже из интереса. Ну и после пары пробных запусков поставил в угол, до сих пор там стоит.

Ну и тут мы плавно подошли к нынешней ситуации и к описанию текущей работающей реализации съемки восходов. Я по прежнему не хотел просто вешать камеру на балкон, поэтому напечатал жесткий корпус, и фиксированно направил его на восток. На всякий случай в корпусе предусмотрена возможность менять угол наклона и поворота, но реальной необходимости в этом нет, камера охватывает весь доступный небосвод.

Корпус

Внутри спрятана HiWatch DS-I450L. Долго выбирал ее, изучая ТТХ и примеры видео, и кажется не прогадал. Угол чуть больше чем нужно, цветопередача хорошая, особенно радует цветное ночное видение. И полноценная влагозащита - несколько замечательных восходов сопровождались ливнями.

Камера подключена витухой к домашней сети и питается по POE через инжектор. В этом месте начинается автоматизация - POE инжектор воткнут в управляемую из HA розетку. Таким образом, на данном этапе у меня появилась надежная камера, направленная в нужную сторону, и возможность включать или выключать ее программно.

Следующий шаг - а на что записывать. Посмотрев что есть из СПО для видеонаблюдения, выбрал практически стандарт - Zoneminder (далее - zm), ролс-ройс в мире опенсорсных систем видеонаблюдения) Конечно, в этом предложении есть снобизм избалованного коммерческими системами человека, но объективно говоря в zm действительно много возможностей, хотя с наскоку в них непросто разобраться.

Покопавшись в запасах, собрал простенький комп под видеорегистратор, поставил на него серверную убунту. Включать сервер буду по питанию (на найденной матери не было wake‑on‑lan), поэтому для надежности еще туда wathdog реле воткнул.
Zoneminder ставится на нее очень просто, несколькими командами. Не буду останавливаться на этом, все как в документации. Добавление камеры тоже не вызывает проблем, главное чтобы она поддерживала rtsp.

Важный момент — по умолчанию zm записывает видео кусками по 10 минут. Лучше поставить минуту, ниже объясню почему.

После настройки записи zm записывает в mp4 файлы все что попадает на камеру, если она включена. Итак, у нас есть что записывать, и на что. Пора автоматизировать запись, и тут собственно вступает home assistant.

Собственно, бОльшая часть задачи решена за меня — в HA есть встроенный объект Sun, на основании которого система рассчитывает точное время восхода, заката, сумерек и тому подобного. Осталось взять это время и использовать его.

Логика такая — ежедневно в полночь будем рассчитывать время старта записи из расчета восход минус полтора часа, и время завершения записи из расчета восход плюс семь часов. HA умеет такое делать.

Заводим несколько вспомогательных объектов класса дата/время - время старта записи, время завершения записи, и время включения камеры. Как оказалось, включать камеру надо немного заранее, чтобы она успела прогреться, и с нее испарилась влага, если она осела на защитное стекло вечером (да, такое бывает).
И еще пару вспомогательных объектов класса переключатель - Записывать восход, и начать конвертацию восхода.

Заводим автоматизацию, рассчитывающую времена.

код автоматизации
alias: Расчитать время старта записи
description: ""
trigger:
  - platform: time
    at: "00:00:00"
condition: []
action:
  - service: input_datetime.set_datetime
    metadata: {}
    data:
      datetime: >-
        {{ (as_timestamp(state_attr("sun.sun", "next_rising"))-9000) |
        timestamp_local }}
    target:
      entity_id: input_datetime.vremia_vkliucheniia_kamery_dlia_progreva
  - service: input_datetime.set_datetime
    metadata: {}
    data:
      datetime: >-
        {{ (as_timestamp(state_attr("sun.sun", "next_rising"))-5400) |
        timestamp_local }}
    target:
      entity_id: input_datetime.start_zapisi_voskhoda
  - service: input_datetime.set_datetime
    metadata: {}
    data:
      datetime: >-
        {{ (as_timestamp(state_attr("sun.sun", "next_rising"))+21600) |
        timestamp_local }}
    target:
      entity_id: input_datetime.konets_zapisi_voskhoda
  - service: telegram_bot.send_message
    data:
      message: >-
        Запланирована запись восхода. Начало - {{
        (as_timestamp(state_attr("sun.sun", "next_rising"))-5400) |
        timestamp_local }}. Конец - {{ (as_timestamp(state_attr("sun.sun",
        "next_rising"))+21600) | timestamp_local }}
mode: single

Автоматизация запускается в полночь, рассчитывает три вспомогательных параметра, и отправляет в телегу уведомление о планировании.

Делаем еще две автоматизации, срабатывающие во время включения камеры и старта записи (при условии что включена запись восхода). Первая включает питание камеры (которая, напомню, включается управляемой розеткой, питающей poe инжектор). Вторая - включает розетку с сервером zoneminder. С ними все просто, даже не буду расписывать.

Собрал все в отдельный дашборд. Он особо не нужен, но кто не любит дашборды...
Собрал все в отдельный дашборд. Он особо не нужен, но кто не любит дашборды...

Третья автоматизация сложнее и вызывает больше событий. Срабатывать будет во время конца записи, и делать две вещи - выключать питание камеры, и переключать служебный переключатель "начать конвертацию восхода". А дальше начинается магия.

Наверное, у zm есть какое то api, которым можно вытаскивать записи, но поскольку у меня тут задача сугубо прикладная, а запись с камеры не постоянная, я не стал с ним разбираться. Проще оказалось взять сами файлы из хранилища. При непрерывной записи zm делит видео на файлы, складывая их в подпапки текущего дня в каталоге камеры. Поскольку у меня камера включается только на время записи восхода, можно принять за данность что все видеофайлы в папке текущего дня являются валидной записью. Дальше надо только составить список файлов, склеить их, и ускорить.

Уже после первых записей стало понятно, что у zm есть косячок. Ну или он был в моей конфигурации, но на тот момент я его не нашел. Если что то случилось во время интервала записи (который напомню по умолчанию составляет 10 минут), то файл‑кусочек окажется битым, и недописанным. Во первых он не будет корректно обрабатываться ffmpeg'ом. Если подсунуть в операцию concat битый файл то операция упадет. А вторых, что хуже, окажется пропущенным какое то время, и будет некрасиво. Поэтому выше я поставил интервал разбивки в одну минуту. В худшем случае я эту минуту потеряю, что при ускорении в пару сотен раз не сильно заметно. Ну и при составлении списка файлов можно тестировать видеофайлы на корректность, выполняя при ошибке попытку восстановления.
UPD: косяк нашел уже существенно позже — производительности системы в первой версии не хватало для нормального функционирования записи. После небольшого апгрейда проблема ушла. А функционал тестирования остался, но я сделал его отключаемым.

файлы записей в zm

Но сначала надо как то понять, что все — пора склеивать. Тут опять понадобится HA с его реквизитом «начать конвертацию восхода». Логика такая — каждые 10 минут обращаемся по api к HA, и смотрим на состояние этого реквизита. Если он выключен то ничего не делаем. А если включен, то делаем вывод что камера выключена, запись завершена. Выключаем его, и начинаем конвертировать. Наверное можно и как то попроще, например прямо с zm смотреть, доступна ли камера, но возможны перебои в сети или еще что то, так что я вынес логику решения наружу.

Для доступа к api понадобится долгосрочный токен. Его можно получить в параметрах текущего пользователя.

Итак, на сервере с zm создаем два скрипта.
Первый — проверка, не пора ли начинать конвертацию. Его пихаем в cron с интервалом 10 минут.

Скрипт, проверяющий не пора ли начинать конвертировать
#!/bin/bash

currentstate=$(curl -X GET http://ip_HA:8123/api/states/input_boolean.nachat_konvertatsiiu_voskhoda -H "Authorization: Bearer ______TOKEN________" | jq '.state' | sed 's/\"//g')

if [[ $currentstate = "on" ]]
  then 
  echo "time2work"

  curl \
   -H "Authorization: Bearer ______TOKEN________" \
   -H "Content-Type: application/json" \
   -d '{"state": "off"}' \
    http://ip_HA:8123/api/states/input_boolean.nachat_konvertatsiiu_voskhoda

  /home/user/makev.sh

else
  echo "relax"
fi

Сначала обращаемся к HA, авторизуемся токеном, получаем состояние элемента, и приводим его к виду on или off.

Если включено, то выключаем его и запускаем второй скрипт.

А иначе ничего не делаем.

Второй - собственно сборка и ускорение.

Скрипт по сборке и конвертации видеозаписей
#!/bin/bash


export today=$(date +"%Y-%m-%d")
export resultfolder="/home/user/sunrise"
export rootf="/var/cache/zoneminder/events/1"
export tempsource="/home/user/sunrise/source"
export filelist="/home/user/sunrise/all.txt"
export TOKEN='====TOKEN===='
export CHAT_ID='====CHATID===='
export checkfiles="no"


MESSAGE="начинаем конвертировать восход"
curl \
      --data parse_mode=HTML \
      --data chat_id=${CHAT_ID}} \
      --data text="${MESSAGE}" \
      --request POST https://api.telegram.org/bot${TOKEN}/sendMessage

rm $filelist
rm -f $tempsource/*
find $rootf/$today -name "*.mp4" | sort -V > $filelist
find $rootf/$today -name "*.mp4" -exec cp "{}" /home/klbr/sunrise/source/ \;


exit
if [[ "$checkfiles" == "yes" ]]
then

rm -f $tempsource/*

for file in $(cat $filelist)
do
#   if [ffmpeg -v error -i $file -f null - 2>&1 | cat | grep -q -wi error]


    ffmpeg -v error -i $file -f null - 2>&1

  if [ $? -eq 0 ]
   then
      echo "found error in $file. repairing..."
        filename="$(basename -- $file)"
        ffmpeg -i $file -vcodec copy -acodec copy $tempsource/$filename
   else
      echo "file $file is ok. copying..."
        cp $file $tempsource/
   fi

done

rm $filelist


find $tempsource -name "*.mp4" | sort -V > $filelist


fi

sed -i 's/^/file /' $filelist

now=$(date +"%d.%m.%Y")
filename="/home/user/sunrise/sunrise_$now.mp4"


cd $resultfolder/
rm $resultfolder/temp.mp4

ffmpeg -f concat -safe 0 -i $filelist -c copy $resultfolder/temp.mp4



ffmpeg -i $resultfolder/temp.mp4 -filter_complex "[0:v]setpts=0.005*PTS[v]" -map "[v]" $filename
rm $resultfolder/temp.mp4

if [ -e $filename ]
then

/usr/bin/curl --upload-file "$filename" ftp://zm:'zm'@_ip_network_storage/SUNRISE/

MESSAGE="Сконвертирован и загружен восход. Файл sunrise_$now.mp4"
curl \
      --data parse_mode=HTML \
      --data chat_id=${CHAT_ID}} \
      --data text="${MESSAGE}" \
      --request POST https://api.telegram.org/bot${TOKEN}/sendMessage

sudo shutdown now

else

MESSAGE="Что то пошло не так при конвертации восхода"
curl \
      --data parse_mode=HTML \
      --data chat_id=${CHAT_ID}} \
      --data text="${MESSAGE}" \
      --request POST https://api.telegram.org/bot${TOKEN}/sendMessage

fi

Поясню коротко: определяем текущую дату, приводим ее в формат, используемый zm, заходим в папку сегодняшнего дня, и рекурсивно составляем список файлов.
Если в переменной на старте включено тестирование видео то все файлы перед склеиванием тестируем. Если файл в норме — копируем его во временную папку без изменений. Если файл с ошибкой то пытаемся его восстановить и копируем уже восстановленный.
Если тестирование выключено, то берем файлы прямо из хранилища, без промежуточного копирования.
Затем передаем список в ffmpeg, получаем большой файл с полной записью. Потом ускоряем его.
Затем проверяем существует ли файл с результатом. Если да, то считаем что конвертация успешна, закидываем получившийся файл на сетевое хранилище, шлем уведомление в телегу, и выключаем сервер. Если нет — то шлем уведомление, и больше ничего не делаем.

Ну вот так вот, с помощью простого советского HA и zoneminder получилось автоматизировать хобби.

Дальше моей задачей было, получив уведомление, зайти на сетевое хранилище, посмотреть запись, и если она достойна коллекции, сохранить, иначе удалить.

В общем то, цель достигнута, коллекция пополняется почти сама, но теперь можно сделать еще одну интересную штуку. Вы когда нибудь видели 64 восхода одновременно?
Наличие множества файлов, в которых какое то общее событие происходит в одну и ту же секунду относительно начала файла, позволяет это сделать.

Видео на ютубе

Остальные записи там же.

Может быть потом руки дойдут до автоматической оценки восхода и заливки на ютуб (хотя зачем буду нужен я?). И еще надо как то убрать эффект рыбьего глаза, вносимый камерой из за ее широкоугольности. С этим тоже может помочь ffmpeg но что то пока не получается.

Периодически, набирая эту статью, я задавался вопросом — а зачем. Вряд ли кто то прочитав будет записывать восходы или закаты (а было бы неплохо, такого контента не хватает). Но потом подумал — ну восходы восходами, но ведь много людей делают таймлапсы. Обычно все ограничиваются набором фоток, которые потом склеивают. Но ведь ускоренное видео это же гораздо лучше, верно? Ну вот, можно взять этот кейс и относительно просто его делать.

Комментарии (16)


  1. Javian
    08.01.2025 18:17

    1. Поселиться в доме, из которого открывался широкий вид на небо.

    Несколько ограничивает выборку потенциальных пользователей. А если человек поехал на море и хочет с балкона отеля/апартаментов снимать? Или вообще автотуристы на пляже?

    Логичнее было бы завязать всё это на GPS (время и координаты) и, например, телефон как сервер с WiFi, берущий снимки с камеры.

    А Вы заметили на палатке антенну? Я только что впервые увидел :)
    А Вы заметили на палатке антенну? Я только что впервые увидел :)


  1. Sazonov
    08.01.2025 18:17

    Скажите, а вы не пробовали вместо видео делать фото? Можно с выдержкой и iso поиграться. И возможно получится более высокое качество. Конечно это только в том случае, если нужен именно таймлапс.


    1. kolabaister Автор
      08.01.2025 18:17

      Попробовал, но получается не то. Видео, даже ускоренное в 200 раз, все равно остается видео, совсем другая плавность.
      Съемка долгих явлений в фото это как ни крути компромисс. Когда надо экономить или место на диске, или энергию, или ресурсы для обработки. А у меня все это есть, экономить не надо. Ну и как и с любым компромиссом получается не так хорошо как могло бы быть.


      1. Sazonov
        08.01.2025 18:17

        Понял, спасибо. Странно, но ок. Впрочем мои сценарии были куда проще (с фото в таймлапс) - рассвет на телефон и закат на квадрокоптер.


      1. Artandpro
        08.01.2025 18:17

        Случайно нашел статью в подборке и не смог пройти мимо.) Сам вдохновившись timestorm films давно занимаюсь съемками, в том числе таймлапсов. Сейчас решился снять годовой проект. Так вот, настоящий таймлапс как раз и делается из фотографий, это даёт лучшее качество и больше простора творчеству, а для плавности как на видео, нужно учитывать много моментов. Это только все ручные настройки, выбор правильного интервала, в зависимости от сцены, и правильная склейка. А хобби на то и должно быть хобби, чтобы получать удовольствие от процесса) А вместо автоматизированной камеры я собрал моторизированный слайдер, для гиперлапсов, когда очень медленно движется камера, и быстро плывут облака. А если нет желания со всем заморачиваться, то какая нибудь экшн камера сделает все за вас))


      1. Quiensabe
        08.01.2025 18:17

        Просто вам достаточно того уровня который получается. А тем кто снимает таймлапсы более профессионально - варианта основанного на видео быстро перестает хватать, вот и уходят на фото.

        В ваших видео постоянные пересветки на облаках близких к солнцу, а если просто сдвинуть экспокоррекцией (если камера это умеет) - то динамический диапазон будет совсем плох. Картинка нечеткая, на резких границах - перешарпленная, до честных 2560x1440 - там очень далеко. А если вы захотите выровнять перспективу - то потеряете еще больше, там уже и FullHD не будет...

        Все это не к тому, что вы что-то плохо делаете, вас устраивает, зрителям нравится - и отлично. Просто поясняю почему выбирают фото, а не видео. Вовсе не потому, что кому-то жалко флешку побольше :)

        Фото таймлапсы действительно снимать сложнее, так чтобы добиться плавности движения, отсутствия мерцания, плавной коррекции экспозиции и прочее - там очень много технических моментов. Но зато и результат офигенный.


  1. Sasha_Berg
    08.01.2025 18:17

    Вряд ли кто то прочитав будет записывать восходы или закаты (а было бы неплохо, такого контента не хватает).

    Честно говоря, не против снимать восходы и закаты. Точно найду чем и придумаю как.

    Но возник вопрос - а кому это надо?

    Почему Вы уверены, что такого контента не хватает? Зачем он? Даже судя по просмотрам Ваших видео становится понятно, что контент не востребован.

    К слову, мне не очень понравилась композиция кадра. Остальное - таймлапс как таймлапс. Хотя...нет, мне бы понравилось, если бы облака не так торопились бежать по небу.


    1. kolabaister Автор
      08.01.2025 18:17

      Такого контента не хватает лично мне в текущем информационном потоке. Если бы его было больше - было бы лучше. Как минимум мне, хотя может и кому то еще) Что по востребованности - да, не особо. Летом, когда видео часто выкладываются, доходит до 1-2 тысяч просмотров в день (не конкретно нового видео а всего, их там много). В несезон - до 100 просмотров в день. Это все объясняется алгоритмами рекомендаций ютуба.

      Скорость видео напрямую диктуется длительностью. 1-2 минуты - это потолок, больше редко кто досмотрит.


      1. Refridgerator
        08.01.2025 18:17

        Музыку накладываете на видео?


        1. kolabaister Автор
          08.01.2025 18:17

          Нет


          1. Refridgerator
            08.01.2025 18:17

            Вот поэтому и не досматривают) У меня есть любимый ролик с заходом солнца от неизвестного автора, с музыкой, на 25 минут. Смотрел много раз от начала до конца.


            1. kolabaister Автор
              08.01.2025 18:17

              Ну и сами себе злобные буратины)

              Это путь в один конец. Не так то просто найти порядка 100 уникальных незаезженных треков в год, к которым не будет претензий по авторским правам.


              1. Refridgerator
                08.01.2025 18:17

                Найти может и нет, а вот генерировать опираясь на видеоряд - вполне реально. И не обязательно прям музыку-музыку, амбиент-дрона вполне достаточно.


  1. Usper
    08.01.2025 18:17

    При наличии экшен камеры не логичнее ли было использовать её для съёмки таймлапсов? Они сейчас это умеют, и защита от осадков есть.


    1. kolabaister Автор
      08.01.2025 18:17

      Первый год я так и делал (не таймлапсы а видео, про таймлапы говорил выше, это не то). Но это требует многих дополнительных движений, и не дает стабильности в положении.


  1. riky
    08.01.2025 18:17

    У нас в городе тоже есть энтузиаст транслирует с высотки на Ютюб 24/7 плюс ускоренные 24 часа за 6 минут. Бывает интересно глянуть когда погода не обычная. Но в целом просмотров жду бог десятки. Но у него закатная сторона дома.