ProjektarbeitSS2020 Erstellung eines Web Portals zur Darstellung von Schwimmwettkampfergebnissen - Timo Lienemann, Tammo Post Juli 2020

Die Seite wird erstellt Simon Schröter
 
WEITER LESEN
ProjektarbeitSS2020 Erstellung eines Web Portals zur Darstellung von Schwimmwettkampfergebnissen - Timo Lienemann, Tammo Post Juli 2020
ProjektarbeitSS2020

Erstellung eines Web Portals zur Darstellung von
        Schwimmwettkampfergebnissen

             Timo Lienemann, Tammo Post
                       Juli 2020

                        Betreuer:
                 Prof. Dr.-Ing. Dirk Rabe
ProjektarbeitSS2020 Erstellung eines Web Portals zur Darstellung von Schwimmwettkampfergebnissen - Timo Lienemann, Tammo Post Juli 2020
Ergebniswebseite                                                    Timo Lienemann, Tammo Post

Erklärung zu Nutzungsrechten:
Soweit unsere Rechte berührt sind, erklären wir uns einverstanden, dass die vorliegende Arbeit
Angehörigen der Hochschule Emden/Leer für Studium / Lehre / Forschung uneingeschränkt
zugänglich gemacht werden kann.

Eidesstattliche Erklärung:
Wir, die Unterzeichnenden, erklären hiermit an Eides statt, dass wir die vorliegende Arbeit selbstständig
verfasst haben und keine anderen als die angegebenen Quellen und Hilfsmittel benutzt haben.
Alle Quellenangaben und Zitate sind richtig und vollständig wiedergegeben und in den jewei-
ligen Kapiteln und im Literaturverzeichnis wiedergegeben. Die vorliegende Arbeit wurde nicht
in dieser oder einer ähnlichen Form ganz oder in Teilen zur Erlangung eines akademischen Ab-
schlussgrades oder einer anderen Prüfungsleistung eingereicht.

Uns ist bekannt, dass falsche Angaben im Zusammenhang mit dieser Erklärung strafrechtlich
verfolgt werden können.

Emden, den . .

 Timo Lienemann                             Tammo Post

                                                 1
ProjektarbeitSS2020 Erstellung eines Web Portals zur Darstellung von Schwimmwettkampfergebnissen - Timo Lienemann, Tammo Post Juli 2020
Ergebniswebseite                                                                           Timo Lienemann, Tammo Post

Inhaltsverzeichnis
1   Einleitung                                                                                                                                          4

2   Aufgabenstellung                                                                                                                                    5
    2.1 Umsetzung der Aufgabenstellung . . . . . . . . . . . . . . . . . . . . . . . . . . . .                                                          5

3   Wahl der Programmiersprache und IDE                                                                                                                 5

4   Bestehende Komponenten                                                                                                                              7

5   Erstes Systemkonzept                                                                                                                                8
    5.1 Schwächen des ersten Systemkonzepts . . . . . . . . . . . . . . . . . . . . . . . . . .                                                        8

6   Layout der Webseite                                                                                                                                 9
    6.1 Bootstrap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .                                                14

7   Finales Systemkonzept                                                                                                                              15

8   Implementierung                                                                                                                                    15
    8.1 Erweiterungen der Kontrollrechner-Software             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   15
    8.2 AJAX . . . . . . . . . . . . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   16
    8.3 Document Object Model (DOM) . . . . . . .              .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   16
    8.4 Struktur des Systems . . . . . . . . . . . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   17
    8.5 database.php . . . . . . . . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   18
    8.6 MQTTCLient.js . . . . . . . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   19
         8.6.1 Klasse Schwimmer . . . . . . . . . . .          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   19
         8.6.2 AJAX Anfragen . . . . . . . . . . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   19
         8.6.3 MQTTCllient . . . . . . . . . . . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   20
         8.6.4 OnMessageArrived . . . . . . . . . . .          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   20
         8.6.5 getResultTime . . . . . . . . . . . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   21
         8.6.6 prepareResultTable . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   21
    8.7 Backend.js . . . . . . . . . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   22
         8.7.1 Timer . . . . . . . . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   22
         8.7.2 AJAX Anfragen . . . . . . . . . . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   23
         8.7.3 getDatabaseResults . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   23
         8.7.4 setDatabaseResults . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   24
         8.7.5 setResults . . . . . . . . . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   24
         8.7.6 emtyResultTable . . . . . . . . . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   25
    8.8 database 2 . . . . . . . . . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   25
    8.9 results.js . . . . . . . . . . . . . . . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   25
         8.9.1 get-/setRaces . . . . . . . . . . . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   25
         8.9.2 getDatabaseResults . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   26
         8.9.3 setDatabaseResults . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   27
         8.9.4 setOldResults . . . . . . . . . . . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   27
         8.9.5 emptyResultTable . . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   27
    8.10 Implementierung der Datenbank . . . . . . .           .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   27

9   Projektmanagement                                                                                                                                  28

10 Systemtests                                                                                                                                         28

11 Installation des Systems                                                                                                                            29
   11.1 Installation des Raspberry Pi‘s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .                                                  29
   11.2 Einrichtung des Apache2 Webservers . . . . . . . . . . . . . . . . . . . . . . . . . .                                                         30

12 Einrichtung und Bedienung des Webservers                                                                                                            31

13 Fazit                                                                                                                                               32

                                                      2
ProjektarbeitSS2020 Erstellung eines Web Portals zur Darstellung von Schwimmwettkampfergebnissen - Timo Lienemann, Tammo Post Juli 2020
Ergebniswebseite                                                                           Timo Lienemann, Tammo Post

14 Ausblick                                                                                                                                            32

15 Anhang                                                                                                                                              32
   15.1 Programmablaufpläne . . . . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   32
        15.1.1 Programmablaufplan result.js . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   33
        15.1.2 Programmablaufplan result.js . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   34
        15.1.3 Programmablaufplan Backend.js       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   35

16 Abbildungsverzeichnis                                                                                                                               36

17 Literaturverzeichnis                                                                                                                                36

                                               3
ProjektarbeitSS2020 Erstellung eines Web Portals zur Darstellung von Schwimmwettkampfergebnissen - Timo Lienemann, Tammo Post Juli 2020
Ergebniswebseite                                                  Timo Lienemann, Tammo Post

1    Einleitung
Diese Dokumentation bezieht sich auf die Erstellung einer Webseite zur Darstellung von Ergeb-
nissen eines Schwimmwettkampfs im Sommersemester 2020. Die Ergebniswebseite ergänzt die
bereits bestehenden Komponenten des Systems zur Erfassung und Auswertung von Schwimm-
wettkämpfen [7]. Da in dieser Dokumentation einige Komponenten des gesamten Systems ver-
wendet werden, werden diese jeweils an entsprechender Stelle kurz erläutert. Weitere Details
sind den Dokumentationen zu den entsprechenden Projektarbeiten zu entnehmen:
    • Dokumentation der Projektgruppe WS18/19 (Erstellung des Systems)[2]
    • Projektarbeit Marc Pollmann (Großdisplay)[3]
    • Dokumentation der Projektguppe im WS19/20 (Erweiterung des Systems)[7]

Folgende Liste liefert einen Überblick über die Inhalte der kommenden Kapitel:
    • 2. Aufgabenstellung
    • 3. Wahl der Programmiersprache und Entwicklungsumgebung

    • 4. Bestehende Komponenten: Erläuterungen zu den bestehenden Komponenten, um einen
      Überblick über das bisherige Gesamtsystem zu bekommen und die Webseite in den Kontext
      einordnen zu können.
    • 5. Erstes Systemkonzept: Das erste Systemkonzept wird erläutert, und es wird dargestellt,
      weshalb dieses noch einmal grundlegend überarbeitet werden musste (siehe Kapitel 7).

    • 6. Layout der Website: Hier wird auf das Layout eingegangen und seine Funktionalität
      erklärt.
    • 7. Finales Systemkonzept: Das Finale Systemkonzept wird erläutert.
    • 8. Implementierung: Erläuterungen zur Funktionsweise des Backends der Webseite

    • 9. Projektmanagement: Ablauf des Projektmanagements
    • 10. Systemtest: Beschreibung der durchgeführten Tests
    • 11. Installation des Systeme: Beschreibung der Installation des Webservers

    • 12. Einrichtung und Bedienung des Webservers: Hier wird der Raspberry Pi als Webserver
      eingerichtet.
    • 12. Fazit Zusammenfassung des Projektverlaufs,
    • 13. Ausblick: Ausblick auf mögliche Verbesserungen und Erweiterungen

                                                4
ProjektarbeitSS2020 Erstellung eines Web Portals zur Darstellung von Schwimmwettkampfergebnissen - Timo Lienemann, Tammo Post Juli 2020
Ergebniswebseite                                                   Timo Lienemann, Tammo Post

