Gleichzeitiger Speedtest auf mehreren LTE-Modems

Während der Quarantäne wurde mir die Möglichkeit angeboten, an der Entwicklung eines Geräts zur Messung der Geschwindigkeit von LTE-Modems für mehrere Mobilfunkanbieter teilzunehmen.

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Der Auftraggeber wollte die Geschwindigkeit verschiedener Anbieter an verschiedenen geografischen Standorten bewerten, um zu bestimmen, welcher Mobilfunkanbieter bei der Installation von Geräten, die eine LTE-Verbindung nutzen, am besten geeignet ist, beispielsweise für Videoübertragungen. Dabei musste die Aufgabe so einfach und kostengünstig wie möglich gelöst werden, ohne teure Geräte.

Ich sage gleich, dass die Aufgabe nicht die einfachste und forschungsintensiv war. Ich werde euch erzählen, mit welchen Problemen ich konfrontiert wurde und wie ich sie gelöst habe. Also, legen wir los.

Hinweis

Die Messung der LTE-Verbindungsgeschwindigkeit ist eine komplexe Angelegenheit: Es ist wichtig, die richtige Ausrüstung und Methodik auszuwählen, sowie die Topologie und Funktionsweise des Mobilfunknetzes gut zu verstehen. Zudem können mehrere Faktoren die Geschwindigkeit beeinflussen: Die Anzahl der Nutzer an der Basisstation, die Wetterbedingungen und sogar von Basisstation zu Basisstation kann die Geschwindigkeit aufgrund der Netzstruktur erheblich variieren. Insgesamt ist dies eine Aufgabe mit vielen Unbekannten, die nur vom Mobilfunkanbieter korrekt gelöst werden kann.

Ursprünglich wollte der Kunde einfach einen Kurier mit den Telefonen der Betreiber herumschicken, die Messungen direkt auf dem Telefon durchführen und die Ergebnisse der Geschwindigkeitsmessung anschließend in ein Notizbuch eintragen. Meine Lösung zur Messung der LTE-Netzgeschwindigkeit, wenn auch nicht perfekt, erfüllt jedoch die gestellte Aufgabe.

Wegen Zeitmangel habe ich Entscheidungen getroffen, die nicht zugunsten von Bedienerfreundlichkeit oder Praktikabilität, sondern zugunsten der Entwicklungszeitschiene gingen. Beispielsweise wurde für den Fernzugriff eine Reverse-SSH-Verbindung eingerichtet, anstatt eines praktischeren VPNs, um Zeit bei der Serverseitigen und bei der Einrichtung jedes einzelnen Clients zu sparen.

Technisches Lastenheft

Wie im Artikel erwähnt Ohne Lastenheft: Warum der Kunde es nicht möchte: Arbeiten Sie niemals ohne ein Pflichtenheft! Weder hier noch anderswo!

Das Pflichtenheft war recht einfach, ich werde es ein wenig erweitern, um das Verständnis des Endbenutzers zu erleichtern. Die Wahl der technischen Lösungen und Geräte wurde vom Auftraggeber vorgegeben. Hier ist das Pflichtenheft, nach all den Genehmigungen:

Basierend auf einem Einplatinencomputer vim2 einen Speedtest für die LTE-Verbindung über die Huawei e3372h – 153 mehrere Netzbetreiber (von einem bis n). Ebenso müssen die Koordinaten vom GPS-Empfänger, der über UART angeschlossen ist, erfasst werden. Die Geschwindigkeitsmessungen erfolgen über den Dienst www.speedtest.net und werden in einer Tabelle des Formats:

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Tabelle im CSV-Format. Danach soll diese Tabelle alle 6 Stunden per E-Mail versendet werden. Bei Fehlern soll eine LED blinken, die an den GPIO angeschlossen ist.

Ich habe das Pflichtenheft in freier Form beschrieben, nach zahlreichen Genehmigungen. Aber der Sinn der Aufgabe ist bereits klar. Der Zeitraum für alles war eine Woche. In der Realität erstreckte er sich jedoch über drei Wochen. Dies unter der Voraussetzung, dass ich dies nur nach der Hauptarbeit und am Wochenende gemacht habe.

Hier möchte ich nochmals betonen, dass der Auftraggeber im Voraus die Nutzung eines Geschwindigkeitstestservices und die Hardware festgelegt hat, was meine Möglichkeiten stark eingeschränkt hat. Es gab auch ein begrenztes Budget, daher wurde nicht viel zusätzlich angeschafft. Ich musste mich also an diese Vorgaben halten.

Architektur und Entwicklung

Das Schema ist einfach und offensichtlich. Daher lasse ich es ohne besondere Kommentare.

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Ich habe beschlossen, das gesamte Projekt in Python umzusetzen, obwohl ich überhaupt keine Erfahrung in der Entwicklung mit dieser Sprache hatte. Ich habe es gewählt, da es eine Vielzahl fertiger Beispiele und Lösungen gab, die die Entwicklung beschleunigen konnten. Daher bitte ich alle professionellen Programmierer, mein erstes Entwicklungserlebnis in Python nicht zu kritisieren, und ich bin immer bereit, konstruktive Kritik zu hören, um meine Fähigkeiten zu verbessern.

