14 мая 2014 г.

Видеонаблюдение

Продолжим. Ну какой умный дом без видео наблюдения?

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

Тем не менее, я выбрал аналоговый вариант с регистратором. Что такое регистратор - по-простому это коробочка для подключения аналоговых камер и микрофонов, с линуксом внутри, что обычно подразумевает возможность подключить sata диск и записывать на него, а также подразумевает наличие ethernet порта, с различными сетевыми возможностями - записью на ftp, samba сервер или даже облако (китайское), возможность просмотра камер с доступом через определенный порт (rtsp) и т.д. Возможностей обычно много - например тот же ntp клиент, dynDns и прочее.



У меня выбор пал на следующий регистратор. Сложно понять, что это за фирма и модель, тем не менее присутствие 960H подкупило. Хотя вот кстати его шильдик:



К сожалению, я не нашел возможность конфигурирования через веб-интерфейс (только просмотр с activex плагином). Конфигурировать возможно только непосредственно подключив мышь и монитор к регистратору или используя программу CMS (только под Windows), идущую на диске с регистратором (что говорит нам о том, что api управления есть - есть и конфигурация порта управления в настройках).

Дальнейшее разбирательство привело к следующим данным. Регистратор на основе hi3520d с такой начинкой:

[root@registrator custom]$ cat ProductDefinition
{
   "Vendor" : "General",
   "Hardware" : "MBD6704T-E",
   "PackSize" : 17408,
   "PreRecSize" : 2048,
   "LogoArea" : {"Begin": "0xe80000", "End": "0xec0000"}
}

[root@registrator custom]$ cat /proc/cpuinfo
Processor       : ARMv7 Processor rev 1 (v7l)
BogoMIPS        : 1318.91
Features        : swp half thumb fastmult edsp
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x4
CPU part        : 0xc09
CPU revision    : 1

Hardware        : hi3520d
Revision        : 0000
Serial          : 0000000000000000


Пароль для доступа через telnet к устройствам с таким контроллером xc3511. В принципе, там делать особо нечего, если не требуется каких-то сугубо специфических действий. Конфигурирование через telnet уж тем более на ваш страх и риск - не стоит там что либо править, если вы не уверены в своих действиях.

Это место в посты было переписано три раза :) Один раз кусок стер блогспот, второй раз я стер сам часто про то как я делал из rtsp jpeg. Провозившись три недели я все таки пришел к общему знаменателю вывода rtsp в веб для показа видео. И это связка - ffmpeg, nginx и nginx-rtmp. Для html5 в данный момент надо поддерживать целый зоопарк различно закодированных потоков. Это накладно для простых файлов, а для живого вещания вообще кошмар.

Как установить рассказывать не буду - вот хотя бы пример. Могу добавить, что для использования модуля надо пересобирать весь nginx целиком. Плюс добавлю, что после компиляции я создаю пакет и ставлю его:
/usr/src/nginx/nginx-1.5.9# checkinstall -D --install=no
/usr/src/nginx/nginx-1.5.9# dpkg -i nginx_1.5.9-1_amd64.deb


Дальше идем на https://github.com/arut/nginx-rtmp-module/ и читаем документацию. Пишем конфигурацию примерно такого содержания:

rtmp {

    max_connections 50;

    server {
 notify_method get;
        listen 1935;
        application cams {
            live on;
            allow publish 127.0.0.1;
            allow publish 192.168.0.0/24;
     deny publish all;
     exec_static ffmpeg -i "rtsp://ipregistrator:554/user=myuser&password=mypasswd&channel=1&stream=1.sdp" -c:v copy -profile:v baseline -c:a copy -f flv rtmp://localhost/cams/stream;
     exec_static ffmpeg -i "rtsp://ipregistrator:554/user=myuser&password=mypasswd&channel=2&stream=1.sdp" -c:v copy -profile:v baseline -c:a copy -f flv rtmp://localhost/cams/stream2;
 }

    }
}


Замечу, что exec_static выполняется при запуске nginx (ffmpeg забирает rtsp поток с регистратора и конвертирует в flv без перекодирования) , что очень удобно, не надо писать никаких дополнительных скриптов для запуска клиента.

Далее настраиваем flash плеер (uppod, flowplayer или др.) на html странице с адресом вида rtmp://server/cams/stream . В openhab с добавил Webview sitemap и в итоге у нас вышло нечто вроде:



