Devices

Device (Base class)

class octopus_sensing.devices.device.Device(name: Optional[str] = None, output_path: str = 'output')[source]

Bases: multiprocessing.context.Process

All devices should inherit from Device class.

Parameters
  • name (str, default: None) – Device name. This name will be used in the output path to identify each device’s data.

  • output_path (str, default: output) – The path for recording files. Audio files will be recorded in folder {output_path}/{name}

run() None[source]

Starts the device’s process. DeviceCoordinator calls this mehod to start data recording

set_queue(queue: multiprocessing.queues.Queue) None[source]

Sets message queue for the device. Device coordinator calls this method and set the queue for its device list

Parameters

queue (Queue) – a queue that will be used for message passing

get_name() str[source]

Gets device’s name

Returns

The name of device

Return type

str

MonitoredDevice

class octopus_sensing.devices.monitored_device.MonitoredDevice(*args, **kwargs)[source]

Bases: octopus_sensing.devices.device.Device

Provides functionalities for monitoring a device’s data. For example, visualizing data in real time.

set_monitoring_queues(monitor_in_q: multiprocessing.queues.Queue, monitor_out_q: multiprocessing.queues.Queue) None[source]

Sets the queues for communicating with the parent process. It should be called before the start of the process.

run() None[source]

Starts the device’s process. DeviceCoordinator calls this mehod to start data recording

Camera

class octopus_sensing.devices.camera_streaming.CameraStreaming(camera_no: Optional[Union[int, str]] = None, camera_path: Optional[str] = None, image_width: int = 1280, image_height: int = 720, **kwargs)[source]

Bases: octopus_sensing.devices.device.Device

Stream and Record video data. If we have several stimuli, one vide file will be recorded for each stimuli. Device coordinator is responsible for triggerng the camera to start or stop recording. The content of recorded file is the recorded video between start and stop triggers

Parameters
  • name (str, default: None:) – The name of device

  • output_path (str, default: output) – The path for recording files. Audio files will be recorded in folder {output_path}/{name}

  • camera_no (int, default:0) – The camera number. Default is 0 which is defaul camera in system

  • camera_path (str, default: None) – The physical path of camera device. It varies in different platforms. For Example in linux it can be something like this: /dev/v4l/by-id/usb-046d_081b_97E6A7D0-video-index0

  • image_width (int, default: 1280) – The width of recorded frame/frames

  • image_height (int, default: 720) – The height of recorded frame/frames.

Notes

  • Only one of camera_no or camera_path should have value.

  • There is no guarantee that we can set the camera resolution. Because camera may not be able to support these resolution and it will change it based on its settings

Example

Creating an instance of camera and adding it to the device coordinator. Device coordinator is responsible for triggerng the camera to start or stop recording

>>> camera = CameraStreaming(camera_no=0,
...                          name="camera",
...                          output_path="./output")
>>> device_coordinator.add_device(camera)

Audio

class octopus_sensing.devices.audio_streaming.AudioStreaming(device_id: int, **kwargs)[source]

Bases: octopus_sensing.devices.device.Device

Stream and Record audio

Parameters
  • device_id (int) – The audio recorder ID. If there is several audio recorder in the system

  • name (str, optional) – device name This name will be used in the output path to identify each device’s data

  • output_path (str, optional) – The path for recording files. Audio files will be recorded in folder {output_path}/{name}

Example

If you want to know what is your audio recorder’s ID run the following example from miniaudio

>>> import miniaudio
>>> devices = miniaudio.Devices()
>>> captures = devices.get_captures()
>>> for d in enumerate(captures):
        print("{num} = {name}".format(num=d[0], name=d[1]['name']))

Example

Creating an instance of audio recorder and adding it to the device coordinator. Device coordinator is responsible for triggerng the audio recorder to start or stop recording

>>> audio_recorder = AudioStreaming(1,
...                                 name="Audio_monitoring",
...                                 output_path="./output")
>>> device_coordinator.add_device(audio_recorder)

Shimmer3

class octopus_sensing.devices.shimmer3_streaming.Shimmer3Streaming(sampling_rate: int = 128, saving_mode: int = 0, serial_port: Optional[str] = None, **kwargs)[source]

Bases: octopus_sensing.devices.monitored_device.MonitoredDevice

Streams and Records Shimmer3 data. Data will be recorded in a csv file/files with the following column order: type, time stamp, Acc_x, Acc_y, Acc_z, GSR_ohm, PPG_mv, time, trigger

