Remote control#

The Open Ephys HTTP Server enables remote control of the GUI via an HTTP API. Immediately upon launching, the GUI starts a server on port 37497 (EPHYS on a phone keypad). You can confirm that the server is running by opening http://localhost:37497/api/processors in a browser. If you are using a different computer, replace localhost with the IP address of the machine running the GUI.

The HTTP server can be disabled or re-enabled via the File menu.

Most read-only endpoints use HTTP GET, while endpoints that change GUI state use PUT with a JSON body. Python examples below use the requests library, while Matlab examples use webread and webwrite.

Malformed JSON requests return HTTP 400 responses. Requests for missing processors, streams, or parameters return HTTP 404 responses.

Quick API reference#

Method

Endpoint

Description

GET

/api/status

Return the current GUI mode.

PUT

/api/status

Set the GUI mode to IDLE, ACQUIRE, or RECORD.

GET

/api/recording

Return default recording settings and all Record Node settings.

PUT

/api/recording

Update default recording settings.

PUT

/api/recording/<record_node_id>

Update a specific Record Node.

GET

/api/config

Return the current signal-chain configuration as XML wrapped in JSON.

PUT

/api/load

Load a signal chain from disk.

PUT

/api/save

Save the current signal chain to disk.

GET

/api/processors/list

List processor types that can be added to the signal chain.

GET

/api/processors

Return all processors currently in the signal chain.

GET

/api/processors/<processor_id>

Return one processor and its streams.

GET

/api/processors/<processor_id>/parameters

Return all processor-level parameters.

GET

/api/processors/<processor_id>/parameters/<parameter_name>

Return one processor-level parameter.

GET

/api/processors/<processor_id>/streams/<stream_index>

Return one stream and its parameters.

GET

/api/processors/<processor_id>/streams/<stream_index>/parameters

Return all parameters for one stream.

GET

/api/processors/<processor_id>/streams/<stream_index>/parameters/<parameter_name>

Return one stream parameter.

PUT

/api/processors/<processor_id>/parameters/<parameter_name>

Set one processor-level parameter.

PUT

/api/processors/<processor_id>/streams/<stream_index>/parameters/<parameter_name>

Set one stream parameter.

PUT

/api/processors/<processor_id>/config

Send a processor-specific configuration message.

PUT

/api/message

Broadcast a message to all processors.

GET

/api/processors/clear

Clear the signal chain.

PUT

/api/processors/add

Add a processor to the signal chain.

PUT

/api/processors/delete

Delete a processor from the signal chain.

GET

/api/undo

Undo the previous action.

GET

/api/redo

Redo the previous action.

GET

/api/cpu

Return the current audio callback CPU usage.

GET

/api/latency

Return processor latency information for each stream.

GET

/api/audio/devices

List available audio device types and device names.

GET

/api/audio/device

Return the currently selected audio device and supported rates and buffer sizes.

PUT

/api/audio

Change the active audio device, sample rate, or buffer size.

PUT

/api/quit

Close the GUI.

Query and control acquisition state#

Use GET /api/status to query the GUI mode and PUT /api/status to change it.

import requests

status = requests.get("http://localhost:37497/api/status").json()
requests.put(
        "http://localhost:37497/api/status",
        json={"mode": "ACQUIRE"},
)
status = webread('http://localhost:37497/api/status');

out = webwrite(
        'http://localhost:37497/api/status',
        struct('mode','ACQUIRE'),
        weboptions('RequestMethod','put','MediaType','application/json'));

The returned JSON contains a single mode field:

  • IDLE means the GUI is not acquiring data.

  • ACQUIRE means the GUI is acquiring but not recording.

  • RECORD means the GUI is both acquiring and recording.

Note

The signal chain must contain at least one Record Node in order for RECORD mode to succeed.

Recording configuration#

Use GET /api/recording to inspect the global recording configuration and the state of each Record Node.

recording = requests.get("http://localhost:37497/api/recording").json()
{
        "parent_directory": "/Users/neuroscientist/Documents/OpenEphys",
        "base_text": "AUTO",
        "prepend_text": "NONE",
        "append_text": "AUTO",
        "default_record_engine": "BINARY",
        "record_nodes": [
                {
                        "node_id": 102,
                        "parent_directory": "/Users/neuroscientist/Documents/OpenEphys",
                        "record_engine": "BINARY",
                        "experiment_number": 1,
                        "recording_number": 3,
                        "is_synchronized": true
                }
        ]
}

Use PUT /api/recording to update global defaults. Supported fields are:

  • parent_directory

  • prepend_text

  • base_text

  • append_text

  • default_record_engine

  • start_new_directory

Example:

requests.put(
        "http://localhost:37497/api/recording",
        json={
                "parent_directory": "/Users/neuroscientist/Documents/Data",
                "base_text": "experiment_01",
                "append_text": "mouse_a",
                "default_record_engine": "BINARY",
                "start_new_directory": "true",
        },
)
out = webwrite(
        'http://localhost:37497/api/recording',
        struct(
                'parent_directory','/Users/neuroscientist/Documents/Data',
                'base_text','experiment_01',
                'append_text','mouse_a',
                'default_record_engine','BINARY',
                'start_new_directory','true'),
        weboptions('RequestMethod','put','MediaType','application/json'));

Use PUT /api/recording/<record_node_id> to update a specific Record Node. Supported fields are parent_directory and record_engine.

requests.put(
        "http://localhost:37497/api/recording/102",
        json={
                "parent_directory": "/Users/neuroscientist/Documents/Data",
                "record_engine": "BINARY",
        },
)