Повесил китайский планшет на стену - openhab теперь используется в виде видеоглазка. Регистратор записывает видео при обнаружении движения (настройка довольно таки не тривиальная, но можно поиcкать инструкцию к программе cms на русском, такая существует.

В будущем планирую видео записывать в облако mail.ru, благо там получен 1 террабайт.

5 февраля 2014 г.

Управление и оповещение через jabber в openHAB

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

Я решил оповещения сделать на основе jabber, тем более, что данный вариант позволяет даже управлять openHABом из jabber. Создаем учетную запись (xmpp или jabber). Ищем секцию xmpp в openhab.cfg. Прописываем сервер, логин, пароль.
Отправляем команду help:

(15:22:48) I: help
(15:22:49) my****@jabber.org: Usage: 
update ⟨item⟩ ⟨state⟩ - sends a status update for an item
send ⟨item⟩ ⟨command⟩ - sends a command for an item
status ⟨item⟩ - shows the current status of an item
items [⟨pattern⟩] - lists names and types of all items matching the pattern
say ⟨sentence to say⟩ - Says a message through TTS on the host machine
⟩ ⟨script to execute⟩ - Executes a script


Теперь разберемся, как нам послать сообщение о смене статуса открытого замка. Для этого просто создадим новое правило в home.rules:

rule "Door Check Lock Send"
when
        Item Main_Door_Lock changed
then
        if(Main_Door_Lock.state==1)
        {
            sendXMPP("jabber@jabber.org", "Замок двери открыт!")
        }
        else if(Main_Door_Lock.state==0)
        {
            sendXMPP("jabber@jabber.org", "Замок двери закрыт!")
        }
        else{
            sendXMPP("jabber@jabber.org", "Неполадки с датчиком замка двери!")
        }
end


Очень помогает в написании правил функция авто-дополнения в дизайнере (Ctrl+Space), ибо документация по этому поводу хромает.

Поэкспериментировав понимаем, что время отклика оставляет желать лучшего. Смотрим лог owfs - датчик опрашивается openHAB'ом раз в минуту - это как раз настройка в openHAB. К сожалению на данный момент время обновления едино для всех датчиков 1-wire в openHAB. Поэтому ничего не остается, как сменить частоту обновления хотя бы на раз в 10 секунд.

Кеш owfs для датчиков по умолчанию 15 секунд. Поэтому, чтобы получать свежие значения, надо изменить его на 10 секунд. Пропишем в owfs.conf:
timeout_volatile = 10
#error_print = 1
error_print = 3
error_level = 2

error_print = 3 обозначает подавление логов - при опросе раз в 10 секунд из слишком много.

Протестировав я понял, что и 10 секунд слишком много. Но дальше увеличивать частоту опросов всех датчиков накладно. И вообще неплохо бы использовать unchached значения из owfs для датчиков, а кеш использовать только для датчиков, данные которых не критичны в времени опроса - например, датчики температуры. Но в openHAB пока с этим проблемы. Поэтому будем использовать небольшой хак. Для датчиков мы будем использовать exec binding и получать данные с файловой системы. Формат запроса:

in:  exec:"<[<commandline execute="" to="">:<refreshintervalinmilliseconds>:<transformationrule>]"

items:

Number Main_Door_Lock "Замок в двери C: [MAP(ru.map):%s]"<door>(Doors) { exec="<[/bin/cat /mnt/1wire/uncached/12.A214B2000000/sensed.A:5000:REGEX((.*?))]" }

В принципе, тут можно использовать и Contact.
Результат срабатывания правила:





Последний штрих - теперь нам надо настроить запуск приложения файловой системы owfs, потому что мы с него получаем данные. (Проверьте, что у вас запускается при старте в директориях rc.d).
# update-rc.d owfs defaults 30

Не забудьте выставить очередь запуска после owserver (у меня, как видно 30, а у owserver 20)!

4 февраля 2014 г.

Датчик открытого замка\двери\окна на 1-wire и openHAB

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

DS2406P универсальный элемент стандарта 1-Wire-net. Она содержит два независимых транзисторных ключа, с током потребления до 50 мА на предельном коммутируемом напряжении +13 В (для канала А) и до 8 мА на предельном коммутируемом напряжении +6 В (для канала B). DS2406P может быть использована также для контроля двух независимых датчиков дискретных сигналов типа "сухой контакт". (с).

Изучаем схему с сайта http://www.benuks.ru/



Схема аналогична этой. Только тут используется более "продвинутая" микросхема.

Освоим технологию создания плат (типа продинутый ЛУТ), мне понравилось вот это видео (пришлось даже ламинатор купить):



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



Качаем архив со схемами в формате layout4. Находим там схему и печатаем на листе  тонкого глянцевого журнала, прогоняем результат с ламинатором.



То, что получилось у меня после печати и прогона в ламинаторе (160 градусов Цельсия):



Травим, получаем (снизу артефакты от первой печати с фотобумагой, сверху - плохой журнальный лист - тонер отскочил от него - подкрасил маркером):



Моем (бензин или ацетон) и сверлим отверстия (я собрал мини дрель - держатель в сборе в радио магазине, двигатель от детской машины).



Для покупки-сбора инструмента, освоение технологий, ушло пару-тройку рабочих недель. Цанговый патрон брал в местном радио-магазине, сверла здесь. Отличные сверла, рекомендую. Лудим, паяем плату.






Обратите внимание - в схеме надо делать перемычку для подачи 5 вольт на ds2406. Далее, я подпаял разъем rj11 и подключил к нашей сети 1wire . Заходим в директорию /mnt/1wire и смотрим - у нас должен появиться новый датчик. Подключив геркон к выводу "земля" и А (или B), а магнит приклеив к замку - получаем датчик закрытого\открытого замка:
root@truck:/mnt/1wire/12.***4B2000000# cat sensed.A
0
root@truck:/mnt/1wire/12.***4B2000000# cat sensed.B
1

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

Стабилизатор с 18 на 12 вольт я впаивать не стал - в данном случае нам 12 вольт не нужно.

OpenHAB

Теперь нам надо показания датчиков открытия отобразить в OpenHAB. Я пытался использовать стандартный Contact item. Но по-видимому он еще не работает с 1wire. Поэтому пришлось прописать показания открытого замка как Number.

/* Active Group */
Group:Number:SUM        Doors   "Двери [открыто: %d]"     (All)

/* Contacts */

Number  Main_Door      "Входная дверь: [MAP(ru.map):%s]"       <door>  (Doors) { onewire="12.A234B4000000#sensed.B" }
Number  Main_Door_Lock "Замок в двери: [MAP(ru.map):%s]"        <door>  (Doors) { onewire="12.A234B4000000#sensed.A" }

1 - открытая дверь/замок, 0 - закрытая. Группа Doors (привет поклонникам Джима :) ) - показывает суммарное значение показаний item в группе - соответственно, количество открытых дверей.
ru.map пишем по аналогу en.map. В sitemap выводим просто группу.

