Prof. J. Walter - Informationstechnik, Mikrocomputertechnik, Digitale Medien Softwaredoku
Hochschule Karlsruhe Logo Informationstechnik
MixHit ESP32 3
Wintersemester 2017/18
Martin Hoffmann

Patrick Suing

Software Dokumentation

Allgemein

Die Software für die Cocktailmaschine wurde in C++ im Stil der Objektorientierung geschrieben.

Es existieren drei Prozesse: Steuerung der Cocktailmaschine, Webserver und OLED-Display. Die Steuerung der Maschine läuft im Kern 1, wobei die anderen beiden Prozesse im Kern 0 laufen. Dies wir durch die Befehle :

xTaskCreatePinnedToCore(loop_1, "MixHit", 8192, NULL, 1, NULL, 1);
xTaskCreatePinnedToCore(loop_2, "WEB", 8192, NULL, 1, NULL, 0);
xTaskCreatePinnedToCore(loop_3, "OLED", 4096, NULL, 1, NULL, 0);

erreicht. Dadurch ergibt sich im Vergleich zum Vorgänger-Projekt die Möglichkeit das die Prozesse parallel ablaufen.

Ausserdem wird das SPIFFS-Dateisystem verwendet um Dateien auf den ESP32 zu schreiben. Die Inhalte der Dateien werden im Sourcecode auf den ESP32 geschrieben, womit erreicht wird, dass der Sourcecode standalone ist. Das heißt man benötigt nur die Hardware und den Sourcecode um die Steuerung zu realisieren.

Cocktailmaschine

siehe Bedienungsanleitung

Webserver

Der Webserver besteht aus einer "Main_WebServer.h" und der dazugehörigen "Main_WebServer.cpp".

Die beiden Hauptfunktionen sind "void setup_WebServer()" und "void loop_WebServer()."

In der setup_WebServer()-Funktion versucht sich der ESP32 zunächst mit einem vorhandenen WLAN-Netzwerk zu verbinden. Die Anmeldeinformationen hierfür sind in einer Textdatei auf dem SPIFSS-Dateisystem gespeichert. Scheitert die Anmeldung spannt der ESP32 ein eigenes WLAN-Netzwerk auf und fungiert als Accesspoint. Die Daten für den Accesspoint sind ebenfalls in der Textdatei enthalten. Aktuell ist kein Passwort vorhanden und die SSID lautet: "MixHit_WiFi".

Mit dem Aufruf von "server.begin()" wird ein Webserver auf Port 80 gestartet.

Bei der loop_webServer()-Funktion handelt es sich um die Hauptfunktion. Zunächst wird auf Anfragen von Clients gewartert. Ist ein Client vorhanden und verbunden wird die Anfrage des Clients ausgelesen und in einen String geschrieben. Dieser String wird an die Funktion getURL übergeben um die angefragte Seite zu parsen und diese dann als String zurückzugeben. Durch eine if / elseif-Abfrage wird dann die gewünschte Seite gefunden und eine void-Funktion aufgerufen, welche den html-code der gewünschten Website an den Client liefert. Der html-Code der einzelnen Websites wird in Strings gespeichert. Es existiert für jede Website ein String und und eine Funktion, die diesen String an den Client liefert.

Es existieren folgende Websiten: Startseite, Alkoholfreie Cocktails, Alkoholische Cocktails, MixHit Informationen, Anwender Informationen, MixHit Einstellungen, MixHit Einstellungen bearbeiten, Wifi Einstellungen, Wifi Einstellungen bearbeiten VIP freischalten, Admin freischalten, Bestellung erfolgreich.

Die Inhalte der Cocktailkarten werden aus den Objekten gNonAlcoholicList und gAlcoholicList generiert. In diesen Objekten sind die verfügbaren Cocktails gespeichert, welche von der Konfiguration der Maschine abhängig sind. Es ist möglich einen kleinen oder einen großen Cocktail zu bestellen.

Bestellt der Anwender einen Cocktail wird die Bestellung mit Namen, Größe und Priorität an die Warteschlange weitergegeben. Dazu dient der Aufruf gCocktailMixer.addOrderToQueue.