2      Aufgabenstellung
Zu Beginn der Projektarbeit wurden die Ziele vereinbart, die erreicht werden sollten. Konkret
handelt es sich dabei um folgende funktionale Anforderungen:
    • Live-Darstellung von Läufen: Die Daten des jeweils aktuelle Laufs (Wettkampfnummer,
      Laufnummer, Namen und Zwischenzeiten der Schwimmer) werden auf der Webseite dar-
      gestellt. Dabei soll es möglich sein, bis zu acht Bahnen anzeigen zu können.
    • Aufbereitete Darstellung der Zeitnehmerergebnisse: Übermittelte Zeitstempel der Zeitneh-
      mer,in Relation zur aktuellen Zeit umwandeln, um die Zwischenzeit zu berechnen und die-
      se dann in einem lesbaren Format auf der Webseite darzustellen.
    • Optional: Wettkampfergebnisse nach der Auswertung anzeigen
    • Alle bereits abgeschlossenen Läufe können mit allen verfügbaren Zwischenzeiten erneut
      angesehen werden (Historie)
    • Livestream oder Videoaufzeichnung der Wettkämpfe
    • Anzeige von organisatorischen Hinweisen: Wichtige Nachrichten, wie den Start des Events
      oder die Ankündigung einer Pause, sollen an die Nutzer der Webseite weiterzugeben wer-
      den. Dazu muss die Kontrollrechner-Software um eine Eingabemöglichkeit erweitert wer-
      den.
    • Installation zusätzlicher Software: Um eine hohe Akzeptanz der Nutzer zu erreichen, soll
      nach Möglichkeit keine zusätzliche Software auf den Endgeräten installiert werden müssen.
    • Sicherheit und Stabilität des bestehenden Systems: Das bestehende System soll durch die
      Erweiterungen dieser Projektarbeit nicht in seiner Sicherheit und Stabilität eingeschränkt
      werden.

2.1     Umsetzung der Aufgabenstellung
Um die zuvor genannte Aufgabenstellung umzusetzen, gibt es grundsätzlich zwei Möglichkeiten:
      • 1. Entwicklung einer Smartphone-App (Android/IOS)
      • 2. Erstellung einer dynamischen Webseite
Die Entscheidung, eine Webseite anstatt einer App zu entwickeln, hatte dabei mehrere Gründe.
Eine App hat die Nachteile, dass sie nur unter bestimmten Plattformen bzw. mit bestimmten
Geräten genutzt werden kann, außerdem müssten interessierte Personen diese App vor dem
Schwimmwettkampf herunterladen, um sie nutzen zu können. Eine Webseite hingegen weist in
der Regel keine Abhängigkeiten zum Betriebssystem auf und kann ohne vorherigen Download
mit jedem aktuellem Internetbrowser aufgerufen werden.

3      Wahl der Programmiersprache und IDE
Bei der Wahl der Programmiersprachen gibt es für Webseiten im wesentlichen zwei Möglichkeiten:
JavaScript oder PHP. Im folgenden Abschnitt möchten wir daher zunächst die Vor- und Nachteile
der jeweiligen Sprache für den Einsatz in unserem System erläutern, um damit die Auswahl zu
begründen.

PHP wird serverseitig ausgeführt. Die Webseite schickt eine Anfrage an den Server, die Berech-
nungen werden durchgeführt und das Ergebnis wird an die Webseite zurückgesendet. Außerdem
werden Datenbankzugriffe unterstützt, was für die Historie der Läufe relevant ist.

JavaScript hingegen wird clientseitig ausgeführt. Das bedeutet, dass flexibel auf Benutzereinga-
ben oder externe Ereignisse reagiert werden kann, ohne dass eine erneute Anfrage an den Server
gesendet werden muss (Neuladen der Webseite bei Änderung nicht notwendig). Der Zugriff auf
Datenbanken wird von JavaScript nicht direkt unterstützt, es gibt jedoch die Möglichkeit, durch

                                                   5
ProjektarbeitSS2020 Erstellung eines Web Portals zur Darstellung von Schwimmwettkampfergebnissen - Timo Lienemann, Tammo Post Juli 2020
Ergebniswebseite                                               Timo Lienemann, Tammo Post

AJAX (siehe Abschnitt 8.1) auf ein PHP Script zuzugreifen und dadurch den Datenbankzugriff
zu ermöglichen.

Aus den genannten Gründen wurde sich daher für die beschriebene Aufgabenstellung zunächst
gegen eine reine PHP Implementierung entschieden, da im Laufe eines Events immer wieder
neue Wettkämpfe und Ergebnisse eintreffen. Somit soll überwiegend JavaScript in Kombination
mit PHP verwendet werden.

Als Entwicklungsumgebung wurde Apache NetBeans verwendet, da bereits positive Erfahrun-
gen damit gemacht wurden. Zudem eignet sich diese IDE aufgrund ihrer Unterstützung von
PHP und JavaScript in Kombination mit HTML sehr gut für das Projekt. Im folgenden Kapitel
wird zunächst auf die bereits vorhandenen Komponenten des Gesamtsystems zur Erfassung und
Auswertung von Schwimmwettkämpfen eingegangen, um die Einbindung der Ergebniswebseite
zu veranschaulichen, danach wird das erste Systemkonzept vorgestellt.

                                             6
ProjektarbeitSS2020 Erstellung eines Web Portals zur Darstellung von Schwimmwettkampfergebnissen - Timo Lienemann, Tammo Post Juli 2020
Ergebniswebseite                                                   Timo Lienemann, Tammo Post

4    Bestehende Komponenten

             Abbildung 1: Bisherige Komponenten des Systems + Ergebniswebseite

Da sich diese Projektarbeit in ein bestehendes System einfügen soll, werden die bereits vorhan-
denen Komponenten kurz erklärt:
    • Kontrollrechner: Der Kontrollrechner ist die zentrale Komponente des Systems. An dieser
      Stelle läuft die gesamte Kommunikation zusammen. Er sendet die Wettkampfdaten zur Dar-
      stellung an ein optionales Großdisplay, sowie zur weiteren Verwendung an die Zielrichter.
      Zusätzlich werden die Daten natürlich auch an den Webserver der Ergebniswebseite ge-
      sendet. Startet ein Lauf, wird zuerst das Startsignal an den Kontrollrechner übermittelt. Im
      Anschluss folgen dann die gemessenen Zwischenzeiten der Zeitnehmer und am Ende die
      Ergebnisse der Zielrichter. All diese Daten werden an den Auswerter-PC zur Verarbeitung
      weitergeleitet.
    • Auswerter-PC: Der Auswerter-PC ist für die Verarbeitung bzw. Auswertung der Ergebnis-
      se des Laufs zuständig. Falls nötig, können Zeiten und Platzierungen angepasst werden.
      Die fertigen Daten werden dann wieder an die Wettkampfverwaltungssoftware EasyWK
      gesendet.
    • Zeitnehmer: Die Zeitnehmer erfassen die Zwischen- und Endzeiten der Schwimmer als
      Zeitstempel. Hierbei ist es wichtig, dass der Startsignalgeber und alle Uhren synchron lau-
      fen. Dazu bekommen sie die Referenzzeit bekommen via PTP vom Zeitserver. Pro Bahn
      werden zwei Zeitnehmer verwendet, um ein wechselndes Zeitgericht und zwei Läufe auf
      einer Bahn zu unterstützen.
    • Zielrichter: Die Zielrichter erfassen die Reihenfolge, in der die Schwimmer im Ziel eintref-
      fen. Für die Erfassung und Übermittlung der Zieleinläufe ist die Zielrichter-App auf den
      Smartphones installiert. Bei Unstimmigkeiten kann die Reihenfolge aber auch noch manu-
      ell am Auswerter-PC verändert werden.
    • Großdisplay: Das Großdisplay dient zur Live-Darstellung der Ergebnisse im Schwimmbad.
      Es empfängt das Startsignal sowie alle Zwischenzeiten vom Kontrollrechner.
    • Access-Point: Der Access-Point ermöglicht die Übertragung der MQTT Nachrichten.
    • Zeitserver: Der Zeitserver synchronisiert sich mittels NTP mit dem Kontrollrechner und
      verteilt die einheitliche Zeit dann an alle Zeitnehmer sowie den Startsignalgeber via PTP.

                                                 7
ProjektarbeitSS2020 Erstellung eines Web Portals zur Darstellung von Schwimmwettkampfergebnissen - Timo Lienemann, Tammo Post Juli 2020
Ergebniswebseite                                                   Timo Lienemann, Tammo Post

