Community discussions

MikroTik App
 
Frozer
newbie
Topic Author
Posts: 48
Joined: Wed Apr 10, 2013 4:14 pm
Contact:

LTE_Repair script w/advanced features

Thu Jan 20, 2022 4:23 am

Hello to all. I propose for testing a script for restoring the health of LTE connection.

In principle, the script can also work like most scripts of this purpose - just reboot the LTE modems by USB power reset if the sites (servers) specified in the settings are not pinged.

But even in this part, I modified it a little (if the USB reset does not help), then the router reboots. Also, if a few reboot cycles do not help, you can set a hibernation period (because in this case there is no need to "torment" the modem usually we just need to wait until the operator fixes his base station or maybe we must to make a payment etc.).

Also, script checking for the type of modem interface (for example, with RB912 there were cases when it spontaneously switching from Mini-PCIe to USB - the script can restore this setting).

Additional functionality for now only works for Mikrotik R11E-4G, R11E-LTE R11E-LTE6, Quecktel EP06-E & Sierra Wireless MC7710 modems, they can be unlocked from frequency ranges and type of wireless network (if forced or locked to before). R11E-LTE6 & EP06-E can be additionally unlocked from the cell (if locked before and the cell stopped working).

It is recommended to configure the execution of this script by the scheduler for execution every 2-3 minutes. The algorithm of its work is as follows (if the Internet is not available):

1. The modem is reset by USB/PCIe power-off;
2. The next execution reset the power again;
3. At the next start, reboot the router;
4. If the modem is R11E-LTE6 or EP06-E, locked to the cell and unlock is enabled by settings, then we unlock it from the cell, then (if there is no success), we repeat steps 2 and 3;
5. For compatible modems, we try to unlock from the frequency bands (if there was a lock and unlock is allowed by the settings), then (if there was no success), we repeat steps 2 and 3;
6. For compatible modems, we try to unlock from network type (if there was a lock and unlock is allowed by the settings), then (if there was no success), we repeat steps 2 and 3;
7. If nothing happened and the sleep period is specified in the settings, then we wait and after the expiration of this period, we back to step 1.

If at a certain step the Internet is restored, the counter is reset and in the event of a loss of the Internet, we then start from step 1.

If at one of the stages the script makes any settings to the modem or router, a file will be created to identify events. If you specified your mobile number in the settings, an SMS of the following form will be sent to you (as soon as it becomes possible):

LTE modem installed at RB #D6B80E4DC5A8 was automaticaly unlocked from cell/band. Event date: jan/20/2022 09:26:01.

P.S. Despite the fact that I have carefully tested it on my equipment and it works properly, there may be bugs. So use at your own risk. And please report all bugs.

# LTE_Repair Advanced Script v.1.1.1 (12.11.2022)
# Author: Sergey Krivosheyev
# About bugs, questions & feedback please contact to: sergey@krivosheyev.ru, instagram: wireless_sensei

# Support for standard functions (USB reset, reboot): all modems with LTE interface.

# Support for advanced functions (detachment from network type, LTE bands): Mikrotik R11E-LTE, R11E-LTE6,
# EG12-EA (Chateau LTE12), Sierra Wireless MC7710, Quectel EP06-E (tested with F/W EP06ELAR03A08M4G & MBIM mode enabled)

# Suport for cell unlock: Mikrotik R11E-LTE6, EG12-EA, Quectel EP06-E

# Minumum ROS version supported is 6.2 (ROS 7 is now supported also*)
# * The functionality of the script has been tested under ROS up to v.7.6, but if in the next versions the ROS 6 command style
# will be canceled (for the sake of the CLI syntax, the script will have to be rewritten entirely).

# Please enable debug logging for scripts for diagnostics.

# **************************************** SETUP SETTINGS BELOW ******************************************

:local StSkipFirstRun 1;
# It is recommended to skip at least one first launch of the script (that the modem would be initialized after a
# reboot or after power failure). Min 0, Max 10.

:local StModemPortType "mini-PCIe";
# Some boards support both USB and mini-PCIe modems. In some obscure cases, the modem's port type is reset and the
# modem becomes unavailable. Specify the correct connection type here and we will try to restore it, or set "" to
# disable function. Available options may be: mini-PCIe, USB-type-A, auto etc. (please see you board's specs for all supported types).

:local StRouterName "";
# A friendly name of the router for identification in SMS. You can leave "", in such case the serial number of the device will be used.
# No more than 40 characters (special characters except spaces & "#-_()@&*:;+<>.," are not allowed).

:local StSleepTimes 40;
# If there is no Internet, we try various ways to restore it (reset the modem's power, reboot the router, disconnect the modem from
# the cell), if none of the methods helps, then this may mean a problem with the base station or payment. In this case, it makes no
# sense to intensively "torment" the modem and it is advisable to suspend the above actions. To do this, specify a value from 0 to 10000.
# For example, if 100 is specified, and this script runs by scheduler every 2 minutes, this will mean
# that the modem will rest for 200 minutes (after which several attempts to restore LTE connection will be made again).

:local StPingAddresses "google.ru,yandex.ru,vk.ru,yota.ru,mts.ru,megafon.ru,beeline.ru,tele2.ru";
# We are trying to ping the hosts below. If at least one ping request for at least one of the hosts listed below recieved, the Internet
# is considered as working and the modem will not be reseted. It is advisable to indicate here also the address(es) of the provider,
# which will be available even if you forgot to pay for Internet access on time. IPs or hosts comma separated (min 1, max 10).