Auf den Seiten MixHit Inforamtionen und Anwender Informationen können entprechende Inforamtionen aufgerufen werden. Mit dem Aufruf gCocktailMixer.getNumberOfOrdersInQueue kann die Anzahl der Cocktails in der Warteschlange abgefragt werden. Mit dem Aufruf von gCocktailMixer.getLastServedOrderNumber kann die aktuelle Bestellnummer abgefragt werden. Die Inforamtion, welche Cocktails sich auf dem Drehteller befinden werden mit gCocktailMixer.getSlotBestellnummer und gCocktailMixer.getSlotCocktailName abgefragt. Bei den Anwender Inforamtionen wird ausserdem eine Liste erzeugt, welche die bereits bestellten Cocktails anzeigt. Diese Inforamtionen sind in User_Order_List[pUserIndex] gespeichert.

Auf den Seiten für die Einstellungen (MixHit, Wifi) werden die aktuellen Config-Files aufgelistet. Diese Files können dann über Drücken der entsprechenden Knöpfe bearbeitet, angewendet oder gelöscht werden. Wird ein Config-File bearbeitet öffnet sich eine textarea in welcher der Inhalt der ausgeählten Config-Datei angezeigt wird. Der Inhalt kann verändert werden und ein neuer Dateiname vergeben werden. Mit dem Button Speichern wird der Inhalt des Texfeldes per HTTP POST-Methode abgeschickt. Dabei wird die Seite /Einstellungen_WiFi/speichern/ oder /Einstellungen_MixHit/speichern/ aufgerufen und der Inhalt mit entsprechendem Dateinamen auf das SPIFFS-Dateisystem geschrieben (writeFile(SPIFFS, lFileName, lFileLines[0] + "\n\r")).

Des Weiteren gibt es drei verschiedene Benutzergruppen. Es gibt den Normal-Anwender, VIP-Anwender und Admin. Verbindet man sich das erste mal mit dem Server ist man ein Normal-Anwender. Durch die entsprechenden Knöpfe auf der Startseite können die VIP- oder Admin-Rechte freigeschaltet werden. Sobald der entsprechende Knopf gedrückt wird muss ein Benutzname und Passwort eingegeben werden. Der Passwortschutz wird über HTTP Basic Authentication realisiert. Ist die Eingabe erfolgreich wird dem Anwender dies mitgeteilt und die entsprechenden Rechte sind freigeschaltet. Dabei wird auch ein Flag gesetzt. Die Seiten für MixHit Einstellungen und Wifi Einstellungen können nur mit Admin-Rechten geöffnet werden. Wird eine dieser Seiten angefragt, fragt eine Schleife das entsprechende Flag ab. Ist es gesetzt wird die Seite geöffnet. Ausserdem haben Bestellungen, die it VIP- oder Admin-Rechten getätigt werden eine höhere Priorität und werden vorher von der Maschine bearbeitet.

Responsive-Design - Bootstrap

Bootstrap behinhaltet ein anpassungsfähiges Rastersystem, das bis zu zwölf Spalten über verschiedene Gerätegrößen skaliert. Für das Design des Webservers wurde das Responsive Design bootstrap gewählt. Durch das responsive-Design ist gewährleistet, dass die einzelnen Websites auf verschiedenen Endgeräten optimal dargestellt werden. Um dieses Desgin zu realisieren muss ein css-framework auf dem ESP32 vorhanden sein, welches die Design-Inforamtionen enthält. Dieses framework wird auf das SPIFFS-Filesystem des ESP32 geschrieben. In der Funktion void WriteBootstrap() wird mithilfe des Befehls writeFile(SPIFFS, "/bootstrap.min.css",INHALT DES FRAMEWORKS) der Inhalt des frameworks auf das Dateisystem geschrieben. Da das framework verhältnismäßig groß ist muss der Inahlt in ca. 400 Einzelschritten geschrieben werden.