Im gelb markierten Teil der Abbildung 1 befindet sich das neu entwickelte Teilsystem, welches
grundsätzlich folgenden Aufbau und Funktion hat:
      • Webserver: Als Webserver wird ein Raspberry Pi verwendet. Der Server stellt die Webseite
        zur Verfügung und sorgt so dafür, dass alle Nutzer mit den entsprechenden Wettkampfda-
        ten versorgt werden. Nähere Details zur inneren Struktur des Systems finden sich in den
        folgenden Abschnitten.
      • Geräte der Anwender: Um die Webseite aufrufen zu können, wird grundsätzlich ein inter-
        netfähiges Endgerät wie ein Smartphone, Tablet, Notebook, oder Desktop-PC benötigt. Das
        Betriebssystem spielt dabei keine Rolle. Da die Webseite voraussichtlich überwiegend von
        mobilen Geräten aufgerufen wird, spielt die entsprechende Anpassung des Layouts eine
        wichtige Rolle; mehr dazu in Kapitel 6. Die Daten werden über den lokalen Access-Point an
        die Anwender gesendet.

5      Erstes Systemkonzept
Für das erste Systemkonzept wurden zunächst die vorhandenen Komponenten analysiert. Die
Webseite soll sich ohne größere Veränderungen in das Gesamtsystem einfügen. Da die gesam-
te Kommunikation des Systems über MQTT abläuft, sollte auch die Webseite Nachrichten über
MQTT empfangen. Zusammenfassend ergibt sich dadurch folgendes Schema:

                                Abbildung 2: Erstes Systemkonzept

Wie in Abbildung 2 dargestellt ist, empfangen die Geräte, mit denen die Webseite aufgerufen wur-
de, die Nachrichten direkt vom Kontrollrechner. Verantwortlich dafür ist der MQTT Client, der
aufgrund von JavaScript auf jedem Gerät ausgeführt wird. Um die Wettkampfdaten zu speichern,
werden diese dann weiter an den Webserver gesendet, welcher auf die Datenbank zugreifen kann.
Als Webserver soll ein Raspberry Pi verwendet werden, da dieser durch den kompakten Form-
faktor portabel ist, aber dennoch alle benötigten Funktionen, wie einen Internetzugang oder die
Möglichkeit, ein Display anzuschließen, bietet. Der Webserver stellt die Ergebniswebseite bereit
und ist mit der Datenbank verbunden. Alle Anfragen für bereits beendete Läufe werden an den
Webserver weitergeleitet und dann dort ausgeführt. Mittels AJAX leitet der Server das Ergebnis
dann zurück an den Client.

5.1     Schwächen des ersten Systemkonzepts
Beim Testen der Software waren zunächst keine Probleme festzustellen, da zu jedem Zeitpunkt
nur ein Gerät mit dem Server verbunden war. Erst als weitere Geräte auf die Webseite zugreifen
wollten, konnten zwei schwerwiegende Probleme festgestellt werden:

                                                 8
ProjektarbeitSS2020 Erstellung eines Web Portals zur Darstellung von Schwimmwettkampfergebnissen - Timo Lienemann, Tammo Post Juli 2020
Ergebniswebseite                                                   Timo Lienemann, Tammo Post

    • 1. Problem: Im Code des MQTT Clients wurde an einer zentralen Stelle versucht, eine MQTT
      Verbindung aufzubauen. Wenn nun mehrere Geräten den Java Code ausführen, wird jedes
      mal versucht, einen MQTT Client mit dem selben Namen zu erstellen. Dies führte zu Ver-
      bindungsabbrüchen , da der Broker nicht zwischen den Clients unterscheiden konnte.
    • 2. Problem: Um Wettkampfinformationen oder Ergebnisse der Zeitnehmer in der Daten-
      bank zu speichern, wird bei eintreffenden Nachrichten eine AJAX Anfrage an ein PHP Script
      gesendet. Wenn jetzt mehrere Geräte mit dem MQTT Broker verbunden sind, werden auch
      entsprechend häufig die Funktionen für den Datenbankzugriff aufgerufen. Dies sorgt dafür,
      dass die Datenbank schnell mit vielen redundanten Datensätzen gefüllt wird (ca. 2000-3000
      Datensätze in 30s).
Um die vorhandenen Probleme zu beheben, war es erforderlich, das Systemkonzept anzupassen.
Auf die Veränderungen wird in Kapitel 7 näher eingegangen. Zunächst wird jedoch im folgendem
Abschnitt das Layout der Webseite beschrieben.

6    Layout der Webseite
Die erste Konzeptzeichnung des Layouts wurde relativ zügig nach dem Projektstart erstellt, so-
dass ersichtlich wird, welche Funktionalität die Website haben soll. Hierbei ging es darum, eine
einfache Übersicht zu bekommen, die genaue Anzahl der Schwimmer steht nicht fest und dient
nur als Beispiel, wie die Bahnen angezeigt werden könnten.

                                   Abbildung 3: Erstes Layout

Nach dem ersten Konzept wurde überlegt, auf welchen Endgeräten die Website aufgerufen wer-
den soll und wie sich diese am besten darstellen lässt.

                                                9
Ergebniswebseite                                                  Timo Lienemann, Tammo Post

Nach einiger Recherche ergab sich Bootstrap als sinnvolle Web Bibliothek, da hier flexible GUI-
Komponenten existieren, die sich den verschiedenen Displaygrößen entsprechend anpassen. Dies
ist wichtig, da im Anwendungsbereich des Schwimmwettkampfes die meisten Benutzer ein Smart-
phone verwenden.
Das Layout wurde nun ähnlich der Konzeptzeichnung erstellt und angepasst, bis dieses auf
Smartphones, Laptops und Tablets gut zu lesen und zu bedienen war. Die Anzahl der Bahnen
ist dabei erst einmal auf 8 festgelegt, leere Bahnen sind automatisch Platzhalter und werden nicht
genutzt. Da der Hauptanwendungsbereich auf dem Smartphone ist, war die Priorität der Bedien-
barkeit hier am höchsten.

                        Abbildung 4: Umsetzung auf dem Smartphone

Das Menü ist auf dem Smartphone eingeklappt und kann rechts oben geöffnet werden. Darunter
sind die Wettkampf-, Laufnummer und die geschwommene Disziplin zu sehen. Im Bereich Zeit
                                                                                          ”
“ wird die live Zeit des aktuellen Laufes ausgegeben. Anschließend folgt eine Auflistung der je-
weiligen Teilnehmer, wobei die letzten aufgenommen Zwischenzeiten dargestellt werden. Durch
Tippen auf die Zeit wird jeweils ein Menü geöffnet, in dem alle Zwischenzeiten des jeweiligen
Teilnehmers zu erkennen sind. Nicht besetzte Bahnen werden dementsprechend gekennzeichnet.
Die Namen wurden geschwärzt.

                                               10
Ergebniswebseite                                                  Timo Lienemann, Tammo Post

                           Abbildung 5: Menü auf dem Smartphone

Durch Öffnen des Menüs kann zwischen den verschiedenen Websites gewechselt werden. Da-
bei gibt es die live Ansicht, die Ergebnisse der vergangenen Läufe sowie eine Kontaktseite. Bei
geöffnetem Menü ist die live Ansicht jedoch weiterhin verfügbar und wird nicht durch das Menü
verdeckt.

                                               11
Ergebniswebseite                                                Timo Lienemann, Tammo Post

                        Abbildung 6: Ergebnisse auf dem Smartphone

Die Ergebnisseite ist ähnlich wie die live Ansicht gestaltet, um so dem Nutzer die Bedienung
zu erleichtern. In dem oben dargestellten Dropdown-Menü können alle bisherigen Wettkämpfe
aufrufen werden, um so die Ergebnisse und Zwischenzeiten der Teilnehmer anzeigen zu lassen.
Dieses funktioniert wie auch auf der live Ansicht durch Tippen auf die jeweilige Endzeit hinter
dem Namen des Teilnehmers.

                                              12
Ergebniswebseite                                                    Timo Lienemann, Tammo Post

                           Abbildung 7: Kontakt auf dem Smartphone

Die Kontaktseite wurde schlicht gehalten. Hier sind die nötigen Informationen und die Infos zu
Bootstrap gelistet.

                                      Abbildung 8: Startseite

Zuletzt wurde eine Startseite erstellt, auf die alle Nutzer zuerst gelangen. So erhält der Anwender
einen Überblick, um welche Website es sich handelt.

                                                13
Ergebniswebseite                                                  Timo Lienemann, Tammo Post

                                 Abbildung 9: Desktop Version

Wie in Abbildung 9 zu sehen, liegt bei der Desktop-Version der wesentliche Unterschied darin,
dass die Menüleiste ausgefüllt zu sehen ist und nicht durch ein Dropdown Menü geöffnet werden
muss. Bei Verkleinerung des Fensters wird aus der Menüleiste wieder ein Menü, damit sich dieses
nicht nach unten vergrößert und weiterhin alles zu lesen ist.

