Цели и задачи

Работающий интернет в частный дом в Московской области. Проводных аналогов нет.

Что имеем на руках

Роутер Mikrotik hap ac3 LTE. Но можно любой микротик + LTE модем - я настраивал сначала все именно так, а потом переносил на микротик LTE. Всю сложную логику будем реализовывать на микротике.

Прошивка RouterOS 7.20.7 long term.

Мобильный тариф с безлимитным интернетом. Тут развилка:

  1. Либо у нас тариф для роутера - тогда перед нами все дороги открыты. Можем использовать роутер микротик LTE - просто вставляем симку в него и настраиваем. Модем использовать микротик без LTE - тогда покупаем любой LTE модем с USB и втыкаем его в микротик. Главное чтобы модем не был прошит под IMEI смартфона, т.к. в смартфоне данная симкарта может не заработать (зависит от оператора)

  2. Либо у нас тариф для смартфона. Тогда симку нельзя вставлять в микротик LTE или другой LTE роутер, потому что оператор это просечет (по IMEI LTE модуля роутера и может в добавок по TTL) и заблокирует интернет на симке. Тут нужен как раз LTE модем прошитый под телефонный IMEI - такие сейчас продаются готовые на любом маркетплейсе. Смотрите его IMEI в настройках роутера в GUI и проверяете на любом сайте проверке IMEI - должен показать модель телефона к которому он относится. Тут у нас получится вариант микротик (любой) + прошитый LTE модем USB.

Нулевой вариант

Вставляем симкарту в LTE роутер и интернет работает. Но не стабильно, медленно, многие сайты периодически не открываются. Если у вас все стабильно и все всегда открывается, нет проблем с сайтами 4pda, xiaomi, не говоря уже у google play, дальше можете не читать - статья для тех у кого есть проблемы при настройках по умолчанию, как было у меня.

Базовые (простейшие) настройки

Закрепить в настройках LTE роутера выбор сети - только LTE, остальные варианты отключаем.

Закрепить конкретную частоту в настроке LTE роутера. Для этого смотрим за какую частоту он зацепился, выбираем только ее, остальные выключаем.

Смотрим качество сигнала, меряем скорость интернета.

Сила сигнала чем больше тем лучше (ближе к нулю лучше, всегда показывает с минусом)

Качество сигнала (SINR) чем больше тем лучше (должно быть 10 и выше, если сигнал хороший).

Далее в настройках оставляем все частоты, кроме той которую замерили, и повторяем все по кругу - смотрим за какую частоту теперь зацепился, проверяем ее качество и скорость. Так пока не переберем все доступные частоты (т.е. у нас остануться включенными часть частот на которые уже не будет подключаться интернет).

В принципе для ускорения предварительно можно посмотреть доступные частоты в точке установки LTE модема через телефон, приложение NetMonster.
Ставите в телефон ту симкарту которая будет в модеме, телефон в ту точку где будет стоять LTE модем, и смотрите доступные частоты и силу и качество сигнала в них. Но учтите, что модем в телефоне гораздо мощнее чем в LTE модеме, кроме того в телефоне есть агрегация частот, и мгновенное переключение между ними (подключение новых). Так что сила и качество сигнала которую покажет телефон будет намного лучше чем в модеме потом. Но нам главное понять 1-2 самых лучших частоты в данной точке и потом проверить их в LTE модеме.

Здесь мы видим 2 частоты: 2600 и 1800, проверять на LTE модеме будем именно их
Здесь мы видим 2 частоты: 2600 и 1800, проверять на LTE модеме будем именно их

Управление качеством

Если после выполнения базовых настроек у нас все равно что-то отваливается, не открываются сайты периодически, то читаем дальше.

У решил сделать комплексную систему мониторинга, оповещения и управления качеством.

На самом деле вариантов управления у нас не так много:

  1. Уменьшать / балансировать MSS (размер пакета) при плохом качестве интернета

  2. Перезапускать LTE модуль для получения нового ip и выхода из блокировок DPI / залипания сессии и т.п.

Для этого нам нужно 1) мониторить качество интернета - настраиваем 2 правила mangle (счетчики качества) на микротик. Заходим в GUI (192.168.88.1), терминал:

/ip firewall mangle
add action=passthrough chain=forward comment=DATA_TRAFFIC connection-state=established protocol=tcp
add action=passthrough chain=forward comment=TCP_ERRORS connection-state=invalid protocol=tcp

Проверить можно в IP --> Firewall --> Mangle

Качество = 100% - %ошибок, где %ошибок = TCP-ошибки / TCP-траффик за период

Можно также смотреть ошибки TCP_RST, но я их не пока не успел настроить.

Если ошибок > порога, будем снижать MSS для стабилизации канала. Если ошибок < порога в течении определенного времени, будем медленно повышать MSS обратно.

2) проверять доступность ключевых сервисов (сайтов). В моем случае это базовые Android и Microsoft (те которые проверяются смартфоном и виндой и если с ними проблемы появляется восклицательный знак на сети Wifi) и важные для меня xiaomi и 4pda. Базовые я рекомендую оставить, а дополнительные у вас могут быть свои.

Если не доступна часть (или хотя бы один) сервисов - пробуем резко снизить mss, и проверить этот сервис еще раз. Если не получается даже с очень низким MSS, то имеем либо физическую проблему на канале, либо зависание сессии LTE, либо что чаще всего для тяжелых https сервисов типа 4pda - DPI блокировку оператора.

Во всех этих случаях наш вариант - перезагрузка LTE модема. Я делал мягкую перезагрузку LTE интерфейса в микротик (disable/enable), но можно попробовать и более быстрый вариант (режим полета вкл/выкл) - через AT команду. Цель этого - перерегистрироваться в сети оператора и получить новый ip, который пройдет по новым чистым путям до наших сервисов и они станут доступны.

Автоматизация - мониторинг качества интернета

  1. Создаем счетчики mangle для расчета качества (см. выше скрипт)

  2. Создаем правило mangle для управление параметром MSS

  3. Создаем скрипт для анализа счетчиков, расчета качества и динамическим управлением MSS. Дополнительно этот скрипт будет логировать метрики если %ошибок > 0 или если меняем MSS (в любую сторону) (скрипт будет ниже)

  4. Ставим на график запуска - каждые 5 сек (чтобы быстрее реагировать на падение качества)

Правило mangle для управления параметром MSS (обратите внимание на out-interface - там должно быть имя вашего LTE интерфейса в микротик)

/ip firewall mangle
add action=change-mss chain=forward comment=MSS_ADAPTIVE connection-state=new new-mss=1100 out-interface=lte1 protocol=tcp tcp-flags=syn tcp-mss=501-65535

