mqtt_client.tls_set(ca_certs=path_to_root_cert, certfile=None, keyfile=None, cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLSv1, ciphers=None) mqtt_client.tls_insecure_set(False) mqtt_client.connect(iot_hub_name + '.azure-devices.net', port=8883) # Get some router data and publish to the IoT Hub device_data = dict() cp.log('device_data = {}'.format(device_data)) device_data['router_id'] = cp.get('/config/system/system_id') device_data['product_name'] = cp.get('/status/product_info/product_name') # Not all CP devices have a modem_temperature if device_data['product_name'].startswith('ibr200') is False: device_data['router_temperature'] = cp.get( '/status/system/modem_temperature') mqtt_client.publish('devices/' + device_id + '/messages/events/', urllib.parse.urlencode(device_data), qos=1) mqtt_client.loop_forever() except Exception as e: cp.log('Exception: {}'.format(e))
debug_log(f'HTTP POST - Headers: {headers}') debug_log(f'HTTP POST - Payload: {payload}') req = requests.post(url, headers=headers, json=payload) cp.log(f'HTTP POST Result: {req.status_code} {req.text}') except Exception as e: logstamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') logs.append(f'{logstamp} Exception in Send to Server: {e}') cp.log(f'Exception in Send to Server: {e}') if __name__ == "__main__": cp = EventingCSClient('Mobile Site Survey') cp.log('Starting...') # Wait for WAN connection while not cp.get('status/ecm/state') == 'connected': time.sleep(1) time.sleep(3) dispatcher = Dispatcher() Thread(target=dispatcher.loop, daemon=True).start() application = tornado.web.Application([ (r"/config", ConfigHandler), (r"/submit", SubmitHandler), (r"/test", TestHandler), (r"/(.*)", tornado.web.StaticFileHandler, {"path": os.path.dirname(__file__), "default_filename": "index.html"}), (r"/FTP", tornado.web.StaticFileHandler, {"path": os.path.dirname(__file__) + '/FTP'}) ]) application.listen(8000)
class DataUsageCheck(object): """ Establish global variables. Set rate shaping values (in Kbps) for 70, 80, 90 & 100% rate tiers. e.g. minbwup_70 & minbwdown_70 refers to upload & download at 70% Each of the rate tiers have a default throttling limit set below: 70% - 6000Kbps Tx/Rx 80% - 3000Kbps Tx/Rx 90% - 1500Kbps Tx/Rx 100% - 600Kbps Tx/Rx """ minbwup_70 = 6000 minbwdown_70 = 6000 minbwup_80 = 3000 minbwdown_80 = 3000 minbwup_90 = 1500 minbwdown_90 = 1500 minbwup_100 = 600 minbwdown_100 = 600 STATUS_DEVS_PATH = '/status/wan/devices' STATUS_DATACAP_PATH = '/status/wan/datacap' CFG_RULES2_PATH = '/config/wan/rules2' def __init__(self): self.cp = EventingCSClient(app_name) def find_modems(self): while True: devs = self.cp.get(self.STATUS_DEVS_PATH) modems_list = [x for x in devs if x.startswith('mdm-')] self.cp.log(f'modems_list: {modems_list}') num_modems = len(modems_list) if not num_modems: self.cp.log('No Modems found at all yet') time.sleep(10) continue else: return modems_list def find_modem_profiles(self): wan_ifcs = self.cp.get(self.CFG_RULES2_PATH) modem_profiles_list = [ x['_id_'] for x in wan_ifcs if x['trigger_string'].startswith('type|is|mdm') ] self.cp.log(f'modem_profiles_list: {modem_profiles_list}') return modem_profiles_list def reset_throttle(self, modem_profiles_list, monthlyreset): for mdm in modem_profiles_list: if monthlyreset: self.cp.delete(self.CFG_RULES2_PATH + '/' + mdm + '/bandwidth_egress') self.cp.delete(self.CFG_RULES2_PATH + '/' + mdm + '/bandwidth_ingress') else: if 'bandwidth_egress' in self.cp.get(self.CFG_RULES2_PATH + '/' + mdm): self.cp.delete(self.CFG_RULES2_PATH + '/' + mdm + '/bandwidth_egress') if 'bandwidth_ingress' in self.cp.get(self.CFG_RULES2_PATH + '/' + mdm): self.cp.delete(self.CFG_RULES2_PATH + '/' + mdm + '/bandwidth_ingress') self.cp.put('config/qos/enabled', False) if monthlyreset: self.cp.log( 'Monthly data usage reset - disabling reduced LTE data rate') message = ( f'Monthly data usage reset - disabling reduced LTE data rate ' f'for {self.system_id} - {self.product_name} - Router ID: ' f'{self.router_id}') self.cp.alert(message) def set_throttle(self, modem_profiles_list, minbwup, minbwdown, tierset): for mdm in modem_profiles_list: self.cp.put(self.CFG_RULES2_PATH + '/' + mdm + '/bandwidth_egress', minbwup) self.cp.put( self.CFG_RULES2_PATH + '/' + mdm + '/bandwidth_ingress', minbwdown) self.cp.put('config/qos/enabled', True) self.cp.log('Exceeded monthly data usage threshold - ' + str(tierset) + '% tier - reducing LTE data rate') message = ( f'Exceeded monthly data usage threshold - reducing LTE data rate ' f'for {self.system_id} - {self.product_name} - Router ID: ' f'{self.router_id}') self.cp.alert(message) def run(self): # Get info from router to populate description field in NCM # alert message self.product_name = self.cp.get('/status/product_info/product_name') self.system_id = self.cp.get('/config/system/system_id') self.router_id = self.cp.get('status/ecm/client_id') # Retrieve list of modems and their profiles modems_list = [str(x.split('-')[1]) for x in self.find_modems()] modem_profiles_list = self.find_modem_profiles() # Reset any throttling to account for router reboots. If a # data cap alert is still active during the monthly cycle, the # appropriate rate shaping will be re-applied monthlyreset = False self.reset_throttle(modem_profiles_list, monthlyreset) time.sleep(5) currtierset = 0 while True: if self.cp.get(self.STATUS_DATACAP_PATH + '/completed_alerts/'): alerts = self.cp.get(self.STATUS_DATACAP_PATH + '/completed_alerts/') limitreached = 0 tierset = 0 for indalert in alerts: for modem in modems_list: if (indalert['alerts'] and indalert['rule_id'] == modem + '-monthly'): if 'email_alert' in indalert['alerts']: limitreached += 1 tierset = 100 minbwup = self.minbwup_100 minbwdown = self.minbwdown_100 continue elif 'early_email-90.0' in indalert['alerts']: limitreached += 1 tierset = 90 minbwup = self.minbwup_90 minbwdown = self.minbwdown_90 continue elif 'early_email-80.0' in indalert['alerts']: limitreached += 1 tierset = 80 minbwup = self.minbwup_80 minbwdown = self.minbwdown_80 continue elif 'early_email-70.0' in indalert['alerts']: limitreached += 1 tierset = 70 minbwup = self.minbwup_70 minbwdown = self.minbwdown_70 continue if limitreached > 0 and currtierset != tierset: currtierset = tierset self.set_throttle(modem_profiles_list, minbwup, minbwdown, currtierset) elif limitreached == 0 and currtierset > 0: currtierset = 0 monthlyreset = True self.reset_throttle(modem_profiles_list, monthlyreset) elif currtierset > 0: currtierset = 0 monthlyreset = True self.reset_throttle(modem_profiles_list, monthlyreset) time.sleep(10)
from csclient import EventingCSClient cp = EventingCSClient('mqtt_app') MQTT_CLIENT_ID = cp.get('config/system/system_id') # MQTT Server settings MQTT_SERVER = 'test.mosquitto.org' MQTT_PORT = 1883 MQTT_USER_NAME = 'anonymous' MQTT_PASSWORD = '******' # MQTT Topics # Topics are named the same as the path to get the data from the # NCOS device. This was done for simplicity. GPS_TOPIC = '/status/gps/lastpos' MODEM_TEMP_TOPIC = '/status/system/modem_temperature' WAN_CONNECTION_STATE_TOPIC = '/status/wan/connection_state'
""" Probe the GPS hardware and log the results. """ from csclient import EventingCSClient cp = EventingCSClient('gps_probe') gps_enabled = cp.get('/config/system/gps/enabled') if not gps_enabled: cp.log('GPS Function is NOT Enabled') else: cp.log('GPS Function is Enabled') gps_data = cp.get('/status/gps') cp.log(gps_data)
class SIMSpeedTest(object): MIN_DOWNLOAD_SPD = 0.0 # Mbps MIN_UPLOAD_SPD = 0.0 # Mbps SCHEDULE = 0 # Run Boot2 every {SCHEDULE} minutes. 0 = Only run on boot. NUM_ACTIVE_SIMS = 0 # Number of fastest (download) SIMs to keep active. 0 = all; do not disable SIMs ONLY_RUN_ONCE = False # True means do not run if Boot2 has been run on this device before. STATUS_DEVS_PATH = '/status/wan/devices' CFG_RULES2_PATH = '/config/wan/rules2' CTRL_WAN_DEVS_PATH = '/control/wan/devices' API_URL = 'https://www.cradlepointecm.com/api/v2' CONNECTION_STATE_TIMEOUT = 7 * 60 # 7 Min NETPERF_TIMEOUT = 5 * 60 # 5 Min sims = {} def __init__(self): self.client = EventingCSClient('Boot2') def check_if_run_before(self): if self.ONLY_RUN_ONCE: if self.client.get('/config/wan/rules2/0/_id_' ) == '00000000-1234-1234-1234-1234567890ab': self.client.log( 'ERROR - Boot2 has been run before! /config/wan/rules2/0/_id = 00000000-1234-1234-1234-1234567890ab' ) raise RunBefore( 'ERROR - Boot2 has been run before! /config/wan/rules2/0/_id = 00000000-1234-1234-1234-1234567890ab' ) return False def wait_for_ncm_sync(self): # WAN connection_state if self.client.get('status/wan/connection_state') != 'connected': self.client.log('Waiting until WAN is connected...') timeout_count = 500 while self.client.get('/status/wan/connection_state') != 'connected': timeout_count -= 1 if not timeout_count: raise Timeout('WAN not connecting') time.sleep(2) # ECM State if self.client.get('status/ecm/state') != 'connected': self.client.log('Waiting until NCM is connected...') self.client.put('/control/ecm', {'start': True}) timeout_count = 500 while self.client.get('/status/ecm/state') != 'connected': timeout_count -= 1 if not timeout_count: raise Timeout('NCM not connecting') time.sleep(2) # ECM Sync if self.client.get('status/ecm/sync') != 'ready': self.client.log('Waiting until NCM is synced...') self.client.put('/control/ecm', {'start': True}) timeout_count = 500 while self.client.get('/status/ecm/sync') != 'ready': self.client.put('/control/ecm', {'start': True}) timeout_count -= 1 if not timeout_count: raise Timeout('NCM not connecting') time.sleep(2) return def NCM_suspend(self): self.client.log('Stopping NCM') timeout_count = 500 while not 'ready' == self.client.get('/status/ecm/sync'): timeout_count -= 1 if not timeout_count: raise Timeout('NCM sync not ready') time.sleep(2) self.client.put('/control/ecm', {'stop': True}) timeout_count = 500 while not 'stopped' == self.client.get('/status/ecm/state'): timeout_count -= 1 if not timeout_count: raise Timeout('NCM not stopping') time.sleep(2) def find_sims(self): while True: sims = {} wan_devs = self.client.get(self.STATUS_DEVS_PATH) or {} for uid, status in wan_devs.items(): if uid.startswith('mdm-'): error_text = status.get('status', {}).get('error_text', '') if error_text: if 'NOSIM' in error_text: continue sims[uid] = status num_sims = len(sims) if not num_sims: self.client.log('No SIMs found at all yet') time.sleep(10) continue if num_sims < 2: self.client.log('Only 1 SIM found!') raise OneModem('Only 1 SIM found!') else: break self.client.log(f'Found SIMs: {sims.keys()}') self.sims = sims return True def modem_state(self, sim, state): # Blocking call that will wait until a given state is shown as the modem's status timeout_counter = 0 sleep_seconds = 0 conn_path = '%s/%s/status/connection_state' % (self.STATUS_DEVS_PATH, sim) self.client.log(f'Connecting {self.port_sim(sim)}') while True: sleep_seconds += 5 conn_state = self.client.get(conn_path) self.client.log( f'Waiting for {self.port_sim(sim)} to connect. Current State={conn_state}' ) if conn_state == state: break if timeout_counter > self.CONNECTION_STATE_TIMEOUT: self.client.log(f'Timeout waiting on {self.port_sim(sim)}') raise Timeout(conn_path) time.sleep(min(sleep_seconds, 45)) timeout_counter += sleep_seconds self.client.log(f'{self.port_sim(sim)} connected.') return True def iface(self, sim): iface = self.client.get('%s/%s/info/iface' % (self.STATUS_DEVS_PATH, sim)) return iface def port_sim(self, sim): return f'{self.sims[sim]["info"]["port"]} {self.sims[sim]["info"]["sim"]}' def run_speedtest(self, speedtest): self.client.put('/state/system/netperf', {"run_count": 0}) res = self.client.put("/control/netperf", speedtest) self.client.log(f'Starting Speedtest... {res}') timeout_counter = 0 # wait for results delay = speedtest['input']['options']['limit']['time'] + 8 status_path = "/control/netperf/output/status" while True: time.sleep(delay) status = self.client.get(status_path) if status == 'complete': break if timeout_counter > self.NETPERF_TIMEOUT: self.client.log( f"Timeout waiting on speedtest for {speedtest['input']['options']['ifc_wan']}" ) raise Timeout(status_path) timeout_counter += delay if status != 'complete': self.client.log(f"ERROR: status=%s expected 'complete' {status}") return None # now get the result results_path = self.client.get("/control/netperf/output/results_path") results = None while not results: results = self.client.get(results_path) time.sleep(2) self.client.log('Speedtest Complete.') return results def do_speedtest(self, sim): default_speedtest['input']['options']['ifc_wan'] = self.iface(sim) default_speedtest['input']['options']['send'] = False default_speedtest['input']['options']['recv'] = True tcp_down = self.run_speedtest(default_speedtest).get('tcp_down') default_speedtest['input']['options']['send'] = True default_speedtest['input']['options']['recv'] = False tcp_up = self.run_speedtest(default_speedtest).get('tcp_up') if not tcp_up: self.client.log('do_speedtest tcp_up results missing!') default_speedtest['input']['options']['send'] = True default_speedtest['input']['options']['recv'] = False results = self.run_speedtest(default_speedtest) tcp_up = results.get('tcp_up') or None if not tcp_down: self.client.log('do_speedtest tcp_down results missing!') default_speedtest['input']['options']['send'] = False default_speedtest['input']['options']['recv'] = True results = self.run_speedtest(default_speedtest) tcp_down = results.get('tcp_down') or None down = float(tcp_down.get('THROUGHPUT', 0.0)) if tcp_down else 0.0 up = float(tcp_up.get('THROUGHPUT', 0.0)) if tcp_up else 0.0 return down, up def test_sim(self, device): try: if self.modem_state(device, 'connected'): # Get diagnostics and log it diagnostics = self.client.get( f'{self.STATUS_DEVS_PATH}/{device}/diagnostics') self.sims[device]['diagnostics'] = diagnostics self.client.log( f'Modem Diagnostics: {self.port_sim(device)} RSRP:{diagnostics.get("RSRP")}' ) # Do speedtest and log results self.sims[device]['download'], self.sims[device][ 'upload'] = self.do_speedtest(self.sims[device]) self.client.log( f'Speedtest Results: {self.port_sim(device)} TCP Download: ' f'{self.sims[device]["download"]}Mbps TCP Upload: {self.sims[device]["upload"]}Mbps' ) # Verify minimum speeds if self.sims[device].get( 'download', 0.0) > self.MIN_DOWNLOAD_SPD and self.sims[device].get( 'upload', 0.0) > self.MIN_UPLOAD_SPD: return True else: # Did not meet minimums self.client.log( f'{self.port_sim(device)} Failed to meet minimums! MIN_DOWNLOAD_SPD: {self.MIN_DOWNLOAD_SPD} MIN_UPLOAD_SPD: {self.MIN_UPLOAD_SPD}' ) return False except Timeout: message = f'Timed out running speedtest on {self.port_sim(device)}' self.client.log(message) self.client.alert(message) self.sims[device]['download'] = self.sims[device]['upload'] = 0.0 return False def create_message(self, uid, *args): message = '' for arg in args: if arg == 'download': message = "DL:{:.2f}Mbps".format( self.sims[uid]['download']) if not message else ' '.join([ message, "DL:{:.2f}Mbps".format( self.sims[uid]['download']) ]) elif arg == 'upload': message = "UL:{:.2f}Mbps".format( self.sims[uid]['upload']) if not message else ' '.join([ message, "UL:{:.2f}Mbps".format( self.sims[uid]['upload']) ]) elif arg in ['PRD', 'HOMECARRID', 'RFBAND']: # Do not include labels for these fields message = "{}".format( self.sims[uid]['diagnostics'][arg] ) if not message else ' '.join( [message, "{}".format(self.sims[uid]['diagnostics'][arg])]) else: # Include field labels (e.g. "RSRP:-82") message = "{}:{}".format( arg, self.sims[uid]['diagnostics'] [arg]) if not message else ' '.join([ message, "{}:{}".format( arg, self.sims[uid]['diagnostics'][arg]) ]) return message def lock_sim(self, sim): rules = [{ "_id_": "00000000-1234-1234-1234-123456789000", "priority": 0, "trigger_name": f"{self.sims[sim]['info']['port']} {self.sims[sim]['info']['sim']}", "trigger_string": f"type|is|mdm%sim|is|{self.sims[sim]['info']['sim']}%port|is|{self.sims[sim]['info']['port']}" }] for i, uid in enumerate(self.sims): if uid != sim: rule = { "_id_": f"0000000{i+1}-1234-1234-1234-123456789000", "priority": -9 + i, "trigger_name": f"{self.sims[sim]['info']['port']} {self.sims[sim]['info']['sim']}", "trigger_string": f"type|is|mdm%sim|is|{self.sims[sim]['info']['sim']}%port|is|{self.sims[sim]['info']['port']}", "disabled": True } rules.append(rule) self.client.put('config/wan/rules2', rules) time.sleep(2) def create_rules(self, sim_list): wan_rules = [{ "_id_": "00000000-1234-1234-1234-1234567890ab", "priority": -10, "trigger_name": "Ethernet", "trigger_string": "type|is|ethernet" }] for i in range(0, len(sim_list)): rule = { "_id_": f"0000000{i+1}-1234-1234-1234-123456789000", "priority": -9 + i, "trigger_name": f"{self.sims[sim_list[i]]['info']['port']} {self.sims[sim_list[i]]['info']['sim']}", "trigger_string": f"type|is|mdm%sim|is|{self.sims[sim_list[i]]['info']['sim']}%port|is|{self.sims[sim_list[i]]['info']['port']}" } if self.NUM_ACTIVE_SIMS and i >= self.NUM_ACTIVE_SIMS: rule['disabled'] = True wan_rules.append(rule) req = self.client.put('config/wan/rules2/', wan_rules) time.sleep(2) if self.client.get('config/wan/rules2/0/_id_' ) == '00000000-1234-1234-1234-1234567890ab': self.client.log(f'Updated WAN rules') else: self.client.log(f'WAN Rules not updated! : {req}') return def run(self): # *** Main Application Starts Here *** self.client.log( f'Boot2 Starting... MIN_DOWNLOAD_SPD:{self.MIN_DOWNLOAD_SPD} MIN_UPLOAD_SPD:{self.MIN_UPLOAD_SPD} ' f'SCHEDULE:{self.SCHEDULE} NUM_ACTIVE_SIMS:{self.NUM_ACTIVE_SIMS} ONLY_RUN_ONCE:{self.ONLY_RUN_ONCE}' ) self.check_if_run_before() self.wait_for_ncm_sync() # Get info from router product_name = self.client.get("/status/product_info/product_name") system_id = self.client.get("/config/system/system_id") router_id = self.client.get('status/ecm/client_id') self.find_sims() # Find active SIM slots # Send startup alert message = f'Boot2 Starting! {system_id} - {product_name} - Router ID: {router_id}' self.client.log(f'Sending alert to NCM: {message}') self.client.alert(message) # Pause for 3 seconds to allow NCM Alert to be sent before suspending NCM time.sleep(3) self.NCM_suspend() success = False # Boot2 Success Status - Becomes True when a SIM meets minimum speeds # Test the connected SIM first primary_device = self.client.get('status/wan/primary_device') if 'mdm-' in primary_device: # make sure its a modem if self.test_sim(primary_device): success = True # test remaining SIMs for sim in self.sims: if not self.sims[sim].get('download'): self.lock_sim(sim) if self.test_sim(sim): success = True # Prioritizes SIMs based on download speed sorted_results = sorted(self.sims, key=lambda x: self.sims[x]['download'], reverse=True) # Create WAN rules self.create_rules(sorted_results) time.sleep(3) # Build text for custom1 field results_text = datetime.datetime.now().strftime( '%m/%d/%y %H:%M:%S') # Start with a timestamp if not success: results_text += f' FAILED TO MEET MINIMUMS! MIN_DOWNLOAD_SPD:{self.MIN_DOWNLOAD_SPD} MIN_UPLOAD_SPD:{self.MIN_UPLOAD_SPD}' for uid in sorted_results: # Add the results of each SIM with the fields specified: results_text = ' | '.join([ results_text, self.create_message(uid, 'PRD', 'HOMECARRID', 'RFBAND', 'RSRP', 'download', 'upload') ]) # put messages to NCM custom fields self.wait_for_ncm_sync() if apikeys.get('X-ECM-API-ID') != 'YOUR': self.client.log( f'X-ECM-API-ID: {apikeys["X-ECM-API-ID"]} X-CP-API-ID: {apikeys["X-CP-API-ID"]}' ) req = requests.put(f'{self.API_URL}/routers/{router_id}/', headers=apikeys, json={'custom1': results_text[:255]}) self.client.log(f'NCM PUT Custom1 Result: {req.status_code}') else: self.client.log( 'No NCM API Keys configured, skipping PUT to custom1') # Complete! Send results. message = f"Boot2 Complete! {system_id} Results: {results_text}" self.client.log(message) self.client.alert(message)
import time from csclient import EventingCSClient cp = EventingCSClient('ports-status') APP_NAME = 'PORTS_STATUS' DEBUG = False MODELS_WITHOUT_WAN = ['CBA', 'W18', 'W200', 'W400', 'L950', 'IBR200', '4250'] if DEBUG: cp.log("DEBUG ENABLED") if DEBUG: cp.log("Getting Model") """Get model number, since some models don't have ethernet WAN""" model = '' model = cp.get('/status/product_info/product_name') if DEBUG: cp.log(model) while True: try: ports_status = "" is_available_modem = 0 is_available_wan = 0 is_available_wwan = 0 is_configured_wwan = 0 wans = cp.get('/status/wan/devices') mdm_present = False for wan in wans: if 'mdm' in wan:
class DataUsageCheck(object): """ Establish global variables. Set rate shaping values (in Kbps) """ # Modem Defaults (as of 7.0.40) - Not used when QoS is Disabled maxbwup = 25000 maxbwdown = 25000 minbwup = 512 minbwdown = 512 capreached = 0 STATUS_DEVS_PATH = '/status/wan/devices' STATUS_DATACAP_PATH = '/status/wan/datacap' CFG_RULES2_PATH = '/config/wan/rules2' def __init__(self): self.cp = EventingCSClient(app_name) def find_modems(self): while True: devs = self.cp.get(self.STATUS_DEVS_PATH) modems_list = [x for x in devs if x.startswith('mdm-')] self.cp.log(f'modems_list: {modems_list}') num_modems = len(modems_list) if not num_modems: self.cp.log('No Modems found at all yet') time.sleep(10) continue else: return modems_list def find_modem_profiles(self): wan_ifcs = self.cp.get(self.CFG_RULES2_PATH) modem_profiles_list = [ x['_id_'] for x in wan_ifcs if x['trigger_string'].startswith('type|is|mdm') ] self.cp.log(f'modem_profiles_list: {modem_profiles_list}') return modem_profiles_list def reset_throttle(self, modem_profiles_list, monthlyreset): for mdm in modem_profiles_list: if monthlyreset: self.cp.delete(self.CFG_RULES2_PATH + '/' + mdm + '/bandwidth_egress') self.cp.delete(self.CFG_RULES2_PATH + '/' + mdm + '/bandwidth_ingress') else: if 'bandwidth_egress' in self.cp.get(self.CFG_RULES2_PATH + '/' + mdm): self.cp.delete(self.CFG_RULES2_PATH + '/' + mdm + '/bandwidth_egress') if 'bandwidth_ingress' in self.cp.get(self.CFG_RULES2_PATH + '/' + mdm): self.cp.delete(self.CFG_RULES2_PATH + '/' + mdm + '/bandwidth_ingress') self.cp.put('config/qos/enabled', False) if monthlyreset: self.cp.log( 'Monthly data usage reset - disabling reduced LTE data rate') message = ( f'Monthly data usage reset - disabling reduced LTE data rate ' f'for {self.system_id} - {self.product_name} - Router ID: ' f'{self.router_id}') self.cp.alert(message) self.capreached = 0 def set_throttle(self, modem_profiles_list): for mdm in modem_profiles_list: self.cp.put(self.CFG_RULES2_PATH + '/' + mdm + '/bandwidth_egress', self.minbwup) self.cp.put( self.CFG_RULES2_PATH + '/' + mdm + '/bandwidth_ingress', self.minbwdown) self.cp.put('config/qos/enabled', True) self.cp.log( 'Exceeded monthly data usage threshold - reducing LTE data rate') message = ( f'Exceeded monthly data usage threshold - reducing LTE data rate ' f'for {self.system_id} - {self.product_name} - Router ID: ' f'{self.router_id}') self.cp.alert(message) self.capreached = 1 def run(self): # Get info from router to populate description field in NCM # alert message self.product_name = self.cp.get('/status/product_info/product_name') self.system_id = self.cp.get('/config/system/system_id') self.router_id = self.cp.get('status/ecm/client_id') # Retrieve list of modems and their profiles modems_list = [str(x.split('-')[1]) for x in self.find_modems()] modem_profiles_list = self.find_modem_profiles() # Reset any throttling to account for router reboots. If a # data cap alert is still active during the monthly cycle, the # appropriate rate shaping will be re-applied monthlyreset = False self.reset_throttle(modem_profiles_list, monthlyreset) time.sleep(5) while True: if self.cp.get(self.STATUS_DATACAP_PATH + '/completed_alerts/'): alerts = self.cp.get(self.STATUS_DATACAP_PATH + '/completed_alerts/') limitreached = 0 for modem in modems_list: if [ x['rule_id'] for x in alerts if x['rule_id'] == modem + '-monthly' if 'email_alert' in x['alerts'] ]: limitreached += 1 if limitreached > 0 and self.capreached == 0: self.set_throttle(modem_profiles_list) elif limitreached == 0 and self.capreached == 1: monthlyreset = True self.reset_throttle(modem_profiles_list, monthlyreset) elif self.capreached == 1: monthlyreset = True self.reset_throttle(modem_profiles_list, monthlyreset) time.sleep(10)