PyCollect - Live protocol

After Install and Run UBT Launcher in any of the available Modes, the system are ready to handle clients connections (take note about the selected port).

Data structure

Requests

  • Each request sent to the WebSocket must be done in JSON format through a stringify command.
  • Each request must include at least one common argument: command.

Response

Each system response must include an debug object with the argumments: command, type and origin:

  • command: With the same request command that trigger the response.
  • type: One of DISP, WAVE, CHANNELS, LOG, ERROR, RESP.
  • origin: One of PYCOLLECT, PYMASIMO.
  • buffersize: The size of internal buffer.
  • recording: Boolean that indicate if system are recording data.
  • transmitting: Boolean that indicate if system are transmitting data, in

this case, will send extra information about the data transmitted.

Types

  • DISP: Indicate the presense os subrecords.
  • WAVE: Indicate the presense os waveforms.
  • CHANNELS: Indicate the presense of subrecords and waveforms.
  • LOG: When a command not need a response, this type is include a message argument.
  • RESP: Contain the response of a request.
  • ERROR: Contain an error message, this type is include a message argument.

Datetimes

All datetimes data are in Unix Timestamp format, for example:

  • Sun Aug 25 20:57:08 1991 is equivalent to 683171828
  • Fri Jul  6 11:23:20 2018 is equivalent to 1530894200

Special values

  • DATA_INVALID_LIMIT: -32001
  • DATA_INVALID: -32767
  • DATA_NOT_UPDATED: -32766
  • DATA_DISCONT: -32765
  • DATA_UNDER_RANGE: -32764
  • DATA_OVER_RANGE: -32763
  • DATA_NOT_CALIBRATED: -32762

Commands

This list a commands are available, some of them need extra arguments.

  • available_channels: Request the list of available subrecords based on the monitor modules activity merged with the list of waveforms supported by the monitor.
  • available_subrecords: Request the list of available subrecords based on the monitor modules activity.
  • clear_data: Clear buffer and stop data transfer.
  • close_stream: Stop stream and close serial port, save data if a recording enabled.
  • debug: Request debug information about device, conection, data transfering.
  • get_csv: Generate and save data un CSV format.
  • get_edf: Generate and save data in EDF+ format.
  • get_raw: Generate and save data in RAW format.
  • list_all_measures: Request a list of all measures supported by the monitor.
  • list_all_waveforms: Request a list of all waveform supported by the monitor.
  • possible_waveforms: Request the list of waveforms supported by the monitor.
  • reconnect_device: Send an instruction for reconnect with the serial port.
  • request_channels: Request to monitor a set of waveforms and subrecords.
  • request_subrecords: Request to monitor a set of subrecords.
  • request_waveforms: Request to monitor a set of waveforms.
  • start_recording: Clear data, continues the data transfer.
  • stop_recording:
  • stop_transfer: Stop the monitor data transfer.

Connection with WebSocket

A standard connection is enough, the default port is 8890, the complete ip could looks like: ws://localhost:8890/ws, note the /ws that complete the address.

Quick test

This request will ask for available_channels, start a default request_channels, wait for 5 seconds, start_recording, wait for 10 seconds stop_transfer and get_edf, get_csv, and get_raw.

The result can be checked with the browser developer tools.

Available subrecords

Request

This command will stop a possible Subrecord transfer.

request
{
"command": "available_subrecords"
}

Response

response
{
"command": "available_subrecords",
"origin": "PYCOLLECT",
"type": "RESP",
"subrecords": [], //A list of available subrecords labels.
}

Live example

request
request = {

"command": "available_subrecords",

}

Request subrecords

Request

