Tijdens de quarantaine werd me gevraagd deel te nemen aan de ontwikkeling van een apparaat voor het meten van de snelheid van LTE-modems voor verschillende telecomoperators.
De klant wilde de snelheid van allerlei telecomoperators op verschillende geografische locaties beoordelen, om te begrijpen welke telecomoperator het meest geschikt is bij het installeren van apparatuur die gebruikmaakt van LTE-verbindingen, bijvoorbeeld voor video-uitzendingen. De taak moest zo eenvoudig en goedkoop mogelijk worden opgelost, zonder dure apparatuur.
Ik moet zeggen dat de taak niet eenvoudig en wetenschappelijk intensief is; ik zal uitleggen welke problemen ik tegenkwam en hoe ik ze oploste. Laten we beginnen.
Opmerking
Het meten van de snelheid van een LTE-verbinding is een behoorlijk complexe zaak: het is noodzakelijk om de juiste apparatuur en meetmethoden te kiezen, en ook een goed overzicht te hebben van de topologie en werking van het mobiele netwerk. Bovendien kunnen verschillende factoren de snelheid beïnvloeden: het aantal abonnees op een zendmast, de weersomstandigheden en zelfs van zendmast tot zendmast kan de snelheid aanzienlijk verschillen door de netwerktopologie. Kortom, deze taak heeft een enorme hoeveelheid onbekenden, en alleen de telecomoperator kan het correct oplossen.
Aanvankelijk wilde de klant gewoon een koerier met telefoons van operators rondsturen, metingen direct op de telefoon uitvoeren en daarna de meetresultaten in een notitieboekje noteren. Mijn oplossing voor het meten van LTE-netwerksnelheden is, hoewel niet ideaal, in staat om de gestelde taak op te lossen.
Door tijdgebrek nam ik beslissingen die niet in het voordeel van gebruiksgemak of praktisch nut waren, maar in het voordeel van de snelheid van ontwikkeling. Bijvoorbeeld, voor externe toegang werd reverse ssh opgezet in plaats van een praktischer vpn, om tijd te besparen op de serverconfiguratie en elke afzonderlijke client.
Technische specificatie
Zoals vermeld in het artikel : Werk nooit zonder specificatie! Nooit en nergens!
De technische specificatie was vrij eenvoudig, ik zal deze iets uitbreiden voor het begrip van de eindgebruiker. De keuze van technische oplossingen en apparatuur werd door de klant gedicteerd. Dus, de specificatie zelf, na alle goedkeuringen:
Op basis van een single-board computer vim2 een tester voor LTE-snelheid maken via H-modemsuawei e3372h — 153 verschillende telecomoperators (van één tot n). Het is ook nodig om coördinaten te verkrijgen van de GPS-ontvanger, aangesloten via UART. Snelheidsmetingen moeten worden uitgevoerd met behulp van de service en deze samen te vatten in een tabel in de volgende indeling:
Tabel in csv-formaat. Vervolgens elke 6 uur deze tabel via e-mail verzenden. In geval van fouten moet er een LED knipperen die is aangesloten op GPIO.
Ik heb de specificaties in vrije vorm beschreven, na vele overeenkomsten. Maar de essentie van de taak is al duidelijk. De tijd voor alles was een week. Maar in werkelijkheid heeft het zich uitgestrekt over drie weken. Dit rekening houdend met het feit dat ik dit alleen na mijn reguliere werk en in het weekend deed.
Hier wil ik nogmaals benadrukken dat het gebruik van de snelheidsmeetservice en de hardware vooraf was afgesproken met de opdrachtgever, wat mijn mogelijkheden sterk heeft beperkt. Er was ook een beperkt budget, dus er is niet veel extra aangeschaft. Dus ik moest me aan deze regels houden.
Architectuur en ontwikkeling
Het schema is eenvoudig en duidelijk. Daarom laat ik het zonder verdere opmerkingen.