Außerdem habe ich im Laufe des Prozesses entdeckt, dass Python zwei gängige Versionen 2 und 3 hat, weshalb ich mich für die dritte entschieden habe.

Hardware-Knoten

Einplatinencomputer vim2

Als Hauptmaschine erhielt ich einen Einplatinencomputer vim2

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Ein hervorragender, leistungsstarker Media-Combiner für Smart Homes und SMART-TVs, jedoch für diesen speziellen Zweck eher ungeeignet oder sagen wir, nur bedingt passend. Zum Beispiel ist das Hauptbetriebssystem Android, während Linux als alternatives OS dient, wobei sicherzustellen, dass alle Komponenten und Treiber unter Linux einwandfrei funktionieren, niemand garantieren kann. Ich vermute, dass einige Probleme mit den USB-Treibern dieser Plattform zusammenhingen, weshalb die Modems auf diesem Board nicht wie erwartet funktionierten. Zudem ist die Dokumentation äußerst schlecht und sporadisch, was jede Operation zu einer zeitaufwändigen Suche in den Unterlagen machte. Selbst die grundlegende Arbeit mit GPIO hat viel Mühe gekostet. Um beispielsweise die Funktion mit einer LED einzurichten, benötigte ich mehrere Stunden. Objektiv betrachtet war es jedoch nicht entscheidend, welches Board verwendet wurde, solange es funktionierte und USB-Ports vorhanden waren.

Zunächst muss ich Linux auf diesem Board installieren. Um nicht in den Tiefen der Dokumentation zu suchen, und auch für diejenigen, die sich mit diesem Einplatinencomputer auseinandersetzen werden, schreibe ich dieses Kapitel.

Es gibt zwei Möglichkeiten, Linux zu installieren: auf einer externen SD-Karte oder auf dem internen MMC-Speicher. Mit der Karte habe ich etwas experimentiert, aber ich konnte einfach nicht herausfinden, wie ich sie zum Laufen bringe. Daher habe ich beschlossen, auf dem MMC zu installieren, obwohl es ohne Zweifel viel einfacher gewesen wäre, mit der externen Karte zu arbeiten.

Über die Firmware wird hier ungenau beschrieben. Ich werde von einem seltsamen auf Russisch übersetzen. Um das Board zu flashen, muss ich die Hardware-UART anschließen. Ich habe es wie folgt angeschlossen.

  • Tool Pin GND: Pin17 des GPIO von VIM
  • Tool Pin TXD: Pin18 des GPIO von VIM (Linux_Rx)
  • Tool Pin RXD: Pin19 des GPIO von VIM (Linux_Tx)
  • Tool Pin VCC: Pin20 des GPIO von VIM

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Danach habe ich die Firmware heruntergeladen hier herunter. Die spezifische Firmware-Version VIM1_Ubuntu-server-bionic_Linux-4.9_arm64_EMMC_V20191231.

Um diese Firmware zu flashen, benötige ich bestimmte Werkzeuge. Mehr dazu wird hier. Ich habe es nicht unter Windows versucht, aber ich sollte ein paar Worte zur Firmware unter Linux sagen. Zuerst werde ich die Werkzeuge gemäß der Anleitung installieren.

git clone https://github.com/khadas/utils
cd /path/to/utils
sudo ./INSTALL

Und… es funktioniert nichts. Ich habe ein paar Stunden damit verbracht, die Installationsskripte anzupassen, damit alles korrekt installiert wird. Ich kann mich nicht mehr erinnern, was ich gemacht habe, aber es war auch ein ziemlicher Zirkus. Seid also vorsichtig. Ohne diese Tools macht es keinen Sinn, weiter mit dem vim2 herumzuhampeln. Am besten gar nicht damit befassen!

Nach sieben Qualen, Skriptkonfigurationen und einem erfolgreichen Setup habe ich ein Paket funktionierender Tools erhalten. Ich habe das Board über USB mit meinem Linux-Computer verbunden und ebenfalls UART gemäß dem obigen Schema angeschlossen.
Ich konfiguriere meinen Lieblingsterminal minicom auf eine Geschwindigkeit von 115200, ohne hardware- oder softwareseitige Fehlerkontrolle. Und los geht's.

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Beim Booten des VIM2 im UART-Terminal drücke ich eine beliebige Taste, zum Beispiel die Leertaste, um das Booten zu stoppen. Nachdem die Zeile erscheint,

kvim2# 

Gebe ich den Befehl ein:

kvim2# run update

Auf dem Host, von dem wir booten, führe ich aus:

burn-tool -v aml -b VIM2 -i VIM2_Ubuntu-server-bionic_Linux-4.9_arm64_EMMC_V20191231.img

Fertig, puh. Geflasht, und auf dem Board ist Linux. Benutzername/Passwort khadas:khadas.

Danach einige grundlegende Ersteinrichtungen. Für die weitere Arbeit deaktiviere ich das Passwort für sudo (ja, nicht sicher, aber praktisch).

sudo visudo

Ich bearbeite die Zeile bis zur Ansicht und speichere.

