V7.23 script bug - incorrect values scanned from lte monitor

After RouterOS upgrade (to 7.23) scanning strings from an interface monitor doesn't work. Everything is offset by one entry.

If we get the LTE interface stats from the command line:

[admin@ATL5G_mast] > /interface/lte/monitor lte1 once                                          
             status: running                              
              model: RG520F-EU                            
           revision: RG520FEUEAR03A06M4GX                 
   current-operator: ABC                                   
     current-cellid: 1234567                              
             enb-id: 12345                                
          sector-id: 0                                    
         phy-cellid: 123                                  
         data-class: LTE                                  
     session-uptime: 42m37s                               
               imei: 123456789012345                      
               imsi: 123456789012345                      
              iccid: 1234567890123456789                  
  subscriber-number: +447000000000                        
       primary-band: B3@20Mhz earfcn: 1617 phy-cellid: 123
            ca-band: B3@20Mhz earfcn: 1815 phy-cellid: 456
      dl-modulation: qpsk                                 
                cqi: 6                                    
                 ri: 2                                    
                mcs: 8                                    
               rssi: -81dBm                               
               rsrp: -112dBm                              
               rsrq: -12dB                                
               sinr: 11dB

Some values obviously redacted. Now if we put values from this into globals we get entries offset by one in the list:

[admin@ATL5G_mast] > :global sector                                                           
[admin@ATL5G_mast] > /interface/lte/monitor lte1 once do={:global sector $"sector-id"};       
[admin@ATL5G_mast] >  put $sector 
12345 (<-this is actually the enb-id!)

When we ask for sector-id we get the entry from the previous line. There are more issues with type conversions too. If we ask for something that returns a string (e.g. the data-class) we don't get the phy-cellid because (I assume) the data types are different.

[admin@ATL5G_mast] > :global datclass                                                  
[admin@ATL5G_mast] > /interface/lte/monitor lte1 once do={:global datclass $"data-class"};
[admin@ATL5G_mast] >  put $datclass                                                       
null

I noticed this due to a change in the behaviour of a script I have that logs cell tower performance. Is this a bug? Seems serious to me! Or a change in the scripting behaviour that has caught me out?

Previous script pasted below for reference (this used to work before the OS upgrade!) ...

:global ActualCellID;
:global RSSI;
:global RSRQ;
:global SINR;
:global DataClass;
/interface/lte/monitor [find] once do={:global ActualCellID $"phy-cellid"};
/interface/lte/monitor [find] once do={:global RSSI $"rssi"};
/interface/lte/monitor [find] once do={:global RSRQ $"rsrq"};
/interface/lte/monitor [find] once do={:global SINR $"sinr"};
/interface/lte/monitor [find] once do={:global DataClass $"data-class"};
:log info message="CellID=$ActualCellID, RSSI=$RSSI dBm, RSRQ=$RSRQ dB, SINR=$SINR dB, DataClass=$DataClass.";

Aside from the fact that the script is really poorly written, regardless of the bug,

it's a really bad bug....

# untested on v7 because I do not have one LTE on v7.23 at the moment
{
:local result [/interface lte monitor ([find]->0) once as-value]

:local ActualCellID ($result->"phy-cellid")
:local RSSI         ($result->"rssi")
:local RSRQ         ($result->"rsrq")
:local SINR         ($result->"sinr")
:local DataClass    ($result->"data-class")

:log info message="CellID=$ActualCellID, RSSI=$RSSI dBm, RSRQ=$RSRQ dB, SINR=$SINR dB, DataClass=$DataClass."
}

@rextended Thank you, your properly written script has very nearly fixed the issue. I assume that my old (terrible) script (which was pasted together from various parts of this forum) stopped working due to some change in behaviour. The good script you wrote almost works as expected...

Old script:

CellID=0, RSSI= dBm, RSRQ= dB, SINR=-80 dB, DataClass=.

@rextended script:

CellID=123, RSSI=-82 dBm, RSRQ=-110 dB, SINR=12 dB, DataClass=LTE.

There is now just one error with the output... the values that are decimals have their point stripped so -10.0 dB is reported as -100 dB. This happens at the...

:local RSRQ ($result->"rsrq")

... and not when the line is written to the log.

@rextended, do you have any suggestions? Thank you!

MikroTik do not support decimals on scripting...

% = modular division, return the remainder, so, for example 5 % 3 = 2

