Иногда в системах умного дома применяя беспроводные технологии не имеет смысла использовать сложные и дорогие модули, например те же NRF24LE1 или NRF24L01+М/К, если необходима только односторонняя связь, например для передачи показаний датчиков влажности или/и температуры- в этом случае можно использовать очень простые решения на базе дешевого микроконтроллера attiny13 и радиомодуля 433 или 315 мгц.
Ниже будет рассказан пример использования датчиков, которые описаны в конструкторе прошивки и статье алгоритма беспроводных датчиков.
Ethernet сервер-приёмник на базе Arduino
#include <RCSwitch.h> #include <Ethernet.h> #include <SPI.h> #include <Arduino.h> #include "WebServer.h" RCSwitch mySwitch = RCSwitch(); unsigned long valueold; char buf[60]; //буфер для отправки данных. byte ip[] = { 192, 168, 1, 10 }; // локальный адрес byte rserver[] = { 192, 168, 1, 20 }; // ip-адрес удалённого сервера byte mac[] = { 0xDE, 0xAD, 0xBE, 0x54, 0xDE, 0x33 }; // MAC-адрес нашего устройства byte subnet[] = { 255, 255, 255, 0 }; byte gateway[] = { 192, 168, 1,1 }; byte dns_server[] = { 192, 168, 1, 1}; #define VERSION_STRING "Radio server" P(Page_info) = "<html><head><title>controller " VERSION_STRING "</title></head><body>\n"; P(location_info) = "server room"; P(version_info) = VERSION_STRING ". Compile date: " __DATE__ " " __TIME__; String url = String(25); #define MAX_COMMAND_LEN (10) #define MAX_PARAMETER_LEN (10) #define COMMAND_TABLE_SIZE (8) #define PREFIX "" WebServer webserver(PREFIX, 80); EthernetClient client; #define NAMELEN 32 #define VALUELEN 32 char gCommandBuffer[MAX_COMMAND_LEN + 1]; char gParamBuffer[MAX_PARAMETER_LEN + 1]; long gParamValue; typedef struct { char const *name; void (*function)(WebServer &server); } command_t; void infoRequest(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete) { server.printP(Page_info); server.print("IP:"); server.print(Ethernet.localIP()); server.print("<br>Location:"); server.printP(location_info); } void setup() { Ethernet.begin(mac, ip, dns_server, gateway, subnet); // Инициализируем Ethernet Shield webserver.setDefaultCommand(&infoRequest); // дефолтная страница webserver.begin(); mySwitch.enableReceive(0); // включаем прием на 2 выводе (прерывание 0) } bool ledA=0,ledB=0,ledC=0,ledD=0; long statesend = 0; void loop() { char buff[64]; int len = 64; webserver.processConnection(buff, &len); // process incoming connections one at a time forever unsigned long currentMillis = millis(); // текущий счетчик if (mySwitch.available()) { unsigned long valuesend = mySwitch.getReceivedValue(); #if 0 // прием команд с радиопультов, выключено ! При использовании не забудьте про установку пина режим на выход.. if ((unsigned int)valuesend==21952){ // A if (currentMillis-statesend>1000){ statesend=currentMillis; ledA=!ledA; sendstate(5,ledA); } } else if ((unsigned int)valuesend==21808){ // B if (currentMillis-statesend>1000){ statesend=currentMillis; ledB=!ledB; sendstate(6,ledB); } } else if ((unsigned int)valuesend==21772){ // C if (currentMillis-statesend>1000){ statesend=currentMillis; ledC=!ledC; sendstate(7,ledC); } } else if ((unsigned int)valuesend==21763){ // D if (currentMillis-statesend>1000){ statesend=currentMillis; ledD=!ledD; sendstate(8,ledD); } } else #endif // отправка принятых данных с беспроводных датчиков и отправка их на сервер. if (valuesend != 0 && valueold !=valuesend) { valueold=valuesend; if (client.connect(rserver, 80)) { sprintf (buf,"GET /server.php?mode=rcskey&n=%hu HTTP/1.0",valuesend); client.println(buf); client.println("Host: local.ru"); client.println(); } //else Serial.println("connection failed"); client.stop(); } mySwitch.resetAvailable(); } } void sendstate (int pin,int mode){ // управление нагрузками с пульта с отправкой статуса на сервер digitalWrite(pin,mode); if (client.connect(rserver, 80)) { sprintf(buf, "GET /server.php?mode=key&n=%i&s=%i HTTP/1.0", pin, mode); client.println(buf); client.println("Host: local.ru"); client.println(); } client.stop(); }
Данный код принимает сигналы с беспроводных датчиков, а так же с радиопультов.
Приемник должен быть подключен к 2 выводу ардуины.
Можно аналогично реализовать и без ethernet, используя последовательный порт.
Обработка принятых данных на сервере
При приеме данных с беспроводных датчиков они пересылаются на компьютер, на котором должен быть запущен веб сервер с поддержкой PHP. Arduina обращается к скрипту server.php, который обрабатывает и заносит данные с датчиков в базу данных.
CREATE TABLE IF NOT EXISTS `logsensors` (
`sensor` varchar(16) NOT NULL,
`val` varchar(12) NOT NULL,
`dtm` varchar(20) NOT NULL,
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251 AUTO_INCREMENT=1029966 ;
CREATE TABLE IF NOT EXISTS `sensors` (
`idd` varchar(16) NOT NULL, -- ид датчика
`name` varchar(35) NOT NULL, -- имя датчика
`type` varchar(3) NOT NULL, -- тип данных:
`val` varchar(12) NOT NULL, --текущие данные датчика
`dtm` varchar(20) NOT NULL, --дата и время
`enable` int(1) NOT NULL, -- датчик разрешен
`logenable` int(1) NOT NULL, -- разрешить логи сенсоров
`hidden` varchar(3) NOT NULL,
`period` int(2) NOT NULL DEFAULT '5', -- период записи в базу в минутах
`radiost` int(1) NOT NULL -- статус датчика:1-не работает(таймаут),0 - работает
) ENGINE=MyISAM DEFAULT CHARSET=cp1251;
INSERT INTO `sensors` (`idd`, `name`, `type`, `val`, `dtm`, `enable`, `logenable`, `hidden`, `period`, `key`, `radiost`) VALUES
( '11000', 'С/У радио', 'T', '22.3', '2014-09-09 13:20:15', 1, 1, 0, 5, 0, 1),
( '12000', 'Кухня', 'T', '20', '2014-09-09 13:21:16', 1, 1, 0, 5, 0, 1);
<?php // не забудьте задать параметры подключения к БД. $link = mysql_connect($dbhost, $dbuser, $dbpassword); mysql_select_db($dbname, $link); $dtm=date('Y-m-d H:i:s'); $mode = $_GET['mode']; if ($mode=="key") { // команда от радиопульта $state=$_GET['s']; $pin=$_GET['n']; mysql_query ("UPDATE `kkeys` SET `state` = '$state' WHERE `idd` = '$pin'"); }else if ($mode=="rcskey") { // команды от беспроводных датчиков $receivedCode=$_GET['n']; $m = mysql_query ("SELECT * FROM sensors WHERE mode LIKE '1'"); for ($c=0;$c<mysql_num_rows($m); $c++) { $fe = mysql_fetch_array($m); if ($fe[idd]<=$receivedCode && $fe[idd]+1024>$receivedCode) { if ($fe[type]=="H") $tdata=($receivedCode-$fe[idd])/10; // прием влажности else if ($fe[type]=="T") $tdata=($receivedCode-$fe[idd]-500)/10; // прием температуры else $tdata=$receivedCode-$fe[idd]; // прием просто число, например от аналогового датчика mysql_query ("UPDATE `sensors` SET `val` = '$tdata',`dtm` = '$dtm',`radiost` = '1' WHERE `idd` = '$fe[idd]'"); } } }
Для того чтобы записывать статистику температуры необходимо скрипт ниже вписать в планировщик на каждые 5 минут:
<?php // не забудьте задать параметры подключения к БД. $link = mysql_connect($dbhost, $dbuser, $dbpassword); mysql_select_db($dbname, $link); $m = mysql_query ("SELECT * FROM sensors WHERE mode LIKE '1' AND logenable LIKE '1' AND radiost LIKE '1'"); for ($c=0;$c<mysql_num_rows($m); $c++) { $p = mysql_fetch_array($m); $res=date('i')/$p[period]; // заносим в БД ,только если датчик обновлялся за последний период времени. if (round($res)==$res) mysql_query("insert into logsensors (sensor,val,dtm) values('$p[idd]','$p[val]','$p[dtm]')"); mysql_query ("UPDATE `sensors` SET `radiost` = '0' WHERE `idd` = '$p[idd]'"); }
Периодичность записи в базу статистики зависит от времени, установленное в столбце period в таблице sensors.
Исходные коды выше предоставлены в качестве примеров, на самом же деле дома работает система с бОльшими функциями, в которой так же имеются и проводные датчики и прочее… Веб интерфейс управления «умным домом» у меня свой, но показывать там пока не чего -его даже сложно назвать «умным домом». Данные примеры можно интегрировать в систему MajorDoMo или же написать свою.
В данный момент у меня в работе 2 беспроводных датчика температуры, которые передают так же данные с входа АЦП( в будущем АЦП будет использоваться для датчика протечки). Датчики, а так же пульт работают на частоте 315мгц.
Преимущества и недостатки
Преимущества данного решения:
-Дешево. Примерно 3 $ за всю схему на базе DS18B20 (по ценам ebay).
-Схема очень простая.
-Достаточно продолжительная работа от батарей.
-Можно использовать этот же канал для управления через радиопульт.
Недостатки:
-Нет шифрования, а зачем ?..
-Дальность не такая уж большая, но достаточна, если у вас не дворец..