Ik besloot het hele project te realiseren in Python, ondanks het feit dat ik helemaal geen ervaring had met deze programmeertaal. Ik koos het omdat er veel voorbeelden en oplossingen zijn die de ontwikkeling konden versnellen. Dus vraag ik alle professionele programmeurs om mijn eerste ervaring met Python niet te veroordelen en ik sta altijd open voor constructieve kritiek om mijn vaardigheden te verbeteren.
Tijdens het proces ontdekte ik ook dat Python twee gangbare versies heeft, 2 en 3, en uiteindelijk besloot ik om versie drie te gebruiken.
Hardwarecomponenten
Single-board computer vim2
Als hoofdmachine kreeg ik een single-board computer

Een geweldige, krachtige mediacomponent voor een smart home en SMART-TV, maar bijzonder ongeschikt voor deze taak, of laten we zeggen, zwak passend. Bijvoorbeeld, zijn hoofd-OS is Android, terwijl Linux een secundair OS is, en daarom kan niemand een goede werking van alle componenten en stuurprogramma's onder Linux garanderen. Ik vermoed dat een deel van de problemen verband hield met de USB-stuurprogramma's van dit platform, waardoor modems niet werkten zoals ik had verwacht. Ook heeft het een zeer slechte en onsamenhangende documentatie, waardoor elke handeling veel tijd kostte om door de documentatie te graven. Zelfs een eenvoudige taak met GPIO kostte veel moeite. Bijvoorbeeld, om de werking met de LED in te stellen, had ik enkele uren nodig. Maar, om objectief te zijn, het maakte principieel niet uit welke enkele board het was, als het maar werkte en USB-poorten had.
Eerst moet ik Linux op dit bord installeren. Om niet in de diepten van de documentatie te moeten graven, en ook voor degenen die met deze enkelplaat aan de slag gaan, schrijf ik dit hoofdstuk.
Er zijn twee opties om Linux te installeren: op een externe SD-kaart of op interne MMC. Ik heb een avond geworsteld met de kaart, maar ik kreeg het niet voor elkaar, daarom besloot ik het op MMC te installeren, hoewel het zonder twijfel gemakkelijker zou zijn geweest om met een externe kaart te werken.
Over de firmware . Ik vertaal van het vreemde naar het Russisch. Om het bord te flashen, moet ik de hardware UART aansluiten. Ik heb het als volgt aangesloten.
- Tool Pin GND: Pin17 van VIMs GPIO
- Tool Pin TXD: Pin18 van VIMs GPIO (Linux_Rx)
- Tool Pin RXD: Pin19 van VIMs GPIO (Linux_Tx)
- Tool Pin VCC: Pin20 van VIMs GPIO

Daarna heb ik de firmware gedownload . De specifieke versie van de firmware .
Om deze firmware te kunnen flashen, heb ik bepaalde utilities nodig. Meer hierover wordt beschreven . Onder Windows heb ik het niet geprobeerd om te flashen, maar ik moet enkele woorden zeggen over de firmware onder Linux. Eerst installeer ik de utilities volgens de instructies.
git clone https://github.com/khadas/utils
cd /path/to/utils
sudo ./INSTALLEn... niets werkt. Ik heb een paar uur besteed aan het aanpassen van de installatiescripts, zodat alles correct kon worden geïnstalleerd bij mij. Wat ik daar deed herinner ik me niet meer, maar het was ook een circus met paarden. Dus wees voorzichtig. Maar zonder deze utilities is het geen zin om verder met vim2 te prutsen. Het is beter om helemaal niets met hem te maken te hebben!
Na zeven cirkels van de hel, het configureren van scripts en het installeren, heb ik een pakket werkende utilities gekregen. Ik heb de kaart via USB op mijn Linux computer aangesloten, en ook UART volgens het bovenstaande schema.
Ik stel mijn favoriete terminal minicom in op een snelheid van 115200, zonder hardwarematige en softwarematige foutcontrole. Laten we beginnen.

