Close

Programování webových rozhraní pro Arduino

Ovládání Arduina přes internet

V poslední době se u nás na webu čas od času objevovaly prosby typu:Komentář

A je pravda, že takovýto článek tu chyběl. Psali jsme sice již o Ethernet Shieldu (dokonce dvakrát) i o WiFi shieldu. Vždy jsme ale rozebírali spíše jak naprogramovat Arduino pro čtení senzorů, ovládání LED… O programování webového rozhraní vždy zaznělo jen několik zběžných informací. To bych chtěl nyní napravit.

Úvod

Jak už to tak bývá, máme prakticky neomezeně možností, co se použitých komponent týče. Ať už chceme měřit vlhkost, teplotu, či rychlost větru, máme na výběr ze spousty různých senzorů. Stejně tak existuje celá řada modulů a shieldů, které připojí Arduino k internetu (zběžně například Ethernet Shield, WiFi Shield, modul ESP8266 a další). I výstupních zařízení můžeme mít spoustu (LED, Motory, Bzučáky…). Celý systém by se dal symbolicky zakreslit takto:

Schéma systému Arduino na Internetu

Schéma systému

Arduino tedy komunikuje se sítí pomocí modulu „Připojení“. Dále ze senzorů získává hodnoty (vlhkost vzduchu, rychlost větru atd.) a může odesílat jiné hodnoty na výstupní zařízení (rychlost otáčení motoru, úhel servomotoru, jas LED atd.). Co mají tyto hodnoty společné?

Všechno jsou to čísla! Ať už desetinná nebo celá, pořád jsou to jenom číselné hodnoty. Proto se dnes nebudeme moc zabývat tím, jaké senzory a výstupy máme. Pro jednoduchost si zvolíme dva analogové senzory – potenciometry (na pinech A4, A5) – a jeden digitální – tlačítko (pin D2). Stejně tak si ale můžete představit že se jedná o teploměr nebo vlhkoměr. Jako výstupní zařízení nám poslouží obyčejná LED (pin D3).

Také se moc nebudeme zabývat částí „Připojení“. Její ovládání závisí na konkrétním použitém modulu. Často je ale práce s moduly velmi podobná (například Ethernet Shield a Wifi Shield). My použijeme Ethernet Shield.

Zapojení simulující senzory a výstupní zařízení Arduino

Naše zapojení

Výběr řešení

Nyní přichází na řadu rozhodnutí, jakým způsobem vytvoříme komunikační rozhraní. Existuje celá řada řešení třetích stran. Některé z nich si představíme na konci článku. Jako první si ale vyzkoušíme vše vytvořit od začátku.

Umístění webové stránky

Jak si možná pamatujete z článku o Ethernet a Wifi shieldu, může Arduino v síti vystupovat dvěma způsoby. Buďto jako server nebo jako klient. V případě prvním běží webová stránka pro ovládání přímo na Arduinu. Nemáme tak tolik možností, protože má Arduino omezenou paměť, ale na základní ovládání to stačí. Toto řešení použijeme v případě, že neplánujeme nad daty provádět analýzy, popřípadě složitější vizualizace.

Arduino jako Server

Základem je HTTP protokol

Základem komunikace mezi serverem a klientem je (většinou) HTTP protokol. Ten přenáší všechny potřebné informace, které klient od webu může očekávat a zároveň pomocí HTTP protokolu klient říká, jaká data od serveru požaduje. O HTTP jsem psal ve článku o Ethernet Shieldu, kde si můžete tuto problematiku připomenout.

Zběžně si připomeňme činnost Shieldu na příkladu z Examples > WebClient, který stáhne obsah webu www.google.com a vypíše jej přes sériovou linku (včetně HTTP hlavičky).

/*
  Web client
 This sketch connects to a website (http://www.google.com)
 using an Arduino Wiznet Ethernet shield.
 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe, based on work by Adrian McEwen
 */
#include <SPI.h>
#include <Ethernet.h>
// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128);  // numeric IP for Google (no DNS)
char server[] = "www.google.com";    // name address for Google (using DNS)
// Set the static IP address to use if the DHCP fails to assign
IPAddress ip(192, 168, 0, 177);
// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;
void setup() {
 // Open serial communications and wait for port to open:
 Serial.begin(9600);
 while (!Serial) {
   ; // wait for serial port to connect. Needed for native USB port only
 }
 // start the Ethernet connection:
 if (Ethernet.begin(mac) == 0) {
   Serial.println("Failed to configure Ethernet using DHCP");
   // try to congifure using IP address instead of DHCP:
   Ethernet.begin(mac, ip);
 }
 // give the Ethernet shield a second to initialize:
 delay(1000);
 Serial.println("connecting...");
 // if you get a connection, report back via serial:
 if (client.connect(server, 80)) {
   Serial.println("connected");
   // Make a HTTP request:
   client.println("GET /search?q=arduino HTTP/1.1");
   client.println("Host: www.google.com");
   client.println("Connection: close");
   client.println();
 } else {
   // if you didn't get a connection to the server:
   Serial.println("connection failed");
 }
}
void loop() {
 // if there are incoming bytes available
 // from the server, read them and print them:
 if (client.available()) {
   char c = client.read();
   Serial.print(c);
 }
 // if the server's disconnected, stop the client:
 if (!client.connected()) {
   Serial.println();
   Serial.println("disconnecting.");
   client.stop();
   // do nothing forevermore:
   while (true);
 }
}

