Speedtest simultané sur plusieurs modems LTE

Pendant la quarantaine, on m'a proposé de participer au développement d'un appareil de mesure de la vitesse des modems LTE pour plusieurs opérateurs cellulaires.

Speedtest simultané sur plusieurs modems LTE

Le client souhaitait évaluer la vitesse de différents opérateurs de télécommunications dans différentes zones géographiques afin de pouvoir comprendre quel opérateur cellulaire lui convenait le mieux lors de l'installation d'équipements utilisant une connexion LTE, par exemple pour la diffusion vidéo. Dans le même temps, le problème devait être résolu aussi simplement et à moindre coût que possible, sans équipement coûteux.

Je dirai tout de suite que la tâche n'est pas la plus simple et la plus gourmande en connaissances, je vais vous dire quels problèmes j'ai rencontrés et comment je les ai résolus. Alors allons-y.

Noter

Mesurer la vitesse d'une connexion LTE est une affaire très complexe : il faut choisir le bon équipement et la bonne technique de mesure, mais aussi avoir une bonne compréhension de la topologie et du fonctionnement du réseau cellulaire. De plus, la vitesse peut être influencée par plusieurs facteurs : le nombre d'abonnés sur une cellule, les conditions météorologiques, même d'une cellule à l'autre, la vitesse peut varier considérablement en raison de la topologie du réseau. En général, il s'agit d'un problème comportant un grand nombre d'inconnues et seul un opérateur télécom peut le résoudre correctement.

Au départ, le client souhaitait simplement conduire le coursier avec les téléphones des opérateurs, prendre des mesures directement sur le téléphone, puis noter les résultats des mesures de vitesse dans un carnet. Ma solution pour mesurer la vitesse des réseaux LTE, bien que non idéale, résout le problème.

Par manque de temps, j'ai pris des décisions non pas en faveur de la commodité ou de l'aspect pratique, mais en faveur de la rapidité de développement. Par exemple, le ssh inversé a été utilisé pour l'accès à distance, au lieu du VPN, plus pratique, afin de gagner du temps sur la configuration du serveur et de chaque client individuel.

Termes de référence

Comme indiqué dans l'article Sans spécifications techniques : pourquoi le client n’en veut pas: Ne travaillez pas sans spécifications techniques ! Jamais, nulle part !

La tâche technique était assez simple, je vais la développer un peu pour la compréhension de l'utilisateur final. Le choix des solutions techniques et des équipements a été dicté par le client. Ainsi, la spécification technique elle-même, après toutes les approbations :

Basé sur un ordinateur monocarte vim2 réaliser un testeur de vitesse pour les connexions LTE via des modems HHuawei E3372h - 153 plusieurs opérateurs télécoms (de un à n). Il est également nécessaire de recevoir les coordonnées d'un récepteur GPS connecté via UART. Effectuer des mesures de vitesse en utilisant le service www.speedtest.net et mettez-les dans un tableau comme :

Speedtest simultané sur plusieurs modems LTE

Tableau au format csv. Envoyez ensuite ce panneau par e-mail toutes les 6 heures. En cas d'erreur, faites clignoter la LED connectée au GPIO.

J'ai décrit les spécifications techniques sous forme libre, après de nombreuses approbations. Mais le sens de la tâche est déjà visible. Une semaine était donnée pour tout. Mais en réalité, cela a duré trois semaines. Cela tient compte du fait que je ne faisais cela qu'après mon travail principal et le week-end.

Ici, je tiens une fois de plus à attirer l'attention sur le fait que le client a accepté à l'avance l'utilisation du service et du matériel de mesure de vitesse, ce qui a considérablement limité mes capacités. Le budget était également limité, donc rien de spécial n'a été acheté. Nous avons donc dû respecter ces règles.

Architecture et développement

Le schéma est simple et évident. Je le laisserai donc sans commentaires particuliers.

Speedtest simultané sur plusieurs modems LTE

