Интеграция китайских xmey, iCSee и прочих с Home Assistant

Есть у меня несколько камер этого OEM вендора

Чем они хороши?

  • Цена, в первую очередь. Я покупал что-то в районе 2500р за 5М камеру с ИК и LED подсветкой
  • Неплохое качество картинки
  • Есть возможность зашить открытую прошивку с линуксом и ssh консолью (не делал)

Чем плохи?

  • NVR вендор сомнительной безопасности (были прецеденты)
  • Немного закрытый софт

Что я реализовал при работе с HomeAssistant

  1. Получение видеопотока, ну тут все из коробки
  2. Получение фотки с камеры не из видеопотока а средствами самой камеры
  3. Изменение настроек камеры из HA
  4. Получение событий из камеры по приетарному протоколу

На 1 пункте не вижу смысла останавливаться
Сейчас распишу 2 и 3, а потом 4

Итак, что нам понадобится

  1. Создать пользователя в камере, дать ему базовые права
  2. HomeAssistant
  3. Желательно поставить vscode аддон - для удобного редактирования файлов
  4. HACS расширение - для установки расширения

Шаги

  1. Устанавливаем hacs расширение pyscript + добавляем его в интеграции - для того, чтобы можно было писать свои скрипты на python
  2. в файл secrets.yaml добавляем креды от камеры
camera_user: assistant
camera_password: redacted
  1. создаем каталог pyscript в корневом каталоге homeassistant
  2. внутри создаем файл requirements.txt со следующим содержимым
python-dvr
  1. создаем файл shell_scripts/camera_take_snapshot.py со следующим содержимым
import sys
from dvrip import DVRIPCam
import yaml
with open("secrets.yaml", "r", encoding="utf-8") as f:
    config = yaml.safe_load(f)
target=sys.argv[1]
filename=sys.argv[2]
cam = DVRIPCam(target, user=config["camera_user"], password=config["camera_password"])
cam.login()
with open(filename, "wb") as f:
    f.write(cam.snapshot())
cam.close()
  1. создаем файл pyscript/set_camera_dn_mode.py со следующим содержимым
@service
def set_camera_dn_mode(target=None, mode=None):
    log.info(f"set_camera_dn_mode: got target {target} mode {mode}")
    from dvrip import DVRIPCam
    mport yaml
    with open("../secrets.yaml", "r", encoding="utf-8") as f:
        config = yaml.safe_load(f)
    cam = DVRIPCam(target, user=config["camera_user"], password=config["camera_password"])
    if cam.login():
        log.info("Success! Connected to " + target)
    else:
        log.warning("set_camera_dn_mode: Could not connect to "+target)
    cam.set_info("Camera.Param.[0]", { "DayNightColor" : "0x0000000" + str(mode)})
    cam.close()
  1. Добавляем shell_command
camera_take_snapshot: "python3 shell_scripts/camera_take_snapshot.py {{target}} {{filename}}"
  1. Не помню уже, но возможно, что перезагружаем HomeAssistant

Должно получиться так

  1. Вызываем сервис создания фотки
data:
  target: 10.50.0.12
  filename: www/test.jpeg
action: shell_command.camera_take_snapshot

  1. Открываем картинку в браузере https://homeassistant.domain.com/local/test.jpeg

Вызываем действие смены режима день/ночь

data:
  target: 10.50.0.12
  mode: 4
action: pyscript.set_camera_dn_mode

Mode соответствует порядковому номеру в настройках камеры

Замечания

  1. Изначально делал скачивание картинок в pyscript, но там нет доступа к ФС, в итоге пришлось сделать обертку над shell командой и вызывать отдельным процессом
  2. Поскольку, это модуль внутри HA, то модули из pyscript/requirements.txt доступны из в консоли
  3. Я еще пробовал заводить выпадающий список для управления из UI, но забил т.к. у меня из автоматизации вызывается
  4. Конкретно режим день/ночь у меня используется т.к. камеры имеют и ИК и белую подсветку, я сделал так, что при снятии сигнализации с охраны включается режим с ИК подсветкой т.к. вечером не очень приятно, когда ты подходишь к камере, а она начинает светить на тебя встроенным прожектором, а когда включается охрана камеры переводятся в режим с прожектором
1 лайк

Ну и расскажу, как получать события движения и не только в HA

Что потребуется

  1. Node-RED
  2. Модуль node-red node-red-contrib-home-assistant-websocket для связи с HA

Настройка камеры


Тут мы указываем IP Node-RED и порт 15002, это стандартный порт для Alarm сервера

При наступлении события камера отправляет на указанный адрес TCP сообщение с некоторой оберткой и после обработки получаем что-то типа такого

{
  "Address": "0x0000000A", // Уникальный ID устройства, если у вас несколько камер, то можно разделять сообщения от них
  "Channel": 0, // Канал видео? особо не надо
  "Descrip": "2023-07-03 01:08:55 [admin]LogOut,admin,DVRIP-Web:192.168.0.1\n", // Текст сообщения, но нам это не надо
  "Event": "HumanDetect", // Тип события
  "SerialID": "1753f1b9ef56e877", // Серийный номер чего-то
  "StartTime": "2023-07-03 01:08:55", // Время сообщения
  "Status": "Start", // Действие, для движения это Start в начале движения и Stop в конце
  "Type": "Log" // Тип сообщения, на не надо
}

В Node-RED создается вот такая штука

