Адначасовы speedtest на некалькіх LTE-мадэмах

На каранціне мне прапанавалі паўдзельнічаць у распрацоўцы прылады вымярэння хуткасці LTE-мадэмаў для некалькіх аператараў сотавай сувязі.

Адначасовы speedtest на некалькіх LTE-мадэмах

Замовец жадаў ацаніць хуткасць разнастайных аператараў сувязі ў розных геаграфічных кропках, для таго каб можна было зразумець, які аператар сотавай сувязі яму найболей аптымальны пры ўсталёўцы абсталявання, выкарыстоўвалае LTE-злучэнне, напрыклад, для відэатрансляцый. Пры гэтым задачу трэба было рашыць максімальна проста і танна, без дарагога абсталявання.

Адразу скажу, што задача не самая простая і навукаёмістая, раскажу, якія праблемы мне сустрэліся і як я іх вырашаў. Такім чынам, паехалі.

Заўвага

Вымярэнне хуткасці LTE-злучэнне справа вельмі складанае: неабходна правільна абраць абсталяванні і методыку вымярэння, таксама добра ўяўляць тапалогію і працу сотавай сеткі. Плюс на хуткасць можа ўплываць некалькі фактараў: колькасць абанентаў на соце, умовы надвор'я, нават ад соты да соты хуткасць можа ашаламляльна адрознівацца з-за тапалогіі сеткі. Увогуле, гэтая задача з вялізнай колькасцю невядомых, і яе правільна вырашыць можа толькі аператар сувязі.

Першапачаткова заказчык хацеў проста ганяць кур'ера з тэлефонамі аператараў, праводзіць вымярэнні прама на тэлефоне і далей у сшытак запісваць вынікі вымярэння хуткасці. Маё рашэнне вымярэння хуткасці сетак lte хоць не ідэальна, але вырашае пастаўленую задачу.

З-за недахопу часу, я прымаў рашэнні не на карысць зручнасці ці практычнасці, а на карысць хуткасці распрацоўкі. Напрыклад, для выдаленага доступу паднімаўся зваротны ssh, замест больш практычнага vpn, дзеля эканоміі часу на наладу сервера і кожнага асобнага кліента.

Тэхнічнае заданне

Як сказана ў артыкуле Без ТЗ: чаму кліент не жадае яго: Не працуйце без ТЗ! Ніколі, нідзе!

Тэхнічнае заданне было дастаткова простае, я крыху яго пашыру для разумення канчатковага карыстальніка. Выбар тэхнічных рашэнняў і абсталяванні быў прадыктаваны замоўцам. Такім чынам, само ТЗ, пасля ўсіх узгадненняў:

На базе аднаплатнага кампутара вім2 зрабіць тэстар хуткасці lte-злучэнні праз мадэмы Huawei e3372h - 153 некалькіх аператараў сувязі (ад аднаго да n). Гэтак жа неабходна атрымліваць каардынаты з GPS-прымача, падлучанага па UART. Замеры хуткасці вырабляць з дапамогай сэрвісу www.speedtest.net і зводзіць іх у табліцу выгляду:

Адначасовы speedtest на некалькіх LTE-мадэмах

Табліца ў фармаце CSV. Пасля чаго адсылаць на е-майл кожныя 6 гадзін дадзеную таблічку. У выпадку ўзнікнення памылак міргаць святлодыёдам, які падлучаны да GPIO.

ТЗ я апісаў у вольнай форме, пасля мноства ўзгадненняў. Але сэнс задачы ўжо відаць. Тэрмін на ўсё пра ўсё быў дадзены тыдзень. Але ў рэальнасці ён расцягнуўся на тры тыдні. Гэта з улікам таго, што я рабіў гэта толькі пасля асноўнай працы і ў выходныя.

Тут я хачу яшчэ раз звярнуць увагу, што заказчыкам было загадзя абумоўлена выкарыстанне сэрвісу вымярэння хуткасці і апаратнае забеспячэнне, што моцна абмежавала мае магчымасці. Быў таксама абмежаваны бюджэт, таму асабліва нічога не дакуплялася. Так што прыйшлося гуляць па дадзеных правілах.

Архітэктура і распрацоўка

Схема простая і відавочная. Таму пакіну яе без асаблівых каментароў.

Адначасовы speedtest на некалькіх LTE-мадэмах

