Привет Хабрахабр! Хочу поделится с вами как я подключил Arduino к своему роутеру. Поехали!
Современные роутеры — как небольшие компьютеры, которые выполняют узкоспециализированную задачу для раздачи сетевого трафика. На борту такого небольшого устройства установлена ОС 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">
<div class="container">
<header>
<h1><span>Температура</span></h1>
</header>
</div>
<div class="ul1" >
<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>
<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 ставим конденсатор на 22 мФ. Это предотвращает перезагрузку во время приема команд.
Пару фоток
Скачать все необходимые файлы одним архивом
P.S.
Это лишь небольшой пример того, как можно использовать arduino в связке с роутером. Можно написать более серьезные вещи. Управлять любыми приборами в своем доме при помощи веб-интерфейса и Arduino.
Спасибо за инвайт НЛО!
Автор: Rimidalw