:local StPingCount 3;
# Number of ping requests to try (1-10)

:local StDoCBUnlock "Y";
# This setting currently only works with the Mikrotik R11E-LTE6, EG12-EA & Quectel EP06-E modems. The specified modems can be locked to a
# specific cell and/or frequency band with special command (see modem manual for details). Thus, if the specified cell fails, the modem
# will not be able to connect to the Internet. By setting the parameter value, you can automatically unlock from cell if the
# Internet stops working. Set "Y" or "N".

:local StDoBRangeUnlock "Y";
# If you use fixed LTE frequency bands, the binding to them may also be reset, if the Internet is not available. Set "Y" or "N".

:local StDoNTypeUnlock "Y";
# If you use binding to the type of wireless network (LTE only, for example), then this can also be reset to the default
# value (support for all) if Internet not working and other steps not helped. Set "Y" or "N".

:local StSMSTo "";
# Phone number in international format (only digits and, possibly, a "+" character at the beginning). This number is only used
# to send an SMS that some changes were applied to the router or modem (unlock from networks, ranges and(or) unlock from the cell).
# Set value to "" if SMS is not needed.

:local StCurrentScriptName "LTE_Repair";
#Please enter the real name of this script here. This way we can use protection against multiple execution & hungs.
# No more than 40 characters (special characters except spaces & "-_" are not allowed).

:local StScriptTimeOut 5;
# The time interval (min) after which the script can be considered as hunged. If the script is run again and running copy
# exists already but the time interval is exceeded, it will remove the hunged copy and run normally.

:local LP "LTE_Repair script";
# Prefix for log messages. No more than 40 characters (special characters except spaces & "-_" are not allowed).
# Set value to "" if you want to disable log prefixes.

# ****************************************** NO SETTINGS BELOW ******************************************

# DEFINE VARS
:local t;
:local temp;
:local pos 0;
:local arT [:toarray ""];
:local arTemp [:toarray ""];
:local Counter 0;
:local ElementsCount;
:local ResolvedIP;
:local PingCheck 0;
:local CheckFound;
:local ROSVer;
:local MinStarted 0;
:local MinCurrent 0;
:local LTEIntID "";
:local arLTEInfo [:toarray ""];
:local CLockStCmd;
:local CUnlockChk;
:local CUnLockCmd;
:local NetModSupC;
:local SMSFile "LTERepScrSMSTxt.txt";
:local SMSText "";
:local NoIntCntData "0";
:local NoIntCntFile "LTERepScrNoIntCntr.txt";
:global LTERepScrRunCntr;
:if ([:typeof $LTERepScrRunCntr] != "num" ) do={ :set LTERepScrRunCntr 0; }
:global LTERepScrCurrStep;
:if ([:typeof $LTERepScrCurrStep] != "num") do={ :set LTERepScrCurrStep 0; }
:global LTERepScrStepFailed;
:if ([:typeof $LTERepScrStepFailed] != "array" ) do={ :set LTERepScrStepFailed [:toarray ""]; }

# LOG PREFIX CHECK
:if (([:typeof $LP] != "str") || ($LP != "")) do={
	:set LP [:tostr $LP];
	:if ($LP~"^[-a-zA-Z0-9 _]{1,40}\$") do={
		:set LP ($LP . ": ");
	} else={
		:set LP "";
		:log warning ($LP . "Incorrect value for \$LP parameter for \"LTE_Rapair\" script, so log prefixes will not be used.");
	}
}

# CHECK ROS VERSION
:set t [/system resource get version];
:if ($t~"^(6\\.[2-9]|7\\.).*\$") do={
	:set ROSVer [:pick $t 0 1];
	:log debug ($LP . "ROS version is OK.");
} else={
	:set t ("Launch terminated due to incompatible ROS version (minimum 6.2 required).");
	:log error ($LP . $t);
	:error $t;
}

# CHECK SCRIPT NAME, DOUBLE RUN AND PREVENT HANG
:if (($StCurrentScriptName~"^[-a-zA-Z0-9 _]{1,40}\$") && ([:tostr [/system script find name=$StCurrentScriptName]] != "")) do={
	:set CheckFound false;
	:set arT [:toarray [/system script job find script=$StCurrentScriptName]];
	:set pos [:len $arT];
	:if ($pos > 1) do={
		:for i from=0 to=($pos-1) step=1 do={
		:set temp [/system script job get ($arT->$i) started];
			:set MinStarted ([:tonum [:pick $temp 12 14]] * 60 + [:tonum [:pick $temp 15 17]]);
			:set temp [/system clock get time];
			:set MinCurrent ([:tonum [:pick $temp 0 2]] * 60 + [:tonum [:pick $temp 3 5]]);
			:set Counter ($MinCurrent - $MinStarted);
			:if (($Counter < 0) || ($Counter >= $StScriptTimeOut)) do={
				:set CheckFound true;
				:do {
					:set t ($i+1);
					:log warning ($LP . "Trying to remove hunged copy #" . $t . " by timeout.");
					/system script job remove ($arT->$i);
					:log debug ($LP . "A copy #" . $t . " removed successfully.");
				} on-error={
					:log warning ($LP . "Failed to remove a copy #" . $t . ".");
				}
			}
		}
		:if ($CheckFound = true) do={ :delay 2; }
		:if ([:len [:toarray [/system script job find script=$StCurrentScriptName]]] > 1) do={
			:set t "Launch terminated - still running another copy.";
			:log error ($LP . $t);
			:error $t;
		}
	}
} else={
	:set t "Incorrect script name defined at \$StCurrentScriptName parameter or script not found, terminating...";
	:log error ($LP . $t);
	:error $t;
}