Так как doors у нас через number, а иконка door завязана на Contact с показаниями open\close, то картинку door-open.png копируем в door-1.png, а door-close.png копируем в door-0.png.

Результат:


ps. Только я спросил про патч, сразу товарищи разработчики его наложили. Так что можете пробовать Contact item в ночном билде (я думаю это исправление войдет в версию 1.4, которая выйдет 9-го февраля 2014 года). Я пробовать не буду, так как меня пока устраивает на основе Numbers.

2 февраля 2014 г.

Owfs - установка из исходников

Начнем с лирического отступления. Проанализировав показания термометра DS18B20 я понял, что он немного завышает показания.   Погуглив я нашел две причины: либо самонагрев датчика от частого опроса, либо неоткаллиброванный датчик. Решил получше изучить логи owfs.

1. Включаем логи: /etc/owfs.conf

error_print = 1 
error_level = 3 

Перезапускаем owserver и смотрим что у нас в логах. (Обратите внимание, что я рассказываю про версию из deb пакета в init.d скрипте которого уже указан путь к конфигу). А в логах у нас пусто. Помните, как мы устанавливали систему? Позже мы поставили rsyslod.

Ищем # whereis owserver , чтобы запустить его не в режиме сервиса , а в консоли.

#/usr/bin/owserver --debug  --error_level=9 --error_print=2 --foreground -c /etc/owfs.conf --pid-file /var/run/owfs/owserver.pid
DEBUG MODE
libow version:
        2.8p15


И снова пусто. Но не только у нас. Похоже, что в deb пакете owfs логирование выключено.

Посему удаляем owfs (сохраним init.d скрипты и owfs.conf - хотя они удалиться не должны). Качаем версию посвежее. Распаковываем tar -xvzf... Устанавливаем необходимое для компиляции и сборки.

#apt-get install autoconf libtool libusb-dev libfuse-dev make ed
#cd /usr/src/owfs-2.9p1
#./configure --help
#/owfs-2.9p1# autoreconf -i

Я сконфигурировал следующим образом (также можно добавить опцию --enable-owtraffic Enable bus traffic reports (default false) - очень интересная опция, дающая возможность отслеживать трафик в самой 1-wire сети):

