Während der Quarantäne wurde mir angeboten, an der Entwicklung eines Geräts zur Messung der Geschwindigkeit von LTE-Modems für mehrere Mobilfunkanbieter teilzunehmen.
Der Auftraggeber wollte die Geschwindigkeit verschiedener Anbieter in unterschiedlichen geografischen Punkten bewerten, um herauszufinden, welcher Mobilfunkanbieter am besten geeignet ist, wenn es darum geht, Geräte zu installieren, die eine LTE-Verbindung nutzen, zum Beispiel für Videoübertragungen. Dabei musste die Aufgabe so einfach und günstig wie möglich gelöst werden, ohne teure Ausrüstung.
Ich sage gleich, dass die Aufgabe nicht die einfachste und forderndste war; ich werde erzählen, auf welche Probleme ich gestoßen bin und wie ich sie gelöst habe. Also, los geht's.
Hinweis
Die Messung der Geschwindigkeit der LTE-Verbindungen ist eine recht komplexe Angelegenheit: Es ist notwendig, die richtige Ausrüstung und Methode zur Messung zu wählen und die Topologie und den Betrieb des Mobilfunknetzes gut zu verstehen. Zudem können mehrere Faktoren die Geschwindigkeit beeinflussen: die Anzahl der Abonnenten auf der Zelle, Wetterbedingungen, und selbst von Zelle zu Zelle kann die Geschwindigkeit aufgrund der Netzwerktopologie erheblich variieren. Insgesamt handelt es sich um eine Aufgabe mit einer riesigen Anzahl von Unbekannten, und nur der Mobilfunkanbieter kann sie korrekt lösen.
Ursprünglich wollte der Auftraggeber einfach einen Kurier mit den Handys der Anbieter los schicken, Messungen direkt am Telefon durchzuführen und die Ergebnisse in ein Heft zu notieren. Meine Lösung zur Messung der LTE-Netzgeschwindigkeit, obwohl nicht perfekt, erfüllt jedoch die gestellte Aufgabe.
Aufgrund des Zeitmangels habe ich Entscheidungen nicht zugunsten von Komfort oder Praktikabilität, sondern zugunsten der Geschwindigkeit der Entwicklung getroffen. Zum Beispiel wurde für den Fernzugriff ein inverses SSH eingerichtet, anstelle eines praktischeren VPNs, um Zeit bei der Konfiguration des Servers und jedes einzelnen Clients zu sparen.
Technisches Pflichtenheft
Wie im Artikel erwähnt : Arbeiten Sie niemals ohne Pflichtenheft! Niemals, nirgendwo!
Das technische Pflichtenheft war recht einfach; ich werde es ein wenig erweitern, um dem Endbenutzer zu helfen. Die Wahl der technischen Lösungen und der Ausrüstung wurde vom Auftraggeber diktiert. Also, das Pflichtenheft, nach allen Abstimmungen:
Auf Basis eines Einplatinencomputers vim2 einen Tester für die LTE-Verbindungsgeschwindigkeit über die H-Modems erstellenuawei e3372h — 153 einige Mobilfunkanbieter (von einem bis n). Außerdem müssen die Koordinaten von einem GPS-Empfänger, der über UART verbunden ist, empfangen werden. Geschwindigkeitsmessungen sind über den Dienst zu einem Tabellentyp zusammengeführt werden:
Tabelle im CSV-Format. Anschließend sollte diese Tabelle alle 6 Stunden per E-Mail versendet werden. Bei Fehlern sollte eine LED, die an GPIO angeschlossen ist, blinken.
Ich habe das Lastenheft in freier Form nach zahlreichen Abstimmungen beschrieben. Aber der Sinn der Aufgabe ist bereits erkennbar. Die Frist für alles betrug eine Woche. In der Realität verlängerte sie sich jedoch auf drei Wochen. Das ist unter der Berücksichtigung, dass ich dies nur nach meiner Hauptbeschäftigung und am Wochenende gemacht habe.
Hier möchte ich erneut darauf hinweisen, dass der Auftraggeber im Vorfeld die Nutzung eines Geschwindigkeitsmessdienstes und der Hardware vereinbart hat, was meine Möglichkeiten erheblich einschränkte. Das Budget war ebenfalls begrenzt, daher wurde nicht viel zusätzlich gekauft. So musste ich nach diesen Regeln spielen.
Architektur und Entwicklung
Das Schema ist einfach und offensichtlich. Daher lasse ich es ohne weitere Kommentare.