Увесь праект вырашыў рэалізаваць на python, нягледзячы на ​​тое, што досведу распрацоўкі на гэтай мове ў мяне не было зусім. Абраў яго, бо была куча гатовых прыкладаў і рашэнняў, якія маглі паскорыць распрацоўку. Таму, прашу ўсіх прафесійных праграмістаў не лаяць мой першы досвед распрацоўкі на python, і заўсёды з задавальненнем гатовы пачуць канструктыўную крытыку, для падвышэння свайго скіла.

Таксама ў працэсе адкрыў, што python мае дзве хадавыя версіі 2 і 3, у выніку спыніўся на трэцяй.

Апаратныя вузлы

Аднаплатнік vim2

У якасці асноўнай машыны мне быў дадзены аднаплатнік вім2

Адначасовы speedtest на некалькіх LTE-мадэмах

Выдатны, магутны медыякамбайн для разумнай хаты і SMART-TV, але на рэдкасць непадыходны для дадзенай задачы, ці скажам так, слаба падыходны. Напрыклад, яго галоўная АС – гэта Android, а Linux – гэта спадарожная АС, і адпаведна ніхто не гарантуе якаснай працы ўсіх вузлоў і драйвераў пад Linux. І я мяркую, што частка праблем была злучана з драйверамі USB дадзенай платформы, таму мадэмы працавалі на дадзенай плаце не бо чакаў. Таксама ў яго вельмі дрэнная і разрозненая дакументацыя, таму кожная аперацыя займала шмат часу капання ў доках. Нават радавая праца з GPIO папіла шмат крыві. Напрыклад, каб настроіць працу са святлодыёдам, мне спатрэбілася некалькі гадзін. Але, калі быць аб'ектыўным, то прынцыпова не было важна, што за аднаплатнік, галоўнае, каб працаваў і былі USB-парты.

Для пачатку мне трэба ўсталяваць Linux на дадзеную плату. Каб не гойсаць усім па нетрах дакументацыі, а таксама для тых, хто будзе разбірацца з гэтым аднаплатнікам, пішу дадзены раздзел.

Ёсць два варыянты ўсталяваць лінукс: на знешнюю SD-карту, альбо на ўнутраную MMC. З картай я пабіўся адвячорак, так і не ўкурыў як жа прымусіць працаваць, таму вырашыў усталёўваць на MMC, хоць без сумневу з вонкавай картай шмат прасцей было б працаваць.

Аб прашыўцы крыва расказана тут. Перакладаю з дзіўнага на рускую. Для таго, каб адштабнаваць плату, мне неабходна падлучыць апаратны UART. Падключаў яго наступным чынам.

  • Tool Pin GND: <-> Pin17 of VIM's GPIO
  • Tool Pin TXD: <-> Pin18 of VIM's GPIO (Linux_Rx)
  • Tool Pin RXD: <-> Pin19 of VIM's GPIO (Linux_Tx)
  • Tool Pin VCC: <-> Pin20 of VIM's GPIO

Адначасовы speedtest на некалькіх LTE-мадэмах

Пасля чаго, я запампаваў прашыўку адсюль. Канкрэтная версія прашыўкі VIM1_Ubuntu-server-bionic_Linux-4.9_arm64_EMMC_V20191231.

Для таго, каб заліць дадзеную прашыўку, мне неабходны патрэбныя ўтыліты. Больш падрабязна пра гэта расказана тут. Пад Windows не спрабаваў прашываць, а вось аб прашыўцы пад Linux трэба пару слоў распавесці. Для пачатку ўсталюю ўтыліты, паводле інструкцыі.

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

Ііі... Нічога не працуе. Патраціў пару гадзін займаючыся праўкамі ўсталявальных скрыптоў, каб усё карэктна ўсталявалася ў мяне. Што там рабіў не памятаю, але таксама яшчэ той цырк з канямі. Так што будзьце асцярожныя. Але без гэтых утыліт далей мучыць vim2 сэнсу няма. Лепш з ім увогуле не звязвацца!

Пасля сямі колаў пекла, канфігурацыі скрыптоў і ўстаноўкі атрымаў пакет якія працуюць утыліт. Падлучыў поплатак па USB да майго кампутара лінукс, і гэтак жа падлучаны UART па схеме вышэй.
Наладжваю мой каханы тэрмінал minicom на хуткасць 115200, без апаратнага і праграмнага кантролю памылак. І прыступаем.