Скрипт "script_changeMSS_on_Network_Quality"

# Запускать каждые 5 сек!
##########################
:local runPeriodSec 5
:local dataComment "DATA_TRAFFIC"
:local errorComment "TCP_ERRORS"
:local mssComment "MSS_ADAPTIVE"

####################################
### ВЫСТАВИТЬ ВЕРСИЮ СКРИПТА!!! ####
####################################
:global gMSSVersion "1.82"
####################################
####################################

:global gLastDataPacketsMangle
:global gLastErrPacketsMangle
:global gNoErrCycles
:global gMSSnotGoDownCycles
:global gSumData

:global gMSSchangedWhileCheckingServices
:global gIsCheckingServices

:local mssMax 1360
:local mssMin 800
:local mssGood (($mssMax + $mssMin) / 2)

:local mssStepUpSlow 10
:local mssStepUpFast 50
:local mssStepUp $mssStepUpSlow

:local mssStepDownFast   300
:local mssStepDownMiddle 150
:local mssStepDownSlow   100
:local mssStepDown $mssStepDownMiddle

:local rateThreshold     3
:local noErrCyclesForMssUp 	 	(50 / $runPeriodSec); # Сколько циклов тишины ждем (50 сек)
:local minCyclesBetweenMssDown	(30 / $runPeriodSec); 

:local dataPacketsIgnore  (3 * $runPeriodSec)
:local errPacketsIgnore   2

:local currData [/ip firewall mangle get [find comment=$dataComment] packets]
:local currErr [/ip firewall mangle get [find comment=$errorComment] packets]

:if ([:len $gLastDataPacketsMangle] = 0) do={ :set gLastDataPacketsMangle $currData; :set gLastErrPacketsMangle $currErr; :set gNoErrCycles 0; :set gSumData 0; :set gMSSnotGoDownCycles 0; }
:if ([:len $gIsCheckingServices] = 0) do={ :set gIsCheckingServices false; }

:local dataPackets ($currData - $gLastDataPacketsMangle)
:local errPackets ($currErr - $gLastErrPacketsMangle)
:set gLastDataPacketsMangle $currData
:set gLastErrPacketsMangle $currErr

:local mssID [/ip firewall mangle find comment=$mssComment]

# ЕСЛИ Правило Mangle задано (есть чем управлять) и есть данные с предыдушего запуска
:if ([:len $mssID] > 0 && $dataPackets > 0) do={

    :local currentMSS [/ip firewall mangle get $mssID new-mss]
	
	:if ([:len $currentMSS] = 0 || [:typeof [:tonum $currentMSS]] = "nil") do={
        :set currentMSS $mssGood
    }
    :local nextMSS $currentMSS
	:if ($currentMSS < $mssGood) do={ :set mssStepUp $mssStepUpFast } else={ :set mssStepUp $mssStepUpSlow }

	:local rawRate 0
    :if ($dataPackets > 0) do={
        :set rawRate (($errPackets * 10000) / $dataPackets)
    }
	:local intRate ($rawRate / 100)
	:local fracRate ($rawRate % 100)
	:local padding ""
	:if ($fracRate < 10) do={ :set padding "0" }

	:if ($errPackets > 0) do={
		:set gNoErrCycles 0;
		:set gSumData $dataPackets;
	} else={
		:set gNoErrCycles ($gNoErrCycles + 1); 
		:set gSumData ($gSumData + $dataPackets);
	}
    # Увеличиваем счетчик здесь, чтобы не зависить от объема трафика ниже. Если будет сброс ниже, то этот счетчик все равно обнулится
	:set gMSSnotGoDownCycles ($gMSSnotGoDownCycles + 1)

	# Формируем строку NoErrCycles для лога (потому что потом gNoErrCycles может изменится, а мы хотим в логе видеть то что было)
	:local noErrCyclesLogString $gNoErrCycles

	:if ($dataPackets >= $dataPacketsIgnore) do={

		# ЛОГИКА СБРОСА (Снижение) - превышен порог ошибок как в % так и в шт., есть куда опускаться, не опускались в ближайших предыдущих циклах
		:if ($intRate >= $rateThreshold && $errPackets > $errPacketsIgnore && $currentMSS > $mssMin && $gMSSnotGoDownCycles >= $minCyclesBetweenMssDown) do={
		
			:if ($intRate > 30) do={ 
				:set mssStepDown $mssStepDownFast 
			} else={ 
				:if ($intRate > 10) do={ 
					:set mssStepDown $mssStepDownMiddle 
				} else={ 
					:set mssStepDown $mssStepDownSlow 
				}
			}
			
			:set nextMSS ($currentMSS - $mssStepDown)
			:if ($nextMSS < $mssMin) do={ :set nextMSS $mssMin }
			:set gMSSnotGoDownCycles 0;
			
		} else={
			# ЛОГИКА ПОДЪЕМА - есть куда подниматься, нет ошибок в течении нескольких последних циклов, не выполняются проверки сервисов
			:if ($currentMSS < $mssMax && $gNoErrCycles >= $noErrCyclesForMssUp && $gIsCheckingServices = false) do={
				:set nextMSS ($currentMSS + $mssStepUp)
				:if ($nextMSS > $mssMax) do={ :set nextMSS $mssMax }
				:set gNoErrCycles 0;
			}
		}
		
	}
	
	# Формируем строку MSS для лога И МЕНЯЕМ MSS!
	:local mssLogString $currentMSS
	:if ($nextMSS != $currentMSS) do={
		/ip firewall mangle set $mssID new-mss=$nextMSS
		:set mssLogString "$currentMSS -> $nextMSS"
		:if ($gIsCheckingServices = true) do={ :set gMSSchangedWhileCheckingServices true; }
	}

	# ЛОГИРОВАНИЕ С РАЗДЕЛЕНИЕМ УРОВНЕЙ (только если есть ошибочные пакеты или изменили MSS)
	:if ($errPackets > 0 || $nextMSS != $currentMSS) do={
		:local logMsg "MSS_ADAPT: Traffic: $gSumData, Errors: $errPackets, Rate: $intRate.$padding$fracRate%, MSS: $mssLogString, NoErrCycles: $noErrCyclesLogString"
		
		:if ($nextMSS < $currentMSS || ($intRate >= $rateThreshold && $errPackets > $errPacketsIgnor)) do={
			# Если стало хуже (снижаем MSS) - пишем Warning
			:log warning $logMsg
		} else={
			# Если стало лучше (повышаем) или сохраняем стабильный MSS - пишем Info
			:log info $logMsg
		}
		# Если напечатали трафик, сбрасываем чтобы в следующий раз считать заново
		:set gSumData 0
	}
}