Das gesamte Projekt habe ich in Python realisiert, obwohl ich keinerlei Erfahrung in der Entwicklung mit dieser Sprache hatte. Ich habe sie gewählt, da es viele fertige Beispiele und Lösungen gab, die die Entwicklung beschleunigen konnten. Daher bitte ich alle professionellen Programmierer, meine ersten Erfahrungen mit Python nicht zu kritisieren, und ich bin immer bereit, konstruktive Kritik zu hören, um meine Fähigkeiten zu verbessern.
Außerdem habe ich während des Prozesses entdeckt, dass Python zwei gängige Versionen 2 und 3 hat, und habe mich schließlich für die dritte entschieden.
Hardwarekomponenten
Einplatinencomputer Vim2
Als Hauptmaschine wurde mir ein Einplatinencomputer zur Verfügung gestellt.

Ein hervorragender, leistungsstarker Media-Controller für Smart Homes und SMART-TV, der jedoch für diese Aufgabe selten geeignet ist, um es milde auszudrücken, oder sagen wir, nur schwach geeignet. Zum Beispiel ist sein Hauptbetriebssystem Android, während Linux ein zusätzliches Betriebssystem ist, und daher garantiert niemand die ordnungsgemäße Funktion aller Bauteile und Treiber unter Linux. Ich vermute, dass einige Probleme mit den USB-Treibern dieser Plattform zusammenhingen, weshalb die Modems auf diesem Board nicht so funktionierten, wie ich es erwartet hatte. Außerdem ist die Dokumentation sehr schlecht und unübersichtlich, sodass jede Operation viel Zeit in Anspruch nahm, um in den Unterlagen zu wühlen. Selbst die grundlegendste Arbeit mit GPIO war ein mühsames Unterfangen. Zum Beispiel benötigte ich mehrere Stunden, um die LED zum Laufen zu bringen. Aber um objektiv zu sein, war es im Grunde genommen nicht wichtig, welches Einplatinen-Board es war, Hauptsache es funktionierte und verfügte über USB-Ports.
Zunächst muss ich Linux auf dieses Board installieren. Um nicht in den Untiefen der Dokumentation zu suchen, und auch für diejenigen, die sich mit diesem Einplatinen-Board auseinandersetzen werden, schreibe ich dieses Kapitel.
Es gibt zwei Möglichkeiten, Linux zu installieren: entweder auf einer externen SD-Karte oder auf einem internen MMC. Mit der Karte habe ich mich den ganzen Abend beschäftigt, ich habe einfach nicht verstanden, wie ich sie zum Laufen bringen soll, also habe ich beschlossen, es auf MMC zu installieren, obwohl es mit einer externen Karte zweifellos einfacher gewesen wäre.
Zur Firmware . Ich übersetze von einem seltsamen auf Russisch. Um das Board zu flashen, muss ich den Hardware-UART anschließen. Ich habe ihn angeschlossen
- Tool Pin GND: Pin17 von VIMs GPIO
- Tool Pin TXD: Pin18 von VIMs GPIO (Linux_Rx)
- Tool Pin RXD: Pin19 von VIMs GPIO (Linux_Tx)
- Tool Pin VCC: Pin20 von VIMs GPIO

Nachdem ich das getan hatte, habe ich die Firmware heruntergeladen . Die spezifische Firmware-Version .
Um diese Firmware zu flashen, benötige ich die entsprechenden Utensilien. Detailliertere Informationen dazu werden . Ich habe es nicht unter Windows ausprobiert, aber ich sollte ein paar Worte zur Firmware unter Linux verlieren. Zunächst werde ich die Utensilien gemäß der Anleitung installieren.
git clone https://github.com/khadas/utils
cd /path/to/utils
sudo ./INSTALLUnd ... nichts funktioniert. Ich habe ein paar Stunden damit verbracht, die Installationsskripte zu bearbeiten, damit alles bei mir korrekt installiert wird. Ich erinnere mich nicht mehr, was ich gemacht habe, aber es war auch ein ziemlicher Zirkus. Also seid vorsichtig. Aber ohne diese Utensilien macht es keinen Sinn, weiter mit Vim2 zu kämpfen. Es ist besser, sich damit gar nicht erst einzulassen!
Nach sieben Runden der Hölle, Konfigurationen der Skripte und Installation erhielt ich ein Paket funktionierender Dienstprogramme. Ich habe die Karte über USB mit meinem Linux-Computer verbunden, und der UART ist ebenfalls nach dem obigen Schema angeschlossen.
Ich konfiguriere mein Lieblingsterminal minicom auf eine Geschwindigkeit von 115200, ohne Hardware- und Software-Fehlerkontrolle. Und wir legen los.