Když si otevřeme monitor sériové linky, vypíše se nám:

connecting...
connected
HTTP/1.1 302 Found
Location: http://www.google.cz/search?q=arduino&gws_rd=cr&ei=LP61VsHFHofjywOK2a3IDA
Cache-Control: private
Content-Type: text/html; charset=UTF-8
P3P: CP="This is not a P3P policy! See https://www.google.com/support/accounts/answer/151657?hl=en for more info."
Date: Sat, 06 Feb 2016 14:07:40 GMT
Server: gws
Content-Length: 278
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Set-Cookie: NID=76=ypwExw5cTiZ5fFfmeEwtEoGo1d8QLO14kjvx7WysrpCleRdBfNX8EhCYE6vkfHt56bneI6Lyi5utrZw7mLVjRBWJS2rj8Z2Jl2NsyobTCeRBUow3PfrL6C81CkeX4AzJPo7vwSiv; expires=Sun, 07-Aug-2016 14:07:40 GMT; path=/; domain=.google.com; HttpOnly
Connection: close
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.cz/search?q=arduino&gws_rd=cr&ei=LP61VsHFHofjywOK2a3IDA">here</A>.
</BODY></HTML>
disconnecting.

Rychlokurz HTML

Základem většiny webových stránek je HTML – HyperText Markup Language, tedy „hypertextový značkovací jazyk“. V češtině asi nejrozsáhlejší stránka zabývající se HTML je http://www.jakpsatweb.cz/, v angličtině je HTML velmi podrobně popsáno na stránkách W3CSchools. Základním stavebním prvkem stránky je značka (častěji se používá anglické označení tag). Tyto tagy se píší do špičatých závorek: <tag>. Mohou být párové – ty ohraničují nějakou část webové stránky, například <strong>Tučné písmo</strong> (ve stránce samozřejmě nejsou vidět, zde jsou pro názornost). Každý otevírací párový tag musí mít jemu odpovídající uzavírající tag (ten začíná lomítkem). Druhou možností jsou tagy nepárové – například nový řádek: <br /> (nepárovost je znázorněna tím, že končí lomítkem). Tagy je navíc možné do sebe vnořovat (jinak by HTML nemělo moc význam :)). <em>ABC<strong>DEF</strong></em> se tedy zobrazí jako ABCDEF.

Základní kostra stránky vypadá takto:

<html>
<head>
<title>Titulek - text v záložkách prohlížeče...</title>
Tato část se nazývá hlavička. 
Obsahuje například vložení skriptů, metadata pro vyhledávače, sociální sítě atd.
</head>
<body>
Tato část se nazývá tělo. Sem se píše samotný obsah stránky. 
</body>
</html>

My tedy potřebujeme, aby nám Arduino po připojení odeslalo webovou stránku, která bude obsahovat patřičné ovládací prvky. Začneme zvolna. Budeme chtít ovládat LED diodu pomocí odkazů vypnout a zapnout.

Ovládání LED

V HTML se odkaz vytvoří pomocí tagu <a href=“URL adresa“>Text odkazu</a>. Parametry budeme serveru předávat metodou GET (tak jako ve článku o Ethernet Shieldu). Když si tedy sestavíme odkaz <a href=“/?l=0″>VYPNI</a>, na který poté klikneme, HTTP request, který klient odešle serveru bude začínat následovně:

GET /?l=0 HTTP/1.1

Z toho my potřebujeme „vyextrahovat“ právě část l=0. Budeme tedy hledat první výskyt ‚?‘ v requestu a dále číst, co část GET obsahuje. Použijeme upravený kód z článku o Ethernet Shield. Všimněte si, že uvozovky, které jsou součástí odkazu před sebou mají zpětné lomítko: “. To je zde nutné kvůli kompilátoru. Řekneme mu tím, že chceme pracovat se znakem uvozovek a že se nejedná o část programu (začátek/konec řetězce). Tag <meta charset=“UTF-8″> říká, že budeme pracovat se znakovou sadou UTF-8, která podporuje i české znaky.