6.1   Bootstrap
Bootstrap ist ein frei verwendbares Frontend-CSS-Framework. Das bedeutet, dass hier Vorlagen
für die grafische Zusammenstellung einer Website in HTML und CSS vorliegen. Mithilfe eines sol-
chen Frontend-Frameworks können viele Oberflächengestaltungselemente genutzt werden, ohne
diese selbst entwerfen zu müssen. Bootstrap bietet außerdem optionale Javascrpit-Erweiterungen
an, welche verwendet werden können.

                    Abbildung 10: Beispielcode für eine Button in bootstrap

In Abbildung 10 ist zu sehen, wie Bootstrap genutzt werden kann. Es gibt hier z.B. vorgefertigte

                                               14
Ergebniswebseite                                                 Timo Lienemann, Tammo Post

Buttons, welche je nach Gebrauch in die Website integriert werden können. Das genutzte Image
für den Button kann anschließend noch anpasst werden, auch hierfür hat Bootstrap einige Icons,
um den Aufwand für ein eigenes Design zu reduzieren.

7     Finales Systemkonzept

                            Abbildung 11: Zweites Systemkonzept

Das zweite, und somit finale Systemkonzept, soll die Probleme des ersten Systemkonzepts be-
heben. Dafür wurde eine neue PHP Seite hinzugefügt, die von allen Geräten aufgerufen wer-
den kann. Der MQTT Client wird nur noch auf dem Raspberry Pi ausgeführt, um mehrfaches
Einfügen in die Datenbank zu verhindern. Sobald neue Daten empfangen werden, werden diese
in der Datenbank gespeichert. Die Webseite, die vom Anwender aufgerufen wird, lädt dann alle
nötigen Informationen aus der Datenbank, und der verwendete JavaScript Code ermöglicht die
Ausgabe der laufenden Zeit, sowie das Auslesen der Wettkampfdaten aus der Datenbank mittels
AJAX Anfragen. Positiver Nebeneffekt ist, dass die Belastung für den MQTT Broker (Kontroll-
rechner) gering bleibt, da nur ein einziger zusätzlicher Client verbunden wird.

Das Layout der ursprünglichen start.html Seite konnte mit leichten Anpassungen auch für die
neue start.php Seite genutzt werden.

8     Implementierung
8.1   Erweiterungen der Kontrollrechner-Software
Um auf der Webseite organisatorische Hinweise anzeigen zu können, musste die Software des
Kontrollrechners leicht erweitert werden. Für die Eingabe der Nachrichten wurden ein Eingabe-
feld sowie ein Button zum Absenden der Nachrichten implementiert. Durch die Platzierung auf
der Einstellungsseite des Kontrollrechners ist es möglich, sowohl vor dem Start des Events eine
Nachricht abzusenden als auch währenddessen.

         Abbildung 12: neue GUI Elemente in den Einstellungen des Kontrollrechners

                                              15
Ergebniswebseite                                                        Timo Lienemann, Tammo Post

Um die Übertragung zu ermöglichen, wurde das neue MQTT topic event/webApp/settings erstellt.

8.2     AJAX
AJAX steht für Asynchronous JavaScript And XML. Es handelt sich dabei nicht um eine ei-
genständige Programmiersprache[1] , sondern eine Erweiterung, die in Kombination mit JavaS-
cript genutzt wird. AJAX ermöglicht es, Daten aus einer Datenbank nachzuladen, ohne dass die
Webseite selbst neu geladen werden muss. Dieser Mechanismus ist wichtig, da reines JavaScript
keine Datenbank-Zugriffe ausführen kann, und reines PHP ein Neuladen der Seite erfordern
würde.

AJAX bietet zusammenfassend also folgende Vorteile gegenüber PHP:

      • Inhalt einer Webseite lässt sich ohne Neuladen aktualisieren
      • Daten können von einem Server angefragt und empfangen werden, nachdem die Seite ge-
        laden wurde
      • Daten können im Hintergrund zum Server gesendet werden

In unserem Fall werden AJAX -Aufrufe sowohl in der Datei MQTTClient.js zum Speichern der
Daten in der Datenbank, als auch in der Datei Backend.js zum Auslesen der Daten genutzt.
Folgende Abbildung veranschaulicht das Schema der Kommunikation:

                                Abbildung 13: AJAX Kommunikation

Wie in der Abbildung 13 zu sehen ist, ruft der Nutzer der Webseite die Hauptdatei des Systems
(start.php) auf. Diese Seite wird durch die JavaScript Backend.js mit den aktuellen Informatio-
nen aus der Datenbank versorgt. Dazu wird in regelmäßigen Abständen eine AJAX Anfrage an
die Datenbank gesendet. Diese wird von dem PHP Script database 2.php bearbeitet, in dem die
übergebenen Parameter genutzt werden, um die passende Datenbankabfrage auszulösen. Das Er-
gebnis der Abfrage gelangt dann wieder über database 2.php an die Datei Backend.js. Dort liegt
die Antwort aus der Datenbank als Zeichenkette vor und kann nach entsprechender Verarbeitung
genutzt werden, um die Felder der start.php Seite mittels DOM (Erklärung siehe Abschnitt 8.3)
zu verändern.

8.3     Document Object Model (DOM)
Das DOM (Document Object Model) ist die Schnittstelle zwischen HTML und dynamischem Ja-
vaScript [4]. Alle Elemente der HTML Seite werden zu Objekten, die dann dynamisch aufgerufen,
verändert, hinzugefügt oder gelöscht werden können.

                                                  16
Ergebniswebseite                                                 Timo Lienemann, Tammo Post

    Wenn eine Webseite vom Browser aufgerufen wird, liegt diese in HTML Textform vor. Bereits
    während des Ladevorgangs der Seite werden die Elemente analysiert und es baut sich ein Baum
    der Elemente im Hauptspeicher auf.

                        Abbildung 14: Baumstruktur der Objekte einer Webseite

    Wie in der Abbildung 14 zu sehen ist, besteht der DOM Baum aus mehreren Ebenen. Je weiter
    sich ein Objekt von der Wurzel entfernt befindet, desto tiefer ist es in Kombination mit anderen
    Elementen verschachtelt.

    Um jetzt auf ein einzelnes Objekt zuzugreifen, kann es per Namen (muss nicht eindeutig sein)
    oder per ID angesprochen werden. Da die Auswahl über eine ID weniger fehleranfällig ist, wurde
    diese Variante favorisiert. Dies soll durch folgenden Code-Ausschnitt aus der Datei Backend.js
    verdeutlicht werden:
1                    document.getElementById("contestID").innerHTML = "W" + content[0] + " L"
                          + content[1];

    Um das entsprechende Element auf der HTML Seite anzusprechen, wird die Funktion getElement-
    ById verwendet. Über das Attribut innerHTML kann dann der Text direkt verändert werden. In
    dem abgebildeten Ausschnitt werden so die ContestID und RaceID auf der Webseite dargestellt.

    8.4   Struktur des Systems
    Die Ergbnisswebseite besteht im wesentlichen aus 2 Komponenten:

    MQTT Client

    Der MQTT Clint ist die Schnittstelle zwischen Kontrollrechner und Datenbank. Die folgenden
    Dokumente werden nur auf dem Server aufgerufen, daher bleibt die Kommunikation für den
    Nutzer verborgen.
       • start.html: Diese HTML Datei muss aufgerufen werden, um die MQTT Nachrichten des
         Kontrollrechners empfangen zu können.

                                                  17