Beim Booten des VIM2 im UART-Terminal drücke ich eine beliebige Taste, zum Beispiel die Leertaste, um den Bootvorgang zu stoppen. Sobald die Zeile erscheint,
kvim2# Gebe ich den Befehl ein:
kvim2# run updateAuf dem Host, von dem wir laden, führe ich aus:
burn-tool -v aml -b VIM2 -i VIM2_Ubuntu-server-bionic_Linux-4.9_arm64_EMMC_V20191231.imgFertig, puh. Ich habe geflasht, auf der Karte ist Linux. Benutzername/Passwort khadas:khadas.
Danach einige grundlegende Erstkonfigurationen. Für die weitere Verwendung deaktiviere ich das Passwort für sudo (ja, ist unsicher, aber bequem).
sudo visudoIch bearbeite die Zeile zu folgendem Format und speichere sie:
# Allow members of group sudo to execute any command
%sudo ALL=(ALL:ALL) NOPASSWD: ALLDanach ändere ich die aktuelle Locale, damit die Zeit nach Moskau ist, sonst wird sie nach Greenwich sein.
sudo timedatectl set-timezone Europe/Moscowoder
ln -s /usr/share/zoneinfo/Europe/Moscow /etc/localtimeWenn es Ihnen kompliziert erscheint, verwenden Sie diese Karte nicht, besser Raspberry Pi. Ehrlich.
Modem Huawei e3372h — 153
Dieses Modem hat mir ordentlich zu schaffen gemacht und wurde im Grunde das größte Nadelöhr des gesamten Projekts. Tatsächlich spiegelt der Begriff „Modem“ für diese Geräte nicht die Funktionsweise wider: Es handelt sich um ein leistungsstarkes Kombigerät, das sich als CD-ROM ausgibt, um Treiber zu installieren, und danach in den Betriebsmodus als Netzwerkkarte wechselt.
Architektonisch sieht es aus Sicht eines Linux-Nutzers nach all den Konfigurationen so aus: Nach dem Anschluss des Modems erscheint bei mir das Netzwerk-Interface eth*, das über DHCP die IP-Adresse 192.168.8.100 und das Standardgateway 192.168.8.1 erhält.
Und der wichtigste Punkt! Dieses Modemmodell kann nicht im Modus eines Modems betrieben werden, das mit AT-Befehlen gesteuert wird.Es wäre wesentlich einfacher, PPP-Verbindungen für jedes Modem einzurichten und dann damit zu arbeiten. Aber in meinem Fall erstellt der „Treiber“ (korrekt gesagt, die Linux-Treiber gemäß den udev-Regeln) automatisch ein eth-Interface und weist ihm über DHCP eine IP-Adresse zu.
Um nicht weiter verwirrt zu werden, schlage ich vor, das Wort „Modem“ zu vergessen und von Netzwerkkarte und Gateway zu sprechen, denn im Grunde handelt es sich um den Anschluss einer neuen Netzwerkkarte mit einem Gateway.
Wenn es nur ein Modem gibt, sind keine besonderen Probleme zu erwarten, aber wenn es mehr als eines gibt, also n Stück, ergibt sich folgendes Bild des Netzwerks.