Ставим на график запуска:

/system scheduler
add interval=5s name=job_changeMSS_on_Network_Quality on-event=script_changeMSS_on_Network_Quality policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon start-time=startup

Через несколько секунд/минут в логе должны пойти примерно такие записи:

2026-01-23 09:03:59 script,info MSS_ADAPT: Traffic: 151, Errors: 0, Rate: 0.00%, MSS: 910 -> 915, NoErrCycles: 4 
2026-01-23 09:04:39 script,info MSS_ADAPT: Traffic: 255, Errors: 0, Rate: 0.00%, MSS: 915 -> 920, NoErrCycles: 4 
2026-01-23 09:05:19 script,info MSS_ADAPT: Traffic: 429, Errors: 0, Rate: 0.00%, MSS: 920 -> 925, NoErrCycles: 4 
2026-01-23 09:05:59 script,info MSS_ADAPT: Traffic: 432, Errors: 0, Rate: 0.00%, MSS: 925 -> 930, NoErrCycles: 4 
2026-01-23 09:06:19 script,info MSS_ADAPT: Traffic: 63, Errors: 1, Rate: 1.58%, MSS: 800, NoErrCycles: 0 
2026-01-23 09:07:09 script,warning MSS_ADAPT: Traffic: 18, Errors: 4, Rate: 22.22%, MSS: 800, NoErrCycles: 0 
2026-01-23 09:07:59 script,info MSS_ADAPT: Traffic: 82, Errors: 0, Rate: 0.00%, MSS: 800 -> 805, NoErrCycles: 5 
2026-01-23 09:08:09 script,info MSS_ADAPT: Traffic: 90, Errors: 1, Rate: 1.11%, MSS: 805, NoErrCycles: 0 

Автоматизация - мониторинг доступности сервисов и жесткие действия

  1. Создаем бота в телеге который будет нам слать ошибки

  2. Создаем скрипт мониторинга доступности сервисов, тестирования на экстремально низком MSS и перезагрузки LTE-модема. А также будем слать уведомления в Telegram при ошибках. В лог конечно тоже все запишем.

  3. Ставим на график раз в 3 минуты

Скрипт "script_Check_Limited_Internet"

:global gIsCheckingServices true;
:global gMSSchangedWhileCheckingServices;
:if ([:len $gMSSchangedWhileCheckingServices] = 0) do={ :set gMSSchangedWhileCheckingServices false; }

:local mssComment "MSS_ADAPTIVE"
:local isDPIbock false
:local androidCheckHttps "ER";
:local windowsCheckHttp "ER";
:local miCheckHttps "ER";
:local forPDACheckHttps "ER";

####################################
### ВЫСТАВИТЬ ВЕРСИЮ СКРИПТА!!! ####
####################################
:global gServicesVersion "4.64"
####################################

##########################################################
# ЗАМЕНИТЬ МНОГОТОЧИЯ НА ID СВОЕГО БОТА и ЧАТА В ТЕЛЕГЕ ##
##########################################################
:local sBotId "........"
:local sChatId "......."
##########################################################

:local sDiagnoseMessages ""
:local logGlobalPfx "CHECK_INET:"

# Считывем текущее значение MSS
:local mssID [/ip firewall mangle find comment=$mssComment]
:local initialMSS ""
:if ([:len $mssID] > 0) do={
    :set initialMSS [/ip firewall mangle get $mssID new-mss]
}

# Объявляем функцию сброса MSS
:local dropMSS do={
	:local newMSSonError 500
	:global gNoErrCycles 0;
	:global gSumData 0;
    :if ([:len $3] > 0) do={
        :global gPrevMSS [/ip firewall mangle get $3 new-mss]
        :if ($gPrevMSS > $newMSSonError) do={
            /ip firewall mangle set $3 new-mss=$newMSSonError
			:log warning "$1 $2 failure detected. Try dropping MSS: $gPrevMSS -> $newMSSonError, NoErrCycles: 0"
			:delay 2s
        }
    }
}
# Объявляем функцию восстановления MSS
:local restoreMSS do={
    :if ([:len $3] > 0) do={
        :local curMSS [/ip firewall mangle get $3 new-mss]
		:global gPrevMSS;
		:if ($curMSS != $gPrevMSS) do={
			/ip firewall mangle set $3 new-mss=$gPrevMSS
			:log warning "$1 $2 DPI block detected, restoring MSS: $gPrevMSS"
			:delay 2s
		}
    }
}

# 1. ЗАЩИТА: Не трогаем модем первые 5 минут после старта роутера
:local lteStatus [/interface lte monitor lte1 once as-value];
:local lteUp ($lteStatus->"session-uptime");
:if ([:len $lteUp] = 0) do={ :set lteUp ($lteStatus->"uptime") };
# Если аптайм пустой (модем инициализируется) или меньше 5 минут
:if ([:len $lteUp] = 0 or $lteUp < 00:05:00) do={
    :log warning "$logGlobalPfx LTE Guard: Modem is warming up (current: $lteUp). Skipping check.";
    :error "Warmup mode";
}

# 1.1 Проверка Android Style HTTPS (max 9 sec)
:do {
	:set $gMSSchangedWhileCheckingServices false
    /tool fetch url="https://connectivitycheck.gstatic.com/generate_204" check-certificate=no keep-result=no idle-timeout=3s;
    :set androidCheckHttps "ok";
} on-error={
	:log warning "$logGlobalPfx Android Check HTTPS: FAILED (https://connectivitycheck.gstatic.com/generate_204)"
	# МГНОВЕННЫЙ СБРОС MSS ДЛЯ БЫСТРОГО ВОССТАНОВЛЕНИЯ
	[$dropMSS $logGlobalPfx "Android" $mssID];
	:do {
		/tool fetch url="https://www.google.com/generate_204" check-certificate=no keep-result=no idle-timeout=3s;
		:set androidCheckHttps "ok";
	} on-error={
		:log warning "$logGlobalPfx Android Check HTTPS: FAILED (https://www.google.com/generate_204)"
		:do {
			/tool fetch url="https://play.google.com/generate_204" check-certificate=no keep-result=no idle-timeout=3s;
			:set androidCheckHttps "ok";	
		} on-error={
			:log warning "$logGlobalPfx Android Check HTTPS: FAILED (https://play.google.com/generate_204)"
			
			# Если после сброса все проверки отвалились, то восстанавливаем MSS (имеем дело с DPI блокировкой или полным отсутствием интернета или попали на опускание MSS другим скриптом)			
			[$restoreMSS $logGlobalPfx "Android" $mssID];
			
			#если при этом попали на опускание mss другим скриптом, то не доверяем результату - ставим skipped
			if ($gMSSchangedWhileCheckingServices = true) do={ 
				:set androidCheckHttps "skipped" 
				:log info "$logGlobalPfx Android Check HTTPS: skipped due to MSS change while checking"
			
			} else={
				:set isDPIbock true;
			}
		};
	};
};

