ESP8266 - HTTP server a AngularJS

Zápisník experimentátora

Hierarchy: ESP8266

Velké množství příkladů pro ESP8266 používá prohlížeč HTML pouze na zobrazení statických stránek, které vygeneroval mikrokontrolér. Takto ale fungoval Internet před deseti lety. Dnes má v sobě každý prohlížeč vysokovýkonné jádro, které pomocí javascriptu dokáže proměnit statické stránky na dynamické. Musíte si uvědomit, že v prohlížeči máte k dispozici vysoký výkon, který je nesrovnatelný s výkonem samotného ESP8266.

Proto si dnes ukážeme, jak tento výkon využít a výslednou stránku z mikrokontroléru generovat až v prohlížeči u uživatele. ESP8266 bude pouze dodávat podkladové údaje a výsledek se bude zobrazovat pomocí AngularJS v prohlížeči. Aby dnešní zdrojový kód nebyl pro vás příliš složitý, napsal jsem dva vzorové příklady, které simulují vše pomocí souborového systému SPIFFS.

  • Jednostránková aplikace pomocí AngularJS a Bootstrap, která z ESP8266 získá seznam kytarových efektů spolu s obrázky a výsledek zobrazí v podobě pěkné tabulky.
  • Vícestránkové aplikace pomocí AngularJS a Bootstrap, která simuluje online teploměr i s tabulkou historických dat.

Zpět do minulosti

V článku využijeme některé technologie, které jsem popisoval v předchozích článcích.

Použité součástky

Toto je jednoduchý projekt, proto nám bude stačit některá deska s mikrokontrolérem ESP8266, kterou lze přímo připojit do USB. Abyste se vyhnuli případnému zkratu, můžete desku zastrčit do breadboardu.

  • ESP8266 {linkESP8266}
  • Breadboard {linkBreadBoard}

Jednostránková aplikace pomocí AngularJS

Na první příklad jsem si vybral několik kytarových efektů od firmy Digitech. Mají zajímavá jména (Nautila, Polara, Obscura) a mají i tajemné obrázky na svém povrchu. Jako výsledná HTML stránka vypadá vidíte v následujícím obrázku. Stránka se skládá z následujících souborů.

  • index.html - Toto je šablona stránky pro AngularJS. Je to normální HTML stránka, která obsahuje odkaz na AngularJS aplikaci, která ze šablony vytvoří výslednou stránku. V šabloně se používá několik speciálních tagů, které AngularJS aplikace použije k tomu, aby podle nich vytvořila výslednou stránku.
  • single.js - Zdrojový kód pro AngularJS aplikaci. Celý princip programu je v tom, že se po inicializaci připojí přes HTTP na ESP8266 a stáhne si odtud údaje o kytarových efektech. Ty údaje vloží mezi své lokální proměnné a z nich se automaticky vygeneruje samotná stránka. V tom je ukryta snadnost použití AngularJS.
  • data.json - Tyto údaje si stáhne AngularJS aplikace a pomocí nich vytvoří na stránce tabulku s popisem jednotlivých kytarových efektů a přidá k nim obrázky.
  • simple_http_server_angularjs1.ino - Zdrojový kód programu pro ESP8266. Tento typ programu jsme si tu už ukázali. Je to HTTP server, který celý obsah dodává ze souborového systému SPIFFS.
  • obrázky - V souborovém systému SPIFFS máme uloženy i obrázky. Když bude AngularJS aplikace vytvářet stránku, doplní do ní i odkazy na obrázky a ty se automaticky stáhnou ze SPIFFS.

index.html

Pojďme si vysvětlit, jak se vytváří AngularJS aplikace pomocí této šablony. Na začátku se toto načte do prohlížeče a aby se AngularJS aplikace spustila, jsou potřebné tyto HTML značky. Na začátku stránky vidíte několik značek <script>. Ty se starají o to, abychom si na stránku stáhli responzívny design Bootstrap a AngularJS. Poslední značka <script src="single.js"></script> načte do prohlížeče zdrojový kód programu. Na to, aby program věděl, kde má na stránce vytvořit výslednou stránku, nám slouží značka <div ng-app="singleApp" ng-controller="singleCtrl">...</div>. Takto jsme označili místo pro aplikaci singleApp s grafickým kontrolérem singleCtrl. Další značky obsahují atributy, které slouží jako příkazy pro AngularJS. Jsou to například atributy ng-repeat pro vytvoření cyklu a značky {{xxx}}, které slouží k zobrazení obsahu proměnné v programu.

<html>

<head>
    <meta http-equiv="content-type" content="text/html;charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.8/angular.js"></script>
    <script src="single.js"></script>
    <link rel="icon" type="image/png" href="favicon.png">
    <title>HTTP Server ESP8266 - AngularJS single</title>