Das heißt, n Netzwerkarten mit derselben IP-Adresse, wobei jeder denselben Standardgateway hat. In Wirklichkeit ist jedoch jeder von ihnen mit seinem eigenen Anbieter verbunden.
Ursprünglich hatte ich eine einfache Lösung: Mit dem Befehl ifconfig oder ip alle Schnittstellen zu deaktivieren und nacheinander einzuschalten und zu testen. Die Lösung war insgesamt gut, abgesehen davon, dass ich in den Momenten des Wechsels keine Möglichkeit hatte, mich mit dem Gerät zu verbinden. Da die Wechsel häufig und schnell sind, hatte ich tatsächlich keine Möglichkeit, mich überhaupt zu verbinden.
Deshalb habe ich mich entschieden, die IP-Adressen der Modems manuell zu ändern und den Verkehr über die Routing-Einstellungen zu leiten.

Damit endeten meine Probleme mit den Modems nicht: Bei Problemen mit der Stromversorgung fielen sie aus, es war eine stabile Stromversorgung des USB-Hubs erforderlich. Dieses Problem habe ich behoben, indem ich die Stromversorgung direkt am Hub angelötet habe. Ein weiteres Problem, das ich hatte und das das gesamte Projekt ruinierte: Nach einem Neustart oder Kaltstart wurden nicht alle Modems erkannt und nicht immer. Ich konnte nicht herausfinden, warum dies geschah und nach welchem Algorithmus. Aber dazu später mehr.
Für den ordnungsgemäßen Betrieb des Modems habe ich das Paket usb-modeswitch installiert.
sudo apt update
sudo apt install -y usb-modeswitch Nach dem Anschluss wird das Modem von der udev-Subsystem korrekt erkannt und konfiguriert. Ich überprüfe das, indem ich einfach das Modem anschließe und sicherstelle, dass das Netzwerk verfügbar ist.
Ein weiteres Problem, das ich nicht lösen konnte: Wie kann ich den Namen des Anbieters, mit dem wir arbeiten, aus diesem Modem erhalten? Der Name des Anbieters befindet sich in der Weboberfläche des Modems unter der Adresse 192.168.8.1. Das ist eine dynamische Webseite, die Daten über ajax-Anfragen erhält, so dass ich die Seite nicht einfach mit wget abrufen und den Namen parsen konnte. Also begann ich zu überlegen, wie ich die Webseite abarbeiten kann usw. und realisierte, dass ich etwas Unsinn mache. Schließlich gab ich auf und begann, den Anbieter über die API von Speedtest abzurufen.
Vieles wäre einfacher, wenn das Modem über AT-Befehle zugänglich wäre. Ich könnte es neu konfigurieren, eine PPP-Verbindung herstellen, IP zuweisen, den Telefonanbieter abrufen usw. Aber leider arbeite ich mit dem, was gegeben ist.
GPS
Der GPS-Empfänger, der mir ausgehändigt wurde, hatte eine UART-Schnittstelle und eine Stromversorgung. Es war nicht die beste Lösung, aber dennoch funktional und einfach. Der Empfänger sah ungefähr so aus.

Ehrlich gesagt, arbeite ich zum ersten Mal mit einem GPS-Empfänger, aber wie ich mir dachte, ist alles schon lange für uns durchdacht. Also nutzen wir einfach die bestehenden Lösungen.
Zunächst aktiviere ich uart_AO_B (UART_RX_AO_B, UART_TX_AO_B) für den Anschluss des GPS.
khadas@Khadas:~$ sudo fdtput -t s /dtb.img /serial@c81004e0 status okayDanach überprüfe ich den Erfolg der Operation.
khadas@Khadas:~$ fdtget /dtb.img /serial@c81004e0 status
okayDieser Befehl bearbeitet anscheinend das devtree in Echtzeit, was sehr praktisch ist.
Nach dem Erfolg dieser Operation starten wir neu und installieren den GPS-Dämon.
khadas@Khadas:~$ sudo rebootInstallation des GPS-Dämons. Ich installiere alles und schalte es sofort für die 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.socketIch bearbeite die Konfigurationsdatei.
sudo vim /etc/default/gpsdIch stelle die UART-Verbindung her, an der der GPS hängt.
DEVICES="/dev/ttyS4"Und danach schalten wir alles ein und starten es.
/* GPS daemon enable/start */
sudo systemctl enable gpsd.socket
sudo systemctl start gpsd.socketDanach schließe ich das GPS an.

In der Hand ein GPS-Kabel, unter den Fingern sind die UART-Debugger-Kabel sichtbar.
Ich starte neu und überprüfe die Funktion des GPS mit dem Programm gpsmon.