# 1.2 Проверка Microsoft Style (max 15 sec)
# если все проверки Android провалились, не тратим время на MS - ставим skipped, нужно быстрее перезагружать модем!
:if ($androidCheckHttps = "ER" ) do={
	:set windowsCheckHttp "skipped"
	:log info "$logGlobalPfx Microsoft Check HTTP: skipped due to Android HTTPS fail"

} else={
	:set $gMSSchangedWhileCheckingServices false
	:local isMSSdroped false
	:for i from=1 to=3 do={
		:if ($windowsCheckHttp != "ok") do={
			:do {
				/tool fetch url="http://www.msftconnecttest.com/connecttest.txt" keep-result=no idle-timeout=3s;
				:set windowsCheckHttp "ok";
			} on-error={
				:log warning "$logGlobalPfx Microsoft Check HTTP: FAILED, i=$i"

				# МГНОВЕННЫЙ СБРОС MSS ДЛЯ БЫСТРОГО ВОССТАНОВЛЕНИЯ
				if ($isMSSdroped = false) do={
					[$dropMSS $logGlobalPfx "Microsoft" $mssID];
					:set isMSSdroped true;
				}
			}
		}
	}
	# Если после сброса все проверки отвалились, то восстанавливаем MSS (имеем дело с DPI блокировкой или полным отсутствием интернета или попали на опускание MSS другим скриптом)			
	if ($windowsCheckHttp != "ok") do={
		[$restoreMSS $logGlobalPfx "Microsoft" $mssID];
			
		#��сли при этом попали на опускание mss другим скриптом, то не доверяем результату - ставим skipped
		if ($gMSSchangedWhileCheckingServices = true) do={
			:set windowsCheckHttp "skipped" 
			:log info "$logGlobalPfx Microsoft Check HTTP: skipped due to MSS change while checking"

		} else={
			:set isDPIbock true;
		}
	}
}

# 1.3 Проверка Xiaomi (max 21 sec)
# если все проверки Android провалились или проверка Microsoft провалилась, не тратим время на Xiaomi - ставим skipped
:if ($windowsCheckHttp = "skipped" or $windowsCheckHttp = "ER") do={
	:set miCheckHttps "skipped"
	:log info "$logGlobalPfx Xiaomi Check HTTPS: skipped due to Android/Microsoft HTTPS/HTTP fail or DPI block"

} else={
	:set $gMSSchangedWhileCheckingServices false
	:local isMSSdroped false
	:for i from=1 to=2 do={
		:if ($miCheckHttps != "ok") do={
			:do {
				/tool fetch url="https://region.hlth.io.mi.com/abroad_download?redir=11817" check-certificate=no keep-result=no idle-timeout=5s http-max-redirect-count=5;
				:set miCheckHttps "ok";
			} on-error={
				:log warning "$logGlobalPfx Xiaomi Check HTTPS: FAILED, i=$i"

				# МГНОВЕННЫЙ СБРОС MSS ДЛЯ БЫСТРОГО ВОССТАНОВЛЕНИЯ
				if ($isMSSdroped = false) do={
					[$dropMSS $logGlobalPfx "Xiaomi" $mssID];
					:set isMSSdroped true;
				}
			}
		}
	}
	# Если после сброса все проверки отвалились, то восстанавливаем MSS (имеем дело с DPI блокировкой или полным отсутствием интернета или попали на опускание MSS другим скриптом)			
	if ($miCheckHttps != "ok") do={
		[$restoreMSS $logGlobalPfx "Xiaomi" $mssID];
			
		#если при этом попали на опускание mss другим скриптом, то не доверяем результату - ставим skipped
		if ($gMSSchangedWhileCheckingServices = true) do={
			:set miCheckHttps "skipped" 
			:log info "$logGlobalPfx Xiaomi Check HTTPS: skipped due to MSS change while checking"

		} else={
			:set isDPIbock true;
		}
	}
};

# 1.4 Проверка forPDA (max 21 sec)
# если все проверки Android провалились или проверка Microsoft провалилась не тратим время на forPDA - ставим skipped
:if ($windowsCheckHttp = "skipped" or $windowsCheckHttp = "ER" or $isDPIbock) do={
	:set forPDACheckHttps "skipped"
	:log info "$logGlobalPfx forPDA Check HTTPS: skipped due to Android/Microsoft HTTPS/HTTP fail or DPI block"
	
} else={
	:set $gMSSchangedWhileCheckingServices false
	:local isMSSdroped false
	:for i from=1 to=2 do={
		:if ($forPDACheckHttps != "ok") do={
			:do {
				/tool fetch url="https://4pda.to/forum/index.php?showtopic=1065946&st=2240#entry141234147" check-certificate=no keep-result=no idle-timeout=5s http-max-redirect-count=5;
				:set forPDACheckHttps "ok";
			} on-error={
				:log warning "$logGlobalPfx forPDA Check HTTPS: FAILED, i=$i"

				# МГНОВЕННЫЙ СБРОС MSS ДЛЯ БЫСТРОГО ВОССТАНОВЛЕНИЯ
				if ($isMSSdroped = false) do={
					[$dropMSS $logGlobalPfx "4pda" $mssID];
					:set isMSSdroped true;
				}
			}
		}
	}
	# Если после сброса все проверки отвалились, то восстанавливаем MSS (имеем дело с DPI блокировкой или полным отсутствием интернета или попали на опускание MSS другим скриптом)			
	if ($forPDACheckHttps != "ok") do={
		[$restoreMSS $logGlobalPfx "4pda" $mssID];
			
		#если при этом попали на опускание mss другим скриптом, то не доверяем результату - ставим skipped
		if ($gMSSchangedWhileCheckingServices = true) do={
			:set forPDACheckHttps "skipped" 
			:log info "$logGlobalPfx 4pda Check HTTPS: skipped due to MSS change while checking"

		} else={
			:set isDPIbock true;
		}
	}
};