Bij het opstarten van VIM2 in de UART-terminal druk ik op een willekeurige toets, bijvoorbeeld spatie, om de opstartprocedure te stoppen. Zodra de regel verschijnt,
kvim2# voer ik de opdracht in:
kvim2# run updateOp de host waar we van opstarten, voer ik uit:
burn-tool -v aml -b VIM2 -i VIM2_Ubuntu-server-bionic_Linux-4.9_arm64_EMMC_V20191231.imgDat is het, phew. Ik heb geflashed, Linux is op de kaart. Login/wachtwoord khadas:khadas.
Daarna een paar kleine initiële instellingen. Voor verder gebruik schakel ik het wachtwoord voor sudo uit (ja, het is niet veilig, maar het is handig).
sudo visudoIk bewerk de regel naar de vorm en sla op.
# Allow members of group sudo to execute any command
%sudo ALL=(ALL:ALL) NOPASSWD: ALLDaarna wijzig ik de huidige locale, zodat de tijd volgens Moskou is, anders is het volgens Greenwich.
sudo timedatectl set-timezone Europe/Moscowof
ln -s /usr/share/zoneinfo/Europe/Moscow /etc/localtimeAls dit ingewikkeld lijkt, gebruik deze kaart dan niet, koop beter een Raspberry Pi. Eerlijk gezegd.
Modem Huawei e3372h — 153
Dit modem heeft me behoorlijk wat hoofdpijn bezorgd en is in feite de grootste bottleneck van het hele project geworden. Over het algemeen weerspiegelt de naam "modem" voor deze apparaten totaal niet de werkelijke functionaliteit: dit is een krachtig apparaat, deze hardware heeft een samengestelde functie, waarbij het zich voordoet als een CD-ROM om de stuurprogramma's te installeren en daarna overgaat in de modus van een netwerkadapter.
Architectonisch, vanuit het perspectief van een Linux-gebruiker na alle instellingen, ziet het er als volgt uit: na het aansluiten van het modem verschijnt een netwerkinterface eth*, die via DHCP een IP-adres 192.168.8.100 ontvangt en de standaardgateway 192.168.8.1.
En het belangrijkste punt! Dit modemmodel kan niet functioneren in de modus van een modem die wordt bestuurd door AT-commando's.Het zou veel eenvoudiger zijn geweest om PPP-verbindingen voor elk modem aan te maken en vervolgens daarmee te werken. Maar in mijn geval, creëert 'zelf' (of beter gezegd de Linux-stuurprogramma's volgens de udev-regels), de eth-interface en wijst deze een IP-adres toe via DHCP.
Om verdere verwarring te voorkomen, stel ik voor om het woord "modem" te vergeten en te spreken van netwerkadapter en gateway, want in feite is het zoals het aansluiten van een nieuwe netwerkadapter met een gateway.
Wanneer er één modem is, zijn er meestal geen bijzondere problemen, maar wanneer er meer dan één is, met name n-stuks, ontstaat het volgende netwerkbeeld.

Dat wil zeggen, n netwerkkaarten, met één IP-adres, en elk heeft dezelfde standaardgateway. Maar in werkelijkheid is elk van hen verbonden met zijn eigen provider.
Aanvankelijk had ik een eenvoudige oplossing: met behulp van de opdracht ifconfig of ip alle interfaces uitschakelen en gewoon één voor één inschakelen en testen. De oplossing was goed, behalve dat ik op het moment van schakelen niet kon verbinden met het apparaat. En aangezien de schakelingen frequent en snel waren, had ik feitelijk geen mogelijkheid om überhaupt verbinding te maken.
Daarom koos ik ervoor om de IP-adressen van de modems 'handmatig' te wijzigen en vervolgens verkeer te laten lopen met behulp van routeringsinstellingen.