1
2
3
4
5
6
7
void WriteBootstrap()
{     
    writeFile(SPIFFS, "/bootstrap.min.css",INHALT DES FRAMEWORKS_1);
    appendFile(SPIFFS, "/bootstrap.min.css",INHALT DES FRAMEWORKS_2);
    ..........
    appendFile(SPIFFS, "/bootstrap.min.css",INHALT DES FRAMEWORKS_ENDE);
}
 
Abb.: Sourcecode Framework schreiben

Wird nun eine Website aufgerufen wird über die Funktion getHeader() ein html-Header erzeugt, der das framework einbindet. In Zeile 29 und 33 ist ein Beispiel für die optimierte Darstellung auf dem Smartphone zu sehen. Mit dem Befehl "col-xs-12" wird der Button bei einem Smartphone über die ganze Bildschirmbreitr dargestellt. Mit dem anderen Befehl "col-lg-6" wird der Button auf Desktop-Geräten nur auf der Hälfte dargestellt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
void Print_StartPage(WiFiClient pWifiClient)
{
    ...     
    HTML_StartPage += "HTTP/1.1 200 OK\n\r";
    HTML_StartPage += "Content-type: text/html\n\r\n\r";
    HTML_StartPage += "<!DOCTYPE html><html>\n\r";
    HTML_StartPage += "<head>\n\r";
    HTML_StartPage += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";
    HTML_StartPage += "<title>MixHit - ESP32 - Webserver</title>\n\r";
    HTML_StartPage += "<link rel=\"stylesheet\" href=\"/bootstrap.min.css\">";
    HTML_StartPage += "</head>\n\r";
    HTML_StartPage += "<body>";

    HTML_StartPage += "<div class=container>";

    HTML_StartPage += "<div class=row>";
    HTML_StartPage += " <div class='col-lg-12 text-center'>";
    HTML_StartPage += " <h1>Herzlich Willkommen zum MixHit!</h1>\n\r";
    HTML_StartPage += " </div>";
    HTML_StartPage += "</div>";

    HTML_StartPage += "<div class=row>";
    HTML_StartPage += " <div class='col-lg-12 text-center'>";
    HTML_StartPage += " <h2>Cocktailkarte</h2>";
    HTML_StartPage += " </div>";
    HTML_StartPage += "</div>";

    HTML_StartPage += "<div class=row>";
    HTML_StartPage += " <div class='col-lg-6 col-xs-12 spacer-bottom'>";
    HTML_StartPage += " <a href='/Cocktailkarte_Alkoholfrei' class='btn btn-info btn-block'>Alkoholfrei</a>";
    HTML_StartPage += " </div>";
    HTML_StartPage += " <div class='col-lg-6 col-xs-12'>";
    HTML_StartPage += " <a href='/Cocktailkarte_Alkoholisch' class='btn btn-info btn-block'>Alkoholisch</a>";
    HTML_StartPage += " </div>";
    HTML_StartPage += "</div>";
    ....
    HTML_StartPage += "</div></body></html>";
    pWifiClient.println(HTML_StartPage);
    pWifiClient.stop();
}
Abb.: Ausschnitt Sourcecode Startseite

Auf den folgenden Abbildungen kann man die unterschiedliche Darstellung der Startseite sehen. Auf der ersten Abbildung sieht man die Darstellung auf einem 15,6" Zoll Laptop, auf der zweiten die auf einem 4,7" Smartphone.  Man kann die unterschiedliche Anordung der Buttons erkennen.

Abb.: Startseite Desktop
 
Abb.: Startseite Smartphone