# Allow members of group sudo to execute any command
%sudo ALL=(ALL:ALL) NOPASSWD: ALL

Danach ändere ich die aktuelle Zeitzone, damit die Zeit nach Moskau eingestellt ist, sonst wird sie nach Greenwich angezeigt.

sudo timedatectl set-timezone Europe/Moscow

oder

ln -s /usr/share/zoneinfo/Europe/Moscow /etc/localtime

Wenn Ihnen das kompliziert vorkommt, verwenden Sie diese Karte nicht, besser Raspberry Pi. Ehrlich gesagt.

Modem Huawei e3372h — 153

Dieses Modem hat mir ganz schön zu schaffen gemacht und wurde letztlich zum größten Engpass des gesamten Projekts. Der Begriff „Modem“ spiegelt für diese Geräte überhaupt nicht den tatsächlichen Betrieb wider: Es ist ein extrem mächtiges Gerät, das eine Besatzung hat, die sich als CD-ROM tarnt, um Treiber zu installieren, und dann in den Netzwerkmodus wechselt.

Architektonisch gesehen, aus der Sicht eines Linux-Benutzers nach all den Einstellungen, sieht es so aus: Nach dem Anschluss des Modems erscheint bei mir eine Netzwerkschnittstelle eth*, die per DHCP die IP-Adresse 192.168.8.100 und das Standard-Gateway 192.168.8.1 erhält.

Und der wichtigste Punkt! Dieses Modell des Modems kann nicht im Modemmodus betrieben werden, der mit AT-Befehlen gesteuert wird.. Es wäre viel einfacher gewesen, PPP-Verbindungen für jeden Modem zu erstellen und dann mit ihnen zu arbeiten. Aber in meinem Fall erstellt der ‚Selbst‘ (genauer gesagt die Linux-Treiber gemäß den udev-Regeln) das eth-Interface und weist ihm eine IP-Adresse über DHCP zu.

Um nicht weiter durcheinanderzukommen, schlage ich vor, das Wort „Modem“ zu vergessen und von Netzwerkkarten und Gateways zu sprechen, denn eigentlich ist das wie das Anschließen einer neuen Netzwerkkarte mit einem Gateway.
Wenn es nur ein Modem gibt, verursacht das keine besonderen Probleme, aber wenn es mehrere gibt, also n Stück, ergibt sich folgendes Bild im Netzwerk.

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Das heißt, n Netzwerkkarten mit einer einzigen IP-Adresse, wobei jede dieselbe Standardgateway hat. Jeder von ihnen ist jedoch tatsächlich mit seinem eigenen Anbieter verbunden.

Mein ursprüngliches einfaches Lösung war: mit dem Befehl ifconfig oder ip alle Interfaces abzuschalten und nacheinander jeweils eines zu aktivieren und zu testen. Diese Lösung war gut, bis auf die Tatsache, dass ich in den Momenten der Umschaltung keine Verbindung zum Gerät herstellen konnte. Da die Umschaltungen häufig und schnell sind, hatte ich praktisch keine Möglichkeit, mich überhaupt zu verbinden.

Deshalb habe ich mich entschieden, die IP-Adressen der Modems "manuell" zu ändern und den Datenverkehr über die Routing-Einstellungen weiterzuleiten.

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Damit waren meine Probleme mit den Modems jedoch noch nicht vorbei: Bei Problemen mit der Stromversorgung fielen sie aus, und ich benötigte eine gute, stabile Stromversorgung für den USB-Hub. Dieses Problem löste ich, indem ich die Stromzufuhr direkt am Hub einlötete. Ein weiteres Problem, dem ich gegenüberstand und das das gesamte Projekt gefährdete, war, dass nach einem Neustart oder einem Kaltstart nicht alle Modems erkannt wurden und dies auch nicht immer geschah. Warum dies passierte und nach welchem Algorithmus ich es festlegen sollte, konnte ich nicht herausfinden. Aber alles der Reihe nach.

Für das korrekte Funktionieren des Modems habe ich das Paket usb-modeswitch installiert.

sudo apt update
sudo apt install -y usb-modeswitch

Danach wird das Modem nach dem Anschluss korrekt von der udev-Subsystem erkannt und konfiguriert. Ich überprüfe es, indem ich das Modem einfach anschließe und sicherstelle, dass das Netzwerk vorhanden ist.
Ein weiteres Problem, das ich nicht lösen konnte: Wie erhalte ich den Namen des Netzbetreibers von diesem Modem, mit dem wir arbeiten? Der Name des Netzbetreibers ist im Web-Interface des Modems unter 192.168.8.1 enthalten. Es handelt sich um eine dynamische Webseite, die Daten über Ajax-Anfragen abruft, daher kann ich die Seite nicht einfach mit wget herunterladen und den Namen parsen. Ich habe also damit begonnen, herauszufinden, wie man die Webseite bearbeitet, und habe festgestellt, dass ich mich mit etwas Unsinn beschäftige. Letztendlich habe ich aufgegeben und den Betreiber über die API von Speedtest abgefragt.

