The WebSocket callbacks in Java

The WebSocket callbacks in Java

Last week we published a preview of our Java and Javascript library with WebSocket support. This week we have updated our RSS feed reader example in Java, which was using the classical HTTP Callback. We have now made it interactive with the help of WebSockets.





The original version of this RSS reader uses a Yocto-MaxiDisplay and a YoctoHub-Ethernet. The YoctoHub-Ethernet is configured to use an HTTP Callback to connect to a Java application server. The server fetches the content of the RSS feed and creates an animation which displays the titles of the RSS articles. This animation is stored on the flash memory of the Yocto-MaxiDisplay and is played in loop. This work very well but has a strong limitation: It's not interactive. The user cannot choose which feed to display, nor force a feed refresh.

This limitation is inherent to the way the HTTP Callback works. An HTTP Callback always execute the following steps, in the same order:

  1. Establishing a connexion
  2. Request
  3. Response
  4. Closing the connexion

It's not possible to keep the connexion open and send commands periodically. All the commands sent by the Java API are interpreted in block. It is possible to trigger a callback each time a button of the Yocto-MaxiDisplay is pressed, but this does not work very well for interactive behaviors: the latency due to the creation of a new HTTP connection makes the interface too laggy to be usable.

Using WebSockets


Fortunately, this limitation does not exists with WebSocket callbacks. With WebSockets, it is now possible to keep an fully bidirectional connection open indefinitely.

With WebSockets, the API works in the exact same way wether in client mode or in callback mode. In both cases the commands are sent immediately to the Yoctopuce module. The YoctoHub notifications are also sent immediately to the API. To sum up, except for the RegisterHub() command, the same code can be used for a simple command line application or for a callback.

The code


The first step is to write a class that implements the endpoint which will respond to the URL /wscallback. During the connection, the method onOpen() is called by the server. The code instantiates a WebSockRSSReader object and pass the Session of the current connexion. Then the code of the WebSockRSSReader is executed in his own thread. This is the only method to implement for the Java application server: we do not need to implement message handler since the Yoctopuce library will do it automatically. The class WebSockRSSReader implements the logic of our application.

@ServerEndpoint("/wscallback")
public class WebSocketEndpoint
{
    @OnOpen
    public void onOpen(final Session session)
    {
        // on each connection start a new thread that will execute the code
        Thread thread = new Thread(new WebSockRSSReader(session));
        thread.start();
    }
}


Since our RSS reader is executed in its own thread, it needs to create and use its own YAPIContext instead of using the global YAPI Class. Indeed, similarly to HTTP Callbacks, all incoming connexions to the Java server are handled in the same process. This implies that all connections share the same memory space. If we would have used the methods of the YAPI class, all devices of all concurrent connections would be mixed together in a single environment. By using a connection-specific YAPIContext, we prevent devices from other connexions to "pollute" our inventory. Instances of YAPIContext implement the exact same methods as the YAPI class: you only need to replace any YAPI.xxx() call by a call to _yctx.xxx().

The first step is to register the YoctoHub which has triggered the connexion to the Java Server. This is done with the RegisterHubWebSocketCallback method. The method takes the session of the connexion as parameter. This allow the library to send and receive packets to the YoctoHub.

From this point on, it's possible to use the Yoctopuce API without any limitation, as if the application was started from a command line with a direct connection.

public class WebSockRSSReader implements Runnable
{
    private YAPIContext _yctx;
    private final Session _session;

    public WebSockRSSReader(Session session)
    {
        _session = session;
    }

    public void run()
    {
        _yctx = new YAPIContext();
        try {
            _yctx.RegisterHubWebSocketCallback(_session);
            setupYoctoDisplay();
            // run while WebSocket is connected
            while (_session.isOpen()) {
                if (checkForNewArticles()) {
                    refreshDisplay();
                }
                _yctx.Sleep(1000);
            }
        } catch (YAPI_Exception e) {
            e.printStackTrace();
        }
        _yctx.FreeAPI();
    }
    ...


Value change callbacks in a WebSocket Callback


Since the communication is in full duplex, it's possible to register a value change callback in Java to handle efficiently the button state changes.

The method setupYoctoDisplay initializes the screen and registers a callback for each button with the method registerValueCallback. This callback will be called as soon as a button is pressed or released. The callback is used to change the index of the article to display, and to force a repaint of the Yocto-MaxiDisplay.

    private void setupYoctoDisplay() throws YAPI_Exception
    {
        _display = YDisplay.FirstDisplayInContext(_yctx);
        // reset screen
        _display.resetAll();

        YModule module = _display.module();
        String serial = module.get_serialNumber();

        YAnButton left = YAnButton.FindAnButtonInContext(_yctx,
                              serial + ".anButton1");
        left.registerValueCallback(new YAnButton.UpdateCallback()
        {
            public void yNewValue(YAnButton button, String value)
            {
                if (debounce(button, value) == 1) {
                    if (_itemIndex > 0) {
                        _itemIndex -= 1;
                        refreshDisplay();
                    }
                }
            }
        });
        //do the same for others buttons
        ...
    }
    ...
}


The method checkForNewArticles checks if the RSS feeds have been updated, and the method refreshDisplay displays the article specified by the variable _itemIndex on the Yocto-MaxiDisplay.

The source code of this example can be found on GitHub: http://github.com/yoctopuce-examples/websocket_preview

  
Demo time..



Conclusion


WebSockets can bypass the limitations of the Callback HTTP mode. It is now possible to build sophisticated Yoctopuce applications in callback mode.

Add a comment No comment yet Back to blog












Yoctopuce, get your stuff connected.