:local finalMSS ""
:local MSSmsg ""
:if ([:len $mssID] > 0) do={
    :set finalMSS [/ip firewall mangle get $mssID new-mss]
	:if ($finalMSS != $initialMSS) do={
        :set MSSmsg "$initialMSS -> $finalMSS"
    } else={
        :set MSSmsg $initialMSS
    }
}

# Получаем внешний IP: Сначала Yandex API, если нет - Ipify
:global gLastPublicIP
:local currentPublicIP "unknown"
:do {
	:do {
		# Попытка через Yandex API
		:local result [/tool fetch url="https://yandex.ru/internet/api/v0/ip" mode=https output=user as-value duration=3s]
		# Проверяем наличие данных перед обработкой
		:if ([:len ($result->"data")] > 0) do={
			:local rawData ($result->"data")
			:set currentPublicIP [:pick $rawData ([:find $rawData "\""] + 1) [:find $rawData "\"" ([:find $rawData "\""] + 1)]]
		} else={ :error "fail" }
	} on-error={
		# Если Яндекс не ответил или данные пустые, пробуем Ipify
		:local result [/tool fetch url="https://api.ipify.org" mode=https output=user as-value duration=3s]
		:if ([:len ($result->"data")] > 0) do={
			:set currentPublicIP ($result->"data")
		} else={ :error "fail" }
	}
} on-error={
	# Сюда попадем, если оба запроса не вернули данные или упали по таймауту
	:set currentPublicIP "timeout"
}

# Очистка от возможных невидимых символов (переносы строк)
:if ($currentPublicIP != "timeout") do={
	:if ([:find $currentPublicIP "\n"] > 0) do={ :set currentPublicIP [:pick $currentPublicIP 0 [:find $currentPublicIP "\n"]] }
	:if ([:find $currentPublicIP "\r"] > 0) do={ :set currentPublicIP [:pick $currentPublicIP 0 [:find $currentPublicIP "\r"]] }
}

# Логика уведомления о смене IP
:local ipMsg ""
:if ([:len $currentPublicIP] > 0 && [:len $gLastPublicIP] > 0 && $currentPublicIP != $gLastPublicIP && $currentPublicIP != "timeout") do={
    :set ipMsg "$gLastPublicIP -> $currentPublicIP"
} else={
    :set ipMsg $currentPublicIP
}
:if ([:len $currentPublicIP] > 0 && $currentPublicIP != "timeout") do={
	:set gLastPublicIP $currentPublicIP
}	

:local sStatus ("As: " . $androidCheckHttps . ", MS: " . $windowsCheckHttp . ", XiaoMIs: " . $miCheckHttps . ", 4pda: " . $forPDACheckHttps . ", MSS: " . $MSSmsg . ", IP: " . $ipMsg)
:if ($isDPIbock = true) do={ :set sStatus ($sStatus . ", DPI BLOCK!!!") }

:set gIsCheckingServices false;
:set gMSSchangedWhileCheckingServices false;

# 2. Логика перезапуска и формирование сообщения для телеграмм: если не прошел AndroidHttpS или WindowsHttp
:if ($androidCheckHttps = "ER" or $windowsCheckHttp = "ER" or $isDPIbock = true) do={
    :log error "$logGlobalPfx INTERNET LIMITED!!! ($sStatus). Restarting LTE...";
	:set sStatus ("FAILED! " . $sStatus . ". Restarting LTE...")
	:if ([:len $sDiagnoseMessages] > 0) do={:set sStatus ($sStatus . "\r\n" . $sDiagnoseMessages)}

    /interface lte disable lte1;
    :delay 10s;
    /interface lte enable lte1;
    
    # Пауза 30 секунд, чтобы модем успел подключиться, прежде чем слать уведомление
    :delay 30s;

} else={
    :if ($androidCheckHttps = "ok" and $windowsCheckHttp = "ok" and $miCheckHttps = "ok" and $forPDACheckHttps = "ok") do={
		:log info "$logGlobalPfx FULL ACCESS (All OK: $sStatus)";
		:set sStatus ("success. " . $sStatus)
	} else= {
		:log warning "$logGlobalPfx CORE SERVICES ACCESS (Warning: $sStatus)";
		:set sStatus ("warning. " . $sStatus)
	}
	:if ([:len $sDiagnoseMessages] > 0) do={:set sStatus ($sStatus . "\r\n" . $sDiagnoseMessages)}

}

# 3. Отправка сообщения в телеграмм
:if ($androidCheckHttps = "ER" or $windowsCheckHttp = "ER" or $miCheckHttps = "ER" or $forPDACheckHttps = "ER") do={
	:do {
		/tool fetch http-method=post \
			url="https://api.telegram.org/bot$sBotId/sendMessage" \
			http-data="chat_id=$sChatId&text=$sStatus" \
			keep-result=no
	} on-error= {
		:log error "$logGlobalPfx Error sending statis message in Telegram , No Internet!"
	}
}

ВАЖНО!

  1. Впишите id бота и чата телеграм в переменные в начале скрипта

  2. Проверьте имя своего LTE интерфейса в микротике. У меня lte1, если у вас другое, поменяйте в скрипте

  3. Данная версия скрипта делаем мягкую перезагрузку модема при недоступности базовых сервисов (Android или Microsoft) или наличии DPI блокировки. Вы можете изменить это условие - добавить другой критичный вам сервис или отключить перезагрузку при DPI блокировке (она снимается перезагрузкой LTE модема, если он получает новый ip адрес). Ищите к в коде раздел "#2. Логика перезапуска ". Также можете поиграться с вкл/выкл режим полета через AT команды вместо мягкой перезагрузки, это должно работать быстрее чем перезагрузка и меньше вредить абонентам подключенным к роутеру.

  4. Для проверки наличия DPI блокировки я обваливаю MSS в пол (500) и делаю повторную проверку. Если она проходит, оставляю MSS=500, если нет возвращаю MSS обратно и ставлю флаг DPI блокировка. Возможно для вас даже краткосрочное падение MSS до 500 будет катастрофично (для каких то других сервисов), тогда скорректируйте уровень пола под себя. Это настраивается в функции dropMSS.

Ставим скрипт на график

/system scheduler
add interval=3m name=job_Check_Limited_Internet on-event=script_Check_Limited_Internet policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon start-time=startup

Через несколько минут в логе пойдут сообщения, например таки��:

2026-01-25 19:35:09 script,warning CHECK_INET: Xiaomi Check HTTPS: FAILED, i=1 
2026-01-25 19:35:10 script,warning CHECK_INET: Xiaomi failure detected. Try dropping MSS: 1000 -> 500, NoErrCycles: 0 
2026-01-25 19:35:43 script,warning CHECK_INET: Xiaomi Check HTTPS: FAILED, i=2 
2026-01-25 19:35:43 script,warning CHECK_INET: Xiaomi DPI block detected, restoring MSS: 1000 
2026-01-25 19:35:45 script,info CHECK_INET: forPDA Check HTTPS: skipped due to Android/Microsoft HTTPS/HTTP fail or DPI block 
2026-01-25 19:35:46 script,error CHECK_INET: INTERNET LIMITED!!! (As: ok, MS: ok, XiaoMIs: ER, 4pda: skipped, MSS: 1000, IP: 31.173.86.163, DPI BLOCK!!!). Restarting LTE... 
2026-01-25 19:38:55 script,info CHECK_INET: FULL ACCESS (All OK: As: ok, MS: ok, XiaoMIs: ok, 4pda: ok, MSS: 1050, IP: 31.173.86.163 -> 31.173.81.232) 
2026-01-25 19:40:55 script,info CHECK_INET: FULL ACCESS (All OK: As: ok, MS: ok, XiaoMIs: ok, 4pda: ok, MSS: 1110, IP: 31.173.81.232)

В случае ошибок - будут сыпаться сообщения в телегу!

Расчет и накопление статистики для анализа

Самом сложным в всем этом управлении качеством был поиск стратегии балансировки MSS чтобы уменьшить кол-во DPI блокировок, недоступности сервисов и перезагрузки LTE модема.

Насколько быстро опускать, как поднимать MSS, насколько быстро и жестко реагировать про появлении ошибок TCP или ошибок в сервисах.

Я хотел добиться поведения приближенного к android смартфону. Ясно что он управляет не только MSS, и в первую очередь у него есть другие инструменты которые не применимы здесь. Но уподобиться идеалу хотелось. Меня всегда возмущало что при появлении сообщения DPI block в моем скрипте тот же сайт в ту же секунду открывался через мобильный интернет того же самого оператора на смартфоне.

Я думаю я не достиг идеала в поиске стратегии, но для того чтобы хотя бы попытаться мне нужна была статистика для сравнения разных версий стратегий (разных версий скриптов).

Я решил запилить третий скрипт, который читает логи, рассчитывает метрики качества и отправляет их в телегу и (самое вкусное!) в excel-таблицу для последующего анализа!

Для записи в excel-таблицу мы будем использовать google -форму с сохранением результатов в таблицу. Я хотел по православному писать в яндекс-форму, с сохранением в таблицу, но когда сделал столкнулся с тем что из скрипта в нее отправить не получается - ругается 302 предлагает заполнить капчу)). Пришлось на делать на гуглоформе.

  1. Создаем бота в телеге, куда будем получать отчеты качества

  2. Создаем google-форму и включаем сохранение результатов в таблицу

  3. Создаем скрипт расчета статистики качества и ее отправки по 2 каналам

  4. Ставим на график запуска 1 раз в час

Создаем гуглоформу с такими полями:

Кого мониторим

Дата

Час

Доступность сервисов, %

Доступность 4pda, %

Доступность Android, %

Доступность Microsoft, %

Доступность xiaomi, %

RTO_AVG 4pda, мин

RTO_AVG ANDROID, мин

RTO_AVG MICROSOFT, мин

RTO_AVG XIAOMI, мин

RTO_MIN 4PDA, мин

RTO_MIN ANDROID, мин

RTO_MIN MICROSOFT, мин

RTO_MIN XIAOMI, мин

RTO_MAX 4PDA, мин

RTO_MAX ANDROID, мин

RTO_MAX MICROSOFT, мин

RTO_MAX XIAOMI, мин

DPI_blocks, шт

DPI_blocks, %

MSS_AVG

MSS_MIN

MSS_MAX

MSS_STABILITY, %

MSS_CHANGES

Версия скриптов подстройки

Включаем сохранение результатов в таблицу: Ответы --> Установить связь с Таблицами

Выгружаем id формы и id ее полей для скрипта: Три точки справа вверху --> Форма с предварительным заполнением. Заполняем поля формы краткими названиями полей по-английски (иначе потом не разберетесь где какое поле) и нажимаем Получить ссылку. Копируем ее в блокнот и в ней будут все id.

Скрипт "script_Analyze_InternetStability_Logs"

:local periodInHours 1
:local sendTelegram true
##########################################################
# ЗАМЕНИТЬ МНОГОТОЧИЯ НА ID СВОЕГО БОТА и ЧАТА В ТЕЛЕГЕ ##
# Если у вас несколько устройств - для разных укажите   ##
# разный sMonitoringSource                              ##
##########################################################
:local sBotId "........"
:local sChatId "......."
:local sMonitoringSource "me"
:local googleFormId "........"
##########################################################

:global gMSSVersion; :if ([:len $gMSSVersion] = 0) do={ :set gMSSVersion 0; }
:global gServicesVersion; :if ([:len $gServicesVersion] = 0) do={ :set gServicesVersion 0; }

:local period [:totime ($periodInHours . "h")]
:local hMinMss 2000; :local hMaxMss 0; :local hSumMss 0; :local hCountMss 0; :local hStabChanges 0
:local totalDPI 0; :local stabThreshold (60 * 2 * $periodInHours)
:local svcNames {"ANDROID";"MICROSOFT";"XIAOMI";"4PDA"}
:local stats [:toarray ""]



# --- УНИВЕРСАЛЬНЫЙ БЛОК ДАТЫ ---
:local cDate [/system clock get date]
:local cTime [/system clock get time]
:local fDate ""
:local gDate ""

:if ([:pick $cDate 4] = "-" || [:pick $cDate 7] = "-") do={
    # Формат ISO (YYYY-MM-DD)
    :set fDate ([:pick $cDate 8 10] . "." . [:pick $cDate 5 7] . "." . [:pick $cDate 0 4])
    :set gDate $cDate
}

:local startTime ($cTime - $period)
:if ($startTime < 0s) do { :set startTime (00:00:00) }
:local timeRange ($fDate . "  " . [:pick $startTime 0 5] . " - " . [:pick $cTime 0 5])

:foreach s in=$svcNames do={ 
    :set ($stats->$s) {"err"=0; "ok"=0; "recSum"=0; "recCnt"=0; "maxRec"=0; "minRec"=999; "lastFail"=""} 
}

:local logEntries [/log find where ((([:timestamp] + ([/system clock get gmt-offset] . "s")) - [:totime (time)]) <= $period)]