Auf diesem Screenshot sind keine Satelliten zu sehen, aber die Kommunikation mit dem GPS-Empfänger ist zu erkennen, was bedeutet, dass alles in Ordnung ist.
Ich habe viele Varianten der 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 counter = %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() # Instanziiere AGPS3-Mechanismen
agps_thread.stream_data() # Von localhost (), oder anderen Hosts, zum Beispiel (host='gps.ddns.net')
agps_thread.run_thread() # Drosselzeit zum Schlafen nach einer leeren Abfrage, standardmäßig '()' 0.2 zwei Zehntel Sekunden
Wenn ich die Koordinaten erhalten muss, geschieht dies mit folgendem Aufruf:
longitude, latitude = getPositionData(agps_thread)
Und innerhalb von 1-10 Sekunden werde ich entweder die Koordinate erhalten oder nicht. Ja, ich hatte zehn Versuche, die Koordinaten zu erhalten. Nicht optimal, ungeschickt und krumm, aber es funktioniert. Ich habe mich so entschieden, weil GPS manchmal schlecht empfängt und die Daten nicht immer erhält. Wenn man auf den Erhalt der Daten wartet, hängt das Programm an dieser Stelle, wenn man in einem geschlossenen Raum arbeitet. Deshalb habe ich diese nicht elegante Lösung umgesetzt.
Im Prinzip, wenn ich mehr Zeit gehabt hätte, könnte ich die Daten direkt über UART vom GPS erhalten, sie in einem separaten Thread parsen und mit ihnen arbeiten. Aber es war überhaupt keine Zeit, daher der hässliche, chaotische Code. Und ja, ich schäme mich nicht.
LED
Die Verbindung der LED war gleichzeitig einfach und kompliziert. Die Hauptschwierigkeit besteht darin, dass die Pin-Nummer im System nicht mit der Pin-Nummer auf der Platine übereinstimmt und weil die Dokumentation mit dem linken Fuß geschrieben wurde. Um die Hardware-Pin-Nummer mit der System-Pin-Nummer abzugleichen, muss man den Befehl ausführen:
gpio readallEs wird eine Tabelle mit der Zuordnung der Pins im System und auf der Platine ausgegeben. Danach kann ich mit dem Pin im Betriebssystem arbeiten. In meinem Fall ist die LED mit GPIOH_5.

Ich setze den GPIO-Pin in den Ausgabemodus.
gpio -g mode 421 outIch schreibe null.
gpio -g write 421 0Ich schreibe eins.
gpio -g write 421 1 
Alles leuchtet, nach dem Schreiben von "1".
#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 Fall von Fehlern error_blink() auf, und die LED blinkt schön.
Software-Knoten
Speedtest API
Es ist eine große Freude, dass der Dienst speedtest.net seine eigene Python-API hat, die man sich ansehen kann unter .
Was gut ist, ist, dass es auch Quellcodes gibt, die man sich ebenfalls ansehen kann. Wie man mit dieser API arbeitet (einfachste Beispiele) kann man im .
Ich installiere die Python-Bibliothek mit folgendem Befehl.
sudo -H pip3 install speedtest-cliZum Beispiel könnt ihr den Speedtester unter Ubuntu direkt aus den Repos installieren. Das ist die gleiche Python-Anwendung, die man dann direkt aus der Konsole starten kann.
sudo apt install speedtest-cli -yUnd die Geschwindigkeit eurer Internetverbindung messen.
speedtest-cli
Konfiguration von speedtest.net wird abgerufen...
Testen von B***** (*.*.*.*)...
Abrufen der Serverliste von speedtest.net...
Wählen des besten Servers 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
Infolgedessen, wie ich es gemacht habe. Ich musste in die Quellcodes dieses Speedtests eingreifen, um sie umfassender in mein Projekt zu integrieren. Eine der wichtigsten Aufgaben ist es, auch den Namen des Mobilfunkanbieters zu erhalten, um ihn in die Tabelle einzufügen.
import speedtest
from datetime import datetime
...
#Wir geben den spezifischen Server für den Test an
#6053) MaximaTelecom (Moscow, Russische Föderation)
servers = ["6053"]
# Wenn Sie einen ein-Thread-Test verwenden möchten
threads = None
s = speedtest.Speedtest()
#wir erhalten den Namen des Mobilfunkanbieters
opos = '%(isp)s' % s.config['client']
s.get_servers(servers)
#wir erhalten eine Textzeile 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)
#wir erhalten die Ergebnisse
s.results.share()
#Danach wird eine Zeile für die Speicherung in einer CSV-Datei formatiert.
#wir erhalten die GPS-Position
longitude, latitude = getPositionData(agps_thread)
#Uhrzeit 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 erfolgt das Schreiben in die Protokolldatei
Es stellte sich heraus, dass auch hier nicht alles so einfach ist, obwohl es zunächst einfacher schien. Der Parameter servers war ursprünglich gleich [], wähle den besten Server. Infolgedessen hatte ich zufällige Server, und wie man sich denken kann, schwankende Geschwindigkeiten. Es ist ziemlich kompliziert, einen festen Server zu verwenden; wenn ja, dann erfordert es Forschung, ob statisch oder dynamisch. Aber hier ist ein Beispiel für Geschwindigkeitstestdiagramme des Anbieters Beeline bei dynamischer Auswahl des Testservers und statisch festgelegt.