J'ai décidé d'implémenter l'intégralité du projet en python, malgré le fait que je n'avais aucune expérience en développement dans ce langage. Je l'ai choisi car il existait de nombreux exemples et solutions prêts à l'emploi qui pourraient accélérer le développement. Par conséquent, je demande à tous les programmeurs professionnels de ne pas gronder ma première expérience de développement en python, et je suis toujours heureux d'entendre des critiques constructives pour améliorer mes compétences.

Au cours du processus, j'ai également découvert que Python avait deux versions en cours d'exécution, 2 et 3, j'ai donc opté pour la troisième.

Nœuds matériels

Vim2 à plaque unique

On m'a donné un ordinateur monocarte comme machine principale vim2

Speedtest simultané sur plusieurs modems LTE

Un processeur multimédia excellent et puissant pour une maison intelligente et une SMART-TV, mais extrêmement inadapté à cette tâche, ou, disons, mal adapté. Par exemple, son système d'exploitation principal est Android et Linux est un système d'exploitation secondaire et, par conséquent, personne ne garantit le fonctionnement de haute qualité de tous les nœuds et pilotes sous Linux. Et je suppose que certains des problèmes étaient liés aux pilotes USB de cette plate-forme, donc les modems n'ont pas fonctionné comme prévu sur cette carte. Il dispose également d'une documentation très pauvre et dispersée, de sorte que chaque opération a pris beaucoup de temps à fouiller les quais. Même un travail ordinaire avec GPIO demandait beaucoup de sang. Par exemple, il m'a fallu plusieurs heures pour configurer la LED. Mais, pour être objectif, peu importe de quel type de carte il s'agissait, l'essentiel était qu'elle fonctionnait et qu'il y ait des ports USB.

Tout d'abord, je dois installer Linux sur cette carte. Afin de ne pas parcourir les profondeurs de la documentation pour tout le monde, et aussi pour ceux qui auront affaire à ce système monocarte, j'écris ce chapitre.

Il existe deux options pour installer Linux : sur une carte SD externe ou sur une MMC interne. J'ai passé la soirée à essayer de comprendre comment le faire fonctionner avec la carte, j'ai donc décidé de l'installer sur la MMC, même si ce serait sans aucun doute beaucoup plus simple de travailler avec une carte externe.

À propos du micrologiciel dit de manière tordue ici. Je traduis d'étrange vers le russe. Afin de flasher la carte, je dois connecter le matériel UART. Je l'ai connecté comme suit.

  • Outil Pin GND : <—> Pin17 du GPIO des VIM
  • Outil Pin TXD : <—> Pin18 du GPIO des VIM (Linux_Rx)
  • Outil Pin RXD : <—> Pin19 du GPIO des VIM (Linux_Tx)
  • Outil Pin VCC : <—> Pin20 du GPIO des VIM

Speedtest simultané sur plusieurs modems LTE

Après quoi, j'ai téléchargé le firmware par conséquent,. Version spécifique du micrologiciel VIM1_Ubuntu-server-bionic_Linux-4.9_arm64_EMMC_V20191231.

Pour télécharger ce firmware, j'ai besoin d'utilitaires. Plus de détails à ce sujet ici. Je n'ai pas essayé de le flasher sous Windows, mais je dois vous dire quelques mots sur le firmware sous Linux. Tout d’abord, je vais installer les utilitaires selon les instructions.

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

Aaand... Rien ne fonctionne. J'ai passé quelques heures à modifier les scripts d'installation pour que tout s'installe correctement pour moi. Je ne me souviens pas de ce que j’ai fait là-bas, mais il y avait aussi ce cirque avec des chevaux. Donc sois prudent. Mais sans ces utilitaires, cela ne sert à rien de torturer davantage vim2. Il vaut mieux ne pas le déranger du tout !

Après sept cercles d'enfer, de configuration et d'installation du script, j'ai reçu un package d'utilitaires fonctionnels. J'ai connecté la carte via USB à mon ordinateur Linux et j'ai également connecté l'UART selon le schéma ci-dessus.
Je configure mon terminal minicom préféré pour une vitesse de 115200 XNUMX, sans contrôle des erreurs matérielles et logicielles. Et commençons.

