Jump to content
iT4iT.CLUB
Kitsum

Видеонаблюдение на основе пакета Motion

Recommended Posts

Всем доброго времени суток.

Как всегда начнем с предыстории. Необходимо было реализовать видеонаблюдение за помещением, естественно с нулевым бюджетом, а как иначе. В наличие имелся сервер с Linux на борту и домашняя usb web камера. За основу был взят программный пакет Motion. В принципе ничего сложного в настройке нет, правим пару строк в конфиге и вуаля. Писать было ни о чем. 

На днях обновил Ubuntu до версии 16.04.1 LTS и заодно, решено было обновить часть пакетов, в том числе Motion, и переделать систему видеонаблюдения. От usb камеры давно было решено отказаться, и ей на смену пришла дешевая IP камера (поддерживающая MJPEG поток) купленная на распродаже.

cam1.JPGcam2.JPG

Отразим все на "бумаге"

Имеется:

  • Сервер Linux Ubuntu 16.04.1 LTS
  • Пакет Motion 3.2.12
  • IP камера с поддержкой MJPEG

Требуется:

  • Писать только видео (никаких фото и таймлапсов)
  • Писать только по движению
  • Оповещать об обнаружении движения
  • Транслировать поток в реальном времени с сервера

В Ubuntu установка пакетов проста до безобразия

apt-get update && apt-get install motion

По завершении установки переходим в каталог с файлом конфигурации

cd /etc/motion
nano motion.conf

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

Сам Motion может работать одновременно с несколькими потоками (камерами для обывателя), неважно будь то IP камеры, USB камеры или иные устройства захвата видео. Да хоть все вперемешку. Самое главное, что если мы используем IP камеры, то они должны поддерживать MJPEG поток. Никакого RTSP (Real Time Streaming Protocol) Motion не поддерживает.

Файл конфигурации motion.conf представляет из себя набор основных настроек программы и настройки для первого потока. Все последующие потоки можно конфигурировать в файлах thread1.conf, thread2.conf ... thread9.conf (по умолчанию они отсутствуют) и подключать в конце файла motion.conf

Лично я предпочитаю основные настройки и настройки по умолчанию хранить в основном файле конфигурации, а настройки самих камер вынести во внешние файлы thread, по одному файлу на каждую камеру. Таким образом, не будет никакой путаницы если например камера №2 выйдет из строя и её понадобится заменить на не типичную камеру.

Основные настройки представлены в двух секциях

############################################################
# Daemon
############################################################

# Запуск в фоновом режиме (default: off)
daemon on

# Файл для хранения идентификатора процесса (default: not defined)
process_id_file /var/run/motion/motion.pid
############################################################
# Basic Setup Mode
############################################################

# Запускать в Setup-Mode, отключает режим демона. (default: off)
setup_mode off

# Путь до файла с логами. (default: not defined)
logfile /var/log/motion/motion.log

# Уровель лог сообщений [1..9] (EMR, ALR, CRT, ERR, WRN, NTC, INF, DBG, ALL). (default: 6 / NTC)
log_level 6

# Фильтр лог сообщений по типу (COR, STR, ENC, NET, DBL, EVT, TRK, VID, ALL). (default: ALL)
log_type all

Тут нас интересует только запуск программы в фоновом режиме, остальные настройки можно оставить без изменения.

Далее идет секция настройки первого потока

###########################################################
# Capture device options
############################################################

# Videodevice to be used for capturing  (default /dev/video0)
# for FreeBSD default is /dev/bktr0
;videodevice /dev/video0

...

Закомментируем все настройки в этой секции, в этом файле они нам не нужны.

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

Отключаем создание снимков при обнаружении движения. Можно указать один из режимов (first, best, center) и тогда мы будем получать по одному снимку на одно видео. Это может пригодиться в том случае, если вы собираетесь организовывать WEB доступ к архиву видеозаписей.

############################################################
# Image File Output
############################################################

# Output 'normal' pictures when motion is detected (default: on)
# Valid values: on, off, first, best, center
# When set to 'first', only the first picture of an event is saved.
# Picture with most motion of an event is saved when set to 'best'.
# Picture with motion nearest center of picture is saved when set to 'center'.
# Can be used as preview shot for the corresponding movie.
output_pictures off

Отключаем стриминг по умолчанию

############################################################
# Live Stream Server
############################################################

# The mini-http server listens to this port for requests (default: 0 = disabled)
stream_port 0

Отключаем встроенный web сервер

############################################################
# HTTP Based Control
############################################################