#include <Ethernet.h>
#include <SPI.h>
boolean zacatekCteni = false;
byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x9C, 0xB7}; //MAC adresa
IPAddress ip(10,0,0,3); //IP adresa
EthernetServer server = EthernetServer(80); //port
void setup(){
   pinMode(3, OUTPUT);
   Ethernet.begin(mac, ip); //vytvoření serveru
   server.begin(); //spuštění serveru
}
void loop(){
   EthernetClient client = server.available(); //načtení klienta
   
   if(client){
       boolean prazdnyRadek = true;
       boolean hlavickaPoslana = false;
       
       while(client.connected() && client.available()){
           if(!hlavickaPoslana){ //jednou pošleme hlavičku
               client.println("HTTP/1.1 200 OK");
               client.println("Content-Type: text/html");
               client.println();
               hlavickaPoslana = true;
               //dále pošleme obsah stránky
               client.println("<html>");
               client.println("<head><meta charset="UTF-8"></head>");
               client.println("<body>");
               client.println("<a href="/?l=0">VYPNI</a>");
               client.println(" - ");
               client.println("<a href="/?l=1">ZAPNI</a>");
               client.println("<br />");
               client.println("</body>");
               client.println("</html>");
           }
           
           char c = client.read();
           
           if(zacatekCteni && c == ' '){ //ukončí čtení
               zacatekCteni = false;
           }
           
           if(c == '?'){ //začne čtení
               zacatekCteni = true;
           }
           
           if(zacatekCteni){                
               if(c == 'l'){
                   client.read(); //přeskočíme jeden znak (=)
                   c = client.read(); //přečteme další znak -> hodnota LED
                   if(c == '0'){
                       digitalWrite(3, LOW);
                   }
                   else if(c == '1'){
                       digitalWrite(3, HIGH);
                   }
                   break; //vyskočí z cyklu
               }
           }
           
           if (c == 'n') {
               prazdnyRadek = true;
           }
           
           else if (c != 'r'){
               prazdnyRadek = false;
           }
       }
       delay(1);
       client.stop();
   } 
}

Zobrazení informací

Přidání informací o stavu potenciometrů a tlačítka je velice jednoduché. Můžeme si vybrat, jakým způsobem data zobrazíme. Abychom si ukázali jednoduchost HTML, zobrazíme si je přehledně v tabulce. Použijeme stejný kód, jen přidáme několik řádek. Tagy pro vytvoření tabulky jsou <table> pro samotnou tabulku, <tr> pro řádek, <td> pro buňku. Všechny tři jsou párové. Kód stránky vypadá následovně:

client.println("<html>");
client.println("<head><meta charset="UTF-8"></head>");
client.println("<body>");
client.println("<a href="/?l=0">VYPNI</a>");
client.println(" - ");
client.println("<a href="/?l=1">ZAPNI</a>");
client.println("<br />");
client.println("<table>");
client.println("<tr>"); //tlačítko
client.println("<td>Tlačítko<td>");
client.println("<td>");
client.println(digitalRead(2));
client.println("</td>");
client.println("</tr>");
client.println("<tr>"); // POT A5
client.println("<td>POT A5<td>");
client.println("<td>");
client.println(analogRead(A5));
client.println("</td>");
client.println("</tr>");
client.println("<tr>"); //POT A4
client.println("<td>POT A4<td>");
client.println("<td>");
client.println(analogRead(A4));
client.println("</td>");
client.println("</tr>");
client.println("</table>");
client.println("</body>");
client.println("</html>");

Mohli bychom pokračovat i dále. Často totiž nepotřebujete aktuální hodnotu, ale spíše průběh v čase. Hodnoty bychom si tedy museli logovat do Arduina a při připojení je zobrazit. Zobrazování hodnot se ale budeme věnovat později.

Poznámka pro zkušenější webaře: Zajímavé by mohlo být použití nějakého JS scriptu vloženého z externího zdroje pro hezké grafy a vizualizace. 

Arduino jako Klient

V tomto případě Arduino odesílá hodnoty na server, který je poté zpracovává. Tato možnost je podle mě daleko vhodnější, protože ulehčíte práci Arduinu. Nevýhodou je, že potřebujete zmíněný server. V našem případě to bude PHP server, který bude přijaté hodnoty zaznamenávat do MySQL databáze (pěkný tutoriál zabývající se PHP naleznete například na serveru ITnetwork). Můžete použít klidně i nějaký free hosting. My budeme hodnoty logovat na adrese https://arduino.cz/data/logger.php. Zde umístěný program bude čekat na hodnoty, které po přijetí uloží do databáze společně s časovým údajem záznamu.

Arduino Datalogger

Vytvoření MySQL tabulky

V dostupném nástroji pro správu MySQL databáze (například phpMyAdmin) vytvořte tabulku arduino_data, která bude mít tři sloupce: id, timestamp, hodnota. V již zmíněném phpMyAdmin to po přihlášení provedeme následovně:

  1. Vybereme databázi
  2. V dolní části okna vyplníme část Vytvořit tabulku. Do Název zadáme arduino_data a do Počet polí zadáme 3.
  3. Klikneme na  tlačítko Proveď.

    Vytvoření MySQL tabulky - Část první - Ovládání Arduina přes internet

    Vytvoření MySQL tabulky – Část první

  4. Objeví se nastavení jednotlivých sloupců.
  5. Řádky nazveme po řadě: id, timestamp, hodnota.
  6. Typ nastavíme pořadě: INT, TIMESTAMP, INT.
  7. V prvním řádku zaškrtneme vlastnost A_I, tedy Auto Increment – automatické zvětšování.
  8. U druhého řádku nastavíme vlastnosti Výchozí na CURRENT_TIMESTAMP.
  9. Zmáčkneme tlačítko Uložit.

Logování hodnot do tabulky

Tak, jak jsme si tabulku vytvořili, nám stačí přidat hodnotu a id a timestamp se přidají automaticky. Nyní k PHP kódu – jednotlivé části jsou okomentovány. Takto vypadá obsah souboru logger.php.