:foreach i in=$logEntries do={
    :local item [/log get $i]
    :local msg ($item->"message")
    :local lTime ($item->"time")
    
    :if ($msg ~ "MSS_ADAPT" || $msg ~ "MSS_STAT") do={
        :local p [:find $msg "MSS: "]
        :if ([:len $p] > 0) do={
            :local pStart ($p + 5)
            :local arrow [:find $msg "->" $p]
            :if ([:len $arrow] > 0) do={ :set pStart ($arrow + 3); :set hStabChanges ($hStabChanges + 1) }
            :local pEnd [:find $msg "," $pStart]
            :if ([:len $pEnd] = 0) do={ :set pEnd [:find $msg " " $pStart] }
            :if ([:len $pEnd] = 0) do={ :set pEnd [:len $msg] }
            :local mVal [:tonum [:pick $msg $pStart $pEnd]]
            :if ($mVal > 0) do={
                :set hSumMss ($hSumMss + $mVal); :set hCountMss ($hCountMss + 1)
                :if ($mVal < $hMinMss) do={ :set hMinMss $mVal }; :if ($mVal > $hMaxMss) do={ :set hMaxMss $mVal }
            }
        }
    }

    :if ($msg ~ "DPI BLOCK!!!" || $msg ~ "BLOCKED") do={ :set totalDPI ($totalDPI + 1) }

    :if ($msg ~ "As:" || $msg ~ "MS:" || $msg ~ "XiaoMIs:" || $msg ~ "4pda:") do={
        :foreach sName in=$svcNames do={
            :local found false; :local sErr false; :local sOk false
            :if ($sName = "ANDROID"		&& $msg ~ "As:")		do={ :set found true; if ($msg ~ "As: ok")		do={:set sOk true} else={:if ($msg ~ "As: ER")		do={:set sErr true} } }
            :if ($sName = "MICROSOFT"	&& $msg ~ "MS:")		do={ :set found true; if ($msg ~ "MS: ok")		do={:set sOk true} else={:if ($msg ~ "MS: ER")		do={:set sErr true} } }
            :if ($sName = "XIAOMI"		&& $msg ~ "XiaoMIs:")	do={ :set found true; if ($msg ~ "XiaoMIs: ok")	do={:set sOk true} else={:if ($msg ~ "XiaoMIs: ER")	do={:set sErr true} } }
            :if ($sName = "4PDA"		&& $msg ~ "4pda:")		do={ :set found true; if ($msg ~ "4pda: ok")	do={:set sOk true} else={:if ($msg ~ "4pda: ER")	do={:set sErr true} } }

            :if ($found) do={
                :if ($sErr) do={ 
                    :set ($stats->$sName->"err") (($stats->$sName->"err") + 1) 
                    :if ([:len ($stats->$sName->"lastFail")] = 0) do={ :set ($stats->$sName->"lastFail") $lTime }
                }
                :if ($sOk) do={ 
                    :set ($stats->$sName->"ok") (($stats->$sName->"ok") + 1) 
                    :local fTime ($stats->$sName->"lastFail")
                    :if ([:len $fTime] > 0) do={
                        :local diff ($lTime - $fTime)
                        :local dur (([:tonum [:pick $diff 0 2]] * 60) + [:tonum [:pick $diff 3 5]])
                        :set ($stats->$sName->"recSum") (($stats->$sName->"recSum") + $dur)
                        :set ($stats->$sName->"recCnt") (($stats->$sName->"recCnt") + 1)
                        :if ($dur > ($stats->$sName->"maxRec")) do={ :set ($stats->$sName->"maxRec") $dur }
                        :if ($dur < ($stats->$sName->"minRec")) do={ :set ($stats->$sName->"minRec") $dur }
                        :set ($stats->$sName->"lastFail") ""
                    }
                }
            }
        }
    }
}

:local avgMss 0; :if ($hCountMss > 0) do={ :set avgMss ($hSumMss / $hCountMss) }
:local stabPct (100 - (($hStabChanges * 100) / $stabThreshold)); :if ($stabPct < 0) do={ :set stabPct 0 }
:local dpiPct (($totalDPI * 100) / (30 * $periodInHours) );

:local weightSum 0
:foreach sn,sd in=$stats do={
    :local eC ($sd->"err"); :local oC ($sd->"ok"); :local av 100
    :if (($eC + $oC) > 0) do={ :set av (($oC * 100) / ($eC + $oC)) }
    :local w 1; :if ($sn = "ANDROID" || $sn = "MICROSOFT") do={ :set w 2 }
    :set weightSum ($weightSum + ($av * $w))
}
:local integralAvail ($weightSum / 6)

:local out "\r\n=== ОТЧЕТ КАЧЕСТВА ===\r\n"
:set out ($out . "$timeRange ($periodInHours ч.)\r\n")
:set out ($out . "1. доступность сервисов $integralAvail%\r\n")

:foreach sName,sData in=$stats do={
    :local eC ($sData->"err"); :local oC ($sData->"ok"); :local av 100
    :local total ($eC + $oC)
    :if ($total > 0) do={ :set av (($oC * 100) / $total) }
    :local rSum ($sData->"recSum"); :local rCnt ($sData->"recCnt"); :local rAvg 0
    :if ($rCnt > 0) do={ :set rAvg ($rSum / $rCnt) }
    :local rMin ($sData->"minRec"); :if ($rMin = 999) do={ :set rMin 0 }
    :local rMax ($sData->"maxRec")
    :local sRTO ""; 
    :if ($rAvg > 0) do={ 
        :set sRTO ", RTO ~$rAvg мин "
        :if ($rMin != $rMax) do={ :set sRTO "$sRTO ($rMin..$rMax мин)" }
    }
    :set out ($out . "  - $sName: $av%$sRTO\r\n")
}

:set out ($out . "2. блокировки DPI: $totalDPI шт. ($dpiPct%)\r\n")
:set out ($out . "3. MSS: ~$avgMss ($hMinMss..$hMaxMss), стабильность: $stabPct% ($hStabChanges изм.)\r\n")

:log info $out

# Отправка в Telegram
:if ($sendTelegram) do={
	:do {
		/tool fetch http-method=post \
			url="https://api.telegram.org/bot$sBotId/sendMessage" \
			http-data="chat_id=$sChatId&text=$out" \
			keep-result=no
	} on-error= {
		:log error "Error sending statis message in Telegram , No Internet!"
	}
}

# --- ОТПРАВКА В GOOGLE ФОРМУ ---
:local currentHour [:tonum [:pick $cTime 0 2]]