The value of subrecords must be a sublist from the list with available subrecords. If the list of `subrecords is empty the response will contain all available measures.

request
{
"command": "request_subrecords",
"subrecords": [], //List of subrecords labels.
}

Response

response
{
  "type": "DISP",
  "origin": "PYCOLLECT",
  "command": "request_subrecords"
  "datetime": 1530894200,
  "data": {}, //A dictionary with the subrecords label and their respective measure.
}

Live example

Request possible waveforms

There is no way to list the waveforms that the device can send, this request return all possible waveforms

Request

request
{
"command": "possible_waveforms",
}

Response

The response is always the same.

response
{
  "type": "RESP",
  "origin": "PYCOLLECT",
  "command": "possible_waveforms",
  "waveforms": [],  //A list of all waveforms.
}

Live example

request
request = {

"command": "possible_waveforms"

}

Request waveforms

Request

The value of waveforms must be a sublist from the list with all waveforms. If the list of wafeforms is empty the request will be ignored.

request
{
"command": "request_waveforms",
"waveforms": [], //A list with the desired waveforms labels.
}

Response

The monitor only will send the available waveforms and not necessarily all that was requested.

response
{
  "type": "WAVE",
  "origin": "PYCOLLECT",
  "command": "request_waveforms"
  "channels": [  //list of channels, each channel is a dictionary

    {  //channel dictionary
      "label": "FLOW",
      "datetime": 1530894182,
      "physicalDimension": "l/min",
      "samplefrequency": 25,
      "samples": 100,
      "physicalMaximum": null,
      "physicalMinimum": null,
      "digitalMaximum": 32768,
      "digitalMinimum": -32768,
      "prefilter": "",
      "transducer": "",
      "data": [...], //list of integers or floats
    },

    ...
  ]

}

Live example

Available channels

Request

This command will stop a possible Subrecord and Waveforms transfer.

request
{
"command": "available_channels"
}

Response

response
{
"command": "available_channels",
"origin": "PYCOLLECT",
"type": "RESP",
"labels": [], //A list of available subrecords and waveforms labels.
}

Live example

request
request = {

"command": "available_channels",

}

Request channels

Request

The value of channels must be a sublist from the list with all waveforms and subrecords. If the list of labels is empty, then will reques the default dataset.

request
{
"command": "request_channels",
"channels": [], //A list with the desired waveforms and subrecords labels.
}

Response

The monitor only will send the available waveforms and not necessarily all that was requested.

response
{
  "channels": [  //list of channels, each channel is a dictionary

    {  //channel dictionary
      "label": "FLOW",
      "datetime": 1530894182,
      "physicalDimension": "l/min",
      "samplefrequency": 25,
      "samples": 100,
      "physicalMaximum": null,
      "physicalMinimum": null,
      "digitalMaximum": 32768,
      "digitalMinimum": -32768,
      "prefilter": "",
      "transducer": "",
      "data": [...], //list of integers, floats, strings or Nones
    },

    ...
  ]

}

Live example

Stop transfer

This command will send a request to the monitor for stop the data transmitting.

request
request = {

"command": "stop_transfer"

}

Close stream

This command will send a request to the monitor for stop the data transmitting and will save possible data recording, the serial port will be closed too.

request
request = {

"command": "close_stream"

}

Reconnect with device

This command will send a request for connect with the monitor, this method is called internally with the first connect, will return a debug response.

request
request = {

"command": "reconnect_device"

}

Start recording

This command will clear the data buffer.

request
request = {

"command": "start_recording"

}

Clear data

This command will clear the data buffer and stop the data transmitting from monitor too.

request
request = {

"command": "clear_data"

}

Get debug information

Request

This request will return useful information about connection and transmission.

request
{
"command": "debug",
}

Response

A complete response, with transmission in process contains the next data.

response
{
  "device": "gehealthcare",         //Name of device connected
  "port": null,                     //Serial port name
  "ip_port": "8890",                //IP port
  "debug_mode": true,               //Debug mode is enable

  "user_dir": "/home/user/ubtdriver",
  "download": "http://localhost:8890/download/",

  "debug": {
    "buffersize": 14976,
    "recording": true,
    "transmitting": true,

    "origin": "PYCOLLECT",
    "command": "debug",
    "type": "RESP",

    "subrecords": {
      "startdatetime": 1532624765,          //Timestamp for the first data
      "enddatetime": 1532624805,            //Timestamp for the last data
      "totalseconds": 40,                   //Total of seconds processed
      "labels": []                          //List of subrecords labels

    },
    "waveforms": {
      "startdatetime": 1532624798,          //Timestamp for the first data
      "enddatetime": 1532624804,            //Timestamp for the last data
      "totalseconds": 6,                    //Total of seconds processed
      "labels": []                          //List of waveforms labels
    },
  }
}

Live example

request
request = {

"command": "debug"

}

List all measures

Request

This request return information about all measures for all modules (availables or not).

request
{
"command": "list_all_measures",
}

Response

Each measure contain: label, description, unit and other information for internal usage.

response
{
  "ECG HR": {               //Label as dictionary key
    "label": "ECG HR",      //Label
    "desc": "Heart rate",   //Description
    "key": "ecg:hr",        //For internal usage
    "unit": "1/min",        //The physical unit
    "subclass": "basic"     //For unternal usage
  },

...

}

Live example

request
request = {

"command": "list_all_measures"

}

List all waveforms

Request

This request return information about all waveforms.

request
{
"command": "list_all_waveforms",
}

Response

Each waveform contain: label, unit, samples per second and other information for internal usage.

response
{
  "ECG1": {                 //Label as dictionary key
    "label": "ECG1",        //Label
    "unit": "uV",           //The physical unit
    "shift": 0.000001,      //For internal usage
    "samps": 300,           //Samples per second
    "transducer": "",       //Transductor used, used for generate the EDF+ file
    "prefilter": "",        //Prefilter, used for generate the EDF+ file
    "physical_min": null,   //Physical minimum, used for generate the EDF+ file
    "physical_max": null,   //Physical maximum, used for generate the EDF+ file
  },

...

}

Live example

request
request = {

"command": "list_all_waveforms"

}

Save as RAW

In this implementation download event will kill the websocket.

request
request = {

"command": "get_raw"

}

Save as CSV

In this implementation download event will kill the websocket.

request
request = {

"command": "get_csv"

}

Save as EDF+

In this implementation download event will kill the websocket.

Bad request

When a request is not understood.

request
request = {

"command": "this_request_not_exist"

}