tag:blogger.com,1999:blog-47971673768815383472024-03-05T07:29:25.952+03:00VermusПрограммирование, администрирование, музыка, мысли.Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.comBlogger104125tag:blogger.com,1999:blog-4797167376881538347.post-5403405442319053262020-10-15T10:18:00.001+03:002020-10-15T10:19:47.935+03:00Создание переключателя Home Assistant для управления правилом фаервола Mikrotik<p>Потребовалось тут выключать\включать правило в ip/firewall/filter в микротике. На данный момент нашел три компонента для работы с микротиком. <a href="https://www.home-assistant.io/integrations/mikrotik/" rel="nofollow" target="_blank">Стандартная</a>, которая ничего не умеет, кроме как обнаружить есть ли микротик в сети. <a href="https://github.com/pilotak/homeassistant-mikrotik" rel="nofollow" target="_blank">Простенький компонент</a>, но без документации. <a href="https://github.com/tomaae/homeassistant-mikrotik_router" rel="nofollow" target="_blank">Серьезный компонент</a>, работающий по winbox api. </p><p>Но мне хотелось более простого варианта. Чтобы не грузить лишние компоненты в Home Assistant (HA). И такой вариант есть - это работа через ssh.</p><h2 style="text-align: left;">Подключаем SSH Public Key Authentication</h2><p><br /></p><p>С паролем работать из HA с ssh непросто, по-крайней мере я нашел кучу тем без ответа как это делать и сразу перешекл к рабочему и более правильному варианту - авторизация по публичному ключу. Там все стандартно, создем пару ключей на клиенте (HA), закидываем публичный на микротик:</p>
<pre class="xml" name="code">ha_user@ha:~$ ssh-keygen -t rsa
ha_user@ha:~$ scp ~/.ssh/id_rsa.pub admin@192.168.1.1:mykey.pub
</pre>
<p>Далее импортируем файл публичного ключа в пользователя:</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFYHQDdLdcYlH7RonhVFoejBjFKx9CmthQTHPmyphvWKpPTho21aUfrPHsn2IUNqByOf9EWN0-ZIoDq3369eTmi0WLs8B2tqIK8Cajeg_x08spsvNEea40EkhgNFjvisXYWpi1Es4q/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="329" data-original-width="599" height="176" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFYHQDdLdcYlH7RonhVFoejBjFKx9CmthQTHPmyphvWKpPTho21aUfrPHsn2IUNqByOf9EWN0-ZIoDq3369eTmi0WLs8B2tqIK8Cajeg_x08spsvNEea40EkhgNFjvisXYWpi1Es4q/" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: justify;">Тестируем, что можем зайти в mikrotik без пароля <span style="background-color: whitesmoke; color: #333333; font-family: Menlo, Monaco, Consolas, "courier new", monospace; font-size: 13px; text-align: left;">ssh admin@192.168.1.1 "/system resource print".</span></div><div class="separator" style="clear: both; text-align: justify;"><br /></div><h2 style="text-align: left;">Настраиваем Switch в Home Assistant.</h2><div><br /></div><div>прописываем в configuration.yaml:</div><div><br /></div>
<pre class="xml" name="code">switch:
- platform: command_line
switches:
rule_1:
command_on: "ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no admin@192.168.1.1 '/ip firewall filter disable 1'"
command_off: "ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no admin@192.168.1.1 '/ip firewall filter enable 1'"
command_state: "ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no admin@192.168.1.1 '/put [ip firewall filter get number=1 disabled]'"
value_template: '{{ value == "true" }}'
friendly_name: Rule 1 </pre>
<p>value_template - параметр который работает с ответом от command_state. Так как command_state нам возвращает "true"\"false" а не "0" как трубет command_state, то используем его. Конечно, лучше завести нового пользователя в микротике, с ограничением прав только на данные операции. Выключатель готов:</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRS5slYsr95bzzPFRIXWXrzUh-inT_812ImhxO5Z3d5xTNw1_CEOv8LLZIjWMk3bLTTjwAteBwsKagz4iTeN8gTWgSF_ERhQwuP6OUQA25qm9V6oMhcqwlMQwgf1LgLqJVuRt3KijY/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="220" data-original-width="994" height="71" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRS5slYsr95bzzPFRIXWXrzUh-inT_812ImhxO5Z3d5xTNw1_CEOv8LLZIjWMk3bLTTjwAteBwsKagz4iTeN8gTWgSF_ERhQwuP6OUQA25qm9V6oMhcqwlMQwgf1LgLqJVuRt3KijY/" width="320" /></a></div><p></p><p><br /></p>Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com0tag:blogger.com,1999:blog-4797167376881538347.post-51090160363294370682020-03-17T15:10:00.001+03:002020-03-17T15:11:17.538+03:00Подключение выключателя Sonoff T4EU1C к Home AssistantВыключатели Xiaomi довольно дорогие, и не входят в стандартный российский подрозетник. Поэтому было решено купить выключатель Sonoff TXT4EU1C, который в два раза дешевле. Он работает поверх сети wifi. Никаких ZigBee.
Это выключатель работает в разрыв фазы, дополнительно надо установить Antiflicker Module, параллельно лампе, который и будет замыкать цепь и питать наш выключатель.
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglQOBuiI0RMF5ndvShp5Z-QZ_pV_PLnRYG7DSeHIAOQVARylawWvWSitqZWmD6Vzn3gFxOhm5I9DKhtqVgiG0CnAiGklZG-3BZoK5CUr0n_sB_AKvmwXDDK85sv4acgRwWCyxJD-9h/s1600/sono.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="225" data-original-width="225" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglQOBuiI0RMF5ndvShp5Z-QZ_pV_PLnRYG7DSeHIAOQVARylawWvWSitqZWmD6Vzn3gFxOhm5I9DKhtqVgiG0CnAiGklZG-3BZoK5CUr0n_sB_AKvmwXDDK85sv4acgRwWCyxJD-9h/s320/sono.jpg" width="320" /></a></div>
<br />
<b>Подключаем Sonoff T4EU1C к Home Assistant </b>
<br />
Буквально на днях наши соотечественники <a href="https://github.com/AlexxIT/SonoffLAN">выпустили перспектинвую библиотеку SonoffLAN</a> для испозования Sonoff устройств в Home Assistant. Ну что же, попробуем.
<br />
Для начала устанавливаем приложение ewelink для регистрации устройства в профиле. Именного из профиля SonoffLAN будет брать всю информацию об устройствах Sonoff. Хотя вы можете прописать всю информацию врчуную, но в этом случае, я так понимаю, все равно нужно приложения, для подключния Sonoff устройства к вашей wifi сети.
<br />
Качаем библиотеку
<br />
<pre class="xml" name="code">#wget https://github.com/AlexxIT/SonoffLAN/archive/master.zip
</pre>
<br />
Распаковываем библиотеку в директорию Home Assistant:
<br />
<pre class="xml" name="code">/config/custom_components/sonoff/
</pre>
<br />
Прописываем логин пароль от eWeLink в /config/configuration.yaml:
<br />
<pre class="xml" name="code">sonoff:
username: mymail@gmail.com
password: mypassword
</pre>
<br />
Перезапускаем сервер Home Assistant из web приложения. И получаем выключатель в Home Assistant<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvS5XM5TOERy-fd5Ep1oLHvNbG2Gu9Htcnamzl7yARF8dQ78An2MbxN5Wg4PwmkFerCSI3dAxxutQtzbaUHrY8qoBUE6drIX_moswNV0CdA36EcFm5GwKL8cnPsd0Dw521r1LsA9zy/s1600/svet.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="176" data-original-width="1082" height="52" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvS5XM5TOERy-fd5Ep1oLHvNbG2Gu9Htcnamzl7yARF8dQ78An2MbxN5Wg4PwmkFerCSI3dAxxutQtzbaUHrY8qoBUE6drIX_moswNV0CdA36EcFm5GwKL8cnPsd0Dw521r1LsA9zy/s320/svet.png" width="320" /></a></div>
<br />
На удивление просто, и писать больше собственоо нечего. :) Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com0tag:blogger.com,1999:blog-4797167376881538347.post-16988101490567565822020-03-16T17:45:00.000+03:002020-03-16T18:02:16.152+03:00Подключение Xiaomi Gateway (Aqara) к Home Assistant<b>Установка home assistant</b>
<br />
Я выбрал вариант для докера (установил docker и portainer (очень удобный веб интерфейс для управления контейнерами). Установка home-assistant описана тут: <a href="https://www.home-assistant.io/docs/installation/docker/">https://www.home-assistant.io/docs/installation/docker/</a> .
<br />
<br />
<b>Режим разработчика или DIY Xiaomi Gateway (Aqara)</b>
<br />
Устанавливаем приложение Mi Home на телефон IOS или Android, добавляем шлюз средствами программы. Активируем режим разработчика (внимание, на данный момент поддерживаются только хабы Aqara версии v2, в дригух пока такого режима нет. В версии 3 можно использовать через Apple Home, гуглите).
<br />
Заходим в хаб, нажимаем Сведения (About) в меню, нажимаем пять раз на версию приложения пока не появятся дополнительные меню на английском (нам нужно меню wireless communication protocol, в нем вы увидите пароль для хаба).
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtNDUyH3zqtrL7X-ihUs2pSwOQAco9MxVRu9KBcuZbHywZP1P1St2sfSkAityUy2yKqUgifQWL5KvEUYYfmqmcTjdwIuLVtjEsWgfimI9YGSijRs0upbiX6-eAWM18H0zWvFVLNSSO/s1600/pass.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1449" data-original-width="723" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtNDUyH3zqtrL7X-ihUs2pSwOQAco9MxVRu9KBcuZbHywZP1P1St2sfSkAityUy2yKqUgifQWL5KvEUYYfmqmcTjdwIuLVtjEsWgfimI9YGSijRs0upbiX6-eAWM18H0zWvFVLNSSO/s320/pass.jpg" width="160" /></a></div>
<br />
<b>Привязываем хаб Xiaomi Gateway (Aqara) к home assistant</b>
<br />
<a href="https://www.home-assistant.io/integrations/xiaomi_aqara/" target="_blank">Для привязки</a> одного хаба пишем в configuration.yaml:
<br />
<pre class="xml" name="code">#yum install sysbench
# You can leave MAC empty if you only have one gateway.
xiaomi_aqara:
discovery_retry: 5
gateways:
- key: xxxxxxxxxxxxxxxx
</pre>
<br />
Хаб найдется через мультикаст запрос, можно прописать ip хаба. Для привязки нескольких configuration.yaml:
<br />
<pre class="xml" name="code">#yum install sysbench
# 12 characters MAC can be obtained from the gateway.
xiaomi_aqara:
gateways:
- mac: xxxxxxxxxxxx
key: xxxxxxxxxxxxxxxx
- mac: xxxxxxxxxxxx
key: xxxxxxxxxxxxxxxx</pre>
<br />
Перезапускаем сервер из веб приложения home assistant (настройки - сервер - перезапустить). И получаем.. ничего :) Ошибка:
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVBw0KulrODe1_PNJFabhmM-diIPZz6uaIDLLfyhOx-828FLMeWLDnRjZAJBj9ZkBEAqYWlbcpovZSlxk904yi6dFD5N6MPWVOnq8B17yHTFDYkgmzMG6qg4hja29hcDEaMUAZKdsk/s1600/error_aqara.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVBw0KulrODe1_PNJFabhmM-diIPZz6uaIDLLfyhOx-828FLMeWLDnRjZAJBj9ZkBEAqYWlbcpovZSlxk904yi6dFD5N6MPWVOnq8B17yHTFDYkgmzMG6qg4hja29hcDEaMUAZKdsk/s320/error_aqara.png" width="320" height="169" data-original-width="964" data-original-height="508" /></a></div>
<br />
<b>Проверяем порт Xiaomi Gateway (Aqara)</b>
<br />
Что бы HA подключился к хабу, нужны открытые UDP порты 4321/9898 на хабе. Говорят, в последних партиях хабов эти порты закрыты по умолчанию (Новые ревизии шлюзов (надпись около вилки идёт по кругу) поставляются с последней прошивкой). Узнаем ip адрес хаба в приложении MI Home (About -> Hub info). Тестируем порты:
<br />
<pre class="xml" name="code">
# nmap -sU 192.168.1.109 -p 5353,9898,4321
PORT STATE SERVICE
4321/udp open|filtered rwhois
5353/udp open|filtered zeroconf
9898/udp open monkeycom
</pre>
<br />
Если у вас порты закрыты - <a href="https://habr.com/ru/post/487768/">прочитайте статью</a>.
<br />
У меня была определенная проблема в том что, сеть докера была в bridge mode и multicast дискаверинг не срабатывал. Переключаем докер в host mode. Открываем порт 8123 на файерволе, а так же прохождение мультикаст пакетов (на хосте с докером), если необходимо. Получаем результат:
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPeb7ajhlXxWj13NdLGtYmcl_6CC9vWwahOdqHV4QaXzDMsD-QEma4NR7o8fc6qx0qhK30OkifPqr1bGZQgEBXok48jxUAUISmnzl7KOkwpV4P5g31s4_dJRn9yqkBFtf_es5_vYV9/s1600/xia_gate.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPeb7ajhlXxWj13NdLGtYmcl_6CC9vWwahOdqHV4QaXzDMsD-QEma4NR7o8fc6qx0qhK30OkifPqr1bGZQgEBXok48jxUAUISmnzl7KOkwpV4P5g31s4_dJRn9yqkBFtf_es5_vYV9/s320/xia_gate.png" width="320" height="246" data-original-width="1165" data-original-height="895" /></a></div>
Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com0tag:blogger.com,1999:blog-4797167376881538347.post-61894551254543773512020-03-12T14:05:00.002+03:002020-03-12T14:29:15.552+03:00Нагрузочное тестирование CPU в CentOS 8 (stress test)<br />
<b>EPEL</b>
<br />
EPEL (Extra Packages for Enterprise Linux) — репозиторий с дополнительными пакетами для Enterprise Linux, предоставляемый командой Fedora, которые не включены в установку по умолчанию в некоторых дистрибутиве CentOS.
<br />
Устанавливаем с помощью пакета epel-release и проверяем, что все работает:<br />
<pre class="xml" name="code"># yum install epel-release
# yum repolist | grep -i "epel\|repo id"
repo id repo name status
*epel Extra Packages for Enterprise Linux 8 - x86_64 4,979
</pre>
<br />
<b>Sysbench</b>
<br />
Устанавливаем и запускаем тест (cpu - этот тест проверит производительность процессоров, используя вычисления с 64-разрядными числами.):
<br />
<pre class="xml" name="code">#yum install sysbench
#sysbench cpu --threads=4 --cpu-max-prime=10000000 run
</pre>
где
<br />
--num-threads=4 - это количество потоков, у меня двухъядерный четырёхпотоковый Intel® Core™ i3 (мобильная U версия), поэтому 4;
<br />
--cpu-max-prime=10000000 - это максимальное количество выполненных операций. Вы можете увеличть это число, если надо тестировать дольше.
<br />
Вот так загружается процессор при выполнении:
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihZWzCc6g8zZDYyTAyljP2lIffa-sayKQ3XlS_t8EEtFVIWbpblhIvA7nTzZk1-We1ELAc_yoQsKdqOr1KqzClEPzs8ydB3i59p9nuZHNznupQHLrnYZYAoGrYnruhSJicJzacJa5w/s1600/sysbench.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="75" data-original-width="1288" height="19" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihZWzCc6g8zZDYyTAyljP2lIffa-sayKQ3XlS_t8EEtFVIWbpblhIvA7nTzZk1-We1ELAc_yoQsKdqOr1KqzClEPzs8ydB3i59p9nuZHNznupQHLrnYZYAoGrYnruhSJicJzacJa5w/s320/sysbench.png" width="320" /></a></div>
<br />
<br />
<b>Отслеживание температуры</b>
<br />
Смысл нагрузки процессора, в моем случае, был не только в проверке в проверке скорости работы процессора, но и в проверки температуры процессора в безвентиляторной системе. Поэтом во время нагрузочного теста, неплохо бы и отслеживать температуру.
<br />
Устанавливаем sensors.
<br />
<pre class="xml" name="code">#yum install lm_sensors
</pre>
<br />
Запускаем программу обнаружения датчиков. Для простоты жмите Enter, когда задаются вопросы.
<br />
<pre class="xml" name="code">#sensors-detect
</pre>
<br />
Добавим 0 в --cpu-max-prime=100000000 (чтобы тест пошел больше, чем 1 минуту) и запускаем sysbench. В отдельной консоли отслеживаем температуру:
<br />
<pre class="xml" name="code">#watch -n 1 -d sensors
</pre>
<br />
Моя температура до запуска:
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVJyR9b79Vb9na5o7WqSj2YCxMSMzuqLKKNIhV67XMocq9KR-OWnBUoAbEij3KGwfT6Hqz4lmOy-mnY8Mljud5QfogAmPKs43YIeHTBLBRHGhjYgHk41SYHh7WP-rK7JTfpai4X9t1/s1600/temp1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="242" data-original-width="1116" height="69" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVJyR9b79Vb9na5o7WqSj2YCxMSMzuqLKKNIhV67XMocq9KR-OWnBUoAbEij3KGwfT6Hqz4lmOy-mnY8Mljud5QfogAmPKs43YIeHTBLBRHGhjYgHk41SYHh7WP-rK7JTfpai4X9t1/s320/temp1.png" width="320" /></a></div>
<br />
Тест длился 570 секунд, температура на пике:
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMJyHEUEKTBicKUrYGQyBkOvnc5dirDt0SIadiGAPMrgcDV5tQwZaIm0bzcUOvx3H6DbLuGxEWmcxmHmRc-FBVDKoGPnqyn4PIvqouqX0je6Ft5A7vDWMsuTeQl-YxqIU_NzjvmvBq/s1600/temp2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMJyHEUEKTBicKUrYGQyBkOvnc5dirDt0SIadiGAPMrgcDV5tQwZaIm0bzcUOvx3H6DbLuGxEWmcxmHmRc-FBVDKoGPnqyn4PIvqouqX0je6Ft5A7vDWMsuTeQl-YxqIU_NzjvmvBq/s320/temp2.png" width="320" height="74" data-original-width="1032" data-original-height="240" /></a></div>
<br />
Достаточно низкая температура, попробуем другую утилиту.
<br />
<br />
<b>Mersenne prime (mprime 95)</b>
<br />
Качаем <a href="https://www.mersenne.org/download/#stresstest">Mersenne prime</a> и запускаем.
<br />
В моем случае:
<pre class="xml" name="code">
#mkdir mprime && cd mprime
#wget http://www.mersenne.org/ftp_root/gimps/p95v298b6.linux64.tar.gz
#tar -zxvf p95v298b6.linux64.tar.gz
#./mprime -m
</pre>
Нажмите N, если не хотите выполнять задания с сервера и перейти к тесту torture (пытка :) ). Выберем количество потоков. Дальше выбираем:
<br />
<pre>
Choose a type of torture test to run.
1 = Smallest FFTs (tests L1/L2 caches, high power/heat/CPU stress).
2 = Small FFTs (tests L1/L2/L3 caches, maximum power/heat/CPU stress).
3 = Large FFTs (stresses memory controller and RAM).
4 = Blend (tests all of the above).
</pre>
Я выбрал 2, так как пока не хочу нагружать память, возможно в следующий раз. Остальные опции по умолчанию. Пошел тест:
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWwkkeUvUwJAnTeC0z0zeOhZPTaXQ-bUoL64zf7xG-W2IpHzt7bWwerRE4JE9itJX6c6p0l16jXrK8AU52QMR_UeS5MawoE1lZOUAHetD4uy_rPDv5QMeYn-j1Wk3rIQpZOeOBvGtJ/s1600/mprime.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWwkkeUvUwJAnTeC0z0zeOhZPTaXQ-bUoL64zf7xG-W2IpHzt7bWwerRE4JE9itJX6c6p0l16jXrK8AU52QMR_UeS5MawoE1lZOUAHetD4uy_rPDv5QMeYn-j1Wk3rIQpZOeOBvGtJ/s320/mprime.png" width="320" height="127" data-original-width="1600" data-original-height="634" /></a></div>
<br />
Загрузка в top те же 400%, но с температурой уже поинтереснее:
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcFm8_cPo9yUDQmm3DEg77pHSJO7GGxcDkgsl8RxaDZlboiNvVVryt5Z60Or_ulhHs323xlMv0nwf2XhCQuFfwA8lVbo2hfctSaWQq44XG62IvZn-uWJkKDOffMnquqbei8LBWW40e/s1600/temp22.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcFm8_cPo9yUDQmm3DEg77pHSJO7GGxcDkgsl8RxaDZlboiNvVVryt5Z60Or_ulhHs323xlMv0nwf2XhCQuFfwA8lVbo2hfctSaWQq44XG62IvZn-uWJkKDOffMnquqbei8LBWW40e/s320/temp22.png" width="320" height="87" data-original-width="977" data-original-height="266" /></a></div>
<br />
Двухчасовое тестирование выдало максимальную температуру 60 градусов (в первый час 58). Максимальная температура PCH (<a href="https://ru.wikipedia.org/wiki/Skylake">южного моста Skylake</a>) 54 градус (первый час 52). Считаю отличный результат для без вентиляторной системы (а для мобильной платформы шикарный), а mprime лучшей утилитой для подобного стресс теста. Sysbench, я думаю, лучше использовать просто, как подсчет попугаев.
<br />
<br />
ps. нормальный показатель температуры диода PCH ноутбуков составляет 45-70°C. Кратковременные поднятия до более высоких температур тоже. Так же и с мобильным процессором, до 70 градусов - абсолютная норма.
Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com0tag:blogger.com,1999:blog-4797167376881538347.post-39104292305433710582014-05-14T12:50:00.000+04:002014-12-02T21:58:48.459+03:00ВидеонаблюдениеПродолжим. Ну какой <a href="http://vermus.blogspot.ru/search/label/%D1%83%D0%BC%D0%BD%D1%8B%D0%B9%20%D0%B4%D0%BE%D0%BC">умный дом</a> без видео наблюдения?<br />
<br />
В связи с тем, что умный дом у нас DIY, соответственно бюджетный, мы будем делать видео наблюдение на основе регистратора и аналоговых камер. Качество сносное, лучший вариант - все таки ip камеры. С другой стороны аналоговые камеры - гораздо меньше размером и существуют, например, в виде глазка.<br />
<br />
Тем не менее, я выбрал аналоговый вариант с регистратором. Что такое регистратор - по-простому это коробочка для подключения аналоговых камер и микрофонов, с линуксом внутри, что обычно подразумевает возможность подключить sata диск и записывать на него, а также подразумевает наличие ethernet порта, с различными сетевыми возможностями - записью на ftp, samba сервер или даже облако (китайское), возможность просмотра камер с доступом через определенный порт (rtsp) и т.д. Возможностей обычно много - например тот же ntp клиент, dynDns и прочее. <br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgL2HgmO-5y5Vec83s2bn8w6iIjd82Lq1ro-6V9TyyJ2jxZg7TV_-dnT6HdaF-tVYuPhpv7Aq1wLvbJ9qElktAo9OwX8Lj-y_Znx_FOPGG_xFU7LdEw-o9XokDmXlKLBLK81KzwIXVq/s1600/617503494_464.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgL2HgmO-5y5Vec83s2bn8w6iIjd82Lq1ro-6V9TyyJ2jxZg7TV_-dnT6HdaF-tVYuPhpv7Aq1wLvbJ9qElktAo9OwX8Lj-y_Znx_FOPGG_xFU7LdEw-o9XokDmXlKLBLK81KzwIXVq/s320/617503494_464.jpg" /></a></div>
<br />
У меня выбор пал на <a href="http://www.aliexpress.com/snapshot/281725692.html">следующий регистратор</a>. Сложно понять, что это за фирма и модель, тем не менее присутствие <a href="http://ru.wikipedia.org/wiki/960H_Technology">960H</a> подкупило. Хотя вот кстати его шильдик:
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0n93mhGVBUkqgw1W4VAxwxTVbQtNd6IBwfHBdxsRwYa3o3_GOr60_a_hUd1vPjOy7XdigRlMjc87g6g4aPoTggyJOQ0LM4vD_c8XfoyYB8aezFQrr8y-1S1y1zhu-CCp_wLnqm61N/s1600/20131210_205010.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0n93mhGVBUkqgw1W4VAxwxTVbQtNd6IBwfHBdxsRwYa3o3_GOr60_a_hUd1vPjOy7XdigRlMjc87g6g4aPoTggyJOQ0LM4vD_c8XfoyYB8aezFQrr8y-1S1y1zhu-CCp_wLnqm61N/s320/20131210_205010.jpg" /></a></div>
<br />
<br />
К сожалению, я не нашел возможность конфигурирования через веб-интерфейс (только просмотр с activex плагином). Конфигурировать возможно только непосредственно подключив мышь и монитор к регистратору или используя программу CMS (только под Windows), идущую на диске с регистратором (что говорит нам о том, что api управления есть - есть и конфигурация порта управления в настройках).
<br />
<br />
Дальнейшее разбирательство привело к следующим данным. Регистратор на основе hi3520d с такой начинкой:
<br />
<br />
<pre class="xml" name="code">[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
</pre>
<br />
<br />
Пароль для доступа через telnet к устройствам с таким контроллером xc3511. В принципе, там делать особо нечего, если не требуется каких-то сугубо специфических действий. Конфигурирование через telnet уж тем более на ваш страх и риск - не стоит там что либо править, если вы не уверены в своих действиях.
<br />
<br />
Это место в посты было переписано три раза :) Один раз кусок стер блогспот, второй раз я стер сам часто про то как я делал из rtsp jpeg. Провозившись три недели я все таки пришел к общему знаменателю вывода rtsp в веб для показа видео. И это связка - ffmpeg, nginx и <a href="https://github.com/arut/nginx-rtmp-module/">nginx-rtmp</a>. Для html5 в данный момент надо поддерживать целый зоопарк различно закодированных потоков. Это накладно для простых файлов, а для живого вещания вообще кошмар.
<br />
<br />
Как установить рассказывать не буду - вот хотя бы <a href="http://smidth.ru/blog/miscellaneous/installing-nginx-rtmp/">пример</a>. Могу добавить, что для использования модуля надо пересобирать весь nginx целиком. Плюс добавлю, что после компиляции я создаю пакет и ставлю его:
<br />
<pre class="xml" name="code">/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
</pre>
<br />
<br />
Дальше идем на https://github.com/arut/nginx-rtmp-module/ и читаем документацию. Пишем конфигурацию примерно такого содержания:
<br />
<br />
<pre class="xml" name="code">
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;
}
}
}
</pre>
<br />
<br />
Замечу, что exec_static выполняется при запуске nginx (ffmpeg забирает rtsp поток с регистратора и конвертирует в flv без перекодирования) , что очень удобно, не надо писать никаких дополнительных скриптов для запуска клиента.
<br />
<br />
Далее настраиваем flash плеер (uppod, flowplayer или др.) на html странице с адресом вида rtmp://server/cams/stream . В openhab с добавил Webview sitemap и в итоге у нас вышло нечто вроде:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLSdogzyGfEA_MEwD74YGXIlfOE_iTUyPPiLrTNVpTh_4GDrgcFQZCXt63CperyNLr_OWHJXIF8Jc24rWOg9fD0jmJsORo0lBXTHj3E4pRRtc_lrA-pRmhaccWfOvIZHb-ZQdWK2SM/s1600/video.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLSdogzyGfEA_MEwD74YGXIlfOE_iTUyPPiLrTNVpTh_4GDrgcFQZCXt63CperyNLr_OWHJXIF8Jc24rWOg9fD0jmJsORo0lBXTHj3E4pRRtc_lrA-pRmhaccWfOvIZHb-ZQdWK2SM/s320/video.png" /></a>
<br />
<br />
Повесил китайский планшет на стену - openhab теперь используется в виде видеоглазка. Регистратор записывает видео при обнаружении движения (настройка довольно таки не тривиальная, но можно поиcкать инструкцию к программе cms на русском, такая существует.<br /><br />
В будущем планирую видео <a href="http://habrahabr.ru/post/209500/">записывать в облако mail.ru</a>, благо там получен 1 террабайт.Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com5tag:blogger.com,1999:blog-4797167376881538347.post-65533723384407413792014-02-05T16:24:00.001+04:002014-02-05T16:38:04.648+04:00Управление и оповещение через jabber в openHABОтлично, у нас есть показания <a href="http://vermus.blogspot.ru/2014/02/1-wire.html">открытой двери и замка</a>. Теперь было бы неплохо, получать какие-нибудь оповещения о событиях. Например, для начала, о том что замок закрылся или открылся.
<br />
<br />
Я решил оповещения сделать на основе jabber, тем более, что данный вариант позволяет даже управлять openHABом из jabber. Создаем <a href="http://jabberworld.info/%D0%9F%D1%83%D0%B1%D0%BB%D0%B8%D1%87%D0%BD%D1%8B%D0%B5_%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80%D1%8B_Jabber">учетную запись</a> (xmpp или jabber). Ищем секцию xmpp в openhab.cfg. Прописываем сервер, логин, пароль.
<br />
Отправляем команду help:<br />
<br />
<pre class="xml" name="code">(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
</pre>
<br />
<br />
Теперь разберемся, как нам послать сообщение о смене статуса открытого замка. Для этого просто создадим новое правило в home.rules:
<br />
<br />
<pre class="xml" name="code">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
</pre>
<br />
<br />
Очень помогает в написании правил функция авто-дополнения в дизайнере (Ctrl+Space), ибо документация по этому поводу хромает.
<br />
<br />
Поэкспериментировав понимаем, что время отклика оставляет желать лучшего. Смотрим лог owfs - датчик опрашивается openHAB'ом раз в минуту - это как раз настройка в openHAB. К сожалению на данный момент <a href="https://github.com/openhab/openhab/issues/592">время обновления едино</a> для всех датчиков 1-wire в openHAB. Поэтому ничего не остается, как сменить частоту обновления хотя бы на раз в 10 секунд.
<br />
<br />
Кеш owfs для датчиков <a href="http://owfs.org/index.php?page=what-is-uncached">по умолчанию</a> 15 секунд. Поэтому, чтобы получать свежие значения, надо изменить его на 10 секунд. Пропишем в owfs.conf:
<br />
<pre class="xml" name="code">timeout_volatile = 10
#error_print = 1
error_print = 3
error_level = 2
</pre>
<br />
error_print = 3 обозначает подавление логов - при опросе раз в 10 секунд из слишком много.
<br />
<br />
Протестировав я понял, что и 10 секунд слишком много. Но дальше увеличивать частоту опросов всех датчиков накладно. И вообще неплохо бы использовать unchached значения из owfs для датчиков, а кеш использовать только для датчиков, данные которых не критичны в времени опроса - например, датчики температуры. Но в openHAB пока с этим <a href="https://github.com/openhab/openhab/issues/592">проблемы</a>. Поэтому будем использовать небольшой хак. Для датчиков мы будем использовать exec binding и получать данные с файловой системы. Формат запроса:
<br />
<br />
<pre class="xml" name="code">in: exec:"<[<commandline execute="" to="">:<refreshintervalinmilliseconds>:<transformationrule>]"
</pre>
<br />
items:
<br />
<br />
<pre class="xml" name="code">Number Main_Door_Lock "Замок в двери C: [MAP(ru.map):%s]"<door>(Doors) { exec="<[/bin/cat /mnt/1wire/uncached/12.A214B2000000/sensed.A:5000:REGEX((.*?))]" }
</pre>
<br />
В принципе, тут можно использовать и Contact.
<br />
Результат срабатывания правила:
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihwEFF-yA88df9zWjC_KX780lKSGl4jnTwnKyMyBf54OWEYz2W3WGLFP09UhZNqeln93JJHUv028LTF_UJ8DXZ3qoy7cV2z5C1zEynGLjEdBc4vHY-4AV5bwrdm-YahG-ylUVzUH2v/s1600/jabber.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihwEFF-yA88df9zWjC_KX780lKSGl4jnTwnKyMyBf54OWEYz2W3WGLFP09UhZNqeln93JJHUv028LTF_UJ8DXZ3qoy7cV2z5C1zEynGLjEdBc4vHY-4AV5bwrdm-YahG-ylUVzUH2v/s320/jabber.png" /></a></div>
<br />
<br />
<br />
<br />
Последний штрих - теперь нам надо настроить запуск приложения файловой системы owfs, потому что мы с него получаем данные. (Проверьте, что у вас запускается при старте в директориях rc.d).
<br />
<pre class="xml" name="code"># update-rc.d owfs defaults 30
</pre>
<br />
Не забудьте выставить очередь запуска после owserver (у меня, как видно 30, а у owserver 20)!Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com0tag:blogger.com,1999:blog-4797167376881538347.post-86519241741264962012014-02-04T14:46:00.000+04:002014-02-04T14:54:29.611+04:00Датчик открытого замка\двери\окна на 1-wire и openHABПосле небольшого перерыва на <a href="http://vermus.blogspot.ru/search/label/OpenHAB">софт</a> вновь перейду к железной стороне. Следующим устройством в сети мне надо сделать датчик открытого замка. Если вы помните, мы <a href="http://vermus.blogspot.ru/2013/12/1-wire-ds9490r-cubietruck-1-wire-ds2401.html">использовали электронную метку ds2401</a> для определения наличия датчика в сети. Как мы убедились, а умные люди нам <a href="http://www.ab-log.ru/forum/viewtopic.php?f=1&t=586#p10812">подсказали</a> - это работает слишком медленно. Поэтому мы будем использовать не определение датчика в сети, а сигналы от датчика-ключа ds2406p (такую микросехму я нашел, можно использовать и другие). Заодно мы сделаем и датчик открытой двери, ибо в таком исполнении у микросхемы два канала.
<br />
<br />
DS2406P универсальный элемент стандарта 1-Wire-net. Она содержит два независимых транзисторных ключа, с током потребления до 50 мА на предельном коммутируемом напряжении +13 В (для канала А) и до 8 мА на предельном коммутируемом напряжении +6 В (для канала B). DS2406P может быть использована также для контроля двух независимых датчиков дискретных сигналов типа "сухой контакт". <a href="http://blog-i.ru/elementi-umnogo-doma/ds2406p-element-1-wire-seti">(с)</a>.
<br />
<br />
Изучаем схему с сайта <a href="http://www.benuks.ru/">http://www.benuks.ru/</a>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi290y6xvpzqBFrQiJn7mEOZo7uVE23p0Cf3zlYWjxwtgFALtJnDXTh14tR4asmfsBKN2jzU-8WGqvNqmgA-HfVCxdD4HxP3OaDkx1WfI3tbAAWbMYl9iQVAGLsr27etaQUXnX6pd-I/s1600/sh_dvi.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi290y6xvpzqBFrQiJn7mEOZo7uVE23p0Cf3zlYWjxwtgFALtJnDXTh14tR4asmfsBKN2jzU-8WGqvNqmgA-HfVCxdD4HxP3OaDkx1WfI3tbAAWbMYl9iQVAGLsr27etaQUXnX6pd-I/s320/sh_dvi.jpg" /></a></div>
<br />
<br />
Схема аналогична <a href="http://www.benuks.ru/walpers/sh_io_1.jpg">этой</a>. Только тут используется более "продвинутая" микросхема.<br />
<br />
Освоим технологию создания плат (типа продинутый ЛУТ), мне понравилось вот это видео (пришлось даже ламинатор купить):
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/gjMBI2RfaKM?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Единственно, я заменил самоклейку на фотобумагу. Но с ней у меня ничего не вышло, в итоге я взял лист от тонкого глянцевого журнала. Процесс травления не показан, ну можно поискать, или вот он:
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="https://ytimg.googleusercontent.com/vi/n_j6r27LSnE/0.jpg" height="266" width="320"><param name="movie" value="https://youtube.googleapis.com/v/n_j6r27LSnE&source=uds" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="https://youtube.googleapis.com/v/n_j6r27LSnE&source=uds" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<br />
<br />
Качаем <a href="http://www.benuks.ru/data/lay4.rar">архив со схемами в формат</a>е layout4. Находим там схему и печатаем на листе тонкого глянцевого журнала, прогоняем результат с ламинатором.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkufDgWKOt1QsgAEhbnqfIUO3uWi5DhmCMzc5qiwHV16Zdy8VUGyJM_c3m2LN9oSoSb7HT20OLXs2ySChQYMz6_iGzPUA7xWqoOrYTTRozunKRz_qe-FM-k5d_19oH5PdolhHFbhpP/s1600/in_out12_lay.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkufDgWKOt1QsgAEhbnqfIUO3uWi5DhmCMzc5qiwHV16Zdy8VUGyJM_c3m2LN9oSoSb7HT20OLXs2ySChQYMz6_iGzPUA7xWqoOrYTTRozunKRz_qe-FM-k5d_19oH5PdolhHFbhpP/s1600/in_out12_lay.jpg" height="294" width="320" /></a></div>
<br />
<br />
То, что получилось у меня после печати и прогона в ламинаторе (160 градусов Цельсия):
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTpJin2Pfr6zdAqQANF-1LjXhDHgv0ssbIvE-6nXziOt6dyOL5BIHv2tMWi82qhQxtKXEuR5XY6ovPSnlK5cDTU8NJA1hOGSdC3-dt5ujY0DoXGKekbXznw6GgGd4_fpes0XXQyVfa/s1600/20140126_221147.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTpJin2Pfr6zdAqQANF-1LjXhDHgv0ssbIvE-6nXziOt6dyOL5BIHv2tMWi82qhQxtKXEuR5XY6ovPSnlK5cDTU8NJA1hOGSdC3-dt5ujY0DoXGKekbXznw6GgGd4_fpes0XXQyVfa/s320/20140126_221147.jpg" /></a></div>
<br />
<br />
Травим, получаем (снизу артефакты от первой печати с фотобумагой, сверху - плохой журнальный лист - тонер отскочил от него - подкрасил маркером):
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhz_fMN6z6F4NbuTzv3pMZysxUfNIC85rNkbYPOmU5PrjajgK1IPbiIBUGjU3OawhZKh4QWpuuhMwgFdi1vsT1Ao52OYzpV4ejrhM3YtARLZuIBWIKg1jUIAgGyimnH5Giss-AnNafC/s1600/20140126_225945.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhz_fMN6z6F4NbuTzv3pMZysxUfNIC85rNkbYPOmU5PrjajgK1IPbiIBUGjU3OawhZKh4QWpuuhMwgFdi1vsT1Ao52OYzpV4ejrhM3YtARLZuIBWIKg1jUIAgGyimnH5Giss-AnNafC/s320/20140126_225945.jpg" /></a></div>
<br />
<br />
Моем (бензин или ацетон) и сверлим отверстия (я собрал мини дрель - держатель в сборе в радио магазине, двигатель от детской машины).
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgp7_fUjqw4HhUmiy5t-MGIKYerxyA1fsJEf8sNbycEp3JUk0Ee-0Wh7dqoP5hn6LIfvl9vwMNCBMbmTsyNQVldmAW_r4aAH-OWySRizPNtNeMFumNQCjRAzXgL8ke_wUu8Ca1t0uAA/s1600/20140128_211956.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgp7_fUjqw4HhUmiy5t-MGIKYerxyA1fsJEf8sNbycEp3JUk0Ee-0Wh7dqoP5hn6LIfvl9vwMNCBMbmTsyNQVldmAW_r4aAH-OWySRizPNtNeMFumNQCjRAzXgL8ke_wUu8Ca1t0uAA/s320/20140128_211956.jpg" /></a></div>
<br />
<br />
Для покупки-сбора инструмента, освоение технологий, ушло пару-тройку рабочих недель. Цанговый патрон брал в местном радио-магазине, сверла <a href="http://www.aliexpress.com/item/Discount-10pcs-0-3-1-2mm-PCB-Print-Circuit-Board-Drill-Bits-Carbide-Micro-Drill-Bits/1432824721.html">здесь</a>. Отличные сверла, рекомендую. Лудим, паяем плату.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEC5Xw6uBx-F8aE7oVyReieVOV-57UBJz0fFvavA5iH8CoYmEvcKrWvmfh9QJ-_0PCF7d5P3yNBURt3IeoH_TRH-mf5VLu8IASayoZ3GlIzg8tHBgdnYCZrACcfmOMgV7LENao6Ao4/s1600/20140201_222443.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEC5Xw6uBx-F8aE7oVyReieVOV-57UBJz0fFvavA5iH8CoYmEvcKrWvmfh9QJ-_0PCF7d5P3yNBURt3IeoH_TRH-mf5VLu8IASayoZ3GlIzg8tHBgdnYCZrACcfmOMgV7LENao6Ao4/s320/20140201_222443.jpg" /></a></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyjGAQvGBE827FiHaJKsHq5aaeIGPX4q20xwwc46k4KNRfzDMb8Mq0lUrEk1IAS3ebLKdMMu1Stkd5CALU7WJEz53AkWmjhxlJr0P8OtIHqethJJvF6-_aZE9lEVT49lgGu__O1ewV/s1600/20140201_223640.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyjGAQvGBE827FiHaJKsHq5aaeIGPX4q20xwwc46k4KNRfzDMb8Mq0lUrEk1IAS3ebLKdMMu1Stkd5CALU7WJEz53AkWmjhxlJr0P8OtIHqethJJvF6-_aZE9lEVT49lgGu__O1ewV/s320/20140201_223640.jpg" /></a></div>
<br />
<br />
Обратите внимание - в схеме надо делать перемычку для подачи 5 вольт на ds2406. Далее, я подпаял разъем rj11 и подключил к <a href="http://vermus.blogspot.ru/2014/01/1-wire.html">нашей сети</a> 1wire . <a href="http://vermus.blogspot.ru/2014/02/owfs.html">Заходим в директорию</a> /mnt/1wire и смотрим - у нас должен появиться новый датчик. Подключив геркон к выводу "земля" и А (или B), а магнит приклеив к замку - получаем датчик закрытого\открытого замка:
<br />
<pre class="xml" name="code">root@truck:/mnt/1wire/12.***4B2000000# cat sensed.A
0
root@truck:/mnt/1wire/12.***4B2000000# cat sensed.B
1
</pre>
<br />
B - можно использовать тут же, например, для датчика закрытой двери.
<br />
<br />
Стабилизатор с 18 на 12 вольт я впаивать не стал - в данном случае нам 12 вольт не нужно.<br />
<br />
<b>OpenHAB</b>
<br />
<br />
Теперь нам надо показания датчиков открытия отобразить в OpenHAB. Я пытался использовать стандартный Contact item. Но по-видимому <a href="http://knx-user-forum.de/openhab/25101-zustandsabfrage-per-1-wire-binding.html">он еще не</a> работает с 1wire. Поэтому пришлось прописать показания открытого замка как Number.
<br />
<br />
<pre class="xml" name="code">/* Active Group */
Group:Number:SUM Doors "Двери [открыто: %d]" <door> (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" }
</door></pre>
<br />
1 - открытая дверь/замок, 0 - закрытая. Группа Doors (привет поклонникам Джима :) ) - показывает суммарное значение показаний item в группе - соответственно, количество открытых дверей.
<br />
ru.map пишем по аналогу en.map. В sitemap выводим просто группу.
<br />
<br />
Так как doors у нас через number, а иконка door завязана на Contact с показаниями open\close, то картинку door-open.png копируем в door-1.png, а door-close.png копируем в door-0.png.
<br />
<br />
Результат:
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpIlZ1cE-vbgzEqNsC-7dS1SOGj41iFS485ASSW1-UDTjmD1NnfpTIPDAehZhuVVnznebCg7i-emGYqVrfD3Q7Xe-q9hPG6hqvRaq-XpHuOrKVwyzWjKPMC0tDwtEL0kpWuePZ-27-/s1600/doors.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpIlZ1cE-vbgzEqNsC-7dS1SOGj41iFS485ASSW1-UDTjmD1NnfpTIPDAehZhuVVnznebCg7i-emGYqVrfD3Q7Xe-q9hPG6hqvRaq-XpHuOrKVwyzWjKPMC0tDwtEL0kpWuePZ-27-/s320/doors.png" /></a></div>
<br />
<br />
ps. Только я спросил про патч, сразу товарищи разработчики его <a href="https://github.com/openhab/openhab/issues/355">наложили</a>. Так что можете пробовать Contact item <a href="https://openhab.ci.cloudbees.com/job/openHAB/">в ночном билде</a> (я думаю это исправление войдет в версию 1.4, которая выйдет 9-го февраля 2014 года). Я пробовать не буду, так как меня пока устраивает на основе Numbers.Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com0tag:blogger.com,1999:blog-4797167376881538347.post-50766962024286217662014-02-02T18:53:00.000+04:002014-02-04T20:41:29.729+04:00Owfs - установка из исходниковНачнем с лирического отступления. Проанализировав показания термометра DS18B20 я понял, что он немного завышает показания. Погуглив я нашел две причины: либо самонагрев датчика от частого опроса, либо неоткаллиброванный датчик. Решил получше изучить логи owfs.<br />
<br />
1. Включаем логи:
/etc/owfs.conf<br />
<br />
<pre class="xml" name="code">error_print = 1
error_level = 3
</pre>
<br />
Перезапускаем owserver и смотрим что у нас в логах. (Обратите внимание, что я рассказываю про версию из deb пакета в init.d скрипте которого уже указан путь к конфигу). А в логах у нас пусто. Помните, <a href="http://vermus.blogspot.ru/2013/12/debian-cubietruck-cubieboard-3-nand.html">как</a> мы <a href="http://vermus.blogspot.ru/2013/12/debian-cubietruck-cubieboard-3.html">устанавливали</a> систему? Позже мы поставили <a href="http://vermus.blogspot.ru/2014/01/1-wire.html">rsyslod</a>.
<br />
<br />
Ищем # whereis owserver , чтобы запустить его не в режиме сервиса , а в <a href="http://owfs.org/index.php?page=debug">консоли</a>.
<br />
<br />
<pre class="xml" name="code">#/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
</pre>
<br />
<br />
И снова пусто. Но не только <a href="http://owfs-developers.1086194.n5.nabble.com/no-stderr-syslog-output-owserver-2-8p15-debian-wheezy-td9839.html">у нас</a>. Похоже, что в deb пакете owfs логирование выключено.
<br />
<br />
Посему удаляем owfs (сохраним init.d скрипты и owfs.conf - хотя они удалиться не должны). Качаем версию <a href="http://owfs.org/index.php?page=download">посвежее</a>. Распаковываем tar -xvzf... <a href="http://owfs.org/index.php?page=building-under-ubuntu">Устанавливаем</a> необходимое для компиляции и сборки.
<br />
<br />
<pre class="xml" name="code">#apt-get install autoconf libtool libusb-dev libfuse-dev make ed
#cd /usr/src/owfs-2.9p1
#./configure --help
#/owfs-2.9p1# autoreconf -i
</pre>
<br />
Я сконфигурировал следующим образом (также можно добавить опцию --enable-owtraffic Enable bus traffic reports (default false) - очень интересная опция, дающая возможность отслеживать трафик в самой 1-wire сети):
<br />
<br />
<pre class="xml" name="code">#./configure --enable-debian --disable-owftpd --disable-owperl --disable-owphp --disable-parport --disable-owpython
# make -j4
# make install
</pre>
<br />
По умолчанию все устанавливается в директорию /opt/owfs/ . Сделаем линк в /usr/bin , что бы было проще использовать и не переписывать скрипты запуска.
<br />
<br />
<pre class="xml" name="code"># for p in owfs owserver owhttpd owftpd owread owwrite owdir ; do ln -sf /opt/owfs/bin/$p /usr/bin/$p ; done</pre>
<br />
Пробуем запускать:
<br />
<br />
<pre class="xml" name="code">/usr/bin/owserver --debug --error_level 9 --error_print 2 --foreground -c /etc/owfs.conf --pid-file /var/run/owfs/owserver.pid
</pre>
<br />
Если все хорошо, перезапускаем сервер с помощью init скрипта и смотрим syslog. Отлично! Теперь укажем всем клиентским приложениям использовать tcp сервер (owserver) для работы, ибо usb устройство уже занято им (то есть все приложения <a href="http://vermus.blogspot.ru/2013/12/1-wire-ds9490r-cubietruck-1-wire-ds2401.html">пакета owfs</a> должны работать через owserver - если он запущен, либо по одиночке). Пропишем в конфиг (он должен автоматически подхватываться (ключ -c) всеми init.d скриптами пакета owfs, которые у нас остались после установки deb пакета из репозитория):
<br />
<br />
<pre class="xml" name="code"># With this setup, any client (but owserver) uses owserver on the
# local machine...
! server: server = localhost:4304
</pre>
<br />
В конфиге программы с репозитория эта строчка уже указана.<br />
<br />
Но скрипта для приложения (не пакет) owfs в init.d нет (вообще странный пакет в репозитории дебиана - логов нет, управление не понятно, такое ощущение, что делал человек, плохо знакомый с owfs). Можем сделать на основе скрипта owhttpd и запускаем:
<br />
<br />
<pre class="xml" name="code"># /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
</pre>
<br />
Смотрим работающие логи.Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com0tag:blogger.com,1999:blog-4797167376881538347.post-4302266875306857592014-01-26T12:31:00.000+04:002014-01-26T12:33:46.748+04:00Тестируем жесткие диски в debian/ubuntuЧтобы не забыть.<br /><br />
<pre class="xml" name="code">
# 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
</pre>
<br /><br />
Проверим kern.log , позиции связанные с ata рассмотреть.
<br /><br />
Быстрый опрос диска на предмет живучести, с предсказанием отказа диска в ближайшие 24 часа
<pre class="xml" name="code">
sudo smartctl -H /dev/sda
</pre>
Лучшее описание параметров <a href="http://www.ixbt.com/storage/hdd-smart-testing.shtml">здесь</a>. На что стоит обратить внимание:<br />
Attribute 04 (4) Start/Stop Count (Количество циклов запуск/останов шпинделя) <br />
Attribute 05 (5) Reallocated Sector Count (Количество переназначенных секторов)<br />
Attribute 09 (9) Power On Hours Count (Количество отработанных часов)<br />
Attribute 0C (12) Power Cycle Count (Количество полных циклов запуска/останова) <br />
Attribute C2 (194) Temperature (Температура диска)<br />
Spin Up Time и Spin Retry Count - изменение значения может означать проблемы с питанием или с мотором. <br />
Current Pending Sector Count - число "кандидатов" в ремапы. <br />
Offline Scan Uncorrectable Count - число ошибок, обнаруженных при Offline самотесте (запускается автоматически, когда нет обращений к диску) <br />
UltraDMA CRC Error Rate - изменение значения может означать плохой контакт в сигнальном кабеле (между MB и HDD).<br />
<br />
На остальное смотреть не обязательно, в поле raw может быть написано все что угодно и для каждого производителя по своему (в разных системах исчисления и т.д.).
<br /><br />
"Следует отметить, что в винчестерах отдельных производителей Raw_Read_Error_Rate и Seek_Error_Rate параметры достигают максимума и обнуляютя несколько раз в день. Это связанно с политикой некоторых производителей в отношении SMART: в эти параметры пишутся все ошибки, а остальные производители только те, что не смог отловить контроллер." <a href="http://mydebianblog.blogspot.com/2007/11/blog-post.html">(с)</a><br /><br />
Current_Pending_Sector - число кандидатов на Reallocate, если сектор успешно читается повторно, то он убирается из списка «плохих» секторов, параметр Current_Pending_Sector уменьшается а Reallocate не происходит.<br />
Изменение счётчика Current_Pending_Sector без Reallocate может быть из-за неправильного температурного режима накопителя.<br /><br />
Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com0tag:blogger.com,1999:blog-4797167376881538347.post-35880254467228945192014-01-21T21:21:00.001+04:002014-01-21T21:36:54.931+04:00Резервная копия в сети, запуск по расписанию, шифрование (debian)В общем, опять. Надо сделать бекап сайта (debian) или чего угодно, вcтречаем:
<br />
<br />
Резервная копия в сети, запуск по расписанию, шифрование. А теперь по-английски: Backup, mysqldump, yandex-disk, cron, gpg.
<br />
<br />
1. Устанавливаем <a href="http://habrahabr.ru/company/yandex/blog/191446/">клиент yandex-disk</a>.
<br />
<br />
2. Скрипт сохранения и шифрования.
<br />
<br />
<pre class="xml" name="code">#!/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"
</pre>
<br />
<br />
--batch --yes может даже лишнее. Но пригодится, если у вас одно и тоже имя для файла бекапа.
<br />
<br />
3. Пишем правило для crontab. Если вы путаетесь в параметрах crontab есть отличная вещь под названием <a href="http://cronwtf.github.io/">cronWTF</a>. :)
<br />
<br />
4. <a href="http://ru.wikipedia.org/wiki/GnuPG">gpg</a> для windows <a href="http://code.google.com/p/cryptophane/downloads/list">здесь</a>.
<br />
<br />
Удаления старых файлов пока нет, так как после удаления на клиенте файлы остаются в корзине на сервере яндекс диска и занимают место и их надо все равно удалять вручную.Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com0tag:blogger.com,1999:blog-4797167376881538347.post-63102032879447515742014-01-20T22:39:00.003+04:002014-01-24T10:42:58.649+04:00Получение данных через интернет или сеть в OpenHAB. Использование Oracle Java 1.7Температура дома <a href="http://vermus.blogspot.ru/2014/01/openhab_16.html">у нас есть</a>. Пока у меня нет внешней температуры, ее можно получить в интернете. Сделать это очень просто используя <a href="https://github.com/openhab/openhab/wiki/Http-Binding">http binding</a>. В демо есть пример.<br />
<br />
Итак, для начала попробуем использовать пример с демо. Ищем свой yahoo <a href="http://www.flickr.com/places/info/23424936">woeid</a>. <br />
<br />
Пишем в sitemap :<br />
<br />
<pre class="xml" name="code">Frame label="Погода" {
Text item=Yahoo_Temperature {
Frame {
Text item=Yahoo_Temp_Max
Text item=Yahoo_Temp_Min
}
Frame {
Chart item=Yahoo_Chart period=h refresh=10000
}
}
}
</pre>
<br />
<br />
Пишем в items : <br />
<br />
<pre class="xml" name="code">Group Yahoo_Chart (Weather)
Number Yahoo_Temperature "Температура на улице yahoo [%.1f °C]" <temperature> (Yahoo_Chart) { http="<[http://weather.yahooapis.com/forecastrss?w=_тут ваш woeid_&u=c:60000:XSLT(yahoo_weather_temperature.xsl)]" }
Number Yahoo_Temp_Max "Сегодня максимум [%.1f °C]" <temperature> (Yahoo_Chart)
Number Yahoo_Temp_Min "Сегодня минимум [%.1f °C]" <temperature> (Yahoo_Chart)
</pre>
<br />
<br />
Загляните в yahoo_weather_temperature.xsl - это шаблон для извлечения данных из возращенного xml. <br />
<br />
Сейчас мы видим, что item Yahoo_Temp_Max и Yahoo_Temp_Min не привязаны к источнику данных. Откуда же их брать? Смотрим <a href="https://github.com/openhab/openhab/wiki/Rules">demo.rules</a>, а также <a href="https://github.com/openhab/openhab/wiki/Actions">документацию здесь</a> и прописываем себе тоже в файл home.rules:
<br />
<br />
<pre class="xml" name="code">
import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
rule "Update max and min temperatures"
when
Item Yahoo_Temperature changed or
Time cron "0 0 0 * * ?" or
System started
then
postUpdate(Yahoo_Temp_Max, Yahoo_Temperature.maximumSince(now.toDateMidnight).state)
postUpdate(Yahoo_Temp_Min, Yahoo_Temperature.minimumSince(now.toDateMidnight).state)
end
</pre>
<br />
<br />
Ну и последнее, сохранение. Добавим в rrd4j.persist:
<br />
<pre class="xml" name="code">Weather*, PersistTemp* : strategy = everyMinute, restoreOnStartup
</pre>
Перезапускаем сервер и я получил ошибку в логах:
<br />
<pre class="xml" name="code"> Executing startup rule 'Startup'
22:32:27.859 ERROR o.e.x.x.s.XbaseScopeProvider[:189]- error during scoping
com.google.inject.ProvisionException: Guice provision errors:
1) Error injecting constructor, java.lang.NullPointerException: null key
</pre>
<br />
<br />
<b>Ошибка решается установкой <a href="https://groups.google.com/forum/#!msg/openhab/ZsPLjTiV5I8/-uZv4ba3ovkJ">Oracle Java</a>.
</b><br />
<br />
Удаляем OpenJDK, <a href="http://www.webupd8.org/2013/12/oracle-java-ppa-updated-with-arm-support.html">устанавливаем Oracle Java</a> (инсталлер качает oracel java с интеренета).
<br />
<br />
<pre class="xml" name="code"># /etc/init.d/openhab stop
# apt-get remove icedtea-6-jre-jamvm
# apt-get autoremove
# echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu precise main" | tee -a /etc/apt/sources.list
# echo "deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu precise main" | tee -a /etc/apt/sources.list
# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys EEA14886
# apt-get update
# apt-get install oracle-java7-installer
# java -version
java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) Client VM (build 24.51-b03, mixed mode)
</pre>
<br />
<br />
Вчера настроил yahoo, а сегодня сервер мне уже показывает вместо -20C реальных: -2C. Поэтому я решил не использовать погоду от yahoo. Решил добавить gismeteo, openweathermap.org и worldweatheronline.net и вычислить среднее арифметическое с показаний. Забирать температуру буду раз в полчаса, чтобы не нагружать сервер.
<br />
<br />
В общем-то, имея демо, несложно написать следующий сценарий, который пришел мне в голову (в скобках, какая часть конфигурации отвечает за действие).
<br />
<br />
<ol>
<li>Запрашиваем данные раз в полчаса с трех источников (чаще нет смысла - их обычно обновляют раз в три часа). (items)</li>
<li>Сохраняем данные раз в полчаса с каждого ресурса. (persist)</li>
<li>Вычисляем среднюю температуру после обновления хотя бы одного источника (rules)</li>
<li>Вычисляем максимальную и минимальную температуру после обновления средней температуры (rules)</li>
<li>Сохраняем среднюю, максимальную и минимальную температуру при их обновлении (everyChange в persist)</li>
<li>Выводим среднюю температуру, а также график средней, минимальной и максимальной (аналогично как в демо)</li>
</ol>
<br />
<b>Update.</b> <strike>Тут обнаружилась проблема (версия openHAB 1.4 - графики не выводятся, если данные сохранены реже, чем раз в минуту. Поэтому сохраняем раз в минуту пока.</strike> В общем, это не проблема, а фича. <a href="http://code.google.com/p/openhab/wiki/rrd4jPersistence">rrd</a> имеет шаг (step) и сердцебиение (heartbeat). Шаг - время обновления базы rrd, сердцебиение - время в течении которого данные сохраняются. То есть, если мы не попадаем в heartbeat (сохраняем реже) - <a href="http://apfelboymchen.net/gnu/rrd/create/">данные</a> не сохраняются! heartbeat в openhab забит жестко (по крайней мере, пока) - и составляет 60 секунд. Поэтому лучше всего сохранять не реже 1 минуты. Шаг, насколько я понял, это параметр во время которого rrd принимает решение о хранении данных. В openhab оно настроено так:
<br />
<br />
<pre class="xml" name="code">
rrdDef.addArchive(function, 0.5, 4, 360); // one day (granularity 4 min)
rrdDef.addArchive(function, 0.5, 15, 644); // one week (granularity 15 min)
rrdDef.addArchive(function, 0.5, 60, 720); // one month (granularity 1 hour)
rrdDef.addArchive(function, 0.5, 720, 730); // one year (granularity 12 hours)
rrdDef.addArchive(function, 0.5, 10080, 520); // ten years (granularity 7 days)
</pre>
<br />
<br />
То есть, после первого дня хранения, точность данных меняется на 4 минуты, после одной недели на 15 минут, одного месяца на на 1 час и так далее...
<br />
<br />
В принципе, все шаги очевидны, единственно, я немного затормозил на этапе вычисления средней температуры. Значения надо предварительно перевести в DecimalType:
<br />
<pre class="xml" name="code">rule "Update average temp"
when
Item Owm_Temperature changed or
Item Gismeteo_Temperature changed or
Item Wwo_Temperature changed or
System started
then
var Number owm = Owm_Temperature.state as DecimalType
var Number gismeteo = Gismeteo_Temperature.state as DecimalType
var Number wwo = Wwo_Temperature.state as DecimalType
postUpdate( Average_Temperature, ( owm + gismeteo + wwo ) / 3 )
end
</pre>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeLI5nz2fhXTA1dMOBJbj1IGVs1hbUlTUWYbyMpniw4VYFoRkDoiKOyKt4Eai_cAW-jvQkvgm_rRhQD4-ES8cWkga42Ed0WXDabAheShtgThoyx6sBPGk7EXTrVYXAARP-KYDMeW1K/s1600/temp_outside.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeLI5nz2fhXTA1dMOBJbj1IGVs1hbUlTUWYbyMpniw4VYFoRkDoiKOyKt4Eai_cAW-jvQkvgm_rRhQD4-ES8cWkga42Ed0WXDabAheShtgThoyx6sBPGk7EXTrVYXAARP-KYDMeW1K/s320/temp_outside.png" /></a></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK1j-OYwhQ5_mzw1RPrB1QkyWNDMjKDOQ6RkcRy0LVf12lvMg7jqLEOWF9fd_r32JRflzGD4n1wlSoBmtWfsN1RCT6gFjbeszrSqkjTyEpMRQPdrRHGvUPq3_LIuUYkk4-AH07K8Id/s1600/chart.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK1j-OYwhQ5_mzw1RPrB1QkyWNDMjKDOQ6RkcRy0LVf12lvMg7jqLEOWF9fd_r32JRflzGD4n1wlSoBmtWfsN1RCT6gFjbeszrSqkjTyEpMRQPdrRHGvUPq3_LIuUYkk4-AH07K8Id/s320/chart.png" /></a></div>
<br />
<br />
ps. Заодно поменяем ntp сервер для даты в файле конфигурации. Я люблю pool.ntp.org.Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com8tag:blogger.com,1999:blog-4797167376881538347.post-34690059355862744942014-01-16T00:05:00.000+04:002014-01-21T22:19:40.242+04:00Сохранение данных OpenHAB. ГрафикиОтлично, <a href="http://vermus.blogspot.ru/2014/01/openhab.html">температура</a> у нас есть.
<br />
<br />
Кстати, теперь можно протестировать и <a href="https://play.google.com/store/apps/details?id=org.openhab.habdroid">android приложение</a>, <a href="https://openhab.ci.cloudbees.com/job/HABDroid/">тут самая</a> последняя версия. У меня на планшете заработало сразу, единственный момент, надо указывать не полный url, а вида http(s)://server:port/ , выбор sitemap происходит в самом приложении, а если он один, то и запускается сразу. К сожалению, работает на android только начиная с версии 4.0.3.
<br />
<br />
Переходим к теме. Для того чтобы заиметь график температуры ее надо сначала сохранить.
<br />
<br />
Изучаем <a href="https://github.com/openhab/openhab/wiki/Persistence">документацию</a> по Persistence (сохранение состояния) и rrd4j. Процитирую слова разработчика: "As said above, I would recommend rrd4j", тем не менее OpenHAB поддерживает больше число мест сохранения данных (db4o, sql и др.), которые могут работать одновременно. Для начала нам нужен org.openhab.persistence.rrd4j-1.3.1.jar в папке addons.
<br />
<br />
<b>Конфигурация</b>.
<br />
<br />
Для редактирования конфигурации <a href="https://github.com/openhab/openhab/wiki/Persistence">советуют использовать</a> openHAB Designer, так как там есть проверка и автодополнение синтаксиса. Основная идея файла конфигурации, сообщить OpenHAB, <i>какие</i> данные и <i>когда</i> сохранять. Для для того, чтобы определить "когда" сохранять данные используют слово "strategies" в файле конфигурации. Синтаксис:
<br />
<br />
<pre class="xml" name="code">Strategies {
<strategyname1> : "<cronexpression1>"
<strategyname2> : "<cronexpression2>"
...
default = <strategynamex>, <strategynamey>
}
</pre>
<br />
<br />
Следующие "стратегии" предварительно сконфигурированы, их можно не описывать, но можно прописать в default:<br />
<br />
<ul>
<li>everyChange: сохранять состояние при его изменении</li>
<li>everyUpdate: сохранят состояние при его обновлении, даже если значение не изменилось</li>
<li>restoreOnStartup: если состояние не определено при запуске, последнее сохраненное значение будет загружено и элемент будет проинициализирован им. Это очень удобно для всех "виртуальных" устройств, которые не имеют связи с реальным железом. (например "Presence").
</li>
</ul>
<br />
Структура описания элементов для сохранения.
<br />
<br />
<pre class="xml" name="code">Items {
<itemlist1> [-> "<alias1>"] : [strategy = <strategy1>, <strategy2>, ...]
<itemlist2> [-> "<alias2>"] : [strategy = <strategyX>, <strategyY>, ...]
...
}
</pre>
<br />
<br />
где <itemlist> разделенный запятыми список следующих опций:<br />
<ul>
<li>* - эта линия должна применяться для всех элементов в системе. Пример: <br />
// persist all items once a day and on every change and restore them from the db at startup <br />
* : strategy = everyChange, everyDay, restoreOnStartup</li>
<li> <itemName> - одиночный элемент (его имя). Это может быть группа, но в таком случае сохранится только значение группы, не значения элементов.</li>
<li> <groupName>* - все члены группы будут сохранены, но не сама группа. если стратегия не предоставлена, используется стратегия по умолчанию, описанная в первой в используемой секции. Как опция, может быть предоставлен псевдоним, если сервис сохранения требует специального имени (например таблица в БД и т.п.).</li>
</ul>
<br />
Ну что же попробуем сохранить температуру. Создадим группу. Назовем ее PersistTemp. Добавляем в Items:<br />
<br />
<pre class="xml" name="code">Group PersistTemp (All)
/* Indoor Temperatures */
Number Temperature_Hall "Температура [%.1f °C]" <temperature> (Hall, PersistTemp) { onewire="28.1A821E040000#temperature" }
</pre>
<br />
Пишем rrd4j.persist (не забудьте про addons/org.openhab.persistence.rrd4j-1.3.1.jar ):
<br />
<br />
<pre class="xml" name="code">// persistence strategies have a name and a definition and are referred to in the "Items" section
Strategies {
// for rrd charts, we need a cron strategy
everyMinute : "0 * * * * ?"
}
Items {
// let's only store temperature values in rrd
PersistTemp* : strategy = everyMinute, restoreOnStartup
}
</pre>
<br />
<br />
Обратите внимание, что крон тут не стандартный и начинается с секунд - <a href="http://www.quartz-scheduler.org/documentation/quartz-2.1.x/tutorials/tutorial-lesson-06">подробнее здесь</a>.
Если все ок, смотрим директорию openHAB/etc/rrd4j/ . Там лежат файлы с данными.
<br />
<br />
Данные мы сохранили, а что делать с ними дальше? Изучаем демо, там есть <b>график температуры</b>.
<br />
<br />
Меняем sitemap. Группа в sitemap по умолчанию синхронизируется с элементами в группе в Items (довольно не очевидно и не очень понятно вначале, тем более в документации об этом не написано вроде). Теперь у нас группа в sitemap Hall будет состоять из Item и Chart, поэтому будет перезаписана правилами sitemap. В примере в демо такие "вручную описанные" блоки имеют вид "Text label="Widget Overview" icon="chart" {}". Но я оставил группу - и так работает, добавляем (пояснение по параметрам ниже):
<br />
<br />
<pre class="xml" name="code">Group item=Hall label="Зал" icon="office"
{
Frame {
Text item=Temperature_Hall
Chart item=Temperature_Hall period=D refresh=10000
Chart item=Temperature_Hall period=W refresh=10000
}
}
</pre>
<br />
<br />
Заходим и не работает график. Копируем url изображения и переходим на него в новой вкладке. Ошибка 500 Probable fatal error:No fonts found.
<br />
<br />
<pre class="xml" name="code"># apt-get install ttf-bitstream-vera ttf-dejavu ttf-liberation ttf-linux-libertine xfonts-terminus ttf-inconsolata
# /etc/init.d/openhab restart
</pre>
<br />
<br />
Кстати, <a href="http://vermus.blogspot.ru/2014/01/1-wire.html">напоминаю</a>, у меня OpenHAB и 1-wire сеть, которые работают на cubietruck.
<br />
<br />
Небольшая <a href="http://code.google.com/p/openhab/wiki/Charts">информация</a> по графикам. Параметры, которые можно передавать:
<br />
<br />
w: ширина, опция, по умолчанию 480 пикселей<br />
h: высота, опция, по умолчанию 240<br />
period: время по оси X. Значения могут быть h,4h,8h,12h,D,3D,W,2W,M,2M,4M,Y - параметр опциональный, по умолчанию "D", то есть за последние 24 часа.<br />
items: разделенные запятыми элементы (items).<br />
или<br />
groups: разделенные запятыми группы.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxN5qAtlIwu0x0HSe8cn1s9nu0Mxneomj9aQbY92qU0F7-JMskXerG3tFT7t_u1bEcJ_f-4NdktaLzIxn_RVY3L8j5OXjZzikoQGrEJxpEZbbfPxQzv9Mcq-KswtVPz99zAx22AQrE/s1600/charts.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxN5qAtlIwu0x0HSe8cn1s9nu0Mxneomj9aQbY92qU0F7-JMskXerG3tFT7t_u1bEcJ_f-4NdktaLzIxn_RVY3L8j5OXjZzikoQGrEJxpEZbbfPxQzv9Mcq-KswtVPz99zAx22AQrE/s320/charts.png" /></a></div>
Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com9tag:blogger.com,1999:blog-4797167376881538347.post-72511951818445593262014-01-14T13:16:00.002+04:002014-02-04T14:32:48.543+04:00Знакомство с OpenHABВ <a href="http://vermus.blogspot.ru/2014/01/openremote.html">прошлой заметке</a> я решил сменить платформу для управления умным домом.
<br />
<br />
Архитектура <a href="https://github.com/openhab/openhab/wiki">OpenHAB</a>:
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdoIgJvgCWGm77QH4o4YKESPdceFMHgy-GU2m5j0JhV7ZwV030CICRZbtH1ORPfuWFZzMTIFmSYItbPBq35rCpZQ3U3jpCDBsPKXXGUiiWYL9t3t1hN9hf7gBT27N7MgzcRbYz-0EI/s1600/architecture.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdoIgJvgCWGm77QH4o4YKESPdceFMHgy-GU2m5j0JhV7ZwV030CICRZbtH1ORPfuWFZzMTIFmSYItbPBq35rCpZQ3U3jpCDBsPKXXGUiiWYL9t3t1hN9hf7gBT27N7MgzcRbYz-0EI/s320/architecture.png" /></a></div>
<br />
<br />
OpenHAB состоит из двух частей райнтайма (аналог контроллера в openremote, ну или просто сервер) и дизайнера. В принципе, дизайнером некоторые не пользуются - правят конфигурацию вручную.
<br />
<br />
Удаляем скрипт OpenRemote из автозагрузки.
<br />
<br />
<pre class="xml" name="code"># update-rc.d openremote remove
</pre>
<br />
Java у нас уже стоит.<br />
<br />
<b>Runtime</b><br />
<br />
Качаем <a href="http://code.google.com/p/openhab/downloads/list?can=3">runtime</a> (проверьте версию, у меня на данный момент 1.3.1).
<br />
<br />
<pre class="xml" name="code"># wget http://openhab.googlecode.com/files/openhab-runtime-1.3.1.zip
# wget https://openhab.googlecode.com/files/openhab-addons-1.3.1.zip
# unzip openhab-runtime-1.3.1.zip -d /srv/openHAB
# unzip openhab-addons-1.3.1.zip -d oh-addons
</pre>
<br />
Копируем необходимые addons в одноименную /srv/openHAB/addons. Я скопировал пока такие:
<br />
<br />
<pre class="xml" name="code"># ls -l
-rw-rw-r-- 1 root root 38725 Sep 19 00:25 org.openhab.action.mail-1.3.1.jar
-rw-rw-r-- 1 root root 1246014 Sep 19 00:26 org.openhab.action.xmpp-1.3.1.jar
-rw-rw-r-- 1 root root 31270 Sep 19 00:29 org.openhab.binding.http-1.3.1.jar
-rw-rw-r-- 1 root root 23164 Sep 19 00:31 org.openhab.binding.ntp-1.3.1.jar
-rw-rw-r-- 1 root root 29468 Sep 19 00:36 org.openhab.binding.onewire-1.3.1.jar
-rw-rw-r-- 1 root root 18734 Sep 19 00:46 org.openhab.persistence.exec-1.3.1.jar
-rw-rw-r-- 1 root root 19373 Sep 19 00:46 org.openhab.persistence.logging-1.3.1.jar
-rw-rw-r-- 1 root root 630764 Sep 19 00:46 org.openhab.persistence.rrd4j-1.3.1.jar
-rw-rw-r-- 1 root root 126 Aug 31 03:03 README
</pre>
<br />
Обратите внимание, org.openhab.binding.owserver-1.3.1.jar используется для железки под названием EDS OWServer . Нам же нужен org.openhab.binding.onewire-1.3.1.jar .
<br />
Не забудьте, <a href="http://vermus.blogspot.ru/2013/12/1-wire-ds9490r-cubietruck-1-wire-ds2401.html">у нас уже установлен</a> owfs с его owserver.
<br />
<br />
Копируем файл configurations/openhab_default.cfg в configurations/openhab.cfg и правим.
<br />
<br />
<i>Из чего состоит openHAB Runtime?</i><br />
<i><br /></i>
1. Асинхронная шина событий.<br />
<br />
Все узлы, которые не сохраняют свое состояние, должны информировать другие узлы о событиях, а также обновляться другими узлами реакцией на внешние события.<br />
Существуют преимущественно два типа событий:<br />
<br />
<ul>
<li>Команды, которые вызывают действие или изменение состояния некоторого элемента/устройства.</li>
<li>Обновления статусов, которые информируют об изменении статуса некоторых элементов/устройств (часто в ответ на команду).</li>
</ul>
<br />
2. Что такое элементы шины? Это items. Кто может запускать события? Это sitemap и rules.<br />
<br />
Items - это представление наших устройств, их значения можно менять с помощью правил или через Sitemap. Sitemap - графическое представление и структура. Rules, соответственно правила.<br />
<br />
Вот еще одна красивая картинка шины событий openHAB:
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCq7brYT6vYe66nUBfXSRvMkw9tFWGCNUH7nFGScsYZf_3Ub1bLT11apeLv9nrTv79A8TPfOsIQeNroYILmsn8dVAT7YW6ZaScTzueHC2J4JR3vlQjwZsFHrLsOBmyEy0YvuWBFgGE/s1600/events.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCq7brYT6vYe66nUBfXSRvMkw9tFWGCNUH7nFGScsYZf_3Ub1bLT11apeLv9nrTv79A8TPfOsIQeNroYILmsn8dVAT7YW6ZaScTzueHC2J4JR3vlQjwZsFHrLsOBmyEy0YvuWBFgGE/s320/events.png" /></a></div>
<br />
<br />
<b>Дизайнер</b><br />
<br />
Так как у нас сервер без иксов и графики, то дизайнер мы будем использовать на машине с windows.<br />
Качаем дизайнер, запускаем и получаю ошибку Failed to load the JNI shared library "c:\soft\jdk1.7\\bin\..\jre\bin\server\jvm.dll". Это потому, что Дизайнер (основанный на eclipse) работает в 32 битной среде. Качаем <a href="http://www.oracle.com/technetwork/java/javase/downloads/jre7-downloads-1880261.html">32 (x86) битную яву</a> и ставим.
<br />
<br />
Меняем конфиг (openHAB-Designer.ini) дизайнера.
<br />
<br />
<pre class="xml" name="code">-vm C:/soft/jdk1.7_32/bin/javaw.exe
</pre>
<br />
И запускаем. Также скачаем папку configuration с сервера (напомню, я использую <a href="http://winscp.net/eng/docs/lang:ru">winscp</a>). Укажем ее, как папку конфигурации (например c:\temp\openhab-demo-configuration-1.3.1\configurations\). Теперь скачем <a href="https://code.google.com/p/openhab/downloads/detail?name=openhab-demo-configuration-1.3.1.zip">демо</a> конфигурацию с сайта на рабочую машину, чтобы было на что ориентироваться.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCqEnmrx3ZWTtqrnQYCaiaSH3iZkktd_Hqxl7ZNCb11FGF8S7zEciXRfa5yF3YHK0qzt71wBQzSlmGZzVuVt-2CobwGy3ZVKAco8KbOpDHyHl9sc5JG-eDRMexB7H1I0k-h2UfMdWa/s1600/opendeisgner+folder.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCqEnmrx3ZWTtqrnQYCaiaSH3iZkktd_Hqxl7ZNCb11FGF8S7zEciXRfa5yF3YHK0qzt71wBQzSlmGZzVuVt-2CobwGy3ZVKAco8KbOpDHyHl9sc5JG-eDRMexB7H1I0k-h2UfMdWa/s320/opendeisgner+folder.png" /></a></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXrrIwJjdWSYNp73pFJIDiEUiMd_wVhp-AyktXLv17ri_KOvW-NnVFIk4OX_R5_o1lPRUo6dIAgea751dWPO9Xy8Cz2TeQXsvoRUdmTGW0wQ6DvrRzbWOo70LWXS_L1wiPD4JwiihD/s1600/openHAB+designer.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXrrIwJjdWSYNp73pFJIDiEUiMd_wVhp-AyktXLv17ri_KOvW-NnVFIk4OX_R5_o1lPRUo6dIAgea751dWPO9Xy8Cz2TeQXsvoRUdmTGW0wQ6DvrRzbWOo70LWXS_L1wiPD4JwiihD/s320/openHAB+designer.png" /></a></div>
<br />
<br />
Поковырявшись немного в дизайнере, кроме всплывающих подсказок (Ctrl+Space), ничего не нашел. Поэтому для начала им воспользуемся, а потом в принципе нужно будет прикрутить <a href="https://github.com/openhab/openhab/wiki/Syntax-Highlighting-for-external-editors">подсветку синтаксиса для mc</a>.
<br />
<br />
Начнем. Создаем файл sitemap, например home.sitemap . Честно говоря, в дизайнере даже этого нет. :) Но создать можно нажав ctrl+N (там проблема с директориями - они не отображаются - но разобраться можно). Пишем в файле "sitem" и нажимаем Ctrl+Space. Выбираем шаблон sitemap. И у нас появляется нечто вроде этого:
<br />
<br />
<pre class="xml" name="code">sitemap name label="label" {
}
</pre>
<br />
<br />
Читаем <a href="https://github.com/openhab/openhab/wiki/Explanation-of-Sitemaps">документацию по sitemap</a>, чтобы понять, что же нам делать дальше. Удобно сравнивать, что у нас в demo.sitemap и в <a href="http://demo.openhab.org:8080/openhab.app?sitemap=demo">онлайн демо</a>. Быстро понимаешь, что к чему.
<br />
Разобьем по комнатам (у меня, к сожалению, этажей нет).
<br />
<br />
<pre class="xml" name="code">sitemap name label="Дом" {
Frame {
Group item=Hall label="Зал" icon="office"
}
Frame label="Дата" {
Text item=Date
}
}
</pre>
<br />
<br />
Иконки хранятся тут openHAB/webapps/images. Скачать дополнительные можно <a href="http://graphicdesignjunction.com/2012/05/750-ui-design-vector-icons-pack/">тут</a>.
<br />
<br />
Создадим новый файл: Items/home.items, прочитав <a href="https://github.com/openhab/openhab/wiki/Explanation-of-Items">документацию по Items</a>. Так как у нас 1-wire, читаем документацию по связи с openHAB <a href="https://github.com/openhab/openhab/wiki/One-Wire-Binding">тут</a>, и правим файл конфигурации в секции OneWire Binding (собственно говоря я только прописал ip - onewire:ip=127.0.0.1). Формат записи item:
<br />
itemtype itemname ["labeltext"] [<iconname>] [(group1, group2, ...)] [{bindingconfig}]
<br />
<br />
<pre class="xml" name="code">Group All
Group Hall (All)
/* Indoor Temperatures */
Number Temperature_Hall "Температура [%.1f °C]" <temperature> (Hall) { onewire="28.1A821E040000#temperature" }
/* NTP binding demo item */
DateTime Date "Дата [%1$tA, %1$td.%1$tm.%1$tY]" <calendar> { ntp="Europe/Moscow:ru_RU" }
</pre>
<br />
<br />
Копируем созданные файлы, исправленный openhab.cfg на сервер.
<br />
Меняем владельца папки с сервером на обычного пользователя и запускаем:
<br />
<br />
<pre class="shell" name="code">$/srv/openHAB$ ./start.sh
UnknownHostException:
</pre>
<br />
<br />
И получаем ошибку. Ну я получил. :) Прописать надо имя хоста в /etc/hosts на 127.0.0.1.
Запускаем еще раз.
<br />
<br />
<pre class="shell" name="code">$ ./start.sh
Launching the openHAB runtime...
osgi> 23:20:46.100 INFO o.o.c.internal.CoreActivator[:92] - openHAB runtime has been started (v1.3.1).
.........
23:21:17.223 INFO o.o.u.w.i.s.WebAppServlet[:99] - Started Classic UI at /openhab.app
23:21:29.349 INFO o.o.c.s.AbstractActiveService[:189] - NTP Refresh Service has been started
23:21:29.655 INFO o.o.c.s.AbstractActiveService[:189] - HTTP Refresh Service has been started
</pre>
<br />
Довольно долгий запуск таки. Заходим http://openhab-srv:8080/openhab.app?sitemap=home .
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeSgFoOX0beZSE5y4do8C8AFfBQxhyphenhyphenCnZQjXOZYfrtnZu32HIdbb81YeCzAIRLA3CggXyUF9ua_D9lWrFyO9ls4ZOVyGB2L5uJVazOfE2FjECTF6aQbx3GN1tH6sEkR9GS2CslzBMu/s1600/openHAB.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeSgFoOX0beZSE5y4do8C8AFfBQxhyphenhyphenCnZQjXOZYfrtnZu32HIdbb81YeCzAIRLA3CggXyUF9ua_D9lWrFyO9ls4ZOVyGB2L5uJVazOfE2FjECTF6aQbx3GN1tH6sEkR9GS2CslzBMu/s320/openHAB.png" /></a></div>
<br />
<br />
Дата на английском. Смотрим локали:
<br />
<br />
<pre class="shell" name="code"># locale -a
C
C.UTF-8
en_US.utf8
POSIX
</pre>
Запускаем, выбираем там ru_RU.UTF-8 UTF-8 и перезапускаем сервер.:
<br />
<pre class="shell" name="code">$ sudo dpkg-reconfigure locales
$ export LANG=ru_RU.UTF-8
или
$ sudo echo "LANG=en_US.UTF-8" > /etc/default/locale
</pre>
<br />
<br />
Ну вот немного обрусевший вид.
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu3pni3SEij4b0CKVHEW67FF9Kc9C7pi1av1PHc7UQU5VzhNdNjsRnH6LKGSghtidA6NvjVFyTstWv8OB5gKZa7oVjKcPzXKJISgjyHFEQacJjBr2pq2XvCf0jvf1M4DzAfQK3mrk6/s1600/openHABrus.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu3pni3SEij4b0CKVHEW67FF9Kc9C7pi1av1PHc7UQU5VzhNdNjsRnH6LKGSghtidA6NvjVFyTstWv8OB5gKZa7oVjKcPzXKJISgjyHFEQacJjBr2pq2XvCf0jvf1M4DzAfQK3mrk6/s320/openHABrus.png" /></a></div>
<br />
<br />
Если что-то не работает, можно посмотреть более детальные логи, прописав в logback.xml <logger level="INFO" name="org.openhab"> на <logger level="DEBUG" name="org.openhab"> и <logger level="DEBUG" name="org.openhab.binding.onewire"> (для примера смотрите logback_debug.xml). Или просто запустив start_debug.sh - в этом случае сообщения смотрим прямо в консоли.
<br />
<br />
Запускаем сервер и смотрим.
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgp_4aO2zQ_2pTSxVwgPSa5mixwSqOLkZiNpVak8VpERGBWApNjVLJOBgb3yE2LnzilxieHzaPzqmI45yIK5e_o8ZkDVXD1tXg4tOcrdP9K1juFqem6TDko8iyO9UpnzdeNMkokpsGQ/s1600/temp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgp_4aO2zQ_2pTSxVwgPSa5mixwSqOLkZiNpVak8VpERGBWApNjVLJOBgb3yE2LnzilxieHzaPzqmI45yIK5e_o8ZkDVXD1tXg4tOcrdP9K1juFqem6TDko8iyO9UpnzdeNMkokpsGQ/s320/temp.png" /></a></div>
<br />
<br />
Скрипт управления и автозагрузки <a href="http://code.google.com/p/openhab-samples/wiki/Tricks#How_to_configure_openHAB_to_start_automatically_on_Linux">здесь</a> (меняем пользователя и путь).
<br />
<br />
Продолжение следует!Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com38tag:blogger.com,1999:blog-4797167376881538347.post-45832174244943017322014-01-12T18:11:00.001+04:002014-01-14T13:17:22.100+04:00Безопасность в Elastix (дистрибутив Asterisk)Пост для заметки. Во-первых, <a href="http://icluzo.livejournal.com/8971.html">прочитать это</a>. В принципе, пост наполовину оттуда - спасибо нужно говорить там :). У меня все за фаерволом, открыты только нужные upd порты (5060 и 10000-20000).
<br />
1. Закрываем доступ через web! Я сделал это внешним фаеролом. Если вы хотите попасть в web конифгуратора elastix создайте ssh туннель с другого хоста.<br />
2. Запретим гостевые вызовы, для этого в файле sip_general_custom.conf пропишем
allowguest=no
<br />
3. Баним всяких подборщиков паролей и сохраняем для восстановления правил после перезагрузки:
<br />
<br />
<pre class="xml" name="code">iptables -I INPUT -j DROP -p udp --dport 5060 -m string --string "friendly-scanner" --algo bm
iptables -I INPUT -j DROP -p udp --dport 5060 -m string --string "sipcli" --algo bm
iptables -I INPUT -j DROP -p udp --dport 5060 -m string --string "iWar" --algo bm
iptables -I INPUT -j DROP -p udp --dport 5060 -m string --string "sipsak" --algo bm
# /sbin/service iptables save
Правила брандмауэра сохраняются в /etc/sysconfig/iptables: [ OK ]
</pre>
4. Запускаем fail2ban.
<br />
<br />
touch /etc/fail2ban/filter.d/asterisk.conf
<br />
<br />
Правила <a href="http://icluzo.livejournal.com/8971.html">скопипастены</a> (нажмите view plain, чтобы скопировать по-нормальному):
<br />
<br />
<pre class="xml" name="code"># Fail2Ban configuration file
#
#
# $Revision: 251 $
#
[INCLUDES]
# Read common prefixes. If any customizations available -- read them from
# common.local
before = common.conf
[Definition]
#_daemon = asterisk
# Option: failregex
# Notes.: regex to match the password failures messages in the logfile. The
# host must be matched by a group named "host". The tag "<host>" can
# be used for standard IP/hostname matching and is only an alias for
# (?:::f{4,6}:)?(?P<host>\S+)
# Values: TEXT
#
# Asterisk 1.8 uses Host:Port format which is reflected here
failregex = NOTICE.* .*: Registration from '.*' failed for ':.*' - Wrong password
NOTICE.* .*: Registration from '\".*\".*' failed for '' - Wrong password
NOTICE.* .*: Registration from '\".*\".*' failed for '' - No matching peer found
NOTICE.* .*: Registration from '.*' failed for '<host>:.*' - No matching peer found
NOTICE.* .*: Registration from '.*' failed for '<host>:.*' - No matching peer found
NOTICE.* .*: Registration from '.*' failed for '<host>:.*' - Username/auth name mismatch
NOTICE.* .*: Registration from '.*' failed for '<host>:.*' - Device does not match ACL
NOTICE.* .*: Registration from '.*' failed for '<host>:.*' - Peer is not supposed to register
NOTICE.* .*: Registration from '.*' failed for '<host>:.*' - ACL error (permit/deny)
NOTICE.* .*: Registration from '.*' failed for '<host>:.*' - Device does not match ACL
NOTICE.* .*: Registration from '\".*\".*' failed for '<host>:.*' - No matching peer found
NOTICE.* .*: Registration from '\".*\".*' failed for '<host>:.*' - Wrong password
NOTICE.* <host> failed to authenticate as '.*'$
NOTICE.* .*: No registration for peer '.*' \(from <host>\)
NOTICE.* .*: Host <host> failed MD5 authentication for '.*' (.*)
NOTICE.* .*: Failed to authenticate user .*@<host>.*
NOTICE.* .*: <host> failed to authenticate as '.*'
NOTICE.* .*: <host> tried to authenticate with nonexistent user '.*'
VERBOSE.*SIP/<host>-.*Received incoming SIP connection from unknown peer
NOTICE.* .*: Sending fake auth rejection for device.* \(<host>:.*\)
NOTICE.* .*: Failed to authenticate device.* \(<host>:.*\)
# Option: ignoreregex
# Notes.: regex to ignore. If this regex matches, the line is ignored.
# Values: TEXT
#
ignoreregex =
</pre>
<br />
Добавляем в конфиг /etc/fail2ban/jail.conf (изменил немного, в почту слать ничего не надо, добавлены ip адреса игнорирования - внешняя статика и локальная сеть, бан изменен на пожизненный).
<br />
<br />
<pre class="xml" name="code">[asterisk-iptables]
enabled = true
filter = asterisk
action = iptables-allports[name=ASTERISK, protocol=all]
#sendmail-whois[name=ASTERISK,dest=ваш_емаил_куда_слать_сообщения_о_бане, sender=fail2ban@local]
logpath = /var/log/asterisk/full
maxretry = 10
bantime = -1
ignoreip = 127.0.0.1 XXX.XXX.XXX.XXX 192.168.0.1/24
</pre>
<br />
/etc/init.d/fail2ban start
<br />
<br />
Статус смотрим командой fail2ban-client status asterisk-iptables или # iptables -L -n (уже забанил :) )
<br />
<br />
<pre class="xml" name="code"># fail2ban-client status asterisk-iptables
Status for the jail: asterisk-iptables
|- filter
| |- File list: /var/log/asterisk/full
| |- Currently failed: 1
| `- Total failed: 16
`- action
|- Currently banned: 1
| `- IP list: 50.30.35.55
`- Total banned: 1
</pre>
<br />
Для автостарта fail2ban в файл /etc/rc.d/rc.local добавим строчку
/etc/rc.d/init.d/fail2ban start
<br />
<br />
После рестарта fail2ban или после перезагрузки все адреса сбрасываются. Поэтому можно добавить /sbin/service iptables save в крон. Я думаю раз в час будет достаточно ( /etc/crontab ):<br />
<br />
<pre class="xml" name="code">0 * * * * root /sbin/service iptables save
</pre>
Правда командой fail2ban-client status asterisk-iptables после перезагрузки забаненных мы уже не увидим. Если вы все-таки захотите видеть и чтобы fail2ban рулил сам iptables после перезагрузки, то прочитайте <a href="http://zach.seifts.us/posts/2013/07/14/how-make-fail2ban-bans-persistent">вот этот</a> пост. Защита от SIP флуда <a href="http://habrahabr.ru/company/myasterisk/blog/130325/">описана тут</a>.Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com0tag:blogger.com,1999:blog-4797167376881538347.post-87902948813051793112014-01-08T23:46:00.000+04:002014-01-09T08:46:04.436+04:00Безопасный доступ к OpenRemote<a href="http://vermus.blogspot.ru/2014/01/openremote-1-wire-owfs.html">Мы создали первое приложение в OpenRemote</a> в локальной сети. Но ясное дело , что управлять то мы хотим не только из локальной сети, а еще и через интернет. Это означает, что нам надо обеспокоиться нашей безопасностью. Ну и самые элементарные вещи это - внедрение парольной защиты и шифрование трафика между клиентом и контроллером.
<br />
<br />
<b>1. Зашифрованное соединение.</b>
<br />
<br />
Очевидно, что для шифрования трафика надо использовать <a href="http://ru.wikipedia.org/wiki/SSL#.D0.92.D0.B5.D0.B1.D1.81.D0.B0.D0.B9.D1.82.D1.8B">https</a>. Подготовим самоподписанные сертификаты в директории /home/openremote/.keystore:
<br />
<br />
<pre class="xml" name="code">$ keytool -genkey -alias tomcat -keyalg RSA -validity 3600 -keystore ~/.keystore
</pre>
<br />
Когда спросят про второй пароль его вводить не надо - вы обязаны оставить прежний (по умолчанию). Далее переходим в файл /srv/openremote/conf/server.xml и правим следующий кусок:
<br />
<br />
<pre class="xml" name="code">
<connector clientauth="false" keystorepass="changeit"
maxthreads="150" port="8443" protocol="HTTP/1.1" scheme="https"
secure="true" sslenabled="true" sslprotocol="TLS"></pre>
<br />
Внимание, мы не только его раскомментировали, но и добавили keystorePass="changeit" - пароль, который вводили при генерации сертификатов. Пробуем запускать скрипт с параметром run - так видно логи сервера. Заходим https://192.168.xx.xx:8443/webconsole/ - должно работать. Теперь закомментируем небезопасный порт 8080, чтобы протестировать клиентов.
<br />
<br />
Пробуем андроид клиент - в нем адрес контроллера оставляем, только нажимаем на кнопочку SSL в самом низу настроек. Порт указан там же. Теперь пробуем онлайн webconsole, тут по-другому. Удаляем старый адрес контроллера, вводим новый https://192.168.xx.xx:8443/controller/
<br />
<br />
<b>2. Авторизация.</b>
<br />
<br />
Хорошо, с шифрованным соединением решили. Авторизация тоже заложена в системе, но немного не явным образом. Для начала правим файл: /security/users.xml:
<br />
<br />
<pre class="xml" name="code"><?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
<role rolename="openremote"/>
<user username="vermus" password="test" roles="openremote"/>
</tomcat-users>
</pre>
<br />
<br />
Потом открываем файл webapp/controller/WEB-INF и расскоментируем следующие строки:
<br />
<pre class="xml" name="code"><!-- Constraint resource: /rest/control/* -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Control command RESTful service of Openremote Controller</web-resource-name>
<description>Control command RESTful service of Openremote Controller</description>
<url-pattern>/rest/control/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>openremote</role-name>
</auth-constraint>
</security-constraint>
<!-- Constraint resource: /rest/panel/* -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Panel identity RESTful service of Openremote Controller</web-resource-name>
<description>Panel identity RESTful service of Openremote Controller</description>
<url-pattern>/rest/panel/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>openremote</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Status command RESTful service of Openremote Controller</web-resource-name>
<description>Status command RESTful service of Openremote Controller</description>
<url-pattern>/rest/status/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>openremote</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Polling command RESTful service of Openremote Controller</web-resource-name>
<description>Polling command RESTful service of Openremote Controller</description>
<url-pattern>/rest/polling/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>openremote</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>OPENREMOTE_Controller</realm-name>
</login-config>
<security-role>
<role-name>openremote</role-name>
</security-role>
</pre>
</pre>
<br />
<br />
Заходим в webconsole и при клике на выбранной панели система спросит нас логин с паролем. Приложение для андроид (кстати, качайте последнее с сайта, в google play на данный момент 2.0.0 , который даже не поддерживает https).
<br />
<br />
Итак, мы неплохо обезопасили нашу систему, жаль что для новичков эти шаги были бы не очевидными. Плюс меня еще смущает: древняя версия openremote под андроид в гугл плей, отсутствие внятной документации, онлайновый дизайнер, отсутствие сбора данных, ориентированность на платный продукт и т.п.... <br />
В общем, я решил испробовать другую систему openhab, которая лишена всех этих недостатков, хоть в ней <a href="https://github.com/openhab/openhab/issues/438">вроде бы</a> и есть <a href="https://github.com/openhab/openhab/issues/109">проблема</a> с 1-wire. Я думаю ее можно как-то решить, кроме owserver же есть еще и owhttpd (может http binding сработает) и owfs (может можно писать в файлы локально). Хоть ее и начали писать позже openremote кстати! Но по моим наблюдениям она гораздо динамичнее развивается. В общем, будем смотреть!Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com0tag:blogger.com,1999:blog-4797167376881538347.post-44783479930792545412014-01-05T20:42:00.002+04:002014-01-07T20:00:14.693+04:00Платформа умного дома OpenRemote. Знакомство. Подключаем 1-wire через owfs.Пока я жду DS2406P+ и DS2408S+ занялся серверной и клиентской стороной <a href="http://vermus.blogspot.ru/2014/01/1-wire.html">умного дома</a>.
<br />
<br />
<a href="http://openremote.org/">OpenRemote</a> представляет из себя сервер, который получает команды от мобильного или веб приложения и дальше транслирует их другому контроллеру или серверу.
<br />
<br />
OpenRemote это:<br />
<br />
1) Сервер умного дома, работает на десятке платформ, даже на NAS Synology и Windows.<br />
<br />
2) Онлайн-cреда для разработки приложения.<br />
<br />
3) Мобильное приложение, которое загружает данные для своей работы из среды для разработки.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfHe5rcM_rzJ5LHX2lgrJknrmGqbKcJPvVWRMHgowbyP1y6jiAc-8HOCP3KZkkaw6d-W7b6sUXCx6plBT4jK_ceksOwTfULvaN-cHDqMcVe0CJ_xpTyFSMQ4cE1NaVJ6Sq9fcIy4zH/s1600/SystemOverview2_1500px.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfHe5rcM_rzJ5LHX2lgrJknrmGqbKcJPvVWRMHgowbyP1y6jiAc-8HOCP3KZkkaw6d-W7b6sUXCx6plBT4jK_ceksOwTfULvaN-cHDqMcVe0CJ_xpTyFSMQ4cE1NaVJ6Sq9fcIy4zH/s320/SystemOverview2_1500px.png" /></a></div>
<br />
<br />
Поддерживаемые технологии.<br />
AMX, KNX, Lutron, Z-Wave, 1-Wire, EnOcean, xPL, Insteon, X10, Infrared, Russound, GlobalCache, IRTrans, XBMC, VLC, panStamps, Denon AVR, FreeBox, MythTV и другие.
<br />
<br />
У нас есть owfs с показаниями термометра. Давайте посмотрим как нам связать все это дело воедино.
<br />
<br />
<b>Установка.</b>
<br />
<br />
Сubietruck похож на Raspberry Pi, поэтому мы воспользуемся следующим <a href="http://www.openremote.org/display/docs/OpenRemote+2.0+How+To+-+Install+Controller+on+Raspberry+Pi">мануалом</a>.
<br />
<br />
Процессор в Cubietruck версии ARMv7, который поддерживает операции с плавающей точкой на аппаратном уровне (Hard-float). Наш <a href="http://vermus.blogspot.ru/2013/12/debian-cubietruck-cubieboard-3-nand.html">Debian</a> ( <a href="http://www.debian.org/releases/stable/armel/release-notes/ch-whats-new.ru.html#idp155392">ARMv7 (EABI hard-float ABI, «armhf»)</a> ) также поддерживает.
<br />
<br />
Вообще <a href="http://www.openremote.org/display/docs/OpenRemote+2.0+How+To+-+Install+Controller+on+Raspberry+Pi#OpenRemote2.0HowTo-InstallControlleronRaspberryPi-2.InstallJavaVirtualMachine">пишут</a>, что использование java машины с плавающей точкой на аппаратном уровне может иметь проблемы со стабильностью и совместимостью. Посмотрим, что у нас в дебиане. Перед тем как ставить java я немного <a href="http://www.openremote.org/pages/viewpage.action?pageId=22877075">изучил</a> возможные проблемы и какую все таки версию ставить. Читаем комментарий ANDREAS DROLLINGER по ссылке - в нем написано:<br />
<br />
<blockquote>
OpenJDK (IcedTea6 Zero VM) is slower than Oracle Java, but it is available for hard float installation and the Drools rule engine 5.1.1 works.</blockquote>
<br />
<br />
В общем-то рекомендует нам использовать OpenJDK 6 с IcedTea6 (с поддержкой таки hard float), оно немного помедленней, ну и ладно, у нас нагрузка не высокая, будет критично - переустановим. Смотрим, что есть у нас в наличии.
<br />
<br />
<pre class="xml" name="code">root@debtruck:~# apt-cache search icedtea-6-jre
icedtea-6-jre-cacao - Alternative JVM for OpenJDK, using Cacao
icedtea-6-jre-jamvm - Alternative JVM for OpenJDK, using JamVM
</pre>
<br />
<br />
Судя по довольно <a href="https://blogs.oracle.com/jtc/entry/comparing_arm_linux_jvms_revisited">интересным статье</a> сравнения JamVM немного <a href="https://blogs.oracle.com/jtc/entry/comparing_jvms_on_arm_linux">получше</a>, чем Cacao, поэтому буду пробовать его. Ставим:
<br />
<br />
<pre class="xml" name="code"># apt-get install icedtea-6-jre-jamvm
root@debtruck:~# which java
/usr/bin/java
# java -version
java version "1.6.0_27"
OpenJDK Runtime Environment (IcedTea6 1.12.6) (6b27-1.12.6-1~deb7u1)
root@debtruck:~# which java
/usr/bin/java
# java -jamvm -version
java version "1.6.0_27"
OpenJDK Runtime Environment (IcedTea6 1.12.6) (6b27-1.12.6-1~deb7u1)
JamVM (build 1.6.0-devel, inline-threaded interpreter with stack-caching)
# export JAVA_HOME=/usr
</pre>
<br />
Редактируем /etc/java-6-openjdk-armhf/jvm-armhf.cfg перенеся -jamvm KNOWN в начало списка.
<br />
<br />
<pre class="xml" name="code"># java -version
java version "1.6.0_27"
OpenJDK Runtime Environment (IcedTea6 1.12.6) (6b27-1.12.6-1~deb7u1)
JamVM (build 1.6.0-devel, inline-threaded interpreter with stack-caching)
</pre>
<br />
Видим, что у нас JamVM используется по умолчанию.
<br />
<br />
Качаем контроллер.
<br />
<pre class="xml" name="code"># cd /usr/src/
# wget http://download.openremote.org/
</pre>
<br />
У меня скачался OpenRemote-Controller-2.1.0_SNAPSHOT-2013-06-17.zip.
<br />
<br />
<b>Настройка и использование OpenRemote</b>
<br />
<br />
Теперь давайте создадим пользователя под которым будет запускаться контроллер. ( #adduser openremote , #su openremote ). Создадим под root директорию /srv/or/ дадим chown openremote на нее. Распакуем архив в нее.
<br />
<pre class="xml" name="code">$ cd /srv/or/bin
$ chmod +x openremote.sh
$ ./openremote.sh run
....
INFO: Server startup in 19386 ms
</pre>
Регистрируемся на <a href="https://composer.openremote.org/demo/register.jsp">сайте</a>. Заходим в online редактор. Я обычно не доверяю таким онлайн штукам. Но да ладно, в принципе есть исходники - пишут, что можно и оффлайн устанавливать дизайнер, но пока я смысла в этом не вижу. Создаем новый <a href="http://www.openremote.org/display/docs/OpenRemote+2.2+How+To+-+1-Wire+Sensors">Device</a>.
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-08-YTdGs7rfaz6IUvqBfvlxvSE7kE2ZeYrQ_7mV-MQrO5RiJWAhz1d-3duSSQiTaxsAZnQzKh128JJ8PraC0LodkNsJTTR1p-Fxv9Ub03IVzUR-4proyLpQ3iyfY5TOmJkrtv5oN/s1600/1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-08-YTdGs7rfaz6IUvqBfvlxvSE7kE2ZeYrQ_7mV-MQrO5RiJWAhz1d-3duSSQiTaxsAZnQzKh128JJ8PraC0LodkNsJTTR1p-Fxv9Ub03IVzUR-4proyLpQ3iyfY5TOmJkrtv5oN/s320/1.png" /></a></div>
<br />
<br />
Теперь создаем команду (тут можно не прописывать хост и порт каждый раз в версии 2.2, там есть config for controller onewire. В версии 2.1. пока его нет).
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghvPqE1LciMSTc2kLffbYy20Q3jdWaEOi84cZyL09HBPxaYnnIcuv9LCrjDb7vlf-V2YKefLam2IFuDf5uoOwFORKeQtp-coZl3WJsxd5OUvCm0PidRy06AhxSxj9czGuIfzxGyGGz/s1600/3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghvPqE1LciMSTc2kLffbYy20Q3jdWaEOi84cZyL09HBPxaYnnIcuv9LCrjDb7vlf-V2YKefLam2IFuDf5uoOwFORKeQtp-coZl3WJsxd5OUvCm0PidRy06AhxSxj9czGuIfzxGyGGz/s320/3.png" /></a></div>
<br />
<br />
Теперь создаем сенсор.
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6l5oM8cIHJnR2o47V6_2ifhyphenhyphenR-4exQN1U3IdhB13WZfv126K3gOnQcbJRjm1M9BbU-LqghG4zqoIUniKjLXhL_pQRG-qxxRjzCwtnP19x7q3H0K44qm5sCLLyi4jgle30Y8ui6XU-/s1600/5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6l5oM8cIHJnR2o47V6_2ifhyphenhyphenR-4exQN1U3IdhB13WZfv126K3gOnQcbJRjm1M9BbU-LqghG4zqoIUniKjLXhL_pQRG-qxxRjzCwtnP19x7q3H0K44qm5sCLLyi4jgle30Y8ui6XU-/s320/5.png" /></a></div>
<br />
<br />
Теперь <a href="http://www.openremote.org/display/docs/OpenRemote+2.0+How+To+-+Design+User+Interface#OpenRemote2.0HowTo-DesignUserInterface-UIDesigner">перейдем во вкладку</a> "Дизайн". Создадим новую панель Android (у меня только андроид :) ). Добавим в нее пару Label - один просто текст, во втором выберем наш сенсор. Ну вот вроде и готово. Перейдем по адресу http://openremoteserver:8080/controller/ и нажмем Sync with Online Designer, тем самым загрузим созданное приложение на контроллер OpenRemote (Что интересно, можно делать это и оффлайн, тем самым сохранив бекап с приложением - в онлайн редакторе есть возможность сохранить приложение как zip файл, а на контроллере импортировать). После синхронизации заходим на веб-консоль ( http://192.168.xx.xx:8080/webconsole/ ) и нажимаем найти контроллер, после этого вебконсоль находит наш локальный контроллер, нажимаем на него и видим наше созданное приложение. И опять не работает. :)
<br />
<br />
Проблема вот в чем, по умолчанию owserver отвечает только по адресу localhost:4304 , то есть контроллер по имени благополучно подключается, а вот по ip (127.0.0.1) нет. Поэтому пропишем так server: port = 127.0.0.1:4304 (для доступа из сети просто пишем server: port = 4304) в owfs.conf. Перезапускаем сервер owserver: #service owserver restart . Работает:
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrt_kvfGMqCXAhisTVK1HRsAt30cS3ZyK26OGDJ2wFpBlAMmdtFJRx9a-46yLpDgsMMwiaPaxEDWcTEvSxggijpTYVdOOEoQA7k0D8XoMS4L2JbiW6LPRVDnwAe4vDuj9GUwy9aSIp/s1600/4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrt_kvfGMqCXAhisTVK1HRsAt30cS3ZyK26OGDJ2wFpBlAMmdtFJRx9a-46yLpDgsMMwiaPaxEDWcTEvSxggijpTYVdOOEoQA7k0D8XoMS4L2JbiW6LPRVDnwAe4vDuj9GUwy9aSIp/s320/4.png" /></a></div>
<br />
<br />
Для установки приложения на мобильный телефон, устанавливаем <a href="http://sourceforge.net/projects/openremote/files/For%20Developers/OpenRemote-2.0-Android_SNAPSHOT_20111012.apk/download">приложение для андроид</a> и оно само находит контроллер в локальной сети - подключаемся, работает.
<br />
Добавляем строчку cd /srv/openremote/bin в openremote.sh, иначе при запуске из другого места могут вылезти косяки. Скрипт init.d для контроллера
<br />
<br />
<pre class="xml" name="code">#!/bin/sh
### BEGIN INIT INFO
# Provides: openremote
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start daemon at boot time
# Description: Enable service provided by daemon.
### END INIT INFO
#!/bin/sh
User=openremote
orpass=/srv/openremote/bin
case "$1" in
stop)
echo "Stopping OpenRemote Controller..."
su -l $User -c "$orpass/openremote.sh stop" > /dev/null 2>&1 &
;;
start)
# start OpenRemote in background mode
su -l $User -c "$orpass/openremote.sh start" > /dev/null 2>&1 &
echo "OpenRemote Controller started..."
;;
restart)
$0 stop
sleep 5
$0 start
;;
*)
echo "usage: $0 { start | stop | restart}" >&2
exit 1
;;
esac
</pre>
<br />
Ну и автозапуск update-rc.d.<br />
<br />
ps. Вообще для доступа через интернет ip адрес контроллера должен быть внешним.Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com0tag:blogger.com,1999:blog-4797167376881538347.post-7713773288642459082014-01-05T14:57:00.001+04:002014-01-17T21:31:13.751+04:00Now Playing (сейчас играет) в связке foobar2000 и pidginОтображение в строке статуса pidgin трека, играющего в foobar2000. Пишу для памяти. :)
<br />
<br />
1. Ставим плагин <a href="http://code.google.com/p/pidgin-musictracker/">http://code.google.com/p/pidgin-musictracker/</a> . К сожалению, поддержка foobar2000 у меня не заработала (хотя ее и удалить собираются вскоре). <a href="http://code.google.com/p/pidgin-musictracker/wiki/FAQ#8">Поэтому</a>:<br />
2. Ставим <a href="http://chronial.de/foobar2000/#foo_winamp_spam">foo_winamp_spam</a> в foobar2000 (копируем в папку components, перезапускаем foobar).
<br />
3. Заходим в pidgin в "средства-модули", включаем winamp. Чтобы увидеть свой статус либо качаем плагин <a href="http://vayurik.ru/wordpress/toobars">http://vayurik.ru/wordpress/toobars</a> , либо добавляем себя в ростер (список контактов).
<br />
4. Если что-то пошло не так, открываем "помощь-окно отладки". У меня например Status format: пустой, поэтому в статус ничего не выводилось. Это происходило потому, что плагин думал, что проигрывание остановлено (поле "остановлено" в настройках по умолчанию пусто). Плюс %t - берет полное название (%t настраивается в foobar2000-tools-winamp api emulation). В pidgin-musictracker вообще какое-то мутное определение плеера, без foo_winamp_spam плагин таки определяет заголовок, но при парсинге возвращает -1. Похоже сначала сканируются заголовки окон, а потом решается какой API использовать) <br />
<br />
В общем, я настраиваю второй раз, на win 7 определение того, что трек "играет" работало, сейчас пока оставляю так.
<br />
<br />
Шаблон: np: %t<br />
Результат:<br />
<b>Состояние: Не беспокоить: np: Samurai - Four Seasons</b>
<br />
<br />
<b>Update</b>. Если у вас на срастется с плагином winamp API под foobar2000, его можно заменить плагином <a href="http://wiki.hydrogenaudio.org/index.php?title=Foobar2000:Components_0.9/WLM_Notifier_%28foo_wlm%29">WLM Notifier</a>, его надо скопировать в components, включить в foobar2000, после чего поменять в настройках pidgin-musictracker плеер на Messenger compatible interface. У меня он работает гораздо лучше (понимает "стоп" и "паузу"):
<br />
<br />
<b>Состояние: Не беспокоить: ♫: Roxy Music - Avalon</b>
<br />Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com0tag:blogger.com,1999:blog-4797167376881538347.post-19985247584701773642014-01-02T22:28:00.001+04:002014-01-03T11:49:54.285+04:00Создание термометра в сети 1-wireИтак, мы <a href="http://vermus.blogspot.ru/2013/12/1-wire-ds9490r-cubietruck-1-wire-ds2401.html">научились подключать устройство</a> 1-wire к контроллеру.
<br />
<br />
Оффтопик. Давайте-ка я все-таки расскажу что и где покупал.<br />
1. Cubietruck - <a href="http://store.r0ck.me/collections/home-slide/products/cubietruck-2gb-ram-8gb-flash-with-wifi-bt">здесь</a>.<br />
2. Контроллер DS9490R, термометр DS18B20 - <a href="http://www.ab-log.ru/smart-house/1-wire-modules">здесь</a>.<br />
3. Прототипные платы - <a href="http://www.aliexpress.com/item/50pcs-5x7-cm-DIY-Prototype-Paper-PCB-Universal-Experiment-Matrix-Circuit-Board-wholesale-Dropshipping/1061339069.html">здесь</a>.<br />
4. Проводочки :) - <a href="http://www.ebay.com/itm/260515307911">30 ft Kynar wire wrap wire 30 awg 4 modding 10 color</a>.<br />
5. 100 штук RJ11\12 - <a href="http://www.ebay.com/itm/200612919210">100× Modular Lan Network Connector Plug RJ11 6P6C CAT5</a><br />
6. Остальное в местном радио магазине (включая внешние телефонные розетки и некоторые разъемы по питанию).
<br />
<br />
Для создания <a href="http://www.e-voron.dp.ua/files/pdf/maxim/ds18b20-rus.pdf">термометра</a> используем схему с сайта <a href="http://www.benuks.ru/oborud.html#5">Бенукс</a> (сайт вообще отличный, самое лучшее и доступное описание 1-wire сети и устройств). <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvg_SV8UM-6yt8cmn6lEzI0CJFTwM-piasoiBKNojcvR5Op_stjT0LvQgrZsQ81HUir1rGWH-2CsBA_riiyskBd_L2alTc31SQAc81jqyBfCj3yse6Z9SABgO7L63NpMo1FVMGjZo9/s1600/sh_ture.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvg_SV8UM-6yt8cmn6lEzI0CJFTwM-piasoiBKNojcvR5Op_stjT0LvQgrZsQ81HUir1rGWH-2CsBA_riiyskBd_L2alTc31SQAc81jqyBfCj3yse6Z9SABgO7L63NpMo1FVMGjZo9/s320/sh_ture.jpg" /></a></div>
<br />
Травить плату я не умею (хотя в инете полно видео технологии ЛУТ - может быть в скором времени и попробую), поэтому решил делать на прототипных платах - схема в принципе не такая сложная:
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9UXLlRHQxUDggatauSJv1cUBi3aNM1cuF4lGe17HahPfJ21O2VHpXIpBmMuHiUTAsv3SU5-nmrQ8dFcv3Bo152JQzjtgiBuHx9vWGa86HlX8dxLEipQDHhKystxXpRpvCrwcJAEuj/s1600/50pcs-5x7-cm-DIY-Prototype-Paper-PCB-Universal-Experiment-Matrix-Circuit-Board-wholesale-Dropshipping.jpg_350x350.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9UXLlRHQxUDggatauSJv1cUBi3aNM1cuF4lGe17HahPfJ21O2VHpXIpBmMuHiUTAsv3SU5-nmrQ8dFcv3Bo152JQzjtgiBuHx9vWGa86HlX8dxLEipQDHhKystxXpRpvCrwcJAEuj/s320/50pcs-5x7-cm-DIY-Prototype-Paper-PCB-Universal-Experiment-Matrix-Circuit-Board-wholesale-Dropshipping.jpg_350x350.jpg" /></a></div>
<br />
<br />
По схеме: в принципе ничего сложного даже для такого новичка, как я. 78L05 - стабилизатор, преобразует 12 вольт на нашей шине в 5 вольт для датчика. Кстати! Мы приведем сеть 1-wire в порядок и пустим по ней 12 вольт, не будем использовать паразитное питание. Остальные элементы <a href="http://benuks.flyboard.ru/viewtopic.php?p=371#p371">описаны разработчиком схемы</a> (обсуждение немного другой платы, поэтому 5 пункт можно не читать и обозначения не все совпадают - но я думаю догадаться можно о чем речь):
<br />
<br />
<blockquote>
<b>1. Диод D6 - для каких целей он служит и почему выбран именно КД521?</b><br />
Этот диод уменьшает влияние "просадок" по общей шине питания на данный модуль. Здесь допускается применение любого маломощного выпрямительного диода. КД521 взят только потому, что был под рукой.<br />
<br />
2. <b>Конденсатор C2 - для каких целей он служит? Ведь в datasheet к 7805 указаны только 2 конденсатора, по 0,33 и 0,1 соответственно.</b><br />
Во время "просадок" питания по общей шине этот конденсатор поддерживает питание данного модуля.<br />
<br />
3. <b>Сопротивление R2 - почему именно 100 Ом?</b><br />
Оптимальный номинал, который с одной стороны является элементом защиты, а с другой стороны не оказывает большого влияния на полезные сигналы 1-wire.<br />
<br />
4.<b> Стабилитрон D3 - почему выбран именно КС156?</b><br />
Этот элемент совместно с резистором R2 является цепочкой защиты модуля от импульсных помех по микросети. Выбран с несколько большим напряжением, чтобы не влиять на полезный сигнал 1-Wire и Pullup, а "срезать" случайные импульсные помехи превышающие 5,6 В.<br />
<br />
5.<b> Действительно ли так нужна опторазвязка на схеме между DS2413 и реле, или можно обойтись транзистором + реле?</b><br />
<br />
Можете исключить опторазвязку, но тогда при работе через USB-адаптер может быть подвисание порта. </blockquote>
<br />
Приступили к пайке схемы, предварительно разрезав плату ножницами по металу под внешнюю телефонную розетку и пролудив ее. Получили нечто вроде этого (микросхему пока не паяем, сначала хочу проверить вольтаж).
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXn8KrrHyN77dTnchg_rGyBRP4xthO873jc4u8gkgXbhHrMysWUQJvoBBBTrLaGj3IAP-zxOYFesbO3rViS4GHnna-NRVz-tM8BzuqXvS_nvVZ1LyU0bpwAwxyKZHD76BTre9WKX88/s1600/20131229_220331.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXn8KrrHyN77dTnchg_rGyBRP4xthO873jc4u8gkgXbhHrMysWUQJvoBBBTrLaGj3IAP-zxOYFesbO3rViS4GHnna-NRVz-tM8BzuqXvS_nvVZ1LyU0bpwAwxyKZHD76BTre9WKX88/s320/20131229_220331.jpg" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoiGAx9LwV5FhcebtE3KcXRkEg70mySLUbKaP7kPWa4pQVThA8jDv3ljtPobDtjTT97Em3bKPq9kBju7as-sg0ZN2YoySD_tsMaImgMyHrF3mQ8nvruVlm2YuO900l7E3dPGGUxcVd/s1600/20131229_225132.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoiGAx9LwV5FhcebtE3KcXRkEg70mySLUbKaP7kPWa4pQVThA8jDv3ljtPobDtjTT97Em3bKPq9kBju7as-sg0ZN2YoySD_tsMaImgMyHrF3mQ8nvruVlm2YuO900l7E3dPGGUxcVd/s320/20131229_225132.jpg" /></a></div>
<br />
<br />
Теперь надо сделать саму шину. Для этого я купил 6 контактные телефонные разъемы (RJ12 в простонародии - почитайте вики, чтобы не купить что-нибудь не то) по цене примерно 200 рублей за 100 штук (см. пункт 5 в закупках). Я решил обжимать по схеме B в RJ45 (без оранжевого и светло-оранжевого) ибо уже привык к ней :) , запишем распиновку. Теперь обжимаю все шесть проводов, а не как в прошлом посте, так обжимка получается качественнее.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOEkCVj_8xeg2ZIIPJi9Pxsra7bmC_4UIQNlFLlChS8j4nvAU5WgP9IA8V78YR8WmaOHOIabZYNAe8yiHZLmUfvTw3N5UdzpJySciHF_xCzBI2EX96SwH1p5mnSxY-BixEfxMH0-s-/s1600/rj45.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOEkCVj_8xeg2ZIIPJi9Pxsra7bmC_4UIQNlFLlChS8j4nvAU5WgP9IA8V78YR8WmaOHOIabZYNAe8yiHZLmUfvTw3N5UdzpJySciHF_xCzBI2EX96SwH1p5mnSxY-BixEfxMH0-s-/s320/rj45.jpg" /></a></div>
<br />
<br />
У меня вид с обратной стороны по B (то есть контакты от 8 до 3 включительно)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8azT0FigziMmR7TRiUY8gWj17pSV8nZGNkUaZXvMtu2nEbFw205DbsxTSRf63FU0XHJ8vhZ9zn5fqlRCvQDijqIZgmWUOom3uae4apjVmU4f9jndSplF8W1vP8t5yZ55vYW38St-O/s1600/20131229_223612.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8azT0FigziMmR7TRiUY8gWj17pSV8nZGNkUaZXvMtu2nEbFw205DbsxTSRf63FU0XHJ8vhZ9zn5fqlRCvQDijqIZgmWUOom3uae4apjVmU4f9jndSplF8W1vP8t5yZ55vYW38St-O/s320/20131229_223612.jpg" /></a></div>
<br />
<br />
1. Светло-зелёный - не используется.<br />
2. Синий - черный в розетку - +12 вольт.<br />
3. Светло-синий - красный в розетке - Data.<br />
4. Зелёный - зелёный в розетке - земля.<br />
5. Светло-коричневый - жёлтый в розетке - +18 вольт.<br />
6. Коричневый - свободный.<br />
<br />
<b>"Организатор" шины</b><br />
<br />
Теперь я подумал как же мы будем подключать 18 и 12 вольт? Ну и решил взять еще одну розетку и сделать из нее некий переходник-организатор (дурацкое название, что-то сейчас лучше в голову не пришло :) ).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoA9WFvQkAgzhcOPk6nl88-3V4qIHIUZCG43b-f4ngLG1xV_IEQ5-9l7AVv8hY_tHTsm1aF3-aUmkNLLecSOifeznkT6Ve7fdS6Y6C3XSFbgqVj9Y3yvL4GsK7E_yzar6zY7sV94vH/s1600/9490.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoA9WFvQkAgzhcOPk6nl88-3V4qIHIUZCG43b-f4ngLG1xV_IEQ5-9l7AVv8hY_tHTsm1aF3-aUmkNLLecSOifeznkT6Ve7fdS6Y6C3XSFbgqVj9Y3yvL4GsK7E_yzar6zY7sV94vH/s320/9490.jpg" /></a></div>
<br />
<br />
Смотрим распиновку. Нам нужны только 3 и 4 контакты. Обжимаем как хотим один конец (советую выщипать лишние контакты), а второй оставляем - его будем впаивать в макетплату.
<br />
<br />
Разбираем розетку, паяем. У меня получилось вот так вот
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitmJilmNr3ugunsLtkFLzxn4VuBMoHsmp1qPz4-azB-pSvMCg-PmzDvXKR1hRgSr17nVKvLMStYLSDe6ct-LYsXHMvnUVeH9uZ4IQD1odaE6TRxFd-v0IJUnjFwxbfRji9O1GENnRR/s1600/20140101_191741.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitmJilmNr3ugunsLtkFLzxn4VuBMoHsmp1qPz4-azB-pSvMCg-PmzDvXKR1hRgSr17nVKvLMStYLSDe6ct-LYsXHMvnUVeH9uZ4IQD1odaE6TRxFd-v0IJUnjFwxbfRji9O1GENnRR/s320/20140101_191741.jpg" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF5O6461rhZ_Cc7o6YviNNzZh2Z-xHNV8idsIoFAsFp9xOB2vttRXOcSrMZYYdo9yzoserXzoaklgwU9M0EPqrbYAY-THuZp9KP_Skvmm02mF4XAGmy7dnS5ex8fNzDZwwtDZQH6q4/s1600/20140101_193559.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF5O6461rhZ_Cc7o6YviNNzZh2Z-xHNV8idsIoFAsFp9xOB2vttRXOcSrMZYYdo9yzoserXzoaklgwU9M0EPqrbYAY-THuZp9KP_Skvmm02mF4XAGmy7dnS5ex8fNzDZwwtDZQH6q4/s320/20140101_193559.jpg" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgb4hu9Aal8B6y_0GX4RQiCXuJ9Gex-nndGDiHakaLW2sxd2ipPAn3a0rj9yR8mONA501jC8tqj_xvOimHiC7UWT_8cJKSqyhIxlMLvhyCtfdkfzcPNb6gVLaZAf6lEQ-d_s-aMSbzk/s1600/20140101_193610.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgb4hu9Aal8B6y_0GX4RQiCXuJ9Gex-nndGDiHakaLW2sxd2ipPAn3a0rj9yR8mONA501jC8tqj_xvOimHiC7UWT_8cJKSqyhIxlMLvhyCtfdkfzcPNb6gVLaZAf6lEQ-d_s-aMSbzk/s320/20140101_193610.jpg" /></a></div>
<br />
<br />
Обжимаем еще один провод. Мультиметром проверяем работу схемы и правильность соединений. Проверяем 12 вольт на шине. 18 вольт у меня пока нет. Чтобы было удобнее пользоваться мультиметром - подключаем по розетке на оба конца:
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiY6ex9VpjlsdObNrTz8aliQ1CX-i6g-gw3W_HX3satNzLm4Rf3ZMKZoLLfconAniD7vjWxYCQYo8L9O5JMo6INA8wNKzNwdYqZ4tExWpX8uFyK5_w1tpkEsqrtuosj1RdtvFG8BQ0h/s1600/20140101_200157.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiY6ex9VpjlsdObNrTz8aliQ1CX-i6g-gw3W_HX3satNzLm4Rf3ZMKZoLLfconAniD7vjWxYCQYo8L9O5JMo6INA8wNKzNwdYqZ4tExWpX8uFyK5_w1tpkEsqrtuosj1RdtvFG8BQ0h/s320/20140101_200157.jpg" /></a></div>
<br />
<br />
Пробуем вставлять наш термометр, пока без DS18B20. Проверим напряжение 5 вольт.
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7LC0hDwnPddwB_3KI_qfnHzpd327gDVu9fJ0Z6Q1Pn-Zz-Wuwo3vIxA2N8fyT2n2uRBTTVdVplp7OLV-X-X9f63gCx2amFwFb4bP4H3_WYGxgtG2HEw4khfmv98tclIqDpRfJrOXH/s1600/20140101_210530.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7LC0hDwnPddwB_3KI_qfnHzpd327gDVu9fJ0Z6Q1Pn-Zz-Wuwo3vIxA2N8fyT2n2uRBTTVdVplp7OLV-X-X9f63gCx2amFwFb4bP4H3_WYGxgtG2HEw4khfmv98tclIqDpRfJrOXH/s320/20140101_210530.jpg" /></a></div>
<br />
<br />
Последний шаг - впаиваем DS18B20 в плату под термометр. Распиновка:
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaCccAcs0xOUnUD1IoOsmXYErDs31qa1ix0HFLZakQULOQYJssxz_zIo9VrI8GJ2jNRWYB0PwO37ER1U1HM8Gov4Clajt9Ax8GQZshc-3icdviJ3qX0paOdRWjrhplqdZrc6_0ydaM/s1600/18b20_p.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaCccAcs0xOUnUD1IoOsmXYErDs31qa1ix0HFLZakQULOQYJssxz_zIo9VrI8GJ2jNRWYB0PwO37ER1U1HM8Gov4Clajt9Ax8GQZshc-3icdviJ3qX0paOdRWjrhplqdZrc6_0ydaM/s320/18b20_p.gif" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3Ihncx1vgooQ84pjg7Jmt7vqKpmHpk0EC_lYOnN_j2XifrQPLZajGqcxv497j7rQf7DQhnH8NUgiQbRFlLhEc6yFa_jZ_dDWnKHp44yzSUL9XPvBicdkRBSf56fgn1AZmAyODpDUX/s1600/20140101_215520.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3Ihncx1vgooQ84pjg7Jmt7vqKpmHpk0EC_lYOnN_j2XifrQPLZajGqcxv497j7rQf7DQhnH8NUgiQbRFlLhEc6yFa_jZ_dDWnKHp44yzSUL9XPvBicdkRBSf56fgn1AZmAyODpDUX/s320/20140101_215520.jpg" /></a></div>
<br />
<br />
У меня заработало не сразу. :) Вышла небольшая заминка по проводам. Поэтому прежде чем обжимать коннектор в DS9490R выщипайте лишние контакты в коннекторе, оставьте два посередине и только после этого обжимайте.
<br />В итоге, у нас есть первое устройство в "нормальной" сети 1 wire, которую можно расширять не боясь. Еще я понял, что лучше все-таки травить плату, это наверное быстрее (если конечно есть работающий макет), чем использовать такие вот прототипные платы (хотя может их надо как-то по другому использовать, я честно говоря не знаю. :) ) и качественее.
<br />
<br />
Кусочек информации с моего термометра:
<br />
<br />
<pre>
power YES (1)
r_address 710000041E821A28
r_id 0000041E821A
r_locator FFFFFFFFFFFFFFFF
temperature 26.3125
temperature10 26.25
temperature11 26.375
temperature12 26.3125
temperature9 26.5</pre>
<br />
<br />
Система в сборе
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8A41wQlbIyxnFCoLN4d6HMZqFSwG2HvtW6K17M5xPK47erIOFDbEICbM_2LrglmqfwAuQDJLWveck6fOKQd31GIjwJzZ_t1ven3T-0KxcZVyBfi64mI_SSGvVgUYVkyY178YFHNWb/s1600/20140102_220920.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8A41wQlbIyxnFCoLN4d6HMZqFSwG2HvtW6K17M5xPK47erIOFDbEICbM_2LrglmqfwAuQDJLWveck6fOKQd31GIjwJzZ_t1ven3T-0KxcZVyBfi64mI_SSGvVgUYVkyY178YFHNWb/s320/20140102_220920.jpg" /></a></div>
<br />
<br />
ps. Кстати, неплохо бы <a href="http://vermus.blogspot.ru/2013/12/debian-cubietruck-cubieboard-3-nand.html">в наш дебиан</a> еще поставить системные логи:<br />
#apt-get install rsyslogVermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com7tag:blogger.com,1999:blog-4797167376881538347.post-41910386852032596272013-12-24T18:44:00.001+04:002014-02-05T09:00:32.020+04:00Подключение контроллера сети 1-wire (DS9490R) к Cubietruck. Первое устройство в сети 1-wire (ds2401).Ну что, теперь можно раскрыть секрет - не просто так же покупался cubietruck. А покупался он для создания сети умного дома 1-wire. Что это такое рассказывать не буду, в интернете полно информации. Просто буду записывать некоторые не очевидные для меня, как чайника вещи. Итак, для начала подключим контроллер DS9490R к нашему cubietruck.
<br />
Вставляем контроллер в cubietruck.
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI2uaMj2QHVoMtdPXZbcfsitXCuH6qAzDLRGsrlHh5b7E-bOSG9EAkDffTV_lHBYchTUSqi9LfXcd1aZdWNpGU52C2YXt1kpUUOHtI8PjwvkyvU5-2vRDU3VqqkblU_FZxBG2Iqzkp/s1600/20131224_094116.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI2uaMj2QHVoMtdPXZbcfsitXCuH6qAzDLRGsrlHh5b7E-bOSG9EAkDffTV_lHBYchTUSqi9LfXcd1aZdWNpGU52C2YXt1kpUUOHtI8PjwvkyvU5-2vRDU3VqqkblU_FZxBG2Iqzkp/s320/20131224_094116.jpg" /></a></div>
<br />
<br />
<pre class="xml" name="code"># dmesg
[ 512.230242] The port change to OHCI now!
[ 512.532997] usb 5-1: new full-speed USB device number 2 using sw-ohci
# apt-get install owfs
# lsusb
Bus 005 Device 003: ID 04fa:2490 Dallas Semiconductor DS1490F 2-in-1 Fob, 1-Wire adapter
# mkdir /mnt/1wire
# owfs -C -uall -m /mnt/1wire --allow_other
# ls -lah /mnt/1wire
total 4.0K
drwxr-xr-x 1 root root 8 Dec 24 06:15 .
drwxr-xr-x 4 root root 4.0K Dec 24 06:14 ..
drwxrwxrwx 1 root root 8 Dec 24 06:16 05.4AEC29CDBAAB
drwxrwxrwx 1 root root 8 Dec 24 06:16 10.67C6697351FF
drwxrwxrwx 1 root root 8 Dec 24 06:16 81.EE6F32000000
drwxr-xr-x 1 root root 8 Dec 24 06:15 alarm
drwxr-xr-x 1 root root 8 Dec 24 06:15 bus.0
drwxr-xr-x 1 root root 8 Dec 24 06:15 bus.1
drwxr-xr-x 1 root root 8 Dec 24 06:15 settings
drwxrwxrwx 1 root root 8 Dec 24 06:16 simultaneous
drwxr-xr-x 1 root root 8 Dec 24 06:15 statistics
drwxr-xr-x 1 root root 32 Dec 24 06:15 structure
drwxr-xr-x 1 root root 8 Dec 24 06:15 system
drwxr-xr-x 1 root root 8 Dec 24 06:15 uncached
</pre>
<br />
<a href="http://ab-log.ru/forum/viewtopic.php?p=6254#p6254">Информация</a>:
<blockquote>owfs - это программа, которая отображает сеть в виде файловой системы. То, что owfs совпадает с названием всего пакета - чистая случайность.<br />
owhttpd - это программа, которая делает доступной сеть по HTTP протоколу (по-народному, через браузер)<br />
И та и другая программы могу работать с мастером сети самостоятельно, но не вместе!<br />
Чтобы owfs и owhttpd работали одновременно, нужно запустить owserver.<br />
owserver -u -p 3000<br />
Запускает сервер работы с сетью, -u значит физическое устройство USB типа DS9490R, и отвечает на запросы по 3000 порту.<br />
owhttpd -s 3000 -p 3001<br />
-s 3000 - порт, на котором запущено owserver<br />
-p 3001 - порт, на котором owhttpd сам отвечает по протоколу HTTP<br />
owfs -s 3000 /mnt/1wire/<br />
-s 3000 понятно, дальше идет mount point, который является обязательным параметром</blockquote>
<br />
Пробуем зайти http://192.168.xx.xx:2121/
<br />
<br />
Добавим в /etc/modprobe.d/fbdev-blacklist.conf (чтобы не использовать модули ядра линукс, а брать из пакета owfs)
<br />
<pre class="xml" name="code">blacklist ds9490r
blacklist ds2490
blacklist wire
</pre>
<br />
<br />
Редактируем файл /etc/owfs.conf
<br />
<pre class="xml" name="code"># Sample configuration file for the OWFS suite for Debian GNU/Linux.
# This is the main OWFS configuration file. You should read the
# owfs.conf(5) manual page in order to understand the options listed
# here.
######################## SOURCES ########################
# With this setup, any client (but owserver) uses owserver on the
# local machine...
! server: server = localhost:4304
# ...and owserver uses the real hardware, by default fake devices
# This part must be changed on real installation
#server: FAKE = DS18S20,DS2405
# USB device: DS9490
server: usb = all
# Serial port: DS9097
#server: device = /dev/ttyS1
# owserver tcp address
#server: server = 192.168.10.1:3131
# random simulated device
#server: FAKE = DS18S20,DS2405
######################### OWFS ##########################
mountpoint = /mnt/1wire
allow_other
####################### OWHTTPD #########################
http: port = 2121
####################### OWFTPD ##########################
ftp: port = 2120
####################### OWSERVER ########################
server: port = localhost:4304
</pre>
<br />
<br />
Редактируем /etc/fuse.conf:
<br />
<pre class="xml" name="code"># Set the maximum number of FUSE mounts allowed to non-root users.
# The default is 1000.
#
#mount_max = 1000
# Allow non-root users to specify the 'allow_other' or 'allow_root'
# mount options.
#
user_allow_other
</pre>
<br />
<br />
После этого монтировать можно командой # owfs.
Хотя в прицнипе монтирование нам особо и не нужно ибо есть tcp owserver, монтировать датчики в файловую систему удобно для тестов. Поэтому процесс автомонтирования при загрузке рассматривать не будем (примеры скрипта можно найти в сети) <b>update</b>. <a href="http://vermus.blogspot.ru/2014/02/owfs.html">или здесь</a>.
<br />
<br />
<b>Создание сети 1-wire.</b><br />
<br />
Небольшой ликбез по поводу сети 1-wire для новичков как я (после моего месячного изучения урывками). Если профи увидят ошибки, прошу комментировать. Итак, сеть 1-wire - сеть на одной шине, компоненты которой подключаются последовательно. Компонентами могут выступать как уже готовые микросхемы с датчиками и так и микросхемы управления вводом\выводом (то есть для подключения дополнительных цифровых или аналоговых датчиков). В сети 1-wire по умолчанию всего два контакта - data и земля. В data передаются данные (как видно по названию), а также т.н. паразитное питание. То есть можно использовать всего два провода. Вначале я не очень понимал это принцип, поэтому накупил штук 10 ds2401 которые как раз от него и работают - сегодня будем тестировать сеть на них. Так вот, строить сеть на паразитном питании (питание идет с контроллера DS9490R) можно, но не нужно. :) Для пары датчиков и короткой шине можно использовать паразитное питание, а вот если шина длиной более 30 метров и датчиков много - ожидается просадка по напряжению, поэтому <a href="http://www.benuks.ru/oborud.html">умные люди придумали</a> (по ссылке много интересного про 1wire) и используют отдельное питание 5V, но не простое, а канал с повышенным напряжением. По ссылке прекрасно <a href="http://www.benuks.ru/power.html">все описано</a>. Я лишь дополню зачем это надо - 12 V в каждом модуле преобразуется стабилизатором в 5V, а 18V в 12V. Это сделано для того, чтобы даже при просадке напряжения в шине на компоненты гарантировано поступало 5V и на некоторые датчики 12V. Далее, сразу используем витую пару 5ой категории, чтобы не переделывать потом. Для коммутации также используем телефонные (rj11\12) коннекторы и внешние телефонные розетки.
<br />
Ну вот в принципе и все.
<br />
<br /><b>Делаем первое устройство сети 1-wire.</b>
<br />
<br />
Сейчас мы будем делать устройство с паразитным питанием, потому что пока у меня нет нужной микросхемы 1-wire с внешним питанием. Тырим одну картинку по ссылке выше:
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoA9WFvQkAgzhcOPk6nl88-3V4qIHIUZCG43b-f4ngLG1xV_IEQ5-9l7AVv8hY_tHTsm1aF3-aUmkNLLecSOifeznkT6Ve7fdS6Y6C3XSFbgqVj9Y3yvL4GsK7E_yzar6zY7sV94vH/s1600/9490.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoA9WFvQkAgzhcOPk6nl88-3V4qIHIUZCG43b-f4ngLG1xV_IEQ5-9l7AVv8hY_tHTsm1aF3-aUmkNLLecSOifeznkT6Ve7fdS6Y6C3XSFbgqVj9Y3yvL4GsK7E_yzar6zY7sV94vH/s320/9490.jpg" /></a></div>
<br />
<br />
Итак, используем так: <br />
светло-зеленый:data (3ий пин в контроллере)<br />
зеленый:земля(GRND) (4ый пин в контроллере)<br />
<br />
<br />
Обжимаем два провода, остальные пока не нужны. Обжато не очень, в следующий раз наверное по другому обожму. Но для теста пойдет.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLHcDQ34d1xOEoHHdGrQuDCuIA11ekkoZkvS6UzbP4yv6gICQcVKyxAnE9ArS6aaFd7xdTNChL4_6PjxsKfgitvvk2kEPnuorg05VvyqZP6tcTV4FxuaSghBibNudrxes9zqUbb0U7/s1600/20131224_170758.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLHcDQ34d1xOEoHHdGrQuDCuIA11ekkoZkvS6UzbP4yv6gICQcVKyxAnE9ArS6aaFd7xdTNChL4_6PjxsKfgitvvk2kEPnuorg05VvyqZP6tcTV4FxuaSghBibNudrxes9zqUbb0U7/s320/20131224_170758.jpg" /></a></div>
<br />
Подключать мы будем устройство, которое выдает уникальный id (например, если устройство с определенным id доступно - дверь закрыта, а если не доступно - значит дверь открыта) - <a href="http://www.elin.ru/files/pdf/1-Wire/1W-chips4.pdf">ds2401</a>.
Нагло тырим еще одну картинку с <a href="http://www.ab-log.ru/forum/viewtopic.php?f=1&t=586&sid=870b7d0142d963bbb38b7b07132c466f#p9780">форума</a>.
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6xrQ_b8-o1Eux8I4TX9SipM5MxyKVNvLWoYx6NbOi6hS_mtTEI0zzgJlMz9t2Ms8bRbFNwG570121eWN9UJykg6G7SCq5ibszeMbK-moD4i7ocICSuUmpOrCkJX1F5Plt-appNmHx/s1600/ds2401.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6xrQ_b8-o1Eux8I4TX9SipM5MxyKVNvLWoYx6NbOi6hS_mtTEI0zzgJlMz9t2Ms8bRbFNwG570121eWN9UJykg6G7SCq5ibszeMbK-moD4i7ocICSuUmpOrCkJX1F5Plt-appNmHx/s320/ds2401.png" /></a></div>
<br />
<br />
Второй конец я впаял в макет плату. Распиновку ds2401 смотрим <a href="http://pdfserv.maximintegrated.com/en/ds/DS2401.pdf">здесь</a>.
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHdc1grxdDsLuzjMlOOLZumCngsFxsq6zu8fEQ0zgObXdfSjL_IUfpvzFnfhmxdKUaRIukDuganMz-7NyLl9PTdKMPlxPWScIDqiR2FzE8ivQ-Vwd9MFpSwhkOe1F97Mp9B4fmdwDJ/s1600/20131224_183026.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHdc1grxdDsLuzjMlOOLZumCngsFxsq6zu8fEQ0zgObXdfSjL_IUfpvzFnfhmxdKUaRIukDuganMz-7NyLl9PTdKMPlxPWScIDqiR2FzE8ivQ-Vwd9MFpSwhkOe1F97Mp9B4fmdwDJ/s320/20131224_183026.jpg" /></a></div>
<br />
Подключаем (геркон замкнут - вот эти две коричневые цилиндрические штуки и есть магнит с герконом):
<br />
<pre class="xml" name="code">/mnt/1wire# ls -l
total 0
drwxrwxrwx 1 root root 8 Dec 24 14:47 01.E890ED150000
drwxrwxrwx 1 root root 8 Dec 24 14:47 81.EE6F32000000
drwxr-xr-x 1 root root 8 Dec 24 10:12 bus.0
drwxr-xr-x 1 root root 8 Dec 24 10:12 settings
drwxr-xr-x 1 root root 8 Dec 24 10:12 statistics
drwxr-xr-x 1 root root 32 Dec 24 10:12 structure
drwxr-xr-x 1 root root 8 Dec 24 10:12 system
drwxr-xr-x 1 root root 8 Dec 24 10:12 uncached
/mnt/1wire/01.E890ED150000# cat type
DS2401
/mnt/1wire/01.E890ED150000# cat r_address
A9000015ED90E801
/mnt/1wire/01.E890ED150000# cat id
E890ED150000
</pre>
Вот у нас и новый элемент сети 1-wire. r_address это и есть уникальный id ds2401, который по идее гарантирует уникальность микросхемы. Я брал в китайском интернет магазине, где-то слышал что они штампуют все под одну гребенку (надо будет поставить вторую ds2401 и проверить). Пробуем убрать магнит от геркона. Смотрим - элемент отсутствует. Вот вам и элементарная проверка на открытую дверь. Я пока не выбрал (может кто посоветует) систему, которая все эти данные собирает в базу, имеет веб-интерфейс и разные плюшки (например работа с tcp сервером 1-wire, jabber), пока в поиске. Но смысл понятен.<br />
Обратите внимание, что появление датчика в сети 1wire может занять некоторое время (около 15 секунд, а может и больше).
<br />
ps. Почти все элементы покупались онлайн, могу поделиться ссылками.Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com0tag:blogger.com,1999:blog-4797167376881538347.post-84124882929058553322013-12-22T22:50:00.000+04:002014-02-08T01:34:06.785+04:00Настройка Debian на Cubietruck (cubieboard 3)В <a href="http://vermus.blogspot.ru/2013/12/debian-cubietruck-cubieboard-3-nand.html">прошлом посте</a> мы установили debian на nand память cubietruck. Итак, сеть не работает.
<br />
<br />
<b>Проводная сеть.</b>
<br />
<br />
<pre class="xml" name="code">modprobe sunxi_gmac
</pre>
<br />
Это команда подгрузки модуля сетевого интерфейса в cubietruck. Она вызовет у нас ошибку вроде "could not open moddep file modules.dep.bin". А все потому что такого файла у нас нет и вообще каталога /lib/modules у нас нет. Решается просто - копируйте с SD карты с debian каталог /lib/modules, только проследите за тем, что у ядра у вас совпадают.
<br />
<br />
<pre class="xml" name="code">root@debtruck:~# mount /dev/mmcblk0p2 /mnt/mmc
root@debtruck:~# modprobe sunxi_gmac
root@debtruck:~# uname -a
Linux debtruck 3.4.61+ #1 SMP PREEMPT Sat Oct 26 13:08:57 CST 2013 armv7l GNU/Linux
</pre>
<br />
После этого сетевой модуль подгрузится и будет работать.
<br />
<br />
Теперь есть интернет можно поставить еще один пакетик:
<br />
<pre class="xml" name="code">apt-get install bash-completion
</pre>
<br />
<b>Включение wifi</b>
<br />
<br />
<pre class="xml" name="code">modprobe bcmdhd
</pre>
<br />
<br />
А проще скопировать файл /mnt/mmc/etc/modules.conf c SD карты в NAND и перезаписать его. Тогда все необходимые модули будут грузиться автоматически. Еще можно скопировать каталог /lib/firmware.
<br />
<br />
<b>Расширение дискового пространства</b>
<br />
<br />
Так как изначально образ lubuntu сервера был где-то около 2 Гигабайт, а в NAND вроде нам обещали 8 Гигабайт, то имеет смысл расширить основной раздел.
Перезагружаемся на SD карту (В принципе можно и работать прямо с nand, но мне не хотелось захламлять систему пока всякими git и make). Я испытываю проблемы с загрузкой с SD карты, похоже какой-то баг нерешенный. Но вроде приноровился вставлять карту при перезагрузке (см. предыдущий пост). Далее:
<pre class="xml" name="code">
# apt-get install git
# git clone git://github.com/linux-sunxi/sunxi-tools
# cd sunxi-tools
# apt-get install libusb-1.0-0-dev make pkg-config
# make
</pre>
<strike># make install</strike>
<br />
<br />
Далее, запускаем скомпилированную программу nand-part и читаем, что <a href="http://www.cubieforums.com/index.php/topic,1134.msg6783.html#msg6783">пишут</a>:<br />
"Как видим мы хотим объединить 2 и 3 раздел в один, поэтому новая часть 2 радела is 4194304 + 10584064 = 14778368. "
<br />
<br />
<pre class="xml" name="code">
# ./nand-part -f a20 /dev/nand 32768 'boot 131072' 'rootfs 14778368'
</pre>
<br />
Перезагружаемся без SD карты.
<br />
<br />
<pre class="xml" name="code">
# resize2fs /dev/nandb
# df -h
Filesystem Size Used Avail Use% Mounted on
rootfs 7.0G 866M 5.9G 13% /
</pre>
Отлично, у нас 7 гигабайт!
<br />
<br />
<b>Память</b>
<br />
<br />
С памятью вроде проблем нет (dmesg):
<br />
<br />
Memory: 448MB 1536MB = 1984MB total
<br />
<br />
<b>Светодиодная индикация</b>
<br />
<br />
1 голубой включено<br />
2 оранжевый cpu0 (загрузка)<br />
3 белый cpu1 (загрузка)<br />
4 зеленый mmc0 (обращение)<br />
<br />
<br />
init.d <a href="http://noobish.in/2014/02/switch-status-leds-cubietruck-startup/">Скрипт отключения/включения</a> светодиодов в cubietruck:
<br />
<br />
<pre class="xml" name="code">
#!/bin/bash
case "$1" in
start)
echo 0 > /sys/class/leds/orange:ph20:led2/brightness
echo "Switching off Orange LED"
echo 0 > /sys/class/leds/blue:ph21:led1/brightness
echo "Switching off Blue LED"
echo 0 > /sys/class/leds/white:ph11:led3/brightness
echo "Switching off White LED"
echo 0 > /sys/class/leds/green:ph07:led4/brightness
echo "Switching off Green LED"
;;
stop)
echo 1 > /sys/class/leds/orange:ph20:led2/brightness
echo "Switching on Orange LED"
echo 1 > /sys/class/leds/blue:ph21:led1/brightness
echo "Switching on Blue LED"
echo 1 > /sys/class/leds/white:ph11:led3/brightness
echo "Switching on White LED"
echo 1 > /sys/class/leds/green:ph07:led4/brightness
echo "Switching on Green LED"
;;
*)
echo "Usage: /etc/init.d/leds {start|stop}"
exit 1
;;
esac
</pre>
<br />
<br />
Правда после включения они не мигаю и горят просто. После перезагрузки будут мигать снова, и не буду мигать, если прописать автозагрузку скрипта.
<br />
<br />Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com4tag:blogger.com,1999:blog-4797167376881538347.post-1536269724490176702013-12-19T17:20:00.000+04:002013-12-25T20:44:13.207+04:00Установка Debian на Cubietruck (cubieboard 3) на внутреннюю память (NAND)<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9rWTCFg6KHre3f8tJXM52ZRSalIfGBB8cTmTXMOvYnMr4QFCUfxcq2EGDeTmYXypM54jqMvuLsDEm4YlWQawJz38klsmA-A92g4LVqZC-VPXKmlKOvv00-yKjYTl6RT2cVlMAWTzI/s1600/20131212_090442.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9rWTCFg6KHre3f8tJXM52ZRSalIfGBB8cTmTXMOvYnMr4QFCUfxcq2EGDeTmYXypM54jqMvuLsDEm4YlWQawJz38klsmA-A92g4LVqZC-VPXKmlKOvv00-yKjYTl6RT2cVlMAWTzI/s320/20131212_090442.jpg" /></a></div>
Пришел мне <a href="http://store.r0ck.me/collections/home-slide/products/cubietruck-2gb-ram-8gb-flash-with-wifi-bt">cubietruck</a>. На нем для тестов предустановлен android 4. Мне графика ни к чему, да и сервер на андроиде бестолковая затея. Выяснив, что на данный момент Cubian толком <a href="https://github.com/cubieplayer/Cubian/issues/179">не поддерживает</a> Cubietruck пришлось <strike>выбирать из рекомендованного программного обеспечения. В итоге выбор пал на <a href="http://docs.cubieboard.org/tutorials/a20-cubietruck_lubuntu_server_releases">Lubuntu Server</a> (<a href="http://www.lubuntu.net/">официальный сайт</a>).</strike><br />
<br />
В процессе поиска, я <a href="http://www.cubieforums.com/index.php/topic,1087.0.html">наткнулся на порт</a> debian для cubietruck для SD Card. Но он нам пригодится не для установки, а для работы с NAND. Можно взять <a href="http://www.cubieforums.com/index.php/topic,1200.msg7459.html">Cubiuntu</a> (пароль по умолчанию linaro\linaro).<br />
<br />
1. Скачиваем образ по ссылкам.<br />
2. Скачиваем <a href="http://sourceforge.net/projects/win32diskimager/">Win32 Disk Imager</a> (делал под виной)<br />
3. Вставляем sd карту или флешку, и пишем на нее образ. После старта, ищет загрузчик сначала на MicroSD карте, если не находит его, тогда на внутреннем накопителе, и в конце на USB флешке.<br />
<br />
Пару команд на заметку:<br />
<br />
<pre class="brush:plain" style="background-color: #d6ded4; color: #333333; line-height: 18px; padding: 0px;"><span style="color: black; line-height: normal; white-space: normal;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">locale-gen ru_RU.UTF8</span></span><span style="font-size: 12px;"><span style="font-family: Courier New, Courier, monospace;">
</span>dpkg-reconfigure locales</span></pre>
<br />
<br />
Устанавливаем <a href="http://docs.cubieboard.org/tutorials/ct1/installation/cb3_lubuntu-12.10-desktop_nand_installation_v1.00">lubuntu</a> в nand с помощью <a href="http://docs.cubieboard.org/tutorials/common/livesuit_installation_guide">LiveSuitPack </a>(или PhoenixSuit1.0.6.rar for Windows). Нажимаем кнопку FEL вставляем miniUSB в компьютер. Отпускаем FEL после включения. Для чего это надо? С этим образом загрузочные разделы, в которых я честно говоря пока не особо шарю, поэтому проще будет сделать так.<br />
<br />
Далее, узнаем ip адрес устройства, заходим по ssh или подключаем клавиатуру.<br />
<br />
Дальше у меня возникла <a href="http://www.cubieforums.com/index.php/topic,1087.msg7343.html#msg7343">проблема</a> с этим портом для sd-карты. Многие кубитраки идут с багой - невозможно загрузить систему с SD карты. Испробовав разные комбинации обнаружил что если нажать ресет, а потом сразу вставить карту - система грузится! Потом нашел и другое <a href="http://www.cubieforums.com/index.php/topic,1139.0.html">решение </a>- загрузить андроид с nand, и перезагрузится из него.<br />
<br />
Попробуем скопировать другой <a href="http://dl.cubieboard.org/software/a20-cubietruck/lubuntu/ct-lubuntu-card0-v1.00/u-boot-sunxi-with-spl-ct-20131102.bin">загрузчик</a> (собранный для lubuntu) в карту (не в раздел,а прямо в устройство).<br />
<br />
<pre class="brush:plain" style="background-color: #d6ded4; padding: 0px;"><span style="color: #333333; font-size: 12px; line-height: 18px;">dd if=u-boot-sunxi-with-spl-ct-20131102.bin of=$card bs=1024 seek=8</span></pre>
<br />
<strike>В итоге в данном виде загрузка с SD карты у меня происходит без проблем.</strike><br />
Черт, вчера работало, сегодня нет, необъяснимо. :)
<br />
<br />
<div>
Форматируем после перезагрузки основной раздел, где лежит ОС (опять же загружаемся с sd карты пока).<br />
<br />
<pre class="brush:plain" style="background-color: #d6ded4; padding: 0px;"><span style="color: #333333; font-size: 12px; line-height: 18px;">mkfs.ext4 /dev/nandb</span></pre>
<pre class="brush:plain" style="background-color: #d6ded4; padding: 0px;"></pre>
<br />
Раздел /dev/nanda трогать, как <a href="http://sigpipe.me/?p=10">тут</a> смысла я думаю нет. Плюс в /dev/nand уже тоже есть загрузочный сектор, который уже подготовлен.<br />
<br />
<b>Установка</b>.<br />
<br />
rootfs, устанавливаем стабильный debian.<br />
<br />
<pre class="xml" name="code">apt-get update
apt-get install debootstrap
mount /dev/nandb /mnt/rootfs
debootstrap --verbose --arch armhf --variant=minbase --foreign stable /mnt/rootfs http://ftp.debian.org/debian
chroot /mnt/rootfs
/debootstrap/debootstrap --second-stage
cat <<END > /etc/apt/sources.list
deb http://ftp.debian.org/debian/ stable main contrib non-free
deb-src http://ftp.debian.org/debian/ stable main contrib non-free
deb http://ftp.debian.org/debian/ stable-updates main contrib non-free
deb-src http://ftp.debian.org/debian/ stable-updates main contrib non-free
deb http://security.debian.org/ stable/updates main contrib non-free
deb-src http://security.debian.org/ stable/updates main contrib non-free
END
apt-get update
export LANG=C
apt-get install apt-utils dialog locales
dpkg-reconfigure locales
# Выбираем en_US.UTF-8 или что сами хотите.
export LANG=en_US.UTF-8
apt-get install dhcp3-client udev netbase ifupdown iproute openssh-server iputils-ping wget net-tools ntpdate ntp vim nano less tzdata console-tools module-init-tools mc
cat <<END > /etc/network/interfaces
auto lo eth0
allow-hotplug eth0
iface lo inet loopback
iface eth0 inet dhcp
END
echo cubietruck > /etc/hostname
cat <<END > /etc/fstab
# /etc/fstab: static file system information.
#
#
proc /proc proc defaults 0 0
/dev/nandb / ext4 noatime,errors=remount-ro 0 1
END
passwd
/etc/init.d/ntp stop
exit
</pre>
<br />
<br />
Выключаем. Вытаскиваем SD карту. Включаем. <strike>Должно работать, но сети у меня пока нет. :) Исправлю - напишу.</strike></div> Продолжение "<a href="http://vermus.blogspot.ru/2013/12/debian-cubietruck-cubieboard-3.html">настройка debian на cubietruck</a>".
<br />
<span style="font-size: x-small;">Еще пару экспериментов для памяти (которые мне не помогли):</span><br />
<br />
<pre class="brush:plain" style="background-color: #d6ded4; padding: 0px;"><span style="color: #333333; line-height: 18px;"><span style="font-size: x-small;">под дескопной Виндой или Линуксом (од нашу АРМ систему не пойдет):</span></span></pre>
<pre class="xml" name="code">wget http://dl.cubieboard.org/software/a20-cubieboard/lubuntu/cb-a20-lubuntu-server-13.06-v1.00.img.gz
wget "http://forum.xda-developers.com/attachment.php?attachmentid=1740401&d=1361198061" -O "imgRePacker_204.zip"
gunzip cb-a20-lubuntu-server-13.06-v1.00.img.gz
unzip imgRePacker_204.zip
chmod 777 imgrepacker
./imgrepacker cb-a20-lubuntu-server-13.06-v1.00.img.gz
Заливаем через scp bootloader.fex
dd if=/usr/src/bootloader.fex of=/dev/nanda
</pre>
<span style="font-size: x-small;">это извлечение из nand образа загрузчика (какого-то уровня). imgrepacker <a href="http://forum.xda-developers.com/showthread.php?t=1753473">отсюда</a>.</span><br />
<br />Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com8tag:blogger.com,1999:blog-4797167376881538347.post-67079283423144137932011-12-18T19:27:00.000+04:002011-12-18T19:56:45.234+04:00Аналог who lock me в windows 7Была такая утилита, <a href="http://www.dr-hoiby.com/WhoLockMe/">who lock me</a>, которая замечательно работала в windows xp. Утилита позволяет узнать какой процесс блокирует файл или папку в windows.
К сожалению, в windows seven она уже не работает.<br />
<br />
Поэтому есть альтернатива: <a href="http://www.emptyloop.com/unlocker/">Unlocker</a>.<br />
<br />
Также на сайте указана табличка с альтернативами, может вам хватит <a href="http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx">Process Explorer</a> от Sysinternals или <a href="http://lockhunter.com/">LockHunter</a> от Crystal Rich.Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com0tag:blogger.com,1999:blog-4797167376881538347.post-38135470866332094572010-11-06T11:00:00.003+03:002010-11-06T11:04:53.456+03:00musicmans.ru | Как сделать сайт на Django | GWTПосмотрел я на дерево <a rel="nofollow" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhH9FQV0UFslwL1KuenfLCZ6EaxEr-UibEX0A3SrsoBnhnM8RiJcD-zzvoQ113uXd8Tnl_EcrWMYH7tpiOqU0zbISBAJOr7OHvwn9rFrW8W9CrQ7h9DeIMUC27p2DdNx7iujMN6sSq3/s400/musicmans.ru+gernres+directions+styles.png">жанров</a> и оно мне не понравилось. Страшное, неудобное. И решил сразу заняться клиентской стороной. Тем более у нас есть отличнейший <a rel="nofollow" href="http://googlewebtoolkit.blogspot.com/2010/09/google-relaunches-instantiations.html">повод</a>!<br /><br />Итак, настроим gwt. Скачиваем <a rel="nofollow" href="http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/heliosr">eclipse 3.6</a> для java. <br />Далле переходим на страницы с <a rel="nofollow" href="http://code.google.com/intl/ru-RU/webtoolkit/download.html">загрузками GWT</a>. Ставим <a rel="nofollow" href="http://code.google.com/intl/ru-RU/eclipse/docs/download.html">gwt плагин</a> для eclipse.<br /><br />Создаем проект File > New > Web Application Project.<br /><br />Название: genre<br />package: ru.musicmans<br /><br />Запуск - Debug As > Web Application.<br /><br />Переходим по адресу, устанавливаем плагин. Все работает.<br /><br />Устанавливаем <a rel="nofollow" href="http://code.google.com/intl/ru-RU/webtoolkit/tools/download-gwtdesigner.html">GWT Designer</a>. Читаем <a rel="nofollow" href="http://code.google.com/intl/ru-RU/webtoolkit/tools/gwtdesigner/quick_start.html">quick start</a>.<br /><br />Далее можно конвертировать, созданный проект из gwt plugin (gwt plugin мы поставили потому, что в нем все равно находиться сам gwt) в gwt java project, который идет с дизайнером (правой кнопкой на проекте - convert to) или создать новый:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWiGX6qVUZsoW42cHy5jfZ0R1L9ok_0VbEluIbewtz-onNZ4kZZvCH_Ta9r68l8vC41mOntgOhUf9j-jiCwpaH0DVmIBuKZXp27cF-_Ci4xF5OuoOOIUBBqvGc4elyBIWbx9o68EkW/s1600/gwt+java+project.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 380px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWiGX6qVUZsoW42cHy5jfZ0R1L9ok_0VbEluIbewtz-onNZ4kZZvCH_Ta9r68l8vC41mOntgOhUf9j-jiCwpaH0DVmIBuKZXp27cF-_Ci4xF5OuoOOIUBBqvGc4elyBIWbx9o68EkW/s400/gwt+java+project.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5519289297191650290" /></a><br /><br />Сразу создадим модуль ru.musicmans.genre.GenreTree:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1suZ_yUbK9lZWHWNcDvL_-uFP_lOP_y8Spk94VNlvYi0vgJt7O4Bwg6ujJtZ3BRVy92mMucX_94qMCxF1QlqjLD6GdPqwOoNy6NZ6EUhhwzhKecawYp5h4BgxNiCHETUk8AzQUA1J/s1600/new+module.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 266px; height: 47px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1suZ_yUbK9lZWHWNcDvL_-uFP_lOP_y8Spk94VNlvYi0vgJt7O4Bwg6ujJtZ3BRVy92mMucX_94qMCxF1QlqjLD6GdPqwOoNy6NZ6EUhhwzhKecawYp5h4BgxNiCHETUk8AzQUA1J/s400/new+module.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5526778127273659074" /></a><br /><br />Итак, проект создан. Открываем genre.java и кликаем на вкладку Design.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaO5HC-FlmYMPmigSXiATR0OHWoNfxbvvQoT0nPxjhyphenhyphen1zpbwmuLh3yqcLc7ko9VQT7Vv-Y2k-isL0I1pdyXGnuPP-k3yAjk2aPXYuf6CcBTnVbYjhwiy_a4JI9y9Fw3Vlk924hxYNZ/s1600/genre+design.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 287px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaO5HC-FlmYMPmigSXiATR0OHWoNfxbvvQoT0nPxjhyphenhyphen1zpbwmuLh3yqcLc7ko9VQT7Vv-Y2k-isL0I1pdyXGnuPP-k3yAjk2aPXYuf6CcBTnVbYjhwiy_a4JI9y9Fw3Vlk924hxYNZ/s400/genre+design.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5526778829451831234" /></a><br /><br />Что нам надо для организации передачи данных? Мы не можем использовать rpc call gwt, так как у нас на стороне сервера django. Что делать в данном случае? Я рассматривал <a href="http://vermus.blogspot.com/2009/12/gwt-django.html">данный вопрос</a> около года назад. Итог такой: возможен вывод данных в темплейте и преобразование их в javascript object, но это не очень оптимальный путь, тем более, что приложению обычно нужны данные в процессе работы (в том числе, обновленные). Поэтому лучшим решением мне предоставляется <a href="http://vermus.blogspot.com/2010/02/smartgwt-django-rest.html">REST</a> (с помощью этого подхода не надо проходить новый путь создания интерфейсов сервисов). Я решил не использовать SmartGWT, слишком он навороченный. В чистом GWT нет поддержки REST, поэтому воспользуемся <a href="http://www.restlet.org/downloads/testing">Restlet Framework</a>, ну а со стороны django - <a rel="nofollow" href="http://bitbucket.org/jespern/django-piston/wiki/Home">django-piston</a>.<br /><br />Скачаем <a rel="nofollow" href="http://www.scribd.com/doc/23792711/Presentation-Restlet">Restlet Framework</a>, Edition for Google Web Toolkit. Установим (укажем java build path в свойствах проекта).<br /><br /><span style="font-weight:bold;">Django-Piston</span><br /><br />Теперь перейдем к серверной стороне. django-piston я уже как-то <a href="http://vermus.blogspot.com/2010/02/smartgwt-django-rest.html">упоминал</a>. Так вот, устанавливаем:<br /><br />>c:\Python26\Scripts\pip.exe install hg+http://bitbucket.org/jespern/django-piston@c4b2d21db51a#egg=piston<br /><br />Читаем <a href="http://bitbucket.org/jespern/django-piston/wiki/Documentation">документацию</a>. Создадим приложение api, пропишем (r'^api/', include('api.urls')), в главном urls.py. Создадим в приложении файлы urls.py и handlers.py. Остальные файлы, кроме __init__.py можно удалить. <br />handlers.py:<br /><pre name="code" class="py"><br />from django.core.urlresolvers import reverse<br /><br />from piston.handler import BaseHandler#@UnresolvedImport<br /><br />from genre.models import GenreDirStyle#@UnresolvedImport<br /><br />class GenreHandler(BaseHandler):<br /> allowed_methods = ('GET', )<br /> fields = ('name', 'type', 'url' )<br /> model = GenreDirStyle<br /><br /> @classmethod<br /> def url(self, genre):<br /> return reverse('genre_genre', args=[genre.id])<br /><br /> def read(self, request, genre_id):<br /> genre = GenreDirStyle.objects.get(id=int(genre_id))<br /> return genre<br /></pre><br />urls.py:<br /><pre name="code" class="py"><br />from django.conf.urls.defaults import *<br /><br />from piston.resource import Resource#@UnresolvedImport<br /><br />from api.handlers import GenreHandler#@UnresolvedImport<br /><br />genre_resource = Resource(handler=GenreHandler)<br /><br />urlpatterns = patterns('',<br /> url(r'^genre/(?P<genre_id>[^/]+)/$', genre_resource, name='api_genre_id'), <br /> )<br /></pre><br /><br />Переходим по адресу, например http://localhost:8000/api/genre/3/ :<br /><pre name="code" class="json"><br />{<br /> "url": "/genre/id/4/", <br /> "type": 3, <br /> "name": "Prog-Rock"<br />}<br /></pre><br />Чтобы открывать application/json в firefox, установите <a rel="nofollow" href="https://addons.mozilla.org/en-US/firefox/addon/8207/">дополнение</a>, а еще лучше используйте <a href="https://addons.mozilla.org/en-US/firefox/addon/9780">RESTClient для Firefox</a>.<br /><br /><span style="font-weight:bold;">Вернемся к клиентской части.</span><br /><br />Добавим widget дерево в gwt приложение tree:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgH4IoD1X6bAwEm5FuzXQBmmo6UEP2Pi4IxbXmBTPeiJNk9iTQPh19x0j5LFxhCKp-DVJWl2Qtp0RtKQdY3fSpBJTsoU6erk3ee_ZdL1_nwZeXayn6e1ugNcPww9eEn2SeKltsAnYD9/s1600/gwt+designer+add+tree.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 251px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgH4IoD1X6bAwEm5FuzXQBmmo6UEP2Pi4IxbXmBTPeiJNk9iTQPh19x0j5LFxhCKp-DVJWl2Qtp0RtKQdY3fSpBJTsoU6erk3ee_ZdL1_nwZeXayn6e1ugNcPww9eEn2SeKltsAnYD9/s400/gwt+designer+add+tree.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5519998645858079090" /></a><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoPVqNAVNJQ5CsTket2qgy59U4aTX0JVUEnhIZy794-mRYZtNI_CFPyi4JCOZJM7GBQUoXm2Sz_uEGmcsf7ZczQujbqam_jxD01q8Lz1cSdtWtO-7ihCVkE7y1bU9n5mJE4jL8yuxa/s1600/gwt+designer+add+tree+item.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 349px; height: 400px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoPVqNAVNJQ5CsTket2qgy59U4aTX0JVUEnhIZy794-mRYZtNI_CFPyi4JCOZJM7GBQUoXm2Sz_uEGmcsf7ZczQujbqam_jxD01q8Lz1cSdtWtO-7ihCVkE7y1bU9n5mJE4jL8yuxa/s400/gwt+designer+add+tree+item.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5520045758776653058" /></a><br /><br /><br />Запускаем отладку, кстати, сразу рекомендую изменить параметр logLevel в конфигурации отладки.<br /><br />С помощью firebug видим, что ответа на запрос по адресу http://localhost:8000/api/genre/3 не увенчались успехом, поэтому вспоминаем про <a href="http://vermus.blogspot.com/2009/12/gwt-django.html">проблему SOP</a>.<br /><br />В процессе поиска решений наткнулся на <a rel="nofollow" href="http://gist.github.com/426829">django-crossdomainxhr-middleware.py</a>, позволяющее использовать <a rel="nofollow" href="https://developer.mozilla.org/En/HTTP_access_control">кроссдоменные запросы</a> (требуется firefox > 3.5).<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0K22H4K3pkLqBCSZbl3OQXCcp_nK0W9waxuYsDGla5S4FmNjpQZW2itk9MCwhF3boswd135Ia5tchkZTIzCGNDtYbw2KrO2LAunGdIr9Xhfqgk5qaFZFNVOKgxJSqPBRVRxU0d_7u/s1600/SOP+headers.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 182px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0K22H4K3pkLqBCSZbl3OQXCcp_nK0W9waxuYsDGla5S4FmNjpQZW2itk9MCwhF3boswd135Ia5tchkZTIzCGNDtYbw2KrO2LAunGdIr9Xhfqgk5qaFZFNVOKgxJSqPBRVRxU0d_7u/s400/SOP+headers.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5521851616368631810" /></a><br /><br />Но мы пока его использовать не будем.<br /><br />Итак, проблему SOP при разработке решим следующим образом. Отключим Jetty сервер, запускаемый в отладке, а также укажем порт 8000.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEircbpwoL_gY7nzlRFOMTZOMM1Ou3OpzCnV43E7Jhhjdmx2VhCvxx2oHRIx1MSPVhVpdMJRw_Sl7LZ4PE8JUZTWbi8_wymki6TbMDuJMZU30qyT_n7NJckmW8r5B9DFtTLwJRQFc4OY/s1600/gwt+noserver.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 363px; height: 117px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEircbpwoL_gY7nzlRFOMTZOMM1Ou3OpzCnV43E7Jhhjdmx2VhCvxx2oHRIx1MSPVhVpdMJRw_Sl7LZ4PE8JUZTWbi8_wymki6TbMDuJMZU30qyT_n7NJckmW8r5B9DFtTLwJRQFc4OY/s400/gwt+noserver.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5522578356080532562" /></a><br /><br />Сделаем символическую ссылку с директории war проекта на www\media\static\gwt\genre, под windows, например, так:<br /><br />www\media\static\gwt>mklink /d genre d:\path\to\gwt\war\<br /><br />Далее, можно отлаживать приложение по адресу примерно такому (предварительно запустив веб-сервер отладки django) http://localhost:8000/media/static/gwt/genre/GenreTree.html?gwt.codesvr=127.0.0.1:9997 адресу. Параметр gwt.codesvr обязателен при отладке gwt приложения.<br /><br />А еще лучше создать темплейт django, подключив к нему приложение gwt примерно следующим образом. Создаем div с id='genreTreeEntryPointId' в темплейте, а в gwt root panel определяем следующим образом: <br />RootPanel rootPanel = RootPanel.get("genreTreeEntryPointId");<br /><br />Теперь мы можем отлаживать gwt приложение прямо в "окружении" django-проекта, например, по адресу такому http://localhost:8000/genre/tree/?gwt.codesvr=127.0.0.1:9997&genre_id=2 .<br /><br />Серверный и клиентский код выкладывать слишком много, остановимся на нюансах:<br /><br />- Выбор конкретного жанра в дереве (например при нажатии на меню жанров сверху). В этом случае загрузка списка для создания дерева вложенного множества осуществляется следующим образом (нам надо загрузить ветку, каждый элемент которой должен загрузить соседей):<br /><pre name="code" class="py"><br /> treeqs = GenreDirStyle.objects.raw("""SELECT t2.*<br /> FROM genre_genredirstyle AS t1<br /> LEFT JOIN genre_genredirstyle AS t2<br /> ON t2.lft BETWEEN t1.lft AND t1.rgt<br /> WHERE t1.lft < %s AND t1.rgt > %s AND t1.tree_id = 1 AND t2.depth-1 = t1.depth AND t2.tree_id = %s<br /> ORDER BY t2.lft;""", (genre.lft, genre.rgt, genre.tree_id))<br /></pre><br />Построение дерева решил возложить на плечи клиентов.<br />- При загрузке приложения выводим div с изображением, который заменяется самим приложением, после его загрузки, а также выполнения всех ajax запросов.<br />- Настройки приложения выводим как JSON объект в javascript, получая значения которого в gwt приложении:<br /><pre name="code" class="py"><br />private final Dictionary paramsDict = Dictionary.getDictionary("gwtGenreParameters");<br />String paramsDict.get("API_GENRES_MAIN_URL");<br /></pre><br />- Автоматический разбор JSON ответа. Используем данное <a href="http://code.google.com/p/piriti/wiki/RestletExtension">приложение</a>.<br />Оно зависит от: google-gin и totoe (погуглите и подключайте в проект).<br />- Для обозначения состояния элемента дерева используем своей объект класса (сокращенный вид):<br /><pre name="code" class="java"><br /> private class GenreTreeItemData<br /> {<br /> private int id;<br /> private Boolean alreadyLoaded = false;<br /> private String description;<br /> }<br /></pre><br />используя функцию setUserObject(Object).<br />- При создании проекта, в настройках gwt приложения наследуется стиль по умолчанию gwt standart. Так вот, проблема в том, что в нем есть правила css, переопределяющие наши (в том числе body). Решить это можно двумя способами, вот <a rel="nofollow" href="http://groups.google.fr/group/Google-Web-Toolkit/msg/3e630a3059303b19">первый</a>, а можно просто удалить нежелательные строки из standard.css файла в директории gwt\standard\ (их там немного и они вначале).<br />- Для генерации документации по API используем вид from piston.doc import documentation_view.<br /><br />После работы все как обычно и результат:<br /><br /><a rel="nofollow" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlTSGCzw95pPO8KIpEJiRUDAYu8S3FGs6yJ6_r7YE1B6bo0RznL9Jj8WX24s4-_p0C8KoVX8LQkzNLugk4ZPe8x3NJoyPa08w328_W1aIFDsmUC4NWd6vMkjV8k_OVQTj-G9PwpK1G/s1600/genres.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 366px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlTSGCzw95pPO8KIpEJiRUDAYu8S3FGs6yJ6_r7YE1B6bo0RznL9Jj8WX24s4-_p0C8KoVX8LQkzNLugk4ZPe8x3NJoyPa08w328_W1aIFDsmUC4NWd6vMkjV8k_OVQTj-G9PwpK1G/s400/genres.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5536332419443991042" /></a><br /><br />ps. На стороне сервера попробовал <a href="http://oradir.blogspot.com/2010/08/aptana-3-beta.html">использовать Aptana 3.0</a>, там действительно отменная поддержка Django темплейтов в PyDev (но наткнулся на баг, ctrl+space вешает IDE, может только у меня так?).Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com2tag:blogger.com,1999:blog-4797167376881538347.post-3628133869120858662010-09-15T17:00:00.005+04:002010-09-16T10:20:13.277+04:00musicmans.ru | Как сделать сайт на Django | Жанры, направления, стилиПрошу прощения за долгое отсутствие. <br />Пишем следующее приложение. Я решил, что жанры, направления и стили; инструменты; композиции; исполнители будут у нас отдельными приложениями, потому что планирую, что они обрастут серьезной функциональностью.<br /><br />Начнем с жанров, направлений и стилей. Создадим приложение genre, сразу создаем модель жанра.<br />Чтобы создать модель, нам надо определиться, что такое жанр собственно? К сожалению, в русском интернете, большая путница и мешанина из жанров, стилей и направлений. Нет ни <a rel="nofollow" href="http://books.google.ru/books?id=Y1OoJE0cu-EC&printsec=frontcover">исследований</a>, ни достаточно устоявшихся критериев. <a rel="nofollow" href="http://www.csl.sony.fr/downloads/papers/2000/pachet-riao2000.pdf">Прочитав эту заметку</a> начал задумываться структуре систематизации жанров и стилей. И главное, неплохо было бы найти уже существующую отлаженную структуру (<a rel="nofollow" href="http://moustaki.org/resources/styles.owl">Amazon</a>). После долгих поисков (amg, amazon, mp3.com, discogs) остановился на варианте от <a rel="nofollow" href="http://allmusic.com/cg/amg.dll?p=amg&sql=73:">amg</a>. <br /><br />Итак, напишем модель жанра, направления и стиля и заполним их структурой. <br /><br />Так как я один, и у меня нет редакторов, то пришлось воспользоваться результатом чужих трудов и спарсить структуру жанров, направлений и стилей с amg. Надеюсь они на меня за это не в обиде.<br /><br />Код приводить не буду, расскажу что использовал <a rel="nofollow" href="http://codespeak.net/lxml">lxml</a>, а также окружение проекта для записи жанров/стилей.<br /><br />После того как данные в базе, сделаем <a rel="nofollow" href="http://docs.djangoproject.com/en/dev/howto/initial-data/">initial data</a> для приложения:<br /><br />>python manage.py dumpdata genre > apps\genre\fixtures\initial_data.json<br /><br />Теперь попробуем вывести дерево жанров/стилей.<br /><br />На данном этапе понимаем, что вывод "детей" стилей сулит нам лавинообразные запросы к базе данных (<a rel="nofollow" href="http://docs.djangoproject.com/en/dev/ref/models/querysets/#select-related">select_related</a> нам тоже не поможет, он не срабатывает для моделей с полями отношения ForeignKey с null=True ( father = models.ForeignKey('self', verbose_name=_(u'Родитель'), related_name='child_dirs_styles', null=True) ) ), поэтому воспользуемся приложением для <a rel="nofollow" href="http://www.slideshare.net/quipo/trees-in-the-database-advanced-data-structures?type=presentation">хранения деревьев</a> в базе данных <a rel="nofollow" href="http://github.com/tabo/django-treebeard/">django-treebeard</a> (<a rel="nofollow" href="https://tabo.pe/projects/django-treebeard/docs/tip/">документация</a>). <br /><br />C:\>c:\Python26\Scripts\pip.exe install git+git://github.com/tabo/django-treebeard@8eb52a4f4274615e86a7572a8bab39b79d718b88<br /><br />Добавляем 'treebeard' в INSTALLED_APPS. Если вы используете админку, то настройка немного <a rel="nofollow" href="https://tabo.pe/projects/django-treebeard/docs/tip/intro.html#configuration">посложней</a>. <br /><br /><a rel="nofollow" href="https://tabo.pe/projects/django-treebeard/docs/tip/intro.html#basic-usage">Воспользуемся</a> моделью хранения деревьев <a rel="nofollow" href="http://www.getinfo.ru/article610.html">Nested Sets</a>. Не стоит пугаться последней ссылки, тем то и хорошо приложение treebeard, что за нас уже <a rel="nofollow" href="https://tabo.pe/projects/django-treebeard/docs/tip/ns_tree.html#treebeard.ns_tree.NS_Node">решен вопрос хранения деревьев</a> в SQL базе. Нам лишь стоит воспользоваться набором функций.<br /><br />Смотрим нашу модель:<br /><pre name="code" class="py"><br /># -*- coding:utf-8 -*-<br />from django.db import models<br />from django.utils.translation import ugettext_lazy as _<br />from treebeard.ns_tree import NS_Node #@UnresolvedImport <br /><br />GENRE_DIR_STYLE = (<br /> (0, _('Музыка')),<br /> (1, _('Жанр')),<br /> (2, _('Направление')),<br /> (3, _('Стиль')),<br />)<br /><br />class GenreDirStyle(NS_Node):<br /> name = models.CharField(max_length=1000, verbose_name=_(u'Title'))<br /> name_ru = models.CharField(max_length=1000, verbose_name=_(u'Название'), blank=True, null=True)<br /> type = models.IntegerField(choices=GENRE_DIR_STYLE)<br /> description = models.CharField(max_length=10000, verbose_name=_(u'Описание'), blank=True)<br /><br /> class Meta:<br /> ordering = ["name"]<br /> verbose_name = _(u'Жанр, направление, стиль')<br /></pre><br /><br />Пробуем, работает ли миграции South с treebeard:<br /><br />./manage.py schemamigration genre --auto<br /><br />получаем сообщение следующего <a rel="nofollow" href="http://south.aeracode.org/docs/tutorial/part2.html">вида</a><br /><br />? The field 'GenreDirStyle.lft' does not have a default specified, yet is NOT NULL.<br /> ? Since you are adding or removing this field, you MUST specify a default<br /> ? value to use for existing rows. Would you like to:<br /> ? 1. Quit now, and add a default to the field in models.py<br /> ? 2. Specify a one-off value to use for existing columns now<br /> ? Please select a choice:<br /><br /><a rel="nofollow" href="http://bitbucket.org/tabo/django-treebeard/issue/8/support-for-migrating-to-django-treebeard-null-true-in-the-model">South нас просит указать обязательное значение</a> по умолчанию. Нажимаем 2, и значение 0.<br /><br />Как создать <a rel="nofollow" href="https://tabo.pe/projects/django-treebeard/docs/tip/api.html#treebeard.models.Node">дерево</a>? Просто:<br />1. Создаем корень дерева.<br />pop_music = GenreDirStyle.add_root(name = "Популярная музыка", type = 0)#оно сразу сохраняется save()<br />2. Создаем жанр:<br />pop_music.add_child(name = "Rock", type = 1)<br /><br />И здесь сталкиваемся с <a href="http://bitbucket.org/tabo/django-treebeard/issue/29/ns_node-do-not-cache-lft-rgt-on-insert">проблемой</a>, в случае парсинга (см. выше) html и создания базы "на лету". Поэтому читаем <a rel="nofollow" href="https://tabo.pe/projects/django-treebeard/docs/1.61/intro.html#basic-usage">basic-usage</a> внимательней и переписываем примерно так:<br /><pre name="code" class="py"><br />>>> get = lambda node_id: Category.objects.get(pk=node_id)<br />>>> root = Category.add_root(name='Computer Hardware')<br />>>> node = get(root.id).add_child(name='Memory')<br />>>> get(node.id).add_sibling(name='Hard Drives')<br /><Category: Category: Hard Drives><br />>>> get(node.id).add_sibling(name='SSD')<br /><Category: Category: SSD><br />>>> get(node.id).add_child(name='Desktop Memory')<br /><Category: Category: Desktop Memory><br />>>> get(node.id).add_child(name='Laptop Memory')<br /><Category: Category: Laptop Memory><br />>>> get(node.id).add_child(name='Server Memory')<br /><Category: Category: Server Memory><br /></pre><br />Не забудем обновить json данные, после изменения и миграций моделей.<br />Для вывода дерева жанров используем функцию <a rel="nofollow" href="https://tabo.pe/projects/django-treebeard/docs/tip/api.html#treebeard.models.Node.get_tree">get_tree</a>.<br /><br /><pre name="code" class="py"><br /># -*- coding: utf-8 -*-<br />from annoying.decorators import render_to#@UnresolvedImport<br />from django.shortcuts import get_object_or_404<br /><br />from models import GenreDirStyle<br /><br />@render_to('genres/genre_tree.html')<br />def genre_tree(request):<br /><br /> pop_genre = GenreDirStyle.objects.get(name="Популярная музыка", type=0)<br /> classic_genre = GenreDirStyle.objects.get(name="Классическая музыка", type=0)<br /><br /> pop_tree = GenreDirStyle.get_tree(pop_genre)<br /> classic_tree = GenreDirStyle.get_tree(classic_genre)<br /> <br /> return {<br /> 'pop_tree': pop_tree,<br /> 'classic_tree': classic_tree<br /> } <br /><br />@render_to('genres/genre_genre.html')<br />def genre_genre(request, genre_id):<br /> <br /> genre = get_object_or_404(GenreDirStyle, id = int(genre_id))<br /><br /> return {<br /> 'genre': genre<br /> } <br /></pre><br />На данном этапе django-toolbar показывал замечательные 5 запросов за 13 мс. А вот общая генерация страницы занимала 6573.00 ms. Это очень долго, хотя при выключенном debug режиме ощутимо быстрее. Все упирается в рендеринг. Проэтому применим кеш в темплейте (на шесть часов, например):<br /><pre name="code" class="xml"><br />{% load cache %}<br />{% cache 21600 pop_tree_chache %}<br />{% for node in pop_tree %}<br /> {% include "genres/genre_node.html" %}<br />{% endfor %}<br />{% endcache %}<br /></pre><br />А также включим на время (позже настроим memcached на сервере) <a href="http://djbook.ru/ch13.html#djangobook.chap13.setup.simple-caching">кеширование в память</a>, в settings/common.py:<br /><br />CACHE_BACKEND = 'locmem:///'<br /><br />Темплейты интуитивно понятны, покажу лишь темплейт жанра, включаемый в цикл вывода дерева. <br /><pre name="code" class="xml"><br />{% load dj_tags %}<br /><div style="padding-left:{{ node.get_depth|multiply:20|subtract:20 }}px;"><br /><h{{ node.type|add:"1" }}><br /><a href="{% url genre_genre node.pk %}">{% if node.get_depth > 1 %}{{ node.get_type_display }} {% endif %}{{ node.name }}</a><br /></h{{ node.type|add:"1" }}><br /></div><br /></pre><br />(Ужасно, blogger все сломал, смотрите <a rel="nofollow" href="http://pastebin.com/SWEHzsMX">здесь</a>)<br />Обратите внимание на фильтр multiply и substract. Это не стандартные фильтры django, а <a rel="nofollow" href="http://docs.djangoproject.com/en/dev/howto/custom-template-tags/">написаные в нашем приложении</a> dj_tags.<br /><pre name="code" class="py"><br /># -*- coding: utf-8 -*-<br />from django import template<br />register=template.Library()<br /><br />@register.filter(name='multiply')<br />def multiply(value, arg):<br /> return int(value) * int(arg)<br /><br />@register.filter(name='subtract')<br />def subtract(value, arg):<br /> return int(value) - int(arg)<br /></pre><br />Итак, мы познакомились с хранением деревьев в базе данных с django, их выводом, затронули кеширование, написали пару темплейт тегов.<br /><br />Ну, окончание, как обычно, тесты, мерж, развертывание.<br /><br /><a rel="nofollow" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgg2uZxj5zYYdKcY1_j5xIugZMql0TqIkI6Qrgb0bH59uG6EV0byBCosrPeVVUSwXKJS44z7WeC7KjCFK17Pw4Ofuo9IJGo8abG0NfjI8ZguhxSnv_hTeRsy-7GGDXX3DOTAiCbDwZN/s1600/musicmans.ru+prog-rock+style.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 283px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgg2uZxj5zYYdKcY1_j5xIugZMql0TqIkI6Qrgb0bH59uG6EV0byBCosrPeVVUSwXKJS44z7WeC7KjCFK17Pw4Ofuo9IJGo8abG0NfjI8ZguhxSnv_hTeRsy-7GGDXX3DOTAiCbDwZN/s400/musicmans.ru+prog-rock+style.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5517121932504456834" /></a><br /><a rel="nofollow" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhH9FQV0UFslwL1KuenfLCZ6EaxEr-UibEX0A3SrsoBnhnM8RiJcD-zzvoQ113uXd8Tnl_EcrWMYH7tpiOqU0zbISBAJOr7OHvwn9rFrW8W9CrQ7h9DeIMUC27p2DdNx7iujMN6sSq3/s1600/musicmans.ru+gernres+directions+styles.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 286px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhH9FQV0UFslwL1KuenfLCZ6EaxEr-UibEX0A3SrsoBnhnM8RiJcD-zzvoQ113uXd8Tnl_EcrWMYH7tpiOqU0zbISBAJOr7OHvwn9rFrW8W9CrQ7h9DeIMUC27p2DdNx7iujMN6sSq3/s400/musicmans.ru+gernres+directions+styles.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5517121922437947026" /></a><br /><br />ps. Не забудем <a rel="nofollow" href="http://www.djangoproject.com/weblog/2010/sep/08/security-release/">обновить</a> django (>c:\Python26\Scripts\pip.exe install --upgrade Django и прописать в requirements.txt)!Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com0tag:blogger.com,1999:blog-4797167376881538347.post-27452214561905596822010-08-07T10:24:00.004+04:002010-08-09T09:03:42.160+04:00musicmans.ru | Как сделать сайт на Django | Пользователи. Личные сообщения. УведомленияПока Вы <a href="http://vermus.blogspot.com/2010/08/musicmansru-django.html">разбираетесь с тестированием</a> в django, попутно приступим к личным сообщениям, без них трудно представить современный веб-сайт. <br />Перед тем как приступить, установим <a rel="nofollow" href="http://github.com/robhudson/django-debug-toolbar">еще такую вещь</a> на машину разработчика. <br /><br />#pip install git+git://github.com/robhudson/django-debug-toolbar<br />Смело ставим последнюю версию, ибо если что-то сломается, то на машине разработчика это не критично.<br />development.py:<br /><pre name="code" class="py"><br />INSTALLED_APPS += (<br /> 'django.contrib.admin',#tests<br /> 'debug_toolbar',<br /> )<br /><br />MIDDLEWARE_CLASSES += ( <br /> 'debug_toolbar.middleware.DebugToolbarMiddleware',<br /> )<br /><br />INTERNAL_IPS = ('127.0.0.1',)<br /></pre><br /><br />Обновляем localhost:<br /><a rel="nofollow" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDYe7LAjRrjrNoGra1fg9BS6woHbPDrgfSYB9ES-PCwxFx1TTTdFTL6kkbC8YKGUgsIBId8Dzd8U8aSkArgdAeakYTPXYixpu0VPVedz0SumjCLuL61FvoXLhADdp-zWsdRhBcsYHP/s1600/django+toolbar.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 295px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDYe7LAjRrjrNoGra1fg9BS6woHbPDrgfSYB9ES-PCwxFx1TTTdFTL6kkbC8YKGUgsIBId8Dzd8U8aSkArgdAeakYTPXYixpu0VPVedz0SumjCLuL61FvoXLhADdp-zWsdRhBcsYHP/s400/django+toolbar.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5501433039572862690" /></a><br /><br />Поинтересуйтесь содержимым пунктов меню, там много интересного.<br /><br />Итак, личные сообщения. Опять <a rel="nofollow" href="http://code.google.com/p/django-messages/">все написано</a> за нас. Устанавливаем из транка (кстати, вот консольный <a rel="nofollow" href="http://www.sliksvn.com/en/download/">svn клиент</a> для windows):<br /><br />>pip.exe install svn+http://django-messages.googlecode.com/svn/trunk/@141#egg=django_messages<br /><br />141-я ревизия транка на данный момент, как написано на странице проекта это будущая версия 0.5, совместимая с Django 1.2 (как раз то, что нам нужно). Не забываем requirements.txt (кстати, я подумал, что неплохо было бы сначала добавлять строчку в requirements.txt, а ставить основываясь на файле. Надо только использовать одну директорию с кешом pip, чтобы он постоянно не скачивал дистрибутивы. Ставить установленные приложения по новой он не будет, но мы будем уверены, что не забудем прописать все приложения в requirements.txt и не испытаем проблем на сервере с сайтом).<br /><br /><a rel="nofollow" href="http://code.google.com/p/django-messages/source/browse/trunk/docs/usage.txt">Документация</a> по настройке. Тут кстати возникает путаница, <a rel="nofollow" href="http://code.google.com/p/django-messages/source/browse/trunk/setup.py">здесь</a> приложение указано как django_messages, а в документации используется messages, так что используем django_messages.<br /><br /><a rel="nofollow" href="http://code.google.com/p/django-messages/source/browse/trunk/docs/customizing.txt">Изменим темплейты</a>.<br /><br />Скопируем из приложения и изменим под свои нужды.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioGsEujY9u6kiJAA3qAiUMv91Ch6IhJpggYJBuMRTnvzJKoxPy3CVnk-azWXD0JZHTC7KcYmGsZs-MBt-a1uLwQWD8D151Ths1Rk3OcucWpe4T66uuHqKaO7YrQT5wVpm5bqcxWmWt/s1600/django+messages+templates.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 275px; height: 224px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioGsEujY9u6kiJAA3qAiUMv91Ch6IhJpggYJBuMRTnvzJKoxPy3CVnk-azWXD0JZHTC7KcYmGsZs-MBt-a1uLwQWD8D151Ths1Rk3OcucWpe4T66uuHqKaO7YrQT5wVpm5bqcxWmWt/s400/django+messages+templates.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5501487155501690370" /></a><br /><br />В документации к приложению читаем, что оно использует <a href="http://vermus.blogspot.com/2010/07/musicmansru-django_31.html">django-mailer</a> и <a rel="nofollow" href="http://github.com/jtauber/django-notification/">django-notification</a>, если они установлены. Первое у нас есть, ставим второе (хорошее приложение, пригодится в будущем).<br />>pip.exe install git+git://github.com/jtauber/django-notification@3f023adf0ce2eafcee744904e2c358792f253721@egg=notification<br /><br />Пропишем 'django_messages', 'notification' в приложения, настроим url.py. Синхронизируем базу.<br /><br />Просмотрим таблицу notification_noticetype, в ней должны находиться оповещения о работе с личными сообщениями. Приложение notification рассмотрим ниже.<br /><br />Как только мы видим список чего бы то ни было (список входящих сообщений), сразу рождаются мысли о пагинации. И как не удивительно :-) , django <a rel="nofollow" href="http://docs.djangoproject.com/en/dev/topics/pagination/">поддерживает ее из</a> коробки, а чтобы было совсем просто установим приложение <a rel="nofollow" href="http://github.com/ericflo/django-pagination">django-pagination</a>.<br /><br />>pip.exe install git+git://github.com/ericflo/django-pagination@47e7ec874cd7dddda5ed13ffb6993a64dced2537<br /><br /><a rel="nofollow" href="http://github.com/ericflo/django-pagination/blob/master/docs/usage.txt">Настраиваем</a>. Добавляем css разметку.<br /><br />А также переведем пару строк, так как в приложении нет русской локализации, djutils\locale\ru_RU\LC_MESSAGES\django.po:<br />msgid "previous"<br />msgstr "назад"<br /><br />msgid "next"<br />msgstr "вперед"<br /><br />Не забудем скомпилировать.<br /><br />в темплейтах с сообщениями добавляем (с месторасположением самостоятельно, 2-ка для теста):<br /><pre name="code" class="xml"><br />{% load pagination_tags %}<br />{% autopaginate message_list 2 %}<br />{% paginate %}<br /></pre><br /><br />В итоге получается:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGMnkiS8ZIDP7OQlPa1jgaEnvAWoBY5tNxMOZx1j6klejko4AJhCSnX_QlNUAh8G8EjlJUjF7d14KEBjPwFlCw6KmpqjMlH47eiivUgKQQZdY1zjYKlgS2w0jTPNlnKYqpU7r42xk3/s1600/django+pagination+messages.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 78px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGMnkiS8ZIDP7OQlPa1jgaEnvAWoBY5tNxMOZx1j6klejko4AJhCSnX_QlNUAh8G8EjlJUjF7d14KEBjPwFlCw6KmpqjMlH47eiivUgKQQZdY1zjYKlgS2w0jTPNlnKYqpU7r42xk3/s400/django+pagination+messages.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5501818569299710994" /></a><br /><br />Чтобы пользователи не были у нас безликими, давайте организуем им вывод профайлов.<br />В user/url.conf<br /><pre name="code" class="py"><br />url(r'^profile/(?P<userprofile_id>\d+)/$', users_views.userprofile, name='users_profile'),<br /></pre><br />(блогспот пытается закрыть тег /userprofile_id самостоятельно, конечно это в коде не требуется)<br />Вид:<br /><pre name="code" class="py"><br />@login_required<br />@render_to('users/user_profile.html')<br />def userprofile(request, userprofile_id):<br /> <br /> request_user = get_object_or_404(User, id=int(userprofile_id), is_active=True)<br /> <br /> return {<br /> 'request_user' : request_user,<br /> } <br /></pre><br />Отмечу, что получать надо user, а не наш UserProfile, который еще может быть не создан.<br /><br />Соответственно, напишем темплейт.<br /><br /><a rel="nofollow" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-bWKQpUJYfBtWjHN9pWWIsh_9FV6t-FBKiDAOu1MzjtzglG1TQJ5gZ8v73LblnJ6_yMDWQb8QffKov0k_RtYLiMBtP_xgagTPHkBA1IPdXmtQIL5dS4xZKr6TCeiGlRnm7cttuTxW/s1600/django+inbox+messages.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 171px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-bWKQpUJYfBtWjHN9pWWIsh_9FV6t-FBKiDAOu1MzjtzglG1TQJ5gZ8v73LblnJ6_yMDWQb8QffKov0k_RtYLiMBtP_xgagTPHkBA1IPdXmtQIL5dS4xZKr6TCeiGlRnm7cttuTxW/s400/django+inbox+messages.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5501897407284148098" /></a><br /><br />django_messages\templates\notification\ переведите вручную, перевод, который идет с приложением не работает (устарел наверное). Скопируем темплейты в users/templates, создадим папку locale в приложении и запустим создание файла перевода:<br />>python C:\Python26\Lib\site-packages\django\bin\django-admin.py makemessages -e .html,.txt --locale=ru_RU<br />в директории users.<br />После редактирования скомпилируем.<br /><br />Темлейт для уведомлений notices.html для самостоятельного написания (можно подсмотреть в <a rel="nofollow" href="http://github.com/pinax/pinax/blob/master/pinax/templates/default/notification/notices.html">pinax</a>).<br /><br />Что такое notification? Это приложение для уведомлений. Когда происходит событие в системе, мы имеем возможность создать уведомление для пользователя, с возможностью настройки дополнительных рассылок уведомлений:<br /><br />* при логине на сайт.<br />* по почте (настраивается пользователем).<br />* по rss<br /><br />Подключим контекстный процессор "notification.context_processors.notification".<br /><br />Мне не понравилась часть приложения по работе с url. Поэтому скопировал приложение себе в проект и поправил под свои нужды, получилось примерно следующее:<br /><br /><a rel="nofollow" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKV70NCdqlhBu2mB3-sY4q1qV0lf64H1UelZJ6ZgmXRcAYeTQcw0KdHdd1CV6NZmW-IXfCeF1ostEbyE3vRPTda1jrl6oDxM22BS3N5FP7Jgci9yDkOjlBhE2yptQ3UxS31Xy293kn/s1600/musimans+user+notification.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 212px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKV70NCdqlhBu2mB3-sY4q1qV0lf64H1UelZJ6ZgmXRcAYeTQcw0KdHdd1CV6NZmW-IXfCeF1ostEbyE3vRPTda1jrl6oDxM22BS3N5FP7Jgci9yDkOjlBhE2yptQ3UxS31Xy293kn/s400/musimans+user+notification.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5502550271802344722" /></a><br /><br />Пишите <a href="http://musicmans.ru/users/profile/1/">сообщения</a>. :)Vermushttp://www.blogger.com/profile/02301362335658588127noreply@blogger.com7