Адначасовы speedtest на некалькіх LTE-мадэмах

Пры загрузцы VIM2 у тэрмінале UART націскаю якую-небудзь клавішу, напрыклад прабел, каб спыніць загрузку. Пасля таго, як з'явіцца радок

kvim2# 

Уводжу каманду:

kvim2# run update

На хасце, адкуль загружаем, выконваю:

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

Усё, фух. Прашыў, на плаце ёсць Linux. Лагін/пароль khadas:khadas.

Пасля гэтага невялікія першасныя наладкі. Для далейшай працы адключаю пароль у sudo (так, не бяспечна, але зручна).

sudo visudo

Рэдактую радок да выгляду і захоўваем

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

Пасля чаго мяняю бягучую лакаль, каб час быў па Маскве, інакш будзе па Грынвічы.

sudo timedatectl set-timezone Europe/Moscow

альбо

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

Калі вам падалося складана, то не карыстайцеся дадзенай платай, лепш Raspberry Pi. Шчыра.

Мадэм Huawei e3372h - 153

Дадзены мадэм у мяне папіў крыві шляхетна, і, у сутнасці, ён і стаў самым вузкім месцам усяго праекту. Наогул, назоў "мадэм" для дадзеных прылад зусім не адлюстроўвае істу працы: гэта наймагутны камбайн, гэтая жалязяка мае складовую прыладу, якое прыкідваецца CD-ROM для таго, каб усталяваць драйвера, а потым пераходзіць у рэжым сеткавай карты.

Архітэктурна, з пункта гледжання карыстача Linux пасля ўсіх налад, выглядае так: пасля падлучэння мадэма, у мяне з'яўляецца сеткавы інтэрфейс eth*, які па dhcp атрымлівае ip адрас 192.168.8.100, і шлюз па змаўчанні 192.168.8.1.

І самы галоўны момант! Дадзеная мадэль мадэма, не ўмее працаваць у рэжыме менавіта мадэма, які кіруецца АТ-камандамі. Усё было б моцна прасцей, стварыць ppp-злучэнні на кожны мадэм і далей ужо апераваць з імі. Але ў маім выпадку "сам" (дакладней дайвера Linux паводле правіл udev), стварае eth-інтэрфейс і па dhcp прызначаюць яму ip-адрас.

Каб далей не блытацца, прапаную забыцца слова "мадэм" і казаць сеткавая карта і шлюз, бо па ісце, гэта як падлучэнне новай сеткавай карты са шлюзам.
Калі адзін мадэм, гэта не выклікае адмысловых праблем, але калі іх больш аднаго, а менавіта n-штук, тое ўзнікае наступная карціна сеткі.

Адначасовы speedtest на некалькіх LTE-мадэмах

Гэта значыць n сеткавых карт, з адным IP-адрасам, у кожнага адзін і той жа шлюз па змаўчанні. Але па факце, кожны з іх падключаны да свайго аператара.

Першапачаткова ў мяне было простае рашэнне: з дапамогай каманды ifconfig або ip гасіць усе інтэрфейсы і проста ўключаць па чарзе адзін і тэсціраваць яго. Рашэнне было ўсім добра, акрамя таго, што ў моманты камутацыі я не меў магчымасці падлучыцца да прылады. А паколькі камутацыі частыя і хуткія, то фактычна ў мяне не было магчымасці далучыцца наогул.

Таму я абраў шлях змяняць "уручную" ip-адрасы мадэмаў і далей ганяць трафік з дапамогай налад маршрутызацыі.

Адначасовы speedtest на некалькіх LTE-мадэмах

На гэтым у мяне праблемы з мадэмамі не скончыліся: у выпадку праблем з сілкаваннем, яны адвальваліся, патрабавалася добрае стабільнае сілкаванне USB-хаба. Гэтую праблему вырашыў жорстка прыпаяўшы харчаванне прама да хаба. Іншая праблема, з якой я сутыкнуўся і якая загубіла ўвесь праект: пасля перазагрузкі ці халоднага старту прылады вызначаліся не ўсе мадэмы і не заўсёды, і чаму гэта адбывалася і па якім алгарытме мне ўсталяваць не ўдалося. Але пра ўсё па парадку.