</head>

<body>
    <div class="container" ng-app="singleApp" ng-controller="singleCtrl">
        <h1>ESP8266 HTTP Server - AngularJS Singlepage Application</h1>
        <div ng-repeat="x in data.pedals | orderBy: 'name'">
            <h2 class="alert alert-info">{{x.name}}</h2>
            <div class="row">
                <div class="col-sm-4"><img class="img-responsive" src="{{x.image}}"></div>
                <div class="col-sm-8">{{x.description}}</div>
            </div>
        </div>

        <p>Copyright (C) 2019 <a href="https://www.arduinoslovakia.eu">Arduino Slovakia</a>.</p>
    </div>
</body>

</html>

single.js

Asi jsem v textu zatím nezmínil, že AngularJS byl navržen tak, aby byly programy v něm jednoduché. Toto je celý program. Vytvoří se aplikace singleApp a přiřadí se do proměnné app. A do této aplikace se přidá kontrolér singleCtrl. Kontrolér po startu zavolá funkci downloadData(), která si stáhne obsah souboru data.json a uloží ho do proměnné $scope.data. A o víc se nemusíte starat, protože v šabloně jsme nastavili, že data.pedals je pole, které se má postupně zobrazit a forma je určena vnořenými HTML značkami v tagu div, který funguje jako cyklus.

var app = angular.module('singleApp', []);

app.controller('singleCtrl', ['$scope', '$http', function ($scope, $http) {

    function downloadData() {
        $http.get('data.json')
        .then(function (response) {
            $scope.data = response.data;
        }, function (response) {
            $scope.error = response.data.error;
        });
    }

    downloadData();

}]);

data.json

Takto vypadá vzorový JSON. Obsahuje tři objekty v poli pedals. Každý objekt má tři atributy. Jméno, popis a odkaz na obrázek.

{
    "pedals": [
        {
            "name": "Nautila",
            "description": "Sing a song of stormy oceans and float upon the calming seas with the Nautila Chorus/Flanger. Create never before heard tidal swirls or soothing rhythmic waves with the Voice and Drift controls. These controls allow you to add up to eight chorus or four flanger voices and then blend and morph the waveforms in real-time with the Drift knob. Alter the modulation speed in real-time by holding down the momentary footswitch and then release to continue on your voyage through the currents. Separate Speed, Depth, Emphasis, Voices and Mix controls shape your waves into clean curls or soupy foam. True Bypass, stereo inputs and outputs, silent switching, and rugged construction, make the Nautila as practical as it is creative. The Nautila uses a 9VDC power supply to easily integrate into your existing pedalboard.",
            "image": "nautila.jpg"
        },
        {
            "name": "Polara",
            "description": "Featuring seven inspirational Lexicon® reverbs, the DigiTech® Polara will be the new architect of your soundscape, defining space and adding dimension to your playing. The Polara’s flexible reverbs cover a full spectrum, from the intimate warmth of “Room”, to the vast expansiveness of “Hall”, through time with the cosmic power of “Reverse”, and anchored by Lexicon’s revered “Modulated”, “Plate” and “Spring” reverbs. In addition to those classics, the Polara introduces the new “Halo” reverb. The “Halo” reverb with cascading octaves interspersed in the reverb decays will cast a heavenly glow over your tone. With its new, compact size and soft-touch vacuum-style footswitch, the Polara truly represents the latest evolution in DigiTech pedal design. We’ve put years of experience into every detail of its mechanical and sonic blueprint. The Polara offers independent Level, Liveliness, Decay and Type controls; Stereo Inputs and Outputs; a Soft Click Footswitch; and a Reverb Tails On/Off Toggle Switch. It is true bypass, and uses a 9V DC power supply to easily integrate into your existing pedalboard.",
            "image": "polara.jpg"
        },
        {
            "name": "Obscura",
            "description": "The Obscura Altered Delay from DigiTech allows you to turn your delays upside down and inside out. The Obscura’s four delay types can be darkened, degraded and distorted on the fly with the stacked Tone and Degrade controls. Combine these controls with the Obscura’s Repeat/Hold feature and lose yourself in long, trippy, gurgling repeats or backwards-manipulated sonic mayhem. In addition to its Tone and Degrade controls, the Obscura features independent Level, Delay Mode and stacked Time and Repeats controls. Complimenting those versatile controls, the Obscura offers four excellent-sounding Analog, Tape, Lo-Fi, and Reverse types, Tap Tempo mode with Beat Divisions, Stereo Inputs/Outputs, a Delay Tails On/Off Switch and True Bypass circuitry. With its compact size and vacuum-style footswitch, the Obscura furthers DigiTech’s evolution in pedal design. We’ve put years of experience into every detail of its mechanical and sonic blueprint. The Obscura uses a 9V DC power supply to easily integrate into your existing pedalboard.",
            "image": "obscura.jpg"
        }
    ]
}