# CHECK OTHER SETUP PARAMS
:if (([:typeof $StSkipFirstRun] != "num") || ($StSkipFirstRun < 0) || ($StSkipFirstRun > 10)) do={
	:set StSkipFirstRun 1;
	:log warning ($LP . "Incorrect value for \$StSkipFirstRun parameter, defaults used (1).");
}

:if ([:typeof $StModemPortType] != "str") do={
	:set StModemPortType "";
	:log warning ($LP . "Incorrect value for \$StModemPortType parameter, defaults used (\"\").");
}

:if (($StRouterName != "") && (($StRouterName~"^[-a-zA-Z0-9 #_()@&*:;+<>.,]{0,40}\$") = false)) do={
	:set StRouterName "";
	:log warning ($LP . "Incorrect value for \$StRouterName parameter, serial number will be used instead.");
}

:if (([:typeof $StSleepTimes] != "num") || ($StSleepTimes < 0) || ($StSleepTimes > 10000)) do={
	:set StSleepTimes 500;
	:log warning ($LP . "Incorrect value for \$StSleepTimes parameter, defaults used (500).");
}

:if (([:typeof $StPingAddresses] != "str") && ([:typeof $StPingAddresses] != "ip")) do={
	:set StPingAddresses false;
} else={
	:set StPingAddresses [:toarray [:tostr $StPingAddresses]];
	:set t [:len $StPingAddresses];
	:if (($t < 1) || ($t > 10) || (($t = 1) && (($StPingAddresses->0) = ""))) do={
		:set StPingAddresses false;
	}
}
:if ($StPingAddresses = false) do={
	:set StPingAddresses {"google.ru";"yandex.ru";"vk.ru";"yota.ru";"mts.ru";"megafon.ru";"beeline.ru";"tele2.ru"};
	:log warning ($LP . "Incorrect value for \$StPingAddresses parameter, defaults used.");
}

:if (([:typeof $StPingCount] != "num") || ($StPingCount < 1) || ($StPingCount > 10)) do={
	:set StPingCount 3;
	:log warning ($LP . "Incorrect value for \$StPingCount parameter, defaults used (3).");
}

:if (($StDoCBUnlock~"^[YN]{1}\$") = false) do={
	:set StDoCBUnlock "Y";
	:log warning ($LP . "Incorrect value for \$StDoCBUnlock parameter, defaults used (Y=Yes).");
}

:if (($StDoBRangeUnlock~"^[YN]{1}\$") = false) do={
	:set StDoBRangeUnlock "Y";
	:log warning ($LP . "Incorrect value for \$StDoBRangeUnlock parameter, defaults used (Y=Yes).");
}

:if (($StDoNTypeUnlock~"^[YN]{1}\$") = false) do={
	:set StDoNTypeUnlock "Y";
	:log warning ($LP . "Incorrect value for \$StDoNTypeUnlock parameter, defaults used (Y=Yes).");
}

:if (($StSMSTo != "") && (($StSMSTo~"^([0-9]{0,15}|\\+?[0-9]{3,16})\$") = false)) do={
	:set StSMSTo "";
	:log warning ($LP . "Incorrect value for \$StSMSTo parameter, defaults used (disabled).");
}

:if (([:typeof $StScriptTimeOut] != "num") || ($StScriptTimeOut < 1) || ($StScriptTimeOut > 30)) do={
	:set StScriptTimeOut 3;
	:log warning ($LP . "Incorrect value for \$StSleepTimes parameter, defaults used (3 min).");
}

# FUNCTIONS >>>
# CONVERT TEXT TO LOWERCASE & REPLACE SOME CHARS
:global LTERepScrGetTxtLCFunc do={
	:if ([:typeof $1] != "str") do={ return false; }
	:local src {"A";"B";"C";"D";"E";"F";"G";"H";"I";"J";"K";"L";"M";"N";"O";"P";"Q";"R";"S";"T";"U";"V";"W";"X";"Y";"Z";"\"";"'"};
	:local dst {"a";"b";"c";"d";"e";"f";"g";"h";"i";"j";"k";"l";"m";"n";"o";"p";"q";"r";"s";"t";"u";"v";"w";"x";"y";"z";"";""};
	:local t "";
	:local temp "";
	:local pos;
	:for i from=0 to=([:len $1] - 1) do={
		:set t [:pick $1 $i];
		:set pos [:find $src $t];
		:if ([:typeof $pos] = "num") do={
			:set t ($dst->$pos);
		}
		:set temp ($temp.$t);
	}
	:return $temp;
}
# FUNCTIONS <<<

# SKIP FIRST RUN
:set LTERepScrRunCntr ($LTERepScrRunCntr + 1);
if ($StSkipFirstRun > 0) do={
	:if ($LTERepScrRunCntr <= $StSkipFirstRun) do={
		:log info ($LP . "Launch #" . $LTERepScrRunCntr . " - skipping...");
		:error ("Launch #" . $LTERepScrRunCntr . " - skipping...");
	}
}