# TCP/IP port for the http server to listen on (default: 0 = disabled)
webcontrol_port 0

В самом конце основного файла конфигурации motion.conf имеется секция для подключения дополнительных потоков. По умолчанию файл motion.conf соответствовал файлу thread0.conf, но мы это доблестно исправили выше. Теперь нам необходимо включить в файл конфигурации файлы с настройками для работы с нашими камерами. Мы рассмотрим на примере конфигурации одной камеры, раскомментируем thread1.conf

##############################################################
# Thread config files - One for each camera.
# Except if only one camera - You only need this config file.
# If you have more than one camera you MUST define one thread
# config file for each camera in addition to this config file.
##############################################################

# Remember: If you have more than one camera you must have one
# thread file for each camera. E.g. 2 cameras requires 3 files:
# This motion.conf file AND thread1.conf and thread2.conf.
# Only put the options that are unique to each camera in the
# thread config files.
thread /etc/motion/thread1.conf
; thread /etc/motion/thread2.conf
; thread /etc/motion/thread3.conf
; thread /etc/motion/thread4.conf

 

Создадим файл thread1.conf

cd /etc/motion && touch thread1.conf && nano thread1.conf

Первым делом вам необходимо узнать:

  • адрес MJPEG потока вашей камеры
  • разрешение камеры (обычно для дешевых камер это 640х480)
  • частоту кадров (у дешевых камер обычно не более 20)
# Разрешение картинки
width 640
height 480

# Частота кадров
framerate 20

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

# Сетевой адрес для захвата изображения с камеры (mjpeg поток)
netcam_url http://10.10.1.101/mjpeg.cgi

# Логин и пароль к видео потоку (only if required). Default: not defined
; netcam_userpass admin:password

Укажем подпись для камеры, это поможет быстро идентификации её местоположение (можно использовать символ перевода каретки)

# Подпись к камере (название камеры)
text_left CAMERA 1\nSH-21 STORAGE

Укажем путь до места хранения видео фрагментов (лучше создать каталог заранее)

# Путь до места сохранения видео\фото
target_dir /media/share/motion/cam1

Включаем детектор движения

# Количество изменившихся пикселей для триггера обнаружения движения
threshold 2000

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

# Не реагировать на резкое изменение яркости (0 - отключено, 0-100% от общего числа пикселей)
lightswitch 60

# Минимальное число кадров, в которых фиксируется движение для взведения триггера тревоги
minimum_motion_frames 5

Добавляем мертвую зону. Она позволит не создавать кучу мусора в папке с видео

# Количество секунд (мертвая зона) после окончания движения, в течении которых отключен детектор
event_gap 10

Для наглядности можно добавить рамку вокруг движущегося объекта. Также рекомендую включить эти параметры на время, пока проходит настройка и обкатка системы

# Рисуем рамку вокруг движущегося объекта
locate_motion_mode on

# Стиль рамки вокруг движущегося объекта
locate_motion_style redbox

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

# Показывать количество изменившихся пикселей (используем для настройки threshold)
text_changes on

Включаем возможность стримить с сервера все происходящее на данной камере

# Настройки потока вещания (порт\качество\частота кадров\доступ только с 172.0.0.1\ограничение потока)
stream_port 8081
stream_quality 70
stream_maxrate 20
stream_localhost off
stream_limit 0

Можно (и нужно, если установлен stream_localhost off) требовать авторизацию при доступе к потоку с этой камеры из вне

# Требовать авторизацию для доступа к потоку вещания
stream_auth_method 1
stream_authentication admin:12345678

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

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

При вызове внешнего скрипта ему можно передать следующие параметры

Скрытый текст

%Y = year
%m = month
%d = date
%H = hour
%M = minute
%S = second,

%v = event
%q = frame number
%t = thread (camera) number
%D = changed pixels
%N = noise level

%i and %J = width and height of motion area
%K and %L = X and Y coordinates of motion center

%C = value defined by text_event
%f = filename with full path
%n = number indicating filetype

# Both %f and %n are only defined for on_picture_save,
# on_movie_start and on_movie_end
# Quotation marks round string are allowed.

 

Добавим строку вызова внешнего исполняемого файла с передачей ему параметрами - номер камеры и координаты центра начала движения

# При обнаружении движения запускать внешний скрипт
on_event_start /etc/motion/zone_alarm.sh %t %K %L

Содержимое zone_alarm.sh

#!/bin/bash

CAM="$1"
X="$2"
Y="$3"