Ergebnis der Geschwindigkeitsmessung bei der Wahl eines dynamischen Servers.

Ergebnis des Geschwindigkeitstests mit einem streng ausgewählten Server.
Es gibt «Rauschen» beim Test sowohl hier als auch dort, das entfernt werden muss, wobei mathematische Methoden angewendet werden. Aber bei einem festen Server ist es etwas weniger, und die Amplitude ist stabiler.
In der Tat ist dies ein Bereich intensiver Forschung. Ich würde Geschwindigkeitsmessungen zu meinem eigenen Server mit dem Tool iperf durchführen. Aber wir halten uns an die Anforderungen.
E-Mail-Versand und Fehler
Für den E-Mail-Versand habe ich mehrere Dutzend verschiedene Varianten ausprobiert, aber letztendlich bin ich auf folgendes gestoßen. Ich habe ein Postfach bei yandex registriert und dann . Ich habe es getestet und in das Programm integriert. In diesem Beispiel werden verschiedene Optionen erläutert, einschließlich dem Versand von Gmail usw. Ich wollte mich nicht mit dem Aufsetzen meines eigenen Mailservers beschäftigen und hatte dafür keine Zeit, aber wie sich später herausstellte, war das auch vergeudete Zeit.
Die Protokolle wurden gemäß dem Planer gesendet, bei bestehender Verbindung, alle 6 Stunden: um 00 Uhr, 06 Uhr, 12 Uhr und 18 Uhr. Ich habe sie wie folgt gesendet.
from send_email import *
...
message_log = "Testprotokolle der 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')
сurtime = datetime.now().strftime('%H:%M:%S')
try:
for addr_to in EmailForSend:
send_email(addr_to, message_log, "Protokolle vom " + curdata + " " + сurtime, files)
except:
print("Netzwerkproblem beim Senden der E-Mail")
return False
return True
Fehler wurden anfangs ebenfalls gesendet. Zunächst wurden sie in einer Liste erfasst und dann ebenfalls mit dem Planer bei bestehender Verbindung gesendet. Allerdings gab es dann Probleme, da Yandex eine Begrenzung für die Anzahl der täglich gesendeten Nachrichten hat (das ist schmerzhaft, traurig und beschämend). Da es selbst in einer Minute eine große Anzahl an Fehlern geben konnte, musste ich auf das Senden von Fehlern per E-Mail verzichten. Daher sollten Sie bei der automatischen Versendung über die Yandex-Dienste auf dieses Problem achten.
Feedback-Server
Um auf die entfernte Hardware zuzugreifen und sie anpassen und umkonfigurieren zu können, benötigte ich einen externen Server. Um Fairness walten zu lassen, wäre es richtig gewesen, alle Daten auf den Server zu senden und im Web-Interface schöne Grafiken zu erstellen. Aber nicht alles auf einmal.
Als VPS habe ich ausgewählt . Man hätte den einfachsten Server wählen können. Und insgesamt würde das für meine Ziele vollkommen ausreichen. Aber da ich den Server nicht aus eigener Tasche bezahlte, entschied ich mich für einen mit ein wenig Spielraum, falls wir ein Web-Interface, einen eigenen SMTP-Server, ein VPN usw. einrichten würden. Außerdem wollte ich die Möglichkeit haben, einen Telegram-Bot zu konfigurieren und keine Probleme mit dessen Sperrungen zu haben. Daher wählte ich Amsterdam und die folgenden Parameter.