Hier eindigden mijn problemen met de modems niet: in geval van stroomproblemen vielen ze uit, en het vereiste een goede, stabiele voeding van de USB-hub. Deze problematiek loste ik op door het voeding rechtstreeks aan de hub te solderen. Een ander probleem waarmee ik werd geconfronteerd en dat het hele project heeft verwoest: na een herstart of koude start werden niet alle modems altijd herkend, en waarom dit gebeurde en volgens welk algoritme kon ik niet achterhalen. Maar laten we met de details beginnen.
Voor een correcte werking van de modem heb ik het usb-modeswitch-pakket geïnstalleerd.
sudo apt update
sudo apt install -y usb-modeswitch Daarna zal de modem correct worden herkend en geconfigureerd door het udev-systeem na aansluiting. Ik controleer dit door de modem gewoon aan te sluiten en te verifiëren dat het netwerk is verschenen.
Een ander probleem dat ik niet kon oplossen: hoe krijg ik de naam van de provider uit deze modem? De naam van de provider bevindt zich in de webinterface van de modem op adres 192.168.8.1. Dit is een dynamische webpagina die gegevens verkrijgt via ajax-aanroepen, dus het is niet mogelijk om de pagina gewoon met wget op te halen en de naam te parseren. Daarom ben ik gaan kijken hoe ik met die webpagina kon werken, en ik begreep dat ik mezelf met iets onzinnigs bezighield. Uiteindelijk gaf ik het op en begon de provider via de API van Speedtest te verkrijgen.
Veel zou eenvoudiger zijn als de modem toegang had via AT-commando's. Dan zou ik het opnieuw kunnen configureren, ppp-verbindingen kunnen creëren, IP-toewijzen, de provider verkrijgen, en ga zo maar door. Maar helaas, ik werk met wat ik heb gekregen.
GPS
De GPS-ontvanger die ik kreeg, had een UART-interface en voeding. Dit was niet de beste oplossing, maar desalniettemin functioneel en eenvoudig. De ontvanger zag er ongeveer zo uit.

Eerlijk gezegd werkte ik voor het eerst met een GPS-ontvanger, maar zoals ik al vermoedde, is alles al lang voor ons uitgevonden. Dus gebruiken we gewoon kant-en-klare oplossingen.
Om te beginnen zet ik uart_AO_B (UART_RX_AO_B, UART_TX_AO_B) aan om de GPS aan te sluiten.
khadas@Khadas:~$ sudo fdtput -t s /dtb.img /serial@c81004e0 status okayDaarna controleer ik of de operatie succesvol was.
khadas@Khadas:~$ fdtget /dtb.img /serial@c81004e0 status
okayDeze opdracht lijkt devtree on-the-fly te bewerken, wat zeer handig is.
Na het slagen van deze operatie herstarten we en installeren we de gps-daemon.
khadas@Khadas:~$ sudo rebootInstallatie van de gps-daemon. Ik installeer alles en schakel het meteen uit voor verdere configuratie.
sudo apt install gpsd gpsd-clients -y
sudo killall gpsd
/* Stop/disable GPS daemon */
sudo systemctl stop gpsd.socket
sudo systemctl disable gpsd.socketIk bewerk het configuratiebestand.
sudo vim /etc/default/gpsdIk stel de UART in waarop de GPS zal draaien.
DEVICES="/dev/ttyS4"En daarna zetten we alles aan en starten we het.
/* GPS daemon enable/start */
sudo systemctl enable gpsd.socket
sudo systemctl start gpsd.socketDaarna sluit ik de GPS aan.

In mijn handen heb ik een GPS-kabel, onder mijn vingers zijn de UART-draden van de debugger zichtbaar.
Ik herstart en controleer de werking van de GPS met behulp van het programma gpsmon.