Signal-chain configuration files#

Use GET /api/config to fetch the current GUI configuration. The response is JSON with the XML payload stored in the info field.

config = requests.get("http://localhost:37497/api/config").json()
xml_text = config["info"]

Load a saved signal chain with PUT /api/load:

requests.put(
        "http://localhost:37497/api/load",
        json={"path": "/Users/neuroscientist/Documents/OpenEphys/chain.xml"},
)

Save the current signal chain with PUT /api/save:

requests.put(
        "http://localhost:37497/api/save",
        json={"filepath": "/Users/neuroscientist/Documents/OpenEphys/chain.xml"},
)

Note

/api/save does not overwrite an existing file. It returns a message if the target path already exists.

Inspect processors, streams, and parameters#

Use GET /api/processors/list to list the processor types that can be added to the graph:

available = requests.get("http://localhost:37497/api/processors/list").json()

Use GET /api/processors to inspect the current signal chain:

graph = requests.get("http://localhost:37497/api/processors").json()

The response has the following structure:

{
        "processors": [
                {
                        "id": 100,
                        "name": "File Reader",
                        "parameters": [],
                        "predecessor": null,
                        "streams": [
                                {
                                        "name": "example_data",
                                        "source_id": 100,
                                        "sample_rate": 40000.0,
                                        "channel_count": 16,
                                        "parameters": []
                                }
                        ]
                }
        ]
}

You can also query narrower endpoints:

  • /api/processors/<processor_id>

  • /api/processors/<processor_id>/parameters

  • /api/processors/<processor_id>/parameters/<parameter_name>

  • /api/processors/<processor_id>/streams/<stream_index>

  • /api/processors/<processor_id>/streams/<stream_index>/parameters

  • /api/processors/<processor_id>/streams/<stream_index>/parameters/<parameter_name>

Note

stream_index is zero-based because the server indexes directly into each processor’s stream list.

Parameter values are returned as strings in the JSON response, together with a type field that describes the parameter kind.

Modify processors and parameters#

Processor-level parameters can be changed with PUT /api/processors/<processor_id>/parameters/<parameter_name>.

requests.put(
        "http://localhost:37497/api/processors/101/parameters/high_cut",
        json={"value": 6000},
)

Stream parameters can be changed with PUT /api/processors/<processor_id>/streams/<stream_index>/parameters/<parameter_name>.

requests.put(
        "http://localhost:37497/api/processors/101/streams/0/parameters/enable_stream",
        json={"value": True},
)

Accepted value payloads are integers, floats, booleans, strings, and numeric arrays. Some parameters cannot be changed while acquisition is active; those requests return HTTP 400.

Use PUT /api/processors/<processor_id>/config to send a processor-specific configuration message before starting acquisition:

requests.put(
        "http://localhost:37497/api/processors/100/config",
        json={"text": "NP REFERENCE 3 1 1 TIP"},
)

To broadcast a message to all processors while acquisition is active, use PUT /api/message:

requests.put(
        "http://localhost:37497/api/message",
        json={"text": "ACQBOARD TRIGGER 1 100"},
)

Tip

Broadcast messages are saved by all Record Nodes, so they can be used to mark epochs within a recording.

The signal chain can also be edited remotely:

  • GET /api/processors/clear clears the graph.

  • PUT /api/processors/delete deletes a processor when given {"id": 101}.

  • PUT /api/processors/add adds a processor when given {"name": "Bandpass Filter"}.

  • PUT /api/processors/add also accepts source_id or dest_id to position the processor relative to an existing node.

  • GET /api/undo undoes the previous action.

  • GET /api/redo redoes the previous action.

Examples:

requests.put(
        "http://localhost:37497/api/processors/add",
        json={"name": "Bandpass Filter", "source_id": 100},
)

requests.put(
        "http://localhost:37497/api/processors/delete",
        json={"id": 101},
)

Graph-editing endpoints that modify the signal chain are blocked while acquisition is active.

Performance endpoints#

Use GET /api/cpu to retrieve the current audio callback CPU usage:

usage = requests.get("http://localhost:37497/api/cpu").json()

The returned JSON has the form:

{"usage": 0.12}

Use GET /api/latency to inspect processor latency per stream:

latency = requests.get("http://localhost:37497/api/latency").json()

This returns one entry per processor, each with a list of stream names and their latency values.

Audio device control#

The audio endpoints let you inspect the available devices and change the currently selected device.

Use GET /api/audio/devices to list available device types and names:

devices = requests.get("http://localhost:37497/api/audio/devices").json()

This returns JSON in the form:

{
        "devices": {
                "ALSA": ["Device A", "Device B"],
                "JACK": ["JACK Audio Connection Kit"]
        }
}

Use GET /api/audio/device to inspect the current device:

{
        "device_type": "ALSA",
        "device_name": "Device A",
        "sample_rate": 30000,
        "buffer_size": 512,
        "available_sample_rates": [30000, 44100, 48000],
        "available_buffer_sizes": [128, 256, 512, 1024]
}

Use PUT /api/audio to change any combination of device_type, device_name, sample_rate, and buffer_size:

requests.put(
        "http://localhost:37497/api/audio",
        json={
                "device_type": "ALSA",
                "device_name": "Device A",
                "sample_rate": 30000,
                "buffer_size": 512,
        },
)

Close the GUI remotely#

To shut down the GUI, send an HTTP PUT request to /api/quit:

requests.put("http://localhost:37497/api/quit")
out = webwrite(
        'http://localhost:37497/api/quit',
        struct(),
        weboptions('RequestMethod','put','MediaType','application/json'));