Für die Verbindung mit dem Gerät vim2 wählte ich eine umgekehrte SSH-Verbindung, und wie sich in der Praxis zeigte — das ist nicht die beste Wahl. Bei Unterbrechung der Verbindung hält der Server den Port und es ist eine Zeit lang nicht möglich, sich damit zu verbinden. Daher ist es besser, andere Verbindungsarten wie ein VPN zu nutzen. In Zukunft wollte ich auf ein VPN umsteigen, hatte aber nicht die Möglichkeit.
Ich möchte nicht ins Detail über die Konfiguration der Firewall, die Einschränkung von Rechten, das Deaktivieren der SSH-Verbindung als root und andere Grundsatzfragen zur Konfiguration eines VPS eingehen. Ich hoffe, dass Sie das bereits alles wissen. Für die Remote-Verbindung erstelle ich einen neuen Benutzer auf dem Server.
adduser vimsshAuf unserer Hardware generiere ich die SSH-Verbindungsschlüssel.
ssh-keygenUnd kopiere sie auf unseren Server.
ssh-copy-id vimssh@host.comAuf unserer Hardware richte ich eine automatische Rück-SSH-Verbindung bei jedem Boot ein.
[Unit]
Beschreibung=Automatisches Rückwärts-SSH
Benötigt=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=immer
[Install]
WantedBy=multi-user.target
Beachten Sie den Port 8083: er bestimmt, über welchen Port die Verbindung über die Rück-SSH hergestellt wird. Wir fügen es zum Autostart hinzu und starten es.
sudo systemctl enable autossh.service
sudo systemctl start autossh.serviceMan kann sogar den Status sehen:
sudo systemctl status autossh.serviceJetzt, auf unserem VPS-Server, wenn ich ausführe:
ssh -p 8083 khadas@localhostDann gelange ich auf meine Testhardware. Von der Hardware aus kann ich ebenfalls Protokolle und beliebige Daten über SSH an meinen Server senden, was sehr bequem ist.
Alles zusammenfassen

