Около полугода назад мне достался миниатюрный видеосервер, применение которому я нашёл в арендуемом для мотоцикла гараже, где он всё это время благополучно работал в связке с двумя китайскими NoName IP-камерами, худо-бедно поддерживающими ONVIF, и 3G-модемом, что позволяло мне удалённо посмотреть видео с камер при оповещениях о детекции движения, к счастью совпадавшими пока только с моим приходом в гараж. Не дал этому микросерверу спокойно работать дальше я сам, так как, ещё когда только получил его в руки, из любопытства разобрал и неожиданно для себя обнаружил, что построен он на одноплатнике Orange Pi PC, который незадолго до этого, благодаря низкой цене, широко освещался в интернете, в том числе и на Geektimes, поэтому я примерно представлял его возможности.
Собственно, спустя полгода использования, в дополнение к основным функциям видеосервера мне захотелось задействовать гребёнку GPIO на его борту для подключения датчика дыма, датчика открытия двери и реле для включения сирены. Самым интересным и, на мой взгляд, сложным этапом этого хобби-проекта, я решил поделиться с сообществом, надеясь получить советы по дальнейшему развитию. Внимание: описанные дальше действия, скорее всего, лишили меня гарантии на устройство, я производил их на свой страх и риск и привожу лишь как пищу для ума, но не руководство к действию.
Исследование прошивки
Первым делом, в надежде, что видеосервер использует полноценный дистрибутив, я попробовал подключить монитор и клавиатуру к плате, но никакого сигнала на выходе HDMI не было, похоже, порт просто никак не задействован в прошивке, о чём, впрочем, и говорят разработчики, заявляя, что это устройство класса MicroNVR (Network Video Recorder), не подразумевающее никакого взаимодействия пользователя с сервером, кроме удалённого доступа. Вторая цель — ssh, порт которого на устройстве открыт, но сервер поддерживает только авторизацию по ключу, который мне никак раздобыть не удалось.
К счастью для меня, устройство базируется на той версии одноплатника, которая идёт без eMMC, и загрузка осуществляется с обычной MicroSD-карты, выступающей с торца платы. Собственно, всё что нужно для получения доступа к содержимому прошивки — вставить карту в кардридер. На 8Gb SanDisk'е расположено 3 раздела:
/dev/sdb1 on /media/user/disk type squashfs
/dev/sdb2 on /media/user/UBOOT type vfat
/dev/sdb3 on /media/user/07836191-ddf8-45ab-b02b-1103320c2e5b type ext4
Размеры разделов:
/dev/sdb1 25M 25M 0 100% /media/user/disk
/dev/sdb2 16M 2.2M 14M 14% /media/user/UBOOT
/dev/sdb3 58M 9.4M 45M 18% /media/user/07836191-ddf8-45ab-b02b-1103320c2e5b
Раздел «UBOOT», судя по всему, используется только загрузчиком U-Boot. Раздел с ext4 содержит логи (/log) основных подсистем (kern, lighttpd, line, netcfgd, syslog) и настройки сервервера видеонаблюдения, доступные изменению пользователем (/lib/line). А на разделе «disk» со squashfs (compressed read-only) расположены уже все файлы ОС и программ. Получается, операционная система и логическая часть со всеми «Аналитиками» и «Облаками» умещена разработчиками в 25 Мб, что совпадает с размером обновлений на их сайте, т.е. заменяется вся прошивка целиком, а не только ПО видеонаблюдения.
Основной раздел содержит привычный набор директорий:
bin dev factory media root sbin tmp var
boot etc lib proc run sys usr
В целом, ничего необычного в дереве каталогов нет, всё на своих местах. Запускаемые runit-сервисы лежат в /etc/service:
dropbear hwclock-fix lighttpd line netcfgd socklog-klog socklog-unix
Увидев в списке lighttpd, я решил проверить, смогу ли использовать его для своих целей. Запускается он с конфигурацией:
server.modules += ( "mod_cgi" )
$SERVER["socket"] == ":19587" {
include_shell "/usr/share/adm/lighttpd-gencert"
server.document-root = "/usr/share/adm/www"
cgi.execute-x-only = "enable"
cgi.assign = ( "" => "" )
}
Содержимое /usr/share/adm/www:
datetime firmware password profiles sysinfo timezones
factory-reset locale profile settings timezone
По набору скриптов понятно, что HTTP-сервер предоставляет возможности для утилиты, позволяющей изменить системные настройки устройства и обновить прошивку, получается, всё это можно сделать и без её участия по протоколу HTTP. Например, получить архив со сведениями о системе можно и через браузер:
https://192.168.1.2:19587/sysinfo
Сервер использует генерируемый самоподписанный сертификат и стандартную авторизацию с возможностью поменять пароль (на устройстве хранится только хэш). Готовый HTTPS-сервер с авторизацией и очень простой возможностью добавить свой скрипт сэкономил мне кучу времени и я приступил непосредственно к GPIO.
Доработка прошивки
Простой запрос в гугле «Orange Pi PC GPIO» сразу вывел меня на команды:
echo 0 > /sys/class/gpio_sw/PA1/data
echo 1 > /sys/class/gpio_sw/PA1/data
Найти имена портов тоже не было проблемой:
Посмотрев на имеющиеся скрипты, я создал по их примеру новый с именем alarm и содержимым:
#!/bin/sh
set -e
. ../lib/devline/http.sh
. ../lib/devline/auth.sh
is_auth || http_err_unauth
[ "$REQUEST_METHOD" = "PUT" ] || http_err_method PUT
value="$(head -c "$CONTENT_LENGTH" | tr -d '.')"
echo $value > /sys/class/gpio_sw/PA3/data
echo "Content-Type: text/plain"
echo
echo OK
Обновление прошивки
Мне оставалось только добавить новый файл на устройство, что нельзя сделать обычным копированием, т.к. целевая файловая система работает только на чтение. Наверное, существуют разные способы внесения изменения в squashfs, но я пошёл самым простым, на мой взгляд. Первым делом я считал образ раздела в файл:
dd if=/dev/sdb2 of=sdb2.img
Затем распаковал squashfs в обычную директорию:
unsquashfs sdb2.img
Скопировал скрипт alarm по нужному пути в squashfs-root и собрал из неё новый squashfs образ:
mksquashfs squashfs-root sdb2-new.img
Который потом залил обратно на флешку:
dd if=sdb2-new.img of=/dev/sdb2
Итог
На данный момент я могу по защищённому каналу замкнуть реле:
curl -X PUT -k --data '1' https://admin:j3ks92ls8f@192.168.1.2:19587/alarm
и разомкнуть его:
curl -X PUT -k --data '0' https://admin:j3ks92ls8f@192.168.1.2:19587/alarm
По большому счёту, лично для меня это было просто оценкой технической возможности реализации задумки. Оценка положительная: у меня есть доступ к портам ввода-вывода и я могу добавить свою логику в прошивку устройства. Бонусом я получил готовый к использованию HTTPS-сервер.
По моему мнению, это была самая интересная часть разработки, дальше по большей части остаётся только рутина, и я не уверен закончу ли всё задуманное в полном объёме. В любом случае, если кто-то решит повторить что-то подобное, вот пара идей по дальнейшему развитию текущего результата:
- Написать скрипт службы, которая будет отслеживать состояние входов с датчиками и реагировать на сработку (оповещать, включать сирену). Тут всё понятно, сложностей ни со службой ни с оповещением не предвидится, даже исполняемый файл curl уже есть на устройстве, т.е. для оповещений есть несколько вариантов: SMTP и получение сообщений по IMAP, готовые сервисы отправки SMS, свой сервер;
- Добиться работы через интернет без прямого IP-адреса. Дело в том, что через облако работает только основной софт видеосервера, а lighttp-сервер, реализующий системные настройки, доступен только прямо, что, конечно, не плохо само себе. По этому пункту я не так уверен в простоте реализации, мои идеи пока ограничиваются двумя вариантами: ssh-тунель (надо добавить свой публичный ключ на устройство) или свой сервер и long polling со стороны устройства.
Буду благодарен за ваши идеи.
Автор: motorcycle
Можно попробовать поднять ipv6 тунель на какой нибудь брокер, и будет доступ отовсюду!