# CHECKING NO INTERNET COUNTER FILE
:if ([:len [/file find name=flash]] > 0) do={
	:set NoIntCntFile ("flash/" . $NoIntCntFile);
}
:set temp [/file find name=$NoIntCntFile];
:if ([:len $temp] = 0) do={
	/file print file=$NoIntCntFile;
	:delay 1;
	:set NoIntCntFile [/file find name=$NoIntCntFile];
	/file set $NoIntCntFile contents=$NoIntCntData;
} else={
	:set NoIntCntFile $temp;
	:set NoIntCntData [/file get $NoIntCntFile contents];
	:if ($LTERepScrRunCntr = ($StSkipFirstRun + 1)) do={ :set LTERepScrCurrStep [:tonum $NoIntCntData]; }
}

# CHECKING SMS DATA FILE
:if ($StSMSTo != "") do={
	:if ([:len [/file find name=flash]] > 0) do={
		:set SMSFile ("flash/" . $SMSFile);
	}
	:set temp [/file find name=$SMSFile];
	:if ([:len $temp] = 0) do={
		/file print file=$SMSFile;
		:delay 1;
		:set SMSFile [/file find name=$SMSFile];
		/file set $SMSFile contents=$SMSText;
	} else={
		:set SMSFile $temp;
		:set SMSText [/file get $SMSFile contents];
	}
}

# CHECKING MODEM PORT TYPE
:if ($StModemPortType != "") do={
	:set temp [/system routerboard usb get type];
	:if ([:tostr $temp] != "") do={
		:if ($temp != $StModemPortType) do={
			:do {
				/system routerboard usb set type=$StModemPortType;
				:set t ("The modem port type has just been restored to: \"" . $StModemPortType . "\", terminating on this step...");
				:log warning ($LP . $t);
				:do { :error $t; } on-error={ }
			} on-error={
				:log error ($LP . "The modem port type can't be changed to the desired one (probably not supported).");
			}
		} else={
			:log debug ($LP . "The desired & current modem port type is the same.");
		}
	} else={
		:log debug ($LP . "The modem port type is not applicable, ignoring \$StModemPortType parameter...");
	}
}

# SEARCHING FOR LTE INTERFACE ID
:set LTEIntID [/interface find type=lte];
:if ($LTEIntID != "") do={
	:set LTEIntID [:toarray $LTEIntID];
	:if ([:len $LTEIntID] > 1) do={
		:log error ($LP . "Found more then 1 of LTE interfaces, working only with first of them (multiple currently unsupported)!");
	} else={
		:log debug ($LP . "ID of LTE interface is: " . ($LTEIntID->0));
	}
	:set LTEIntID [:toid ($LTEIntID->0)];
} else={
	:log error ($LP . "No LTE interfaces found!");
}

# CHECKING INTERNET (PINGING)
:set ElementsCount [:len $StPingAddresses];
:while (($Counter < $ElementsCount) && ($PingCheck = 0)) do={
	:do {
		:if ([:toip ($StPingAddresses->$Counter)] = ($StPingAddresses->$Counter)) do={
			:set ResolvedIP [:toip ($StPingAddresses->$Counter)];
		} else={
			:set ResolvedIP [:resolve ($StPingAddresses->$Counter)];
		}
		:if (!($ResolvedIP in 10.0.0.0/8) && !($ResolvedIP in 192.168.0.0/16) && !($ResolvedIP in 127.0.0.0/8)) do={
			:do {
				:set PingCheck [/ping $ResolvedIP count=$StPingCount];
			} on-error={
				:set PingCheck 0;
			}
		}
	} on-error={
		:set PingCheck 0;
	}
	:set Counter ($Counter + 1);
}