<?php 
$server = "localhost";
$user = "uzivatel";
$pass = "heslo";
$db = "jmeno_databaze";
$mysqli = mysqli_connect($server, $user, $pass, $db); //připojení k MySQL
if($mysqli and isset($_GET['hodnota'])){ //pokud GET obsahuje 'hodnota', pokračuj
$hodnota = sanitize($_GET['hodnota']);
$sql = "INSERT INTO arduino_data (hodnota) VALUES (".$hodnota.")"; //sestavení SQL
$doSql = $mysqli->query($sql); //vykonání SQL
if($doSql){ //test úspěchu
echo 'Zápis byl úspěšný';
}
else{
echo 'Něco se nepovedlo';
}
}
else{
echo "Neco je špatně";
}
function sanitize($input){ //ořízne řetězec
$input = htmlspecialchars($input);
$input = htmlentities($input);
$input = strip_tags($input);
$input = trim($input);
return $input;
}
?>

Pokud nyní nahrajeme tento kód na server a otevřeme jej v prohlížeči přes https://arduino.cz/data/logger.php/?hodnota=1000, objeví se nám v databázi nový záznam:

Záznam v databázi - Ovládání Arduina přes internet

Záznam v databázi

Arduino program

Nyní se přesuňme k Arduinu. Z něj potřebujeme odeslat naměřenou hodnotu.