Ergebniswebseite                                                   Timo Lienemann, Tammo Post

        • MQTTClient.js: Diese JavaScript Datei beinhaltet den eigentlichen MQTT Client und sorgt
          dafür, dass eintreffende Nachrichten verarbeitet und dann mittels AJAX an das PHP Scipt
          für die Datenbankzugriffe gesendet werden.

        • database.php: Dieses PHP Script führt die Datenbankzugriffe durch.
     Ergebniswebseite

     Dieser Teil der Anwendung ist für alle Benutzer der Webseite sichtbar. Die Dateien start.php und
     database 2.php befinden sich auf dem Server und werden dort vom Benutzer aufgerufen. Die Da-
     tei Backend.js wird von jedem Gerät selbst ausgeführt, auf dem die Webseite aufgerufen wird. Zu-
     sammenfassend bilden diese Dateien somit die Schnittstelle zwischen Datenbank und Zuschauer.

        • start.php: Beinhaltet die Struktur und das Layout der Webseite
        • Backend.js: Sorgt dafür, dass in regelmäßigen Abständen die aktuellen Wettkampfdaten
          aus der Datenbank geholt werden (durch AJAX Anfragen)
        • database 2.php: Führt die eingehenden AJAX Anfragen aus und liefert die Werte an die
          JavaScript Datei Backend.js zurück.
        • tabellen.php: Diese Datei ermöglicht den Zugriff auf vergangene Läufe.
        • result.js: In dieser Datei wurden Funktionen implementiert, die die Wettkampfdaten des
          ausgewählten Laufs auf der Seite tabellen.php darstellen.

     Da in dieser Dokumentation nicht der gesamte Quellcode mit allen Details erläutert werden kann,
     werden in den folgenden Unterkapiteln vorrangig die wesentlichen Funktionen beschrieben. Um
     dennoch die gesamte Implementierung nachvollziehen zu können, wurden einige Kommentare
     im Code ergänzt. Zusätzlich befinden sich Programmablaufpläne zu den JavaScript Dateien im
     Anhang 15.1.

     8.5   database.php
     Wie bereits im vorherigen Kapitel erwähnt, führt dieses PHP Script sämtlicher Datenbankzugriffe
     der MQTTClients.js durch. Da der MQTTClient nur schreibend auf die Datenbank zugreift, wur-
     den entsprechende Funktionen implementiert. Das Einfügen der Daten in die Datenbank läuft in
     allen Funktionen sehr ähnlich ab und unterscheidet sich nur anhand der übergebenen Parameter.
     Daher soll die Vorgehensweise exemplarisch an der Funktion insertRace erläutert werden:
 1   // Daten empfangen
 2
 3   $ContestID = filter_input(INPUT_POST, "ContestID");
 4   $RaceID = filter_input(INPUT_POST, "RaceID");
 5   $ContestName = filter_input(INPUT_POST, "ContestName");
 6   $StartTimestamp = filter_input(INPUT_POST, "StartTimestamp");
 7   $Name = filter_input(INPUT_POST, "Name");
 8   $Result = filter_input(INPUT_POST, "Result");
 9   $function = filter_input(INPUT_POST, "function");
10   $BahnNummer = filter_input(INPUT_POST, "BahnNummer");
11   $twoRaces=filter_input(INPUT_POST, "twoRaces");
12   $Message=filter_input(INPUT_POST, "Message");

     Wie in dem Code-Ausschnitt zu sehen ist, werden zunächst die übergebenen Parameter aus-
     gelesen. Dazu wird die Funktion filter input verwendet, da nicht immer dieselben Parameter
     übergeben werden. Es muss also nicht die Existenz jeder Variablen geprüft werden, sondern alle
     vorhandenen Werte werden zugewiesen. Zusammenfassend wird der Code so kompakter und es
     können Fehler vermieden werden [5].

     Durch den übergebenen Parameter function kann dann entschieden werden, welche Funktion
     aufgerufen wird. Diese Auswahl ist in folgendem Ausschnitt aus dem Code zu sehen:

                                                    18
Ergebniswebseite                                                    Timo Lienemann, Tammo Post

1    //Auswahl der Funktion anhand des übergebenen Parameters fuction
2
3    switch ($function) {
4        case "insertRace": insertRace($ContestID, $RaceID, $ContestName, $StartTimestamp,
             $twoRaces);
 5           break;
 6       case "insertResult": insertResult($BahnNummer, $ContestID, $RaceID, $Name, $Result);
 7           break;
 8       case "insertName": insertName($BahnNummer,$ContestID, $RaceID, $Name);
 9           break;
10       case "insertMessage": insertMessage($Message);
11           break;
12       default: break;
13   }

     Die eigentliche Funktion insertRace stellt dann zuerst die Verbindung zur Datenbank her. Danach
     wird der SQL-Ausdruck definiert und die Werte werden durch Ausführung der Abfrage in die
     Tabelle wettkampf eingefügt. Um Fehler oder Angriffe auf die Datenbank zu vermeiden, wird die
     Verbindung am Ende der Funktion wieder geschlossen.
1    //Lauf in die Tabelle wettkampf einfügen
2    function insertRace($ContestID, $RaceID, $ContestName, $StartTimestamp,$twoRaces) {
3
4          $db = mysqli_connect("localhost", "root", "", "schwimmwettkampf");
5          $querry = "INSERT INTO wettkampf (Contest_ID, Race_ID, Contest_Name, StartTimestamp,
                twoRaces) VALUES (’$ContestID’, ’$RaceID’, ’$ContestName’, ’$StartTimestamp’, ’
               $twoRaces’)";
6          mysqli_query($db, $querry);
7          mysqli_close($db);
8    }

     8.6     MQTTCLient.js
     In dieser Datei werden der MQTT Client, Funktionen zur Formatierung der empfangenen Daten
     und AJAX Anfragen zum Einfügen der Werte in die Datenbank definiert.

     8.6.1   Klasse Schwimmer
     Im Code wurde zunächst die Klasse Swimmer definiert. Jedes Swimmer-Objekt beinhaltet einen
     Namen, ein Array, welches beliebig viele Ergebnisse aufnehmen kann, den Wert der vorherigen
     Zwischenzeit sowie einen boolean Wert, der angibt, ob es sich um eine neue Zwischenzeit handelt.
     Die Funktion addResult prüft, ob es sich um ein neues Ergebnis handelt und fügt es in das Array
     der Ergebnisse ein. Diese Funktionalität wird anhand des folgendem Codeausschnitts deutlich:
