New Websocket for registering to Item changes

I am currently working on a wall mounted touch wiz for Android. Therefore i added a new websocket method: rest/items to register for changes to all items. I would appreciate if somebody can test it or use it.

I will add that this was merged a few minutes ago and will be on cloudbees soon. If you currently use the endpoint /rest/items in your application it would be great to get feedback that this continues to work as expected (without web sockets).

1 Like

@querdenker2k:
Could you please update the wiki with what you changed so I can read up on it?
That would be very nice.

Thanks for reminder. Adding description to “Server-Push” Section.

Hey Guys. This is confusing. The wiki still says ‘websocket server-push does not work for /rest/items’ (“You do not get notifications from all items, item groups, or item states.”) On the other hand, the PR says it should work:

So does this thread, if I got this right. I’m currently running OpenHAB 1.8 from the .deb repo, and it does not seem to work. Is there an error on my side or is this just not implemented yet, even though the PR and this thread say so?

Perhaps you can clear up my confusion a bit here, thanks.

I added the PR and for me its working. I haven’t updated to 1.8, but the feature is still in the code so it should work.
This is some code which works for 1.7.1.

final String stateUrl = restUrl + ITEMS;

LOG.debug("creating websocket");

final AtmosphereClient client = ClientFactory.getDefault().newClient(AtmosphereClient.class);
final AtmosphereRequest request = client.newRequestBuilder()
        .uri(stateUrl)
        .header("Accept", MediaType.APPLICATION_JSON)
        .header("type", "json")
        .queryString("type", "json")
        .transport(Request.TRANSPORT.WEBSOCKET)
        .transport(Request.TRANSPORT.STREAMING)
        .transport(Request.TRANSPORT.LONG_POLLING)
        .build();
final Realm.RealmBuilder realmBuilder = new Realm.RealmBuilder();
if (this.username != null && this.password != null) {
    realmBuilder.setPrincipal(this.username)
            .setPassword(this.password)
            .setUsePreemptiveAuth(true)
            .setScheme(Realm.AuthScheme.BASIC);
}
final AsyncHttpClientConfig httpClientConfig = new AsyncHttpClientConfig.Builder()
        .setRealm(realmBuilder.build())
        .build();
final DefaultOptions options = client.newOptionsBuilder()
        .runtime(new AsyncHttpClient(httpClientConfig))
        .reconnect(false)
        .requestTimeoutInSeconds(Integer.MAX_VALUE)
        .build();

This is also not working for me. I’m trying from the atmosphere javascript library, using this code:

`

        var socket = $.atmosphere;
        var request = {
            url: "http://localhost:8080/rest/items?type=json",
            contentType: "application/json",
            header: {"Accept": "application/json"},
            trackMessageLength: true,
            shared: true,
            transport: 'websocket',
            fallbackTransport: 'long-polling'
        };

        request.onOpen = function () {
            console.info("opOpen");
        };

        request.onMessage = function (message) {
            console.info("onMessage", message);
            console.info(JSON.parse(message.responseBody));
        };

        var subSocket = socket.subscribe(request);

`

onMessage is never called, but if I switch the url to sitemaps, then I get results. I’m using the demo sitemaps and items. I’m using 1.8

Ok, i will update my server to 1.8 and test again with this version.

Thanks. If it helps, I’ve just taken the 1.8 core, applied the demo for 1.8, and used this code (using jquery atmosphere).

As an interesting side note, I noticed that when I subscribe to /rest/sitemaps and set type=json, it returned sitemap is chunked into a number of onMessage calls. This is due to the default max message size of atmosphere being 8kB. The problem is that you aren’t aware when the message has finished so you can’t reliably concat the messages together. I’ll probably increase the default max size, but something to keep in mind.

I’ve tested with 1.8 core and it still works fine.

Ok, I finally got this to work, using this code:

var socket = $.atmosphere;

var request = new $.atmosphere.AtmosphereRequest();

request.url = "http://localhost:8080/rest/items?type=json";
request.contentType = "application/json";
request.headers = {"Accept": "application/json", "type": "json"};
request.transport = 'websocket';
request.fallbackTransport = 'long-polling';

request.onOpen = function () {
   console.info("opOpen");
 };

 request.onMessage = function (message) {
   console.info("onMessage", message);
    console.info(message.responseBody);
 };

 var subSocket = socket.subscribe(request);

I’m not entirely sure why the other code i posted doesn’t work. The other thing that threw me was I was expecting the initial subscription to return the current state of all items, not for it to just send through updates after the subscription. I think it would be nice for the first subscription request to return the current state of all items, so that I don’t have to make a separate REST request to items. I’m sure that would prevent race conditions as well. Perhaps it should be an option on the query string, if that’s possible.

Hi Marc,

I would like to use server side push for a html page displaying some items and trying to reuse your code. unfortunately I am receiving an error:

TypeError: undefined is not an object (evaluating ‘new $.atmosphere.AtmosphereRequest’)

Any idea?

this my test html


<html>
<header><title>This is title</title></header>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
var socket = $.atmosphere;

var request = new $.atmosphere.AtmosphereRequest();

request.url = "http://localhost:8080/rest/items?type=json";
request.contentType = "application/json";
request.headers = {"Accept": "application/json", "type": "json"};
request.transport = 'websocket';
request.fallbackTransport = 'long-polling';

request.onOpen = function () {
   console.info("opOpen");
 };

 request.onMessage = function (message) {
   console.info("onMessage", message);
    console.info(message.responseBody);
 };

 var subSocket = socket.subscribe(request);

</script>
Hello world
</body>
</html>