read -102
convert -102 in positive 102 (because -102 / -10 = 10, but -102 % ±10 do -2 on both cases) multipling by -1
create a string that start with "-",
add as string the result of (102/10) = "10",
add the point "."
add as string the result of (102%10) = "2",
done.

TIP: for remove the space between number and dB, simply use quotes for var name...
on this peculiar way, the quotes are not needed to be escaped.

# untested on v7 because I do not have one LTE on v7.23 at the moment
{
:local result [/interface lte monitor ([find]->0) once as-value]

:local ActualCellID ($result->"phy-cellid")
:local RSSI         ($result->"rssi")
:local RSRQ         (($result->"rsrq") * -1)
:local RSRQ         "-$($RSRQ / 10).$($RSRQ % 10)"
:local SINR         ($result->"sinr")
:local DataClass    ($result->"data-class")

:log info message="CellID=$ActualCellID, RSSI=$"RSSI"dBm, RSRQ=$"RSRQ"dB, SINR=$"SINR"dB, DataClass=$DataClass."
}
{
    :local result [/interface lte monitor ([find]->0) once as-value]
    
    :local ActualCellID ($result->"phy-cellid")
    :local RSSI         ($result->"rssi")
    :local RSRQ         ($result->"rsrq")
    :local SINR         ($result->"sinr")
    :local DataClass    ($result->"data-class")

    # Determine the data types
    :local typeCellID   [:typeof $ActualCellID]
    :local typeRSSI     [:typeof $RSSI]
    :local typeRSRQ     [:typeof $RSRQ]
    :local typeSINR     [:typeof $SINR]
    :local typeDataClass [:typeof $DataClass]

    :log info message="CellID=$ActualCellID (type: $typeCellID), RSSI=$RSSI dBm (type: $typeRSSI), RSRQ=$RSRQ dB (type: $typeRSRQ), SINR=$SINR dB (type: $typeSINR), DataClass=$DataClass (type: $typeDataClass)."
}

I'd try this first to see what we're dealing with.

This is RouterOS 6.48.7:
CellID=170 (type: num), RSSI= dBm (type: nothing), RSRQ=-140 dB (type: num), SINR=4 dB (type: num), DataClass= (type: nothing).

MikroTik do not support decimals on scripting...

Arg! :man_facepalming: I should have remembered this. I assume decimals are strictly for IP addresses? Thank you for reminding me.

:astonished_face: Thank you script Sensei @rextended :man_bowing:

That solves it completely:

CellID=191, RSSI=-82dBm, RSRQ=-8.0dB, SINR=13dB, DataClass=LTE.

Awesome scripting, thank you for sharing, I really appreciate it.

This is RouterOS 7.23 on ATLGM:
CellID=191 (type: num), RSSI=-79 dBm (type: num), RSRQ=-110 dB (type: num), SINR=11 dB (type: num), DataClass=LTE (type: str).

I see differences :slight_smile:

Final script that runs really well. Search terms:
5G LTE signal reporting script interface monitor system log

# Max kudos to @rextended on Mikrotik forums for this and their thorough explanation
{
# Get the interface data we want and store in temporary value 'result'
:local result [/interface lte monitor ([find]->0) once as-value]
# Now scan from 'result' the information we want
:local ActualCellID    ($result->"phy-cellid")
:local RSSI                 ($result->"rssi")
# Read rsrq in and mutliply it by -1 in a single step, works because the RSRQ cannot be positive in theory
# Result is read in but it will have any decimal place removed so -11.3dB will be read in as -113
# because Mikrotik scripts cannot deal with decimals
# Note for later... this is effectively taking the result and ×10
:local RSRQ                 (($result->"rsrq") * -1)
# Make a string that starts with "-", then has the integer part of the RSRQ value by div by 10
# Then add a decimal point followed by the quotient part left when modular division is used
# Using % for modular division returning just the remainder i.e. 5%3=2. 
:local RSRQ                 "-$($RSRQ / 10).$($RSRQ % 10)"
:local SINR                 ($result->"sinr")
:local DataClass        ($result->"data-class")

# Write log entry without spaces between values and units
#:log info message="CellID=$ActualCellID, RSSI=$"RSSI"dBm, RSRQ=$"RSRQ"dB, SINR=$"SINR"dB, DataClass=$DataClass."

# Write log entry lazy way (has spaces between values and decibel units)
:log info message="CellID=$ActualCellID, RSSI=$RSSI dBm, RSRQ=$RSRQ dB, SINR=$SINR dB, DataClass=$DataClass."
}