simple_http_server_angularjs1.ino

Zdrojový kód pro ESP8266. Je to HTTP server, který celý obsah dodává ze SPIFFS. Ten obsah se nachází v adresáři data a je třeba jej do SPIFFS načíst pomocí příkazu Tools/ESP8266 Sketch Data Upload. SPIFFS je popsán podrobně v samostatném článku.

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <FS.h>
#include "arduino_secret.h"

ESP8266WebServer server(80);

void setup(void) {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: http://");
  Serial.println(WiFi.localIP());

  SPIFFS.begin();

  server.serveStatic("/", SPIFFS, "/index.html");
  server.serveStatic("/favicon.png", SPIFFS, "/favicon.png");
  server.serveStatic("/single.js", SPIFFS, "/single.js");
  server.serveStatic("/data.json", SPIFFS, "/data.json");
  server.serveStatic("/nautila.jpg", SPIFFS, "/nautila.jpg");
  server.serveStatic("/obscura.jpg", SPIFFS, "/obscura.jpg");
  server.serveStatic("/polara.jpg", SPIFFS, "/polara.jpg");

  server.onNotFound([]() {
    server.send(404, "text/plain", "404: Not Found");
  });

  server.begin();
  Serial.println("HTTP server started");
}

void loop(void) {
  server.handleClient();
}

Vícestránkové aplikace pomocí AngularJS

Druhý příklad je více komplexnější. Tento příklad se hodí na situace, když chcete v rámci jedné webstránky vybudovat rozsáhlejší aplikaci. Pokud v ní budete zobrazovat informace na více stránkách, musíte si vytvořit tabulku směrování mezi URL podstránkami a jednotlivými kontroléry, které se postarají o zobrazení obsahu na každé podstránce. Já jsem vymyslel následující situaci, která se poměrně často objevuje jako příklad pro ESP8266. Je to aplikace, která měří teplotu. Používá dvě stránky:

  • Temperature - Zde zobrazuje aktuální teplotu.
  • History - Zde zobrazuje tabulku s historickými daty měření teploty.

Pro vytvoření příkladu používám opět jen statické údaje, které se nacházejí v souborovém systému SPIFFS, ale pro šikovnějšího programátora není problém tyto údaje doplnit. Pokud k nim nepatříte, tak si počkejte na některé z pokračování seriálu o ESP8266, kde vám celý příklad naprogramuji.

Stránka se skládá z následujících souborů:

  • index.html - Šablona aplikace. Je mírně odlišná od předchozí, protože přímo na ní není nastaven kontrolér. Ty se nastavují ve speciální tabulce.
  • page1.html - Šablona pro stránku, na níž je aktuální teplota.
  • page2.html - Šablona pro stránku, na níž je tabulka historických měření teploty.
  • multiple.js - Zdrojový kód AngularJS aplikace. Vytvoří stránku se dvěma podstránkami. Pro každou podstránku má vlastní kontrolér, který se postará o zobrazení údajů.
  • data1.json - Obsahuje vzorová data aktuální teploty.
  • data2.json - Obsahuje vzorová data tabulky historických měření teploty.
  • simple_http_server_angularjs2.ino - Zdrojový kód programu pro ESP8266. Tento typ programu jsme si tu už ukázali. Je to HTTP server, který celý obsah dodává ze souborového systému SPIFFS.

index.html

Pojďme si vysvětlit, jak se vytváří AngularJS aplikace pomocí této šablony. Na začátku se toto načte do prohlížeče a aby se AngularJS aplikace spustila, jsou potřebné tyto HTML značky. Na začátku stránky vidíte několik značek <script>. Ty se starají o to, abychom si na stránku stáhli responzívny design Bootstrap a AngularJS. Poslední značka <script src="multiple.js"></script> načte do prohlížeče zdrojový kód programu. Na to, aby program věděl, kde má na stránce vytvořit výslednou stránku, nám slouží značka <div ng-app="multiple" ng-view></div>. Takto jsme označili místo pro aplikaci multipleApp s více stránkami. Vůči předchozí šabloně zde je změna v atributu ng-view. Tím nastavíme, že kdesi ve zdrojovém kódu aplikace bude tabulka, která přiřadí pro každou URL konkrétní šablonu a kontrolér.

<html>

<head>
    <meta http-equiv="content-type" content="text/html;charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.8/angular.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.8/angular-route.js"></script>
    <script src="multiple.js"></script>
    <link rel="icon" type="image/png" href="favicon.png">
    <title>HTTP Server ESP8266 - AngularJS multiple</title>
</head>