:if ($PingCheck = 0) do={
	# NO INTERNET
	:set LTERepScrCurrStep ($LTERepScrCurrStep + 1);
	# Steps reserved for new actions
	:if (($LTERepScrCurrStep > 12) && ($LTERepScrCurrStep < 22)) do={
		:set LTERepScrCurrStep 22;
	}
	# Check if cell, band, type unlock re-try needed
	:set pos 4;
	:while ($pos <= 10) do={
		:if (([:typeof ($LTERepScrStepFailed->$pos)] = "num") && (($LTERepScrStepFailed->$pos) > 0)) do={
			:if (($LTERepScrStepFailed->$pos) < 5) do={
				:set LTERepScrCurrStep $pos;
			} else={
				:set ($LTERepScrStepFailed->$pos) 0;
				:set LTERepScrCurrStep ($pos + 1);
			}
		} else={
			:set ($LTERepScrStepFailed->$pos) 0;
		}
		:set pos ($pos + 3);
	}
	# Skip some steps or restart
	:if ($LTERepScrCurrStep > ($StSleepTimes + 21)) do={
		:log debug ($LP . "Resetting step counter after sleep period...");
		:set LTERepScrCurrStep 1;
	} else={
		:if ($LTERepScrCurrStep > 21) do={
			:log debug ($LP . "The Internet still does not work, but we must do nothing during the sleep period.");
		}
	}
	# Check if modem info needed (for steps 4,7,10)
	:set arT [:toarray "4,7,10"];
	:set CheckFound false;
	:if ((($StDoCBUnlock = "Y") || ($StDoBRangeUnlock = "Y") || ($StDoNTypeUnlock = "Y")) && ([:typeof [:find $arT [:tostr $LTERepScrCurrStep]]] = "num")) do={
		:log debug ($LP . "Getting LTE interface details...");
			:if ($LTEIntID != "") do={
				:do {
					:if ($ROSVer = "7") do={
						:set arLTEInfo [/interface lte monitor $LTEIntID once as-value];
					} else={
						:set arLTEInfo [/interface lte info $LTEIntID once as-value];
					}
				} on-error={
					:set CheckFound true;
					:log warning ($LP . "Failed to get LTE interface info (no reply from modem).");
				}
				:if ($CheckFound = false) do={
					:set ($arLTEInfo->"model") [$LTERepScrGetTxtLCFunc ($arLTEInfo->"model")];
					:if (([:typeof ($arLTEInfo->"model")] != "str") || (($arLTEInfo->"model")) = "") do={
						:set CheckFound true;
						:log warning ($LP . "Failed to get LTE interface model (required for advanced steps).");
					}
				}
			} else={
				:set CheckFound true;
				:log warning ($LP . "Failed to get LTE interface info (interface not found).");
			}
		:if ($CheckFound = true) do={
			:set $arLTEInfo false;
		}
	}
	# Rerforming USB reset on step 1,2,5,8,11
	:set arT [:toarray "1,2,5,8,11"];
	:if ([:typeof [:find $arT [:tostr $LTERepScrCurrStep]]] = "num") do={
		:log debug ($LP . "Trying to hard-reset LTE modem...");
		:do {
			/system routerboard usb power-reset duration=5s;
			:log warning ($LP . "Supposedly hunged LTE modem has just been hard-resetted.");
		} on-error={
			:log error ($LP . "Failed to hard-reset supposedly hunged LTE modem (feature may not supported).");
		}
	}
	# Rerforming reboot on step 3,6,9,12
	:set arT [:toarray "3,6,9,12"];
	:if ([:typeof [:find $arT [:tostr $LTERepScrCurrStep]]] = "num") do={
		:log warning ($LP . "The previous modem reset did not help, so after 15 s. we will reboot additionally.");
		/file set $NoIntCntFile contents=[:tostr $LTERepScrCurrStep];
		:delay 5;
		/system reboot;
	}
	# Check if cell/band unlock needed for some modems (step 4)
	:set CheckFound false;
	:if ($LTERepScrCurrStep = 4) do={
		:if ($StDoCBUnlock = "Y") do={
			:if ([:typeof $arLTEInfo] = "array") do={
				:log debug ($LP . "Cell/band unlock is allowed by settings and now is the right step to check and do it.");
				:if (($arLTEInfo->"model") = "r11e-lte6") do={
					:set CLockStCmd "AT*Cell\?";
					:set CUnlockChk "CELL: 0,";
					:set CUnLockCmd "AT*Cell=0";
				} else={

					:if (($arLTEInfo->"model")~"^(ep06-e|eg12-ea)\$") do={
						:set CLockStCmd "AT+QNWLOCK=\"common/4g\"";
						:set CUnlockChk "\"common/4g\",0";
						:set CUnLockCmd "AT+QNWLOCK=\"common/4g\",0";
					} else={
						:set CLockStCmd false;
					}
				}
				:if ($CLockStCmd != false) do={
					:log debug ($LP . "Found supported modem for cell/band unlock check.");
					:do {
						:set ($arLTEInfo->"cell_status") ([/interface lte at-chat $LTEIntID input=$CLockStCmd as-value]->"output");
					} on-error={
						:set CheckFound true;
					}
					:if (($CheckFound = false) && ([:typeof ($arLTEInfo->"cell_status")] = "str") && (($arLTEInfo->"cell_status") != "")) do={
						:if ([:typeof [:find ($arLTEInfo->"cell_status") $CUnlockChk]] != "num") do={
							:do {
								/interface lte at-chat $LTEIntID input=$CUnLockCmd;
								:set CheckFound "U";
								:log warning ($LP . "The modem has just been unlocked from cell/band (sat to default).");
								# Saving SMS about this action (to send in a future, when Internet become available)
								:if ($StSMSTo != "") do={
									:do {
										:if ($SMSText != "") do={ :set SMSText ($SMSText . ","); }
										:set SMSText ($SMSText . [:tostr $LTERepScrCurrStep]);
										/file set $SMSFile contents=$SMSText;
									} on-error={
										:log error ($LP . "Failed to record SMS text to data-file.");
									}
								}
							} on-error={
								:set CheckFound true;
								:log warning ($LP . "Failed to execute modem command to remove cell/band lock.");
							}
						} else={
							:log debug ($LP . "Modem cell/band unlocked allready.");
						}
					} else={
						:set CheckFound true;
						:log warning ($LP . "Can't check modem cell/band lock status.");
					}
				} else={
					:log debug ($LP . "No supported modem found for cell/band unlock.");
				}
				:if ($CheckFound = true) do={
					:set ($LTERepScrStepFailed->$LTERepScrCurrStep) (($LTERepScrStepFailed->$LTERepScrCurrStep) + 1);
				} else={
					:set ($LTERepScrStepFailed->$LTERepScrCurrStep) 0;
				}
			} else={
				:set CheckFound true;
			}
			:if ($CheckFound = true) do={
				:set ($LTERepScrStepFailed->$LTERepScrCurrStep) (($LTERepScrStepFailed->$LTERepScrCurrStep) + 1);
			} else={
				:set ($LTERepScrStepFailed->$LTERepScrCurrStep) 0;
			}
		}
		:if ($CheckFound = false) do={
			:set LTERepScrCurrStep 7;
		}
	}
	# Check if band range unlock needed for some modems (step 7)
	:set CheckFound false;
	:if ($LTERepScrCurrStep = 7) do={
		:if ($StDoBRangeUnlock = "Y") do={
			:if ([:typeof $arLTEInfo] = "array") do={
				:log debug ($LP . "Band range unlock is allowed by settings and now is the right step to check and do it.");
				# If band lock supported by ROS
				:if (($arLTEInfo->"model")~"^(r11e-4g|r11e-lte|r11e-lte6|ep06-e|eg12-ea)\$") do={
					:log debug ($LP . "Found supported modem for band range unlock check.");
					:do {
						:set ($arLTEInfo->"curr_bands") [:tostr [/interface lte get $LTEIntID band]];
					} on-error={
						:set CheckFound true;
						:log warning ($LP . "Can't get modem current band range.");
					}
					:if ($CheckFound = false) do={
						:if (($arLTEInfo->"curr_bands") != "") do={
							:do {
								/interface lte set $LTEIntID band="";
								:set CheckFound "U";
								:log warning ($LP . "The modem has just been unlocked from band range (sat to default).");
							} on-error={
								:set CheckFound true;
								:log warning ($LP . "Failed to execute command to remove band range lock.");
							}
						} else={
							:log debug ($LP . "Modem band range unlocked allready.");
						}
					}
				} else={
					# Sierra Wireless MC7710 modem
					:if (($arLTEInfo->"model") = "mc7710") do={
						:log debug ($LP . "Found supported modem for band range unlock check.");
						:set ($arLTEInfo->"curr_bands") [:tostr [/interface lte get $LTEIntID band]];
						:if ((($arLTEInfo->"curr_bands") != "false") && (($arLTEInfo->"curr_bands") != "")) do={
							/interface lte set $LTEIntID band="";
						}
						:do {
							:set arT [:toarray [/interface lte at-chat $LTEIntID input="AT!BAND\?" as-value]];
							:if (([:typeof ($arT->"output")] != "str") || (($arT->"output") = "")) do={
								:error ("Can't get modem current band range.");
							}
						} on-error={
							:set CheckFound true;
							:log warning ($LP . "Can't get modem current band range.");
						}
						:if ($CheckFound = false) do={
							:if ([:typeof [:find ($arT->"output") "00, All bands"]] != "num") do={
								:do {
									/interface lte at-chat $LTEIntID input="AT!ENTERCND=\"A710\"";
									:delay 1;
									/interface lte at-chat $LTEIntID input="AT!BAND=00";
									:set CheckFound "U";
									:log warning ($LP . "The modem has just been unlocked from band range (sat to default).");
								} on-error={
									:set CheckFound true;
									:log warning ($LP . "Failed to execute modem command(s) to remove band range lock.");
								}
							} else={
								:log debug ($LP . "Modem band range unlocked allready.");
							}
						}
					} else={
						:log debug ($LP . "No supported modems found for band range unlock.");
					}
				}
				:if ($CheckFound = "U") do={
				# Saving SMS about this action (to send in a future, when Internet become available)
					:if ($StSMSTo != "") do={
						:do {
							:if ($SMSText != "") do={ :set SMSText ($SMSText . ","); }
							:set SMSText ($SMSText . [:tostr $LTERepScrCurrStep]);
							/file set $SMSFile contents=$SMSText;
						} on-error={
							:log error ($LP . "Failed to record SMS text to data-file.");
						}
					}
				}
			} else={
				:set CheckFound true;
			}
			:if ($CheckFound = true) do={
				:set ($LTERepScrStepFailed->$LTERepScrCurrStep) (($LTERepScrStepFailed->$LTERepScrCurrStep) + 1);
			} else={
				:set ($LTERepScrStepFailed->$LTERepScrCurrStep) 0;
			}
		}
		:if ($CheckFound = false) do={
			:set LTERepScrCurrStep 10;
		}
	}
	# Check if network type unlock needed for some modems (step 10)
	:set CheckFound false;
	:if ($LTERepScrCurrStep = 10) do={
		:if ($StDoNTypeUnlock = "Y") do={
			:if ([:typeof $arLTEInfo] = "array") do={
				:log debug ($LP . "Network type unlock is allowed by settings and now is the right step to check and do it.");
				# If network type lock supported by ROS (r11e-4g excluded beacuse only support 4G)
				:if (($arLTEInfo->"model")~"^(r11e-lte|r11e-lte6|ep06-e|eg12-ea)\$") do={
					:log debug ($LP . "Found supported modem for network type unlock check.");
					:set NetModSupC 3;
					:if (($arLTEInfo->"model")~"^(ep06-e|eg12-ea)\$") do={ :set NetModSupC 2; }
					:do {
						:set ($arLTEInfo->"curr_nmode") [:len [:toarray [/interface lte get $LTEIntID network-mode]]];
					} on-error={
						:set CheckFound true;
						:log warning ($LP . "Can't get modem current network type.");
					}
					:if ($CheckFound = false) do={
						:if (($arLTEInfo->"curr_nmode") < $NetModSupC) do={
							:do {
								/interface lte set $LTEIntID network-mode="";
								:set CheckFound "U";
								:log warning ($LP . "The modem has just been unlocked from network type (sat to default).");
							} on-error={
								:set CheckFound true;
								:log warning ($LP . "Failed to execute command to remove network type lock.");
							}
						} else={
							:log debug ($LP . "Modem network type unlocked allready.");
						}
					}
				} else={
					# Sierra Wireless MC7710 modem
					:if (($arLTEInfo->"model") = "mc7710") do={
						:log debug ($LP . "Found supported modem for network type unlock check.");
						:set ($arLTEInfo->"curr_nmode") [:len [:toarray [/interface lte get $LTEIntID network-mode]]];
						:if (($arLTEInfo->"curr_nmode") != 3) do={
							/interface lte set $LTEIntID network-mode="";
						}
						:do {
							:set arT [:toarray [/interface lte at-chat $LTEIntID input="AT!SELRAT\?" as-value]];
							:if (([:typeof ($arT->"output")] != "str") || (($arT->"output") = "")) do={
								:error ("Can't get modem current network type.");
							}
						} on-error={
							:set CheckFound true;
							:log warning ($LP . "Can't get modem current network type.");
						}
						:if ($CheckFound = false) do={
							:if ([:typeof [:find ($arT->"output") "03, Automatic"]] != "num") do={
								:do {
									/interface lte at-chat $LTEIntID input="AT!ENTERCND=\"A710\"";
									:delay 1;
									/interface lte at-chat $LTEIntID input="AT!SELRAT=03";
									:set CheckFound "U";
									:log warning ($LP . "The modem has just been unlocked from network type (sat to default).");
								} on-error={
									:set CheckFound true;
									:log warning ($LP . "Failed to execute modem command(s) to remove network type lock.");
								}
							} else={
								:log debug ($LP . "Modem network type unlocked allready.");
							}
						}
					} else={
						:log warning ($LP . "No supported modems found for network type unlock.");
					}
				}
				:if ($CheckFound = "U") do={
				# Saving SMS about this action (to send in a future, when Internet become available)
					:if ($StSMSTo != "") do={
						:do {
							:if ($SMSText != "") do={ :set SMSText ($SMSText . ","); }
							:set SMSText ($SMSText . [:tostr $LTERepScrCurrStep]);
							/file set $SMSFile contents=$SMSText;
						} on-error={
							:log error ($LP . "Failed to record SMS text to data-file.");
						}
					}
				}
			} else={
				:set CheckFound true;
			}
			:if ($CheckFound = true) do={
				:set ($LTERepScrStepFailed->$LTERepScrCurrStep) (($LTERepScrStepFailed->$LTERepScrCurrStep) + 1);
			} else={
				:set ($LTERepScrStepFailed->$LTERepScrCurrStep) 0;
			}
		}
		:if ($CheckFound = false) do={
			:set LTERepScrCurrStep 21;
		}
	}
} else={
	:log debug ($LP . "No reset needed for USB/Mini-PCIe modem (Internet is working).");
	:set LTERepScrCurrStep 0;
	:set LTERepScrStepFailed [:toarray ""];
	# Resetting data in NoIntCntFile
	:if ($NoIntCntData != "0") do={
		/file set $NoIntCntFile contents="0";
		:log debug ($LP . "The file that retained the previous Internet status has been cleared.");
	}
	# Resetting data in SMSFile & sending SMS if needed
	:if (($StSMSTo != "") && ($SMSText != "")) do={
		:do {
			:set arTemp [:toarray $SMSText];
			:set arT {"4"="cell/band";"7"="band range";"10"="network type"};
			:set t "";
			:for i from=0 to=([:len $arTemp]-1) step=1 do={
				:if ($i > 0) do={ :set t ($t . ", "); }
				:set t ($t . ($arT->($arTemp->$i)));
			}
			:if ($StRouterName = "") do={ :set StRouterName ("RB #" . [/system routerboard get serial-number]); }
			:set temp ("LTE modem installed at " . $StRouterName . " was automaticaly unlocked from " . $t . ". Event date: " . [/system clock get date] . " " . [/system clock get time] . ".");
			/tool sms send [/interface lte get $LTEIntID name] $StSMSTo message=$temp;
			/file set $SMSFile contents="";
			:log debug ($LP . "SMS about unlock actions has been sent, file with SMS info cleared.");
		} on-error={
			:log warning ($LP . "Failed to send SMS about unlock actions.");
		}
	}
}
Last edited by Frozer on Sat Nov 12, 2022 6:50 pm, edited 4 times in total.
 