Для карэктнай працы мадэма, я ўсталяваў пакет usb-modeswitch.

sudo apt update
sudo apt install -y usb-modeswitch

Пасля чаго, мадэм пасля падлучэння будзе карэктна вызначацца і канфігуравацца падсістэмай udev. Правяраю, проста падлучыўшы мадэм і пераканаўшыся, што сетка з'явілася.
Яшчэ адна праблема, якую я не змог вырашыць: гэта як з гэтага мадэма атрымаць імя аператара, з якім мы працуем? Імя аператара змяшчаецца ў вэб-інтэрфейсе мадэма па адрасе 192.168.8.1. Гэта дынамічная вэб-старонка, якая атрымлівае дадзеныя з дапамогай ajax-запытаў, таму проста wget-тнуць старонку і спарсить імя не атрымаецца. Таму пачаў глядзець, як адпрацаваць web-старонку і да т.п., і зразумеў, што займаюся нейкім глупствам. У выніку плюнуў, і аператара пачаў атрымліваць з дапамогай API самога Speedtest.

Многае было б прасцей, калі б у мадэма быў бы доступ праз AT-каманды. Можна было б яго пераканфігураваць, ствараць ppp-злучэнне, прызначаць IP, атрымліваць аператара сувязі і т.д. Але нажаль, працую з тым што далечы.

GPS

GPS-прымач, які мне выдалі, меў інтэрфейс UART і харчаванне. Гэта было не самае лепшае рашэнне, але тым не менш працоўнае і простае. Прымач быў прыкладна такога віду.

Адначасовы speedtest на некалькіх LTE-мадэмах

Шчыра кажучы, упершыню працаваў з GPS-прымачом, але як і меркаваў, усё даўно прыдумана за нас. Так што проста карыстаемся гатовымі рашэньнямі.

Для пачатку ўключаю uart_AO_B (UART_RX_AO_B, UART_TX_AO_B) для падлучэння GPS.

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

Пасля правяраю паспяховасць аперацыі.

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

Дадзеная каманда, судзячы па ўсім, на лёце рэдагуе devtree, што вельмі зручна.

Пасля поспеху гэтай аперацыі перазагружаемся і ўсталёўваны gps-дэман.

khadas@Khadas:~$ sudo reboot

Ўстаноўка gps-дэмана. Усталёўваю ўсё і адсякаю яго адразу для далейшай канфігурацыі.

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

Рэдактую файл налад.

sudo vim /etc/default/gpsd

Усталёўваю UART, на якім будзе вісець GPS.

DEVICES="/dev/ttyS4"

І пасля ўсё ўключаем і стартуем.

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

Пасля чаго, падключаю GPS.

Адначасовы speedtest на некалькіх LTE-мадэмах

У руках провад GPS, пад пальцамі бачныя правады UART адладчыка.

Перазагружаюся, і правяраю працу GPS з дапамогай праграмы gpsmon.

Адначасовы speedtest на некалькіх LTE-мадэмах

На гэтым скрыншоце спадарожнікаў не відаць, але відаць зносіны з GPS-прымачом, і гэта кажа, што ўсё добра.

На python апрабаваў шмат варыянтаў працы з дадзеным дэманам, але я спыніўся на тым, які карэктна працаваў з python 3.

Усталёўваю неабходную бібліятэку.

sudo -H pip3 install gps3 

І вываю код працы.

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

Калі мне трэба атрымаць каардынаты, тое робіцца гэта наступным выклікам:

longitude, latitude = getPositionData(agps_thread)

І на працягу 1-10 секунд я альбо атрымаю каардынату, альбо не. Так, у мяне спробаў атрымаць каардынаты было дзесяць. Не аптымальна, крыва і наперакос, але працуе. Я вырашыў так зрабіць, таму што GPS можа лавіць дрэнна і не заўседы атрымліваць дадзеныя. Калі чакаць атрыманні дадзеных, то ў выпадку працы ў глухім памяшканні, праграма завісне ў гэтым месцы. Таму рэалізаваў такі не элегантны варыянт.

У прынцыпе, было б больш часу, можна было б напрамую па UART атрымліваць дадзеныя з GPS, парсіць іх у асобным патоку і працаваць з імі. Але часу не было зусім, адсюль люты непрыгожы код. І так, мне не сорамна.