#./configure --enable-debian --disable-owftpd --disable-owperl --disable-owphp --disable-parport --disable-owpython
# make -j4
# make install

По умолчанию все устанавливается в директорию /opt/owfs/ . Сделаем линк в /usr/bin , что бы было проще использовать и не переписывать скрипты запуска.

# for p in owfs owserver owhttpd owftpd owread owwrite owdir ; do ln -sf /opt/owfs/bin/$p /usr/bin/$p ; done

Пробуем запускать:

/usr/bin/owserver --debug  --error_level 9 --error_print 2 --foreground -c /etc/owfs.conf --pid-file /var/run/owfs/owserver.pid

Если все хорошо, перезапускаем сервер с помощью init скрипта и смотрим syslog. Отлично! Теперь укажем всем клиентским приложениям использовать tcp сервер (owserver) для работы, ибо usb устройство уже занято им (то есть все приложения пакета owfs должны работать через owserver - если он запущен, либо по одиночке). Пропишем в конфиг (он должен автоматически подхватываться (ключ -c) всеми init.d скриптами пакета owfs, которые у нас остались после установки deb пакета из репозитория):

# With this setup, any client (but owserver) uses owserver on the
# local machine...
! server: server = localhost:4304

В конфиге программы с репозитория эта строчка уже указана.

Но скрипта для приложения (не пакет) owfs в init.d нет (вообще странный пакет в репозитории дебиана - логов нет, управление не понятно, такое ощущение, что делал человек, плохо знакомый с owfs). Можем сделать на основе скрипта owhttpd и запускаем:

# /etc/init.d/owfs start
[ ok ] Starting 1-Wire owfs Daemon: owfs.
root@debtruck:/etc/init.d# ps -A | grep ow
 2478 ?        00:00:01 owserver
 3262 ?        00:00:00 owfs

Смотрим работающие логи.

26 января 2014 г.

Тестируем жесткие диски в debian/ubuntu

Чтобы не забыть.

# apt-get install smartmontools
# fdsik -l
# smartctl -A /dev/sda
# smartctl -t conveyance /dev/sda 
//через две минутки:
# smartctl -a /dev/sda
# smartctl -t long /dev/sda
//через пару часов
# smartctl -a /dev/sda


Проверим kern.log , позиции связанные с ata рассмотреть.

Быстрый опрос диска на предмет живучести, с предсказанием отказа диска в ближайшие 24 часа
sudo smartctl -H /dev/sda
Лучшее описание параметров здесь. На что стоит обратить внимание:
Attribute 04 (4) Start/Stop Count (Количество циклов запуск/останов шпинделя)
Attribute 05 (5) Reallocated Sector Count (Количество переназначенных секторов)
Attribute 09 (9) Power On Hours Count (Количество отработанных часов)
Attribute 0C (12) Power Cycle Count (Количество полных циклов запуска/останова)
Attribute C2 (194) Temperature (Температура диска)
Spin Up Time и Spin Retry Count - изменение значения может означать проблемы с питанием или с мотором.
Current Pending Sector Count - число "кандидатов" в ремапы.
Offline Scan Uncorrectable Count - число ошибок, обнаруженных при Offline самотесте (запускается автоматически, когда нет обращений к диску)
UltraDMA CRC Error Rate - изменение значения может означать плохой контакт в сигнальном кабеле (между MB и HDD).

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

"Следует отметить, что в винчестерах отдельных производителей Raw_Read_Error_Rate и Seek_Error_Rate параметры достигают максимума и обнуляютя несколько раз в день. Это связанно с политикой некоторых производителей в отношении SMART: в эти параметры пишутся все ошибки, а остальные производители только те, что не смог отловить контроллер." (с)

Current_Pending_Sector - число кандидатов на Reallocate, если сектор успешно читается повторно, то он убирается из списка «плохих» секторов, параметр Current_Pending_Sector уменьшается а Reallocate не происходит.
Изменение счётчика Current_Pending_Sector без Reallocate может быть из-за неправильного температурного режима накопителя.

24 января 2014 г.

Лев Толстой. Воскресение

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

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

- Кому молиться-то? - решительно наступающе и быстро выговаривая слог за слогом, сказал лохматый старик.

- Известно кому, богу, - иронически проговорил ямщик.

- А ты покажи мне, игде он? Бог-то?

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

- Игде? Известно - на небе,

- А ты был там?

- Был - не был, а все знают, что богу молиться надо.

