ESP8266 - HTTP server a AngularJS

Zápisník experimentátora

Hierarchy: ESP8266

Veľké množstvo príkladov pre ESP8266 používa prehliadač HTML len na zobrazenie statických stránok, ktoré vygeneroval mikrokontrolér. Takto ale fungoval Internet pred desiatimi rokmi. Dnes má v sebe každý prehliadač vysokovýkonné jadro, ktoré pomocou javascriptu dokáže premeniť statické stránky na dynamické. Musíte si uvedomiť, že v prehliadači máte k dispozícii vysoký výkon, ktorý je neporovnateľný s výkonom samotného ESP8266.

Preto si dnes ukážeme, ako tento výkon využiť a výslednú stránku z mikrokontroléra generovať až v prehliadači u užívateľa. ESP8266 bude iba dodávať podkladové údaje a výsledok sa bude zobrazovať pomocou AngularJS v prehliadači. Aby dnešný zdrojový kód nebol pre vás príliš zložitý, napísal som dva vzorové príklady, ktoré simulujú všetko pomocou súborového systému SPIFFS.

  • Jednostránková aplikácia pomocou AngularJS a Bootstrap, ktorá z ESP8266 získa zoznam gitarových efektov spolu s obrázkami a výsledok zobrazí v podobe peknej tabuľky.
  • Viacstránková aplikácia pomocou AngularJS a Bootstrap, ktorá simuluje online teplomer aj s tabuľkou historických údajov.

Naspäť do minulosti

V článku využijeme niektoré technológie, ktoré som popisoval v predchádzajúcich článkoch.

Použité súčiastky

Toto je jednoduchý projekt, preto nám bude stačiť niektorá doska s mikrokontrolérom ESP8266, ktorú je možné priamo pripojiť do USB. Aby ste sa vyhli prípadnému skratu, môžete dosku zastrčiť do breadboardu.

  • ESP8266 {linkESP8266}
  • Breadboard {linkBreadBoard}

Jednostránková aplikácia pomocou AngularJS

Na prvý príklad som si vybral niekoľko gitarových efektov od firmy Digitech. Majú zaujímavé mená (Nautila, Polara, Obscura) a majú aj tajomné obrázky na svojom povrchu. Ako výsledná HTML stránka vyzerá vidíte v nasledujúcom obrázku. Stránka sa skladá z nasledovných súborov.

  • index.html - Toto je šablóna stránky pre AngularJS. Je to normálna HTML stránka, ktorá obsahuje odkaz na AngularJS aplikáciu, ktorá zo šablóny vytvorí výslednú stránku. V šablóne sa používa niekoľko špeciálnych tagov, ktoré AngularJS aplikácia použije na to, aby podľa nich vytvorila výslednú stránku.
  • single.js - Zdrojový kód pre AngularJS aplikáciu. Celý princíp programu je v tom, že sa po inicializácii pripojí cez HTTP na ESP8266 a stiahne si odtiaľ údaje o gitarových efektoch. Tie údaje vloží medzi svoje lokálne premenné a z nich sa automaticky vygeneruje samotná stránka. V tom je ukrytá jednoduchosť použitia AngularJS.
  • data.json - Tieto údaje si stiahne AngularJS aplikácia a pomocou nich vytvorí na stránke tabuľku s popisom jednotlivých gitarových efektov a pridá k nim obrázky.
  • simple_http_server_angularjs1.ino - Zdrojový kód programu pre ESP8266. Tento typ programu sme si tu už ukázali. Je to HTTP server, ktorý celý obsah dodáva zo súborového systému SPIFFS.
  • obrázky - V súborovom systéme SPIFFS máme uložené aj obrázky. Keď bude AngularJS aplikácia vytvárať stránku, doplní do nej aj odkazy na obrázky a tie sa automaticky stiahnu zo SPIFFS.

index.html

Poďme si vysvetliť, ako sa vytvára AngularJS aplikácia pomocou tejto šablóny. Na začiatku sa toto načíta do prehliadača a aby sa AngularJS aplikácia spustila, sú potrebné tieto HTML značky. Na začiatku stránky vidíte niekoľko značiek <script>. Tie sa starajú o to, aby sme si na stránku stiahli responzívny dizajn Bootstrap a AngularJS. Posledná značka <script src="single.js"></script> načíta do prehliadača zdrojový kód programu. Na to, aby program vedel, kde má na stránke vytvoriť výslednú stránku, nám slúži značka <div ng-app="singleApp" ng-controller="singleCtrl">...</div>. Takto sme označili miesto pre aplikáciu singleApp s grafickým kontrolérom singleCtrl. Ďalšie značky obsahujú atribúty, ktoré slúžia ako príkazy pre AngularJS. Sú to napríklad atribúty ng-repeat pre vytvorenie cyklu a značky {{xxx}}, ktoré slúžia na zobrazenie obsahu premennej v programe.