Speedtest simultané sur plusieurs modems LTE

Lors du chargement de VIM2 dans le terminal UART, j'appuie sur une touche, comme la barre d'espace, pour arrêter le chargement. Après l'apparition de la ligne

kvim2# 

Je rentre la commande :

kvim2# run update

Sur l'hôte à partir duquel nous chargeons, j'exécute :

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

Ça y est, ouf. J'ai vérifié, il y a Linux sur la carte. Nom d'utilisateur/mot de passe khadas:khadas.

Après cela, quelques réglages initiaux mineurs. Pour des travaux ultérieurs, je désactive le mot de passe pour sudo (oui, pas sécurisé, mais pratique).

sudo visudo

Je modifie la ligne dans le formulaire et j'enregistre

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

Ensuite, je change les paramètres régionaux actuels pour que l'heure soit à Moscou, sinon ce sera à Greenwich.

sudo timedatectl set-timezone Europe/Moscow

ou

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

Si vous trouvez cela difficile, n'utilisez pas cette carte, Raspberry Pi est meilleur. Honnêtement.

Modem Huawei e3372h – 153

Ce modem a été pour moi une source de sang importante et, en fait, il est devenu le goulot d'étranglement de tout le projet. En général, le nom « modem » pour ces appareils ne reflète pas du tout l'essence du travail : il s'agit d'une puissante moissonneuse-batteuse, ce matériel possède un périphérique composite qui se fait passer pour un CD-ROM afin d'installer les pilotes, puis passe en mode carte réseau.

Architecturalement, du point de vue d'un utilisateur Linux, après tous les réglages, cela ressemble à ceci : après avoir connecté le modem, j'ai une interface réseau eth*, qui via DHCP reçoit l'adresse IP 192.168.8.100, et la passerelle par défaut est 192.168.8.1.

Et le moment le plus important ! Ce modèle de modem ne peut pas fonctionner en mode modem, qui est contrôlé par les commandes AT. Tout serait beaucoup plus simple, créez des connexions PPP pour chaque modem puis exploitez-les. Mais dans mon cas, « lui-même » (plus précisément, un plongeur Linux selon les règles udev), crée une interface eth et lui attribue une adresse IP via DHCP.

Pour éviter davantage de confusion, je suggère d’oublier le mot « modem » et de dire carte réseau et passerelle, car en substance, cela revient à connecter une nouvelle carte réseau à une passerelle.
Lorsqu'il y a un modem, cela ne pose pas de problèmes particuliers, mais lorsqu'il y en a plusieurs, à savoir n pièces, l'image de réseau suivante apparaît.

Speedtest simultané sur plusieurs modems LTE

C'est-à-dire n cartes réseau, avec la même adresse IP, chacune avec la même passerelle par défaut. Mais en réalité, chacun d’eux est connecté à son propre opérateur.

Au départ, j'avais une solution simple : à l'aide de la commande ifconfig ou ip, désactivez toutes les interfaces et activez-en simplement une à tour de rôle et testez-la. La solution était bonne pour tout le monde, sauf que pendant les moments de commutation, je ne parvenais pas à me connecter à l'appareil. Et comme les changements sont fréquents et rapides, je n’ai en réalité aucune possibilité de me connecter.

Par conséquent, j'ai choisi la voie consistant à modifier manuellement les adresses IP des modems, puis à générer du trafic à l'aide des paramètres de routage.

Speedtest simultané sur plusieurs modems LTE

Ce n'était pas la fin de mes problèmes avec les modems : en cas de problèmes d'alimentation, ils tombaient et une bonne alimentation stable au hub USB était nécessaire. J'ai résolu ce problème en soudant dur l'alimentation directement au hub. Autre problème que j'ai rencontré et qui a ruiné tout le projet : après un redémarrage ou un démarrage à froid de l'appareil, tous les modems n'étaient pas détectés et pas toujours, et je n'ai pas pu déterminer pourquoi cela s'est produit et par quel algorithme. Mais tout d’abord.