святлодыёд

З падключэннем святлодыёда было ўсё проста і складана адначасова. Галоўная складанасць у тым, што нумар піна ў сістэме не адпавядае нумару піна на плаце і таму што дакументацыя напісана левай пяткай. Каб супаставіць нумар апаратнага піна і нумар піна ў АС, трэба выканаць каманду:

gpio readall

Будзе выведзена табліца адпаведнасці піна ў сістэме, і на плаце. Пасля чаго я ўжо магу апераваць пінам у самой АС. У маім выпадку святлодыёд падлучаны да GPIOH_5.

Адначасовы speedtest на некалькіх LTE-мадэмах

Перакладаю пін GPIO у рэжым вываду.

gpio -g mode 421 out

Запісваю нуль.

gpio -g write 421 0

Запісваю адзінку.

gpio -g write 421 1

Адначасовы speedtest на некалькіх LTE-мадэмах
Усё гарыць, пасля запісу "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)

Цяпер, у выпадку памылак я выклікаю error_blink() і святлодыёд нам прыгожа міргае.

Праграмныя вузлы

Speedtest API

Вялікая радасць, што ў сервісу speedtest.net ёсць свой уласны python-API, паглядзець можна на Github.

Чым добра, што есць зыходныя коды, якія таксама можна паглядзець. Як працаваць з дадзеным API (найпростыя прыклады) можна паглядзець у адпаведным раздзеле.

Усталёўваю python-бібліятэку наступнай камандай.

sudo -H pip3 install speedtest-cli

Для прыкладу вы можаце наогул паставіць спідтэстар у Ubuntu прама з рэп. Гэта таксама самае python-дадатак, якое потым можна запусціць прама з кансолі.

sudo apt install speedtest-cli -y

І зрабіць замеры хуткасці вашага інтэрнэту.

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

У выніку, як зрабіў гэта я. Мне прыйшлося ўлезці ў зыходныя коды гэтага спідтэсту, каб больш поўна ўкараніць іх у мой праект. Адна з найважнейшых задач – гэта атрымліваць яшчэ імя аператара сувязі, для падстаноўкі яго ў таблічку.

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"
#тут идет запись в файл логов

Тут таксама аказалася не так усё проста, хоць, здавалася б, куды прасцей. Першапачаткова параметр servers у мяне быў роўны [], Маўляў абяры лепшы сервер. У выніку ў мяне былі выпадковыя сервера, і як няцяжка здагадацца, якая плавае хуткасць. Гэта дастаткова складаная тэма, выкарыстоўваць фіксаваны сервер, калі так, то статычны ці дынамічны, патрабуе даследавання. Але вось прыклад графікаў замераў хуткасці аператара Білайн пры дынамічным выбары тэставага сервера і статычна зафіксаванага.

Адначасовы speedtest на некалькіх LTE-мадэмах
Вынік вымярэння хуткасці пры выбары дынамічнага сервера.

Адначасовы speedtest на некалькіх LTE-мадэмах
Вынік тэсціравання хуткасці, пры адным строга абраным адным серверы.

"Поўсць" пры тэставанні ёсць і там і там, і яе трэба прыбіраць матэматычнымі метадамі. Але пры фіксаваным серверы яе крыху менш і амплітуда стабільней.
Наогул гэтае месца вялікіх даследаванняў. І я бы праводзіў замеры хуткасці да свайго сервера, па сродкам утыліты iperf. Але мы прытрымліваемся ад ТЗ.

Адпраўка пошты і памылак

Для адпраўкі пошты паспрабаваў некалькі дзясяткаў розных варыянтаў, але ў выніку спыніўся на наступным. Зарэгістраваў паштовую скрыню на yandex і далей узяў дадзены прыклад адпраўкі пошты. Праверыў яго і ўкараніў у праграму. У гэтым прыкладзе разбіраюцца розныя варыянты, у тым ліку адпраўка з gmail і да т.п. Вазіцца з узняццем свайго паштовага сервера мне не хацелася і не было часу на гэта, але як потым аказалася таксама дарма.

Адпраўка логаў рабіў па планавальніку, пры наяўнасці сувязі, кожныя 6 гадзін: у 00 гадзін, 06 раніцы, 12 дні і 18 вечара. Адпраўляў наступным чынам.

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

