Skip to content
Zachary Heins edited this page Jun 4, 2019 · 4 revisions

eVOLVER server wiki

The eVOLVER server runs on the raspberry pi on the eVOLVER unit. It acts as the "brains" of the eVOLVER, controlling and collecting data from attached experimental parameters (Arduinos) such as OD, temperature, stir rate, and fluidics. We are currently using websockets to allow the server to interact with users and other applications. When you run an experiment on your computer or use the desktop or touchscreen application, this is how the commands get sent to the arduino and how that application receives data.

Sending commands

To send a command to the server, emit a command event, passing JSON in the following format:

{
    "param": "<parameter_name>",
    "value": "<value_to_be_sent>",
    "immediate": true
}

In python, this will look like this:

data = {'param': 'temp', 'value': [4095] * 16, 'immediate': True}
evolver_ns.emit('command', data, namespace = '/dpu-evolver')

where evolver_ns is configured as the following somewhere in the script:

socketIO = SocketIO(EVOLVER_IP, EVOLVER_PORT)
evolver_ns = socketIO.define(EvolverNamespace, '/dpu-evolver')

If you would also like to change how that experimental parameter is formatted, just add the fields to the json, like this:

{
    "param": "<parameter_name>",
    "value": "<value_to_be_sent>",
    "recurring": true,
    "fields_expected_outgoing": 2,
    "fields_expected_incoming": 17
}

Adding the immediate field tells the server to immediately send the command to the Arduino. Otherwise, it will apply the new values/configurations on the next broadcast event.

The recurring field tells the server whether the values should be sent to the Arduino every time it broadcasts (a good thing to do for a parameter like temperature or OD), or if it only should accept one off commands (useful for fluidics).

The other two fields tell the server how many fields to send to and expect from the Arduino. This is used for error checking, letting it know if any problems occurred during serial communications.

Receiving Data from the server

The server emits a broadcast event over websockets with the data it collects every query from the experimental paramters connected and with it's current configurations for itself and for the experimental parameters connected.

To receive the broadcast, put a class similar to what is shown below in your script. The on_broadcast function will be called when a broadcast event from the server is emitted.

class EvolverNamespace(BaseNamespace):
    def on_connect(self, *args):
        print("Connected to eVOLVER as client")

    def on_disconnect(self, *args):
        print("Discconected from eVOLVER as client")

    def on_reconnect(self, *args):
        print("Reconnected to eVOLVER as client")

    def on_broadcast(self, data):
        print(data)  

The data will look like this:

{
  "config": {
    "od_90": {
      "recurring": true,
      "fields_expected_incoming": 17,
      "fields_expected_outgoing": 2,
      "value": "1000"
    },
    "od_135": {
      "recurring": true,
      "fields_expected_incoming": 17,
      "fields_expected_outgoing": 2,
      "value": "1000"
    },
    "temp": {
      "recurring": true,
      "fields_expected_incoming": 17,
      "fields_expected_outgoing": 17,
      "value": [
        "30",
        "30",
        "30",
        "30",
        "30",
        "30",
        "30",
        "30",
        "30",
        "30",
        "30",
        "30",
        "30",
        "30",
        "30",
        "30"
      ]
    },
    "od_led": {
      "recurring": true,
      "fields_expected_incoming": 17,
      "fields_expected_outgoing": 17,
      "value": [
        "2500",
        "2500",
        "2500",
        "2500",
        "2500",
        "2500",
        "2500",
        "2500",
        "2500",
        "2500",
        "2500",
        "2500",
        "2500",
        "2500",
        "2500",
        "2500"
      ]
    },
    "lxml": {
      "recurring": false,
      "fields_expected_incoming": 17,
      "fields_expected_outgoing": 17,
      "value": [
        "4095",
        "4095",
        "4095",
        "4095",
        "4095",
        "4095",
        "4095",
        "4095",
        "4095",
        "4095",
        "4095",
        "4095",
        "4095",
        "4095",
        "4095",
        "4095"
      ]
    },
    "pump": {
      "recurring": false,
      "fields_expected_incoming": 49,
      "fields_expected_outgoing": 49,
      "value": None
    },
    "stir": {
      "recurring": true,
      "fields_expected_incoming": 17,
      "fields_expected_outgoing": 17,
      "value": [
        "8",
        "8",
        "8",
        "8",
        "8",
        "8",
        "8",
        "8",
        "8",
        "8",
        "8",
        "8",
        "8",
        "8",
        "8",
        "8"
      ]
    }
  },
  "data": {
    "temp": [
      "2744",
      "2746",
      "2744",
      "2759",
      "2736",
      "2740",
      "2740",
      "2749",
      "2721",
      "2729",
      "2727",
      "2749",
      "4095",
      "2703",
      "2726",
      "2749"
    ],
    "od_90": [
      "0",
      "0",
      "0",
      "0",
      "0",
      "0",
      "0",
      "0",
      "0",
      "0",
      "0",
      "0",
      "65418",
      "0",
      "0",
      "0"
    ],
    "od_135": [
      "24541",
      "24364",
      "24256",
      "24424",
      "24382",
      "24441",
      "24283",
      "24417",
      "24430",
      "24384",
      "24418",
      "24370",
      "24374",
      "24574",
      "24387",
      "24378"
    ]
  }
}
Clone this wiki locally