Pour que le modem fonctionne correctement, j'ai installé le package usb-modeswitch.

sudo apt update
sudo apt install -y usb-modeswitch

Après quoi, après la connexion, le modem sera correctement détecté et configuré par le sous-système udev. Je vérifie en connectant simplement le modem et en m'assurant que le réseau apparaît.
Autre problème que je n'ai pas pu résoudre : comment puis-je obtenir le nom de l'opérateur avec lequel nous travaillons depuis ce modem ? Le nom de l'opérateur est contenu dans l'interface Web du modem à l'adresse 192.168.8.1. Il s'agit d'une page Web dynamique qui reçoit des données via des requêtes Ajax, donc simplement récupérer la page et analyser le nom ne fonctionnera pas. J'ai donc commencé à chercher comment développer une page Web, etc., et j'ai réalisé que je faisais une sorte de bêtise. En conséquence, il a craché et l'opérateur a commencé à recevoir en utilisant l'API Speedtest elle-même.

Ce serait beaucoup plus facile si le modem avait accès via les commandes AT. Il serait possible de le reconfigurer, de créer une connexion ppp, d'attribuer une IP, d'obtenir un opérateur télécom, etc. Mais hélas, je travaille avec ce qu’on m’a donné.

GPS

Le récepteur GPS qu'on m'a donné avait une interface et une alimentation UART. Ce n’était pas la meilleure solution, mais elle restait néanmoins réalisable et simple. Le récepteur ressemblait à ceci.

Speedtest simultané sur plusieurs modems LTE

Pour être honnête, c'était la première fois que je travaillais avec un récepteur GPS, mais comme je m'y attendais, tout avait été pensé pour nous il y a longtemps. Nous utilisons donc simplement des solutions toutes faites.

Tout d'abord, j'active uart_AO_B (UART_RX_AO_B, UART_TX_AO_B) pour connecter le GPS.

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

Ensuite, je vérifie le succès de l'opération.

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

Cette commande édite apparemment le devtree à la volée, ce qui est très pratique.

Après le succès de cette opération, redémarrez et installez le démon GPS.

khadas@Khadas:~$ sudo reboot

Installation du démon GPS. J'installe tout et je le coupe immédiatement pour une configuration ultérieure.

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

Modification du fichier de paramètres.

sudo vim /etc/default/gpsd

J'installe un UART sur lequel le GPS sera accroché.

DEVICES="/dev/ttyS4"

Et puis nous allumons tout et commençons.

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

Après cela, je connecte le GPS.

Speedtest simultané sur plusieurs modems LTE

Le fil GPS est dans mes mains, les fils du débogueur UART sont visibles sous mes doigts.

Je redémarre et vérifie le fonctionnement du GPS à l'aide du programme gpsmon.

Speedtest simultané sur plusieurs modems LTE

Vous ne pouvez pas voir les satellites sur cette capture d'écran, mais vous pouvez voir la communication avec le récepteur GPS, ce qui signifie que tout va bien.

En python, j'ai essayé de nombreuses options pour travailler avec ce démon, mais j'ai opté pour celle qui fonctionnait correctement avec python 3.

J'installe la bibliothèque nécessaire.

sudo -H pip3 install gps3 

Et je sculpte le code du travail.

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 ("Wait gps counter = %d" % counter)
		if counter == 10:
			ErrorMessage("Ошибка GPS приемника!!!")
			return "NA", "NA"
		time.sleep(1.0)
...
f __name__ == '__main__':
...
	#gps
	agps_thread = AGPS3mechanism()  # Instantiate AGPS3 Mechanisms
	agps_thread.stream_data()  # From localhost (), or other hosts, by example, (host='gps.ddns.net')
	agps_thread.run_thread()  # Throttle time to sleep after an empty lookup, default '()' 0.2 two tenths of a second

Si j'ai besoin d'obtenir des coordonnées, cela se fait avec l'appel suivant :