Памылкі таксама першапачаткова адпраўляліся. Для пачатку яны назапашваліся ў спісе, і потым адпраўляў таксама з дапамогай планавальніка, пры наяўнасці сувязі. Аднак потым узніклі праблемы з тым, што yandex мае абмежаванне на колькасць адпраўляемых паведамленняў у суткі (гэта боль, смутак і зневажэнне). Паколькі памылак нават у хвіліну магла быць вялізная колькасць, адпаведна ад адпраўкі памылак па пошце прыйшлося адмовіцца. Так што майце на ўвазе, пры аўтаматычнай адпраўкі праз сэрвісы яндэкса аб такой праблеме.

Сервер зваротнай сувязі

Для таго, каб мець доступ да выдаленай жалязякі і мець магчымасць яе даналадзіць і пераканфігураваць мне спатрэбіўся вонкавы сервер. Наогул, справядлівасці кажучы, правільна было б усе дадзеныя адпраўляць на сервер і ў вэб-інтэрфейсе будаваць усе прыгожыя графікі. Але не ўсё адразу.

У якасці VPS я абраў ruvds.com. Можна было б узяць самы просты сервер. І ў цэлым для маіх мэт гэтага хапіла б за вочы. Але паколькі плаціў за сервер не са сваёй кішэні, вырашыў узяць з невялікім запасам, каб хапіла, калі будзем разгортваць web-інтэрфейс, свой SMTP-сервер, vpn і т.д. Плюс мець магчымасць наладзіць Telegram-бота і не мець праблем з яго блакіроўкамі. Таму абраў Amsterdam і наступныя параметры.

Адначасовы speedtest на некалькіх LTE-мадэмах

У якасці спосабу сувязі з жалязякай vim2 абраў зваротнае ssh злучэнне і як паказала практыка - не самае лепшае. Пры разрыве злучэння, сервер утрымлівае порт і па ім немагчыма падлучыцца некаторы час. Таму, усё ж лепей выкарыстоўваць іншыя спосабы сувязі, напрыклад vpn. У будучыні хацеў перайсці на vpn, але не паспеў.

Не буду ўдавацца ў падрабязнасці налады файрвала, абмежаванні правоў, адключэнні ssh злучэння root і іншыя вялікія ісціны налады VPS. Жадаецца верыць, што вы і так усё ведаеце. Для выдаленага злучэння, ствараю новага карыстальніка на сэрвэры.

adduser vimssh

На нашай жалязяцы генерую ключы ssh злучэння.

ssh-keygen

І капіюю іх на наш сервер.

ssh-copy-id [email protected]

На нашай жалязяцы ствараю аўтаматычнае падлучэнне зваротнага ssh пры кожнай загрузцы.

