def _get_stream_inlet(lsl_predicate): """Return the stream that fits the given predicate. Raise ValueError if multiple streams or zero streams match the predicate. Parameters ---------- lsl_predicate : str Predicate used to find LabStreamingLayer stream. See `default_predicates.py` for more info. Returns ------- inlet : pylsl.StreamInlet The LSL stream that matches the given predicate. """ stream = resolve_bypred(lsl_predicate) # Times out after ~ 1 year. if len(stream) == 1: inlet = StreamInlet(stream[0]) logger.info("Connected to stream.") else: msg = ("Multiple streams match the given predicate. Only one " "stream must match the predicate.") logger.error(msg) raise ValueError(msg) return inlet
def _resolve(self): """ Search for available EEG streams on LSL and connect to them by saving them as Stream objects """ # resolve EEG streams and retrieve their information streams_info = resolve_bypred("type='EEG'", 0, 2.5) streams_active = [] self.logger.debug("Found {} available streams".format( len(streams_info))) # iterate for each stream for stream_info in streams_info: # uid = stream_info.source_id() if stream_info.source_id() else stream_info.uid() # retrieve 'source_id' uid = stream_info.source_id() + ' | ' + stream_info.uid() streams_active.append(uid) # if the current stream has not been saved, then connect to the current stream if uid not in self.streams_by_uid: if self._validate_stream_signature(stream_info): self._connect_to(uid, stream_info) # if the current stream is already saved, but is not running, then disconnect if uid in self.streams_by_uid: if self.streams_by_uid[uid].running == False: self._disconnect_from({uid}) self._disconnect_from( list(set(self.streams_by_uid.keys()) - set(streams_active)))
def sub_live_streams(data: List[Dict[str, Union[str, dict]]], queue: asyncio.Queue): # source = <source_id> | type = <desc/stream/name> stream_query: List[Tuple[str, str, dict]] = [( str(d.get('source', '')), str(d.get('stream', {}).get('name', {})), dict(d.get('attributes', {})) ) for d in data] pred_str = RelayMode.gen_pred_str(stream_query) logger.debug('predicate: %s', pred_str) # count of queries and tasks num_queries = len(stream_query) num_tasks = 0 # run one query to get a superset of the requested streams available_live_stream_info: List[pylsl.StreamInfo] = pylsl.resolve_bypred(pred_str) logger.debug('found %d live stream match(es) for predicate', len(available_live_stream_info)) # iterate each query and start live streams for live_stream_info in available_live_stream_info: # create task to live-stream data inlet = pylsl.StreamInlet(live_stream_info, max_chunklen=1, recover=False) asyncio.create_task(RelayMode.start_live_stream(inlet, queue)) num_tasks += 1 logger.info("started %d live stream tasks for the %d queries", num_tasks, num_queries) return { 'command': 'notification', 'data': {'message': f'started {num_tasks} live stream tasks for the {num_queries} queries'}, 'error': None }
def _get_stream_inlet(lsl_predicate): """Return the stream that fits the given predicate. Raise ValueError if multiple streams or zero streams match the predicate. Parameters ---------- lsl_predicate : str Predicate used to find LabStreamingLayer stream. See `default_eeg_predicates.py` for more info. Returns ------- inlet : pylsl.StreamInlet The LSL stream that matches the given predicate. """ stream = resolve_bypred(lsl_predicate) # Should timeout be specified? if len(stream) == 1: inlet = StreamInlet(stream[0]) print("Connected to stream.") # TODO: change this to logging. elif not stream: # This would never happen without a timeout. raise ValueError("Zero streams match the given predicate.") else: raise ValueError( "Multiple streams match the given predicate. Only one " "stream must match the predicate.") return inlet
def _resolve_streams(verbose=True) -> list: if verbose: logger.info("Finding stream...") # Get the Muse EEG stream streams = pylsl.resolve_bypred("name='Muse' and type='EEG'", timeout=10) if not streams: logger.error("No appropriate stream could be found") exit(1) return streams
def __init__(self, name=LSL_STREAM_NAMES[2], only_this_host=False): if not only_this_host: streams = resolve_byprop('name', name, timeout=LSL_RESOLVE_TIMEOUT) else: streams = resolve_bypred("name='{}' and hostname='{}'".format(name, socket.gethostname())) self.inlet = None self.dtype = 'float64' if len(streams) > 0: self.inlet = FixedStreamInlet(streams[0], max_buflen=2) # self.dtype = fmt2string[self.inlet.info().channel_format()] print(self.dtype)
def __init__(self, name=LSL_STREAM_NAMES[2], only_this_host=False): if not only_this_host: streams = resolve_byprop('name', name, timeout=LSL_RESOLVE_TIMEOUT) else: streams = resolve_bypred("name='{}' and hostname='{}'".format(name, socket.gethostname())) self.inlet = None self.dtype = 'float64' if len(streams) > 0: self.inlet = FixedStreamInlet(streams[0], max_buflen=2) # self.dtype = fmt2string[self.inlet.info().channel_format()] print('Connected to {} LSL stream successfully'.format(name)) self.n_channels = self.inlet.info().channel_count() else: raise ConnectionError('Cannot connect to "{}" LSL stream'.format(name))
def __init__(self): self.task = {'phase':'precue', 'class':1, 'target':1} print("Looking for stream with type Markers") streams = resolve_bypred("type='Markers'", minimum=1) proc_flags = 0 # Marker events are relatively rare. No need to post-process. self.inlet = StreamInlet(streams[0], processing_flags=proc_flags) # The following is an example of how to read stream info stream_info = self.inlet.info() stream_Fs = stream_info.nominal_srate() stream_xml = stream_info.desc() chans_xml = stream_xml.child("channels") chan_xml_list = [] ch = chans_xml.child("channel") while ch.name() == "channel": chan_xml_list.append(ch) ch = ch.next_sibling("channel") stream_ch_names = [ch_xml.child_value("label") for ch_xml in chan_xml_list] print("Reading from inlet named {} with channels {}".format(stream_info.name(), stream_ch_names))
def __init__(self): self.task = {'phase': 'precue', 'class': 1, 'target': 1} print("Looking for stream with type Markers") streams = resolve_bypred("type='Markers'", minimum=1) proc_flags = 0 # Marker events are relatively rare. No need to post-process. self.inlet = StreamInlet(streams[0], processing_flags=proc_flags) # The following is an example of how to read stream info stream_info = self.inlet.info() stream_Fs = stream_info.nominal_srate() stream_xml = stream_info.desc() chans_xml = stream_xml.child("channels") chan_xml_list = [] ch = chans_xml.child("channel") while ch.name() == "channel": chan_xml_list.append(ch) ch = ch.next_sibling("channel") stream_ch_names = [ ch_xml.child_value("label") for ch_xml in chan_xml_list ] print("Reading from inlet named {} with channels {}".format( stream_info.name(), stream_ch_names))
def _resolve(self): streams_info = resolve_bypred("type='EEG'", 0, 2.5) streams_active = [] self.logger.debug("Found {} available streams".format( len(streams_info))) for stream_info in streams_info: uid = stream_info.source_id() if stream_info.source_id( ) else stream_info.uid() streams_active.append(uid) if uid not in self.streams_by_uid: if self._validate_stream_signature(stream_info): self._connect_to(uid, stream_info) if uid in self.streams_by_uid: if self.streams_by_uid[uid].running == False: self._disconnect_from({uid}) #werkt soms niet? # streams_active.remove(uid) #werkt self._disconnect_from( list(set(self.streams_by_uid.keys()) - set(streams_active)))
def run(self): streams = resolve_bypred("*", timeout=5) self.streams = [StreamInlet(stream).info() for stream in streams] self.taskFinished.emit()
def plot(device: str): """Plot existing LSL stream""" from eegwatch.lslutils import PULL_INTERVAL, PLOT_DURATION, _get_inlets assert device.startswith("muse"), "Only Muse devices supported for now" # print(eeg_device) # TODO: Get the live data and do basic stuff to check signal quality, such as: # - Checking signal variance. # - Transforming into the frequency domain. offset = datetime.now(tz=timezone.utc).timestamp() - pylsl.local_clock() def local_clock_to_timestamp(local_clock): return local_clock + offset streams = pylsl.resolve_bypred("name='Muse' and type='EEG'", timeout=10) if not streams: print("No stream could be found") exit(1) for s in streams: logger.debug(streams) # Create the pyqtgraph window pw = pg.plot(title="LSL Plot") plt = pw.getPlotItem() plt.enableAutoRange(x=False, y=True) inlets = _get_inlets(plt=plt) def scroll(): """Move the view so the data appears to scroll""" # We show data only up to a timepoint shortly before the current time # so new data doesn't suddenly appear in the middle of the plot fudge_factor = PULL_INTERVAL * 0.002 plot_time = local_clock_to_timestamp(pylsl.local_clock()) pw.setXRange(plot_time - PLOT_DURATION + fudge_factor, plot_time - fudge_factor) def update(): # Read data from the inlet. Use a timeout of 0.0 so we don't block GUI interaction. mintime = local_clock_to_timestamp(pylsl.local_clock()) - PLOT_DURATION # call pull_and_plot for each inlet. # Special handling of inlet types (markers, continuous data) is done in # the different inlet classes. for inlet in inlets: inlet.pull_and_plot(mintime, plt) # create a timer that will move the view every update_interval ms update_timer = QtCore.QTimer() update_timer.timeout.connect(scroll) update_timer.start(UPDATE_INTERVAL) # create a timer that will pull and add new data occasionally pull_timer = QtCore.QTimer() pull_timer.timeout.connect(update) pull_timer.start(PULL_INTERVAL) import sys # Start Qt event loop unless running in interactive mode or using pyside. if (sys.flags.interactive != 1) or not hasattr(QtCore, "PYQT_VERSION"): QtGui.QApplication.instance().exec_()
def find_pylsl_outlets(v=None, **kwargs): # noqa: C901 ''' This function is easier to use than func `pylsl.resolve_stream`. Examples -------- >>> find_pylsl_outlets() # same as pylsl.resolve_streams() >>> find_pylsl_outlets(1) # same as pylsl.resolve_streams(timeout=1) >>> find_pylsl_outlets('type', 'EEG') # Invalid >>> find_pylsl_outlets("type='EEG'") # pylsl.resolve_bypred("type='EEG'") >>> find_pylsl_outlets(type='EEG') # pylsl.resolve_byprop('type', 'EEG') If no wanted pylsl stream outlets found, ``RuntimeError`` will be raised. ''' timeout = v if isinstance(v, (int, float)) else kwargs.pop('timeout', 1) keys = set(kwargs.keys()).intersection({ 'name', 'type', 'channel_count', 'nominal_srate', 'channel_format', 'source_id' }) if isinstance(v, str): infos = pylsl.resolve_bypred(v, 0, timeout) elif not keys: infos = pylsl.resolve_streams(timeout) else: infos = [] for key in keys: infos += pylsl.resolve_byprop(key, kwargs[key], 0, timeout) streams = dict() for info in infos: if info.uid() not in streams: streams[info.uid()] = info stream_list = list(streams.values()) if len(stream_list) == 0: raise RuntimeError('No stream available! Abort.') elif len(stream_list) == 1: stream = stream_list[0] else: # Display stream as: $No $Name $Type - $CHx$Format $SourceID prompt = ('Please choose one from all available streams:\n ' + '\n '.join([ '{:2d} {:s}({:s}) CH{:d}x{:s} - `{}`@ {}'.format( n, s.name(), s.type(), s.channel_count(), pylsl.pylsl.fmt2type[s.channel_format()]._type_, s.source_id() and '`%s` ' % s.source_id() or '', s.hostname()) for n, s in enumerate(stream_list) ]) + '\nstream num (default 0): ') answer = {str(i): stream_list[i] for i in range(len(stream_list))} answer[''] = stream_list[0] try: stream = check_input(prompt, answer) if stream == '': stream = answer[stream] except KeyboardInterrupt: raise RuntimeError('No stream selected! Abort.') logger.info('Using stream `{}`({}) `{}`@ {}'.format( stream.name(), stream.type(), stream.source_id(), stream.hostname())) return stream