Op deze schermafbeelding zijn er geen satellieten zichtbaar, maar er is communicatie met de GPS-ontvanger, wat aangeeft dat alles goed is.
Ik heb veel opties met deze daemon geprobeerd in Python, maar ik ben gestopt bij degene die goed werkte met Python 3.
Ik installeer de benodigde bibliotheek.
sudo -H pip3 install gps3 En ik schrijf de code.
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 ("Wacht gps teller = %d" % counter)
if counter == 10:
ErrorMessage("Fout GPS-ontvanger!!!")
return "NA", "NA"
time.sleep(1.0)
...
f __name__ == '__main__':
...
#gps
agps_thread = AGPS3mechanism() # Instantieer AGPS3 Mechanismen
agps_thread.stream_data() # Van localhost (), of andere hosts, bijvoorbeeld, (host='gps.ddns.net')
agps_thread.run_thread() # Throttle tijd om te slapen na een lege lookup, standaard '()' 0.2 twee tienden van een seconde
Als ik de coördinaten wil krijgen, doe ik dit met de volgende aanroep:
longitude, latitude = getPositionData(agps_thread)
En binnen 1-10 seconden ontvang ik ofwel de coördinaten, ofwel niet. Ja, ik heb tien pogingen gedaan om de coördinaten te krijgen. Het is niet optimaal, het is niet perfect, maar het werkt. Ik besloot dit te doen omdat GPS soms slecht ontvangst heeft en niet altijd gegevens kan verkrijgen. Als je wacht op het ontvangen van gegevens, dan kan het programma vastlopen op dat punt als je in een afgesloten ruimte werkt. Daarom heb ik zo'n niet-elegante oplossing geïmplementeerd.
In principe, als ik meer tijd had gehad, zou ik rechtstreeks via UART gegevens van de GPS kunnen verkrijgen, deze in een aparte thread kunnen parseren en ermee kunnen werken. Maar er was helemaal geen tijd, vandaar de lelijke code. En ja, ik schaam me er niet voor.
LED
Het aansluiten van de LED was eenvoudig en tegelijkertijd lastig. De belangrijkste moeilijkheid is dat het pin-nummer in het systeem niet overeenkomt met het pin-nummer op de kaart en omdat de documentatie haast onbegrijpelijk is. Om het nummer van de hardwarepin en het nummer van de pin in het besturingssysteem te koppelen, moet je de volgende opdracht uitvoeren:
gpio readallEr zal een tabel worden weergegeven die de overeenkomst van de pin in het systeem en op de kaart toont. Daarna kan ik al met de pin in het besturingssysteem werken. In mijn geval is de LED aangesloten op GPIOH_5.

Ik zet de GPIO-pin in de uitvoermodus.
gpio -g mode 421 outIk schrijf nul.
gpio -g write 421 0Ik schrijf één.
gpio -g write 421 1 
Alles brandt, na het schrijven van '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)
Nu, in geval van fouten, roep ik error_blink() aan en de LED knippert mooi voor ons.
Softwaremodulen
Speedtest API
Het is geweldig dat de service speedtest.net zijn eigen python-API heeft, je kunt het bekijken op .
Wat goed is, is dat er ook bronteksten zijn die je kunt bekijken. Hoe je met deze API werkt (basisvoorbeelden) kun je zien in .
Ik installeer de python-bibliotheek met de volgende opdracht.
sudo -H pip3 install speedtest-cliAls voorbeeld kun je zelfs de speedtest rechtstreeks vanuit de repositories in Ubuntu installeren. Het is dezelfde python-applicatie die je later vanuit de console kunt uitvoeren.
sudo apt install speedtest-cli -yEn meet de snelheid van je internet.
speedtest-cli
Bezig met het ophalen van de configuratie van speedtest.net...
Testen vanaf B***** (*.*.*.*)...
Bezig met het ophalen van de serverlijst van speedtest.net...
De beste server selecteren op basis van ping...
Gehost door MTS (Moskou) [0.12 km]: 11.8 ms
Snelheid downloaden testen.................................................................................
Download: 7.10 Mbit/s
Snelheid uploaden testen.........................................................................................................
Upload: 3.86 Mbit/s
Als resultaat, zoals ik het heb gedaan. Ik moest in de broncode van deze speedtest duiken om het beter in mijn project te integreren. Een van de belangrijkste taken is om ook de naam van de mobiele provider te verkrijgen, om deze in de tabel in te vullen.
import speedtest
from datetime import datetime
...
# Geef een specifieke server op voor de test
#6053) MaximaTelecom (Moskou, Russische Federatie)
servers = ["6053"]
# Als je een enkele threadtest wilt gebruiken
threads = None
s = speedtest.Speedtest()
# Verkrijg de naam van de mobiele operator
opos = '%(isp)s' % s.config['client']
s.get_servers(servers)
# Verkrijg een tekststring met parameters van de server
testserver = '%(sponsor)s (%(name)s) [%(d)0.2f km]: %(latency)s ms' % s.results.server
# Downloadtest
s.download(threads=threads)
# Uploadtest
s.upload(threads=threads)
# Verkrijg de resultaten
s.results.share()
# Daarna wordt er een string gevormd voor opslaan in een csv-bestand.
# Verkrijg GPS-positie
longitude, latitude = getPositionData(agps_thread)
# Tijd en 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 wordt de registratie in het logboekbestand uitgevoerd
Hier is het ook niet zo eenvoudig, hoewel het, zo lijkt het, eenvoudiger kan. Aanvankelijk was de parameter servers gelijk aan [], kies de beste server. Het resultaat was dat ik willekeurige servers had, en zoals je kunt raden, fluctuerende snelheid. Dit is een vrij complex onderwerp; het gebruiken van een vaste server, ja of nee, statisch of dynamisch, vereist onderzoek. Maar hier is een voorbeeld van snelheidstests van de operator Beeline met dynamische serverkeuze en een statisch vastgestelde server.