longitude, latitude = getPositionData(agps_thread)

Et dans 1 à 10 secondes, j'obtiendrai les coordonnées ou non. Oui, j'ai eu dix tentatives pour obtenir les coordonnées. Pas optimal, tordu et de travers, mais ça marche. J'ai décidé de le faire car le GPS peut avoir une mauvaise réception et ne pas toujours recevoir de données. Si vous attendez de recevoir des données, si vous travaillez dans une pièce distante, le programme se bloquera à cet endroit. Par conséquent, j'ai mis en œuvre cette option peu élégante.

En principe, s'il y avait plus de temps, il serait possible de recevoir des données du GPS directement via UART, de les analyser dans un thread séparé et de travailler avec. Mais il n’y avait pas de temps du tout, d’où le code brutalement laid. Et oui, je n'ai pas honte.

Diode électro-luminescente

La connexion de la LED était à la fois simple et difficile. La principale difficulté est que le numéro de broche dans le système ne correspond pas au numéro de broche sur la carte et parce que la documentation est écrite de la main gauche. Pour comparer le numéro de broche matériel et le numéro de broche dans le système d'exploitation, vous devez exécuter la commande :

gpio readall

Un tableau de correspondance des broches dans le système et sur le tableau sera affiché. Après quoi, je peux déjà utiliser la broche dans le système d'exploitation lui-même. Dans mon cas, la LED est connectée à GPIOH_5.

Speedtest simultané sur plusieurs modems LTE

Je passe la broche GPIO en mode sortie.

gpio -g mode 421 out

J'écris zéro.

gpio -g write 421 0

J'en écris un.

gpio -g write 421 1

Speedtest simultané sur plusieurs modems LTE
Tout est allumé, après avoir écrit "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)

Maintenant, en cas d'erreurs, j'appelle error_blink() et la LED clignote magnifiquement.

Nœuds logiciels

API de test de vitesse

C'est une grande joie que le service speedtest.net ait sa propre API python, vous pouvez consulter Github.

La bonne nouvelle est qu'il existe des codes sources qui peuvent également être consultés. Comment travailler avec cette API (exemples simples) peut être trouvé dans rubrique pertinente.

J'installe la bibliothèque python avec la commande suivante.

sudo -H pip3 install speedtest-cli

Par exemple, vous pouvez même installer un testeur de vitesse dans Ubuntu directement depuis le logiciel. Il s’agit de la même application python, qui peut ensuite être lancée directement depuis la console.

sudo apt install speedtest-cli -y

Et mesurez votre vitesse Internet.

speedtest-cli
Retrieving speedtest.net configuration...
Testing from B***** (*.*.*.*)...
Retrieving speedtest.net server list...
Selecting best server based on ping...
Hosted by MTS (Moscow) [0.12 km]: 11.8 ms
Testing download speed................................................................................
Download: 7.10 Mbit/s
Testing upload speed......................................................................................................
Upload: 3.86 Mbit/s

En conséquence, tout comme moi. J'ai dû entrer dans les codes sources de ce test de vitesse afin de les implémenter plus pleinement dans mon projet. L'une des tâches les plus importantes consiste à obtenir le nom de l'opérateur télécom afin de le substituer dans la plaque.

import speedtest
from datetime import datetime
...
#Указываем конкретный сервер для теста
#6053) MaximaTelecom (Moscow, Russian Federation)
servers = ["6053"]
# If you want to use a single threaded test
threads = None
s = speedtest.Speedtest()
#получаем имя оператора сотовой связи
opos = '%(isp)s' % s.config['client']
s.get_servers(servers)
#получаем текстовую строку с параметрами сервера
testserver = '%(sponsor)s (%(name)s) [%(d)0.2f km]: %(latency)s ms' % s.results.server
#тест загрузки
s.download(threads=threads)
#тест выгрузки
s.upload(threads=threads)
#получаем результаты
s.results.share()

#После чего формируется строка для записи в csv-файл.
#получаем позицию GPS
longitude, latitude = getPositionData(agps_thread)
#время и дата
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"
#тут идет запись в файл логов