<body>
    <div class="container">
        <h1>ESP8266 HTTP Server - AngularJS Multiplepage Application</h1>
        <div ng-app="multipleApp" ng-view>
        </div>

        <p>Copyright (C) 2019 <a href="https://www.arduinoslovakia.eu">Arduino Slovakia</a>.</p>
    </div>
</body>

</html>

page1.html

Šablona pro aktuální teplotu. Teplota se zobrazí pomocí proměnné {{data.temperature}}.

<nav class="navbar navbar-default">
    <div class="container-fluid">
        <div class="navbar-header">
            <a class="navbar-brand" href="/">ESP8266</a>
        </div>
        <ul class="nav navbar-nav">
            <li class="active"><a href="/#!/">Temperature</a></li>
            <li><a href="/#!/history">History</a></li>
        </ul>
    </div>
</nav>

<p>Temperature: <b>{{data.temperature}}</b></p>

page2.html

Šablona pro historické měření teploty. Je to tabulka, do které se zobrazí údaje z proměnné data.history. Protože v té proměnné je pouze pole čísel, musel jsem doplnit parametr track by $index. Kdyby to byla tabulka objektů, toto není nutné.

<nav class="navbar navbar-default">
    <div class="container-fluid">
        <div class="navbar-header">
            <a class="navbar-brand" href="/">ESP8266</a>
        </div>
        <ul class="nav navbar-nav">
            <li><a href="/#!/">Temperature</a></li>
            <li class="active"><a href="/#!/history">History</a></li>
        </ul>
    </div>
</nav>

<table class="table">
    <tr>
        <th>#</th>
        <th>Temperature</th>
    </tr>
    <tr ng-repeat="x in data.history track by $index">
        <td>{{$index+1}}</td>
        <td>{{x}}</td>
    </tr>
</table>

multiple.js

Tento zdrojový kód je jen mírně odlišný. Funkcí config si přidáme routovací tabulku mezi URL, šablonou a kontrolérem. A kontroléry se chovají stejně jako v předchozím příkladu. Stáhnou si JSON a nastaví si ho do proměnné. O zbytek se postará AngularJS a vytvoří výsledné stránky v prohlížeči.

var app = angular.module('multipleApp', ['ngRoute']);

app.config(function ($routeProvider, $locationProvider) {
    $routeProvider.when('/', {
        controller: 'mainCtrl',
        templateUrl: '/page1.html',
    });

    $routeProvider.when('/history', {
        controller: 'historyCtrl',
        templateUrl: '/page2.html',
    });

    $routeProvider.otherwise({
        redirectTo: '/'
    });
});

app.controller('mainCtrl', ['$scope', '$http', function ($scope, $http) {

    function downloadData() {
        $http.get('data1.json')
        .then(function (response) {
            $scope.data = response.data;
        }, function (response) {
            $scope.error = response.data.error;
        });
    }

    downloadData();

}]);

app.controller('historyCtrl', ['$scope', '$http', function ($scope, $http) {

    function downloadData() {
        $http.get('data2.json')
        .then(function (response) {
            $scope.data = response.data;
        }, function (response) {
            $scope.error = response.data.error;
        });
    }

    downloadData();

}]);

data1.json

Jediné číslo s aktuální hodnotou.

{
    "temperature": 12.5
}

data2.json

Pole čísel, které představují měřenou teplotu.

{
    "history": [12, 13, 14, 13, 12, 11, 12, 13]
}

simple_http_server_angularjs2.ino

Zdrojový kód pro ESP8266. Je to HTTP server, který celý obsah dodává ze SPIFFS. Ten obsah se nachází v adresáři data a je třeba jej do SPIFFS načíst pomocí příkazu Tools / ESP8266 Sketch Data Upload. SPIFFS je popsán podrobně v samostatném článku.

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <FS.h>
#include "arduino_secret.h"

ESP8266WebServer server(80);

void setup(void) {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: http://");
  Serial.println(WiFi.localIP());

  SPIFFS.begin();

  server.serveStatic("/", SPIFFS, "/index.html");
  server.serveStatic("/favicon.png", SPIFFS, "/favicon.png");
  server.serveStatic("/multiple.js", SPIFFS, "/multiple.js");
  server.serveStatic("/data1.json", SPIFFS, "/data1.json");
  server.serveStatic("/data2.json", SPIFFS, "/data2.json");
  server.serveStatic("/page1.html", SPIFFS, "/page1.html");
  server.serveStatic("/page2.html", SPIFFS, "/page2.html");

  server.onNotFound([]() {
    server.send(404, "text/plain", "404: Not Found");
  });

  server.begin();
  Serial.println("HTTP server started");
}

void loop(void) {
  server.handleClient();
}

Zdrojový kód

Zdrojový kód se nachází na serveru GitHub.


01.12.2019


Menu