Vieles wäre einfacher, wenn das Modem über AT-Befehle zugänglich wäre. Man könnte es neu konfigurieren, eine PPP-Verbindung erstellen, IPs zuweisen, den Dienstanbieter abrufen usw. Aber leider arbeite ich mit dem, was mir gegeben wurde.

GPS

Der GPS-Empfänger, den ich erhalten habe, hatte eine UART-Schnittstelle und eine Stromversorgung. Das war keine optimale Lösung, aber es war dennoch funktional und einfach. Der Empfänger sah ungefähr so aus.

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Ehrlich gesagt, arbeitete ich zum ersten Mal mit einem GPS-Empfänger, aber wie ich vermutet hatte, gibt es schon längst Lösungen dafür. Also nutzen wir einfach die vorhandenen Lösungen.

Zuerst aktiviere ich uart_AO_B (UART_RX_AO_B, UART_TX_AO_B), um den GPS-Empfänger anzuschließen.

khadas@Khadas:~$ sudo fdtput -t s /dtb.img /serial@c81004e0 status okay

Ich überprüfe nun den Erfolg der Operation.

khadas@Khadas:~$ fdtget /dtb.img /serial@c81004e0 status
okay

Dieser Befehl bearbeitet anscheinend den Device Tree in Echtzeit, was sehr praktisch ist.

Nach dem Erfolg dieser Operation starten wir neu und installieren den GPS-Daemon.

khadas@Khadas:~$ sudo reboot

Installation des GPS-Daemons. Ich installiere alles und schalte ihn sofort für eine weitere Konfiguration ab.

sudo apt install gpsd gpsd-clients -y
sudo killall gpsd
 
/* GPS-Daemon stoppen/deaktivieren */
sudo systemctl stop gpsd.socket
sudo systemctl disable gpsd.socket

Ich bearbeite die Einstellungsdatei.

sudo vim /etc/default/gpsd

Ich installiere den UART, an dem der GPS hängt.

DEVICES="/dev/ttyS4"

Und dann schalten wir alles ein und starten es.

/* GPS daemon enable/start */
sudo systemctl enable gpsd.socket
sudo systemctl start gpsd.socket

Anschließend schließe ich den GPS-Empfänger an.

Gleichzeitiger Speedtest auf mehreren LTE-Modems

In der Hand das GPS-Kabel, unter den Fingern die UART-Drähte des Debuggers sichtbar.

Ich starte neu und teste die GPS-Funktion mit dem Programm gpsmon.

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Auf diesem Screenshot sind keine Satelliten zu sehen, aber die Kommunikation mit dem GPS-Empfänger ist sichtbar, was bedeutet, dass alles gut ist.

Ich habe viele Varianten zur Arbeit mit diesem Daemon in Python ausprobiert, aber ich habe mich für die entschieden, die korrekt mit Python 3 funktionierte.

Ich installiere die benötigte Bibliothek.

sudo -H pip3 install gps3 

Und ich schreibe den Arbeitscode.

from gps3.agps3threaded import AGPS3mechanism
...
def getPositionData(agps_thread):
	counter = 0;
	while True:
		longitude = agps_thread.data_stream.lon
		latitude = agps_thread.data_stream.lat
		if latitude != 'n/a' and longitude != 'n/a':
			return '{}' .format(longitude), '{}' .format(latitude)
		counter = counter + 1
		print ("Warte GPS Zähler = %d" % counter)
		if counter == 10:
			ErrorMessage("Fehler des GPS-Empfängers!!!")
			return "NA", "NA"
		time.sleep(1.0)
...
f __name__ == '__main__':
...
	#gps
	agps_thread = AGPS3mechanism()  # AGPS3 Mechanismen instanziieren
	agps_thread.stream_data()  # Von localhost (), oder anderen Hosts, zum Beispiel (host='gps.ddns.net')
	agps_thread.run_thread()  # Zeitverzögerung nach einer leeren Abfrage, Standard '()' 0,2 zwei Zehntel einer Sekunde

Wenn ich die Koordinaten erhalten möchte, mache ich dies mit dem folgenden Aufruf:

longitude, latitude = getPositionData(agps_thread)

Innerhalb von 1-10 Sekunden erhalte ich entweder die Koordinaten oder eben nicht. Ja, ich hatte zehn Versuche, die Koordinaten zu erhalten. Nicht optimal, etwas klobig, aber es funktioniert. Ich habe mich so entschieden, weil GPS manchmal schlecht fängt und nicht immer Daten erhält. Wenn ich auf Daten warten würde, würde das Programm an dieser Stelle in einem geschlossenen Raum hängen bleiben. Daher habe ich diese nicht elegante Lösung implementiert.

Im Grunde genommen, wenn ich mehr Zeit hätte, könnte ich die GPS-Daten direkt über UART empfangen, sie in einem separaten Thread parsen und damit arbeiten. Aber ich hatte überhaupt keine Zeit, daher der chaotische, unansehnliche Code. Und ja, ich schäme mich nicht dafür.

LED

Der Anschluss der LED war gleichzeitig einfach und kompliziert. Das Hauptproblem besteht darin, dass die Pin-Nummer im System nicht mit der Pins auf dem Board übereinstimmt und weil die Dokumentation schlecht geschrieben ist. Um die Hardware-Pin-Nummer mit der Pin-Nummer im Betriebssystem zuzuordnen, muss der Befehl ausgeführt werden:

