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

image Привет Хабрахабр! Хочу поделится с вами как я подключил Arduino к своему роутеру. Поехали!
Современные роутеры — как небольшие компьютеры, которые выполняют узкоспециализированную задачу для раздачи сетевого трафика. На борту такого небольшого устройства установлена ОС Linux, только без графического интерфейса и с урезанной программной частью. Передо мной встал вопрос, а почему бы не подключить arduino к своему роутеру — Zyxel Keenetic 4G? Немного погуглив я наткнулся на замечательный форум, где одним из участников была сделана модифицированная прошивка с поддержкой установки дополнительных пакетов для Keenetic 4G.
В нашем случае управление 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 кОм
image
Скетч

Заливаем скетч. За основу взят код из этого урока и немного доработан под нашу задачу.
#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());
}
?>

Проблемы, с которыми я столкнулся
  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

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

P.S.

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

Спасибо за инвайт НЛО!
Поделиться публикацией

Комментарии 31

    +2
    Забавно. Правда, громоздкая конструкция получилась. Не смотрели в сторону LillyPad?
      +1
      LillyPad все же немного для другого предназначено… Чтоб было компактее — можно купить Teensy или Arduino Nano, а чтоб аккуратнее все выглядело — здорово помагает Sensor Shield — это тупо плата с кучей разъемчиков (GND, V, DATA), на которые удобно цеплять сенсоры или исполнительные устройства.
      У меня это выглядит так:
        0
        А температура чем определяется, терморезистор?
          0
          Так же как и у автора топика — DS18B20, на конце провода собственно он и резитор под термоусадкой. Замечательная штука, недорогой, точность 0.5 градуса, не требует калибровки, на одну шину 1wire можно много датчиков таких посадить.
      0
      Поздравляю с инвайтом.
      Зачем сажать два ds18b20 на отдельные ноги? А если их нужно несколько десятков? Шина 1-wire для того и придумана, чтобы вешать несколько датчиков на один провод.
      Конечно, нужно вкурить алгоритм поиска адресов, но он не такой сложный, как кажется на первый взгляд. К тому же, в библиотеке, которую вы используете, он наверняка уже реализован.
        0
        А можно просто считать адрес с датчика с помощью утилиты и несложного переходника, и забить напрямую. Но это так, для себя :)
          0
          Спасибо. Не разобрался с алгоритмом поиска адресов, поэтому пошел более простым для себя путем.
          +2
          Тут упомянули мой форум охарактеризовав его, как
          «где энтузиасты собирают модифицированные прошивки с поддержкой установки дополнительных, пакетов для серии Keenetic».

          С такой формулировкой не согласен. Дополнительные пакеты устанавливаются на usb накопитель и прошивку маршрутизатора никак не затрагивают. Очень многие это не понимают.

          Для keenetic 4G одним из участников форума сделана модифицированная прошивка для этой модели. Это очень частный случай. Разработчики обещают сделать поддержку пакетов в новой серии прошивок V2. Когда это будет, то и на Keenetic 4G не потребуется модифицированная прошивка.
            0
            Исправил.
            +2
            Чтобы ардуино не перезагружался при отсылке команд ничего паять не нужно, достаточно правильно сконфигурировать последовательный порт, команда должна быть такой:
            stty -F /dev/ttyUSB0 cs8 9600 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts -hupcl
            Подробнее смотрите в моей темке про Arduino на форуме Zyxmon.
              0
              Попробовал предварительно сконфигурировать через putty командой stty -F /dev/ttyACM0 cs8 9600 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts -hupcl в итоге все равно перезагружается. В чем может быть проблема?
                0
                Может используемая вами библиотека по своему его переконфигурирует после этого? Она поидее тоже должна вызывать stty, посмотрите в исходник.
              +1
              Arduino у меня нет, зато есть DS9094R с двумя датчиками DS18B20 — и все это дело подключено напрямую в юсб кинетика, правда пришлось пакет owfs компилировать — но все работает и мониторит температуру за окном.
                0
                Знакомые все люди ) В задаче мониторинга температуры за окном — самая сложная часть провести кабель к наружному датчику не испортив при этом интерьер )))
                  +1
                  Провода — убийцы интерьера
                  0
                  Чуток очепятался… Не DS9094R, а DS9490R
                    0
                    Прочитал статью и сразу мысль возникла — скоро уже диммеры или еще какую-нибудь простенькую фигню будут на ардуинах собирать.
                    Сразу возникла мысль — конвертер usb to 1-wire, плюс шелловый скрипт, который в базу кидает значения, плюс в текстовый файл текущие значения. Базу если надо потом на ББ можно подтянуть и строить красивые графики. А текущие значения через shtml инклюды в страничку пихать, либо сразу генерить скриптом страничку со значениями.
                    Забывают у нас про принцип KISS :(
                      0
                      Только вы не учитываете, что конвертер usb to 1-wire стоит дороже (а часто и очень дороже) чем та же ардуинка. К тому же конвертер — это просто конвертер, а если вам завтра надоест просто мерять температуру можно к ардуинке поцепить IR светодиод и управлять кондеем, или там включать/выключать свет, а конвертер… будет только мерять температуру…
                        +1
                        Конвертер он на то и конвертер, что к нему можно присобачить любой девайс с 1-wire. На этом одном проводе сколько угодно устройств может болтаться. И рулить ими можно будет в обе стороны. А IR-светодиод тоже при большом желании можно на 1-wire вывесить. Мы же не покупаем конвертер тупо с двумя датчиками всего? :)
                        В данном случае просто избыточные сущности, на мой взгляд, — php и ардуинка. Первое не кисло жрет ресурсы и так не особо шустрой железки. Второе — большая часть функционала просто простаивает.
                          0
                          Ну я в принципе поэтому для своих экспериментов с ардуиной и keenetic использовать bash скрипты, а расширение веб-интерфейса для него писал используя Lua и минималистичный вебсервер.
                          А ардуинка — это она ж для прототипирования и экспериментов… Сегодня работает термометром, завтра переставлена в радиоуправляемую машинку, после завтра — управляет фотоаппаратом.
                            0
                            Написал последний коммент и руки зачесались сделать дома такую штуку. А то dir-320 только инет раздает, да пару не особо полезных вещей крутит. Надо будет присобачить к нему датчик влажности+температуры и за борт второй такой же выкинуть.
                            В принципе при разумной экономии ресурсов можно половину функций мониторинга дома на роутер повесить, с учетом того, что для этой задачи мощностей с запасом. Но никаких php и иже с ним. Штук 20 запросов одновременно и роутер ласты склеит.
                            А на счет ардуины да. Для экспериментов штука хорошая, хотя по нынешним временам пора на STM8/32 переходить или на MSP430. Но блин дура здоровая эта ардуина. У меня такую болтающуюся плату ребенок махом вырвер и на запчасти разберет :( А конвертер за роутером скорее всего даже не заметит, как не замечает флешку в 320м :)
                              0
                              конвертеры кстати многие вообще внутрь корпуса роутера запихивают.
                                0
                                Отличная мысль! Спасибо.
                                Там внутри места — хоть пляши. На корпус только джек 3.5мм повесить, при желании можно даже несколько.
                                Пошел заказывать конвертер :)
                                  0
                                  может все же лучше Arduino nano? оно и дешевле и не больше по размерам, чем флешка, ну и можно еще что то кроме температуры на него повесить…
                                    0
                                    Не, с конвертером интереснее поиграться. Научусь с 1-wire напрямую работать. Тем более что у меня уже лежат LaunchPad 430й и STM32VLDiscovery. Ардуинка это уже старовато, да и многовато будем для меня платформ. Если мощности нужны хорошие — STM, если низкое потребление при хорошем функционале — 430ки. Не хочу время тратить разбираться со старыми технологиями.
                        0
                        Когда-то я так и сделал. Только конвертер сам паял т.к. готовые дорогие были. А дальше в сервер на FreeBSD и мониторил температуру в разных местах.
                      –1
                      Всегда удивляло. Целая ардуино и для таких мелких целей…
                        +2
                        А почему DS18B20 подключены на разные ноги? Вся соль интерфейса OneWire в возможности по одной ноге кучей всего управлять
                          +2
                          Комменты не читай @ Сразу отвечай
                            +1
                            именно так и поступил. Вину осознал, каюсь
                          0
                          У роутеров обычно есть GPIO порты, которыми можно управлять из прошивки. Почему бы не прицепить термометр сразу туда?

                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                          Самое читаемое