Домашняя погодная станция
В этой заметке хочу рассказать о маленькой погодной станции для Вашего дома. Основным заданием которой было:
Температура
* вывод на сайт и на LCD экран температуры с 3-х комнат и улицы
* уличные показания температуры отправлять на проект Народный мониторинг
Сигнализация
* постановка/снятие с охраны
* датчик открытия/закрытия двери, при срабатывании, возможность отправлять уведомления на Jabber.
Что нам для этого нужно:)
* Маленький карманный роутер TP-LINK3020 (OpenWRT)
* USB хаб D-Link DUB-1040 4port
* USB Flash на 8Gb
* Среда разработки Arduino UNO
* Датчики температуры DS18B20 - 4шт.
* Геркон - 2 шт.
* LCD экран 4X20
О прошивке роутера TP-LINK3020 в OpenWRT и монтирование флеши в качестве системного раздела думаю писать не стоит.
Для взаимодействия Arduino с OpenWRT по USB, необходимо установить дополнительно USB-Serial:
#opkg install kmod-usb-acm
Также устанавливаем lighttpd, php5, rrdtool.
Перейдем к аппаратной части Arduino + LCD + DS18B20.
Подключаем экран по данной схеме.( Регулируемый резистор на 10к, на подсветку 6-8 Ом. ). Заливаем скетч, недостающие библиотеки берем в аттаче к заметке).
#include <LiquidCrystalRus.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define SOMK 7 //геркон двери
#define BUTTON 8 //кнопка снятия с охраны
#define ONE_WIRE_BUS 6 // DS18B20 подключены к контакту 6 на Arduino
int n = 1;
boolean stat_alarm = true ;
boolean delay_alarm_on = false;
long prev_time = 0;
long interval_alarm = 30000; //задержка выхода до постановки на охрану 30сек.
long temp_prev_time = 0;
long temp_interval_alarm = 20000; //интервал между опросами датчиков температуры 20сек.
float out_temp = 200; //Улица
float zal_temp = 200; //Зал
float spalnya_temp = 200; //Спальня
float detskaya_temp = 200; //Детская
float ex_out_temp = 200; //Предыдущее улица
float ex_zal_temp = 200; //Предыдущее Зал
float ex_spalnya_temp = 200; //Предыдущее Спальня
float ex_detskaya_temp = 200;//Предыдущее Детская
LiquidCrystalRus lcd(12, 11, 10, 5, 4, 3, 2);
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire); // Передаем наш OneWire ссылкой Dallas Temperature.
//создаем объект класса Bounce. Указываем пин, к которому подключена кнопка, и время дребезга в мс.
Bounce somk = Bounce(SOMK,5);
Bounce button = Bounce(BUTTON,5);
//дверь открыта
byte open_d[8] =
{
B11111,
B10001,
B10001,
B10001,
B10001,
B10001,
B10001,
B11111,
};
//дверь закрыта
byte close_d[8] =
{
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
};
//знак температуры
byte temp_c[8] =
{
B00010,
B00101,
B00010,
B00000,
B00000,
B00000,
B00000,
B00000,
};
//стрелка вверх
byte up[8] =
{
B00100,
B01110,
B10101,
B00100,
B00100,
B00100,
B00100,
B00100,
};
//стрелка вниз
byte down[8] =
{
B00100,
B00100,
B00100,
B00100,
B00100,
B10101,
B01110,
B00100,
};
//знак звонка
byte alarm_on[8] =
{
B00100,
B01110,
B01110,
B01110,
B11111,
B00100,
B00000,
B00000,
};
void setup() {
Serial.begin(9600);
sensors.begin();
sensors.setResolution(12); //9-bit 0.5 93.75 ms 10-bit 0.25 187.5 ms 0.12 11-bit 375 ms 12-bit 0.06 750 ms
pinMode(BUTTON, INPUT);
pinMode(SOMK, INPUT);
Serial.println ("system:start");
lcd.begin(20, 4);
lcd.setCursor(2, 0);
lcd.print("Погодная станция");
lcd.setCursor(2, 2);
lcd.print("vlymar");
lcd.setCursor(0, 3);
lcd.print ("Датчиков темп.: ");
lcd.print (sensors.getDeviceCount());
lcd.print ("шт.");
delay (2000);
lcd.clear();
lcd.createChar(1, open_d);
lcd.createChar(2, close_d);
lcd.createChar(3, temp_c);
lcd.createChar(4, up);
lcd.createChar(5, down);
lcd.createChar(6, alarm_on);
/*заголовки*/
lcd.setCursor(0, 0);
lcd.print("Улица:");
lcd.setCursor(0, 1);
lcd.print("Зал:");
lcd.setCursor(0, 2);
lcd.print("Спальня:");
lcd.setCursor(0, 3);
lcd.print("Детская:");
lcd.setCursor(19, 3);
lcd.print("\6");
/*конец заголовки*/
}
void loop() {
if (millis() - temp_prev_time > temp_interval_alarm) {
temp_prev_time = millis();
switch (n) {
case 1:
sensors.requestTemperaturesByIndex(0);
out_temp = sensors.getTempCByIndex(0);
n++;
break;
case 2:
sensors.requestTemperaturesByIndex(1);
zal_temp = sensors.getTempCByIndex(1);
n++;
break;
case 3:
sensors.requestTemperaturesByIndex(2);
spalnya_temp = sensors.getTempCByIndex(2);
n++;
break;
case 4:
sensors.requestTemperaturesByIndex(3);
detskaya_temp = sensors.getTempCByIndex(3);
n=1;
break;
}
}
/* Состояние двери */
if ( somk.update() ) {
if ( somk.read() == HIGH) {
if (stat_alarm == true) {
Serial.println ("door:open");
}
lcd.setCursor(19, 0);
lcd.print("\1");
}
else {
if (stat_alarm == true) {
Serial.println ("door:close");
}
lcd.setCursor(19, 0);
lcd.print("\2");
}
}
/* Конец Состояние двери */
/* Вкл/Выл сигнализации */
if ( button.update() ) {
if (button.read() == HIGH) {
if ( stat_alarm == true ) {
Serial.println ("alarm:off");
lcd.setCursor(19, 3);
lcd.print(char(47));
stat_alarm = false;
}
else {
lcd.setCursor(19, 3);
lcd.print(char(34));
prev_time = millis(); //запоминаем время
delay_alarm_on = true;
Serial.println ("alarm:delay");
}
}
}
/* Конец Вкл/Выл сигнализации */
/* Вывод Температура - Улица */
if (out_temp != ex_out_temp) {
if (out_temp >= 0) {
lcd.setCursor(9, 0);
}
else {
lcd.setCursor(8, 0);
}
lcd.print(out_temp);
lcd.print("\3C");
if (out_temp > ex_out_temp) {
lcd.print(" \4 ");
}
else {
lcd.print(" \5 ");
}
Serial.print("temp:out:");
Serial.println(out_temp);
ex_out_temp = out_temp;
}
/* Конец Вывод Температура - Улица */
/* Вывод Температура - Зал */
if (zal_temp != ex_zal_temp) {
if (zal_temp >= 0) {
lcd.setCursor(9, 1);
}
else {
lcd.setCursor(8, 1);
}
lcd.print(zal_temp);
lcd.print("\3C");
if (zal_temp > ex_zal_temp) {
lcd.print(" \4 ");
}
else {
lcd.print(" \5 ");
}
Serial.print("temp:zal:");
Serial.println(zal_temp);
ex_zal_temp = zal_temp;
}
/* Конец Вывод Температура - Зал */
/* Вывод Температура - Спальня */
if (spalnya_temp != ex_spalnya_temp) {
if (spalnya_temp >= 0) {
lcd.setCursor(9, 2);
}
else {
lcd.setCursor(8, 2);
}
lcd.print(spalnya_temp);
lcd.print("\3C");
if (spalnya_temp > ex_spalnya_temp) {
lcd.print(" \4 ");
}
else {
lcd.print(" \5 ");
}
Serial.print("temp:spalnya:");
Serial.println(spalnya_temp);
ex_spalnya_temp = spalnya_temp;
}
/* Конец Вывод Температура - Спальня */
/* Вывод Температура - Детская */
if (detskaya_temp != ex_detskaya_temp) {
if (detskaya_temp >= 0) {
lcd.setCursor(9, 3);
}
else {
lcd.setCursor(8, 3);
}
lcd.print(detskaya_temp);
lcd.print("\3C");
if (detskaya_temp > ex_detskaya_temp) {
lcd.print(" \4 ");
}
else {
lcd.print(" \5 ");
}
Serial.print("temp:detskaya:");
Serial.println(detskaya_temp);
ex_detskaya_temp = detskaya_temp;
}
/* Конец Вывод Температура - Детская */
if (delay_alarm_on == true) {
if (millis() - prev_time > interval_alarm) {
Serial.println ("alarm:on");
lcd.setCursor(19, 3);
lcd.print("\6");
stat_alarm = true;
delay_alarm_on = false;
}
}
}
По скетчу, на 7-ю ногу arduino вешаем геркон открытия/закрытия двери, на 8-ю ногу вместо кнопки постановки/снятия с охраны я также повестил геркон, который скрыл от посторонних глаз, включение-выключение сигнализации производится с помощью неодимового магнитика на брелке ключей, на 6-ю ногу вешаем наши 4-ре датчика температуры по 1-wire.
Проверяем работоспособность, в консоль должны идти данные вида:
door:close - дверь закрыта
alarm:off - снято с охраны
alarm:on - взято под охрану
alarm:delay - у вас есть 30сек. для выхода с дома
temp:out: - значение температуры "Улица"
temp:zal: - значение температуры "Зал"
temp:spalnya: - значение температуры "Спальня"
temp:detskaya: - значение температуры "Детская"
При подключении Adruino к роутеру в OpenWRT появится устройство /dev/ttyACM0.
Забирать и парсить поток данных с /dev/ttyACM0 будем с помощью php:
<?php
$ch='';
$bufer = '';
$filename = "/dev/ttyACM0";
$fp = fopen($filename, "r+");
if ($fp)
{
while (1) {
while ($ch != chr(0xA))
{
$ch = fgetc($fp);
$bufer.=$ch;
}
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://127.0.0.1:8080/receiver.php?a='.$bufer);
curl_setopt($curl, CURLOPT_RETURNTRANSFER,true);
$out = curl_exec($curl);
echo $out;
curl_close($curl);
echo $bufer;
$ch='';
$bufer = '';
}
}
?>
Передаем буфер с помощью GET-запроса в receiver.php.
<?php
$a = $_GET['a'];
$n=1;
$count = substr_count("$a",":");
if ($count == 1)
{
list($n1, $n2) = explode(":", $a);
switch($n) {
case 1:
if ($n1 == system & $n2 == start ) {
include '/narodmon/j_send/XMPPHP/XMPP.php';
$conn = new XMPPHP_XMPP('jabber.org', 5222, 'пользователь', 'пароль', 'xmpphp', 'jabber.org', $printlog=false, $loglevel=XMPPHP_Log::LEVEL_INFO);
try {
$conn->useEncryption(false);
$conn->connect();
$conn->processUntil('session_start');
$conn->presence();
$conn->message('пользователь@jabber.org', 'Arduino Start System');
$conn->disconnect();
} catch(XMPPHP_Exception $e) {
die($e->getMessage());
}
}
case 2:
if ($n1 == door & $n2 == open ) {
include '/narodmon/j_send/XMPPHP/XMPP.php';
$conn = new XMPPHP_XMPP('jabber.org', 5222, 'пользователь', 'пароль', 'xmpphp', 'jabber.org', $printlog=false, $loglevel=XMPPHP_Log::LEVEL_INFO);
try {
$conn->useEncryption(false);
$conn->connect();
$conn->processUntil('session_start');
$conn->presence();
$conn->message('пользователь@jabber.org', 'Door Open!');
$conn->disconnect();
} catch(XMPPHP_Exception $e) {
die($e->getMessage());
}
}
case 3:
if ($n1 == door & $n2 == close ) {
include '/narodmon/j_send/XMPPHP/XMPP.php';
$conn = new XMPPHP_XMPP('jabber.org', 5222, 'пользователь', 'пароль', 'xmpphp', 'jabber.org', $printlog=false, $loglevel=XMPPHP_Log::LEVEL_INFO);
try {
$conn->useEncryption(false);
$conn->connect();
$conn->processUntil('session_start');
$conn->presence();
$conn->message('пользователь@jabber.org', 'Door Close!');
$conn->disconnect();
} catch(XMPPHP_Exception $e) {
die($e->getMessage());
}
}
}
}
if ($count == 2 ){
list($t1, $t2, $t3) = explode(":", $a);
switch($n) {
case 1:
if ($t1 == temp & $t2 == out ) {
$f_write = fopen("/tmp/temp_out.txt", "w");
fwrite($f_write, "$t3");
fclose($f_write);
}
case 2:
if ($t1 == temp & $t2 == zal ) {
$f2_write = fopen("/tmp/temp_zal.txt", "w");
fwrite($f2_write, "$t3");
fclose($f2_write);
}
case 3:
if ($t1 == temp & $t2 == spalnya ) {
$f3_write = fopen("/tmp/temp_spalnya.txt", "w");
fwrite($f3_write, "$t3");
fclose($f3_write);
}
case 4:
if ($t1 == temp & $t2 == detskaya ) {
$f4_write = fopen("/tmp/temp_detskaya.txt", "w");
fwrite($f4_write, "$t3");
fclose($f4_write);
}
}
}
?>
С помощью скрипта to_narod_m.php, отпарвляем данные о температуре на народмон.
$f0 = fopen("/tmp/temp_out.txt", "r");
$out = fgets($f0);
fclose($f0);
$f1 = fopen("/tmp/temp_zal.txt", "r");
$zal = fgets($f1);
fclose($f1);
$f2 = fopen("/tmp/temp_spalnya.txt", "r");
$spalnya = fgets($f2);
fclose($f2);
$f3 = fopen("/tmp/temp_detskaya.txt", "r");
$detskaya = fgets($f3);
fclose($f3);
$fp = @fsockopen("tcp://narodmon.ru", 8283, $errno, $errstr);
if(!$fp) exit("ERROR(".$errno."): ".$errstr);
fwrite($fp, "#90-В6-12-7B-13-2C\n#1AB00000142ADE3828#$out\n#940000040876AFC218#$zal\n#12000004F564C428#$spalnya\n#12000004F61D1451#$detskaya\n##");
fclose($fp);
?>
так же дублируем температуру себе на страничку роутера:
Ставим задания в системный крон
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
#RRDTOOLS
*/5 * * * * /bin/bash /narodmon/rrd2/src.sh
#SEND_TO_N_MON
*/6 * * * * /usr/bin/php-cgi /narodmon/to_narod_m.php
sh /etc/init.d/cron enable
Прикрепленный файл | Размер |
---|---|
lib.tar_.bz2 | 21.55 кб |
- Войдите на сайт для отправки комментариев
- Версия для печати
Мой сайт погоды в городе Вознесенске, Украина. http://vozmeteo.com.ua
Приветствую! Уважаемый автор, а вы бы не могли выложить код страницы которая у вас на скрине, куда выводятся данные о температуре, просто в сети не нашел подобных примеров. Спасибо!
Отправил
не увидел, как это
"так же дублируем температуру себе на страничку роутера:"
?
судя по коду значения записываются в файлы в папке tmp
а как выводится график?
Вывод страницы и графиков расписан в другой заметке http://www.unix.ck.ua/content/monitoring-temperatury-s-pomoshchyu-rrdtool с помощью rrdtool.