gpio readall

Es wird eine Tabelle angezeigt, die die Zuordnung der Pins im System und auf dem Board zeigt. Danach kann ich dann mit dem Pin im Betriebssystem arbeiten. In meinem Fall ist die LED angeschlossen an GPIOH_5.

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Ich setze den GPIO-Pin in den Ausgabemodus.

gpio -g mode 421 out

Ich schreibe eine Null.

gpio -g write 421 0

Ich schreibe eine Eins.

gpio -g write 421 1

Gleichzeitiger Speedtest auf mehreren LTE-Modems
Es leuchtet alles, nachdem ich die "1" geschrieben habe.

#gpio subsistem
def gpio_init():
	os.system("gpio -g mode 421 out")
	os.system("gpio -g write 421 1")

def gpio_set(val):
	os.system("gpio -g write 421 %d" % val)
	
def error_blink():
	gpio_set(0)
	time.sleep(0.1)
	gpio_set(1)
	time.sleep(0.1)
	gpio_set(0)
	time.sleep(0.1)
	gpio_set(1)
	time.sleep(0.1)
	gpio_set(0)
	time.sleep(1.0)
	gpio_set(1)

def good_blink():
	gpio_set(1)

Jetzt rufe ich im Falle von Fehlern error_blink() auf und die LED blinkt schön für uns.

Software-Module

Speedtest API

Es ist großartig, dass der Dienst speedtest.net seine eigene Python-API hat, die man sich ansehen kann. Github.

Es ist vorteilhaft, dass die Quellcodes auch einsehbar sind. Wie man mit dieser API arbeitet (einfachste Beispiele) finden Sie in dem entsprechenden Abschnitt.

Ich installiere die Python-Bibliothek mit dem folgenden Befehl.

sudo -H pip3 install speedtest-cli

Sie können beispielsweise den Speedtest direkt aus dem Repository in Ubuntu installieren. Dies ist die gleiche Python-Anwendung, die Sie dann direkt aus der Konsole starten können.

sudo apt install speedtest-cli -y

Und die Geschwindigkeit Ihres Internets messen.

speedtest-cli
Lade Konfiguration von speedtest.net...
Testen von B***** (*.*.*.*)...
Lade Serverliste von speedtest.net...
Wähle besten Server basierend auf Ping...
Gehostet von MTS (Moskau) [0,12 km]: 11,8 ms
Testen der Downloadgeschwindigkeit................................................................................
Download: 7,10 Mbit/s
Testen der Uploadgeschwindigkeit......................................................................................................
Upload: 3,86 Mbit/s

So habe ich es gemacht. Ich musste in den Quellcode dieses Speedtests eintauchen, um ihn umfassender in mein Projekt zu integrieren. Eine der wichtigsten Aufgaben besteht darin, auch den Namen des Internetanbieters zu erhalten, um ihn in die Tabelle einzufügen.

import speedtest
from datetime import datetime
...
#Hier geben wir den spezifischen Server für den Test an
#6053) MaximaTelecom (Moskau, Russische Föderation)
servers = ["6053"]
# Wenn Sie einen einseitigen Test verwenden möchten
threads = None
s = speedtest.Speedtest()
# erhalten den Namen des Mobilfunkanbieters
opos = '%(isp)s' % s.config['client']
s.get_servers(servers)
# erhalten den Textstring mit den Serverparametern
testserver = '%(sponsor)s (%(name)s) [%(d)0.2f km]: %(latency)s ms' % s.results.server
# Download-Test
s.download(threads=threads)
# Upload-Test
s.upload(threads=threads)
# erhalten die Ergebnisse
s.results.share()

#Daraufhin wird eine Zeichenkette zur Speicherung in einer CSV-Datei gebildet.
# erhalten die GPS-Position
longitude, latitude = getPositionData(agps_thread)
# Zeit und Datum
curdata = datetime.now().strftime('%d.%m.%Y')
curtime = datetime.now().strftime('%H:%M:%S')
delimiter = ';'
result_string = opos + delimiter + str(curpos) + delimiter + 
	curdata + delimiter + curtime + delimiter + longitude + ', ' + latitude + delimiter + 
	str(s.results.download / 1000.0 / 1000.0) + delimiter + str(s.results.upload / 1000.0 / 1000.0) + 
	delimiter + str(s.results.ping) + delimiter + testserver + "n"
#hier wird in die Logdatei geschrieben

Hier stellte sich heraus, dass es auch nicht so einfach war, obwohl es zunächst so schien. Ursprünglich war der Parameter servers bei mir gleich [], wählen Sie den besten Server. Das Ergebnis waren zufällige Server und wie nicht schwer zu erraten ist, schwankende Geschwindigkeiten. Es ist eine recht komplexe Angelegenheit, einen dedizierten Server zu nutzen, wobei die Frage bleibt, ob statisch oder dynamisch – das erfordert Forschung. Aber hier ist ein Beispiel für die Grafiken der Geschwindigkeitstests des Anbieters Beeline bei dynamischer Auswahl des Testservers und einem statisch festgelegten Server.

