SSE over REST-API

Hey there,

I just can´t establish a connection to the event stream through a JS Function.

This is the JS Code:

 function test_sse()
         {
         var eventSource = new EventSource("http://192.168.178.52:8080/rest/items/FEG_HZ_Ist/state");

         eventSource.addEventListener('message', function (eventPayload) {

             var event = JSON.parse(eventPayload.data);
             console.log(event.topic);
             console.log(event.type);
             console.log(event.payload);

             if (event.type === 'InboxAddedEvent') {
                 var discoveryResult = JSON.parse(event.payload);
                 console.log(discoveryResult.flag);
                 console.log(discoveryResult.label);
                 console.log(discoveryResult.thingUID);
             }
         });
         }

If I look in the console.log within firebug, there only the following Error occurs:

Firefox kann keine Verbindung zu dem Server unter http://192.168.178.52:8080/rest/items/FEG_HZ_Ist/state aufbauen.

In English:

Firefox could not establish a Connection to the Server http://http://192.168.178.52:8080/rest/items/FEG_HZ_Ist/state .

Could anyone give me a hint what am I Doing wrong?

Greetings Dominic

Update: I set the Log Leve to debug and now could log the error on the openhab2 side:

2017-01-01 16:44:38.853 [DEBUG] [io.rest.JSONResponse$ExceptionMapper] - exception during REST Handling
javax.ws.rs.NotAcceptableException: HTTP 406 Not Acceptable
	at org.glassfish.jersey.server.internal.routing.MethodSelectingRouter.getMethodRouter(MethodSelectingRouter.java:529)[156:org.glassfish.jersey.core.jersey-server:2.22.2]
	at org.glassfish.jersey.server.internal.routing.MethodSelectingRouter.access$000(MethodSelectingRouter.java:94)[156:org.glassfish.jersey.core.jersey-server:2.22.2]
	at org.glassfish.jersey.server.internal.routing.MethodSelectingRouter$4.apply(MethodSelectingRouter.java:779)[156:org.glassfish.jersey.core.jersey-server:2.22.2]
	at org.glassfish.jersey.server.internal.routing.MethodSelectingRouter.apply(MethodSelectingRouter.java:371)[156:org.glassfish.jersey.core.jersey-server:2.22.2]
	at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:109)[156:org.glassfish.jersey.core.jersey-server:2.22.2]
	at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:112)[156:org.glassfish.jersey.core.jersey-server:2.22.2]
	at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:112)[156:org.glassfish.jersey.core.jersey-server:2.22.2]
	at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:112)[156:org.glassfish.jersey.core.jersey-server:2.22.2]
	at org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:92)[156:org.glassfish.jersey.core.jersey-server:2.22.2]
	at org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:61)[156:org.glassfish.jersey.core.jersey-server:2.22.2]
	at org.glassfish.jersey.process.internal.Stages.process(Stages.java:197)[155:org.glassfish.jersey.core.jersey-common:2.22.2]
	at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:318)[156:org.glassfish.jersey.core.jersey-server:2.22.2]
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)[155:org.glassfish.jersey.core.jersey-common:2.22.2]
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)[155:org.glassfish.jersey.core.jersey-common:2.22.2]
	at org.glassfish.jersey.internal.Errors.process(Errors.java:315)[155:org.glassfish.jersey.core.jersey-common:2.22.2]
	at org.glassfish.jersey.internal.Errors.process(Errors.java:297)[155:org.glassfish.jersey.core.jersey-common:2.22.2]
	at org.glassfish.jersey.internal.Errors.process(Errors.java:267)[155:org.glassfish.jersey.core.jersey-common:2.22.2]
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)[155:org.glassfish.jersey.core.jersey-common:2.22.2]
	at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)[156:org.glassfish.jersey.core.jersey-server:2.22.2]
	at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)[156:org.glassfish.jersey.core.jersey-server:2.22.2]
	at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473)[153:org.glassfish.jersey.containers.jersey-container-servlet-core:2.22.2]
	at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)[153:org.glassfish.jersey.containers.jersey-container-servlet-core:2.22.2]
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)[153:org.glassfish.jersey.containers.jersey-container-servlet-core:2.22.2]
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341)[153:org.glassfish.jersey.containers.jersey-container-servlet-core:2.22.2]
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228)[153:org.glassfish.jersey.containers.jersey-container-servlet-core:2.22.2]
	at com.eclipsesource.jaxrs.publisher.internal.ServletContainerBridge.service(ServletContainerBridge.java:76)[11:com.eclipsesource.jaxrs.publisher:5.3.1.201602281253]
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:812)[79:org.eclipse.jetty.servlet:9.2.14.v20151106]
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:587)[79:org.eclipse.jetty.servlet:9.2.14.v20151106]
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:70)[170:org.ops4j.pax.web.pax-web-jetty:4.2.4]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)[78:org.eclipse.jetty.server:9.2.14.v20151106]
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)[77:org.eclipse.jetty.security:9.2.14.v20151106]
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)[78:org.eclipse.jetty.server:9.2.14.v20151106]
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)[78:org.eclipse.jetty.server:9.2.14.v20151106]
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:271)[170:org.ops4j.pax.web.pax-web-jetty:4.2.4]
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)[79:org.eclipse.jetty.servlet:9.2.14.v20151106]
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)[78:org.eclipse.jetty.server:9.2.14.v20151106]
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)[78:org.eclipse.jetty.server:9.2.14.v20151106]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)[78:org.eclipse.jetty.server:9.2.14.v20151106]
	at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:80)[170:org.ops4j.pax.web.pax-web-jetty:4.2.4]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)[78:org.eclipse.jetty.server:9.2.14.v20151106]
	at org.eclipse.jetty.server.Server.handle(Server.java:499)[78:org.eclipse.jetty.server:9.2.14.v20151106]
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)[78:org.eclipse.jetty.server:9.2.14.v20151106]
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)[78:org.eclipse.jetty.server:9.2.14.v20151106]
	at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)[70:org.eclipse.jetty.io:9.2.14.v20151106]
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)[81:org.eclipse.jetty.util:9.2.14.v20151106]
	at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)[81:org.eclipse.jetty.util:9.2.14.v20151106]
	at java.lang.Thread.run(Thread.java:745)[:1.8.0_40-internal]