Parameters
  • name (str, default: None) – Device name. This name will be used in the output path to identify each device’s data.

  • output_path (str, default: output) – The path for recording files. Audio files will be recorded in folder {output_path}/{name}

  • saving_mode (int, default: SavingModeEnum.CONTINIOUS_SAVING_MODE) –

    The way of saving data: saving continiously in a file or save data related to each stimulus in a separate file. SavingModeEnum is:

    1. CONTINIOUS_SAVING_MODE

    2. SEPARATED_SAVING_MODE

  • serial_port (str, default: Windows=Com12, Linux=/dev/rfcomm0) – The serial port that Shimmer is paired with (See the Note below)

  • sampling_rate (int, default: 128) – The sampling frequency for acquiring data from the device

Example

Creating an instance of shimmer3 and adding it to the device coordinator. Device coordinator is responsible for triggerng the shimmer3 to start or stop recording or to add markers to recorded data. In this example, since the saving mode is continuous, all recorded data will be saved in a file. But, when an event happens, device coordinator will send a trigger message to the device and recorded data will be marked with the trigger

>>> my_shimmer = Shimmer3Streaming(name="shimmer",
...                                saving_mode=SavingModeEnum.CONTINIOUS_SAVING_MODE,
...                                output_path="./output")
>>> device_coordinator.add_device(my_shimmer)

Note

Keep in your mind, before running the code for Shimmer data recording, turn on the Shimmer3 sensor and pair bluetooth and the serial port. (Shimmer password: 1234)

For example in linux you can do it as follow:

1- hcitool scan //It shows the macaddress of device. for shimmer it is 00:06:66:F0:95:95

2- vim /etc/bluetooth/rfcomm.conf write the below line in it: rfcomm0{ bind no; device 00:06:66:F0:95:95; channel 1; comment “serial port” }

3- sudo rfcomm connect rfcomm0 00:06:66:F0:95:95 // This is for reading bluetooth data from a serial port

Note

This class is based on ShimmerReader which is an extended version of LogAndStream python firmware for Shimmer3 data streaming.

get_saving_mode()[source]

Gets saving mode

Returns

saving_mode – The way of saving data: saving continiously in a file or save data related to each stimulus in a separate file. SavingModeEnum is CONTINIOUS_SAVING_MODE = 0 or SEPARATED_SAVING_MODE = 1

Return type

int

get_output_path()[source]

Gets the path that is used for data recording

Returns

output_path – The output path that use for data recording

Return type

str

OpenBCI (brainflow)

class octopus_sensing.devices.brainflow_openbci_streaming.BrainFlowOpenBCIStreaming(channels_order: Optional[List[str]] = None, board_type: str = 'cyton-daisy', name: Optional[str] = None, output_path: str = 'output', serial_port=None)[source]

Bases: octopus_sensing.devices.brainflow_streaming.BrainFlowStreaming

Manages OpenBCI streaming using brainflow Data will be recorded in a csv file/files with the following column order: channels, Acc_x, Acc_y, Acc_z, sample_id, time_stamp, trigger

Parameters
  • name (str, default: None) – Device name. This name will be used in the output path to identify each device’s data.

  • output_path (str, default: output) – The path for recording files. Audio files will be recorded in folder {output_path}/{name}

  • saving_mode (int, default: SavingModeEnum.CONTINIOUS_SAVING_MODE) –

    The way of saving data: saving continiously in a file or save data related to each stimulus in a separate file. SavingModeEnum is:

    1. CONTINIOUS_SAVING_MODE

    2. SEPARATED_SAVING_MODE

  • board_type (str, default: cyton-daisy) –

    The type of OpenBCI boards that connect by USB dongle. It can be:

    • cyton: for cyton board sampling rate is 250 and it has 8 channels

    • cyton-daisy: for cyton-daisy board sampling rate is 125 and it has 16 channels

    • ganglion: for Ganglion board sampling rate is 200 and it has 4 channels

  • serial_port (str, default: None) –

    The serial port for reading OpenBCI data. By default we set this as follows for various platforms:

    • Linux: /dev/ttyUSB0

    • Windows: Com3

    • MacOS: /dev/cu.*

  • channels_order (List(str), default: None) – A list of channel names which specify the order and names of channels

Example

Creating an instance of OpenBCI board with USB dongle using brainflow, and adding it to the device coordinator. Device coordinator is responsible for triggerng the OpenBCI to start or stop recording or to add markers to recorded data. In this example, since the saving mode is continuous, all recorded data will be saved in a file. But, when an event happens, device coordinator will send a trigger message to the device and recorded data will be marked with the trigger

>>> my_openbci =
...     BrainFlowOpenBCIStreaming(name="OpenBCI",
...                               output_path="./output",
...                               board_type="cyton-daisy",
...                               saving_mode=SavingModeEnum.CONTINIOUS_SAVING_MODE,
...                               channels_order=["Fp1", "Fp2", "F7", "F3",
...                                               "F4", "F8", "T3", "C3",
...                                               "C4", "T4", "T5", "P3",
...                                               "P4", "T6", "O1", "O2"])
>>> device_coordinator.add_device(my_openbci)

