def test_get_fleet(): """Make sure we can get fleets.""" auth_payload = { 'jwt': 'big-token', 'username': '******' } test_payload = {"count":1, "next":"Null", "previous":"Null", "results":[{"device":"d--0000-0000-0000-0001","always_on":True,"is_access_point":False}]} expected = { "d--0000-0000-0000-0001":{ "always_on":True, "is_access_point":False} } manager = ConfigManager() with requests_mock.Mocker() as mocker: mocker.post('https://iotile.cloud/api/v1/auth/login/', json=auth_payload) link_cloud(manager, '*****@*****.**', 'password') cloud = IOTileCloud() mocker.get('https://iotile.cloud/api/v1/fleet/g--0000-0000-0001/devices/', json=test_payload) mocker.get('https://iotile.cloud/api/v1/fleet/g--0000-0000-0002/devices/', status_code=404) assert cloud.get_fleet(1) == expected with pytest.raises(ArgumentError): cloud.get_fleet(2) with pytest.raises(ArgumentError): cloud.get_fleet(pow(16,12) + 1)
def test_alternative_domains(registry): """Make sure we can specify an alternative domain.""" payload = { 'jwt': 'big-token', 'username': '******' } manager = ConfigManager() manager.set('cloud:server', 'https://testcloud.com') with requests_mock.Mocker() as mocker: mocker.post('https://testcloud.com/api/v1/auth/login/', json=payload) link_cloud(manager, '*****@*****.**', 'password') assert registry.get_config('arch:cloud_user') == 'user1' assert registry.get_config('arch:cloud_token') == 'big-token' cloud = IOTileCloud() payload = { 'token': 'new-token' } with requests_mock.Mocker() as mocker: mocker.post('https://testcloud.com/api/v1/auth/api-jwt-refresh/', json=payload) cloud.refresh_token() assert registry.get_config('arch:cloud_token') == 'new-token'
def __init__(self, domain=None, username=None, **kwargs): reg = ComponentRegistry() conf = ConfigManager() if domain is None: domain = conf.get('cloud:server') self.api = Api(domain=domain, **kwargs) self._domain = self.api.domain try: token = reg.get_config('arch:cloud_token') token_type = reg.get_config('arch:cloud_token_type', default='jwt') self.api.set_token(token, token_type=token_type) except ArgumentError: # If we are interactive, try to get the user to login for a single # session rather than making them call link_cloud to store a cloud token if type_system.interactive: username, password = self._prompt_user_pass(username, domain) ok_resp = self.api.login(email=username, password=password) if not ok_resp: raise ExternalError("Could not login to %s as user %s" % (domain, username)) else: raise ExternalError( "No stored iotile cloud authentication information", suggestion= 'Call iotile config link_cloud with your username and password' ) self.token = self.api.token self.token_type = self.api.token_type
def refresh_token(self): """Attempt to refresh out cloud token with iotile.cloud.""" if self.token_type != 'jwt': raise DataError( "Attempting to refresh a token that does not need to be refreshed", token_type=self.token_type) conf = ConfigManager() domain = conf.get('cloud:server') url = '{}/api/v1/auth/api-jwt-refresh/'.format(domain) resp = self.api.session.post(url, json={'token': self.token}) if resp.status_code != 200: raise ExternalError("Could not refresh token", error_code=resp.status_code) data = resp.json() # Save token that we just refreshed to the registry and update our own token self.token = data['token'] reg = ComponentRegistry() reg.set_config('arch:cloud_token', self.token)
def test_getting_and_setting(): """Test setting and getting variables with correct types """ man = ConfigManager() man.add_variable('test:var', 'bool', 'test variable', 'false') val = man.get('test:var') assert val is False man.set('test:var', 'true') assert man.get('test:var') is True # Make sure we can get and set without a default value man.add_variable('test:var2', 'bool', 'test variable') with pytest.raises(ArgumentError): man.get('test:var2') man.set('test:var2', 'True') assert man.get('test:var2') is True man.set('test:var2', 'False') assert man.get('test:var2') is False # Make sure removing a variable works man.remove('test:var2') with pytest.raises(ArgumentError): man.get('test:var2') man.remove('test:var') assert man.get('test:var') is False
def __init__(self, port, on_scan=None, on_disconnect=None, passive=None, **kwargs): super(BLED112Adapter, self).__init__() # Get optional configuration flags stop_check_interval = kwargs.get('stop_check_interval', 0.1) #Make sure that if someone tries to connect to a device immediately after creating the adapter #we tell them we need time to accumulate device advertising packets first self.set_config('minimum_scan_time', 2.0) if on_scan is not None: self.add_callback('on_scan', on_scan) if on_disconnect is not None: self.add_callback('on_disconnect', on_disconnect) if port is None or port == '<auto>': devices = self.find_bled112_devices() if len(devices) > 0: port = devices[0] else: raise ValueError("Could not find any BLED112 adapters connected to this computer") self.scanning = False self.stopped = False if passive is not None: self._active_scan = not passive else: config = ConfigManager() self._active_scan = config.get('bled112:active-scan') #Prepare internal state of scannable and in progress devices # Do this before spinning off the BLED112CommandProcessor # in case a scanned device is seen immediately. self.partial_scan_responses = {} self._connections = {} self.count_lock = threading.Lock() self.connecting_count = 0 self.maximum_connections = 0 self._logger = logging.getLogger(__name__) self._logger.addHandler(logging.NullHandler()) self._serial_port = serial.Serial(port, 256000, timeout=0.01, rtscts=True) self._stream = AsyncPacketBuffer(self._serial_port, header_length=4, length_function=packet_length) self._commands = Queue() self._command_task = BLED112CommandProcessor(self._stream, self._commands, stop_check_interval=stop_check_interval) self._command_task.event_handler = self._handle_event self._command_task.start() try: self.initialize_system_sync() self.start_scan(self._active_scan) except: self.stop_sync() raise
def test_format_nodefault(): """Test formatting of config variable without a default value """ man = ConfigManager() man.add_variable('test:var', 'bool', 'test variable') desc = man.describe('test:var') assert desc == 'test:var (bool): test variable [no default]'
def test_format_default(): """Test formatting of config variable defaults """ man = ConfigManager() man.add_variable('test:var', 'bool', 'test variable', 'false') desc = man.describe('test:var') assert desc == 'test:var (bool): test variable [default: false]'
def setup_environment(chip): """ Setup the SCons environment for compiling arm cortex code """ config = ConfigManager() #Make sure we never get MSVC settings for windows since that has the wrong command line flags for gcc if platform.system() == 'Windows': env = Environment(tools=['mingw'], ENV=os.environ) else: env = Environment(tools=['default'], ENV=os.environ) env['INCPREFIX'] = '-I"' env['INCSUFFIX'] = '"' env['CPPPATH'] = chip.includes() env['ARCH'] = chip #Setup Cross Compiler env['CC'] = 'arm-none-eabi-gcc' env['AS'] = 'arm-none-eabi-gcc' env['LINK'] = 'arm-none-eabi-gcc' env['AR'] = 'arm-none-eabi-ar' env['RANLIB'] = 'arm-none-eabi-ranlib' #AS command line is by default setup for call as directly so we need to modify it to call via *-gcc to allow for preprocessing env['ASCOM'] = "$AS $ASFLAGS -o $TARGET -c $SOURCES" # Setup nice display strings unless we're asked to show raw commands if not config.get('build:show-commands'): env['CCCOMSTR'] = "Compiling $TARGET" env['ARCOMSTR'] = "Building static library $TARGET" env['RANLIBCOMSTR'] = "Indexing static library $TARGET" env['LINKCOMSTR'] = "Linking $TARGET" #Setup Compiler Flags env['CCFLAGS'] = chip.combined_properties('cflags') env['LINKFLAGS'] = chip.combined_properties('ldflags') env['ARFLAGS'].append(chip.combined_properties( 'arflags')) #There are default ARFLAGS that are necessary to keep env['ASFLAGS'].append(chip.combined_properties('asflags')) #Add in compile tile definitions defines = utilities.build_defines(chip.property('defines', {})) env['CCFLAGS'].append(defines) #Setup Target Architecture env['CCFLAGS'].append('-mcpu=%s' % chip.property('cpu')) env['ASFLAGS'].append('-mcpu=%s' % chip.property('cpu')) env['LINKFLAGS'].append('-mcpu=%s' % chip.property('cpu')) #Initialize library paths (all libraries are added via dependencies) env['LIBPATH'] = [] env['LIBS'] = [] return env
def test_list_vars(): """Test listing variables using a glob """ man = ConfigManager() man.add_variable('test:var', 'bool', 'test variable', 'false') man.add_variable('test:var2', 'bool', 'test variable', 'false') man.add_variable('test2:var', 'bool', 'test variable', 'false') man.add_variable('test:hello', 'string', 'test variable', 'false') # Note that other plugins may register config vars here assert len(man.list("*")) >= 4 assert len(man.list('test:*')) == 3 assert len(man.list('test:var*')) == 2 assert len(man.list('test:hello')) == 1
def test_login(registry): """Make sure successful login is properly handled.""" payload = { 'jwt': 'big-token', 'username': '******' } manager = ConfigManager() with requests_mock.Mocker() as mocker: mocker.post('https://iotile.cloud/api/v1/auth/login/', json=payload) link_cloud(manager, '*****@*****.**', 'password') assert registry.get_config('arch:cloud_user') == 'user1' assert registry.get_config('arch:cloud_token') == 'big-token'
def test_setting_config_function(): """Test adding a config function to ConfigManager """ man = ConfigManager() def conf_function(self, arg1): if arg1 == 5: raise ArgumentError("test") return arg1 with pytest.raises(AttributeError): man.test_conf(5) man.add_function('test_conf', conf_function) with pytest.raises(ArgumentError): man.test_conf(5) assert man.test_conf(3) == 3
def test_check_time(): """ Make sure we can check if the time is correct""" json_true = {'now': datetime.datetime.now(tzutc()).strftime('%a, %d %b %Y %X %Z')} json_false = {'now': 'Wed, 01 Sep 2010 17:30:32 GMT'} payload = { 'jwt': 'big-token', 'username': '******' } manager = ConfigManager() with requests_mock.Mocker() as mocker: mocker.post('https://iotile.cloud/api/v1/auth/login/', json=payload) link_cloud(manager, '*****@*****.**', 'password') cloud = IOTileCloud() mocker.get('https://iotile.cloud/api/v1/server/', json=json_true) assert cloud.check_time() == True mocker.get('https://iotile.cloud/api/v1/server/', json=json_false) assert cloud.check_time() == False
def __init__(self, port=None, record=None, adapter=None): if port is None and adapter is None: try: conf = ConfigManager() port = conf.get('core:default-port') except ArgumentError: raise ArgumentError( "No port given and no core:default-port config variable set", suggestion= "Specify the port to use to connect to the IOTile devices") elif port is None: port = "" transport, _, arg = port.partition(':') self.transport = transport self.port = None if arg != "": self.port = arg self._record = record self.stream = self._create_stream(adapter) self._stream_queue = None self._trace_queue = None self._broadcast_queue = None self._trace_data = bytearray() self._proxies = {'TileBusProxyObject': TileBusProxyObject} self._name_map = { TileBusProxyObject.ModuleName(): [TileBusProxyObject] } self._known_apps = {} self._named_apps = {} self._setup_proxies() self._setup_apps()
def test_get_whitelist(): """ Make sure we can retrieve the whitelist correctly """ with open('test/large_mock_answer.json') as lma: j = json.load(lma) test_payload = j['whitelist_test'] p1 = j['whitelist_g1'] p2 = j['whitelist_g2'] p3 = j['whitelist_g3'] expected = j['expected'] empty_whitelist_test = j['empty_whitelist_test'] p4 = j['whitelist_g4'] payload = { 'jwt': 'big-token', 'username': '******' } manager = ConfigManager() with requests_mock.Mocker() as mocker: mocker.post('https://iotile.cloud/api/v1/auth/login/', json=payload) link_cloud(manager, '*****@*****.**', 'password') cloud = IOTileCloud() mocker.get('https://iotile.cloud/api/v1/fleet/?device=d--0000-0000-0000-0001', status_code=404) with pytest.raises(ExternalError): cloud.get_whitelist(1) mocker.get('https://iotile.cloud/api/v1/fleet/?device=d--0000-0000-0000-0002', json={'results':[]}) with pytest.raises(ExternalError): cloud.get_whitelist(2) mocker.get('https://iotile.cloud/api/v1/fleet/?device=d--0000-0000-0000-01bd', json=test_payload) mocker.get('https://iotile.cloud/api/v1/fleet/g--0000-0000-0001/devices/', json=p1) mocker.get('https://iotile.cloud/api/v1/fleet/g--0000-0000-0002/devices/', json=p2) mocker.get('https://iotile.cloud/api/v1/fleet/g--0000-0000-0003/devices/', json=p3) assert cloud.get_whitelist(0x1bd) == expected mocker.get('https://iotile.cloud/api/v1/fleet/?device=d--0000-0000-0000-01bd', json=empty_whitelist_test) mocker.get('https://iotile.cloud/api/v1/fleet/g--0000-0000-0004/devices/', json=p4) with pytest.raises(ExternalError): cloud.get_whitelist(0x1bd)
def __init__(self, port, on_scan=None, on_disconnect=None, active_scan=None, **kwargs): super(NativeBLEDeviceAdapter, self).__init__() # Create logger self._logger = logging.getLogger(__name__) self._logger.addHandler(logging.NullHandler()) # Register configuration self.set_config( 'minimum_scan_time', 2.0) # Time to accumulate device advertising packets first self.set_config('default_timeout', 10.0) # Time before timeout an operation self.set_config('expiration_time', 60.0) # Time before a scanned device expired self.set_config( 'maximum_connections', 3) # Maximum number of simultaneous connections per controller # Create the baBLE interface to interact with BLE controllers self.bable = bable_interface.BaBLEInterface() # Get the list of BLE controllers self.bable.start(on_error=self._on_ble_error) controllers = self._find_ble_controllers() self.bable.stop() if len(controllers) == 0: raise ExternalError( "Could not find any BLE controller connected to this computer") # Parse port and check if it exists if port is None or port == '<auto>': self.controller_id = controllers[0].id else: self.controller_id = int(port) if not any(controller.id == self.controller_id for controller in controllers): raise ExternalError( "Could not find a BLE controller with the given ID, controller_id=%s" .format(self.controller_id)) # Restart baBLE with the selected controller id to prevent conflicts if multiple controllers self.bable.start(on_error=self._on_ble_error, exit_on_sigint=False, controller_id=self.controller_id) # Register callbacks if on_scan is not None: self.add_callback('on_scan', on_scan) if on_disconnect is not None: self.add_callback('on_disconnect', on_disconnect) self.scanning = False self.stopped = False if active_scan is not None: self._active_scan = active_scan else: config = ConfigManager() self._active_scan = config.get('ble:active-scan') # To register advertising packets waiting for a scan response (only if active scan) self.partial_scan_responses = {} # To manage multiple connections self.connections = ConnectionManager(self.id) self.connections.start() # Notification callbacks self.notification_callbacks_lock = threading.Lock() self.notification_callbacks = {} try: self._initialize_system_sync() self.start_scan(active=self._active_scan) except Exception: self.stop_sync() raise
def setup_environment(chip, args_file=None): """Setup the SCons environment for compiling arm cortex code. This will return an env that has all of the correct settings and create a command line arguments file for GCC that contains all of the required flags. The use of a command line argument file passed with @./file_path is important since there can be many flags that exceed the maximum allowed length of a command line on Windows. """ config = ConfigManager() # Make sure we never get MSVC settings for windows since that has the wrong command line flags for gcc if platform.system() == 'Windows': env = Environment(tools=['mingw'], ENV=os.environ) else: env = Environment(tools=['default'], ENV=os.environ) env['INCPREFIX'] = '-I"' env['INCSUFFIX'] = '"' env['CPPDEFPREFIX'] = '' env['CPPDEFSUFFIX'] = '' env['CPPPATH'] = chip.includes() env['ARCH'] = chip # Setup Cross Compiler env['CC'] = 'arm-none-eabi-gcc' env['AS'] = 'arm-none-eabi-gcc' env['LINK'] = 'arm-none-eabi-gcc' env['AR'] = 'arm-none-eabi-ar' env['RANLIB'] = 'arm-none-eabi-ranlib' # AS command line is by default setup for call as directly so we need # to modify it to call via *-gcc to allow for preprocessing env['ASCOM'] = "$AS $ASFLAGS -o $TARGET -c $SOURCES" # Setup nice display strings unless we're asked to show raw commands if not config.get('build:show-commands'): env['CCCOMSTR'] = "Compiling $TARGET" env['ARCOMSTR'] = "Building static library $TARGET" env['RANLIBCOMSTR'] = "Indexing static library $TARGET" env['LINKCOMSTR'] = "Linking $TARGET" # Setup Compiler Flags env['CCFLAGS'] = chip.combined_properties('cflags') env['LINKFLAGS'] = chip.combined_properties('ldflags') env['ARFLAGS'].append(chip.combined_properties( 'arflags')) # There are default ARFLAGS that are necessary to keep env['ASFLAGS'].append(chip.combined_properties('asflags')) # Add in compile tile definitions defines = utilities.build_defines(chip.property('defines', {})) env['CPPDEFINES'] = defines if args_file is not None: env['CCCOM'] = "$CC $CCFLAGS $CPPFLAGS @{} -c -o $TARGET $SOURCES".format( args_file) # Setup Target Architecture env['CCFLAGS'].append('-mcpu=%s' % chip.property('cpu')) env['ASFLAGS'].append('-mcpu=%s' % chip.property('cpu')) env['LINKFLAGS'].append('-mcpu=%s' % chip.property('cpu')) # Initialize library paths (all libraries are added via dependencies) env['LIBPATH'] = [] env['LIBS'] = [] return env
def watch_broadcasts(self, whitelist=None, blacklist=None): """Spawn an interactive terminal UI to watch broadcast data from devices. Devices are allowed to post a broadcast report containing stream data. This function will create a list in your console window with the latest broadcast value from each device in range. Args: whitelist (list(integer)): Only include devices with these listed ids. blacklist (list(integer)): Include every device **except** those with these specific ids. If combined with whitelist, whitelist wins and this parameter has no effect. """ title = "Watching Broadcast Reports (Ctrl-C to Stop)" subtitle = "" if self.transport == 'bled112': reg = ConfigManager() if not reg.get('bled112:active-scan'): subtitle = "Active Scanning not active, you won't see v1 broadcasts" if whitelist is not None: whitelist = set(whitelist) if blacklist is not None: blacklist = set(blacklist) def _title(_items): return [title, subtitle] def _poll(): results = [x for x in self.iter_broadcast_reports(blocking=False)] return results def _text(item): fmt_uuid = "%08X" % item.origin fmt_uuid = fmt_uuid[:4] + '-' + fmt_uuid[4:] reading = item.visible_readings[0] return "{0: <15} stream: {1: 04X} value: {2: <8}".format( fmt_uuid, reading.stream, reading.value) def _sort_order(item): return item.origin def _hash(item): uuid = item.origin stream_id = item.visible_readings[0].stream if whitelist is not None and uuid not in whitelist: return None if blacklist is not None and whitelist is None and uuid in blacklist: return None item_id = str(uuid) + "," + str(stream_id) return item_id line_ui = LinebufferUI(_poll, _hash, _text, sortkey_func=_sort_order, title=_title) line_ui.run()
def __init__(self, port, on_scan=None, on_disconnect=None, passive=None, **kwargs): super(BLED112Adapter, self).__init__() # Get optional configuration flags stop_check_interval = kwargs.get('stop_check_interval', 0.1) # Make sure that if someone tries to connect to a device immediately after creating the adapter # we tell them we need time to accumulate device advertising packets first self.set_config('minimum_scan_time', 2.0) if on_scan is not None: self.add_callback('on_scan', on_scan) if on_disconnect is not None: self.add_callback('on_disconnect', on_disconnect) self.scanning = False self.stopped = False config = ConfigManager() if passive is not None: self._active_scan = not passive else: self._active_scan = config.get('bled112:active-scan') self._throttle_broadcast = config.get('bled112:throttle-broadcast') self._throttle_scans = config.get('bled112:throttle-scan') self._throttle_timeout = config.get('bled112:throttle-timeout') # Prepare internal state of scannable and in progress devices # Do this before spinning off the BLED112CommandProcessor # in case a scanned device is seen immediately. self.partial_scan_responses = {} self._broadcast_state = {} self._connections = {} self.count_lock = threading.Lock() self.connecting_count = 0 self.maximum_connections = 0 self._scan_event_count = 0 self._v1_scan_count = 0 self._v1_scan_response_count = 0 self._v2_scan_count = 0 self._device_scan_counts = {} self._last_reset_time = time.monotonic() self._logger = logging.getLogger(__name__) self._logger.addHandler(logging.NullHandler()) self._serial_port = open_bled112(port, self._logger) self._stream = AsyncPacketBuffer(self._serial_port, header_length=4, length_function=packet_length) self._commands = Queue() self._command_task = BLED112CommandProcessor(self._stream, self._commands, stop_check_interval=stop_check_interval) self._command_task.event_handler = self._handle_event self._command_task.start() try: self.initialize_system_sync() self.start_scan(self._active_scan) except: self.stop_sync() raise