Server Sent Event. Is it possible?

Dear Community,

I’m trying to figure out how to use server sent events to enable instant updates for my Web Dashboard. If I figure this out it would be a great feature to enable instant updates!

From what I researched and tried, it seems that it is not possible, since request time is limited to 20 seconds. Maybe I’m missing something obvious?

I tried to follow this tutorial. At the example below, when I hit the endpoint I get one event reaching the browser, as expected.

def stream() {
    render contentType: "text/event-stream", data: "id: ${now()}\nretry: 10000\ndata: stream ${getTS()}\n\n"
}

If I change the endpoint above to this, then there are 5 debug statements in my console, then the method times out. I have no events reaching the browser.

def stream() {
    for (def i = 0; i < 10 ; i++ )  {
        log.debug "stream $i"
        render contentType: "text/event-stream", data: "id: ${now()}\nretry: 60000\ndata: stream $i ${getTS()}\n\n"
        pause(3000)
    }
}

I would appreciate if someone could shed any light on this. I’m either very close or it’s impossible.

1 Like

@bflorian do you have any input on this?

The actual send from the stream() mapping callback is done when the rendered content is return’ed from the stream function. In the first case, the rendered content created by the render command is returned automatically because it is the last line in the function (crazy, obscure groovy). In the second case, nothing is returned from the function as it times out, so nothing is sent to the website.

Looks like what is needed is the ability to send the message back at the time we want and not just when that callback returns. I’m not sure if the information needed is available in the params variable or not. You could try adding this line to your callback to see if it has any of the caller info:

debugEvent ("stream callback: $params", true)

I’m not at home to actually try it with one of my apps.

There is no such function debugEvent, unless the syntax above is wrong.

Looking at the params argument does not give anything of value.

I pulled that function call from the Ecobee (Connect) SmartApp available from the IDE. It was used in the swapToken() function there. I don’t know if it will actually give any more useful info than just printing the params object though which it sounds like you’ve already done.

Maybe @Ben can give some suggestions from their dev side of how they would approach this problem internally? We have to speculate on how things we do would affect performance of their system, and this type of system could obviously cause a lot of load depending on the implementation.

It’s not enough to just render a page with the right content type. The server needs to actually keep the connection open indefinitely.

As far as I know, SmartThings only provides a REST endpoint. There isn’t a way for you to use WebSockets or even Server Sent Events. There is still a chance that this is just completely undocumented, undiscovered functionality that is already provided, but I wouldn’t hold my breath for it.

Maybe you can come up with some form of true long polling. Not sure how you would do it without executing at least the REST callback, or the event handlers asynchronously.

Lastly, you could just try banging on the REST endpoint every second or so. Possibly have a GET handler called /hasnewevents to act as a very lightweight gating mechanism before you trigger a full refresh on the client side. Not sure to what degree the ST cloud will tolerate this, though.

EDIT: The lack of SSE or WebSockets btw is exactly why I did it this way with having the app backend live on a remote host that is easily reachable by the SmartApp.

1 Like

That’s what I’m hoping for, that there is something undiscovered, because the documentation is just the tip of the iceberg.

I attempted long polling, but the connection terminates after 20 second. So true polling is not possible I believe. I think this also implies that SSE is not possible either because that would require a longer active connection.

I would like to avoid banging on the ST cloud too frequently. I think this is a very crude way of doing it, but it seems that this is the only way to go.

The whole point of my approach is not to use any third party services for zero out-of-app configuration.

Thanks for input!

There is currently no support for streaming or WebSockets from SmartApps at this time. If your app has its own back-end server you could have it maintain stream and post events to it from SmartThings. I understand why you’d like to avoid having to do that, and we will take this requirement into consideration as we plan future updates to the platform, but I can’t commit to any time frame for this capability at this point.

Thank you. Please consider it as it would open a lot of doors.

1 Like

@bflorian: Please do. Another +1 from me, and I know there have been other threads on the discussion board with the same feature request.