[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

Звярніце ўвагу на порт 8083: ён і вызначае па якім порце ў мяне будзе ажыццяўляецца падлучэнне праз зваротны ssh. Дадаем у аўтазагрузку і стартуем.

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

Можна нават паглядзець статут:

sudo systemctl status autossh.service

Цяпер, на нашым VPS-серверы, калі выканаць:

ssh -p 8083 khadas@localhost

То я пападаю на маю тэставую жалязяку. І з жалязякі магу гэтак жа адпраўляць логі і любыя дадзеныя па ssh на мой сервер, што вельмі зручна.

Збіраны ўсё разам

Адначасовы speedtest на некалькіх LTE-мадэмах
Уключэнне, прыступаем да распрацоўкі і адладкі

Фух, ну накшталт усё, апісаў усе вузлы. Цяпер прыйшоў час сабраць усё гэта ў адзіную кучу. Код можна паглядзець вось тут.

Важны момант з кодам: Дадзены праект вось дык вось «улоб» можа не запусціцца, бо вострыўся на вызначаную задачу, вызначанай архітэктуры. Хоць я і даю зыходнікі, але ўсё ж самае каштоўнае разбяру вось тут, прама ў тэксце, інакш зусім незразумела.

У пачатку ў мяне ідзе ініцыялізацыя gps, gpio і запуск асобнай плыні планавальніка.

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

Планавальнік дастаткова просты: ён глядзіць ці не прыйшоў час адпраўкі паведамленняў і які зараз стаіць статус памылак. Калі ёсць сцяг памылкі, то міргаем святлодыёдам.

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

Самы складаны момант у дадзеным праекце - гэта захоўваць зваротнае ssh-злучэнне пры кожным тэсце. У кожным тэсце ідзе зноўку настройка шлюза па змаўчанні і dns-сервера. Паколькі ўсё роўна ніхто не чытае, то ведайце, што цягнік не катаецца па драўляных рэйках. Хто знойдзе пасхалку, таму цукерка.

Для гэтага я ствараю асобную табліцу маршрутызацыі -set-mark 0x2 і правіла для перанакіравання трафіку.

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

Больш падрабязна аб тым, як гэта працуе можна прачытаць у гэтым артыкуле.

Пасля чаго пераходжу ў бясконцы цыкл, дзе кожны раз атрымліваем спіс падлучаных мадэмаў (каб пазнаць, раптам канфігурацыя сеткі змянілася).

network_list = getNetworklist()

Атрыманне спісу сеткавых інтэрфейсаў дастаткова простае.

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

Пасля атрымання спісу, задаю IP-адрасы ўсім інтэрфейсам, як я прыводзіў на малюнку ў главе пра мадэм.

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

Далей проста ў цыкле іду па кожным інтэрфейсе. І канфігурую кожны інтэрфейс.

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

Правяраю інтэрфейс на працаздольнасць, калі сеткі няма, то фармую памылкі. Калі сетка ёсць, то час дзейнічаць!

Тут я наладжваю ssh маршрутызацыю на дадзены інтэрфейс (калі не было зроблена), адпраўляю памылкі на сервер, калі час нетутэйша, адпраўляю логі і ў выніку праводжу speedtest і захоўваем логі ў 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()
#и далее тестируем скорость и сохраняем логи. 

Няўжо што варта сказаць аб функцыі налады зваротнага 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")

Ну і вядома ж, неабходна ўсю гэтую прыгажосць дадаць у аўтазагрузку. Для гэтага ствараю файл:

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

І запісваю ў яго:

[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

Уключаю аўтазагрузку і стартую!

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

Цяпер я магу глядзець логі таго, што адбываецца з дапамогай каманды:

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

Вынікі

Ну зараз самае галоўнае, што ж атрымалася ў выніку? Прывяду некалькі графікаў, якія мне ўдалося засняць у працэсе распрацоўкі і адладкі. Графікі будаваліся з дапамогай gnuplot наступным скрыптам.

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

Першы досвед быў аператара Tele2, які я праводзіў на працягу некалькіх дзён.

Адначасовы speedtest на некалькіх LTE-мадэмах

Тут я выкарыстоўваў дынамічны вымяральны сервер. Замеры хуткасці працуюць, але вельмі моцна плаваюць, аднак усё ж бачная некаторая сярэдняя велічыня, і яе можна атрымаць, вырабячы фільтраванне дадзеных, напрыклад, слізгальным сярэднім.

Пазней я пабудаваў яшчэ шэраг графікаў для іншых аператараў сувязі. Сервер тэсціравання ў гэтым выпадку ўжо быў адзін, і вынікі таксама вельмі цікавыя.

Адначасовы speedtest на некалькіх LTE-мадэмах

Адначасовы speedtest на некалькіх LTE-мадэмах

Адначасовы speedtest на некалькіх LTE-мадэмах

Адначасовы speedtest на некалькіх LTE-мадэмах

Як бачна тэма вельмі шырокая для даследаванняў і апрацоўкі гэтых дадзеных, і відавочна не цягне на пару тыдняў працы. Але...

Вынік працы

Праца была рэзка завершана па незалежных ад мяне абставінах. Адной са слабых бакоў дадзенага праекту, на мой суб'ектыўны погляд, быў мадэм, які не вельмі жадаў працаваць адначасова з іншымі мадэмамі, і пры кожнай загрузцы вырабляў такія фортэль. Для гэтых мэт існуе велізарная колькасць іншых мадэляў мадэмаў, звычайна яны ўжо маюць фармат Mini PCI-e і ставяцца ўнутр прылады і іх моцна прасцей канфігураваць. Але гэта ўжо зусім іншая гісторыя. Праект быў цікавы і быў вельмі рады, што ўдалося ў ім паўдзельнічаць.

Адначасовы speedtest на некалькіх LTE-мадэмах

Крыніца: habr.com

Дадаць каментар