Frozer
newbie
Topic Author
Posts: 48
Joined: Wed Apr 10, 2013 4:14 pm
Contact:

Re: LTE_Repair script w/advanced features

Thu Jan 27, 2022 3:02 pm

Updated v.1.0.0 RC4 (27.01.2022)
- Fixed a bug with getting band/cell lock status for R11E-LTE6 modems, which led to multiple unnecessary attempts to unlock it from range/cell;
- Fixed syntax errors preventing modem unbinding from fixed bands and network type.
 
DerAlSem
just joined
Posts: 7
Joined: Sun Jul 23, 2017 1:25 pm

Re: LTE_Repair script w/advanced features

Sun Jul 17, 2022 12:23 pm

Thanks, looks very promising, though it doesn't work as expected on ROS7:

It asks for confirmation on system reboot if run from terminal (for testing purpose). I'd suggest to use this command for reboot:
:execute {/system reboot};
For RBM33g with EP06 installed to miniPCIe i changed the line
/system routerboard usb power-reset duration=5s;
to
/interface/disable lte1;
:delay 4000ms;
/interface/enable lte1;
Still it doesn't reset it. Any clues?
 
Frozer
newbie
Topic Author
Posts: 48
Joined: Wed Apr 10, 2013 4:14 pm
Contact:

Re: LTE_Repair script w/advanced features

Fri Nov 04, 2022 2:50 pm

v.1.1.0 RC1 (04.11.2022)
- Added support for ROS 7 (tested with ROS v.7.6)
- Added support for Quecktel EP06-E (tested with F/W EP06ELAR03A08M4G)
- Removed network type check support for R11E-4G (not needed)
- Added ROS version check
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11967
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: LTE_Repair script w/advanced features

Fri Nov 04, 2022 5:53 pm

on next release fix all errors, like the missing = between else and {
the missing = between on-error and {
remove all useless ;
use one unique string instead of all pieces, from example from this
:set temp ("LTE modem installed at RB #" . [/system routerboard get serial-number] . " was automaticaly unlocked from " . $t . ". Event date: " . [/system clock get date] . " " . [/system clock get time] . ".");

to this
:set temp "LTE modem installed at RB #$[/system routerboard get serial-number] was automaticaly unlocked from $t. Event date: $[/system clock get date] $[/system clock get time]."


need also some optimization, for example from this
:do {
	:set t [/system resource get version];
	:set t [:pick $t 0 [:find $t " "]];
	:set ROSVer [:pick $t 0 [:find $t "."]];
	:if (($ROSVer = "6") && ($t < "6.2")) do={ :set ROSVer ""; }
} on-error={ }
:if (($ROSVer = "6") || ($ROSVer = "7")) do={
	:log debug ($LP . "ROS version is OK (" . $t . ").");
} else {
	:log error ($LP . "Launch terminated, bacause of unsupported version of ROS (" . $t . ").");
	:error ("Launch terminated, bacause of unsupported version of ROS (" . $t . ").");
}

to this
:set t [/system resource get version]
:if ($t~"^(6|7)\\.") do={
	:log info "$LP ROS version is OK [$t]."
} else={
    :set t "$LP Launch terminated, bacause of unsupported version of ROS [$t]."
	:log error $t
	:error $t
}
 
Frozer
newbie
Topic Author
Posts: 48
Joined: Wed Apr 10, 2013 4:14 pm
Contact:

Re: LTE_Repair script w/advanced features

Fri Nov 04, 2022 8:32 pm

Thanks for the recommendations.

1. "=" will be added to the next release, ОК
2. Variables inside strings are not my style, sorry. so will be as is with escape. Whoever likes it the other way around - they rule themselves.
3. Identical parts of the strings will be reduced, OK.
4. The example with regexp for ROS version is certainly laconic, but it would have to be performed several times below and it does not solve the problem of checking for version below 6.2.

I can’t get too careful optimization, because we are talking about code hosted on hundreds of remote routers, so first of all we need to catch existing bugs, if any.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11967
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: LTE_Repair script w/advanced features

Fri Nov 04, 2022 9:09 pm

About 6.2, why?
I honestly think that those who use a version older than 6.44.6 have some serious problems (and I don't want say where) ...
So why bother if it's older than 6.2 (2013!!!), when it's fundamentally wrong to have that version???

Regardeless the idiocy to use pre 6.44.6 versions, adding check for lower than 6.2 is easy...
:if ($t~"^(6\\.[2-9]|7\\.)") do={
 
Frozer
newbie
Topic Author
Posts: 48
Joined: Wed Apr 10, 2013 4:14 pm
Contact:

Re: LTE_Repair script w/advanced features

Sat Nov 05, 2022 12:02 pm

About 6.2, why?
I honestly think that those who use a version older than 6.44.6 have some serious problems (and I don't want say where) ...
So why bother if it's older than 6.2 (2013!!!), when it's fundamentally wrong to have that version???

Regardeless the idiocy to use pre 6.44.6 versions, adding check for lower than 6.2 is easy...
:if ($t~"^(6\\.[2-9]|7\\.)") do={
In version 6.2 added a key->val (key) for foreach cycle, and something else... Some of my routers use 6.1.x, because there was support for some old modems, then support removed (think accidently). In the latest versions, it was added again (after a long correspondence with the support). But often there is no need to update anything if we are dealing with a router with an old modem that only provides Internet access. Also I got the need to do a netinstall after upgrade to new version. Mobile routers can be located very far and high, so I think that I'm not the only one with similar views, so we have what we have.

Added & corrected/optimized a few things in the script, it works well for me now in various conditions.

So waiting for feedback.
 
Frozer
newbie
Topic Author
Posts: 48
Joined: Wed Apr 10, 2013 4:14 pm
Contact:

Re: LTE_Repair script w/advanced features

Sat Nov 05, 2022 12:10 pm

v.1.1.0 RC2 (05.11.2022)
- Added the ability to specify the friendly name of the sender's router for SMS instead of its serial number
- Minor bugs fixed and minor code optimization
 
Frozer
newbie
Topic Author
Posts: 48
Joined: Wed Apr 10, 2013 4:14 pm
Contact:

Re: LTE_Repair script w/advanced features

Sat Nov 12, 2022 6:45 pm

v.1.1.1 (13.11.2022)
- Added support for Mikrotik EG12-EA (Chateau LTE12)
- Fixed a bug that prevented a hunged script job from being removed by timeout (if it ever happens)
- Other minor code optimization

Who is online

Users browsing this forum: JDF, miks and 24 guests