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 |
|
Return the current GUI mode. |
PUT |
|
Set the GUI mode to |
GET |
|
Return default recording settings and all Record Node settings. |
PUT |
|
Update default recording settings. |
PUT |
|
Update a specific Record Node. |
GET |
|
Return the current signal-chain configuration as XML wrapped in JSON. |
PUT |
|
Load a signal chain from disk. |
PUT |
|
Save the current signal chain to disk. |
GET |
|
List processor types that can be added to the signal chain. |
GET |
|
Return all processors currently in the signal chain. |
GET |
|
Return one processor and its streams. |
GET |
|
Return all processor-level parameters. |
GET |
|
Return one processor-level parameter. |
GET |
|
Return one stream and its parameters. |
GET |
|
Return all parameters for one stream. |
GET |
|
Return one stream parameter. |
PUT |
|
Set one processor-level parameter. |
PUT |
|
Set one stream parameter. |
PUT |
|
Send a processor-specific configuration message. |
PUT |
|
Broadcast a message to all processors. |
GET |
|
Clear the signal chain. |
PUT |
|
Add a processor to the signal chain. |
PUT |
|
Delete a processor from the signal chain. |
GET |
|
Undo the previous action. |
GET |
|
Redo the previous action. |
GET |
|
Return the current audio callback CPU usage. |
GET |
|
Return processor latency information for each stream. |
GET |
|
List available audio device types and device names. |
GET |
|
Return the currently selected audio device and supported rates and buffer sizes. |
PUT |
|
Change the active audio device, sample rate, or buffer size. |
PUT |
|
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:
IDLEmeans the GUI is not acquiring data.ACQUIREmeans the GUI is acquiring but not recording.RECORDmeans 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_directoryprepend_textbase_textappend_textdefault_record_enginestart_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/clearclears the graph.PUT /api/processors/deletedeletes a processor when given{"id": 101}.PUT /api/processors/addadds a processor when given{"name": "Bandpass Filter"}.PUT /api/processors/addalso acceptssource_idordest_idto position the processor relative to an existing node.GET /api/undoundoes the previous action.GET /api/redoredoes 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'));