Skip to content

User interface and server message handler

meguiraun edited this page Nov 10, 2015 · 4 revisions

Extend the existing messaging system to the web. Flask-socketIO (websockets) can be used to send the pydispatcher’s signals to Javascript functions. It is also possible to define different namespaces over a single websocket. Flask-SocketIO transparently downgrades itself for older browsers that don’t have WebSocket, SocketIO emulates the connection using one of the older solutions, the best one available for each given client.

Two kind of signals:

  • Signal from HO to HO (hidden for the user, so no action is required)
  • Signals from HO to User interface

In any case, whenever a signal is intercepted for sending to the ui, it must fulfill a generic structure (see below), in order to ease the data retrieval in the web interface.

The implementation is done [here] (https://github.com/mxcube/mxcube3/blob/master/mxcube3/routes/signals.py) and starts with the socketio imports:

from flask.ext.socketio import emit

Then, all the signals we are interested on sending to the web interface are defined,

MaxLabMicrodiff_signals = ['minidiffReady','centringStarted','centringSuccessful', 'diffractometerMoved', ...]

And the signal callback is defined (here it is simplified):

def signalCallback(*args, **kwargs):
    sender = str(kwargs['sender'].__class__).split('.')[0] # to get the origin of the signal, e.g. MicroDiff, ...
    signal = kwargs['signal'] # e.g. 'phiyMotorStateChanged' ...
    if args[0] in MaxLabMicrodiff_signals: #some messages contain data
            msg = {'data':'no data', 'signal': args[0],'sender':sender}
        else:
            msg = {'data':json.dumps(args), 'signal': signal,'sender':sender}

    socketio.emit('newSignal',msg , namespace='/test') #and finally propagate the message

But, we still need to link the callback with the hardware object. Which means adding self.someHO.connect(hw_obj, 'aSignal', 'aCallback') for each message we want to propagate to the user interface.

However, in roures.signals.py there is not any hw_obj defined so we need to add that line where the hw_obj is defined. Currently in routes.SampleCentring.py we propagate the signals generated in the diffractometer with the following lines:

import signals

for signal in signals.MaxLabMicrodiff_signals:
    mxcube.diffractometer.connect(mxcube.diffractometer,signal, signals.signalCallback4)

From this point onwards, any time a signal is generated in the diffractometer it will be propagated through the websocket. But that does not mean that anyone is listening to that! For that we need a bit of javascript in the web interface.

In [js.Functions.jsx] (https://github.com/mxcube/mxcube3/blob/master/mxcube3/js/SampleView/Functions.jsx) there is some initialization code. We are interested in these lines:

var socket = io.connect('http://' + document.domain + ':' + location.port+'/test');// + namespace);
socket.on('newSignal', function(msg) {
    //do something with the message, popup a modal, append to the log field,...
}

Where 'newSignal' is the signal name that was emitted in socketio.emit, and 'test' is the namespace. With these parameters one can filter the the incoming messages. Currently, all the messages go to the log field in the interface and the 'centringSuccesful' message opens a modal window.

A more detailed message/signal/namespace filtering will be required in the future as well as determine which are the messages we should propagate, probably not all of them are needed for the user.

Example of messages received in the web interface (and appended to the log file):

04/11/2015 12:52:43 #MaxLabMicrodiff::progressMessage::Data: ["Starting automatic centring procedure..."]
04/11/2015 12:52:43 #MaxLabMicrodiff::progressMessage::Data: ["Loop found: Coord (215, 252)"]
04/11/2015 12:52:43 #MaxLabMicrodiff::newAutomaticCentringPoint::Data: [215, 252]
04/11/2015 12:52:43 #MaxLabMicrodiff::progressMessage::Data: ["Doing automatic centring"]
04/11/2015 12:52:43 #MaxLabMicrodiff::progressMessage::Data: ["Loop found: Coord (214, 254)"]
04/11/2015 12:52:43 #MaxLabMicrodiff::newAutomaticCentringPoint::Data: [214, 254]
04/11/2015 12:52:45 #MaxLabMicrodiff::progressMessage::Data: ["Loop found: Coord (226, 231)"]
04/11/2015 12:52:45 #MaxLabMicrodiff::newAutomaticCentringPoint::Data: [226, 231]
04/11/2015 12:52:46 #MaxLabMicrodiff::progressMessage::Data: ["Loop found: Coord (240, 242)"]
04/11/2015 12:52:46 #MaxLabMicrodiff::newAutomaticCentringPoint::Data: [240, 242]
04/11/2015 12:52:48 #MaxLabMicrodiff::sampyMotorStateChanged::Data: [4]
04/11/2015 12:52:48 #MaxLabMicrodiff::phizMotorStateChanged::Data: [4]
04/11/2015 12:52:48 #MaxLabMicrodiff::phizMotorStateChanged::Data: [2]
04/11/2015 12:52:48 #MaxLabMicrodiff::sampxMotorStateChanged::Data: [4]
04/11/2015 12:52:48 #MaxLabMicrodiff::phiyMotorStateChanged::Data: [4]
04/11/2015 12:52:48 #MaxLabMicrodiff::sampyMotorStateChanged::Data: [2]
04/11/2015 12:52:49 #MaxLabMicrodiff::phiyMotorStateChanged::Data: [2]
04/11/2015 12:52:49 #MaxLabMicrodiff::sampxMotorStateChanged::Data: [2]
04/11/2015 12:52:49 #MaxLabMicrodiff::progressMessage::Data: ["Doing automatic centring"]
04/11/2015 12:52:49 #MaxLabMicrodiff::progressMessage::Data: ["Loop found: Coord (345, 239)"]
04/11/2015 12:52:49 #MaxLabMicrodiff::newAutomaticCentringPoint::Data: [345, 239]
04/11/2015 12:52:51 #MaxLabMicrodiff::progressMessage::Data: ["Loop found: Coord (342, 247)"]
04/11/2015 12:52:51 #MaxLabMicrodiff::newAutomaticCentringPoint::Data: [342, 247]
04/11/2015 12:52:52 #MaxLabMicrodiff::progressMessage::Data: ["Loop found: Coord (335, 242)"]
04/11/2015 12:52:52 #MaxLabMicrodiff::newAutomaticCentringPoint::Data: [335, 242]
04/11/2015 12:52:54 #MaxLabMicrodiff::sampyMotorStateChanged::Data: [4]
04/11/2015 12:52:54 #MaxLabMicrodiff::phizMotorStateChanged::Data: [4]
04/11/2015 12:52:54 #MaxLabMicrodiff::sampxMotorStateChanged::Data: [4]
04/11/2015 12:52:54 #MaxLabMicrodiff::phiyMotorStateChanged::Data: [4]
04/11/2015 12:52:54 #MaxLabMicrodiff::phizMotorStateChanged::Data: [2]
04/11/2015 12:52:54 #MaxLabMicrodiff::sampyMotorStateChanged::Data: [2]
04/11/2015 12:52:54 #MaxLabMicrodiff::phiyMotorStateChanged::Data: [2]
04/11/2015 12:52:54 #MaxLabMicrodiff::sampxMotorStateChanged::Data: [2]
04/11/2015 12:52:55 #MaxLabMicrodiff::progressMessage::Data: [""]
04/11/2015 12:52:55 #MaxLabMicrodiff::newAutomaticCentringPoint::Data: [-1, -1]
04/11/2015 12:52:55 #MaxLabMicrodiff::centringSuccessful::Data: [null, {"valid": true, "motors": {"sampx": 0.24454231800511531, "sampy": -0.37840437420521589, "phi": 359.99990000000253, "kappa": 0.0015625125024403275, "kappa_phi": 0.0, "focus": -0.6409042976997994, "phiz": 0.083846283650123254, "phiy": 0.043114907325533469}, "method": null, "endTime": "2015-11-04 12:38:46"}]