Gleichzeitiger Speedtest auf mehreren LTE-Modems
Ergebnis der Geschwindigkeitsmessung bei Wahl eines dynamischen Servers.

Gleichzeitiger Speedtest auf mehreren LTE-Modems
Ergebnis des Geschwindigkeitstests mit einem streng ausgewählten Server.

Es gibt sowohl bei der Testung als auch dort ein gewisses Maß an 'Rauschen', das mathematisch entfernt werden muss. Bei einem festgelegten Server ist es jedoch etwas geringer und die Amplitude stabiler.
Im Grunde genommen ist dies ein Bereich intensiver Forschung. Ich würde Geschwindigkeitsmessungen zu meinem Server mit dem Tool iperf durchführen, aber wir halten uns an die Vorgaben.

E-Mail-Übertragung und Fehler

Für den Versand von E-Mails habe ich mehrere Dutzend Varianten ausprobiert, aber am Ende habe ich mich für Folgendes entschieden. Ich habe ein Postfach bei Yandex registriert und genommen dieses Beispiel für den Versand von E-Mails.Ich habe es überprüft und in die Software integriert. In diesem Beispiel werden verschiedene Optionen behandelt, einschließlich des Versands über Gmail usw. Ich wollte keinen eigenen Mailserver aufsetzen und hatte dafür keine Zeit, aber wie sich später herausstellte, war das auch nicht nötig.

Der Logversand erfolgte über den Scheduler, wenn eine Verbindung vorhanden war,, alle 6 Stunden: um 00 Uhr, 06 Uhr, 12 Uhr und 18 Uhr. Ich habe es folgendermaßen gesendet.

from send_email import *
...
message_log = "Testprotokolle für Platine Nr. 1"
EmailForSend = ["dlinyj@trololo.ru", "pupkin@trololo.ru"]
files = ["/home/khadas/modems_speedtest/csv"]
...
def sendLogs():
	global EmailForSend
	curdata = datetime.now().strftime('%d.%m.%Y')
	curtime = datetime.now().strftime('%H:%M:%S')
	try:
		for addr_to in EmailForSend:
			send_email(addr_to, message_log, "Protokolle vom " + curdata + " " + curtime, files)
	except:
		print("Netzwerkproblem beim Versand der Mail")
		return False
	return True

Fehler wurden anfangs ebenfalls gesendet. Zuerst wurden sie in einer Liste gesammelt und dann von einem Scheduler gesendet, sofern eine Verbindung vorhanden war. Allerdings traten später Probleme auf, da Yandex eine Beschränkung für die Anzahl der täglich gesendeten Nachrichten hat (das ist ärgerlich und demütigend). Da es selbst in einer Minute eine enorme Anzahl von Fehlern geben konnte, musste auf das Senden von Fehlern per E-Mail verzichtet werden. Bitte beachten Sie also, dass es bei der automatischen Übertragung über die Yandex-Dienste ein solches Problem gibt.

Feedback-Server

Um Zugriff auf die Remote-Hardware zu haben und sie anpassen und neu konfigurieren zu können, benötigte ich einen externen Server. Fairerweise wäre es eigentlich richtig, alle Daten auf einen Server zu senden und im Web-Interface alle ansprechenden Diagramme zu erstellen. Aber nicht alles auf einmal.

Als VPS habe ich gewählt ruvds.com. Man könnte den einfachsten Server wählen. Für meine Zwecke würde das vollkommen ausreichen. Da ich jedoch nicht aus eigener Tasche für den Server bezahle, habe ich mich entschieden, etwas mehr Kapazität zu nehmen, um genug Platz zu haben, falls wir ein Web-Interface, einen eigenen SMTP-Server, VPN usw. einrichten möchten. Außerdem wollte ich die Möglichkeit haben, einen Telegram-Bot zu konfigurieren, ohne Probleme mit Blockierungen zu bekommen. Daher habe ich Amsterdam und folgende Parameter gewählt.

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Als Verbindungsmethode zur Hardware habe ich ein umgekehrtes SSH-Verbindung gewählt und wie sich gezeigt hat, ist das nicht die beste Wahl. Bei einer Unterbrechung der Verbindung hält der Server den Port und es ist eine Zeit lang unmöglich, sich damit zu verbinden. Daher ist es besser, andere Verbindungsarten, z. B. VPN, zu verwenden. In Zukunft wollte ich auf VPN umsteigen, aber ich hatte nicht genug Zeit.

Ich werde nicht auf die Einzelheiten der Firewall-Konfiguration, der Berechtigungsbeschränkungen, der Deaktivierung der Root-SSH-Verbindung und andere grundlegende VPS-Einstellungen eingehen. Ich hoffe, dass Sie bereits alles wissen. Für die Remote-Verbindung erstelle ich einen neuen Benutzer auf dem Server.

adduser vimssh

Auf unserem Server generiere ich die SSH-Verbindungsschlüssel.

ssh-keygen

Und kopiere sie auf unseren Server.

ssh-copy-id vimssh@host.com

