- PVSM.RU - https://www.pvsm.ru -

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

image Привет Хабрахабр! Хочу поделится с вами как я подключил Arduino к своему роутеру. Поехали!
Современные роутеры — как небольшие компьютеры, которые выполняют узкоспециализированную задачу для раздачи сетевого трафика. На борту такого небольшого устройства установлена ОС Linux, только без графического интерфейса и с урезанной программной частью. Передо мной встал вопрос, а почему бы не подключить arduino к своему роутеру — Zyxel Keenetic 4G? Немного погуглив я наткнулся на замечательный форум [1], где энтузиасты собирают модифицированные прошивки с поддержкой установки дополнительных, пакетов для серии Keenetic.
В нашем случае управление Arduino происходит через библиотеку php_serial.class.php [2] и легкого веб сервера на основе Lighttpd [3] + php. С помощью этих инструментов будем подавать команды ардуинке на чтение показаний с двух температурных датчиков (дом, улица), записывать ответ в базу данных Sqlite3 [4] и выводить на нашу веб-страничку.

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

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

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

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

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

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

#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» [11].

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());
}
?>

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

  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).
    deviceSet("/../../../../dev/ttyACM0"); 
  2. В 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);
    }
  3. После заливки скетча в Arduino между пинами GND и Reset ставим конденсатор на 22 мФ. Это предотвращает перезагрузку во время приема команд.

Пару фоток

image

image

Скачать все необходимые файлы одним архивом [12]

P.S.

Это лишь небольшой пример того, как можно использовать arduino в связке с роутером. Можно написать более серьезные вещи. Управлять любыми приборами в своем доме при помощи веб-интерфейса и Arduino.

Спасибо за инвайт НЛО!

Автор: Rimidalw


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/arduino/5148

Ссылки в тексте:

[1] форум: http://forum.zyxmon.org/forum6-marshrutizatory-zyxel-keenetic.html

[2] php_serial.class.php: http://www.phpclasses.org/browse/file/17926.html

[3] Lighttpd: http://ru.wikipedia.org/wiki/Lighttpd

[4] Sqlite3: http://ru.wikipedia.org/wiki/Sqlite

[5] Альтернативная прошивка: http://ifolder.ru/29072957

[6] обсуждение: http://forum.zyxmon.org/post4593.html#p4593

[7] opkg: http://code.google.com/p/zyxel-keenetic-packages/wiki/opkg_setup

[8] здесь: http://code.google.com/p/zyxel-keenetic-packages/source/browse/#svn%2Fbinary-packages-r2

[9] Lighttpd и php: http://code.google.com/p/zyxel-keenetic-packages/wiki/Drupal7

[10] урока: http://cxem.net/arduino/arduino17.php

[11] «3D кнопки с помощью CSS3»: http://habrahabr.ru/post/137005/

[12] Скачать все необходимые файлы одним архивом: http://lukjanow.ru/?dl_id=55