Resultaat van de snelheidstest met dynamische serverkeuze.

Resultaat van de snelheidstest, met één streng gekozen server.
De "ruis" bij de test is daar en daar, en deze moet met wiskundige methoden worden verwijderd. Maar bij een vaste server is het iets minder en de amplitude is stabieler.
Dit is eigenlijk een gebied van uitgebreid onderzoek. En ik zou snelheidstests naar mijn server uitvoeren met behulp van de iperf-tool. Maar we houden ons aan het technische specificaties.
E-mailverzending en fouten
Voor het verzenden van e-mail heb ik verschillende opties geprobeerd, maar uiteindelijk ben ik gestopt bij het volgende. Ik registreerde een e-mailadres bij yandex en nam daarna . Ik heb het getest en geïmplementeerd in het programma. In dit voorbeeld worden verschillende opties bestudeerd, inclusief verzenden met gmail, enzovoort. Het opzetten van mijn eigen mailserver had ik niet willen doen en had daar geen tijd voor, maar zoals het later bleek, was dat ook tevergeefs.
De logbestanden werden volgens de planner verzonden, wanneer er verbinding is,, elke 6 uur: om 00:00, 06:00, 12:00 en 18:00. Ik verzond ze als volgt.
from send_email import *
...
message_log = "Testlogboeken van bord №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, "Logboeken voor " + curdata + " " + сurtime, files)
except:
print("Netwerkprobleem bij het verzenden van de mail")
return False
return True
Fouten werden ook in het begin verzonden. Eerst werden ze opgeslagen in een lijst en vervolgens verstuurd via de planner, wanneer er verbinding was. Maar later ontstonden er problemen omdat yandex een beperking heeft op het aantal verzonden berichten per dag (dat is vervelend, pijnlijk en vernederend). Aangezien er zelfs per minuut een enorme hoeveelheid fouten kon zijn, moest ik besluiten om geen fouten meer per e-mail te verzenden. Houd hier rekening mee bij automatische verzending via de yandex-services.
Feedbackserver
Om toegang te krijgen tot de externe hardware en in staat te zijn om deze aan te passen en opnieuw te configureren, had ik een externe server nodig. Eerlijk gezegd zou het beter zijn geweest om alle gegevens naar de server te verzenden en in de webinterface mooie grafieken te maken. Maar niet alles kan tegelijk.
Als VPS heb ik gekozen voor . Ik had de eenvoudigste server kunnen nemen. En over het algemeen zou dat voldoende zijn geweest voor mijn doeleinden. Maar omdat ik de server niet uit mijn eigen zak betaalde, besloot ik om een beetje extra capaciteit te nemen, voor het geval we de webinterface, onze SMTP-server, vpn, enzovoort willen opzetten. Daarnaast wilde ik in staat zijn om de Telegram-bot in te stellen en geen problemen te hebben met blokkeringen. Daarom koos ik voor Amsterdam en de volgende parameters.

