Доброе время суток, уважаемое хабрасообщество!
Неделю назад я наконец-то дождался свою Малинку. Этот пост о том, как можно набить шишки в такой простой задаче как работа с датчиками температуры.
Кому интересно — добро пожаловать под кат.
Итак, став обладателем Малинового счастья с 512 МБ ОЗУ на борту, заново начал пересматривать множество постов, в том числе на Хабре, про возможные варианты создания «Умного дома». Но поскольку мое образование далеко от IT, решил не делать сразу Алису, а начал с простого — контроля температуры.
Установку системы на Малинку я опущу, эта тема достаточно детально описана тут и тут. Перейду сразу к настройке Малинки для автоматизации контроля температуры с хранением и отображением результатов через веб.
Я ориентировался на связку 1-wire, ds18b20 и rrdtool, как самый простой и доступный вариант.
Маленькая ремарка к скрипту создания БД. В скрипте я задал температурные диапазоны для датчика на улице и в квартире. --step 300 — интервал хранения данных температуры — 300 сек (5 минут). 600 — параметр в секундах, при отсутствии в течение которых значений температуры ее значение становится «UNKNOWN».
Это первоначальный вид скрипта, такой каким я его нашел на просторах интернета. Подключенные датчики, находящиеся в комнате, показывали адекватные результаты, Но когда я вынес один датчик на улицу на ПМЖ, я был разочарован тем, что температуру показывало ровно 0 градусов цельсия, что бы я ни делал (а на улице у нас сейчас -5...-10).
Как оказалось, все дело в этой строке:
которая предполагает получение температуры с датчика без учета отрицательных температур. Ввиду отсутствия соответствующих знаний я потратил пол-часа и пару чашек кофе на приведение строки к виду:
что позволило нормально заносить в БД и отрицательные температуры.
В этом скрипте я разнес часовые графики температур в квартире и на улице, т.к. большой разброс между температурами делает графики не очень читабельными. Также подправил под себя цвета и подписи к графикам.
После этого я создал скрипт последовательного запуска получения температур с датчиков и генерирования графиков get.sh
и добавил в crontab -e строку его запуска:
что позволяет запускать скрипт автоматически каждые 5 минут.
Это все отображается на простенькой веб-страничке.
По просьбе трудящихся добавляю информацию о подключении всего этого хозяйства для пересылки данных на narodmon.ru. Делал по материалам отсюда.
Итак:
1. Вносим изменения в скрипт получения данных из датчиков с целью записи текущих результатов, каждого в свой файл (добавил код в скрипт, см. выше).
2. Устанавливаем (если еще не стоит)
3. Создаем скрипт отправки данных из файлов с показаниями на сайт narodmon.ru
01-23-45-67-89-AF — МАС-адрес сетевой карты Малинки, 0123456789ABCDEF — серийные номера датчиков температуры.
4. Добавляем в crontab строку для регулярной отправки информации на narodmon.ru (на сайте есть ограничение на частоту приемки информации — не чаще раза в 5 минут, поэтому я сделал отправку каждые 10 минут):
5. Регистрируемся на проекте narodmon.ru и добавляем МАС-адрес Малинки. Теперь статистика ведется и у них :)
Порывшись в закромах кладовки, я обнаружил у себя двухрядный коннектор типа «мама» и телефонный удлинитель. От коннектора я откусил 2х4 и подпаял резистор 4k7 между ножкой 1 и ножкой 7 (на ножке 1 у нас +3В, ножка 6 — земля, ножка 7 — PIN4, который в Малинке позволяет общаться по протоколу 1-wire).
В удлинитель был впаян первый датчик ds18b20, а второй датчик я подпаял напрямую к телефонному кабелю, замотал черной (не синей) изолентой и через бывшее отверстие для кабеля спутниковой антенны вывел за пределы квартиры на улицу.
В собранном виде с учетом размещения Малинки в транспортировочном корпусе получилась следующая картина:
Как оказалось, использование микротройничка — очень удобная штука :)
Ну и напоследок — картинка с сайта.
Результат на проекте narodmon.ru.
Если вы ожидали увидеть подключение датчиков температуры к чайнику — приношу свои извинения :) «Чайник» в данной статье — это я. Понемногу разбирался с вопросом в меру сил и знаний, заглядывая в Гугл и используя метод проб и ошибок.
Поставленной цели я добился. Буду признателен всем за подсказки по улучшению или правильному подходу к достижению локальных целей. Спасибо за внимание :)
З.Ы. Ссылку на страничку с графиками не дам — «ляжет» «Малинка» ;)
Неделю назад я наконец-то дождался свою Малинку. Этот пост о том, как можно набить шишки в такой простой задаче как работа с датчиками температуры.
Кому интересно — добро пожаловать под кат.
Итак, став обладателем Малинового счастья с 512 МБ ОЗУ на борту, заново начал пересматривать множество постов, в том числе на Хабре, про возможные варианты создания «Умного дома». Но поскольку мое образование далеко от IT, решил не делать сразу Алису, а начал с простого — контроля температуры.
Установку системы на Малинку я опущу, эта тема достаточно детально описана тут и тут. Перейду сразу к настройке Малинки для автоматизации контроля температуры с хранением и отображением результатов через веб.
Я ориентировался на связку 1-wire, ds18b20 и rrdtool, как самый простой и доступный вариант.
1. Установка софта
Патч ядра для 1-wire
cd /boot
wget www.frank-buss.de/raspberrypi/kernel-rpi-w1.tgz
tar -xzf kernel-rpi-w1.tgz
rm -f kernel-rpi-w1.tgz
cd /lib/modules
wget www.frank-buss.de/raspberrypi/modules-rpi-w1.tgz
tar -xzf modules-rpi-w1.tgz
rm -f modules-rpi-w1.tgz
sync
reboot
wget www.frank-buss.de/raspberrypi/kernel-rpi-w1.tgz
tar -xzf kernel-rpi-w1.tgz
rm -f kernel-rpi-w1.tgz
cd /lib/modules
wget www.frank-buss.de/raspberrypi/modules-rpi-w1.tgz
tar -xzf modules-rpi-w1.tgz
rm -f modules-rpi-w1.tgz
sync
reboot
Установка libwww-perl и rrdtool
sudo apt-get install libwww-perl rrdtool
2. Создание необходимых скриптов
Скрипт создания базы данных create_db.sh
#!/bin/bash
rrdtool create multirPItemp.rrd --step 300 \
DS:in_temp:GAUGE:600:0:50 \
DS:out_temp:GAUGE:600:-30:50 \
RRA:AVERAGE:0.5:1:12 \
RRA:AVERAGE:0.5:1:288 \
RRA:AVERAGE:0.5:12:168 \
RRA:AVERAGE:0.5:12:720 \
RRA:AVERAGE:0.5:288:365
rrdtool create multirPItemp.rrd --step 300 \
DS:in_temp:GAUGE:600:0:50 \
DS:out_temp:GAUGE:600:-30:50 \
RRA:AVERAGE:0.5:1:12 \
RRA:AVERAGE:0.5:1:288 \
RRA:AVERAGE:0.5:12:168 \
RRA:AVERAGE:0.5:12:720 \
RRA:AVERAGE:0.5:288:365
Маленькая ремарка к скрипту создания БД. В скрипте я задал температурные диапазоны для датчика на улице и в квартире. --step 300 — интервал хранения данных температуры — 300 сек (5 минут). 600 — параметр в секундах, при отсутствии в течение которых значений температуры ее значение становится «UNKNOWN».
Скрипт получения температуры из датчиков get_temp.pl
#!/usr/bin/perl
use warnings;
&check_modules;
&get_device_IDs;
foreach $device ( @deviceIDs)
{
$reading = &read_device($device);
if ($reading != «9999»)
{
push(@temp_readings,$reading);
}
}
#update the database
`/usr/bin/rrdtool update /home/pi/temperature/multirPItemp.rrd N:$temp_readings[0]:$temp_readings[1]`;
print «Temp 1 = $temp_readings[0] Temp 2 = $temp_readings[1]\n»;
#######################################################################
# Дополнения для narodmon.ru. По материалам habrahabr.ru/post/166373
open(FILE, ">/home/pi/temperature/temp_out");
print FILE "$temp_readings[0]";
close (FILE);
open(FILE, ">/home/pi/temperature/temp_in");
print FILE "$temp_readings[1]";
close (FILE);
#######################################################################
sub check_modules
{
$mods = `cat /proc/modules`;
if ($mods =~ /w1_gpio/ && $mods =~ /w1_therm/)
{
print «w1 modules already loaded \n»;
}
else
{
print «loading w1 modules \n»;
`sudo modprobe w1-gpio`;
`sudo modprobe w1-therm`;
}
}
sub get_device_IDs
{
# The Hex IDs off all detected 1-wire devices on the bus are stored in the file
# «w1_master_slaves»
# open file
open(FILE, "/sys/bus/w1/devices/w1_bus_master1/w1_master_slaves") or die(«Unable to open file»);
# read file into an array
@deviceIDs = ;
# close file
close(FILE);
}
sub read_device
{
#takes one parameter — a device ID
#returns the temperature if we have something like valid conditions
#else we return «9999» for undefined
$readcommand = «cat /sys/bus/w1/devices/».$_[0]."/w1_slave 2>&1";
$readcommand =~ s/\R//g;
$sensor_temp = `$readcommand`;
if ($sensor_temp !~ /No such file or directory/)
{
if ($sensor_temp !~ /NO/)
{
$sensor_temp =~ /t=(\d+)/i;
$temperature = (($1/1000));
}
else
{
$ret = «9999»;
}
}
else
{
$ret = «9999»
}
}
use warnings;
&check_modules;
&get_device_IDs;
foreach $device ( @deviceIDs)
{
$reading = &read_device($device);
if ($reading != «9999»)
{
push(@temp_readings,$reading);
}
}
#update the database
`/usr/bin/rrdtool update /home/pi/temperature/multirPItemp.rrd N:$temp_readings[0]:$temp_readings[1]`;
print «Temp 1 = $temp_readings[0] Temp 2 = $temp_readings[1]\n»;
#######################################################################
# Дополнения для narodmon.ru. По материалам habrahabr.ru/post/166373
open(FILE, ">/home/pi/temperature/temp_out");
print FILE "$temp_readings[0]";
close (FILE);
open(FILE, ">/home/pi/temperature/temp_in");
print FILE "$temp_readings[1]";
close (FILE);
#######################################################################
sub check_modules
{
$mods = `cat /proc/modules`;
if ($mods =~ /w1_gpio/ && $mods =~ /w1_therm/)
{
print «w1 modules already loaded \n»;
}
else
{
print «loading w1 modules \n»;
`sudo modprobe w1-gpio`;
`sudo modprobe w1-therm`;
}
}
sub get_device_IDs
{
# The Hex IDs off all detected 1-wire devices on the bus are stored in the file
# «w1_master_slaves»
# open file
open(FILE, "/sys/bus/w1/devices/w1_bus_master1/w1_master_slaves") or die(«Unable to open file»);
# read file into an array
@deviceIDs = ;
# close file
close(FILE);
}
sub read_device
{
#takes one parameter — a device ID
#returns the temperature if we have something like valid conditions
#else we return «9999» for undefined
$readcommand = «cat /sys/bus/w1/devices/».$_[0]."/w1_slave 2>&1";
$readcommand =~ s/\R//g;
$sensor_temp = `$readcommand`;
if ($sensor_temp !~ /No such file or directory/)
{
if ($sensor_temp !~ /NO/)
{
$sensor_temp =~ /t=(\d+)/i;
$temperature = (($1/1000));
}
else
{
$ret = «9999»;
}
}
else
{
$ret = «9999»
}
}
Это первоначальный вид скрипта, такой каким я его нашел на просторах интернета. Подключенные датчики, находящиеся в комнате, показывали адекватные результаты, Но когда я вынес один датчик на улицу на ПМЖ, я был разочарован тем, что температуру показывало ровно 0 градусов цельсия, что бы я ни делал (а на улице у нас сейчас -5...-10).
Как оказалось, все дело в этой строке:
$:sensor_temp =~ /t=(\d+)/i;
которая предполагает получение температуры с датчика без учета отрицательных температур. Ввиду отсутствия соответствующих знаний я потратил пол-часа и пару чашек кофе на приведение строки к виду:
$:sensor_temp =~ /t=(\D*\d+)/i;
что позволило нормально заносить в БД и отрицательные температуры.
Скрипт создания графиков create_graphs.sh
#!/bin/bash
RRDPATH="/home/pi/temperature/"
INCOLOUR="#990000"
OUTCOLOUR="#009900"
TRENDCOLOUR1="#FF0000"
TRENDCOLOUR2="#00FF00"
#hour
rrdtool graph $RRDPATH/mhour_in.png --start -6h --alt-autoscale \
DEF:intemp=$RRDPATH/multirPItemp.rrd:in_temp:AVERAGE \
DEF:outtemp=$RRDPATH/multirPItemp.rrd:out_temp:AVERAGE \
CDEF:intrend=intemp,1200,TREND \
CDEF:outtrend=outtemp,1200,TREND \
LINE2:intemp$INCOLOUR:"Inside" \
LINE1:intrend$TRENDCOLOUR1:"20 min AVG" \
#LINE2:outtemp$OUTCOLOUR:"Outside" \
#LINE1:outtrend$TRENDCOLOUR2:"20 min AVG"
#hour outside
rrdtool graph $RRDPATH/mhour_out.png --start -6h --alt-autoscale \
DEF:intemp=$RRDPATH/multirPItemp.rrd:in_temp:AVERAGE \
DEF:outtemp=$RRDPATH/multirPItemp.rrd:out_temp:AVERAGE \
CDEF:intrend=intemp,1200,TREND \
CDEF:outtrend=outtemp,1200,TREND \
LINE2:outtemp$OUTCOLOUR:"Outside" \
LINE1:outtrend$TRENDCOLOUR2:"20 min AVG"
#day
rrdtool graph $RRDPATH/mday.png --start -1d --alt-autoscale \
DEF:intemp=$RRDPATH/multirPItemp.rrd:in_temp:AVERAGE \
DEF:outtemp=$RRDPATH/multirPItemp.rrd:out_temp:AVERAGE \
CDEF:intrend=intemp,1800,TREND \
CDEF:outtrend=outtemp,1800,TREND \
LINE2:intemp$INCOLOUR:"Inside" \
LINE1:intrend$TRENDCOLOUR1:"1h min AVG" \
LINE2:outtemp$OUTCOLOUR:"Outside" \
LINE1:outtrend$TRENDCOLOUR2:"1h min AVG"
#week
rrdtool graph $RRDPATH/mweek.png --start -1w --alt-autoscale \
DEF:intemp=$RRDPATH/multirPItemp.rrd:in_temp:AVERAGE \
DEF:outtemp=$RRDPATH/multirPItemp.rrd:out_temp:AVERAGE \
LINE2:intemp$INCOLOUR:"Inside temperature" \
LINE2:outtemp$OUTCOLOUR:"Outside temperature" \
#month
rrdtool graph $RRDPATH/mmonth.png --start -1m --alt-autoscale \
DEF:intemp=$RRDPATH/multirPItemp.rrd:in_temp:AVERAGE \
DEF:outtemp=$RRDPATH/multirPItemp.rrd:out_temp:AVERAGE \
LINE2:intemp$INCOLOUR:"Inside temperature" \
LINE2:outtemp$OUTCOLOUR:"Outside temperature" \
#year
rrdtool graph $RRDPATH/myear.png --start -1y --alt-autoscale \
DEF:intemp=$RRDPATH/multirPItemp.rrd:in_temp:AVERAGE \
DEF:outtemp=$RRDPATH/multirPItemp.rrd:out_temp:AVERAGE \
LINE2:intemp$INCOLOUR:"Inside temperature" \
LINE2:outtemp$OUTCOLOUR:"Outside temperature" \
В этом скрипте я разнес часовые графики температур в квартире и на улице, т.к. большой разброс между температурами делает графики не очень читабельными. Также подправил под себя цвета и подписи к графикам.
После этого я создал скрипт последовательного запуска получения температур с датчиков и генерирования графиков get.sh
#!/bin/bash
/home/pi/temperature/get_temp.pl
/home/pi/temperature/create_graphs.sh
и добавил в crontab -e строку его запуска:
*/5 * * * * /home/pi/temperature/get.sh
что позволяет запускать скрипт автоматически каждые 5 минут.
Это все отображается на простенькой веб-страничке.
2.1. Подключение к narodmon.ru
По просьбе трудящихся добавляю информацию о подключении всего этого хозяйства для пересылки данных на narodmon.ru. Делал по материалам отсюда.
Итак:
1. Вносим изменения в скрипт получения данных из датчиков с целью записи текущих результатов, каждого в свой файл (добавил код в скрипт, см. выше).
2. Устанавливаем (если еще не стоит)
sudo apt-get install php5-cgi
3. Создаем скрипт отправки данных из файлов с показаниями на сайт narodmon.ru
Скрипт отправки данных на narodmon.ru - send.php
#!/usr/bin/php-cgi -q
<?
$file_name="/home/pi/temperature/temp_out";
$file=fopen("$file_name", «r»);
$gradus_out=fread($file, filesize($file_name));
echo "$gradus_out\n";
fclose($file);
$file_name="/home/pi/temperature/temp_in";
$file=fopen("$file_name", «r»);
$gradus_in=fread($file, filesize($file_name));
echo "$gradus_in\n";
fclose($file);
$fp = @fsockopen(«tcp://narodmon.ru», 8283, $errno, $errstr);
if(!$fp) exit(«ERROR(».$errno."): ".$errstr);
fwrite($fp, "#01-23-45-67-89-AF\n#0123456789ABCDEF#$gradus_out\n#0123456789ABCDEF#$gradus_in\n##");
fclose($fp);
?>
01-23-45-67-89-AF — МАС-адрес сетевой карты Малинки, 0123456789ABCDEF — серийные номера датчиков температуры.
4. Добавляем в crontab строку для регулярной отправки информации на narodmon.ru (на сайте есть ограничение на частоту приемки информации — не чаще раза в 5 минут, поэтому я сделал отправку каждые 10 минут):
*/10 * * * * /home/pi/temperature/send.php
5. Регистрируемся на проекте narodmon.ru и добавляем МАС-адрес Малинки. Теперь статистика ведется и у них :)
3. Теперь переходим к железу
Порывшись в закромах кладовки, я обнаружил у себя двухрядный коннектор типа «мама» и телефонный удлинитель. От коннектора я откусил 2х4 и подпаял резистор 4k7 между ножкой 1 и ножкой 7 (на ножке 1 у нас +3В, ножка 6 — земля, ножка 7 — PIN4, который в Малинке позволяет общаться по протоколу 1-wire).
В удлинитель был впаян первый датчик ds18b20, а второй датчик я подпаял напрямую к телефонному кабелю, замотал черной (не синей) изолентой и через бывшее отверстие для кабеля спутниковой антенны вывел за пределы квартиры на улицу.
В собранном виде с учетом размещения Малинки в транспортировочном корпусе получилась следующая картина:
Как оказалось, использование микротройничка — очень удобная штука :)
Ну и напоследок — картинка с сайта.
Результат на проекте narodmon.ru.
Вместо послесловия
Если вы ожидали увидеть подключение датчиков температуры к чайнику — приношу свои извинения :) «Чайник» в данной статье — это я. Понемногу разбирался с вопросом в меру сил и знаний, заглядывая в Гугл и используя метод проб и ошибок.
Поставленной цели я добился. Буду признателен всем за подсказки по улучшению или правильному подходу к достижению локальных целей. Спасибо за внимание :)
З.Ы. Ссылку на страничку с графиками не дам — «ляжет» «Малинка» ;)