Код для вставки
[{"id":"399975518a531e8a","type":"tab","label":"Cameras","disabled":false,"info":"","env":[]},{"id":"1be1fe0728cccff9","type":"tcp in","z":"399975518a531e8a","name":"","server":"server","host":"","port":"15002","datamode":"single","datatype":"utf8","newline":"\\n","topic":"","base64":false,"x":80,"y":200,"wires":[["c3a4b57664e8cbe2"]]},{"id":"13b8d6a57d68b6c7","type":"json","z":"399975518a531e8a","name":"","property":"payload","action":"","pretty":false,"x":390,"y":200,"wires":[["3fedc9767ceec12c","ea1c7436a1793ccc"]]},{"id":"c3a4b57664e8cbe2","type":"string","z":"399975518a531e8a","name":"Parse","methods":[{"name":"between","params":[{"type":"str","value":"{"},{"type":"str","value":"}"}]},{"name":"ensureLeft","params":[{"type":"str","value":"{"}]},{"name":"ensureRight","params":[{"type":"str","value":"}"}]}],"prop":"payload","propout":"payload","object":"msg","objectout":"msg","x":230.8328857421875,"y":199.3395004272461,"wires":[["13b8d6a57d68b6c7"]]},{"id":"3fedc9767ceec12c","type":"debug","z":"399975518a531e8a","name":"debug 10","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":560,"y":260,"wires":[]},{"id":"5b09ed59aa79192f","type":"ha-binary-sensor","z":"399975518a531e8a","name":"Boolean Sensor","entityConfig":"","version":0,"state":"payload","stateType":"msg","attributes":[],"inputOverride":"allow","outputProperties":[],"x":1660,"y":160,"wires":[[]]},{"id":"75a96470dc015720","type":"switch","z":"399975518a531e8a","name":"Switch Event","property":"payload.Event","propertyType":"msg","rules":[{"t":"eq","v":"HumanDetect","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":750,"y":200,"wires":[["cee2eb3f1dc64e03"]]},{"id":"4d6b64cfe37a024d","type":"inject","z":"399975518a531e8a","name":"Motion Start","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"Address\":\"0x0000000A\",\"Channel\":0,\"Descrip\":\"2023-07-03 01:08:55 [admin]LogOut,admin,DVRIP-Web:10.110.0.139\\n\",\"Event\":\"HumanDetect\",\"SerialID\":\"1753f1b9ef56e877\",\"StartTime\":\"2023-07-03 01:08:55\",\"Status\":\"Start\",\"Type\":\"Log\"}","payloadType":"json","x":350,"y":100,"wires":[["ea1c7436a1793ccc"]]},{"id":"213a722df19c0016","type":"switch","z":"399975518a531e8a","name":"Switch Camera","property":"event.Address","propertyType":"msg","rules":[{"t":"eq","v":"0x0000000A","vt":"str"},{"t":"eq","v":"0x0000000B","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":1440,"y":200,"wires":[["5b09ed59aa79192f"],[]]},{"id":"cee2eb3f1dc64e03","type":"switch","z":"399975518a531e8a","name":"Switch Status","property":"payload.Status","propertyType":"msg","rules":[{"t":"eq","v":"Start","vt":"str"},{"t":"eq","v":"Stop","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":940,"y":200,"wires":[["5297f3c9a649ecad"],["f021b8b498aadfef"]]},{"id":"5297f3c9a649ecad","type":"change","z":"399975518a531e8a","name":"Set Sensor to On","rules":[{"t":"set","p":"payload","pt":"msg","to":"on","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1170,"y":180,"wires":[["213a722df19c0016"]]},{"id":"ea1c7436a1793ccc","type":"change","z":"399975518a531e8a","name":"Save Event","rules":[{"t":"set","p":"event","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":550,"y":200,"wires":[["75a96470dc015720"]]},{"id":"f021b8b498aadfef","type":"change","z":"399975518a531e8a","name":"Set Sensor to Off","rules":[{"t":"set","p":"payload","pt":"msg","to":"off","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1170,"y":240,"wires":[["213a722df19c0016"]]},{"id":"5c2ddaf3e08d10db","type":"inject","z":"399975518a531e8a","name":"Motion End","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"Address\":\"0x0C00320A\",\"Channel\":0,\"Descrip\":\"2023-07-03 01:08:55 [admin]LogOut,admin,DVRIP-Web:10.110.0.139\\n\",\"Event\":\"HumanDetect\",\"SerialID\":\"1753f1b9ef56e877\",\"StartTime\":\"2023-07-03 01:08:55\",\"Status\":\"Stop\",\"Type\":\"Log\"}","payloadType":"json","x":350,"y":140,"wires":[["ea1c7436a1793ccc"]]}]
1 лайк

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

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

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

я менял кондеры на POE плате, года через 2 камеры начали отваливаться. Благо, при наличии паяльника и прямых рук цена вопроса у меня вышла что-то в районе 150р за 5 камер.

Ну вот я пообщался с ребятами в сообществе и решил пока остаться на родном регике. Перепрошивке есть смысл если надо какие-то автоматизации делать, стримить хитро и использовать что-то типа Frigate NVR.

  • В офисе у меня регик их и камеры, пока ни времени ни желания нет заморачиваться с ними (работает и ладно)
  • Дома frigate, я думал прикупить пару камер, или вот этих китайских и перепрошить на openipc (без возможности возврата на оригинальную прошивку) или что-то нормальное типа reolink
1 лайк