Voor de verbinding met de hardware vim2 koos ik voor een omgekeerde ssh-verbinding en zoals de praktijk heeft aangetoond, is dat niet de beste optie. Bij het verbreken van de verbinding houdt de server de poort vast en is het een tijdje niet mogelijk om opnieuw verbinding te maken. Daarom is het beter om andere verbindingsmethodes te gebruiken, zoals vpn. In de toekomst wilde ik overstappen op vpn, maar ik had geen tijd meer.
Ik zal niet ingaan op de details van de firewallconfiguratie, toegangsbeperkingen, het uitschakelen van ssh-verbindingen voor root en andere basisinstellingen voor VPS. Laten we hopen dat je dat allemaal al weet. Voor een externe verbinding maak ik een nieuwe gebruiker aan op de server.
adduser vimsshOp onze machine genereer ik de ssh-sleutels voor de verbinding.
ssh-keygenEn ik kopieer ze naar onze server.
ssh-copy-id vimssh@host.comOp onze machine stel ik automatische omgekeerde ssh-verbinding in bij elke opstart.
[Unit]
Omschrijving=Auto Reverse SSH
Vereist=systemd-networkd-wait-online.service
Na=systemd-networkd-wait-online.service
[Service]
Gebruiker=khadas
ExecStart=//usr//bin//ssh -NT -o ExitOnForwardFailure=yes -o ServerAliveInterval=60 -CD 8080 -R 8083:localhost:22 vimssh@host.com
RestartSec=5
Restart=altijd
[Install]
WantedBy=multi-user.target
Let op poort 8083: deze bepaalt via welke poort ik verbinding maak via omgekeerde ssh. We voegen dit toe aan de opstart en starten het op.
sudo systemctl enable autossh.service
sudo systemctl start autossh.serviceJe kunt zelfs de status bekijken:
sudo systemctl status autossh.serviceNu, op onze VPS-server, als je uitvoert:
ssh -p 8083 khadas@localhostDan kom ik op mijn testmachine. En vanaf de machine kan ik ook logs en gegevens via ssh naar mijn server sturen, wat heel handig is.
Alles samenbrengen