Note

Before running the code, turn on the OpenBCI, connect the dongle and make sure its port is free.

get_output_path()[source]

Gets the path that is used for data recording

Returns

output_path – The output path that use for data recording

Return type

str

get_channels()[source]

Gets the list of channels

Returns

channels_name – The list of channels’ name

Return type

List[str]

get_saving_mode()[source]

Gets saving mode

Returns

saving_mode – The way of saving data: saving continiously in a file or save data related to each stimulus in a separate file. SavingModeEnum is CONTINIOUS_SAVING_MODE = 0 or SEPARATED_SAVING_MODE = 1

Return type

int

OpenBCI (pyOpenBCI)

class octopus_sensing.devices.openbci_streaming.OpenBCIStreaming(daisy=True, channels_order=None, saving_mode=0, **kwargs)[source]

Bases: octopus_sensing.devices.monitored_device.MonitoredDevice

Manages OpenBCI streaming It uses pyOpenBCI library which is not supporting by OpenBCI anymore. We recommend to use octopus_sensing.devices.brainflow_openbci_streaming instead.

Data will be recorded in a csv file/files with the following column order: channels, Acc_x, Acc_y, Acc_z, sample_id, time_stamp, trigger

Parameters
  • name (str, default: None) – Device name. This name will be used in the output path to identify each device’s data.

  • output_path (str, default: output) – The path for recording files. Audio files will be recorded in folder {output_path}/{name}

  • saving_mode (int, default: SavingModeEnum.CONTINIOUS_SAVING_MODE) –

    The way of saving data: saving continiously in a file or save data related to each stimulus in a separate file. SavingModeEnum is:

    1. CONTINIOUS_SAVING_MODE

    2. SEPARATED_SAVING_MODE

  • daisy (bool, default: True) – If it is True, it means we use cyton-daisy board, otherwise we use cyton board

  • channels_order (list of str, default: None) – A list of channel names which specify the order and names of channels

Example

Creating an instance of OpenBCI board with USB dongle using pyOpenBCI, and adding it to the device coordinator. Device coordinator is responsible for triggerng the OpenBCI to start or stop recording or to add markers to recorded data. In this example, since the saving mode is continuous, all recorded data will be saved in a file. But, when an event happens, device coordinator will send a trigger message to the device and recorded data will be marked with the trigger

>>> my_openbci =
...     OpenBCIStreaming(name="OpenBCI",
...                      output_path="./output",
...                      daisy=True,
...                      saving_mode=SavingModeEnum.CONTINIOUS_SAVING_MODE,
...                      channels_order=["Fp1", "Fp2", "F7", "F3",
...                                      "F4", "F8", "T3", "C3",
...                                      "C4", "T4", "T5", "P3",
...                                      "P4", "T6", "O1", "O2"])
>>> device_coordinator.add_device(my_openbci)

Note

Before running the code, turn on the OpenBCI, connect the dongle and make sure its port is free.

get_saving_mode()[source]

Gets saving mode

Returns

saving_mode – The way of saving data: saving continiously in a file or save data related to each stimulus in a separate file. SavingModeEnum is CONTINIOUS_SAVING_MODE = 0 or SEPARATED_SAVING_MODE = 1

Return type

int

get_output_path()[source]

Gets the path that is used for data recording

Returns

output_path – The output path that use for data recording

Return type

str

get_channels()[source]

Gets the list of channels

Returns

channels_name – The list of channels’ name

Return type

List[str]

Brainflow

class octopus_sensing.devices.brainflow_streaming.BrainFlowStreaming(device_id: int, sampling_rate: int, brain_flow_input_params: brainflow.board_shim.BrainFlowInputParams, saving_mode: int = 0, name: Optional[str] = None, output_path: str = 'output')[source]

Bases: octopus_sensing.devices.monitored_device.MonitoredDevice

Manage brainflow streaming

device_id

Device ID. Brainflow support a list of devices, to see supported device IDs go to: https://brainflow.readthedocs.io/en/stable/SupportedBoards.html

sampling_rate

the sampling rate for recording data

brain_flow_input_params

Each supported board in brainflow gets some parameters, to see the list of parameters for each board go to: https://brainflow.readthedocs.io/en/stable/SupportedBoards.html

name

device name This name will be used in the output path to identify each device’s data

output_path

The path for recording files. Audio files will be recorded in folder {output_path}/{name}

saving_mode

The way of saving data. It saves data continiously in a file or saves data which are related to various stimulus in separate files. default is SavingModeEnum.CONTINIOUS_SAVING_MODE SavingModeEnum is [CONTINIOUS_SAVING_MODE, SEPARATED_SAVING_MODE]

