ProjektarbeitSS2020 Erstellung eines Web Portals zur Darstellung von Schwimmwettkampfergebnissen - Timo Lienemann, Tammo Post Juli 2020
←
→
Transkription von Seiteninhalten
Wenn Ihr Browser die Seite nicht korrekt rendert, bitte, lesen Sie den Inhalt der Seite unten
ProjektarbeitSS2020 Erstellung eines Web Portals zur Darstellung von Schwimmwettkampfergebnissen Timo Lienemann, Tammo Post Juli 2020 Betreuer: Prof. Dr.-Ing. Dirk Rabe
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
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
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
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
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
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
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
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
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