1             this.addResult = function (result) {
2                 this.resultChanged = false;
3                 //prüfen, ob es sich um neues Ergebis handelt
4                 if (result !== this.previousResult) {
5                     this.results.push(result);
6                     this.previousResult = result;
7                     //resultChanged auf true setzen --> Verwendug in setResults
8                     this.resultChanged = true;

     Der Wert von resultChanged wird zunächst auf false gesetzt. Da der Kontrollrechner immer für
     jeden Schwimmer das letzte vorhandene Ergebnis sendet, ist eine Abfrage, ob es sich um ein
     neues Ergebnis handelt, notwendig. Durch die Abfrage wird geprüft, ob sich die eingetroffene
     Zwischenzeit von der vorherigen unterscheidet. Wenn dies der Fall ist, wird die neue Zwischen-
     zeit dem Schwimmer zugeordnet und previousResult wird für folgende Zwischenzeiten angepasst.
     Zusätzlich wird das Attribut resultChanged auf true gesetzt. Dieser Wert wird später benötigt, um
     zu entscheiden, ob die Zeit in die Datenbank eingefügt werden soll oder nicht. Neben dieser zen-
     tralen Funktion beinhaltet die Klasse auch noch die Funktionen getName(), isresultChanged und
     getResults, um die Attribute des Schwimmers bei Bedarf auslesen zu können.

     8.6.2   AJAX Anfragen
     Die AJAX Anfragen werden benötigt, um die Daten an das database.php Script zu übertragen.
     Insgesamt wurden vier dieser Anfragen definiert, die sich nur in der Art und Anzahl der übergebenen

                                                     19
Ergebniswebseite                                                    Timo Lienemann, Tammo Post

    Parameter unterscheiden. Da sich der Aufbau der Anfragen kaum zu denen aus der Datei Backend.js
    (siehe Kapitel 8.7.2) unterscheidet, wird auf eine erneute Beschreibung an dieser Stelle verzichtet.

    8.6.3   MQTTCllient
    Ein weiterer wesentlicher Teil ist die Implementierung der MQTT Kommunikation. Dazu wur-
    de ein Phao MQTT Client (siehe https://www.eclipse.org/paho/clients/js/) für Ja-
    vaScript definiert. Um den Client nutzen zu können, wird die entsprechende Bibliothek in der
    (start.html) eingebunden [8]. Zuerst wird der Client durch Übergabe der IP Adresse des Kontroll-
    rechners, dem MQTT WebSocket Port (hier: 8081), sowie dem Namen des Clients initialisiert.
1   // MQTT Client erstellen (Connection over WebSockets)
2   var client = new Paho.MQTT.Client("192.168.178.102", Number(8081), "clientId");

    Im Anschluss müssen die sogenannten Callback Handler für onConnectionLost und onMessagAr-
    rived festgelegt werden. Durch Aufruf der connect Funktion verbindet sich der Client dann mit
    dem Kontrollrechner und abonniert die topics event/display/timer für die Startsignale, event/dis-
    play/results für eingehende Zwischenzeiten sowie das neu erstellte topic event/webApp/settings für
    sonstige Nachrichten (siehe Kapitel 8.1). Das Abonnieren wird durch folgenden Code ermöglicht:
1       client.subscribe("event/display/timer");            //Startsignal
2       client.subscribe("event/display/results");          //Ergebnisse
3       client.subscribe("event/webApp/settings");          //Nachrichten

    8.6.4   OnMessageArrived
    Die Funktion onMessageArrived nimmt alle eingehenden Nachrichten des Kontrollrechners ent-
    gegen. Um das Verständnis der Funktion zu erleichtern, wurde folgender Programmablaufplan
    erstellt:

                        Abbildung 15: Programmablaufplan OnMessageArrrived

    Wie in Abbildung 15 zu sehen ist, besteht der Programmablaufplan im wesentlichen aus drei
    Zweigen, die über das topic der MQTT Nachricht ausgewählt werden. Je nach Zweig wird der In-

                                                    20
Ergebniswebseite                                                     Timo Lienemann, Tammo Post

    halt der Nachricht dann anders verarbeitet. Bei einer eingehenden Nachricht auf dem topic event/-
    display/timer werden zunächst die Wettkampfdaten (Disziplin, Startzeitstempel, Contest- und Ra-
    ceID und der boolean Wert für gleichzeitige Läufe) ausgelesen. Danach kann überprüft werden,
    ob ein neuer Lauf vorliegt, welcher dann sowohl intern als auch in der Datenbank abgespeichert
    wird. Wenn Zwischenzeiten über das topic event/display/timer eingehen, wird als erstes geprüft,
    ob es sich um die ersten Ergebnisse des Laufs (neuer Lauf) handelt. Wenn das der Fall ist, wird
    die Ergebnistabelle vorbereitet und die Objekte der Klasse Swimmer werden für zukünftige Er-
    gebnisse erstellt. Wenn Ergebnisse für einen bereits vorhandenen Lauf eingetroffen sind, werden
    diese direkt gesetzt und gespeichert. Bei zwei Läufen wird zuvor geprüft, zu welchem Lauf die
    Ergebnisse gehören, in dem die Namen verglichen werden. Wenn weder ein neuer Lauf oder eine
    neue Zwischenzeit eingetroffen ist, handelt es sich um eine allgemeine Nachricht des Kontroll-
    rechners (topic event/display/settings). Eine solche Nachricht könnte sich z.B. auf die Verzögerung
    eines Laufs oder eine Pause beziehen. Durch Speicherung in der Datenbank kann sie auf der
    Webseite für die Nutzer angezeigt werden.

    8.6.5   getResultTime
    Übergabeparameter: resultTime
    Rückgabewert: timeString

    Die Methode getResutTime erstellt aus dem übergebenen Zeitstempel eine Zwischenzeit im For-
    mat s:mm:ss:hh. Anhand des folgenden Ausschnitts aus dem Code soll die Funktionalität erläutert
    werden:
1       //Zwischenzeit berechnen
2       var result = new Date(startTimestamp - (startTimestamp - resultTime));
3
4       var   hours = result.getHours();
5       var   minutes = result.getMinutes();
6       var   seconds = result.getSeconds();
7        //   durch 10 teilen --> nur zwei Nachkommastellen (Hundertstel)
8       var   hundredth_sec = result.getMilliseconds() / 10;

    Zu Beginn wird die Zwischenzeit berechnet. Aus dem entstandenen Datum können dann die
    benötigten Werte für Stunden, Minuten, Sekunden und Millisekunden ausgewählt werden. Da
    für die Millisekunden nur 2 Nachkommastellen benötigt werden, wird das Ergebnis durch zehn
    geteilt. Für den Fall, dass Werte kleiner Zehn sind, wird eine 0 hinzugefügt, um das Format einzu-
    halten. Am Ende können die formatierten Werte zusammengesetzt als timeString zurückgegeben
    werden.
1       //Zusammensetzen der formatierten Zeit
2       var timeString = hours - 1 + ":" + minutes + ":" + seconds + "." + hundredth_sec;

    8.6.6   prepareResultTable
    Diese Funktion wurde ursprünglich entwickelt, um die Namen bei Eintreffen der Ergebnisse zu
    setzen und die Swimmer Objekte zu erstellen. Nach dem Umbau des Systemkonzepts (siehe Ab-
    schnitt 7) und leichten Anpassungen an der Funktion selbst, konnten diese dennoch weiter ver-
    wendet werden. Um die Schwimmer zusammen mit der richtigen Bahnnummer abzuspeichern,
    wird zunächst die Anzahl der Ergebnisse ermittelt:
1       for (i in details.results) {
2           resultCount += 1;                    //Zählen der Results = Anzahl Schwimmer
3       }
4
5       if (resultCount < 5) {
6           console.log("Weniger als 5 Ergebnisse");
7           j = 2;      //Schwimmer ab Bahn 2
8       }

    Wie der Code-Ausschnitt verdeutlicht, wird ein Zähler auf die Anzahl der Ergebnisse gesetzt.
    Wenn weniger als fünf Ergebnisse vorhanden sind, wird der Variablen j der Wert 2 “ zugewiesen
                                                                                   ”
    (Bahnnummer beginnt bei zwei), da bei Läufen mit weniger als fünf Schwimmern die erste Bahn

                                                     21
Ergebniswebseite                                                 Timo Lienemann, Tammo Post

     freigelassen wird. Der Wert von j wird dann später beim Einfügen der Schwimmer in die Daten-
     bank verwendet. Zuvor müssen jedoch noch die Namen aus den Ergebnissen extrahiert werden,
     um diese zu speichern und die Swimmer Objekte erstellen zu können. Dies zeigt folgender Code:
 1            for (i in details.results) {
 2                resultData[i] = details.results[i] + "";
 3                //Namen aus den Ergebnisdaten extrahieren
 4                name = resultData[i].split(’,’)[0];
 5                //Schwimmer Objekt erstellen
 6                var s = new Swimmer(name);
 7                //Schwimmer und Namen in die globalen Arrays einfügen
 8                swimmers.push(s);
 9                names.push(name);
10            }

     Im letzten Schritt können die Namen an die AJAX Funktion insertNames übergeben werden:
1             for (var i = j; i
Ergebniswebseite                                                  Timo Lienemann, Tammo Post

1        currentDate = new Date();              //Aktuelles Datum
2
3        if (stopWatchRunning === false) {
4            return;
5        }
6
7        var duration = new Date(currentDate - startTime);    //Berechnung der seit dem Start
              vergangenen Zeit
 8       var minutes = duration.getMinutes();
 9       var seconds = duration.getSeconds();
10       var hundredth_sec = duration.getMilliseconds() / 10;

     Die Funktion setStopWatch berechnet ein Datum aus der Differenz des aktuellen Datums und dem
     Startzeitstempel. Das aktuelle Datum richtet sich nach der Uhr des Endgeräts. So kann es auf
     Basis von durchgeführten Systemtests zu Verzögerungen zwischen 1 und 4 Sekunden kommen
     (Diese Differenz wirkt sich jedoch später nicht auf die berechneten Zwischenzeiten aus, da diese
     relativ zum Startzeitstempel berechnet werden). Wie im Codeausschnitt zu erkennen ist, werden
     die benötigten Daten ausgewählt und bei Werten kleiner als Zehn wird eine Null ergänzt. Die
     formatierte Zeit wird dann wie folgt auf der Webseite dargestellt:
1        var showDuration = duration.getHours() - 1 + ":" + minutes + ":" + seconds + "," +
             hundredth_sec.toFixed(0);
2
3        document.getElementById("timer").innerHTML = showDuration;           //formatierten Zeit
             String ausgeben

     8.7.2   AJAX Anfragen
     Um immer die aktuellsten Daten darstellen zu können, werden mehrere AJAX Anfragen benötigt,
     um die Daten aus der Datenbank nachladen zu können. Da die Anfragen von der Struktur her
     alle gleich aufgebaut sind, soll diese anhand der Funktion setContestName erklärt werden.
1    function setContestName() {      //Name des Laufs setzen
2        $.ajax({
3            type: "POST",
4            url: ’../../PHP/database_2.php’,
5            data: {function: "getContestName", previous: previousContestName, twoRaces:
                  twoRaces, getLatestID:getLatestID},
 6           datatype: "json",
 7           success: function (data) {
 8                if (String(data) !== previousContestName) {   //Bei neuem Lauf
 9                    previousContestName = data;
10                    document.getElementById("contestName").innerHTML = String(data);
11                }
12           }
13       });
14   }

     Zu Beginn der Anfrage wird festgelegt, wie die Variablen an den Server übertragen werden sol-
     len. Der Typ POST hat dabei im Vergleich zu GET den Vorteil, dass es keine Limitierungen bei
     der Anzahl sowie Größe der Variablen gibt und die Parameter im Hintergrund übertragen wer-
     den anstatt über die URL [9]. Die Adresse des PHP Scripts wird im Punkt url eingetragen. Die
     Daten werden im JSON Format übermittelt. Wenn die Anfrage erfolgreich durchgeführt wurde,
     kann das Ergebnis mit dem vorherigen Wettkampfnamen verglichen werden. Wenn diese unter-
     schiedlich sind, wird previousContestName aktualisiert und der neue Wettkampfname kann auf
     der Webseite angezeigt werden.

     8.7.3   getDatabaseResults
     Übergabeparameter:value

     Die Funktion getDatabaseResults wird durch die Funktion getLatestIDs aufgerufen. Dazu wurden
     in getLatestId zuvor die Contest- und RaceID des aktuellen Laufs ermittelt. Dadurch werden im-
     mer die Ergebnisse für den aktuellsten Lauf gewählt bzw. bei zwei parallelen Läufen für die
     letzten beiden Läufe. Zur besseren Verständlichkeit folgt ein Ausschnitt aus der Funktion:

                                                    23
Ergebniswebseite                                                  Timo Lienemann, Tammo Post

 1       value += "";
 2       content = value.split(",");        //value=(ContestID,RaceID)
 3       contestID = content[0];
 4       raceID = content[1];
 5
 6       $.ajax({
 7           type: "POST",
 8           url: "../../PHP/database_2.php",
 9           data: {function: "selectResults", contestID: contestID, raceID: raceID},
10           datatype: "json",
11           success: function (data) {
12                setDatabaseResults(data);      //Ergebnisse formatieren
13           }
14       });

     Durch Aufsplitten des übergebenen Parameters value, können Contest- und RaceID bestimmt
     werden. Mit diesen Werten kann dann die AJAX Anfrage ausgeführt werden. Bei Erfolg wird
     die Funktion setDatabaseResults aufgerufen.

     8.7.4   setDatabaseResults
     Die Zwischenzeiten, die aus der Datenbank geholt wurden, liegen in der Form Name, Zwi-
                                                                                         ”
     schenzeit, Name, ... “ vor. Um eine bessere Verarbeitung der Ergebnisse aus der Datenbank zu
     ermöglichen, wurde die Funktion setDatabaseResults implementiert. Diese ermöglicht es, ein neu-
     es Array von Tupeln der Form (Name des Schwimmers, Zwischenzeit) zurückzugeben. Dazu
     werden die aus getDatebaseResults erhaltenen Werte nach jedem Komma aufgetrennt, um Namen
     und Zwischenzeiten zu trennen. Anschließend wird das gesamte Array durchgegangen, bei je-
     dem geraden Wert wird geprüft, ob der Name sich bereits in der Liste der Namen befindet, falls
     nicht, wird er hinzugefügt. An jeder ungeraden Stelle befindet sich eine Zwischenzeit. Diese wird
     dann mit dem aktuellen Namen durch Komma getrennt eingefügt. Der folgende Ausschnitt aus
     der Methode zeigt den inneren Teil der Schleife:
 1            if (i % 2 === 0) {
 2                name = resultData[i];
 3                if (!names.includes(resultData[i])) {          //neuer Name
 4                    names[j] = resultData[i];                  //Name hinufügen
 5                    j += 1;
 6                }
 7            }
 8
 9            if (i % 2 === 1) {
10                resultTimes[k] = resultData[i];                 //Zwischenzeit auslesen
11                data[x] = name + "," + resultTimes[k];          //Name und Zwischenzeit zusammen
                       abspeichern
12                x++;
13                k += 1;
14            }

     Die neu entstandenen Datensätze können dann an die Funktion setResults weitergegeben werden.

     8.7.5   setResults
     Übergabeparameter: data

     Mithilfe dieser Funktion werden die Tupel bestehend aus dem Namen des Schwimmers sowie
     der Zwischenzeit ausgewertet, um die Ergebnisse auf der Webseite anzeigen zu können. Zuerst
     wird dazu die Funktion emptyResultTable aufgerufen, um alle alten Ergebnisse zu entfernen. Da-
     nach werden die Namen durch setNames gesetzt. Da in setNames das globale Array mit den Na-
     men der Schwimmer gesetzt wird, kann im Anschluss für jede Zwischenzeit geprüft werden,
     zu welchem Namen und daraus folgend welchem Dropdown-Menü das Ergebnis zugeordnet
     werden muss. Für jede Zwischenzeit muss ein neues option Element erstellt werden, das dann
     dem Dropdown-Menü hinzugefügt wird. Diese Funktionalität wird durch zwei verschachtelte
     for-Schleifen realisiert, die wie folgt implementiert wurden:
1        for (i = 0; i < data.length; i++) {                 //Für jeden Tupel
2
3             newName = data[i].split(",")[0];               //Namen +...

                                                    24
Ergebniswebseite                                                   Timo Lienemann, Tammo Post

4                results[i] = data[i].split(",")[1];         //... Ergebnis zuweisen
5
6                for (k = 0; k < names.length; k++) {       //prüfen für welchen Namem das
                     Ergebnis gesetzt werden soll
7                    if (newName === names[k + 1]) {
8                        menu = document.getElementById("results" + (k + 1));      //passendes
                             dropdown Menü auswählen
 9                       option = document.createElement("option");
10                       option.text = results[i];
11                       menu.add(option);                                         //option (
                             Zwischenzeit) hinzufügen
12                   }
13               }
14         }

     8.7.6     emtyResultTable
     Die Funktion emptyResultTable ist für das entfernen der Zwischenzeiten des vorherigen Laufs
     zuständig. Konkret werden dabei alle option Elemente durch folgenden Code aus den Dropdown-
     Menüs entfernt:
1          for (var i = 1; i  0) {
6                    dropdown.removeChild(dropdown.lastChild);     //Alle Zwischenzeiten löschen
7                }
8          }

     8.8       database 2
     Die Datei database 2.php ist ähnlich aufgebaut wie das bereits beschriebene Script database.php.
     Der wesentliche Unterschied ist, dass nur lesend auf die Datenbank zugegriffen wird. Das Vor-
     gehen bleibt jedoch gleich: Die Daten werden aus der Anfrage extrahiert und danach wird die
     entsprechende Funktion ausgeführt. Relevant ist für einige Funktionen der Wert vom Parameter
     twoRaces. Wenn es zwei Läufe gibt, werden entweder die Daten des ersten oder des zweiten Laufs
     geholt. Dies kann mit Hilfe des folgenden Code-Auschnitts verdeutlicht werden:
1          if($twoRaces=="false"){
2              $querry = "SELECT StartTimestamp FROM wettkampf WHERE ID = (SELECT MAX(ID) FROM
                   wettkampf)";
3          }else{
4              $querry = "SELECT StartTimestamp FROM wettkampf WHERE ID < (select MAX(ID) FROM
                   wettkampf) ORDER BY ID DESC LIMIT 1";
5          }

     Wenn twoRaces false ist, werden die Daten des aktuellsten Laufs geladen. Wenn twoRaces hingegen
     true ist, werden die Daten des vorherigen Laufs geladen.

     8.9       results.js
     Die JavaScript Datei results.js wird in Verbindung mit der Seite tabellen.php genutzt und wählt in
     Abhängigkeit des ausgewählten Laufs aus dem Dropdown-Menü die richtigen Wettkampfdaten
     aus der Datenbank aus.

     8.9.1     get-/setRaces
     Nachdem die Seite geladen wurde, wird die Funktion getRaces aufgerufen, um alle verfügbaren
     IDs der Läufe mittels AJAX aus der Datenbank zu holen. Mit dem Ergebnis wird dann die Funkti-
     on setRaces aufgerufen. In der Implementierung wird die übergebene Zeichenkette dann zunächst
     nach jedem Komma aufgetrennt, um dann die ContestIDs und RaceIDs zu erhalten. Diese können
     dann wie folgt zwischengespeichert werden:

                                                       25