\*\* kwargs

Extra optional arguments according to the board type

Examples

Here is an example of using brainflow for reading cyton_daisy board data

>>> params = BrainFlowInputParams()
>>> params.serial_port = "/dev/ttyUSB0"
>>> my_brainflow =
...       BrainFlowStreaming(2,
...                          125,
...                          brain_flow_input_params=params,
...                          name="cyton_daisy",
...                          output_path="./output",
...                          saving_mode=SavingModeEnum.CONTINIOUS_SAVING_MODE)

Open Vibe

class octopus_sensing.devices.open_vibe_streaming.OpenVibeStreaming(host: str = '127.0.0.1', port: int = 15361)[source]

Bases: octopus_sensing.devices.device.Device

Sending triggers to OpenVibe data recorders. OpenVibe supports data acquisition through many biosensors. We can record data through OpenVibe and send markers using this class.

Parameters
  • host (str) – host IP address

  • port (int) – port number

Example

Creating an instance of OpenVibeStreaming in the local machine and adding it to the device_coordinator

>>> device_coordinator = DeviceCoordinator()
>>> openvibe_device = OpenVibeStreaming()
>>> device_coordinator.add_devices([openvibe_device])

Note

We need a scenario in OpenVibe to record data. OpenVibe should start data recording before sending the triggers.

run()[source]

Starts the device’s process. DeviceCoordinator calls this mehod to start data recording

Network

class octopus_sensing.devices.network_devices.socket_device.SocketNetworkDevice(host: str, port: str, **kwargs)[source]

Bases: octopus_sensing.devices.device.Device

This class is being used for sending triggers to other softwares using TCP-IP socket. It works as a server socket, which sends triggers (when an event happen) to the connected clients.

For example if we have a device that record data through matlab, through this server socket, we can send the trigger to the matlab application to mark the recorded data.

Parameters
  • host (str) – host IP address

  • port (str) – port number

Example

Creating a SocketNetworkDevice in the local machine and adding it to the device_coordinator. By adding it to the DeviceCoordinator, it starts listening

>>> device_coordinator = DeviceCoordinator()
>>> socket_device = SocketNetworkDevice("0.0.0.0", 5002)
>>> device_coordinator.add_devices([socket_device])

Note

Look at Examples/send_trigger_to_remote_device.py (server code), Examples/matlabRecorder.m or examples/client.py (client codes)

class octopus_sensing.devices.network_devices.http_device.HttpNetworkDevice(external_endpoints: List[str], serialization_type: Callable[[...], Union[bytes, str]] = <function dumps>, name: Optional[str] = None, timeout: int = 3)[source]

Bases: octopus_sensing.devices.device.Device

This class can be used to send messages (triggers) to the other softwares through HTTP protocol.

The external software need to listen for incoming HTTP connections (a.k.a HTTP server or HTTP endpoint). This device will POST message to the specified URLs.

The messages will be in the form of a dictionary, serialized by the specified type. For example, if the serialization_type is JSON, a START message will be:

{“type”: “START”, “experiment_id”: “exp1”, “stimulus_id”: “s1”}

Parameters
  • external_endpoints (List[str]) – A list of URLs to send the message to. It should have the scheme (http or https) at the beginning. For example: [”http://localhost:8080”] Note that for IPv6, you need to put it between braces, like this: `http://[2345:425:2ca1:0000:0000:567:5673:23b5]/

  • serialization_type – Should be one of the types defined in SerializationTypes

  • name (str, default: None) – Name of this device

  • timeout (int, default: 3) – Timeout for both connecting to the external endpoint and POSTing messages. In seconds.

Example

In your Octopus Sensing software:

>>> coordinator = DeviceCoordinator()
>>> device = HttpNetworkDevice(["http://localhost:8080/", "http://192.168.1.1/trigger"])
>>> coordinator.add_device(device)

Every message that is dispatched using coordinator.dispatch method will be send to http://localhost:8080/.

Common

class octopus_sensing.devices.common.SavingModeEnum[source]

Bases: object

In CONTINIOUS_SAVING_MODE all data will be saved in one file, and some markers will be used to specify an event. In SEPARATED_SAVING_MODE, the data related to different events will be saved in separate files. For example, if stimuli is a list of videos, in CONTINIOUS_SAVING_MODE, the data recorded during displaying all videos, will be recorded in a file and two markers one for start and one for the stop of each video will be recorded in the data. In SEPARATED_SAVING_MODE for each video stimuli, the data recorded while displaying each video will be recorded in a separated file.

CONTINIOUS_SAVING_MODE = 0
SEPARATED_SAVING_MODE = 1