if (("$CAM" == "1"))
then
        if (("$X" < "320" && "$Y" < "240"))
        then
                beep -f 4000 -l 200 -n -f 4000 -l 200 -n -f 4000 -l 200 -n -f 4000 -l 200 -n -f 4000 -l 200
        fi
fi

В данном случае происходит звуковое оповещение на самом сервере с помощью утилиты beep, по умолчанию её может и не быть

apt-get install beep

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

Необходимо разрешить Motion работать в режиме демона, для этого правим файл /etc/default/motion

# set to 'yes' to enable the motion daemon
start_motion_daemon=yes

Проверяем работу

/etc/init.d/motion start

Что мы имеем на выходе

cam6.pngcam7.png

cam4.JPG

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

crontab -e

И добавим запись, которая будет выполняться ежедневно в 23:30 и искать файлы формата .avi в указанном нами каталоге и если найденный файл существует более 14 суток, то он удаляется. Естественно если камера стоит в проходном месте, то стоит уменьшить время жизни видео.

30 23 * * * find /media/share/motion/ -name '*.avi' -mtime +14 -exec rm {} \;

На этом настройка завершена.

PS: в файле motion.conf можно найти еще очень много интересных параметров!

  • Like 1

Share this post


Link to post
Share on other sites

Для того, чтобы motion стартовал автоматически при запуске системы, попробуйте добавить разрешение на запуск юнита в systemd

systemctl enable motion

или

/lib/systemd/systemd-sysv-install enable motion

перезапускаем систему и смотрим вывод

service motion status
Скрытый текст

