NETGEAR is aware of a growing number of phone and online scams. To learn how to stay safe click here.
Forum Discussion
pollardd
Aug 05, 2019Aspirant
4G Signal Bars drop from 5 to 2 after 30 minutes and stays that way
Hi Guys, I have a LB2120 and it is working fairly well. I'm in a regional area and have it connected to an external 4G antenna. It's permanently connected to 4G. It is not used in fail over mode. ...
psynpase
Feb 18, 2020Aspirant
Hi,
Well I have been doing a little more investigation. On Github I found that somebody had written some python (called eternalegypt) .... for which many thanks. This allows you to interrogate the modem without having to go to the web page. By modifying one of these scripts and running it under cron (every 5 minutes) I have been able to log statistics. These show quite clearly that the modem starts by connecting to the B3 band and after a certain (and variable) period of time switches to the higher frequency B7 band. In the process I lose 10dB of signal strength and a great deal of upload performance (a factor of 10-20, ie from 20Mbps to less that 1). I am pretty sure that this is frequency management by the cell tower and nothing to do with the modem. However I would love to be able to lock the modem down to bands below 2GHz because I live in a rural area and radio propogation is not obvious.
My partial work around is to reboot the modem before I need to use it (simply going offline and then online does NOT resolve the problem), But in your case and IF you have the same problem then the speed with which this all happens gives you very little time to work.
For reference the B7 signal comes in at RSSI -90dB whilst the B3 signal is in the -77 to -81 range. The RSRP levels are more marked -120dB vs-105dB. If this is a firmware issue, I certainly hope that Netgear fix it!
pollardd
Mar 08, 2020Aspirant
Hey psynpase ,
I'm just wondering if you have reached any conclusions with your diagnosis?
My modem started doing more weird stuff today. This morning it was not connected to Telstra and it stayed off for about 5 hours. No amount of rebooting could get it back on line. I had to fall back to my satalite connection with its painfully slow round trip times.
Suddnely with out me doing anything I looked over to my modem and it had 5 Bars. I ran speedtest.net and I was getting around 50Mbps up and down! After 20 minutes or so it has dropped back down to 1 or 2 bars again and 30 down 5 up aka normal.
I was wondering if I could get a copy of the python script you have been using to log data. I found the author on github but I don't really need to reinvent the wheel if you have made some useful changes to the script.
Thanks
David.
- psynpaseMar 09, 2020Aspirant
Hi Pollard,
First things first! I am going to be looking at my data for a good twelve months yet, because where I am the signal path passes through vegetation and I am expecting a degradation in signal quality as spring arrives in the northern hemisphere. So this will be the first of several updates.
I have been logging data for around a month now and apart from occasional storms I expect the signal path has been pretty stable .... which is more that I can say for the signal! My own experience (reinforced by what I have read elsewhere) is that the service providers play fast and loose with band allocations and in a dynamic manner (Just as a point of reference, here in France I use "Free" largely because it uses its own microwave trunk infrastructure, which is currently less burdened that the infrastructure of the ex state owned France Telecom, which nearly everybody uses).
It is still early days, but there is a strong trend for the ISP to switch me to the highest frequency band available, B7. Despite having a mast mounted MIMO array, the signal staggers in at around -118db, with OKish download speeds but almost not existant <0.4Mbps upload speeds. A modem reset gets me back to band B3 which (depending on other users present on the net) will get me anything up to 90/20Mbps , very nice thank you. After a variable time (which seems to be related to network load) I will drop back down to B7. An interesting thing to note is that this will happen regardless of whether the modem is left in the "connected" or "disconnected" state. Which poses the question as to what "connected" actually means to Netgear.
On just one occasion the modem has switched to B28 (which, btw, the Netgear reports as "unknown" band, but with a correct channel number).
On very few occasions have I seen the network "upgrade" me from B7 to B3.
As a point of pure conjecture, I believe that Free brought their B7 band allocation first, rolled out their 4G infrastructure in a hurry, even to rural areas where 2.5GHz propogation is problematic. They then acquired a B3 licence and recently a B28. Users with handsets or tablets hence struggle to get B7, nearly everybody tries to get onto B3, because at the moment B28 is too new for most in the field hardware.
Second point. Python scripts. I use Linux, so I cannot give chapter and verse for windows, but hey it is python, so how hard can it be? But then I regard myself as just a script kiddy:- all credit to the original author.
I have modded one file (the main one) in the original distro, in order for it to report more parameters. And added two example scipts, one to report stats in a readable form, the other to generate time stamped csv values for import to a speadsheet.
So eg I can run the logging script manually with
/usr/bin/env python3 /home/myusername/Downloads/eternalegypt-master/examples/logstats.py <netgear ip> <netgear password>
I have added this line to my (user) cron file.
And, in the right directory the stats reporter is run simply by
./status2.py <netgear ip> <netgear password>
The additions/modifications I have made to the original distro are in the attached zip .... note that you will have to edit logstats.py to reflect the path to your logfile, because I did not make this a parameter specified at run time.
Postscript, no zips to tne community board :-(
Good luck
- psynpaseMar 09, 2020Aspirant
Modified eternalegypt.py
"""Library for interfacing with Netgear LTE modems."""
import logging
import re
import json
from functools import wraps
from datetime import datetime
import asyncio
from aiohttp.client_exceptions import ClientError
import async_timeout
import attr
import flatten_jsonTIMEOUT = 3
_LOGGER = logging.getLogger(__name__)
class Error(Exception):
"""Base class for all exceptions."""
@attr.s
class SMS:
"""An SMS message."""
id = attr.ib()
timestamp = attr.ib()
unread = attr.ib()
sender = attr.ib()
message = attr.ib()
@attr.s
class Information:
"""Various information from the modem."""
serial_number = attr.ib(default=None)
usage = attr.ib(default=None)
upstream = attr.ib(default=None)
wire_connected = attr.ib(default=None)
mobile_connected = attr.ib(default=None)
connection_text = attr.ib(default=None)
connection_type = attr.ib(default=None)
current_nw_service_type = attr.ib(default=None)
current_ps_service_type = attr.ib(default=None)
register_network_display = attr.ib(default=None)
roaming = attr.ib(default=None)
radio_quality = attr.ib(default=None)
rx_level = attr.ib(default=None)
tx_level = attr.ib(default=None)
current_band = attr.ib(default=None)
cell_id = attr.ib(default=None)
sms = attr.ib(factory=list)
items = attr.ib(factory=dict)
def autologin(function, timeout=TIMEOUT):
"""Decorator that will try to login and redo an action before failing."""
@wraps(function)
async def wrapper(self, *args, **kwargs):
"""Wrap a function with timeout."""
try:
async with async_timeout.timeout(timeout):
return await function(self, *args, **kwargs)
except (asyncio.TimeoutError, ClientError, Error):
pass_LOGGER.debug("autologin")
try:
async with async_timeout.timeout(timeout):
await self.login()
return await function(self, *args, **kwargs)
except (asyncio.TimeoutError, ClientError, Error):
raise Error(str(function))return wrapper
@attr.s
class LB2120:
"""Class for Netgear LB2120 interface."""hostname = attr.ib()
websession = attr.ib()password = attr.ib(default=None)
token = attr.ib(default=None)listeners = attr.ib(init=False, factory=list)
max_sms_id = attr.ib(init=False, default=None)@property
def _baseurl(self):
return "http://{}/".format(self.hostname)def _url(self, path):
"""Build a complete URL for the device."""
return self._baseurl + pathasync def add_sms_listener(self, listener):
"""Add a listener for new SMS."""
self.listeners.append(listener)async def logout(self):
"""Cleanup resources."""
self.websession = None
self.token = Noneasync def login(self, password=None):
"""Create a session with the modem."""
# Work around missing https://github.com/aio-libs/aiohttp/pull/3576
try:
await self._login(password)
except (asyncio.TimeoutError, ClientError, Error):
await self._login(password)async def _login(self, password=None):
"""Create a session with the modem."""
if password is None:
password = self.password
else:
self.password = passwordtry:
async with async_timeout.timeout(TIMEOUT):
url = self._url('model.json')
async with self.websession.get(url) as response:
data = json.loads(await response.text())
self.token = data.get('session', {}).get('secToken')if self.token is None:
_LOGGER.error("No token found during login")
raise Error()_LOGGER.debug("Token: %s", self.token)
url = self._url('Forms/config')
data = {
'session.password': password,
'token': self.token
}
async with self.websession.post(url, data=data) as response:
_LOGGER.debug("Got cookie with status %d", response.status)except (asyncio.TimeoutError, ClientError, Error):
raise Error("Could not login")@autologin
async def sms(self, phone, message):
"""Send a message."""
_LOGGER.debug("Send to %s via %s len=%d",
phone, self._baseurl, len(message))url = self._url('Forms/smsSendMsg')
data = {
'sms.sendMsg.receiver': phone,
'sms.sendMsg.text': message,
'sms.sendMsg.clientId': __name__,
'action': 'send',
'token': self.token
}
async with self.websession.post(url, data=data) as response:
_LOGGER.debug("Sent message with status %d", response.status)def _config_call(self, key, value):
"""Set a configuration key to a certain value."""
url = self._url('Forms/config')
data = {
key: value,
'err_redirect': '/error.json',
'ok_redirect': '/success.json',
'token': self.token
}
return self.websession.post(url, data=data)@autologin
async def disconnect_lte(self):
"""Do an LTE disconnect."""
async with self._config_call('wwan.connect', 'Disconnect') as response:
_LOGGER.debug("Disconnected LTE with status %d", response.status)@autologin
async def connect_lte(self):
"""Do an LTE reconnect."""
async with self._config_call('wwan.connect', 'DefaultProfile') as response:
_LOGGER.debug("Connected to LTE with status %d", response.status)@autologin
async def delete_sms(self, sms_id):
"""Delete a message."""
async with self._config_call('sms.deleteId', sms_id) as response:
_LOGGER.debug("Delete %d with status %d", sms_id, response.status)@autologin
async def set_failover_mode(self, mode):
"""Set failover mode."""
modes = {
'auto': 'Auto',
'wire': 'WAN',
'mobile': 'LTE',
}if mode not in modes.keys():
_LOGGER.error("Invalid mode %s not %s", mode, "/".join(modes.keys()))
returnasync with self._config_call('failover.mode', modes[mode]) as response:
_LOGGER.debug("Set mode to %s", mode)@autologin
async def set_autoconnect_mode(self, mode):
"""Set autoconnect mode."""
modes = {
'never': 'Never',
'home': 'HomeNetwork',
'always': 'Always',
}if mode not in modes.keys():
_LOGGER.error("Invalid mode %s not %s", mode, "/".join(modes.keys()))
returnasync with self._config_call('wwan.autoconnect', modes[mode]) as response:
_LOGGER.debug("Set mode to %s", mode)def _build_information(self, data):
"""Read the bits we need from returned data."""
result = Information()result.serial_number = data['general']['FSN']
result.usage = data['wwan']['dataUsage']['generic']['dataTransferred']
if 'failover' in data
if 'backhaul' in data['failover']:
result.upstream = data['failover']['backhaul']
result.wire_connected = data['failover']['wanConnected']
result.mobile_connected = (data['wwan']['connection'] == 'Connected')
result.connection_text = data['wwan']['connectionText']
result.connection_type = data['wwan']['connectionType']
result.current_nw_service_type = data['wwan']['currentNWserviceType']
result.current_ps_service_type = data['wwan']['currentPSserviceType']
result.register_network_display = data['wwan']['registerNetworkDisplay']
result.roaming = data['wwan']['roaming']
result.radio_quality = data['wwanadv']['radioQuality']
result.rx_level = data['wwanadv']['rxLevel']
result.tx_level = data['wwanadv']['txLevel']
result.current_band = data['wwanadv']['curBand']
result.cell_id = data['wwanadv']['cellId']
result.ecio = data['wwan']['signalStrength']['ecio']
result.rscp = data['wwan']['signalStrength']['rscp']
result.rsrp = data['wwan']['signalStrength']['rsrp']
result.rsrq = data['wwan']['signalStrength']['rsrq']
result.rssi = data['wwan']['signalStrength']['rssi']
result.sinr = data['wwan']['signalStrength']['sinr']
mdy_models = ('MR1100')for msg in [m for m in data['sms']['msgs'] if 'text' in m]:
# {'id': '6', 'rxTime': '11/03/18 08:18:11 PM', 'text': 'tak tik',
# 'sender': '555-987-654', 'read': False}
try:
if ('model' in data['general'] and data['general']['model'] in mdy_models):
dt = datetime.strptime(msg['rxTime'], '%m/%d/%y %I:%M:%S %p')
else:
dt = datetime.strptime(msg['rxTime'], '%d/%m/%y %I:%M:%S %p')
except ValueError:
dt = Noneelement = SMS(int(msg['id']), dt, not msg['read'], msg['sender'], msg['text'])
result.sms.append(element)
result.sms.sort(key=lambda sms: sms.id)result.items = {
key.lower(): value
for key, value in flatten_json.flatten(data, '.').items()
if value != {}
and not re.search(r'\.\d+\.', key)
and not re.search(r'\.end$', key)
and key.lower() not in ('webd.adminpassword', 'session.sectoken', 'wifi.guest.passphrase', 'wifi.passphrase')
}return result
@autologin
async def information(self):
"""Return the current information."""
url = self._url('model.json')
async with self.websession.get(url) as response:
data = json.loads(await response.text())try:
result = self._build_information(data)
except KeyError:
_LOGGER.debug("Failed to read information: %s", data)
raise Error()self._sms_events(result)
return result
def _sms_events(self, information):
"""Send events for each new SMS."""
if not self.listeners:
returnif self.max_sms_id is not None:
new_sms = (s for s in information.sms if s.id > self.max_sms_id)
for sms in new_sms:
for listener in self.listeners:
listener(sms)if information.sms:
self.max_sms_id = max(s.id for s in information.sms)
class Modem(LB2120):
"""Class for any modem."""- pollarddMar 10, 2020Aspirant
Hi Psynpase,
Thanks for the very detailed response. I'm not that deep into all the different bands as you are. Basically here they are named 3G, 4G, and the new one is named 5G. I expect the B codes you mentioned are the underlying protocol code names.
I'm a C# programer and haven't played much with Linux for the last 15 years but I'm sure python will come back to me.
I think I'd call my self a script Grand Pa. :)
I managed to install Python on windows and when I tried to run the standard eternalegypt.py script it reported a missing dependancy. I forget the name of that one now 2 days later. I managed to figure out a bit about the installer and fix them one up but now I have been distracted by actual work. :)
I'll let you know when I get it to work or get stuck. I may even post some of my results here to see if other can make sense of them if I can't.
By The Way. I thought to get MIMO to work you needed a device with two antenna ports and it being specifically built to take advantage of it. My LB2120 only has one port. I found this bit in an online manual. I'm guessing there is more than one version.
Optional External Antenna
=====================
You can purchase an external multiple input, multiple output (MIMO) antenna for the modem to extend the
mobile broadband signal range indoors or in fringe network areas.
The external antenna plugs into the two antenna connectors on the modem to boost speeds and extend
coverage in buildings or vehicles, or in remote sites where network coverage is sparse.You could, for
example, attach the external antenna on a window with a suction cup