- Бога никто же не видел нигде же. Единородный сын, сущий в недре отчем, он явил, - строго хмурясь, той же скороговоркой сказал старик.

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

Кто-то засмеялся.

- А ты какой, дедушка, веры? - спросил немолодой уже человек, с возом стоявший у края парома.

- Никакой веры у меня нет. Потому никому я, никому не верю, окроме себе, - так же быстро и решительно ответил старик.

- Да как же себе верить? - сказал Нехлюдов, вступая в разговор. - Можно ошибиться.

- Ни в жизнь, - тряхнув головой, решительно отвечал старик.

- Так отчего же разные веры есть? - спросил Нехлюдов.

- Оттого и разные веры, что людям верят, а себе не верят. И я людям верил и блудил, как в тайге; так заплутался, что не чаял выбраться. И староверы, и нововеры, и субботники, и хлысты, и половцы, и беспоповцы, и австрияки, и молокане, и скопцы. Всякая вера себя одна восхваляет. Вот все и расползлись, как кутята {Кутята - щенки. (Прим. Л. Н. Толстого.)} слепые. Вер много, а дух один. И в тебе, и во мне, и в нем. Значит, верь всяк своему духу, и вот будут все соединены. Будь всяк сам себе, и все будут заедино.

Старик говорил громко и все оглядывался, очевидно желая, чтобы как можно больше людей слышали его.

- Что же, вы давно так исповедуете? - спросил его Нехлюдов.

- Я-то? Давно уж. Уж они меня двадцать третий год гонят.

- Как гонят?

- Как Христа гнали, так и меня гонят. Хватают да по судам, по попам - по книжникам, по фарисеям и водят; в сумасшедший дом сажали. Да ничего мне сделать нельзя, потому я слободен. "Как, говорят, тебя зовут?" Думают, я звание какое приму на себя. Да я не принимаю никакого. Я от всего отрекся: нет у меня ни имени, ни места, ни отечества, - ничего нет. Я сам себе. Зовут как? Человеком. "А годов сколько?" Я, говорю, не считаю, да и счесть нельзя, потому что я всегда был, всегда и буду. "Какого, говорят, ты отца, матери?" Нет, говорю, у меня ни отца, ни матери, окроме бога и земли. Бог - отец, земля - мать. "А царя, говорят, признаешь?" Отчего не признавать? он себе царь, а я себе царь. "Ну, говорят, с тобой разговаривать". Я говорю: я и не прошу тебя со мной разговаривать. Так и мучают.

- А куда же вы идете теперь? - спросил Нехлюдов.

- А куда бог приведет. Работаю, а нет работы - прошу, - закончил старик, заметив, что паром подходит к тому берегу, и победоносно оглянулся на всех слушавших его.

Паром причалил к другому берегу. Нехлюдов достал кошелек и предложил старику денег. Старик отказался.

- Я этого не беру. Хлеб беру, - сказал он.

- Ну, прощай.

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

21 января 2014 г.

Резервная копия в сети, запуск по расписанию, шифрование (debian)

В общем, опять. Надо сделать бекап сайта (debian) или чего угодно, вcтречаем:

Резервная копия в сети, запуск по расписанию, шифрование. А теперь по-английски: Backup, mysqldump, yandex-disk, cron, gpg.

1. Устанавливаем клиент yandex-disk.

2. Скрипт сохранения и шифрования.

#!/bin/sh
# get the current timestamp for filename #
NOWDATE=`date +%d.%m.%y_%H%M`

echo 'zipping ...'

BACKUP="/path/to/yadisk"
TMPBACKUP="/path/to/temp"

tar -cz /path/to/site/ | gpg --batch --yes -c --passphrase _passwordhere_ -o "$BACKUP/$NOWDATE-site_files.tgz.gpg"

echo 'mysql_dump ...'

DB_USER="dbuser"
DB_PASSWD="dbpassword"
DB_BASE="dbname"

mysqldump --user=$DB_USER --password=$DB_PASSWD --opt $DB_BASE > "$TMPBACKUP/$NOWDATE-db_backup"
gpg --batch --yes --passphrase _passwordhere_  -o "$BACKUP/$NOWDATE-db_backup.gpg" -c "$TMPBACKUP/$NOWDATE-db_backup" && rm -f "$TMPBACKUP/$NOWDATE-db_backup"


--batch --yes может даже лишнее. Но пригодится, если у вас одно и тоже имя для файла бекапа.

3. Пишем правило для crontab. Если вы путаетесь в параметрах crontab есть отличная вещь под названием cronWTF. :)

4. gpg для windows здесь.

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