Auf unserem Server richte ich eine automatische SSH-Rückverbindung bei jedem Bootvorgang ein.

[Unit]
Beschreibung=Auto Reverse SSH
Erfordert=systemd-networkd-wait-online.service
Nach=systemd-networkd-wait-online.service
[Service]
Benutzer=khadas
ExecStart=/usr/bin/ssh -NT -o ExitOnForwardFailure=yes -o ServerAliveInterval=60 -CD 8080 -R 8083:localhost:22 vimssh@host.com
RestartSec=5
Restart=always
[Install]
WantedBy=multi-user.target

Beachten Sie den Port 8083: dieser bestimmt, über welchen Port die Verbindung über die Rückverbindung SSH hergestellt wird. Fügen wir es zum Autostart hinzu und starten wir es.

sudo systemctl enable autossh.service
sudo systemctl start autossh.service

Sie können sogar den Status überprüfen:

sudo systemctl status autossh.service

Jetzt, auf unserem VPS-Server, wenn ich ausführe:

ssh -p 8083 khadas@localhost

Dann gelange ich auf meinen Testserver. Und von der Hardware aus kann ich auch Protokolle und beliebige Daten per SSH zu meinem Server senden, was sehr praktisch ist.

Alles zusammenführen

Gleichzeitiger Speedtest auf mehreren LTE-Modems
Wir starten, gehen zur Entwicklung und Fehlersuche über.

Puh, ich habe anscheinend alles beschrieben, was notwendig ist. Jetzt ist es an der Zeit, alles zusammenzustellen. Den Code können Sie einsehen. hier nachlesen.

Ein wichtiger Punkt zum Code: Dieses Projekt kann so nicht ohne weiteres starten, da es für eine bestimmte Aufgabe und Architektur optimiert wurde. Obwohl ich den Quellcode bereitstelle, werde ich das Wertvollste hier direkt im Text erklären, ansonsten ist es völlig unverständlich.

Zunächst erfolgt die Initialisierung von GPS, GPIO und der Start eines separaten Threads für den Scheduler.

#запуск потока планировщика
pShedulerThread = threading.Thread(target=ShedulerThread, args=(1,))
pShedulerThread.start()

Der Scheduler ist recht einfach: Er überprüft, ob es an der Zeit ist, Nachrichten zu senden, und welchen Status die Fehler aktuell haben. Wenn ein Fehlerflag gesetzt ist, blinkt die LED.

#sheduler
def ShedulerThread(name):
	global ready_to_send
	while True:
		d = datetime.today()
		time_x = d.strftime('%H:%M')
		if time_x in time_send_csv:
			ready_to_send = True
		if error_status:
			error_blink()
		else:
			good_blink()
		time.sleep(1)

Der schwierigste Teil dieses Projekts besteht darin, die Rückverbindung über SSH bei jedem Test aufrechtzuerhalten. Bei jedem Test wird das Standardgateway und der DNS-Server neu konfiguriert. Da ohnehin niemand liest, wissen Sie, dass der Zug nicht auf Holzschienen fährt. Wer das Osterei findet, bekommt ein Bonbon.

Dazu erstelle ich eine separate Routingtabelle —set-mark 0x2 und eine Regel zur Weiterleitung des Verkehrs.

def InitRouteForSSH():
	cmd_run("sudo iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 22 -j MARK --set-mark 0x2")
	cmd_run("sudo ip rule add fwmark 0x2/0x2 lookup 102")

Mehr darüber, wie das funktioniert, kann man in diesem Artikel.

Nach welchem ich in eine Endlosschleife übergehe, in der ich jedes Mal die Liste der angeschlossenen Modems abrufe (um zu erfahren, ob sich die Netzwerkkonfiguration geändert hat).

network_list = getNetworklist()

Das Abrufen der Liste der Netzwerkinterfaces ist recht einfach.

def getNetworklist():
	full_networklist = os.listdir('/sys/class/net/')
	network_list = [x for x in full_networklist if "eth" in x and x != "eth0"]
	return network_list

Nachdem ich die Liste erhalten habe, weise ich allen Schnittstellen IP-Adressen zu, wie ich es im Kapitel über das Modem gezeigt habe.

SetIpAllNetwork(network_list)

def SetIpAllNetwork(network_list):
	for iface in network_list:
		lastip = "%d" % (3 + network_list.index(iface))
		cmd_run ("sudo ifconfig " + iface + " 192.168.8." + lastip + " up")

Anschließend gehe ich einfach in einer Schleife durch jede Schnittstelle und konfiguriere jede davon.

	for iface in network_list:
		ConfigNetwork(iface)

def ConfigNetwork(iface):
#Setze alle Einstellungen zurück
		cmd_run("sudo ip route flush all")
#Weise das Standardgateway zu
		cmd_run("sudo route add default gw 192.168.8.1 " + iface)
#Lege den DNS-Server fest (das ist notwendig für speedtest)
		cmd_run ("sudo bash -c 'echo nameserver 8.8.8.8 > /etc/resolv.conf'")

Ich überprüfe die Schnittstelle auf Funktionsfähigkeit; wenn das Netzwerk nicht vorhanden ist, melde ich Fehler. Wenn das Netzwerk funktioniert, ist es Zeit zu handeln!