#include <SPI.h>
#include <Ethernet.h>
byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x9C, 0xB7}; //MAC adresa
IPAddress ip(10,0,0,3); //IP adresa
char server[] = "arduino.cz"; //URL adresa serveru   
EthernetClient client;
void setup() {
   Serial.begin(9600);
   
   if (Ethernet.begin(mac) == 0) {
       Ethernet.begin(mac, ip);
   }
   delay(1000);
}
void loop() {
   if(client.connect(server, 80)){
       delay(1000);
       Serial.println("OK");
       client.print("GET https://arduino.cz/data/logger.php?hodnota=");
       client.println(analogRead(A5));
       client.println("Host: arduino.cz");
       client.println("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
       client.println("Connection: close");
       client.println();
       client.stop();
       delay(5000);
   }
}

Tento kód každých přibližně pět vteřin odešle hodnotu na server. Tabulka se nám postupně plní údaji.

Hodnoty v MySQL - Ovládání Arduina přes internet

Hodnoty v MySQL

Zobrazení naměřených hodnot

Pro zobrazení hodnot použijeme JavaScript knihovnu Chart.js. Stáhneme archiv s knihovnou a rozbalíme do do data/Chart. K práci nám stačí Chart.js a obsah složky src. Program, který bude data zobrazovat nazveme show.php.

<?php
$server = "localhost";
$user = "uzivatel";
$pass = "heslo";
$db = "jmeno_databaze";
$mysqli = mysqli_connect($server, $user, $pass, $db); //připojení k MySQL
//načtení hodnot z MySQL
$sql = 'SELECT * FROM arduino_data ORDER BY timestamp';
$doSql = $mysqli->query($sql);
while($row = $doSql->fetch_assoc()){
$popisky[] = $row['timestamp']; //načte popisky do pole
$hodnoty[] = $row['hodnota'];    //načte hodnoty do pole
}
$json_popisky = json_encode($popisky);
$json_hodnoty = json_encode($hodnoty);
?>
<html>
<head>
<script src="Chart/Chart.js"></script>
</head>
<body>
<div style="width:50%">
<div>
<canvas id="canvas" height="100%" width="100%"></canvas>
</div>
</div>
<script>
var randomScalingFactor = function(){ return Math.round(Math.random()*100)};
var lineChartData = {
labels : <?php echo $json_popisky ?>,
datasets : [
{
label: "My First dataset",
fillColor : "rgba(220,220,220,0.2)",
strokeColor : "rgba(220,220,220,1)",
pointColor : "rgba(220,220,220,1)",
pointStrokeColor : "#fff",
pointHighlightFill : "#fff",
pointHighlightStroke : "rgba(220,220,220,1)",
data : <?php echo $json_hodnoty ?>
}
]
}
window.onload = function(){
var ctx = document.getElementById("canvas").getContext("2d");
window.myLine = new Chart(ctx).Line(lineChartData, {
responsive: true
});
}
</script>
</body>
</html>

Na výsledek se můžete podívat na https://arduino.cz/data/show.php. Chart.js nabízí celou řadu typů grafů. Spolu s přehledným popisem je naleznete v dokumentaci Chart.js.

Ovládání Arduina

Možná si říkáte, jak ovládat Arduino, které se ke stránce připojuje jako klient. I zde existuje více cest. My použijeme opět PHP a MySQL. V MySQL budeme mít uložené konfigurační hodnoty, které Arduino získá připojením na stránku sloužící jako prostředník mezi Arduinem a MySQL.

Vytvoření tabulky

Začneme vytvořením velice jednoduché tabulky, kterou nazveme arduino_ovladani a bude mít dva sloupce. První nazveme modul (co ovládáme) a druhý hodnota (jaký má stav). Zbytek nastavíme podle obrázku. (Ano, měli bychom nastavit klíč, ale pro jednoduchost to vynechávám.).

Konfigurační tabulka - Ovládání Arduina přes internet

Konfigurační tabulka

Konfigurační formulář

Nyní si vytvoříme formulář, který bude měnit hodnoty v tabulce. V našem případě budeme pracovat s jediným řádkem tabulky. Jeho hodnota modul bude led a bude mít hodnotu 0 nebo 1. Ve formuláři použijeme pro přepínání hodnoty mezi 0 a 1 tzv. radio button (který určitě znáte, jen možná nevíte, že se tak jmenuje). Kód bude obsahovat i část, která zjistí, zda řádek s názvem led existuje. Pokud neexistuje vytvoří jej. Soubor nazveme config.php.

<?php
$server = "localhost";
$user = "uzivatel";
$pass = "heslo";
$db = "jmeno_databaze";
$mysqli = mysqli_connect($server, $user, $pass, $db); //připojení k MySQL
$sql = 'SELECT * FROM arduino_ovladani WHERE modul="led"';
$doSql = $mysqli->query($sql);
if($doSql->num_rows == 0){
$sql = 'INSERT INTO arduino_ovladani (modul, hodnota) VALUES ("led", 0)';
$doSql = $mysqli->query($sql);
}
if(isset($_POST['odeslano'])){ //pokud byl formulář odeslán
$hodnota = sanitize($_POST['stav']);
$sql = 'UPDATE arduino_ovladani SET hodnota="'.$hodnota.'" WHERE modul="led"';
$doSql = $mysqli->query($sql);
if($hodnota == 1){
echo 'Zapnuto';
}
else{
echo 'Vypnuto';
}
echo '<br /><br />';
}
$sql = 'SELECT * FROM arduino_ovladani WHERE modul="led"';
$doSql = $mysqli->query($sql);
$hodnota = $doSql->fetch_assoc()['hodnota']; //načte hodnotu led z DB
$zapnutoChecked = $hodnota == 1 ? 'checked' : ''; //nastaví výchozí hodnotu radio buttonu
$vypnutoChecked = $hodnota == 0 ? 'checked' : '';
echo '<form action="" method="POST" >';
echo '<input type="hidden" value="1" name="odeslano" />';
echo '<input type="radio" name="stav" value="1" '.$zapnutoChecked.' /> Zapnout<br>';
echo '<input type="radio" name="stav" value="0" '.$vypnutoChecked.' /> Vypnout<br><br>';
echo '<input type="submit" value="Odeslat">';
echo '</form>';
function sanitize($input){
$input = htmlspecialchars($input);
$input = htmlentities($input);
$input = strip_tags($input);
$input = trim($input);
return $input;
}
?>

Když se nyní podíváte na https://arduino.cz/data/config.php, uvidíte následující formulář:

Konfigurační formulář - Ovládání Arduina přes internet

Konfigurační formulář

Formulář nemusí obsahovat pouze radio button, ale celou řadu různých vstupů. Jejich přehled si můžete zobrazit například zde. Nyní musíme vytvořit stránku, která Arduinu pošle údaje z databáze.

Stránka zobrazující konfiguraci

Soubor nazveme controller.php. Za úkol bude mít vypisovat obsah tabulky arduino_ovladani ve tvaru modul:hodnota: (zobrazí takto za sebou všechny případné řádky tabulky). Bude se jednat o velice jednoduchý program:

<?php
$server = "localhost";
$user = "uzivatel";
$pass = "heslo";
$db = "jmeno_databaze";
$mysqli = mysqli_connect($server, $user, $pass, $db); //připojení k MySQL
$sql = 'SELECT * FROM arduino_ovladani';
$doSql = $mysqli->query($sql);
while($row = $doSql->fetch_assoc()){
echo $row['modul'].':'.$row['hodnota'].':';
}
?>

Nyní zbývá vytvořit Arduino program, který se připojí ke stránce https://arduino.cz/data/controller.php a podle toho nastaví stav LED.

Změna stavu LED

Závisí na projektu, jak často potřebujeme kontrolovat změnu stavu. Někdy stačí kontrolu provést jednou za hodinu a někdy je zase vteřina moc. My si zvolíme interval kontroly přibližně jednou za minutu.

#include <SPI.h>
#include <Ethernet.h>
#define BUFF_DELKA 255
byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x9C, 0xB7}; //MAC adresa
IPAddress ip(10,0,0,3); //IP adresa
char server[] = "arduino.cz"; //URL adresa serveru   
char buffer[BUFF_DELKA]; //zásobník na příchozí řetězec
EthernetClient client;
void setup() {
   pinMode(3, OUTPUT);
   
   Serial.begin(9600);
   
   if (Ethernet.begin(mac) == 0) {
       Ethernet.begin(mac, ip);
   }
   delay(1000);
}
void loop() {
   if(client.connect(server, 80)){
       delay(1000);
       client.println("GET https://arduino.cz/data/controller.php");
       client.println("Host: arduino.cz");
       client.println("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
       client.println("Connection: close");
       client.println();
       delay(1000);
       int inBuffer = 0;
       for(int i = 0; i < BUFF_DELKA; i++){ //vyprázdní buffer
           buffer[i] = ''; //nastaví všechny prvky buffer na znak konce řetězce
       }
       
       while(client.available()){
           buffer[inBuffer] = client.read();    
           inBuffer++;
       }
       
       if(inBuffer == 6){
           if(buffer[0] == 'l' && buffer[1] == 'e' && buffer[2] == 'd'){
               if(buffer[4] == '1'){
                   digitalWrite(3, HIGH);
               }
               else{
                   digitalWrite(3, LOW);
               }
               Serial.println(buffer[4]);
           }
       }
       client.stop();
   }
   delay(60000);
}

Dobré je si uvědomit, že stránka, která Arduinu poskytuje údaje může být zároveň i stránka, která od Arduina hodnoty přijímá a zapisuje je do databáze.

Tímto jsme dokončili část, kdy jsme si vše programovali sami a můžeme se stručně podívat na některé existující služby, které můžeme využít.

Řešení třetích stran

Plotly

Jak už název napovídá, služba Plotly slouží primárně k vizualizaci dat. Nabízí neplacený program pro menší objemy dat. Naleznete jej na URL adrese plot.ly. Inspirovat se můžete například u projektů zobrazujících aktuální teplotu nebo teplotu a vlhkost.

Phant

Americká společnost Sparkfun, která prodává velmi povedené shieldy a komponenty pro Arduino i další desky je autorem projektu Phant. Ten naleznete na data.sparkfun.com. Výhodou je, že Phant běží na Node.js a je možné jej rozběhnout i na vlastním serveru. Jeho používání přehledně popisují v sérii Pushing Data to Data.SparkFun.com. Veřejné feedy si můžete prohlédnout na data.sparkfun.com/streams.

IFTTT

Tuto službu možná znáte. Slouží k propojování API různých aplikací, které spolu normálně komunikovat neumí. Vytvoříte si předpis, který na základě akce spustí nějakou reakci (odsud také pochází název – IF This Then That – když to, tak ono). Například si můžete vytvořit předpis, který vám automaticky uloží všechny přílohy z Gmail do Skydrive, všechny Tweety o vás vám pošle na mail a podobně. Magie nastává, když k IFTTT připojíte Arduino. Co třeba vytvořit detektor otevření dveří s ESP8266 (za pomoci Adafruit.io), odeslat email po stisknutí tlačítka nebo zapnout WiFi zásuvku při detekci pohybu?

Thingspeak

Thingspeak je služba, který si klade za cíl propojit IoT zařízení. Vyzkoušejte například jednoduchý tutoriál zabývající se nahráváním dat nebo logováním vlhkosti.

IBM Bluemix

Poslední dva příklady patří spíše do kategorie „s kanonem na vrabce“. Jejich použití ale může přijít vhod, máte-li s těmito platformami nějaké zkušenosti. S IBM Bluemix můžete začít například v tutoriálu, se kterým k Bluemix připojíte teploměr. Ten využívá MQTT protokol, který má být náhražkou HTTP pro zařízení v internetu věcí.

Amazon Web Services

Amazon v srpnu minulého roku oznámil podporu SDK pro Arduino Yun. Více o AWS se můžete dočíst zde.

Závěr

Vidíte, že různých kombinací je nepřeberné množství, které není možné vtěsnat do jednoho článku. Doufám ale, že jsem vám poskytl dobrý vhled do probírané problematiky a že nabyté znalosti budou dostačující pro jednoduchý průchod vašimi projekty 🙂

Není vám z výkladu něco jasné, nebo máte jiné nápady, jak kterou část udělat? Neváhejte nám dát vědět v komentářích nebo na fóru!

Zbyšek Voda

Zbyšek Voda

Už nějaký čas se zajímám o věci kolem Internetu věcí a otevřeného hardware a software. Tak jsem se také v roce 2010 dostal k Arduinu, pro které dodnes programuji a taky píšu články o práci s ním. Baví mě vymýšlet, jak staré věci používat novým způsobem.
Zbyšek Voda

21 Comments on “Programování webových rozhraní pro Arduino

jiri.urban
14.12.2016 at 23:12

Ahoj pokouším se zprovoznit odesílání dat do databáze ale nějak se mi to nedaří chtěl jsme posílat jen obyčejně teplotu.

Zde je zdrojový kód arduina

#include
#include
#include

byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x9C, 0xB7}; //MAC adresa
IPAddress ip(10,0,0,3); //IP adresa
char server[] = „arduinohome.8u.cz“; //URL adresa serveru
dht11 cidlo;
int dht11pin = 5;
int teplota;
int vlhkost;
EthernetClient client;