Ergebniswebseite                                                Timo Lienemann, Tammo Post

 1       for (i = 2; i < raceData.length - 1; i++) {       //Zuweisen der Contest und RaceIDs
 2
 3             if (i % 2 === 0) {
 4                 contestIDs[j] = raceData[i];
 5                 j += 1;
 6             }
 7
 8             if (i % 2 === 1) {
 9                 RaceIDs[k] = raceData[i];
10                 k += 1;
11             }

     An jedem geraden Index befindet sich eine ContestID und an jedem ungeradem Index eine Ra-
     ceID. Wenn das gesamte Array durchlaufen ist, können die IDs in das Dropdown-Menü eingefügt
     werden mittels folgendem Code:
1        i = 0;
2        var menuContestID = document.getElementById("contestID");
3        var option;
4
5        for (i in contestIDs) {     //IDs in das Select Menü einfügen
6                option = document.createElement("option");
7                option.text = contestIDs[i] + ", " + RaceIDs[i];
8                menuContestID.add(option);
9        }

     Die Variable menuContestID wird mit dem entsprechenden Element der Webseite initialisiert, um
     schreibend darauf zugreifen zu können. Anschließend wird für jede ContestID (Anzahl Conte-
     stIDs = Anzahl RaceIDs) ein neues option Element erstellt und dem Dropdown-Menü hinzu-
     gefügt.

     8.9.2   getDatabaseResults
     Übergabeparameter: value

     Diese Funktion wird aufgerufen, wenn der Anwender der Webseite einen Lauf aus dem Dropdown-
     Menü auswählt. Dieser Wert wird dann an die Funktion übergeben, um die Wettkampfdaten (Na-
     men der Schwimmer, Disziplin und Zwischenzeiten) aus der Datenbank laden zu können. Der
     übergebene Parameter value beinhaltet die ContestID und RaceID per Komma getrennt. Nach
     auftrennen des Werts können dann zwei Ajax Anfragen gesendet werden, die im folgenden be-
     schrieben werden:
 1       $.ajax({                             //AJAX Anfrage an die Datenbank
 2           type: "POST",
 3           url: "../../PHP/database_2.php",
 4           data: {function: "selectResults" ,contestID: contestID, raceID: raceID},
 5           datatype: "json",
 6           success: function (data) {
 7                emptyResultTable();         //alte Ergebnisse entfernen
 8                setDatabaseResults(data);   //Ergebnisse formatieren
 9
10             }
11       });

     Die erste Anfrage soll die Zwischenzeiten aus der Datenbank laden. Dazu werden die zuvor
     ermittelte ContestID und RaceID übergeben. Wenn die Anfrage erfolgreich durchgeführt wer-
     den konnte, werden, falls vorhanden, alle vorherigen Namen, Zwischenzeiten und die Disziplin
     gelöscht, und die erhaltenen Daten werden zur Weiterverarbeitung an die Funktion setDatabase-
     Results übergeben.

     Die zweite Anfrage soll den entsprechenden Wettkampfnamen laden und dann auf der Seite dar-
     stellen:
1        $.ajax({                           //Alten Wettkampfnamen setzen
2            type: "POST",
3            url: "../../PHP/database_2.php",
4            data: {function: "selectOldContestName", raceID: raceID, contestID: contestID},
5            datatype: "json",
6            success: function (data) {

                                                  26
Ergebniswebseite                                                     Timo Lienemann, Tammo Post

7                 document.getElementById("contestName").innerHTML = data;
8             }
9       });

    8.9.3   setDatabaseResults
    Diese Funktion konnte direkt aus dem Script Backend.js übernommen werden (Erläuterungen sie-
    he 8.7.4), daher wird an dieser Stelle auf eine erneute Beschreibung verzichtet.

    8.9.4   setOldResults
    Übergabeparameter: data

    Die Funktion setOldResults funktioniert in weiten Teilen wie die Funktion setResults (siehe Ab-
    schnitt 8.7.5). Ein Unterschied ist der Zeitpunkt, an dem die Namen gesetzt werden (in Backend.js
    findet dies in einer eigenen Funktion statt, in results.js wird dies ebenfalls in setOldResults durch-
    geführt). Dieser Unterschied entsteht dadurch, dass bei der Auswahl eines alten Laufs bereits alle
    Zwischenzeiten und somit auch alle Namen der Schwimmer mindestens einmal in der Tabelle
    result vorhanden sind. In der Funktion setResults hingegen ist dies nicht gegeben, da die Ergeb-
    nisse erst nach und nach eintreffen und somit aus der Tabelle schwimmer in lauf gesetzt werden.
    Ein weiterer Unterschied existiert im Zusammenhang mit dem Leeren der Ergebnistabelle (in
    Backend.js wird diese mit dem Eintreffen des ersten Ergebnisses des neuen Laufs gelöscht und in
    results.js nach Auswahl durch den Anwender).

    8.9.5   emptyResultTable
    Wie bereits in der Datei Backend.js gibt es auch hier eine Funktion, um alte Ergebnisse zu entfer-
    nen. Zusätzlich werden auch der ContestName und alle Namen des vorherigen Laufs zurückgesetzt.

    8.10    Implementierung der Datenbank
    Die Datenbank ist der zentrale Baustein zwischen dem MQTT Client und der Ergebniswebseite.
    Eine Datenbank hat den Vorteil, dass alle Daten in einem übersichtlichen Schema abgespeichert
    werden und mittels SQL sowohl einfache als auch komplexe Anfragen möglich sind. Folgende
    Tabellen wurden dabei erstellt, um alle Informationen eines Laufs anzeigen zu können:

                                  Abbildung 16: Schema der Datenbank

    Wie in der Abbildung 16 zu erkennen ist, wurden vier Tabellen definiert. Die Tabelle wettkampf
    beinhaltet alle Informationen eines Laufs. Dazu gehören die ContestID und RaceID, der Wett-
    kampfname, der Startzeitstempel, der Wert twoRaces, der angibt, ob derzeit zwei gleichzeitige

                                                     27
Ergebniswebseite                                                  Timo Lienemann, Tammo Post

Läufe stattfinden, sowie der auto increment Wert ID. In der Tabelle result werden alle Zwischen-
zeiten gespeichert. Für jede Zwischenzeit werden die Bahnnummer, die ContestID und RaceID,
der zugehörende Name des Schwimmers sowie die eigentliche Zwischenzeit gespeichert. Die re-
sult ID bildet einen fortlaufenden Wert. Die Tabelle schwimmer in lauf ordnet jedem Schwimmer
den Lauf zu, in dem er antritt. Dazu werden eine fortlaufende ID, die Bahnnummer, die Con-
testID, die RaceID und der Name des Schwimmers erfasst. Die letzte Tabelle info beinhaltet alle
eingehenden Nachrichten des Kontrollrechners, die sich nicht direkt auf einen Lauf, sondern auf
Ereignisse wie den Start des Events oder die Ankündigung von Pausen beziehen. Dazu wird eine
fortlaufende ID sowie die eigentliche Nachricht abgespeichert.

9     Projektmanagement
Zu Beginn der Projektarbeit wurde entschieden, das gesamte Thema in zwei möglichst gleich-
wertige Abschnitte einzuteilen, um effizient arbeiten zu können. Dabei ergab sich folgende Zu-
ordnung der Arbeitspakete:
     • Timo Linemann: Erstellung des Webseiten-Layouts, Einrichtung des Raspberry Pi als Webser-
       ver
     • Tammo Post: Erstellung der Software, welche im Hintergrund der Webseite arbeitet (Backend):
       Datenbank, Funktionen zum Ein/Auslesen der Daten, MQTT Client, Anzeige der laufenden
       Zeit und Zwischenzeiten
Um den wöchentlichen Fortschritt, aufgetretene Probleme, die Ziele der nächsten Woche und
weitere Themen zu besprechen, wurde mindestens einmal pro Woche ein Treffen innerhalb des
Teams vereinbart. Dieses musste gerade zu Beginn aufgrund der Corona-Pandemie ausschließ-
lich online durchgeführt werden, was jedoch aufgrund der technischen Möglichkeiten kein allzu
großes Hindernis darstellte. Zudem wurde am Ende jeder Woche eine Meilensteintrendanslyse
ausgefüllt, um den tatsächlichen Fortschritt mit dem geplanten Fortschritt abzugleichen.

Im Laufe des Projekts wurde deutlich, dass sich die Systemtests nur schwer in einem Online-
Gespräch durchführen lassen. Aufgrund der steigenden Lockerungen wurden zum Ende des
Projekts hin auch normale “ Projekttreffen wieder möglich. Näheres zur Durchführung der Tests
                  ”
findet sich in Kapitel 10.

Zusammenfassend wurde also ein eher agiles Projektmanagement, welches Scrum ähnelt, ver-
wendet.

10      Systemtests
In diesem Abschnitt werden die durchgeführten Systemtests beschrieben. Da in diesem Jahr auf-
grund der Corona-Pandemie keine Schwimmwettkämpfe durchgeführt werden können, konn-
te das System leider noch nicht im Praxiseinsatz getestet werden. Um dennoch die Funktiona-
lität des Systems sicherzustellen, wurden während der gesamten Entwicklungszeit sowohl Tests
direkt auf dem Entwicklungscomputer, als auch unter praxisnahen Bedingungen mit mehreren
Geräten durchgeführt.

Um die Korrektheit der implementierten Funktionen zu überprüfen, wurde die Webseite nach
jeder größeren Änderung geprüft. So konnten eventuelle Fehler oder Seiteneffekte entdeckt und
behoben werden. Hilfreich waren in diesem Zusammenhang auch die Java Script Konsolenaus-
gaben. Diese können in den meisten Browsern durch die Tastenkombination strg + shift + i “
                                                                               ”
angezeigt werden.

     Bei den durchgeführten Tests wurden im wesentlichen folgende Punkte berücksichtigt:
     • Layout:
         – Passt sich die Größe der Komponenten an die Displaygröße und Auflösung an

                                               28
Sie können auch lesen