Ici aussi, tout s'est avéré pas si simple, même si cela semblerait beaucoup plus simple. Initialement, le paramètre des serveurs était égal à [], disent-ils, choisissez le meilleur serveur. En conséquence, j'avais des serveurs aléatoires et, comme vous pouvez le deviner, à vitesse variable. C'est un sujet assez complexe, l'utilisation d'un serveur fixe, qu'il soit statique ou dynamique, nécessite des recherches. Mais voici un exemple de graphiques de mesure de vitesse pour un opérateur Beeline lors de la sélection dynamique d'un serveur de test et d'un serveur fixe statiquement.

Speedtest simultané sur plusieurs modems LTE
Le résultat de la mesure de la vitesse lors du choix d’un serveur dynamique.

Speedtest simultané sur plusieurs modems LTE
Le résultat de tests de vitesse, avec un serveur strictement sélectionné.

Lors des tests, il y a de la « fourrure » aux deux endroits et elle doit être éliminée à l’aide de méthodes mathématiques. Mais avec un serveur fixe c'est un peu moins et l'amplitude est plus stable.
En général, c'est un lieu de grande recherche. Et je mesurerais la vitesse de mon serveur à l'aide de l'utilitaire iperf. Mais nous nous en tenons aux spécifications techniques.

Envoi de mail et erreurs

Pour envoyer du courrier, j'ai essayé plusieurs dizaines d'options différentes, mais j'ai finalement opté pour la suivante. J'ai enregistré une boîte aux lettres sur Yandex, puis j'ai pris Ceci est un exemple d'envoi de courrier. Je l'ai vérifié et implémenté dans le programme. Cet exemple examine diverses options, notamment l'envoi depuis Gmail, etc. Je ne voulais pas m'embêter à configurer mon serveur de messagerie et je n'avais pas le temps pour cela, mais comme il s'est avéré plus tard, c'était également en vain.

Les logs ont été envoyés selon le planificateur, s'il y a une connexion, toutes les 6 heures : à 00h, 06h, 12h et 18h. Envoyé comme suit.

from send_email import *
...
message_log = "Логи тестирования платы №1"
EmailForSend = ["[email protected]", "[email protected]"]
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, "Логи за " + curdata + " " + сurtime, files)
	except:
		print("Network problem for send mail")
		return False
	return True

Des erreurs ont également été envoyées initialement. Pour commencer, ils étaient accumulés dans la liste, puis envoyés également à l'aide du planificateur, s'il y avait une connexion. Cependant, des problèmes sont survenus du fait que Yandex a une limite sur le nombre de messages envoyés par jour (c'est la douleur, la tristesse et l'humiliation). Comme il pouvait y avoir un grand nombre d'erreurs même par minute, nous avons dû abandonner l'envoi d'erreurs par courrier. Gardez donc à l'esprit lorsque vous envoyez automatiquement des informations sur un tel problème via les services Yandex.

Serveur de commentaires

Afin d'avoir accès à un matériel distant et de pouvoir le personnaliser et le reconfigurer, j'avais besoin d'un serveur externe. En général, pour être honnête, il serait correct d'envoyer toutes les données au serveur et de créer tous les beaux graphiques dans l'interface Web. Mais pas tout à la fois.

Pour VPS j'ai choisi ruvds.com. Vous pouvez prendre le serveur le plus simple. Et en général, pour mes besoins, cela suffirait. Mais comme je n'ai pas payé le serveur de ma poche, j'ai décidé de le prendre avec une petite réserve pour que ce soit suffisant si nous devions déployer une interface web, notre propre serveur SMTP, VPN, etc. De plus, vous pourrez configurer un bot Telegram sans avoir de problèmes de blocage. J'ai donc choisi Amsterdam et les paramètres suivants.

Speedtest simultané sur plusieurs modems LTE