201

Is there anyone who could help?

Thanks for bring the topic up. I am also interested in this for some time.
Maybe you could try to change the url of eventSource

var eventSource = new EventSource(“http://192.168.178.52:8080/rest/rest/events?topics=smarthome/items/FEG_HZ_Ist/state”);

Hi Martin!

Thank you for replying. For sadness your URL also does not work: I get an 404 Not Found Error now.

But your hint was although very helpful. The following URL now gives me all events:
var eventSource = new EventSource("http://192.168.178.52:8080/rest/events");

Do you have an idea how I could delimit the events on one or more specified items and only next to updated Items?

Greetings Dominic

I have just realized that I had a typo in my url

http://192.168.178.52:8080/rest/events?topics=smarthome/items/FEG_HZ_Ist/state

try using the one above

I have test a bit further.
It seems that under Safari the described function is working but NOT under chrome nor Firefox it is not.

From Chrome it is also working as far as I can see.

What maybe is hampering is the authorization ( check if you see in the developers tab a “No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://zzz’ is therefore not allowed access.” errors)

Putting very basic example in the html folder of openhab2 will give you results in a filtered way (replace with your item)

<!DOCTYPE html>
<html>
<body>
<h1>Getting server updates</h1>
<div id="result"></div>
<script>
if(typeof(EventSource) !== "undefined") {
    var source = new EventSource("http://192.168.3.50:8080/rest/events?topics=smarthome/items/ReigerPowerAbsWd/state");
    source.onmessage = function(event) {
        document.getElementById("result").innerHTML += event.data + "<br>";
    };
} else {
    document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
}
</script>
</body>
</html>
1 Like

To get rid of “No ‘Access-Control-Allow-Origin’ you have to edit “service.cfg” under runtime and add the line
"org.eclipse.smarthome.cors:enable=true”.

Then SSE is working on all browsers I have tested.

Hey there,

thank you very much. The combination of both solutions does work.

Just one question to @marcel_verpaalen : if I just want to get the state element - how would I have to change your code? I tried

document.getElementById("result").innerHTML = event.data.state + "<br>"; and
document.getElementById("result").innerHTML += event.state + "<br>";

but both gives me “undefined”.

Sound I use a json parser?

You mean something like this:

This filters only state events and parses the data (and puts it in a table). I think you indeed need to use the jsonparser

<!DOCTYPE html>
<html>
<head>
<style> table, td {border: 1px solid black;} </style>
</head>
<body>

<h1>Getting Openhab server updates</h1>

<div id="result"></div>
<table id="myTable">
  <tr>
    <th>Topic</th>
	<th>Value</th>
    <th>Type</th> 
    <th>Payload</th>
  </tr>
</table>
<br>

<script>
if(typeof(EventSource) !== "undefined") {
    var source = new EventSource("http://192.168.3.50:8080/rest/events?topics=smarthome/items/ReigerPowerAbsWd/state");
    source.onmessage = function(eventPayload) {
        <!--document.getElementById("result").innerHTML += eventPayload.data + "<br>"; -->
		var event = JSON.parse(eventPayload.data);
		if (event.type == "ItemStateEvent") {
			var stateData = JSON.parse(event.payload);
			var table = document.getElementById("myTable");
			var row = table.insertRow(1);
			var cell1 = row.insertCell(0);
			var cell2 = row.insertCell(1);
			var cell3 = row.insertCell(2);
			var cell4 = row.insertCell(3);
			cell1.innerHTML = event.topic;
			cell2.innerHTML = stateData.value;
			cell3.innerHTML = event.type;
			cell4.innerHTML = event.payload;
		};
	};
} else {
    document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
}
</script>
</body>
</html>

thank you very much! that´s it!

Hey there again,

Just another question:

If i would like to connect to the event Stream and get events for more then just 1device- what whoud be the best way? Should i open many single event connections or is there a better way?

Perhaps I have to describe it a little bit further:

Th following Code gives me an event stream for one Device / Item.

var eventSource = new EventSource("http://192.168.178.52:8080/rest/events?topics=smarthome/items/GEG_HZ_Ist/state");

    eventSource.addEventListener('message', function (eventPayload) {

        var event = JSON.parse(eventPayload.data);  
        if (event.type === 'ItemStateEvent') {
            var Result = JSON.parse(event.payload);
            console.log(Result.value);
       
    }
});

If I would change the line

var eventSource = new EventSource("http://192.168.178.52:8080/rest/events?topics=smarthome/items/GEG_HZ_Ist/state");

to

var eventSource = new EventSource("http://192.168.178.52:8080/rest/events?topics=smarthome/items/*/state");

i will get lot of values. How could I use this values seperatly? Or in other words: If there are three values in the Stream (1,2,3) for three Devices (A,B,C) how could I take the pair “B2” to use it further in my html code?

@marcel_verpaalen: @Marty56 : It would be great, if you could help me again.

Greetings Dominic

Sorry, have no experience with that approach.
Guess it will be trial & error if no body knows

hey there,

i have some working code for now. But because i´m a newbie to javascript the code is for sure not optimized.
In my example tyou can see the code for getting the events for 2 devices.

Could someone please have a look at the code?

<script>



var eventSource = new EventSource("http://192.168.178.52:8080/rest/events");

eventSource.addEventListener('message', function (eventPayload) {

    var event = JSON.parse(eventPayload.data);
    
    if ((event.type == 'ItemStateEvent') && (event.topic="smarthome/items/GEG_HZ_Soll/state"))
    
    {
    
    var GEG_HZ_Soll = JSON.parse(event.payload);
    console.log(GEG_HZ_Soll.value);

    }
    
    
    
      if ((event.type == 'ItemStateEvent') && (event.topic="smarthome/items/GEG_HZ_Ist/state"))
    
    {
    
    var GEG_HZ_Ist = JSON.parse(event.payload);
    console.log(GEG_HZ_Ist.value);

    }
    
    
    
});














</script>

Hi,

i just worked on exactly that topic for the vscode-extension:

You can find a bit more about using SSE here:

In the event method i parse the incoming events.

You can use ‘/rest/events?topics=smarthome/items’ to only get item events. With rest/events you will get all other events as well.

Sorry for being a bit late with my reply, i just noticed, that the last post here is ~2years ago :sweat_smile:

Thank you Marcel, this is a very useful example!

All the endpoints can be found here in the documentation
https://www.eclipse.org/smarthome/documentation/features/events.html
Johannes

Good Day Guys
Just a quick question regarding the REST API, Is there any way to pass an event origin parameter to rest API and get it back from the event streaming API. What I want to do is differentiate the events coming from openhab and connected devices vs events coming back form the updates I sent from REST to avoid loops.
Cheers
Roshan

I am desperate. I have tried everything possible, but I never get a message about my event source.
Do I need to activate anything in openhab? I am running openhabian, on a Raspberry 4, in the latest version.

I do not receive an error message. The HTTP-Request is built and kept open. See picture.

This is the Code.

Does anybody have an idea?

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>EventSource</title>
</head>

<body>
	<div id="result"></div>


    </script>
<script>
if(typeof(EventSource) !== "undefined") {
    var source = new EventSource("http://192.168.178.56:8080/rest/events?topics=smarthome/items");
    source.onmessage = function(event) {
        document.getElementById("result").innerHTML += event.data + "<br>";
		console.log(event);
    };
} else {
    document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
}
</script>
</body>

</html>