def get_diagnostics_data(): """Gets diagnostics data on the SupaBRCK Includes: - temperature information - connected clients information :return: dict """ status = {} client_data = run_command(['connected_clients'], output=True) or '{}' try: _data = json.loads(client_data) status['clients'] = _data.get('clients', []) except ValueError as exc: LOG.error('Failed to load connected_clients: %r', exc) modem_temp = run_command(['querymodem', 'temp'], output=True) try: status['modem'] = dict(temperature=[float(modem_temp)]) except (ValueError, TypeError) as e: LOG.error('Failed to get modem temperature: %r', e) status['modem'] = dict(temperature=[STATE_UNKNOWN]) bat_temp = get_battery_temperature() # cpu temperatures sensors_temp = psutil.sensors_temperatures() or {} cpu_temps = [t.current for t in sensors_temp.get('coretemp', [])] status['cpu'] = dict(temperature=cpu_temps) status['battery'] = dict(temperature=[bat_temp]) return status
def get_software(): """Gets the versions of the installed software on the system. This includes packages, firmware and operating system versions. See the REST API documentation for payload schema. :return: dict """ os_version = run_command(['uname', '-s', '-r', '-v', '-o'], output=True) or STATE_UNKNOWN firmware_version = get_firmware_version() packages_text = run_command(['opkg', 'list-installed'], output=True) or '' package_data = dict( [p.split(' - ') for p in packages_text.splitlines() if p]) # we're only interested in a subset of packages package_list = [] for package_name in BRCK_PACKAGES: version = package_data.get(package_name) installed = version is not None package_list.append( dict(name=package_name, version=version, installed=installed)) return dict(os=os_version, firmware=firmware_version, packages=package_list)
def restart_modem(): """Restarts the current modem """ LOG.warn("Restarting modem") s0 = run_command(['querymodem', 'run', 'AT+CFUN=4']) s1 = run_command(['querymodem', 'run', 'AT+CFUN=6']) LOG.warn("Restart modem status|%r|%r", s0, s1)
def apply_wifi_configuration(config): """Applies wireless configuration to UCI. Also reloads wireless. :param dict config: :return: None """ if uci_get('mwan3.wwan.enabled') != '1': LOG.warn('Enabling wwan interface') uci_set('mwan3.wwan.enabled', '1') uci_commit('mwan3') base_bridge_path = 'wireless.wifibridge.{}' base_radio_path = 'wireless.radio1.{}' mode = config['mode'] if mode == MODE_STA: config['hidden'] = '1' for k,v in config.iteritems(): if v: uci_path = ( base_radio_path.format(k) if k in RADIO_CONFIGS else base_bridge_path.format(k) ) LOG.warn('configuring wireless [%s] | [%s]', uci_path, v) uci_set(uci_path, v) uci_commit('wireless') LOG.warn('Reloading Network') run_command(['wifi', 'reload'])
def get_battery_status(no_cache=False): """Gets the battery status of the BRCK device. Sample Response: { 'state': 'CHARGING', 'battery_level': 98 } :return: dict """ if no_cache: run_command(['check_battery']) state = read_file('/tmp/battery/status') or STATE_UNKNOWN battery_level = read_file('/tmp/battery/capacity') or 0 extended = read_file('/tmp/battery/status_ex') or '{}' try: battery_level = int(battery_level) extended = json.loads(extended) except ValueError: battery_level = 0 LOG.error('Failed to ready battery capacity | Returned: %s', battery_level) state = dict(state=state.upper(), battery_level=battery_level) state.update(extended) if 'charging current' in state: state['charging_current'] = state['charging current'] state.pop('charging current') if 'iadp' in state: state.pop('iadp') return state
def get_uci_state(option, command='show', as_dict=True): """Gets the uci state stored at `option` :param str option: the name of the uci option :param str command: the command to run on state (`show` or `get`) :param bool expand_options: whether the response should be expanded :return: dict|string """ cmd_list = ['uci', '-P'] cmd_list.append('/var/state') cmd_list.append(command) cmd_list.append(option) response = run_command(cmd_list, output=True) or '' if response is False: LOG.warn("No UCI state found at: %s", option) return {} if as_dict else False out = response if as_dict: out = dict() if not (response is False) and len(response): out.update( [l.replace("'", "").split('=') for l in response.splitlines()]) return out
def get_connection_status(): """Gets the connection status via 3g-wan interface :return bool: """ command = ['ping', '-c', '2', '-I', '3g-wan', '-W', '1', '8.8.8.8'] return run_command(command)
def get_modem_network_info(*args): """Gets network information. """ net_info = {} try: info_str = run_command(['querymodem', 'run', 'AT+XCELLINFO?'], output=True) if not info_str: info_str = run_command(['querymodem', 'run', 'AT+XCELLINFO?'], output=True) LOG.debug("XCELL_INFO INFO: %r", info_str) cell_data = info_str.split(',') _mode, cell_type, _mcc, mnc, lac, cell_id = cell_data[:6] net_info = dict( mnc=mnc, lac=int('0x{}'.format(lac), 16), cell_id=int('0x{}'.format(cell_id), 16), net_type=MOBILE_TECH_MAP.get(cell_type, 'Unknown') ) except Exception as e: LOG.error("Failed to load modem network information: %r", e) return net_info
def get_network_status(): """Gets the network state of the BRCK This is a summarized view of the connection state of the BRCK Sample Response: { "connected": true, "connection": { "connection_type": "WAN", "up_speed": 1000000, "down_speed": 1000000, "signal_strengh": 77 }, "connected_clients": 0 } :return: dict """ num_clients = 0 connected = False net_type = STATE_NO_CONNECTION chilli_list = run_command(['connected_clients', 'list'], output=True) if chilli_list: num_clients = (chilli_list.splitlines().__len__() - 1) net_order = get_uci_state('brck.network.order', command='get', as_dict=False) active_net = None if net_order: nets = [n.strip() for n in net_order.split(' ')] net_state = get_uci_state('network') for net in nets: conn_state = net_state.get('network.{}.connected'.format(net), '') == '1' if conn_state: active_net = net net_type = net.upper() if net in ['wan', 'wan2']: net_type = net_state.get('network.{}.proto'.format(net), STATE_UNKNOWN).upper() elif net == 'wwan': net_type = 'Wireless' break up, down = get_interface_speed(active_net) state = dict(connected=connected, connected_clients=num_clients, connection=dict( connection_type=net_type, up_speed=up, down_speed=down, signal_strength=get_signal_strength(net_type))) return state
def configure_ip(net_id, dhcp_enabled, net_info): """Configures ethernet IP configuration. Reloads the network. """ interface = CONNECTION_MAP.get(net_id) if dhcp_enabled: LOG.warn('Configuring interface [%s] proto to DHCP', interface) uci_set('network.{}.proto'.format(interface), 'dhcp') for static_key in ['ipaddr', 'netmask', 'gateway', 'dns']: uci_option = 'network.{}.{}'.format(interface, static_key) LOG.warn('Deleting UCI option:[%s]', uci_option) uci_delete(uci_option) else: net_info['proto'] = 'static' for k, v in net_info.iteritems(): if v: uci_option = 'network.{}.{}'.format(interface, k) LOG.warn('Configuring network: [%s = %s]', uci_option, v) uci_set(uci_option, v) uci_commit('network.{}'.format(interface)) run_command(['iptables', '--flush']) run_command(['/etc/init.d/network', 'reload']) run_command(['iptables', '--flush']) LOG.warn( 'Sleeping for five (5) seconds to see if interface connection comes up.' ) time.sleep(NETWORK_CONFIG_WAIT_TIME) return (200, 'OK')
def get_signal_strength(net_type): """Get wireless signal strength (Mobile) :return: int (percentage 0-100) """ if net_type == 'wan': signal_strength = 0 model_id = run_command(['querymodem', 'model_id'], output=True) resp = run_command(['querymodem', 'signal'], output=True) try: rssi = int(resp or '') if model_id == 'MU736' or not model_id: if (rssi >= 0 and rssi <= 31): signal_strength = (rssi * 827 + 127) >> 8 else: signal_strength = 0 if (rssi == 255) else rssi except ValueError: LOG.error( "Failed to load signal strength: QueryModem Response: %s", resp) else: signal_strength = 100 return signal_strength
def get_modems(): """Gets active modem set :return: (bool, bool) """ m1 = False m2 = False _path = '/sys/class/tty' _paths_str = run_command(['ls', '-l', _path], output=True) _paths = _paths_str.splitlines() matches1 = [p for p in _paths if MODEM1_PATTERN.match(p)] matches2 = [p for p in _paths if MODEM2_PATTERN.match(p)] if len(matches1) == 4: m1 = True if len(matches2) == 4: m2 = True return (m1, m2)
def get_wan_connections(sim_id=None): """Returns list of SIM connections Sample Reponse: [ { "id": "SIM1", "name": "SIM 1", "connection_type": "SIM", "connection_available": true, "connected": true, "info": { "pin_locked": true, "puk_locked": false, "apn_configured": true, "network_info": { "operator": "Operator Name", "imei": 350089999084990, "cell_id": 300300, "lac": 300, "mnc": 304, "mcc": 639, "network_type": "2G" } } } ] :return: list(dict) """ conns = [] conn_paths = SIM_STATUS_FILES if sim_id is not None: sim_id_num = int(sim_id[-1]) if sim_id_num in [1, 2, 3]: conn_paths = [SIM_STATUS_FILES[sim_id_num - 1]] net_connected = get_connection_status() active_sim = uci_get('brck.active_sim') sim_statuses = [read_file(p) for p in conn_paths] # when only one SIM is available - assume that's the active SIM active_sims = len([s for s in sim_statuses if s == '1']) for (i, sim_status) in enumerate(sim_statuses): key = i + 1 c_id = 'SIM%d' %(key) name = 'SIM %d' % (key) available = False connected = False if sim_status != False and sim_status == '1': available = True info = {} if available: sim_state = get_sim_state(key) info['apn_configured'] = sim_state.get('apn', '') != '' is_active_sim = (active_sims == 1 and net_connected) or (str(key) == active_sim) if is_active_sim and (not net_connected): sim_status = run_command(['querymodem', 'check_pin'], output=True) or '' if REG_PIN_LOCK.match(sim_status): info['pin_locked'] = True else: info['pin_locked'] = False if REG_PUK_LOCK.match(sim_status): info['puk_locked'] = True else: info['puk_locked'] = False elif is_active_sim: info['pin_locked'] = False info['puk_locked'] = False if net_connected: ex_net_info = {} connected = True signal_strength = get_signal_strength('wan') operator = run_command(['querymodem', 'carrier'], output=True) imei = run_command(['querymodem', 'imei'], output=True) imsi = run_command(['querymodem', 'imsi'], output=True) if REG_ERROR.match(operator) or operator == "0": operator = 'Unknown' connected = False else: ex_net_info['imei'] = imei ex_net_info['imsi'] = imsi ex_net_info['mcc'] = imsi[:3] ex_net_info.update(get_modem_network_info(imsi, imei)) ex_net_info.update(dict( operator=operator, signal_strength=signal_strength )) info['network_info'] = ex_net_info c_data = dict( id=c_id, name=name, available=available, connected=connected, info=info ) conns.append(c_data) return conns
def start_service(name): run_command(['/etc/init.d/{}'.format(name), 'start'])
def disable_pin(pin): """Disable PIN """ s0 = run_command(['querymodem', 'run', "AT+CLCK=SC,0,{}".format(pin)]) LOG.warn("Disable PIN status|%r", s0)
def connect_sim_actual(sim_id, modem_id, previous_sim): """Connects to the selected SIM in interactive fashion. This method pushes all events to a websocket topic for consumption. :param int sim_id: SIM ID (1 or 2 or 3) :param int modem_Id: Modem ID (1 or 2) """ from local_api import socketio as io, NS_SIM_CONNECTIVITY as ns try: if is_service_running(THREEG_MONITOR_SERVICE): LOG.warn("Stopping 3g-monitor") disable_service(THREEG_MONITOR_SERVICE) stop_service(THREEG_MONITOR_SERVICE) emit_event(io, DISABLE_3G_MONITOR, ns) else: LOG.warn("3g-monitor is already stopped") flags = SIM_FLAGS.get('%d-%d' % (modem_id, sim_id)) if flags: LOG.warn("Bringing down WAN") run_command(['ifdown', 'wan']) emit_event(io, STOP_WAN, ns) emit_event(io, SELECT_SIM, ns) for (key, flag) in enumerate(flags): port_path = SIM_CONFIG_PATHS[key] run_call(port_path, flag) for modem_flag_path in MODEM_FLAG_PATHS: run_call(modem_flag_path, '0') eventlet.sleep(1) run_call(modem_flag_path, '1') eventlet.sleep(5) emit_event(io, CHECK_SIM, ns) check_imei_status = run_command(['querymodem', 'imei'], output=True) LOG.warn("SIM|IMEI STATUS|%s", check_imei_status) requires_input = False if not REG_ERROR.match(check_imei_status): emit_event(io, SIM_DETECTED, ns) emit_event(io, CHECK_PIN, ns) pin_status = run_command(['querymodem', 'check_pin'], output=True) if not pin_status: eventlet.sleep(2) pin_status = run_command(['querymodem', 'check_pin'], output=True) LOG.warn("SIM|PIN STATUS|%s", pin_status) puk_path = 'brck.sim{}.puk'.format(sim_id) pin_path = 'brck.sim{}.pin'.format(sim_id) ready = False if REG_PUK.match(pin_status): puk = uci_get(puk_path) pin = uci_get(pin_path) if puk: emit_event(io, SET_PUK, ns) pin = pin or DEFAULT_PIN set_puk_status = run_command([ 'querymodem', 'run', 'AT+CPIN={},{}'.format( puk, pin) ], output=True) LOG.warn("SIM|SET PUK STATUS|%s", set_puk_status) if REG_OK.match(set_puk_status): emit_event(io, DISABLE_PIN, ns) disable_pin(pin) eventlet.sleep(3) emit_event(io, PUK_OK, ns) emit_event(io, CHECK_READY, ns) eventlet.sleep(5) check_sim_ready_status = run_command( ['querymodem', 'check_pin'], output=True) if REG_READY.match(check_sim_ready_status): emit_event(io, SIM_READY, ns) ready = True else: emit_event(io, DELETE_PUK, ns) uci_delete(puk_path) uci_commit('brck') emit_event(io, SIM_NOT_READY, ns) else: emit_event(io, PUK_REJECTED, ns) emit_event(io, DELETE_PUK, ns) uci_delete(puk_path) uci_commit('brck') emit_event(io, REQUIRES_PUK, ns) requires_input = True else: emit_event(io, REQUIRES_PUK, ns) requires_input = True elif REG_PIN.match(pin_status): pin = uci_get(pin_path) if pin: emit_event(io, SET_PIN, ns) set_pin_status = run_command( ['querymodem', 'run', 'AT+CPIN={}'.format(pin)], output=True) LOG.warn("SIM|SET PIN STATUS|%s", set_pin_status) eventlet.sleep(5) sim_status = run_command(['querymodem', 'check_pin'], output=True) if REG_OK.match(set_pin_status) or REG_READY.match( sim_status): emit_event(io, PIN_OK, ns) emit_event(io, DISABLE_PIN, ns) disable_pin(pin) emit_event(io, CHECK_READY, ns) eventlet.sleep(5) check_sim_ready_status = run_command( ['querymodem', 'check_pin'], output=True) if REG_READY.match(check_sim_ready_status): emit_event(io, SIM_READY, ns) ready = True else: emit_event(io, DELETE_PIN, ns) uci_delete(pin_path) uci_commit('brck') emit_event(io, SIM_NOT_READY, ns) else: emit_event(io, PIN_REJECTED, ns) emit_event(io, DELETE_PIN, ns) uci_delete(pin_path) uci_commit('brck') emit_event(io, REQUIRES_PIN, ns) requires_input = True else: emit_event(io, REQUIRES_PIN, ns) requires_input = True elif REG_READY.match(pin_status): emit_event(io, PIN_NOT_REQUIRED, ns) ready = True else: emit_event(io, SIM_NOT_READY, ns) restore_sim(previous_sim) emit_event(io, ACTIVE_SIM_RESET, ns) if ready: if uci_get('network.wan.apn'): emit_event(io, WAIT_CARRIER, ns) eventlet.sleep(10) emit_event(io, CHECK_CARRIER, ns) carrier_resp = run_command(['querymodem', 'carrier'], output=True) LOG.warn("SIM|CHECK CARRIER STATUS|%s", carrier_resp) if REG_ERROR.match( carrier_resp) or carrier_resp == "0": emit_event(io, NO_CARRIER, ns) # emit_event(io, RESTART_MODEM, ns) # restart_modem() # eventlet.sleep(10) else: emit_event(io, CARRIER_DETECTED, ns) emit_event(io, START_WAN, ns) LOG.warn("Bringing up WAN") run_command(['ifup', 'wan']) emit_event(io, WAIT_CONNECTION, ns) _connected = False for _ in xrange(6): _connected = get_connection_status() if _connected: emit_event(io, CONNECTED, ns) break else: eventlet.sleep(10) if not _connected: emit_event(io, NO_CONNECTION, ns) else: emit_event(io, REQUIRES_APN, ns) requires_input = True else: emit_event(io, SIM_NOT_READY, ns) else: LOG.error('No such modem configuration exists: SIM: %d MODEM: %d', sim_id, modem_id) emit_event(io, NO_MODEM, ns) if not requires_input: LOG.warn("Bringing up WAN") run_command(['ifup', 'wan']) emit_event(io, ENABLE_3G_MONITOR, ns) LOG.warn('Enabling 3G Monitor') enable_service(THREEG_MONITOR_SERVICE) start_service(THREEG_MONITOR_SERVICE) except Exception as e: restore_sim(previous_sim) LOG.error("Failed to connect with SIM CARD|%d|%r", sim_id, e) emit_event(io, ACTIVE_SIM_RESET, ns) restore_sim(previous_sim) emit_event(io, NO_CONNECTION, ns) run_command(['ifup', 'wan']) emit_event(io, ENABLE_3G_MONITOR, ns) LOG.warn('Enabling 3G Monitor') enable_service(THREEG_MONITOR_SERVICE) start_service(THREEG_MONITOR_SERVICE)
def disable_service(name): run_command(['/etc/init.d/{}'.format(name), 'disable'])