Современные роутеры как небольшие компьютеры, которые выполняют узкоспециализированную задачу для раздачи сетевого трафика. На борту такого небольшого устройства установлена ОС Linux, только без графического интерфейса и с урезанной программной частью. Передо мной встал вопрос, а почему бы не подключить arduino к своему роутеру — Zyxel Keenetic 4G? Немного погуглив я наткнулся на замечательный форум, где энтузиасты собирают модифицированные прошивки с поддержкой установки дополнительных, пакетов для серии Keenetic.
В нашем случае управление Arduino происходит через библиотеку php_serial.class.php и легкого веб сервера на основе Lighttpd + php. С помощью этих инструментов будем подавать команды ардуинке на чтение показаний с двух температурных датчиков (дом, улица) , записывать ответ в базу данных Sqlite3 и выводить на нашу веб-страничку.
Подготовка маршрутизатора
Первым делом необходимо настроить наш маршрутизатор. У Zyxel Keenetic 4G очень маленькая внутренняя память, поэтому приобретете простенький usb-хаб и флешку не большого объема. Все тонкости настройки я не буду расписывать, а лишь поделюсь необходимыми ссылками. Сразу приготовитесь к долгой и утомительной процедуре.
- Альтернативная прошивка. Система opkg для установки дополнительных пакетов. (читаем внимательно WIKI, там все расписано)
- Устанавливаем Sqlite3 командой opkg install <имя пакета>, где <имя пакета> полный путь к пакету. Все необходимые пакеты берем здесь.
- Устанавливаем и настраиваем Lighttpd и php.
Подключение датчиков
Подключаем температурные датчики ds18b20 к arduino. Номинал резисторов — 4,7 кОм