Einleitung, wir beginnen mit der Entwicklung und dem Debugging
Puh, ich habe anscheinend alles beschrieben. Jetzt ist es an der Zeit, das Ganze in eine Einheit zu bringen. Den Code können Sie ansehen .
Ein wichtiger Punkt zum Code: Dieses Projekt kann so «in den Raum geworfen» nicht gestartet werden, da es für eine bestimmte Aufgabe und Architektur optimiert wurde. Auch wenn ich die Quellcodes bereitstelle, werde ich doch das Wertvollste hier direkt im Text erklären, sonst bleibt es völlig unklar.
Am Anfang steht die Initialisierung von GPS, GPIO und der Start eines separaten Planungs-Threads.
#запуск потока планировщика
pShedulerThread = threading.Thread(target=ShedulerThread, args=(1,))
pShedulerThread.start()Der Scheduler ist ziemlich einfach: Er prüft, ob es Zeit zum Senden von Nachrichten ist und welchen Fehlerstatus es gerade gibt. Wenn es ein Fehlerflag gibt, blinken wir mit der 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 komplizierteste Punkt in diesem Projekt besteht darin, die Rück-SSH-Verbindung bei jedem Test aufrechtzuerhalten. Bei jedem Test wird das Standard-Gateway und der DNS-Server neu konfiguriert. Da sowieso niemand liest, wissen Sie, dass der Zug nicht auf hölzernen Gleisen fährt. Wer das Easter Egg findet, bekommt ein Bonbon.
Dafür erstelle ich eine separate Routing-Tabelle —set-mark 0x2 und eine Regel zum Umleiten 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 .
Danach gehe ich in eine Endlosschleife, in der ich jedes Mal die Liste der angeschlossenen Modems abrufe (um herauszufinden, 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_listNachdem ich die Liste erhalten habe, weise ich allen Interfaces IP-Adressen zu, wie ich es im Bild im Kapitel über Modems 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")Dann gehe ich einfach in einer Schleife durch jedes Interface und konfiguriere es.
for iface in network_list:
ConfigNetwork(iface)def ConfigNetwork(iface):
#reset all settings
cmd_run("sudo ip route flush all")
#set default gateway
cmd_run("sudo route add default gw 192.168.8.1 " + iface)
#specify DNS server (needed for speedtest)
cmd_run ("sudo bash -c 'echo nameserver 8.8.8.8 > \/etc\/resolv.conf'")Ich überprüfe das Interface auf Funktionsfähigkeit. Gibt es kein Netzwerk, forme ich Fehler. Wenn ein Netzwerk vorhanden ist, ist es Zeit zu handeln!
Hier konfiguriere ich die SSH-Routing auf diesem Interface (falls noch nicht geschehen), sende Fehler an den Server, und wenn die Zeit gekommen ist, sende ich Protokolle und führe letztendlich einen Speedtest durch und speichere die Protokolle in einer CSV-Datei.
if not NetworkAvalible():
....
#Hier formulieren wir Fehler
....
else: #Netzwerk vorhanden, hurra, wir arbeiten!
#Falls wir ein problematisches Interface haben, auf dem SSH läuft, ändern wir es
if (sshint == lastbanint or sshint =="free"):
print("********** Setup SSH ********************")
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, lass uns schnell alles senden!!!
if ready_to_send:
print ("**** Bereit zum Senden!!!")
if sendLogs():
ready_to_send = False
if error_status:
SendErrors()
#und dann testen wir die Geschwindigkeit und speichern die Protokolle. Es sei nur gesagt, dass es die Funktion zur Einstellung von Reverse SSH gibt.
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 müssen wir all diese Schönheit zur Autostart hinzufügen. Dafür erstelle ich eine Datei:
sudo vim \/etc\/systemd\/system\/modems_speedtest.serviceUnd schreibe folgendes hinein:
[Unit]
Beschreibung=Modemgeschwindigkeitstest
Benötigt=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=immer
[Install]
WantedBy=multi-user.target
Ich aktiviere den Autostart und starte!
sudo systemctl enable modems_speedtest.service
sudo systemctl start modems_speedtest.serviceJetzt kann ich die Protokolle dessen, was passiert, mit dem Befehl verfolgen:
journalctl -u modems_speedtest.service --no-pager -fErgebnisse
Nun, was ist als Ergebnis herausgekommen? Ich möchte einige Grafiken zeigen, die ich während der Entwicklung und Anpassung aufnehmen konnte. Die Grafiken wurden mit Hilfe von gnuplot mit folgendem Skript 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 war mit dem Anbieter Tele2, die ich über mehrere Tage durchgeführt habe.

Hier habe ich einen dynamischen Messserver verwendet. Die Geschwindigkeitsmessungen funktionieren, schwanken jedoch stark, aber es ist dennoch eine gewisse Durchschnittszahl zu erkennen, die durch Datenfilterung, zum Beispiel mit gleitendem Durchschnitt, erhalten werden kann.
Später habe ich eine Reihe weiterer Grafiken für andere Mobilfunkanbieter erstellt. Der Testserver war in diesem Fall bereits einer, und die Ergebnisse sind ebenfalls sehr interessant.




Wie man sieht, ist das Thema sehr umfangreich für Forschungen und die Verarbeitung dieser Daten und offensichtlich nicht geeignet für nur ein paar Wochen Arbeit. Aber...
Ergebnisse der Arbeit
Die Arbeit wurde abrupt aufgrund von Umständen, die nicht in meiner Kontrolle waren, beendet. Einer der Schwachpunkte dieses Projekts war aus meiner subjektiven Sicht das Modem, das nicht gut mit anderen Modems gleichzeitig arbeiten wollte und bei jedem Neustart solche Schwierigkeiten machte. Für diese Zwecke gibt es eine riesige Anzahl anderer Modemtypen, die normalerweise bereits im Mini PCI-e-Format vorliegen und im Gerät installiert werden, sowie viel einfacher zu konfigurieren sind. Aber das ist eine ganz andere Geschichte. Das Projekt war interessant, und ich war sehr froh, dass ich daran teilnehmen konnte.
Quelle: habr.com