void setup() {
Serial.begin(9600);

if (Ethernet.begin(mac) == 0) {
Ethernet.begin(mac, ip);
}
delay(1000);
}

void loop() {

cidlo.read(dht11pin);
teplota = cidlo.temperature;
vlhkost = cidlo.humidity;

if(client.connect(server, 80)){
delay(1000);
Serial.println(„OK“);
client.print(„GET http://arduinohome.8u.cz/logger.php?hodnota=„);
client.println(teplota);
client.println(„Host: arduinohome.8u.cz“);
client.println(„Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8“);
client.println(„Connection: close“);
client.println();
Serial.println(teplota);
client.stop();
delay(5000);
}
}

snažím se s tím poprat už pár dní takže jsem vytvořil stejnou tabulku a vše abych eliminoval chybu ale stejně se mi to nepodařilo (tabulka má id, timestamp, hodnota)

když napíšu do prohlížeče http://arduinohome.8u.cz/logger.php?hodnota=80 tak se mi hodnota do databáze zapíše ale z arduina ne a ne zapsat.

Budu rád za jakoukoliv radu

Zbyšek Voda
Zbyšek Voda
14.12.2016 at 23:23

Dobrý den, jestli můžu z těchto informací soudit, tak problém bude v hostingu. To máte nějaký webhosting zdarma, že?
Nedávno jsem s jedním čtenářem řešil stejný problém. Řekl bych, že problém bude v tom, že při připojení na server dojde k přesměrování, se kterým si webový prohlížeč umí poradit, ale Arduino si s ním neporadí.
Web po připojení pravděpodobné vrátí HTTP odpověď s přesměrováním, kde je uvedeno i kam se dotaz má přesměrovat.

Řešením je buďto tuto odpověď serveru analyzovat (tedy zjistit tu koncovou adresu) a poslat dotaz až na koncovou adresu (toto by snad mělo stačit udělat jednou, čímž si zjistíte adresu přesměrování a potom už se z Arduina vždy dotazovat přímo na tuto adresu), nebo přejít na jiný hosting. V případě, který jsem zmiňoval dříve, se problém povedlo vyřešit přechodem na placený hosting, konkrétně Wedos, kde k žádnému přesměrování nedochází. Možná existuje i nějaký free hosting, který by fungoval, ale v tomto se moc neorientuji.

jiri.urban
15.12.2016 at 23:56

Zkoušel jsem to na localhostu a tam to jde. Takže děkuji za radu. Bylo to na endoře na free hostingu. Myslíš že na endoře u placeného hostingu to bude fungovat správně ?? nebo takov přesměrování nejspíše budou mít udělaný u free i u placeného hostingu.

Zbyšek Voda
Zbyšek Voda
17.12.2016 at 9:50

V tomto se nevyznám, takže nedokážu soudit a nerad bych vám kecal 🙂
Jak už jsem psal, vím, že na Wedosu to fungovalo.

Korčagin
29.10.2016 at 11:46

Dobrý den, dělám si podle návodu

http://arduino.cz/programovani-webovych-rozhrani-pro-arduino/

meteostanici. Zatím ale nemohu rozchodit zápis hodnot do MySQL.
Nefunguje mi to volání „loggeru“. Když to dám ručně do prohlížeče, tak mi to hodnoty do MySql zapisuje. Např:
http://sazeni.borec.cz/ARmetLogger1.php?teplo=40&tlak=980&vlhko=50

Nefunguje mi tato část programu na Arduinu: (IP a MAC jsou v pořádku – odzkoušeno PINgem atd…)
****************************************************************************************
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; //MAC adresa
IPAddress ip(192, 168, 1, 78);
char server[] = „sazeni.borec.cz“; //URL adresa serveru
int tempe = 37;
int interval = 1;
int ijk;
EthernetClient client;

void setup() {
Serial.begin(9600);
interval = (interval*60-2);
Serial.print(„Interval zobrazovani je „);
Serial.print(interval/60+1);
Serial.println(“ minut“);
// ************************************************************************************************************
while(!Serial) {} // Wait
while(!bme.begin()){
Serial.println(„Could not find BME280 sensor!“);
delay(1000);
}
// *************************************************************************************************************
Ethernet.begin(mac, ip);
Serial.print(„Local IP „);
Serial.println(Ethernet.localIP());
delay(100);
}
void loop() {
printBME280Data(&Serial);
if(client.connect(server, 80)){
delay(1000);
Serial.println(“ –> OK“);
client.println(„GET http://sazeni.borec.cz/ARmetLogger1.php?teplo=40&tlak=980&vlhko=50„);
// client.println(tempe);
client.println(„Host: sazeni.borec.cz“);
client.println(„Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8“);
client.println(„Connection: close“);
client.println();
client.stop();
for(ijk=0;ijk<=interval;ijk++)
{
delay(1000);
}
}
else {
Serial.println("Spojeni se nepovedlo ");
client.stop();
delay(100);
}
}

Pokud na to bude mít někdo náladu a čas, můžete to vyzkoušet. Na stránce

http://www.sazeni.borec.cz si funkcí "Počasí na Tajchu"
zobrazím graf a tabulku počasí.

Poradí něko???
S pozdravem
==============================================
Pavel Pokorný
Liberec

Zbyšek Voda
Zbyšek Voda
30.10.2016 at 16:28

Dobrý den, můžete prosím k problému napsat ještě další info?
Jak se projevuje to, že program nefunguje? Nepodaří se připojit k síti, nevypisuje “ -> OK“, nebo se zdá, že funguje, jenom neloguje na web?

Zkoušel jste přímo ten program ze článku (s vaší URL) ?

Korčagin
30.10.2016 at 18:55

K síti připojený jsem. Na 192.168.1.78 si PINGnu. Když odpojim sítový kabell nebo když je Arduino bez napájení, tak PING nefunguje. Když jej opětovně připojím tak PING reaguje normálně. To “ -> OK“ mi to vypisuje. Nefunguje mi ten „… GET htttp://sazeni…“ – to volání ARmetLogger1.php. Když to zadám ručně do prohlížeče, tak to hodnoty do MySQL zapíše.

Korčagin
30.10.2016 at 20:16

Jo jo, program jsem dá se říci doslova okopíroval, pouze jsem změnil „arduino.cz“ na „sazeni.borec.cz“ a jméno loggeru na ARmetLogger1.php

Zbyšek Voda
Zbyšek Voda
1.11.2016 at 19:30

Dobře. Pojďme od sebe zkusit odizolovat jednotlivé části a zjistit, kde je problém.

Podle chování shieldu při pingání v místní síti komunikuje.
Zkusil bych otestovat, jestli se mu podaří dostat i mimo síť 🙂

Co vám vypisuje sériová linka na tomto příkladu https://www.arduino.cc/en/Tutorial/WebClient?

Korčagin
2.11.2016 at 9:24

Zatím díky za ochotu a čas…

Vrací mi to TOTO:

connecting…
connected
HTTP/1.1 302 Found
Location: http://www.google.cz/search?q=arduino&gws_rd=cr&amp;
.
.
.
disconnecting.

Nejde mi to tu celé poslat mohu to poslat někam na mail?

wegac
6.9.2016 at 8:17

ahoj,
potreboval bych do tabulky zapisovat nejen cisla, ale i pismena, poradite prosim, co zmenit jak v kodu pro arduino, tak v PHP? databazi jsem nastavil na text
diky

Zbyšek Voda
Zbyšek Voda
6.9.2016 at 15:04

Dobrý den, url pro odeslání čísla vypadá takto:
http://arduino.cz/data/logger.php/?hodnota=1000
pro odeslání textu bude tedy vypadat nějak takto:
http://arduino.cz/data/logger.php/?hodnota='ahoj‚, což pokud se převede do tvaru validního url bude vypadat takto:
http://arduino.cz/data/logger.php/?hodnota=%27ahoj%27

Miroslav
4.7.2016 at 7:15

Diky, tenhle clanek je uplne super navod

Honza
3.4.2016 at 8:56

Kromě načítání dat do myslq bežící na NASu Synology už delší dobu jsem se nyní pokus i druhý směr – ovládání arduina jako klienta pomocí dat v databázi jak je ukázáno v závěru článku s tím že jsem ti upravil pro svůj lokální server na NASu a vše fungovalo. Pak jsem však provedl ubdate Synolgy s DSM 5.2 na DSM 6 což v sobě má i update PHP z verze 5.5 na 5.6. Po tomto updatu však nastal problém-přestože při spuštění scriptu controller.php z prohlížeče dostanu správnou odezvu led:1: tak to arduina se načte do bufferu:
buffer_délka=226
buffer obsah:

400 Bad Request

Bad Request
Your browser sent a request that this server could not understand.

Pokud kód přesměruji na externí controller.php na arduino.cz tak se správně vráti 6 znaku led:1:
Nemáte prosím tip jak tento problém napravit.
Děkuji

Honza
3.4.2016 at 8:59

v hlaviče načtené do bufferu (co se bohužel v předchozím příspěvku nezobrazilo) je ještě uvedeno DOCTYPE HTML PUBLIC „-//IETF//DTD HTML 2.0//EN“

vaseks0001
3.3.2016 at 17:14

Dobrý den,
Super článek, ale u posledního příkladu mi to hází chybu.

buffer[i] = “; //nastaví všechny prvky buffer na znak konce řetězce

a píše to :

test_Mysql:39: error: empty character constant

buffer[i] = “; //nastavĂ­ všechny prvky buffer na znak konce Ĺ™etÄ›zce

^

exit status 1
empty character constant

Pomohl by mi někdo s tímto problémem? Moc děkuji

Zbyšek Voda
Zbyšek Voda
4.3.2016 at 10:54

Dobrý den, omlouvám se, byla to moje chyba. V kódu už je to opraveno.
Nevšiml jsem si, že HTML také escapuje znak \0
Správný tvar je:
buffer[i] = ‚\0‘; (obě uvozovky nahoře, WordPress nějak sám dává tu první dolů :/)

Tomáš Jurman
9.2.2016 at 7:55
Pepepi
8.2.2016 at 18:39

Dobrý den,
perfektní .
Super, po přečtení mě začala spousta věcí do sebe zapadat 🙂 . Beru jako úvod do problematiky a podklady ke studiu 🙂 . Pouštím se do toho.

Děkuji

Honza
8.2.2016 at 10:44

Super článek, uvedené informace jsem dohledával po kouskách cca 14 dní a když jsem si to dal do kupy tak to autor servíruje na stříbrném podnose 🙂
Jen doplním ,že MYSQL lze bez potřeby dalších znalostí spustit na domácím NASu od Synology včetně phpMyAdmin a mít to tak pod jednou střechou kdy systém bude pracovat i při případném výpadku internetu. Uvedené kódy lze s drobnou úpravou použít i pro NodeMCU a přes wifi tak přípojit senzory i tam kde není kabel, navíc i levněji.

MIlan
13.2.2016 at 12:30

Veľmi dobrý článok. Za zmienku by stala aj aplikácia tretích strán a to Exosite portal https://portals.exosite.com/login dokonca pre arduino existuje hotová knižnica.

Napsat komentář