Inschakelen, laten we beginnen met ontwikkelen en debuggen
Pfoe, ik heb blijkbaar alles beschreven. Het is tijd om dit allemaal samen te voegen. De code kun je bekijken .
Een belangrijk punt met de code: Dit project kan zomaar niet starten, omdat het is afgestemd op een specifieke taak en architectuur. Hoewel ik de broncode geef, ga ik het belangrijkste hier uitleggen, anders is het totaal niet duidelijk.
Aan het begin initialiseer ik gps, gpio en start ik een aparte planner thread.
#запуск потока планировщика
pShedulerThread = threading.Thread(target=ShedulerThread, args=(1,))
pShedulerThread.start()De planner is vrij eenvoudig: hij controleert of het tijd is om berichten te verzenden en wat de huidige status van de fouten is. Als er een foutvlag is, knipperen we met de 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)Het moeilijkste moment in dit project is het behouden van de omgekeerde ssh-verbinding bij elke test. Bij elke test wordt de standaardgateway en de dns-server opnieuw ingesteld. Aangezien niemand het toch leest, weet dat de trein niet over houten rails rijdt. Wie de easter egg vindt, krijgt een snoepje.
Daarvoor maak ik een aparte routeringstabel —set-mark 0x2 en een regel voor het omleiden van traffic.
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")Meer over hoe dit werkt kun je .
Daarna ga ik verder in een oneindige loop, waar we elke keer de lijst van aangesloten modems ontvangen (om te controleren of de netwerkconfiguratie is veranderd).
network_list = getNetworklist()Het verkrijgen van de lijst met netwerkinterfaces is vrij eenvoudig.
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_listNa het krijgen van de lijst wijs ik IP-adressen toe aan alle interfaces, zoals ik in de afbeelding in het hoofdstuk over de modem heb weergegeven.
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")Vervolgens loop ik gewoon door elke interface en configureer ik elke interface.
for iface in network_list:
ConfigNetwork(iface)def ConfigNetwork(iface):
#reset alle instellingen
cmd_run("sudo ip route flush all")
#Stel de standaardgateway in
cmd_run("sudo route add default gw 192.168.8.1 " + iface)
#stel de dns-server in (dit is nodig voor speedtest)
cmd_run ("sudo bash -c 'echo nameserver 8.8.8.8 > \/etc\/resolv.conf'")Ik controleer de interface op werking; als er geen netwerk is, geef ik fouten aan. Als het netwerk er is, is het tijd om te handelen!
Hier configureer ik de ssh-routing op deze interface (als dat nog niet is gedaan), send fouten naar de server, als de tijd gekomen is, stuur ik logs en uiteindelijk voer ik een speedtest uit en sla de logs op in een csv-bestand.
if not NetworkAvalible():
....
#Hier vormen we de fouten
....
else: #Er is netwerk, hoera, we werken!
#Als we een probleeminterface hebben waarop ssh werkt, wijzigen we deze
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
#nu het netwerk werkt, laten we alles snel versturen!!!
if ready_to_send:
print ("**** Klaar om te versturen!!!")
if sendLogs():
ready_to_send = False
if error_status:
SendErrors()
#en testen dan de snelheid en bewaren de logs. Er valt nog te zeggen over de functie voor het instellen van omgekeerde 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")En natuurlijk moet al deze pracht in de opstartprogramma's worden toegevoegd. Hiervoor maak ik een bestand aan:
sudo vim \/etc\/systemd\/system\/modems_speedtest.serviceEn ik schrijf erin:
[Unit]
Beschrijving=Modem Snelheidstest
Vereist=systemd-networkd-wait-online.service
Na=systemd-networkd-wait-online.service
[Service]
Gebruiker=khadas
ExecStart=\/usr\/bin\/python3.6 \/home\/khadas\/modems_speedtest\/networks.py
RestartSec=5
Restart=altijd
[Install]
WantedBy=multi-user.target
Ik schakel de opstartfunctie in en start het!
sudo systemctl enable modems_speedtest.service
sudo systemctl start modems_speedtest.serviceNu kan ik de logs van wat er gebeurt bekijken met het commando:
journalctl -u modems_speedtest.service --no-pager -fResultaten
Wat is nu het belangrijkste resultaat? Ik zal enkele grafieken laten zien die ik heb kunnen vastleggen tijdens de ontwikkeling en debugging. De grafieken zijn gemaakt met behulp van gnuplot met het volgende script.
#! /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"
De eerste ervaring was met de operator Tele2, die ik gedurende een paar dagen heb uitgevoerd.

Hier heb ik een dynamische meetserver gebruikt. De snelheidsmetingen werken, maar fluctueren sterk. Echter, er is wel een gemiddelde waarde zichtbaar, die kan worden vastgesteld door de data te filteren, bijvoorbeeld met een voortschrijdend gemiddelde.
Later heb ik nog een aantal grafieken opgesteld voor andere telecomoperators. In dit geval was er al één testserver en de resultaten zijn ook erg interessant.




Zoals te zien is, is het onderwerp erg breed voor onderzoek en verwerking van deze gegevens, en dit vraagt duidelijk om meer dan een paar weken werk. Maar…
Conclusie van het werk
Het werk werd abrupt beëindigd door omstandigheden die buiten mijn controle lagen. Een van de zwakke punten van dit project, naar mijn subjectieve mening, was de modem, die niet goed wilde samenwerken met andere modems en bij elke opstart vreemde fratsen vertoonde. Voor dergelijke doeleinden zijn er talloze andere modemmodellen beschikbaar, die normaal gesproken al in Mini PCI-e formaat zijn en in het apparaat worden ingebouwd, waardoor ze veel makkelijker te configureren zijn. Maar dat is een heel ander verhaal. Het project was interessant en ik was erg blij dat ik eraan kon bijdragen.
Bron: habr.com