:local aAv 100; :local mAv 100; :local xAv 100; :local pAv 100
:local aSum (($stats->"ANDROID"->"ok")  + ($stats->"ANDROID"->"err"))
:local mSum (($stats->"MICROSOFT"->"ok")+ ($stats->"MICROSOFT"->"err"))
:local xSum (($stats->"XIAOMI"->"ok")   + ($stats->"XIAOMI"->"err"))
:local pSum (($stats->"4PDA"->"ok")      + ($stats->"4PDA"->"err"))

:if ($aSum > 0) do={ :set aAv (($stats->"ANDROID"->"ok" * 100) / $aSum) }
:if ($mSum > 0) do={ :set mAv (($stats->"MICROSOFT"->"ok" * 100) / $mSum) }
:if ($xSum > 0) do={ :set xAv (($stats->"XIAOMI"->"ok" * 100) / $xSum) }
:if ($pSum > 0) do={ :set pAv (($stats->"4PDA"->"ok" * 100) / $pSum) }

:local aRa 0; :if (($stats->"ANDROID"->"recCnt") > 0) do={ :set aRa (($stats->"ANDROID"->"recSum") / $stats->"ANDROID"->"recCnt") }
:local mRa 0; :if (($stats->"MICROSOFT"->"recCnt") > 0) do={ :set mRa (($stats->"MICROSOFT"->"recSum") / $stats->"MICROSOFT"->"recCnt") }
:local xRa 0; :if (($stats->"XIAOMI"->"recCnt") > 0) do={ :set xRa (($stats->"XIAOMI"->"recSum") / $stats->"XIAOMI"->"recCnt") }
:local pRa 0; :if (($stats->"4PDA"->"recCnt") > 0) do={ :set pRa (($stats->"4PDA"->"recSum") / $stats->"4PDA"->"recCnt") }

:local aMi ($stats->"ANDROID"->"minRec"); :if ($aMi = 999) do={:set aMi 0}; :local aMa ($stats->"ANDROID"->"maxRec")
:local mMi ($stats->"MICROSOFT"->"minRec"); :if ($mMi = 999) do={:set mMi 0}; :local mMa ($stats->"MICROSOFT"->"maxRec")
:local xMi ($stats->"XIAOMI"->"minRec"); :if ($xMi = 999) do={:set xMi 0}; :local xMa ($stats->"XIAOMI"->"maxRec")
:local pMi ($stats->"4PDA"->"minRec"); :if ($pMi = 999) do={:set pMi 0}; :local pMa ($stats->"4PDA"->"maxRec")


:local urlData ("entry.263257593=" . $sMonitoringSource . \
"&entry.922317815=MSS v$gMSSVersion, Services v$gServicesVersion" . \
"&entry.1972153670=" . $gDate . \
"&entry.1309071647=" . $currentHour . \
"&entry.1232031999=" . $integralAvail . \
"&entry.1037735613=" . $pAv . \
"&entry.310815387=" . $aAv . \
"&entry.235660758=" . $mAv . \
"&entry.1138524409=" . $xAv . \
"&entry.1825690509=" . $pRa . \
"&entry.472580822=" . $aRa . \
"&entry.1981616555=" . $mRa . \
"&entry.1297338224=" . $xRa . \
"&entry.1749190856=" . $pMi . \
"&entry.939473659=" . $aMi . \
"&entry.355961275=" . $mMi . \
"&entry.1374920035=" . $xMi . \
"&entry.2101070622=" . $pMa . \
"&entry.1109708284=" . $aMa . \
"&entry.1109226438=" . $mMa . \
"&entry.1999941440=" . $xMa . \
"&entry.1938952119=" . $totalDPI . \
"&entry.1999467399=" . $dpiPct . \
"&entry.1882390038=" . $avgMss . \
"&entry.631664603=" . $hMinMss . \
"&entry.1412379302=" . $hMaxMss . \
"&entry.1772357571=" . $stabPct . \
"&entry.1644530981=" . $hStabChanges)

:do {
    /tool fetch http-method=post \
        url="https://docs.google.com/forms/d/e/$googleFormId/formResponse" \
        http-data=$urlData \
        check-certificate=no \
        keep-result=no
} on-error={ :log error "GoogleForm: Send failed." }

ВАЖНО!

  1. Впишите id бота и чата телеграм в переменные в начале скрипта

  2. Впишите id google формы в начале скрипта

  3. Замените id полей гугл формы (entry.*) в скрипте на ваши. Как их узнать см. выше

Ставим скрипт на график:

/system scheduler
add interval=1h name=job_script_Analyze_InternetStability_Logs on-event=script_Analyze_InternetStability_Logs policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon start-date=2026-01-24 start-time=17:00:00

Через час в телегу начнут приходить такие уведомления:

А в google таблице должны накапливаться такие записи:

Поиск идеала

Проверяем что все логи пишутся, уведомления приходят, а записи падают в гугл таблицу. Затем даем поработать несколько дней или лучше неделю - накапливаем статистику.

После этого можно изменить параметры скриптов, например скорость падения MSS при ошибках, порог %ошибки для падения, скорость роста MSS при отсутствии ошибок, а также изменить реакцию на недоступность сервисов. Не забудьте в скриптах поменять версию в глобальной переменной, чтобы в excel-файле со статистой потом можно было разобраться к какой версии относятся те или иные записи.

Даем системе еще поработать с новыми параметрами несколько дней или неделю.

Затем открываем файл в старом добром excel, строим сводную отчетность, графики, короче проводим анализ всеми известными способами. Цель - сравнить разные версии скриптов доступность базовых сервисов, %DPI блокировок, стабильность MSS (частые дерганья MSS не идут на пользу). Выбираем версию которая показала себя лучше. Еще подкручиваем параметры у нее и повторяем все по кругу. И так можно до бесконечности. Работать также хорошо как на смартфоне android все равно не будет. Но увеличить доступность сервисов с базового уровня можно очень существенно!

Кстати ради интереса можете установить постоянную MSS и посмотреть, что будет. Для этого параметры max и min MSS можно установить в одно и тоже значение (например 1100 при плохом сигнале), такое же значение прописать в функции dropMSS.Накопить статистику также за неделю и сравнить. Не забывайте при любых изменениях менять версию скрипта в глобальной переменной в начале скрипта.

Выводы

Данная работа была посвящена изучению возможностей роутеров микротик в деле управления качеством мобильного интернета с плохим качеством LTE сигнала, т.е. в удаленных уголках. И да, качество можно поднять антенной, но оно все равно не будет таким как по проводному интернету.

Дополнительно, по ходу дела мы научились пулять сообщения в телегу из микротика, парсить логи микротика, а также отправлять статистику работы в гугл таблицу для накопления и последующего удаленного анализа.