Zyxel Keenetic 4G, arduino и датчики температуры ds18b20

Современные роутеры как небольшие компьютеры, которые выполняют узкоспециализированную задачу для раздачи сетевого трафика. На борту такого небольшого устройства установлена ОС Linux, только без графического интерфейса и с урезанной программной частью. Передо мной встал вопрос, а почему бы не подключить arduino к своему роутеру — Zyxel Keenetic 4G? Немного погуглив я наткнулся на замечательный форум, где энтузиасты собирают модифицированные прошивки с поддержкой установки дополнительных,  пакетов для серии Keenetic.

В нашем случае управление Arduino происходит через библиотеку php_serial.class.php и легкого веб сервера на основе Lighttpd + php. С помощью этих инструментов будем подавать команды ардуинке на чтение показаний с двух температурных датчиков (дом, улица) , записывать ответ в базу данных Sqlite3 и выводить на нашу веб-страничку.

Подготовка маршрутизатора

Первым делом необходимо настроить наш маршрутизатор. У Zyxel Keenetic 4G очень маленькая внутренняя память, поэтому приобретете простенький usb-хаб и флешку не большого объема. Все тонкости настройки я не буду расписывать, а лишь поделюсь необходимыми ссылками. Сразу приготовитесь к долгой и утомительной процедуре.

  1. Альтернативная прошивка. Система opkg для установки дополнительных пакетов. (читаем внимательно WIKI, там все расписано)
  2. Устанавливаем Sqlite3 командой opkg install <имя пакета>, где <имя пакета> полный путь к пакету. Все необходимые пакеты берем здесь.
  3. Устанавливаем и настраиваем Lighttpd и php.

Подключение датчиков

Подключаем температурные датчики ds18b20 к arduino. Номинал резисторов — 4,7 кОм

Схема подключения температурных датчиков

Скетч
Заливаем скетч. За основу был взят код из этого урока и немного доработан под нашу задачу.

[php]
#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();
}
}
}
[/php]

Передаем команды, принимаем ответы

Скетч принимает две команды — «1» и «2». Для того что бы отправлять команды в Arduino, я использовал обработку кнопок на java script при помощи известной библиотеки Jquery. На моей страничке находятся 2 кнопки и 2 табличных поля в которые выводятся значения с температурных датчиков(см. index.php). При помощь метода POST, скрипт обращается к arduino.php и передает значения наших команд. Здесь происходит передача команд непосредственно в Arduino и чтение ответа в виде температуры, а так же запись в базу данных Sqlite3 (см. arduino.php). Файл readbd.php нужен для первоначального занесения данных температуры в табличку. Красивое оформление кнопок было позаимствовано из статьи «3D кнопки с помощью CSS3».

index.php:

[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>
[/php]

arduino.php:

[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());
}
?>
[/php]

Проблемы с которыми я столкнулся:

  1. Arduino в маршрутизаторе определялся как /dev/ttyACM0, а не /dev/ttyUSB0.
  2. После того как php был написан, постоянно выскакивала ошибка — No stty availible, unable to run.», E_USER_ERROR.
  3. При отсылке команд Arduino постоянно перезагружался.

Решения:

  1. Так как Веб сервер у меня установлен на флешке в своем php скрипте нужно правильно указать путь к устройству. Так же установите права 777 на /dev/ttyACM0 или /dev/ttyUSB0 (зависит от Arduino).[php]deviceSet(/../../../../dev/ttyACM0);[/php]
  2. В php_serial.class.php убрал кусок кода:[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);
    }
    [/php]
  3. После заливки скетча в Arduino между пинами GND и Reset ставим конденсатор на 220 мФ. Это предотвращает перезагрузку во время приема команд.

Пару фоток


[stextbox id=»custom» caption=»Скачать все необходимые файлы»]

[download id=»55″]
[/stextbox]
P.S.
Это лишь небольшой пример того как можно использовать arduino в связке с роутером. Можно написать более серьезные вещи. Управлять любыми приборами в своем доме при помощи веб-интерфейса и Arduino.

16 комментариев к “Zyxel Keenetic 4G, arduino и датчики температуры ds18b20”

  1. Здравствуйте. Прочитав о вашем изобретении, я понял, насколько я дремучий ;). А теперь по существу: можно использовать роутеры TP-Link, D-Link, Asus и др. с USB-портом?

Обсуждение закрыто.