service motion status
 motion.service - LSB: Start Motion detection
   Loaded: loaded (/etc/init.d/motion; bad; vendor preset: enabled)
   Active: active (running) since Пн 2016-10-17 15:26:47 MSK; 2min 24s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 568 ExecStart=/etc/init.d/motion start (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/motion.service
           └─1324 /usr/bin/motion

окт 17 15:26:46 hostname systemd[1]: Starting LSB: Start Motion detection...
окт 17 15:26:47 hostname motion[568]:  * Starting motion detection daemon motion
окт 17 15:26:47 hostname motion[568]:    ...done.
окт 17 15:26:47 hostname systemd[1]: Started LSB: Start Motion detection.
окт 17 15:26:53 hostname motion[796]: [25567616] [NTC] [ALL] conf_load: Processing thread 0 - config file /etc/motion/motion.conf
окт 17 15:26:53 hostname motion[796]: [25567616] [NTC] [ALL] config_thread: Processing config file /etc/motion/thread1.conf
окт 17 15:26:53 hostname motion[796]: [25567616] [NTC] [ALL] motion_startup: Motion 3.2.12+git20140228 Started with SDL support
окт 17 15:26:53 hostname motion[796]: [25567616] [NTC] [ALL] motion_startup: Logging to file (/var/log/motion/motion.log)

 

 

  • Like 3

Share this post


Link to post
Share on other sites

Debian 10, motion.

Может ли motion работать через видеорегистратор ?

Если да, то как ?

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Similar Content

    • By Kitsum
      Просмотреть файл [esp8266] Библиотека CMD, реализует настройку микроконтроллера и управление вашей программой через терминал.
      Основная задача библиотеки, это прием пользовательских команд через UART интерфейс, их обработка и выполнение пользовательского кода, связанного с той или иной командой.
      Данная библиотека позволяет реализовать:
      Управление микроконтроллером Любую настройку, будь то WiFi, другие библиотеки или часть Вашей программы Вызывать Ваши задачи (функции) из терминала по команде и передавать им требуемые параметры Использовать контроллер в качестве шлюза между датчиками и программами на PC Внимание: любая команда, передаваемая в терминал обязана заканчиваться символом перевода строки "\n".
      Подключение библиотеки
      #include <cmd.h> Инициализация объекта, к которому мы будем обращаться для добавления команд. В качестве параметра объекту необходимо передать указатель на объект Serial или любой другой схожий по типу интерфейс.
      cmd command(&Serial); В функции Setup описываем какие команды требуется обрабатывать. Например, по команде "test" вызывать пользовательскую функцию с именем "myFunctionName". Имя пользовательской функции может быть абсолютно любым.
      void Setup() { Serial.begin(115200); command.add("test", myFunctionName); } Пользовательская функция будет вызываться каждый раз, когда по интерфейсу Serial поступит команда "test". Если команда будет передана с параметрами, то эти параметры будут переданы в качестве аргументов пользовательской функции.
      В функции loop должна находится команда вызова обработчика.
      void loop() { command.handleEvents(); } Пользовательская функция обязана соответствовать ряду требований:
      Не возвращать никакого результата (быть объявленной с типом void) Принимать в качестве первого аргумента переменную с типом byte в которой будет храниться число равное количеству переданных параметров Принимать в качестве второго параметра переменную с типом char** в которой будет храниться указатель на массив со всеми указателями (char*) на переданные параметры void myFunctionName(byte argc, char** argv) { /* ... */ } Функция всегда должна иметь такой вид, даже если не подразумевается, что ей будут передаваться какие-либо параметры.
      Чтобы перебрать все переданные параметры и вывести их в консоль, можно воспользоваться следующим примером
      void myFunctionName(byte argc, char** argv) { if (0 < argc) { for (uint8_t i = 0; i < argc; i++) { Serial.printf("%i. %s\n", i, argv[i]); } } } Пример вызова пользовательской функции без параметров и с ними
      # test No parameter was passed # test p1 p2 p3 p4 p5 0. p1 1. p2 2. p3 3. p4 4. p5 Помните, что параметры представлены в виде указателей и работать с ними нужно как с обычными переменными не получится т.к указатель содержит не значение переменной (переданный параметр), а указатель на ту область памяти микроконтроллера в которой это значение находится.
      Чтобы сравнить два значения, например, параметр под индексом 0 (идет первым в списке) с каким-либо значением в программе, воспользуйтесь функцией strcmp, которая возвращает целочисленное значение, указывающее на лексическое расхождение строк. Если строки равны, то возвращаемое значение равно 0.
      if (!strcmp(argv[0], "wifi")) { Serial.println(F("Первый аргумент WiFi")); } else { Serial.println(F("Первый аргумент НЕ WiFi!!!")); } Для копирования значения указателя в другую переменную с типом char можно воспользоваться функцией strcpy
      char myVar[20]; strcpy(myVar, argv[0]); if (myVar == "123456") { Serial.prinln(F("ok")); } Также можно обернуть указатель объектом String и получить весь функционал этого объекта, который будет содержать значение параметра
      String param1(argv[0]); // String param1 = argv[0]; Serial.printf("argv[0] length: %i\n", param1.length()); Serial.printf("argv[0] is integer?: %s\n", param1.toInt() ? "YES" : "NO"); if (param1 == "qwerty") { Serial.println(F("Hello QWERTY!")); } С библиотекой идут несколько примеров, в том числе и пример конфигурации WiFi в режиме STA.
      Автор Kitsum Добавлен 05.12.2018 Категория Библиотеки  
    • By Kitsum
      Основная задача библиотеки, это прием пользовательских команд через UART интерфейс, их обработка и выполнение пользовательского кода, связанного с той или иной командой.
      Данная библиотека позволяет реализовать:
      Управление микроконтроллером Любую настройку, будь то WiFi, другие библиотеки или часть Вашей программы Вызывать Ваши задачи (функции) из терминала по команде и передавать им требуемые параметры Использовать контроллер в качестве шлюза между датчиками и программами на PC Внимание: любая команда, передаваемая в терминал обязана заканчиваться символом перевода строки "\n".
      Подключение библиотеки
      #include <cmd.h> Инициализация объекта, к которому мы будем обращаться для добавления команд. В качестве параметра объекту необходимо передать указатель на объект Serial или любой другой схожий по типу интерфейс.
      cmd command(&Serial); В функции Setup описываем какие команды требуется обрабатывать. Например, по команде "test" вызывать пользовательскую функцию с именем "myFunctionName". Имя пользовательской функции может быть абсолютно любым.
      void Setup() { Serial.begin(115200); command.add("test", myFunctionName); } Пользовательская функция будет вызываться каждый раз, когда по интерфейсу Serial поступит команда "test". Если команда будет передана с параметрами, то эти параметры будут переданы в качестве аргументов пользовательской функции.
      В функции loop должна находится команда вызова обработчика.
      void loop() { command.handleEvents(); } Пользовательская функция обязана соответствовать ряду требований:
      Не возвращать никакого результата (быть объявленной с типом void) Принимать в качестве первого аргумента переменную с типом byte в которой будет храниться число равное количеству переданных параметров Принимать в качестве второго параметра переменную с типом char** в которой будет храниться указатель на массив со всеми указателями (char*) на переданные параметры void myFunctionName(byte argc, char** argv) { /* ... */ } Функция всегда должна иметь такой вид, даже если не подразумевается, что ей будут передаваться какие-либо параметры.
      Чтобы перебрать все переданные параметры и вывести их в консоль, можно воспользоваться следующим примером
      void myFunctionName(byte argc, char** argv) { if (0 < argc) { for (uint8_t i = 0; i < argc; i++) { Serial.printf("%i. %s\n", i, argv[i]); } } } Пример вызова пользовательской функции без параметров и с ними
      # test No parameter was passed # test p1 p2 p3 p4 p5 0. p1 1. p2 2. p3 3. p4 4. p5 Помните, что параметры представлены в виде указателей и работать с ними нужно как с обычными переменными не получится т.к указатель содержит не значение переменной (переданный параметр), а указатель на ту область памяти микроконтроллера в которой это значение находится.
      Чтобы сравнить два значения, например, параметр под индексом 0 (идет первым в списке) с каким-либо значением в программе, воспользуйтесь функцией strcmp, которая возвращает целочисленное значение, указывающее на лексическое расхождение строк. Если строки равны, то возвращаемое значение равно 0.
      if (!strcmp(argv[0], "wifi")) { Serial.println(F("Первый аргумент WiFi")); } else { Serial.println(F("Первый аргумент НЕ WiFi!!!")); } Для копирования значения указателя в другую переменную с типом char можно воспользоваться функцией strcpy
      char myVar[20]; strcpy(myVar, argv[0]); if (myVar == "123456") { Serial.prinln(F("ok")); } Также можно обернуть указатель объектом String и получить весь функционал этого объекта, который будет содержать значение параметра
      String param1(argv[0]); // String param1 = argv[0]; Serial.printf("argv[0] length: %i\n", param1.length()); Serial.printf("argv[0] is integer?: %s\n", param1.toInt() ? "YES" : "NO"); if (param1 == "qwerty") { Serial.println(F("Hello QWERTY!")); } С библиотекой идут несколько примеров, в том числе и пример конфигурации WiFi в режиме STA.
    • By Kitsum
      Данную тему не поднимал только ленивый. По существу все просто и очень подробно описано в первоисточнике https://github.com/esp8266/Arduino
      Скачиваем Arduino IDE с официального сайта Запускаем Arduino и открываем окно настроек (Файл -> Настройки) В поле "Дополнительные ссылки для Менеджера плат:" указываем адрес  http://arduino.esp8266.com/stable/package_esp8266com_index.json Открываем менеджер плат (Инструменты -> Список плат -> Менеджер плат) и в качестве фильтра поиска указываем "esp8266". И жмем кнопку установить. В списке поддерживаемых плат появится ESP8266 в различных вариациях. Все необходимые файлы для поддержки работы с этим микроконтроллером и дополнительные библиотеки с примерами их работы будут закачаны в каталог %APPDATA%\Arduino15\
      Подключение ESP8266 для загрузки скетча
      В сети множество схем для подключения всех разновидностей ESP, от ESP-01 до ESP-12, но нужно понимать, что как бы они не назывались и не выглядели, собраны они на одном микроконтроллере ESP8266EX, следовательно, подключаются они все одинаково за исключением того момента, что если у ESP не выведена та или иная нога (например, ESP-01), то и искать, и подключать её не требуется. Достаточно знать, как подключить ESP-12 и Вы сможете завести и прошить любой тип ESP.
      Предлагаю использовать схему подключения с автоматическим сбросом и переводом микроконтроллера в режим загрузки программы. Главное, что понадобится - USB-TTL конвертер с выведенными ногами DTR и RTS. Я использовал конвертер на базе FT232RL.

      Если вы собираетесь использовать deepSleep(), то необходимо обязательно подтянуть GPIO-16 к RESET через резистор 470 Ом.
      И так, что тут к чему
      RTS - Запрос на передачу (Request to Send) DTR - Готовность приемника данных (Data Terminal Ready) Во время загрузки скетча транзистор T1 откроется и подтянет GPIO-0 к земле, в это время конденсатор C1 перезарядится и тем самым нога RESET кратковременно окажется подтянута к земле, что приведет к перезагрузке микроконтроллера и загрузке программы. Также благодаря конденсатору C1 мы будем перезапускать микроконтроллер каждый раз, при открытии монитора порта (как при использовании обычной Arduino UNO и т.п).
      Подведем итоги
      Лично мое мнение, что на базе ESP8266 стоит брать только ESP-07 или ESP-12 с переходной платой под отверстия 2,54мм, чтобы можно было установить модуль в макетную плату. Таким образом, за туже цену мы получаем микроконтроллер с максимальным количеством выведенных для нас ног и возможностью быстрого монтажа для экспериментов с разными поделками.

       
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...