Что делает модуль

Модуль держит одно постоянное HTTP-соединение со звонком Imou DB61i (CGI eventManager.cgi, Digest-авторизация), записывает каждое событие в журнал, вызывает ваш обработчик и отдаёт фото и видео с SD-карты через панель MajorDoMo. Облако Imou не нужно, достаточно локальной сети и пароля устройства.

Настройка

  1. Включите в роутере постоянный IP-адрес для звонка и укажите его на вкладке «Настройки».
  2. Логин обычно admin. Пароль — пароль устройства, тот же, что для CGI и RTSP (см. ниже).
  3. Нажмите «Проверить подключение»: модуль сделает один CGI-запрос и покажет модель, прошивку, серийный номер и время устройства.
  4. Статус слушателя обновляется сам. «Подключено» и свежая «последняя активность» (heartbeat каждые 5 секунд) означают, что события принимаются.

Пароль устройства нужен для локального доступа по CGI и RTSP (логин admin). Его задают и меняют в Imou Life: настройки звонка → имя устройства → «Пароль устройства»; на некоторых устройствах — в приложении Dahua DMSS. Если команда curl из раздела «Проверка» ниже и скачивание видео работают с каким-то паролем — это он.

Security Code — другое значение, его модулю указывать не нужно. Это код проверки устройства: Imou Life → звонок → меню «⋮» → «Об устройстве» → изображение устройства → экран с QR-кодом самого устройства. На прошивке 1.000.0000003.1.R он служил паролем ONVIF и может не совпадать с паролем устройства.

Неверный пароль. Звонок блокирует учётную запись после нескольких неудачных попыток, поэтому при ошибке 401 модуль ждёт 5, затем 15, затем 30 минут. Сохранение настроек сразу запускает новую попытку.

Обработчик событий

Обработчик вызывается для каждого нового события сразу после записи в журнал, включая незнакомые коды. Он выполняется отдельным запросом к /api.php (как обработчики MQTT), поэтому долгий или упавший код не мешает приёму событий. Состояние каждого вызова видно в журнале, ошибки — в карточке события и на вкладке «Диагностика».

$params = array(
    'id'          => 418,                       // ID записи журнала
    'code'        => 'AlarmLocal',              // Code из сообщения камеры
    'action'      => 'Start',
    'index'       => 0,                         // int или null
    'received_at' => '2026-11-05T23:21:02.264+03:00',
    'device_time' => null,                      // время устройства, если оно есть в data
    'fields'      => array('Code' => 'AlarmLocal', 'action' => 'Start', 'index' => '0'),
    'data'        => null,                      // декодированный data (массив) или null
    'data_error'  => null,                      // текст ошибки, если data не разобрался как JSON
    'raw'         => 'Code=AlarmLocal;action=Start;index=0',
    'media'       => array(),                   // файлы, известные к моменту вызова
);

Для NewFile с допустимым путём media содержит запись вида array('id' => 7, 'event_id' => 419, 'type' => 'jpg', 'size' => 32879, 'path' => '/mnt/sd/…', 'start' => …, 'end' => …, 'preview_url' => '/admin.php?…', 'download_url' => '/admin.php?…'). Если видео уверенно сопоставлено со звонком (интервал записи в имени файла содержит ровно одно нажатие), добавляется 'call' => array('event_id' => 418, 'match' => 'interval'). Ссылки открываются только в браузере с доступом к панели. Пароль устройства в массив никогда не попадает.

Нажатие кнопки — это AlarmLocal / Start / index=0, отпускание через ~10 секунд — AlarmLocal / Stop. NewFile приходит и при движении, поэтому он не является признаком звонка. Первый JPEG обычно появляется через ~1 секунду после нажатия, MP4 — примерно через минуту, после окончания записи. Обработчик AlarmLocal Start не вызывается повторно, когда появляются файлы.

Пример PHP-кода (объект Doorbell здесь только для примера):

if ($event['code'] === 'AlarmLocal' && $event['index'] === 0) {
    if ($event['action'] === 'Start') {
        setGlobal('Doorbell.call', 1);
    } elseif ($event['action'] === 'Stop') {
        setGlobal('Doorbell.call', 0);
    }
}

Отправить первое фото после звонка, например в Telegram, можно так:

if ($event['code'] === 'NewFile' && !empty($event['media']) && $event['media'][0]['type'] === 'jpg') {
    include_once(DIR_MODULES . 'imou_doorbell/imou_doorbell.class.php');
    $doorbell = new imou_doorbell();
    $file = ROOT . 'cms/cached/doorbell_' . $event['media'][0]['id'] . '.jpg';
    if ($doorbell->fetchMediaToFile($event['media'][0]['id'], $file)) {
        // ... отправить $file, затем удалить: unlink($file);
    }
}

Ошибки в методах объектов MajorDoMo, выброшенные как Exception, ядро перехватывает само и записывает в «Системные ошибки»; остальные ошибки и предупреждения попадают в «Диагностику» модуля.

Перенос существующей автоматизации

Если свойство вроде Doorbell.call уже обновляется из ONVIF, облачного вебхука или другого модуля, отвяжите старый источник вручную, иначе один звонок запустит сценарий дважды.

Фото и видео

Модуль хранит только метаданные. Файл при просмотре запрашивается у звонка (RPC_Loadfile) и передаётся в браузер потоком, на диск MajorDoMo он не записывается. Видео поддерживает перемотку (Range). Если браузер не воспроизводит кодек, используйте «Скачать». Когда камера удаляет или перезаписывает файл, ссылка показывает понятное сообщение. Ссылки работают только для пользователей панели.

Прямой эфир

На вкладке «Эфир» показаны RTSP-ссылки без пароля: основной поток, дополнительный поток и альтернативный путь дополнительного потока, который нужен на некоторых прошивках. Кнопка «Проверить RTSP» с сервера определяет, какие пути отвечают. Логин и пароль вводятся в самом плеере (VLC и т. п.).

Браузеры не воспроизводят RTSP, поэтому на вкладке показывается текущий снимок с камеры (snapshot.cgi), который модуль запрашивает на сервере и передаёт потоком. Его можно обновлять вручную или раз в пару секунд. Видео в реальном времени — по RTSP-ссылке во внешнем плеере.

Журнал и очистка

Heartbeat от звонка (каждые 5 секунд) в журнал не пишется — он только обновляет «последнюю активность». Служебные события, которые вам не нужны (например, RtspSessionState и RtspSessionDisconnect, когда к звонку подключается RTSP-плеер), можно перечислить в поле «Не записывать коды»: такие события не попадают в журнал и не передаются обработчику.

Записи старше заданного срока (по умолчанию 3 дня) удаляются раз в час вместе с их медиаданными и связями. Файлы на SD-карте не трогаются — ими управляет камера. Кнопка «Очистить сейчас» на вкладке «Диагностика» запускает очистку немедленно.

Проверка на живом устройстве

  1. Пройдите перед камерой — в журнале появятся VideoMotion / VideoMotionInfo и, возможно, NewFile.
  2. Нажмите кнопку — появятся AlarmLocal Start и через ~10 секунд AlarmLocal Stop (строки подсвечены).
  3. Откройте карточку звонка: исходное тело, поля, статус обработчика, найденные по времени фото; через минуту — видео.
  4. Проверка потока событий вручную (пароль будет запрошен):
    curl --digest --user admin --globoff --no-buffer --max-time 60 \
      'http://IP_ЗВОНКА/cgi-bin/eventManager.cgi?action=attach&codes=[All]&heartbeat=5'