Comme méthode de communication avec le matériel, vim2 a choisi une connexion SSH inversée et, comme la pratique l'a montré, ce n'est pas la meilleure. Si la connexion est perdue, le serveur conserve le port et il est impossible de s'y connecter pendant un certain temps. Par conséquent, il est toujours préférable d’utiliser d’autres méthodes de communication, par exemple VPN. À l’avenir, je voulais passer au VPN, mais je n’avais pas le temps.

Je n'entrerai pas dans les détails de la configuration d'un pare-feu, de la restriction des droits, de la désactivation des connexions root ssh et d'autres truismes liés à la configuration d'un VPS. J'aimerais croire que vous savez déjà tout. Pour une connexion à distance, je crée un nouvel utilisateur sur le serveur.

adduser vimssh

Je génère des clés de connexion ssh sur notre matériel.

ssh-keygen

Et je les copie sur notre serveur.

ssh-copy-id [email protected]

Sur notre matériel, je crée une connexion SSH inversée automatique à chaque démarrage.

[Unit] Description=Auto Reverse SSH
Requires=systemd-networkd-wait-online.service
After=systemd-networkd-wait-online.service
[Service] User=khadas
ExecStart=/usr/bin/ssh -NT -o ExitOnForwardFailure=yes -o ServerAliveInterval=60 -CD 8080 -R 8083:localhost:22 [email protected]
RestartSec=5
Restart=always
[Install] WantedBy=multi-user.target

Faites attention au port 8083 : il détermine quel port je vais utiliser pour me connecter via ssh inversé. Ajoutez-le au démarrage et démarrez.

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

Vous pouvez même voir le statut :

sudo systemctl status autossh.service

Maintenant, sur notre serveur VPS, si nous exécutons :

ssh -p 8083 khadas@localhost

Ensuite, j'arrive à mon matériel de test. Et depuis le matériel, je peux également envoyer des journaux et des données via ssh à mon serveur, ce qui est très pratique.

Tout mettre ensemble

Speedtest simultané sur plusieurs modems LTE
Allumage, commençons le développement et le débogage

Ouf, et bien ça y est, j'ai décrit tous les nœuds. Il est maintenant temps de tout mettre en place. Vous pouvez voir le code ici.

Un point important avec le code : ce projet ne peut pas démarrer comme ça, car il a été conçu pour une tâche spécifique, d'une architecture spécifique. Même si je donne le code source, je vais quand même expliquer ici les choses les plus précieuses, directement dans le texte, sinon c'est complètement incompréhensible.

Au début, j'initialise gps, gpio et lance un thread de planification séparé.

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

Le planificateur est assez simple : il regarde si le moment est venu d'envoyer des messages et quel est l'état d'erreur actuel. S'il y a un indicateur d'erreur, nous faisons clignoter la 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)

La partie la plus difficile de ce projet consiste à maintenir la connexion SSH inversée pour chaque test. Chaque test implique de reconfigurer la passerelle par défaut et le serveur DNS. Puisque personne ne lit de toute façon, sachez que le train ne roule pas sur des rails en bois. Celui qui trouve l'œuf de Pâques reçoit des bonbons.

Pour ce faire, je crée une table de routage distincte -set-mark 0x2 et une règle pour rediriger le trafic.

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")

Vous pouvez en savoir plus sur son fonctionnement lire dans cet article.

Après quoi je rentre dans une boucle sans fin, où à chaque fois on obtient une liste des modems connectés (pour savoir si la configuration réseau a subitement changé).

network_list = getNetworklist()

Obtenir une liste d’interfaces réseau est assez simple.

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

Après avoir reçu la liste, j'ai défini les adresses IP de toutes les interfaces, comme je l'ai montré sur l'image du chapitre sur le modem.

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")

Ensuite, je parcours simplement chaque interface en boucle. Et je configure chaque interface.

	for iface in network_list:
		ConfigNetwork(iface)

def ConfigNetwork(iface):
#сбрасываем все настройки
		cmd_run("sudo ip route flush all")
#Назначаем шлюз по умолчанию
		cmd_run("sudo route add default gw 192.168.8.1 " + iface)
