Podczas kwarantanny zaproponowano mi udział w opracowaniu urządzenia do pomiaru prędkości modemów LTE dla kilku operatorów komórkowych.
Klient chciał ocenić prędkość różnych operatorów telekomunikacyjnych w różnych lokalizacjach geograficznych, aby móc zrozumieć, który operator komórkowy będzie dla niego najbardziej optymalny przy instalacji sprzętu wykorzystującego połączenie LTE, na przykład do transmisji wideo. Jednocześnie problem należało rozwiązać możliwie najprościej i najtaniej, bez drogiego sprzętu.
Od razu powiem, że zadanie nie należy do najprostszych i wymaga dużej wiedzy, opowiem z jakimi problemami się spotkałem i jak je rozwiązałem. Więc chodźmy.
Operacja
Pomiar prędkości łącza LTE to bardzo złożona sprawa: trzeba dobrać odpowiedni sprzęt i technikę pomiaru, a także dobrze poznać topologię i działanie sieci komórkowej. Ponadto na prędkość może wpływać kilka czynników: liczba abonentów w komórce, warunki pogodowe, nawet w przypadku poszczególnych komórek prędkość może się znacznie różnić ze względu na topologię sieci. Ogólnie rzecz biorąc, jest to problem z ogromną liczbą niewiadomych i tylko operator telekomunikacyjny może go poprawnie rozwiązać.
Początkowo klient chciał po prostu poprowadzić kuriera telefonami operatorów, dokonać pomiarów bezpośrednio na telefonie, a następnie zapisać wyniki pomiaru prędkości w notatniku. Moje rozwiązanie pomiaru prędkości sieci LTE, choć nie idealne, rozwiązuje problem.
Z braku czasu podjąłem decyzje nie na korzyść wygody czy praktyczności, ale na korzyść szybkości rozwoju. Na przykład do zdalnego dostępu zamiast bardziej praktycznego VPN zastosowano odwrotny ssh, aby zaoszczędzić czas na konfigurowaniu serwera i każdego indywidualnego klienta.
Zadanie techniczne było dość proste, rozwinę je trochę, aby było zrozumiałe dla użytkownika końcowego. Wybór rozwiązań technicznych i wyposażenia został podyktowany przez Klienta. A więc sama specyfikacja techniczna, po wszelkich atestach:
Oparty na komputerze jednopłytkowym vim2 wykonaj tester prędkości dla połączeń LTE za pośrednictwem modemów Huawei e3372h-153 kilku operatorów telekomunikacyjnych (od jednego do n). Konieczne jest także odebranie współrzędnych z odbiornika GPS podłączonego poprzez UART. Dokonuj pomiarów prędkości korzystając z usługi www.speedtest.net i umieść je w tabeli takiej jak:
Tabela w formacie csv. Następnie wysyłaj ten znak e-mailem co 6 godzin. W przypadku błędów mrugnij diodą podłączoną do GPIO.
Specyfikację techniczną opisałem w dowolnej formie, po wielu atestach. Ale sens zadania jest już widoczny. Na wszystko dano tydzień. Ale w rzeczywistości trwało to trzy tygodnie. Biorąc pod uwagę fakt, że robiłem to tylko po mojej głównej pracy i w weekendy.
W tym miejscu chcę jeszcze raz zwrócić uwagę na fakt, że Klient z góry wyraził zgodę na korzystanie z usługi pomiaru prędkości oraz sprzętu, co znacznie ograniczyło moje możliwości. Budżet również był ograniczony, więc nie zakupiono nic specjalnego. Musieliśmy więc grać według tych zasad.
Architektura i rozwój
Schemat jest prosty i oczywisty. Dlatego pozostawię to bez specjalnych komentarzy.
Zdecydowałem się na wdrożenie całego projektu w Pythonie, mimo że nie miałem żadnego doświadczenia w programowaniu w tym języku. Wybrałem go, ponieważ było mnóstwo gotowych przykładów i rozwiązań, które mogłyby przyspieszyć rozwój. Dlatego proszę wszystkich profesjonalnych programistów, aby nie karcili mojego pierwszego doświadczenia z programowaniem w Pythonie i zawsze jestem szczęśliwy, gdy słyszę konstruktywną krytykę w celu udoskonalenia moich umiejętności.
W trakcie tego procesu odkryłem, że Python ma dwie działające wersje 2 i 3, w wyniku czego zdecydowałem się na trzecią.
Węzły sprzętowe
Jednopłytowy vim2
Jako maszynę główną dostałem komputer jednopłytkowy vim2
Doskonały, wydajny procesor multimedialny dla inteligentnego domu i SMART-TV, ale do tego zadania skrajnie się nie nadaje, albo, powiedzmy, słabo się nadaje. Na przykład jego głównym systemem operacyjnym jest Android, a Linux jest systemem dodatkowym, w związku z czym nikt nie gwarantuje wysokiej jakości działania wszystkich węzłów i sterowników pod Linuksem. I zakładam, że część problemów była związana ze sterownikami USB tej platformy, więc modemy na tej płycie nie działały zgodnie z oczekiwaniami. Ma też bardzo ubogą i rozproszoną dokumentację, więc każda operacja zajmowała dużo czasu, przekopując się przez doki. Nawet zwykła praca z GPIO wymagała sporo krwi. Na przykład ustawienie diody LED zajęło mi kilka godzin. Ale żeby być obiektywnym, zasadniczo nie było ważne, jaki to był rodzaj single-board, najważniejsze, że działał i były porty USB.
Najpierw muszę zainstalować Linuksa na tej płycie. Aby nie przedzierać się przez gąszcz dokumentacji dla każdego, a także dla tych, którzy będą mieli do czynienia z tym jednopłytkowym układem, piszę ten rozdział.
Istnieją dwie możliwości instalacji Linuksa: na zewnętrznej karcie SD lub na wewnętrznej pamięci MMC. Wieczór spędziłem próbując wymyślić, jak to zrobić, aby działało z kartą, więc zdecydowałem się zainstalować ją na MMC, chociaż bez wątpienia znacznie łatwiej byłoby pracować z kartą zewnętrzną.
Aby wgrać to oprogramowanie, potrzebuję narzędzi. Więcej szczegółów na ten temat tutaj. Nie próbowałem flashować go pod Windowsem, ale muszę powiedzieć kilka słów o oprogramowaniu pod Linuksem. Najpierw zainstaluję narzędzia zgodnie z instrukcjami.
git clone https://github.com/khadas/utils
cd /path/to/utils
sudo ./INSTALL
Aaa... Nic nie działa. Spędziłem kilka godzin edytując skrypty instalacyjne, aby wszystko zainstalowało się poprawnie. Nie pamiętam co tam robiłem, ale był też ten cyrk z końmi. Więc uważaj. Ale bez tych narzędzi nie ma sensu dalej torturować vima2. Lepiej w ogóle z nim nie zadzierać!
Po siedmiu kręgach piekła, konfiguracji skryptu i instalacji otrzymałem paczkę działających narzędzi. Podłączyłem płytkę przez USB do mojego komputera z systemem Linux, a także podłączyłem UART zgodnie ze schematem powyżej.
Konfiguruję mój ulubiony terminal minicom na prędkość 115200, bez kontroli błędów sprzętu i oprogramowania. I zaczynajmy.
Podczas ładowania VIM2 do terminala UART naciskam klawisz, taki jak spacja, aby zatrzymać ładowanie. Po pojawieniu się linii
kvim2#
Wpisuję polecenie:
kvim2# run update
Na hoście, z którego ładujemy, wykonuję:
burn-tool -v aml -b VIM2 -i VIM2_Ubuntu-server-bionic_Linux-4.9_arm64_EMMC_V20191231.img
To tyle, uff. Sprawdziłem, na płycie jest Linux. Login/hasło khadas:khadas.
Następnie kilka drobnych ustawień początkowych. Do dalszej pracy wyłączam hasło do Sudo (tak, nie bezpieczne, ale wygodne).
sudo visudo
Edytuję linię w formularzu i zapisuję
# Allow members of group sudo to execute any command
%sudo ALL=(ALL:ALL) NOPASSWD: ALL
Następnie zmieniam obecną lokalizację, aby czas był w Moskwie, w przeciwnym razie będzie w Greenwich.
Jeśli sprawia ci to trudność, nie używaj tej płyty; Raspberry Pi jest lepsze. Szczerze mówiąc.
Modem Huawei e3372h – 153
Modem ten był dla mnie znaczącym źródłem krwi i tak naprawdę stał się wąskim gardłem całego projektu. Generalnie nazwa „modem” dla tych urządzeń w ogóle nie oddaje istoty pracy: to potężny kombajn, ten sprzęt ma złożone urządzenie, które udaje CD-ROM w celu zainstalowania sterowników, a następnie przełącza się w tryb karty sieciowej.
Architektonicznie z punktu widzenia użytkownika Linuksa po wszystkich ustawieniach wygląda to tak: po podłączeniu modemu mam interfejs sieciowy eth*, który przez dhcp otrzymuje adres IP 192.168.8.100, a bramę domyślną to 192.168.8.1.
I najważniejszy moment! Ten model modemu nie może pracować w trybie modemu, który jest sterowany poleceniami AT. Wszystko byłoby znacznie prostsze, utwórz połączenia PPP dla każdego modemu, a następnie operuj z nimi. Ale w moim przypadku „sam” (dokładniej linuksowy nurek zgodnie z zasadami udev) tworzy interfejs eth i przypisuje mu adres IP poprzez dhcp.
Aby uniknąć dalszych nieporozumień, sugeruję zapomnieć o słowie „modem” i powiedzieć karta sieciowa i brama, ponieważ w istocie przypomina to połączenie nowej karty sieciowej z bramą.
Gdy jest jeden modem, nie powoduje to żadnych specjalnych problemów, ale gdy jest ich więcej, czyli n-sztuk, powstaje następujący obraz sieci.
Oznacza to, że n kart sieciowych ma ten sam adres IP, a każda ma tę samą bramę domyślną. Ale tak naprawdę każdy z nich jest podłączony do własnego operatora.
Początkowo miałem proste rozwiązanie: za pomocą polecenia ifconfig lub ip wyłącz wszystkie interfejsy i po prostu włącz jeden z nich po kolei i przetestuj. Rozwiązanie było dobre dla wszystkich, z tym wyjątkiem, że w momentach przełączania nie mogłem połączyć się z urządzeniem. A ponieważ przełączanie jest częste i szybkie, właściwie w ogóle nie miałem okazji się połączyć.
Dlatego wybrałem ścieżkę ręcznej zmiany adresów IP modemów, a następnie kierowania ruchem za pomocą ustawień routingu.
To nie był koniec moich problemów z modemami: w razie problemów z zasilaniem odpadały, a potrzebne było dobre, stabilne zasilanie do koncentratora USB. Rozwiązałem ten problem, lutując na twardo zasilanie bezpośrednio do koncentratora. Kolejny problem, który napotkałem i który zrujnował cały projekt: po ponownym uruchomieniu lub zimnym uruchomieniu urządzenia nie wszystkie modemy zostały wykryte i nie zawsze i nie mogłem ustalić, dlaczego tak się stało i według jakiego algorytmu. Ale najpierw sprawy.
Aby modem działał poprawnie zainstalowałem pakiet usb-modeswitch.
Następnie po podłączeniu modem zostanie poprawnie wykryty i skonfigurowany przez podsystem udev. Ja sprawdzam po prostu podłączając modem i upewniając się, że sieć się pojawia.
Kolejny problem, którego nie mogłem rozwiązać: jak mogę uzyskać nazwę operatora, z którym współpracujemy, z tego modemu? Nazwa operatora jest zawarta w interfejsie internetowym modemu pod adresem 192.168.8.1. Jest to dynamiczna strona internetowa, która otrzymuje dane za pośrednictwem żądań Ajax, więc samo pobranie strony i przeanalizowanie nazwy nie będzie działać. Zacząłem więc zastanawiać się, jak stworzyć stronę internetową itp. i zdałem sobie sprawę, że robię jakiś nonsens. W rezultacie splunął, a operator zaczął odbierać za pomocą samego interfejsu API Speedtest.
Byłoby znacznie łatwiej, gdyby modem miał dostęp za pomocą poleceń AT. Można byłoby go przekonfigurować, utworzyć połączenie ppp, przypisać adres IP, uzyskać operatora telekomunikacyjnego itp. Ale niestety, pracuję z tym, co dostałem.
GPS
Odbiornik GPS, który dostałem, miał interfejs UART i zasilanie. Nie było to najlepsze rozwiązanie, ale nadal było wykonalne i proste. Odbiornik wyglądał mniej więcej tak.
Szczerze mówiąc, to była moja pierwsza praca z odbiornikiem GPS, ale tak jak się spodziewałem, wszystko było już dawno za nas obmyślone. Korzystamy więc po prostu z gotowych rozwiązań.
Najpierw włączam uart_AO_B (UART_RX_AO_B, UART_TX_AO_B), aby połączyć GPS.
khadas@Khadas:~$ sudo fdtput -t s /dtb.img /serial@c81004e0 status okay
Następnie sprawdzam powodzenie operacji.
khadas@Khadas:~$ fdtget /dtb.img /serial@c81004e0 status
okay
To polecenie najwyraźniej edytuje drzewo deweloperów w locie, co jest bardzo wygodne.
Po pomyślnym zakończeniu tej operacji uruchom ponownie komputer i zainstaluj demona GPS.
khadas@Khadas:~$ sudo reboot
Instalacja demona GPS. Instaluję wszystko i od razu odcinam do dalszej konfiguracji.
Przewód GPS mam w rękach, przewody debugera UART widać pod palcami.
Uruchamiam ponownie i sprawdzam działanie GPS za pomocą programu gpsmon.
Na tym zrzucie ekranu nie widać satelitów, ale widać komunikację z odbiornikiem GPS, a to oznacza, że wszystko jest w porządku.
W Pythonie wypróbowałem wiele opcji pracy z tym demonem, ale zdecydowałem się na tę, która działała poprawnie z Pythonem 3.
Instaluję niezbędną bibliotekę.
sudo -H pip3 install gps3
I rzeźbię kod pracy.
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
Jeśli potrzebuję uzyskać współrzędne, można to zrobić za pomocą następującego wywołania:
longitude, latitude = getPositionData(agps_thread)
W ciągu 1–10 sekund albo otrzymam współrzędne, albo nie. Tak, miałem dziesięć prób uzyskania współrzędnych. Nieoptymalne, krzywe i krzywe, ale działa. Zdecydowałem się to zrobić, ponieważ GPS może mieć słaby odbiór i nie zawsze odbiera dane. Jeśli będziesz czekać na odbiór danych, to jeśli będziesz pracować w odległym pokoju, program w tym miejscu się zawiesi. Dlatego zaimplementowałem tę nieelegancką opcję.
W zasadzie gdyby było więcej czasu to dałoby się odbierać dane z GPS bezpośrednio przez UART, analizować je w osobnym wątku i pracować z nimi. Ale czasu w ogóle nie było, stąd brutalnie brzydki kod. I tak, nie wstydzę się.
LED
Podłączenie diody LED było proste i trudne jednocześnie. Główna trudność polega na tym, że numer pinu w systemie nie odpowiada numerowi pinu na płycie oraz dlatego, że dokumentacja jest pisana lewą ręką. Aby porównać numer PIN sprzętu i numer PIN w systemie operacyjnym, należy uruchomić polecenie:
gpio readall
Wyświetlona zostanie tabela korespondencji pinów w systemie i na płytce. Po czym mogę już obsługiwać pin w samym systemie operacyjnym. W moim przypadku dioda LED jest podłączona do GPIOH_5.
Teraz w razie błędów wywołuję error_blink() i dioda LED będzie pięknie migać.
Węzły oprogramowania
Speedtest API
To wielka radość, że usługa speedtest.net ma własne python-API, możesz zajrzeć Github.
Dobrą rzeczą jest to, że istnieją również kody źródłowe, które można przeglądać. Jak pracować z tym API (proste przykłady) można znaleźć w odpowiednia sekcja.
Instaluję bibliotekę Pythona za pomocą następującego polecenia.
sudo -H pip3 install speedtest-cli
Na przykład możesz nawet zainstalować tester prędkości w Ubuntu bezpośrednio z oprogramowania. Jest to ta sama aplikacja Pythona, którą można następnie uruchomić bezpośrednio z konsoli.
sudo apt install speedtest-cli -y
I zmierz prędkość swojego Internetu.
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
W efekcie tak jak ja. Musiałem dostać się do kodów źródłowych tego testu prędkości, aby pełniej wdrożyć je w moim projekcie. Jednym z najważniejszych zadań jest uzyskanie nazwy operatora telekomunikacyjnego w celu podstawienia jej w tabliczce.
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"
#тут идет запись в файл логов
Tutaj również wszystko okazało się nie takie proste, choć wydawałoby się znacznie prostsze. Początkowo parametr serwerów był równy [], mówią, wybierz najlepszy serwer. W rezultacie miałem losowe serwery i, jak można się domyślić, zmienną prędkość. Jest to dość złożony temat, korzystanie ze stałego serwera, jeśli tak, statycznego lub dynamicznego, wymaga badań. Ale oto przykład wykresów pomiaru prędkości dla operatora Beeline przy dynamicznym wyborze serwera testowego i serwera statycznie ustalonego.
Wynik pomiaru prędkości przy wyborze serwera dynamicznego.
Wynik testów szybkości, z jednym ściśle wybranym serwerem.
Podczas testów w obu miejscach pojawiło się „futro”, które należy usunąć metodami matematycznymi. Ale w przypadku serwera stałego jest on nieco mniejszy, a amplituda jest bardziej stabilna.
Ogólnie rzecz biorąc, jest to miejsce świetnych badań. Zmierzyłbym prędkość mojego serwera za pomocą narzędzia iperf. Trzymamy się jednak specyfikacji technicznych.
Wysyłanie poczty i błędy
Wypróbowałem kilkadziesiąt różnych opcji wysyłania poczty, ale ostatecznie zdecydowałem się na następujące. Zarejestrowałem skrzynkę pocztową na Yandex, a następnie wziąłem To jest przykład wysyłania poczty. Sprawdziłem i zaimplementowałem w programie. W tym przykładzie zbadano różne opcje, w tym wysyłanie z Gmaila itp. Nie chciało mi się zawracać głowy konfiguracją serwera pocztowego i nie miałem na to czasu, ale jak się później okazało, to też było na marne.
Logi zostały wysłane zgodnie z harmonogramem, jeśli istnieje połączenie, co 6 godzin: o godzinie 00:06, 12:18, XNUMX:XNUMX i XNUMX:XNUMX. Wysłałem w następujący sposób.
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
Początkowo wysyłane były również błędy. Na początku były one gromadzone na liście, a następnie wysyłane również za pomocą harmonogramu, jeśli było połączenie. Jednak potem pojawiły się problemy z tym, że Yandex ma ograniczenie liczby wysyłanych dziennie wiadomości (jest to ból, smutek i upokorzenie). Ponieważ nawet w ciągu minuty mogła pojawić się ogromna liczba błędów, musieliśmy zrezygnować z wysyłania błędów pocztą. Należy więc pamiętać o automatycznym wysyłaniu informacji o takim problemie za pośrednictwem usług Yandex.
Serwer opinii
Aby mieć dostęp do zdalnego sprzętu i móc go dostosowywać i rekonfigurować, potrzebowałem zewnętrznego serwera. Ogólnie rzecz biorąc, słuszne byłoby przesłanie wszystkich danych na serwer i zbudowanie wszystkich pięknych wykresów w interfejsie internetowym. Ale nie wszystko na raz.
Wybrałem VPS ruvds.com. Możesz wziąć najprostszy serwer. I ogólnie dla moich celów to by wystarczyło. Ponieważ jednak nie płaciłem za serwer z własnej kieszeni, zdecydowałem się wziąć go z niewielką rezerwą, aby wystarczyło nam wdrożenie interfejsu WWW, własnego serwera SMTP, VPN itp. Ponadto możesz skonfigurować bota Telegramu i nie mieć problemów z jego blokowaniem. Dlatego wybrałem Amsterdam i następujące parametry.
Jako metodę komunikacji ze sprzętem vim2 wybrał odwrotne połączenie ssh i jak pokazała praktyka, nie jest to najlepsze. W przypadku utraty połączenia serwer wstrzymuje port i przez pewien czas nie można się przez niego połączyć. Dlatego nadal lepiej jest skorzystać z innych metod komunikacji, na przykład VPN. W przyszłości chciałem przejść na VPN, ale nie miałem czasu.
Nie będę wdawał się w szczegóły konfiguracji firewalla, ograniczania praw, wyłączania połączeń root ssh i inne truizmy związane z konfiguracją VPS. Chciałbym wierzyć, że już wszystko wiesz. W przypadku połączenia zdalnego tworzę nowego użytkownika na serwerze.
adduser vimssh
Generuję klucze połączenia ssh na naszym sprzęcie.
Następnie przechodzę do mojego testowego sprzętu. Ze sprzętu mogę także wysyłać logi i dowolne dane przez ssh na mój serwer, co jest bardzo wygodne.
Wszystko razem
Włączając, zacznijmy programowanie i debugowanie
Uff, cóż, to wszystko, opisałem wszystkie węzły. Teraz nadszedł czas, aby to wszystko połączyć w jedną całość. Możesz zobaczyć kod tutaj.
Ważny punkt dotyczący kodu: Ten projekt nie może zacząć się w ten sposób, ponieważ był dostosowany do konkretnego zadania, o określonej architekturze. Mimo że podam kod źródłowy, to i tak to, co najcenniejsze, wyjaśnię tutaj, bezpośrednio w tekście, bo inaczej byłoby to całkowicie niezrozumiałe.
Na początek inicjuję gps, gpio i uruchamiam osobny wątek harmonogramu.
Harmonogram jest dość prosty: sprawdza, czy nadszedł czas na wysłanie wiadomości i jaki jest bieżący stan błędu. Jeśli pojawi się flaga błędu, migamy diodą 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)
Najtrudniejszą częścią tego projektu jest utrzymanie odwrotnego połączenia SSH dla każdego testu. Każdy test polega na rekonfiguracji bramy domyślnej i serwera DNS. Ponieważ i tak nikt nie czyta, wiedzcie, że pociąg nie jedzie po drewnianych szynach. Kto znajdzie jajko wielkanocne, otrzyma cukierka.
Aby to zrobić, tworzę osobną tablicę routingu -set-mark 0x2 i regułę przekierowującą ruch.
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")
Po czym wchodzę w nieskończoną pętlę, gdzie za każdym razem otrzymujemy listę podłączonych modemów (aby dowiedzieć się, czy konfiguracja sieci nagle się nie zmieniła).
network_list = getNetworklist()
Uzyskanie listy interfejsów sieciowych jest dość proste.
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
Po otrzymaniu listy ustawiam adresy IP dla wszystkich interfejsów, tak jak pokazałem na obrazku w rozdziale o modemie.
Następnie po prostu przechodzę przez każdy interfejs w pętli. I konfiguruję każdy interfejs.
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'")
Sprawdzam interfejs pod kątem funkcjonalności, jeżeli nie ma sieci to generuje mi błędy. Jeśli jest sieć, czas działać!
Tutaj konfiguruję routing ssh do tego interfejsu (jeśli tego nie zrobiono), wysyłam błędy do serwera jeśli nadejdzie czas, wysyłam logi i na koniec uruchamiam speedtest i zapisuję logi do pliku 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()
#и далее тестируем скорость и сохраняем логи.
Warto wspomnieć o funkcji ustawienia odwrotnego 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")
I oczywiście musisz dodać całe to piękno do startu. W tym celu tworzę plik:
sudo vim /etc/systemd/system/modems_speedtest.service
Cóż, teraz najważniejsze jest to, co się w rezultacie wydarzyło? Oto kilka wykresów, które udało mi się uchwycić podczas procesu programowania i debugowania. Wykresy zostały zbudowane przy użyciu gnuplot z następującym skryptem.
#! /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"
Pierwsze doświadczenie było z operatorem Tele2, które przeprowadziłem przez kilka dni.
Tutaj użyłem dynamicznego serwera pomiarowego. Pomiary prędkości działają, ale bardzo się wahają, ale nadal widoczna jest pewna wartość średnia, a można to uzyskać filtrując dane, na przykład średnią ruchomą.
Później zbudowałem szereg wykresów dla innych operatorów telekomunikacyjnych. W tym przypadku istniał już jeden serwer testowy i wyniki również były bardzo interesujące.
Jak widać temat jest bardzo obszerny pod względem badania i przetwarzania tych danych i wyraźnie nie starcza na kilka tygodni pracy. Ale…
Wynik pracy
Prace zostały zakończone nagle z przyczyn niezależnych ode mnie. Jedną ze słabości tego projektu, moim subiektywnym zdaniem, był modem, który nie bardzo chciał współpracować z innymi modemami jednocześnie i robił takie sztuczki przy każdym załadowaniu. Do tych celów istnieje ogromna liczba innych modeli modemów, zwykle są one już w formacie Mini PCI-e i są instalowane wewnątrz urządzenia i są znacznie łatwiejsze w konfiguracji. Ale to zupełnie inna historia. Projekt był ciekawy i bardzo się cieszę, że mogłam w nim wziąć udział.