<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 som v texte zatiaľ nespomenul, že AngularJS bol navrhnutý tak, aby boli programy v ňom jednoduché. Toto je celý program. Vytvorí sa aplikácia singleApp a priradí sa do premennej app. A do tejto aplikácie sa pridá kontrolér singleCtrl. Kontrolér po štarte zavolá funkciu downloadData(), ktorá si stiahne obsah súboru data.json a uloží ho do premennej $scope.data. A o viac sa nemusíte starať, pretože v šablóne sme nastavili, že data.pedals je pole, ktoré sa má postupne zobraziť a forma je určená vnorenými HTML značkami v tagu div, ktorý funguje ako 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 vyzerá vzorový JSON. Obsahuje tri objekty v poli pedals. Každý objekt má tri atribúty. Meno, popis a odkaz na obrázok.

{
    "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 pre ESP8266. Je to HTTP server, ktorý celý obsah dodáva zo SPIFFS. Ten obsah sa nachádza v adresári data a je potrebné ho do SPIFFS načítať pomocou príkazu Tools/ESP8266 Sketch Data Upload. SPIFFS je popísaný podrobne v samostatnom č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();
}

Viacstránková aplikácia pomocou AngularJS

Druhý príklad je viac komplexnejší. Tento príklad sa hodí na situácie, keď chcete v rámci jednej webstránky vybudovať rozsiahlejšiu aplikáciu. Ak v nej budete zobrazovať informácie na viacerých stránkach, musíte si vytvoriť smerovaciu tabuľku medzi URL podstránkami a jednotlivými kontrolérmi, ktoré sa postarajú o zobrazenie obsahu na každej podstránke. Ja som vymyslel nasledovnú situáciu, ktorá sa pomerne často objavuje ako príklad pre ESP8266. Je to aplikácia, ktorá meria teplotu. Používa dve stránky:

  • Temperature - Tu zobrazuje aktuálnu teplotu.
  • History - Tu zobrazuje tabuľku s historickými údajmi merania teploty.

Na vytvorenie príkladu používam opäť len statické údaje, ktoré sa nachádzajú v súborovom systéme SPIFFS, ale pre šikovnejšieho programátora nie je problém tieto údaje doplniť. Ak k nim nepatríte, tak si počkajte na niektoré z pokračovaní seriálu o ESP8266, kde vám celý príklad naprogramujem.

Stránka sa skladá z nasledovných súborov:

  • index.html - Šablóna aplikácie. Je mierne odlišná od predchádzajúcej, pretože priamo na nej nie je nastavený kontrolér. Tie sa nastavujú v špeciálnej tabuľke.
  • page1.html - Šablóna pre stránku, na ktorej je aktuálna teplota.
  • page2.html - Šablóna pre stránku, na ktorej je tabuľka historických meraní teploty.
  • multiple.js - Zdrojový kód AngularJS aplikácie. Vytvorí stránku s dvomi podstránkami. Pre každú podstránku má vlastný kontrolér, ktorý sa postará o zobrazenie údajov.
  • data1.json - Obsahuje vzorové údaje aktuálne teploty.
  • data2.json - Obsahuje vzorové údaje tabuľky historických meraní teploty.
  • simple_http_server_angularjs2.ino - Zdrojový kód programu pre ESP8266. Tento typ programu sme si tu už ukázali. Je to HTTP server, ktorý celý obsah dodáva zo súborového systému SPIFFS.

index.html

Poďme si vysvetliť, ako sa vytvára AngularJS aplikácia pomocou tejto šablóny. Na začiatku sa toto načíta do prehliadača a aby sa AngularJS aplikácia spustila, sú potrebné tieto HTML značky. Na začiatku stránky vidíte niekoľko značiek <script>. Tie sa starajú o to, aby sme si na stránku stiahli responzívny dizajn Bootstrap a AngularJS. Posledná značka <script src="multiple.js"></script> načíta do prehliadača zdrojový kód programu. Na to, aby program vedel, kde má na stránke vytvoriť výslednú stránku, nám slúži značka <div ng-app="multiple" ng-view></div>. Takto sme označili miesto pre aplikáciu multipleApp s viac stránkami. Voči predchádzajúcej šablóne tu je zmena v atribúte ng-view. Tým nastavíme, že kdesi v zdrojovom kóde aplikácie bude tabuľka, ktorá priradí pre každú URL konkrétnu šablónu 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

Šablóna pre aktuálnu teplotu. Teplota sa zobrazí pomocou premennej {{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

Šablóna pre historické merania teploty. Je to tabuľka, do ktorej sa zobrazia údaje z premennej data.history. Pretože v tej premennej je iba pole čísel, musel som doplniť parameter track by $index. Keby to bola tabuľka objektov, toto nie je 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 len mierne odlišný. Funkciou config si pridáme routovaciu tabuľku medzi URL, šablónou a kontrolérom. A kontroléry sa správajú rovnako ako v predchádzajúcom príklade. Stiahnu si JSON a nastavia si ho do premennej. O zvyšok sa postará AngularJS a vytvorí výsledné stránky v prehliadač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álnou hodnotou.

{
    "temperature": 12.5
}

data2.json

Pole čísiel, ktoré predstavujú meranú teplotu.

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

simple_http_server_angularjs2.ino

Zdrojový kód pre ESP8266. Je to HTTP server, ktorý celý obsah dodáva zo SPIFFS. Ten obsah sa nachádza v adresári data a je potrebné ho do SPIFFS načítať pomocou príkazu Tools/ESP8266 Sketch Data Upload. SPIFFS je popísaný podrobne v samostatnom č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 sa nachádza na serveri GitHub.


30.11.2019


Menu