Sobald eine Website aufgerufen wird möchte der Browser auf das framework zugreifen. Durch das oben beschriebene einbinden der /bootstrap.min.css in den <head> der jeweiligen Website ensteht ein erneuter HTTP-Request an den Server (zur Website /bootstrap.min.css).  Über die beschriebene Website-Auswahl wird der Inhalt des framework an den Client übertragen. Um die Zugriffszeiten auf die Websites zu verkürzen und den ESP32 zu entlasten wird das framework nur beim ersten Aufruf eines Clients an diesen ausgeliefert. Dies geschieht durch den Befehl "Expires: Sun, 17-Jan-2038 19:14:07 GMT".  Der Browser des Clients speichert das framework auf dem Endgerät und bezieht die Informationen für die aktuelle Sitzung dann darüber.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
else if(lURL == "/bootstrap.min.css")
{
    // this method STREAMS a file to the client
    // without the need to load the whole file in a buffer

    Serial.println("################ bootstrap #############");


    // open file from SPIFFS
    File file = SPIFFS.open("/bootstrap.min.css");
    if(!file)
    {
        Serial.println("Can not open bootstrap file");
        return;
    }
    Serial.println("Load bootstap");
    // HTTP header
    client.println("HTTP/1.1 200 OK");
    client.println("Content-type: text/css");
    client.println("Expires: Sun, 17-Jan-2038 19:14:07 GMT"); // for caching in browser, file is loaded only once
    Serial.println("Bootstrap.size() = " + String(file.size()));
    client.println("Content-Length: 120296");
    client.println();

    // reserve buffer varialbe on stack with size 100
    char buf[100] = "";

    // read as long as there is content in file
    while(file.available())
    {

        // read 99 bytes
        file.readBytes(buf, 99);

        // set 100th (array is 0-indexed!) to \0
        // \0 marks end of a string
        buf[99] = '\0';

        //send buf to client
        client.print(buf);
        //memset(buf, 0, sizeof(buf));
    }

    client.println();
    client.stop();
    Serial.println("################ bootstrap ende #############");
    file.close();
}
 
Abb.: Sourcecode Framework an den Client senden

Mit den Developer Tools von Google Chrome kann man die Verbesserung durch das Zwischenspeichern sichtbar machen. Im unteren Bereich kann man die Ladezeit von 143ms ablesen und man erhält die Information, dass die Seite bootstrap.min.css von einem Zwischenspeicher gelesen wurde.

Abb.: Chrome Developer Tools - Caching von bootstrap.min.css
Zum Vergrößern bitte auf das Bild klicken 

Um die Vollständigkeit der bootstrap.min.css zu überprüfen wurde das Linux-Kommandozeilen-Programm "cURL" eingesetzt.

Abb.: cURL - bootrstrap.min.css

Um die Datei zu überprüfen wird diese vom Server angefragt. Die URL der Datei lautet: http://192.168.4.1/bootstrap.min.css.

Mit dem Befehl "> foo.txt" wird der Inhalt der Datei in die neu erzeugte Textdatei foo.txt umgeleitet. Danach wird von foo.txt und der originalen bootstrap.min.css ein md5-Hash gebildet. Wie auf dem Bild zu sehen ist dieser Hash identisch. Damit wurde die Datei korrekt auf den ESP32 geschrieben.

Screenshots des Webservers

Abb.: Website Startseite Mixhit Desktop
 
 
Abb.: Website Startseite Mixhit Smartphone
 
 
Abb.: Website Cocktailkarte Alkoholfrei Mixhit Desktop 
 
 
Abb.: Website Cocktailkarte Alkoholfrei Mixhit Smartphone 
 
 
Abb.: Website Cocktailkarte Alkoholisch Mixhit Desktop
 
 
Abb.: Website Cocktailkarte Alkoholisch Mixhit Smartphone 
 
 
Abb.: Website Inforamtionen Mixhit Desktop
 
 
Abb.: Website Inforamtionen Mixhit Smartphone
 
 
Abb.: Website Inforamtionen Anwender Desktop
 
 
Abb.: Website Inforamtionen Anwender Smartphone
 
 
Abb.: Website Authentifizierung Desktop
 
 
Abb.: Website Authentifizierung Smartphone
 
 
Abb.: Website MixHit Konfigurationen Desktop

Programmablaufpläne

struktogramm_normalbetrieb
Abb.: Struktogramm Normalbetrieb


init_zutaten
Abb.: Struktogramm Initialisierung Zutaten


test_mode 
Abb.: Struktogramm Test Modus (Service) 


  Mit Unterstützung von Prof. J. Walter Wintersemester 2017/18