Скетч
Заливаем скетч. За основу был взят код из этого урока и немного доработан под нашу задачу.
#include <OneWire.h> int nc; OneWire ds(10); // Первый датчик OneWire ds2(11); // Второй датчик byte addr[8]; byte addr2[8]; void setup(void) { Serial.begin(9600); ds.search(addr); ds2.search(addr2); } void loop(void) { byte i; byte present = 0; byte data[12]; int Temp; int znak; if (Serial.available() > 0) { nc = Serial.read(); if (nc==1) { ds.reset(); ds.select(addr); ds.write(0x44,1); present = ds.reset(); ds.select(addr); ds.write(0xBE); for ( i = 0; i < 9; i++) { data[i] = ds.read(); } Temp=(data[1]<<8)+data[0]; Temp=Temp; znak=((Temp%16)*100)/16; if (znak<0){ znak=znak*-1; } Serial.print(Temp/16); Serial.print("."); Serial.print(znak); Serial.println(); } if (nc==2) { ds2.reset(); ds2.select(addr2); ds2.write(0x44,1); present = ds2.reset(); ds2.select(addr2); ds2.write(0xBE); for ( i = 0; i < 9; i++) { data[i] = ds2.read(); } Temp=(data[1]<<8)+data[0]; Temp=Temp; znak=((Temp%16)*100)/16; if (znak<0){ znak=znak*-1; } Serial.print(Temp/16); Serial.print("."); Serial.print(znak); Serial.println(); } } }
Передаем команды, принимаем ответы
Скетч принимает две команды — «1» и «2». Для того что бы отправлять команды в Arduino, я использовал обработку кнопок на java script при помощи известной библиотеки Jquery. На моей страничке находятся 2 кнопки и 2 табличных поля в которые выводятся значения с температурных датчиков(см. index.php). При помощь метода POST, скрипт обращается к arduino.php и передает значения наших команд. Здесь происходит передача команд непосредственно в Arduino и чтение ответа в виде температуры, а так же запись в базу данных Sqlite3 (см. arduino.php). Файл readbd.php нужен для первоначального занесения данных температуры в табличку. Красивое оформление кнопок было позаимствовано из статьи «3D кнопки с помощью CSS3».
index.php:
<?php include("readbd.php"); ?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="ru"> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> <head> <link href="style.css" rel="stylesheet" media="all" /> <title>Температура в доме и на улице</title> <link href="flot/examples/layout.css" rel="stylesheet" type="text/css"> <script type="text/javascript" src="jquery.js"></script> </head> <body class="body"> <br> <div class="container"> <header> <h1><span>Температура</span></h1> </header> </div> <div class="ul1" > <br> <table width="60px" border="0"><tr> <td><a href="#" id="led6" class="button black" onMouseDown="command(1);">Улица</a></td> <td><a href="#" id="led6" class="button yellow" onMouseDown="command(2);">Дом</a></td> </tr><tr> <td class="c1"><div id="content1" ><?php echo ''.$temp1.""; ?></div></td> <td class="c1"><div id="content2" ><?php echo ''.$temp2.""; ?></div></td> </tr> </table> </div> <br> <script> function command(id) { $.ajax({ type:'POST', url:'arduino.php', data:{msg:id}, cache: false, success: function(html){ $("#content"+id).html(html); } }) } </script> </center> </body> </html>
arduino.php:
<?php include "php_serial.class.php"; $serial = new phpSerial; //Задаем путь к Arduino (У вас может быть совсем по другому) $serial->deviceSet("/../../../../dev/ttyACM0"); //Это стандарт $serial->confBaudRate(9600); $serial->confParity("none"); $serial->confCharacterLength(8); $serial->confStopBits(1); $serial->confFlowControl("none"); $serial->deviceOpen(); //Отправляем команду $serial->sendMessage(chr($_POST['msg'])); //Читаем ответ Arduino $read = $serial->readPort(); //Зыкрываем соединение $serial->deviceClose(); try { // Создаем или открываем созданную ранее базу данных $db = new PDO('sqlite:'.dirname(__FILE__).DIRECTORY_SEPARATOR.'arduino.db'); // Создаем таблицу temp, если не найдена $db->exec('CREATE TABLE IF NOT EXISTS temp ( idtemp INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, temperature VARCHAR(255) NOT NULL, datetime VARCHAR(255) NOT NULL )'); $db->exec('CREATE TABLE IF NOT EXISTS temp2 ( idtemp INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, temperature VARCHAR(255) NOT NULL, datetime VARCHAR(255) NOT NULL )'); //определяем текущцю дату и время $d=date("d.m.y, G:i:s"); //Обновляем //$db->exec('UPDATE temp SET temperature="'.$read.'", datetime="'.$d.'" WHERE idtemp='.$_POST['msg'].''); if ($_POST['msg']==1){ //Добавляем новую строку в БД $db->exec('INSERT INTO temp (temperature, datetime) VALUES ("'.$read.'","'.$d.'" )'); //Получаем последнюю запись $st = $db->query('SELECT MAX(idtemp) as id, temperature FROM temp'); $results = $st->fetchAll(); foreach ($results as $row) { echo ''.$row['temperature']."\n"; } } if ($_POST['msg']==2){ $db->exec('INSERT INTO temp2 (temperature, datetime) VALUES ("'.$read.'","'.$d.'" )'); $st = $db->query('SELECT MAX(idtemp) as id, temperature as tempe FROM temp2'); $results = $st->fetchAll(); foreach ($results as $row) { echo ''.$row['tempe']."\n"; } } } catch (PDOException $e) { die($e->getMessage()); } ?>
Проблемы с которыми я столкнулся:
- Arduino в маршрутизаторе определялся как /dev/ttyACM0, а не /dev/ttyUSB0.
- После того как php был написан, постоянно выскакивала ошибка — No stty availible, unable to run.», E_USER_ERROR.
- При отсылке команд Arduino постоянно перезагружался.
Решения:
- Так как Веб сервер у меня установлен на флешке в своем php скрипте нужно правильно указать путь к устройству. Так же установите права 777 на /dev/ttyACM0 или /dev/ttyUSB0 (зависит от Arduino).
deviceSet(/../../../../dev/ttyACM0);
- В php_serial.class.php убрал кусок кода:
if($this->_exec("stty --version") === 0) { register_shutdown_function(array($this, "deviceClose")); } else { trigger_error("No stty availible, unable to run.", E_USER_ERROR); }
- После заливки скетча в Arduino между пинами GND и Reset ставим конденсатор на 220 мФ. Это предотвращает перезагрузку во время приема команд.
Пару фоток
Arduino_Zyxel_ds18b20.zip (95,9 KiB, 2 690 загрузок)
P.S.
Это лишь небольшой пример того как можно использовать arduino в связке с роутером. Можно написать более серьезные вещи. Управлять любыми приборами в своем доме при помощи веб-интерфейса и Arduino.
Здравствуйте. Прочитав о вашем изобретении, я понял, насколько я дремучий ;). А теперь по существу: можно использовать роутеры TP-Link, D-Link, Asus и др. с USB-портом?