#задаем dns-сервер (это нужно для работы speedtest)
		cmd_run ("sudo bash -c 'echo nameserver 8.8.8.8 > /etc/resolv.conf'")

Je vérifie la fonctionnalité de l'interface, s'il n'y a pas de réseau, alors je génère des erreurs. S’il existe un réseau, alors il est temps d’agir !

Ici, je configure le routage ssh vers cette interface (si cela n'a pas été fait), j'envoie les erreurs au serveur si le moment est venu, j'envoie les logs et enfin j'exécute un speedtest et j'enregistre les logs dans un fichier csv.

if not NetworkAvalible():
....
#Здесь мы формируем ошибки
....
else: #Есть сеть, ура, работаем!
#Если у нас проблемный интерфейс, на котором ssh, то меняем его
  if (sshint == lastbanint or sshint =="free"):
    print("********** Setup SSH ********************")
    if sshint !="free":
      сmd_run("sudo ip route del default via 192.168.8.1 dev " + sshint +" table 102")
    SetupReverseSSH(iface)
    sshint = iface
#раз сетка работает, то давай срочно все отправим!!!
    if ready_to_send:
      print ("**** Ready to send!!!")
        if sendLogs():
          ready_to_send = False
        if error_status:
          SendErrors()
#и далее тестируем скорость и сохраняем логи. 

Il convient de mentionner la fonction de configuration de Reverse SSH.

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")

Et bien sûr, vous devez ajouter toute cette beauté au démarrage. Pour ce faire je crée un fichier :

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

Et j'y écris :

[Unit] Description=Modem Speed Test
Requires=systemd-networkd-wait-online.service
After=systemd-networkd-wait-online.service
[Service] User=khadas
ExecStart=/usr/bin/python3.6 /home/khadas/modems_speedtest/networks.py
RestartSec=5
Restart=always
[Install] WantedBy=multi-user.target

J'active le chargement automatique et je démarre !

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

Maintenant, je peux voir les journaux de ce qui se passe en utilisant la commande :

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

résultats

Eh bien, maintenant, la chose la plus importante est : que s’est-il passé en conséquence ? Voici quelques graphiques que j'ai réussi à capturer pendant le processus de développement et de débogage. Les graphiques ont été construits en utilisant gnuplot avec le script suivant.

#! /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"

La première expérience a eu lieu chez l'opérateur Tele2, que j'ai réalisée pendant plusieurs jours.

Speedtest simultané sur plusieurs modems LTE

Ici, j'ai utilisé un serveur de mesure dynamique. Les mesures de vitesse fonctionnent, mais fluctuent beaucoup, mais une certaine valeur moyenne est toujours visible, et cela peut être obtenu en filtrant les données, par exemple avec une moyenne mobile.

Plus tard, j'ai construit un certain nombre de graphiques pour d'autres opérateurs télécoms. Dans ce cas, il existait déjà un serveur de test et les résultats étaient également très intéressants.

Speedtest simultané sur plusieurs modems LTE

Speedtest simultané sur plusieurs modems LTE

Speedtest simultané sur plusieurs modems LTE

Speedtest simultané sur plusieurs modems LTE

Comme vous pouvez le constater, le sujet est très vaste pour la recherche et le traitement de ces données, et ne dure clairement pas quelques semaines de travail. Mais…

Résultat du travail

Les travaux ont été brusquement terminés en raison de circonstances indépendantes de ma volonté. L'une des faiblesses de ce projet, à mon avis subjectif, était le modem, qui ne voulait pas vraiment fonctionner simultanément avec d'autres modems, et faisait de telles astuces à chaque fois qu'il était chargé. À ces fins, il existe un grand nombre d'autres modèles de modems, généralement déjà au format Mini PCI-e, installés à l'intérieur de l'appareil et beaucoup plus faciles à configurer. Mais c'est une histoire complètement différente. Le projet était intéressant et j'étais très heureux d'avoir pu y participer.

Speedtest simultané sur plusieurs modems LTE

Source: habr.com

Ajouter un commentaire