Hier konfiguriere ich die SSH-Routing auf dieser Schnittstelle (falls das nicht bereits gemacht wurde), sende Fehler an den Server, wenn die Zeit gekommen ist, übermittle ich die Logs und schließlich führe ich einen Speedtest durch und speichere die Logs in einer CSV-Datei.

if not NetworkAvalible():
....
#Hier definieren wir die Fehler
....
else: #Netzwerk vorhanden, wunderbar, wir arbeiten!
#Wenn wir ein problematisches Interface haben, auf dem ssh läuft, ändern wir es
  if (sshint == lastbanint or sshint == "free"):
    print("********** SSH einrichten ********************")
    if sshint != "free":
      cmd_run("sudo ip route del default via 192.168.8.1 dev " + sshint + " table 102")
    SetupReverseSSH(iface)
    sshint = iface
#Da das Netzwerk funktioniert, lassen Sie uns alles dringend senden!!!
    if ready_to_send:
      print ("**** Bereit zu senden!!!")
        if sendLogs():
          ready_to_send = False
        if error_status:
          SendErrors()
#Und dann testen wir die Geschwindigkeit und speichern die Logs. 

Es sollte erwähnt werden, dass die Funktion zur Konfiguration von Reverse-SSH wichtig ist.

def SetupReverseSSH(iface):
	cmd_run("sudo systemctl stop autossh.service")
	cmd_run("sudo ip route add default via 192.168.8.1 dev " + iface + " table 102")
	cmd_run("sudo systemctl start autossh.service")

Und natürlich muss all diese Schönheit zur automatischen Startkonfiguration hinzugefügt werden. Dazu erstelle ich eine Datei:

sudo vim /etc/systemd/system/modems_speedtest.service

Und schreibe darin:

[Unit]
Beschreibung=Modem-Geschwindigkeitstest
Erfordert=systemd-networkd-wait-online.service
Nach=systemd-networkd-wait-online.service
[Service]
Benutzer=khadas
ExecStart=/usr/bin/python3.6 /home/khadas/modems_speedtest/networks.py
RestartSec=5
Restart=always
[Install]
WantedBy=multi-user.target

Ich aktiviere den Autostart und starte ihn!

sudo systemctl enable modems_speedtest.service
sudo systemctl start modems_speedtest.service

Jetzt kann ich die Logs der Vorgänge mit dem Befehl ansehen:

journalctl -u modems_speedtest.service --no-pager -f

Ergebnisse

Was ist nun das Wichtigste, was dabei herausgekommen ist? Ich werde einige Grafiken zeigen, die ich während der Entwicklung und Fehlersuche aufgenommen habe. Die Grafiken wurden mit gnuplot mittels des folgenden Skripts erstellt.

#! /usr/bin/gnuplot -persist
set terminal postscript eps enhanced color solid
set output "Rostelecom.ps"
 
#set terminal png size 1024, 768
#set output "Rostelecom.png"
 
set datafile separator ';'
set grid xtics ytics
set xdata time
set ylabel "Speed Mb/s"
set xlabel 'Time'
set timefmt '%d.%m.%Y;%H:%M:%S'
set title "Rostelecom Speed"

plot "Rostelecom.csv" using 3:6 with lines title "Download", '' using 3:7 with lines title "Upload"
 
set title "Rostelecom 2 Ping"
set ylabel "Ping ms"
plot "Rostelecom.csv" using 3:8 with lines title "Ping"

Die erste Erfahrung stammt vom Anbieter Tele2, die ich über mehrere Tage gesammelt habe.

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Hier habe ich einen dynamischen Messserver verwendet. Die Geschwindigkeitstests funktionieren zwar, schwanken jedoch stark, aber es ist dennoch eine gewisse Durchschnittsgeschwindigkeit erkennbar, die durch Datenfilterung, beispielsweise durch gleitende Mittelwerte, ermittelt werden kann.

Später habe ich auch weitere Grafiken für andere Telekommunikationsanbieter erstellt. In diesem Fall war der Testserver bereits einmalig, und die Ergebnisse waren ebenfalls sehr interessant.

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Wie zu sehen ist, gibt es ein sehr breites Themenfeld für Forschungen und die Aufbereitung dieser Daten, das offensichtlich nicht nur ein paar Wochen Arbeit beansprucht. Aber ...

Fazit der Arbeit

Die Arbeit wurde abrupt aus unabhängigen Gründen beendet. Ein Schwachpunkt dieses Projekts war meiner Meinung nach das Modem, das nicht wirklich gleichzeitig mit anderen Modems zusammenarbeiten wollte und bei jedem Booten solche Probleme verursachte. Es gibt zahlreiche andere Modemmodelle, die normalerweise im Mini PCI-e Format vorliegen und intern im Gerät installiert werden, was sie deutlich einfacher konfigurierbar macht. Aber das ist eine ganz andere Geschichte. Das Projekt war interessant und ich war sehr froh, daran teilnehmen zu können.

Gleichzeitiger Speedtest auf mehreren LTE-Modems

Quelle: habr.com

Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen 🔥 Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen | ProHoster