Snapcast Binding

Hi! Sorry to resurrect a dead thread. Is this binding still being maintained? I have multiple instances of Snapclient running on machine and it seems to break this binding. I am able to find the SnapServer and Clients, but they are always Offline - Communication_Error.

Looking at the console, I see this error:

16:54:37.711 [ERROR] [internal.DiscoveryServiceRegistryImpl] - Cannot trigger scan for thing types '[snapcast:client]' on 'ClientDiscoveryService'!

java.lang.IllegalArgumentException: ID segment 'b827eb86c43c#2' contains invalid characters. Each segment of the ID must match the pattern [A-Za-z0-9_-]*.

at org.eclipse.smarthome.core.common.AbstractUID.validateSegment(AbstractUID.java:97) ~[133:org.openhab.core:2.5.0.M4]

at org.eclipse.smarthome.core.common.AbstractUID.<init>(AbstractUID.java:75) ~[133:org.openhab.core:2.5.0.M4]

at org.eclipse.smarthome.core.common.AbstractUID.<init>(AbstractUID.java:58) ~[133:org.openhab.core:2.5.0.M4]

at org.eclipse.smarthome.core.thing.UID.<init>(UID.java:57) ~[185:org.openhab.core.thing:2.5.0.M4]

at org.eclipse.smarthome.core.thing.ThingUID.<init>(ThingUID.java:54) ~[185:org.openhab.core.thing:2.5.0.M4]

at org.openhab.binding.snapcast.internal.discovery.ClientDiscoveryService.getThingUID(ClientDiscoveryService.java:79) ~[?:?]

at org.openhab.binding.snapcast.internal.discovery.ClientDiscoveryService.discover(ClientDiscoveryService.java:66) ~[?:?]

at org.openhab.binding.snapcast.internal.discovery.ClientDiscoveryService.startScan(ClientDiscoveryService.java:51) ~[?:?]

at org.eclipse.smarthome.config.discovery.AbstractDiscoveryService.startScan(AbstractDiscoveryService.java:209) ~[139:org.openhab.core.config.discovery:2.5.0.M4]

at org.eclipse.smarthome.config.discovery.internal.DiscoveryServiceRegistryImpl.startScan(DiscoveryServiceRegistryImpl.java:382) [139:org.openhab.core.config.discovery:2.5.0.M4]

at org.eclipse.smarthome.config.discovery.internal.DiscoveryServiceRegistryImpl.startScans(DiscoveryServiceRegistryImpl.java:358) [139:org.openhab.core.config.discovery:2.5.0.M4]

at org.eclipse.smarthome.config.discovery.internal.DiscoveryServiceRegistryImpl.startScan(DiscoveryServiceRegistryImpl.java:216) [139:org.openhab.core.config.discovery:2.5.0.M4]

at org.eclipse.smarthome.io.rest.core.internal.discovery.DiscoveryResource.scan(DiscoveryResource.java:97) [153:org.openhab.core.io.rest.core:2.5.0.M4]

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]

at java.lang.reflect.Method.invoke(Method.java:498) ~[?:?]

at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81) [125:org.glassfish.jersey.core.jersey-server:2.22.2]

at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144) [125:org.glassfish.jersey.core.jersey-server:2.22.2]

at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161) [125:org.glassfish.jersey.core.jersey-server:2.22.2]

at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160) [125:org.glassfish.jersey.core.jersey-server:2.22.2]

at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99) [125:org.glassfish.jersey.core.jersey-server:2.22.2]

at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389) [125:org.glassfish.jersey.core.jersey-server:2.22.2]

at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347) [125:org.glassfish.jersey.core.jersey-server:2.22.2]

at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102) [125:org.glassfish.jersey.core.jersey-server:2.22.2]

at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326) [125:org.glassfish.jersey.core.jersey-server:2.22.2]

at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271) [124:org.glassfish.jersey.core.jersey-common:2.22.2]

at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267) [124:org.glassfish.jersey.core.jersey-common:2.22.2]

at org.glassfish.jersey.internal.Errors.process(Errors.java:315) [124:org.glassfish.jersey.core.jersey-common:2.22.2]

at org.glassfish.jersey.internal.Errors.process(Errors.java:297) [124:org.glassfish.jersey.core.jersey-common:2.22.2]

at org.glassfish.jersey.internal.Errors.process(Errors.java:267) [124:org.glassfish.jersey.core.jersey-common:2.22.2]

at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317) [124:org.glassfish.jersey.core.jersey-common:2.22.2]

at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305) [125:org.glassfish.jersey.core.jersey-server:2.22.2]

at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154) [125:org.glassfish.jersey.core.jersey-server:2.22.2]

at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473) [122:org.glassfish.jersey.containers.jersey-container-servlet-core:2.22.2]

at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427) [122:org.glassfish.jersey.containers.jersey-container-servlet-core:2.22.2]

at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388) [122:org.glassfish.jersey.containers.jersey-container-servlet-core:2.22.2]

at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341) [122:org.glassfish.jersey.containers.jersey-container-servlet-core:2.22.2]

at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228) [122:org.glassfish.jersey.containers.jersey-container-servlet-core:2.22.2]

at com.eclipsesource.jaxrs.publisher.internal.ServletContainerBridge.service(ServletContainerBridge.java:76) [20:com.eclipsesource.jaxrs.publisher:5.3.1.201602281253]

at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:873) [90:org.eclipse.jetty.servlet:9.4.18.v20190429]

at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:542) [90:org.eclipse.jetty.servlet:9.4.18.v20190429]

at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:71) [194:org.ops4j.pax.web.pax-web-jetty:7.2.10]

at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146) [89:org.eclipse.jetty.server:9.4.18.v20190429]

at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548) [87:org.eclipse.jetty.security:9.4.18.v20190429]

at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) [89:org.eclipse.jetty.server:9.4.18.v20190429]

at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257) [89:org.eclipse.jetty.server:9.4.18.v20190429]

at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1700) [89:org.eclipse.jetty.server:9.4.18.v20190429]

at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255) [89:org.eclipse.jetty.server:9.4.18.v20190429]

at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1345) [89:org.eclipse.jetty.server:9.4.18.v20190429]

at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:293) [194:org.ops4j.pax.web.pax-web-jetty:7.2.10]

at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203) [89:org.eclipse.jetty.server:9.4.18.v20190429]

at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:480) [90:org.eclipse.jetty.servlet:9.4.18.v20190429]

at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1667) [89:org.eclipse.jetty.server:9.4.18.v20190429]

at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201) [89:org.eclipse.jetty.server:9.4.18.v20190429]

at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1247) [89:org.eclipse.jetty.server:9.4.18.v20190429]

at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144) [89:org.eclipse.jetty.server:9.4.18.v20190429]

at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:80) [194:org.ops4j.pax.web.pax-web-jetty:7.2.10]

at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) [89:org.eclipse.jetty.server:9.4.18.v20190429]

at org.eclipse.jetty.server.Server.handle(Server.java:505) [89:org.eclipse.jetty.server:9.4.18.v20190429]

at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:370) [89:org.eclipse.jetty.server:9.4.18.v20190429]

at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:267) [89:org.eclipse.jetty.server:9.4.18.v20190429]

at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305) [80:org.eclipse.jetty.io:9.4.18.v20190429]

at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) [80:org.eclipse.jetty.io:9.4.18.v20190429]

at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117) [80:org.eclipse.jetty.io:9.4.18.v20190429]

at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333) [92:org.eclipse.jetty.util:9.4.18.v20190429]

at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:310) [92:org.eclipse.jetty.util:9.4.18.v20190429]

at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168) [92:org.eclipse.jetty.util:9.4.18.v20190429]

at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126) [92:org.eclipse.jetty.util:9.4.18.v20190429]

at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366) [92:org.eclipse.jetty.util:9.4.18.v20190429]

at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:698) [92:org.eclipse.jetty.util:9.4.18.v20190429]

at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:804) [92:org.eclipse.jetty.util:9.4.18.v20190429]

at java.lang.Thread.run(Thread.java:748) [?:?]

same here canā€™t connect to the snapserverā€¦

ok I found the problem. I use two snapclients on the same device with #1 und #2 so my ID Adresse in the things file has a #1 or #2 at the end and the plugin did not like this. So I had to start one client with a preset ID with the option ā€œā€“hostIDā€ and now it works.

OH 3.0 is released and I like to ask if someone is able to port the binding to OH3.0. I heard from another binding that it is not to hard to do. So it needs not many changes but I canā€™t do it I have no idea how to do that.

by the way here is the log output when putting the jar file into the addon folder:

10:23:30.551 [WARN ] [org.apache.felix.fileinstall         ] - Error while starting bundle: file:/usr/share/openhab/addons/org.openhab.binding.snapcast-2.5.0-SNAPSHOT.jar
org.osgi.framework.BundleException: Could not resolve module: org.openhab.binding.snapcast [327]
  Unresolved requirement: Import-Package: org.eclipse.jdt.annotation; resolution:="optional"
  Unresolved requirement: Import-Package: org.eclipse.smarthome.config.core

        at org.eclipse.osgi.container.Module.start(Module.java:444) ~[org.eclipse.osgi-3.12.100.jar:?]
        at org.eclipse.osgi.internal.framework.EquinoxBundle.start(EquinoxBundle.java:383) ~[org.eclipse.osgi-3.12.100.jar:?]
        at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundle(DirectoryWatcher.java:1260) [bundleFile:3.6.4]
        at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundles(DirectoryWatcher.java:1233) [bundleFile:3.6.4]
        at org.apache.felix.fileinstall.internal.DirectoryWatcher.startAllBundles(DirectoryWatcher.java:1221) [bundleFile:3.6.4]
        at org.apache.felix.fileinstall.internal.DirectoryWatcher.doProcess(DirectoryWatcher.java:515) [bundleFile:3.6.4]
        at org.apache.felix.fileinstall.internal.DirectoryWatcher.process(DirectoryWatcher.java:365) [bundleFile:3.6.4]
        at org.apache.felix.fileinstall.internal.DirectoryWatcher.run(DirectoryWatcher.java:316) [bundleFile:3.6.4]
10:23:30.557 [WARN ] [org.apache.felix.fileinstall         ] - Error while starting bundle: file:/usr/share/openhab/addons/org.openhab.binding.snapcast-2.5.0-SNAPSHOT.jar
org.osgi.framework.BundleException: Could not resolve module: org.openhab.binding.snapcast [327]
  Unresolved requirement: Import-Package: org.eclipse.jdt.annotation; resolution:="optional"
  Unresolved requirement: Import-Package: org.eclipse.smarthome.config.core

        at org.eclipse.osgi.container.Module.start(Module.java:444) ~[org.eclipse.osgi-3.12.100.jar:?]
        at org.eclipse.osgi.internal.framework.EquinoxBundle.start(EquinoxBundle.java:383) ~[org.eclipse.osgi-3.12.100.jar:?]
        at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundle(DirectoryWatcher.java:1260) [bundleFile:3.6.4]
        at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundles(DirectoryWatcher.java:1233) [bundleFile:3.6.4]
        at org.apache.felix.fileinstall.internal.DirectoryWatcher.doProcess(DirectoryWatcher.java:520) [bundleFile:3.6.4]
        at org.apache.felix.fileinstall.internal.DirectoryWatcher.process(DirectoryWatcher.java:365) [bundleFile:3.6.4]
        at org.apache.felix.fileinstall.internal.DirectoryWatcher.run(DirectoryWatcher.java:316) [bundleFile:3.6.4]

Andy

I guess nobody is maintaining it so Iā€™ve updated the plugin for 3.0:

org.openhab.binding.snapcast-3.1.0-SNAPSHOT.jar

@StbX Iā€™ve also updated it for the new build Bnd system, and I can try to work a bit more on the code review comments, so it might be merged, as long as you donā€™t mind.

3 Likes

wow thx a lot! It works as expected!
How hard is it to maintain this binding, and how hard was it to update it from 2.5 to 3.0?

Iā€™m just asking since my system relies on the snapcast binding (I use a NEEO Remote which can control all the snapcast clients). In the meantime I made a solution with EXEC and some python scripts which work but are not very neat.

2.5 to 3.0 was easy, it only needed a couple of renames. It took me a bit of time to get to know it and to convert the binding to use the new build system as it was still using the old one.

I might try to fix the code review comments that were on the old pull request and make an new one and see if I can get this plugin merged into openHab addons.

But first I have to convert the rest of my system to openHab 3.

thx for your work and yeah would be great to have it integrated into the openHab addon.

great work - thank you!

Also a big thank you from my side. Everything works great on OH3.1.

Just wondering how I can achieve to change the stream of a specific client. I have the streams channel bound to a string item. It shows me a comma separated string, but how do I change from one stream to another.

@esdeboer @StbX any chance to port this excellent addon to OH v3.2? its essential for me before upgradingā€¦

Iā€™m running openHAB 3.2.0 and the binding is working

I think my 3.1 version just works for 3.2. Iā€™ll let you know once Iā€™ve upgraded my openHab (I should have some time for that before the end of the month)

oh, I didnā€™t know that! So i can upgrade and just leave this addon jar as-is? great! thank you!

Yes most addons should still be compatible with 3.2, the core did not change that much, I hope that remains until at least version 4.0.

I had removed all bindings for debugging and now i canā€™t seem to get it working again. Can someone help?

Iā€™m on 3.1.1
I tried installing via bundle:install https://github.com/esdeboer/openhab2-addons/releases/download/v3.1.0-SNAPSHOT/org.openhab.binding.snapcast-3.1.0-SNAPSHOT.jar
bundle:resolve
bundle:capabilities start

and via putting the jar file in /usr/share/openhab/addons

then, bundle:list states that the binding is installed and active, but it doesnā€™t appear in the UI

EDIT: It does appear in the UI when adding a thing but not in the list of installed bindings! thatā€™s unexpected for me. but it seems to work.

How would i go about configuring this via things file?

This is the thing configuration via thing files:

snapcast.things

Bridge snapcast:server:mySnapserver "Snapserver Bridge" @ "someroom" [host="192.168.0.2", port=1705 ] {
	Things:
		client sz "one" [id="putMacAddressofDeviceHere"]
		client wz "two" [id="orWhateverYourIdIs"]
}

snapcast.items

String snap_sz_name    "Name"        {channel="snapcast:client:mySnapserver:sz:name"} 
Dimmer snap_sz_volume  "LautstƤrke" <speaker> (gVolume) { channel="snapcast:client:mySnapserver:sz:volume" }
Switch snap_sz_mute    "Mute"       <speaker> (gVolume) { channel="snapcast:client:mySnapserver:sz:mute" }
Number snap_sz_latency "Latenz"      { channel="snapcast:client:mySnapserver:sz:latency" }
String snap_sz_stream  "Stream"      { channel="snapcast:client:mySnapserver:sz:stream" }
String snap_sz_stream_state "Status" { channel="snapcast:client:mySnapserver:sz:streamStatus" }

@esdeboer

Have you gotten around to working on a pull-request?

I didnā€™t have a chance to work on a pull-request yet, but I will keep it in a working state.

The list of installed bindings seems to only show the ones you install through the ui, ones you drop in with jar files seem to be missing.

Thanks for thing config example, I switched to the ui config for it, so I didnā€™t try the config file yet.

This binding crashes for me as soon as I connect Snapweb on my phone. As far as I understood from the logs, the problem is that the device id contains space symbol. Snapserver handles such idā€™s fine, but binding doesnā€™t.
If someone maintains this binding , can you tell me where to report the bug. Or, just keep that in mind.

      "clients": [
        {
          "config": {
            "instance": 1,
            "latency": 0,
            "name": "",
            "volume": {
              "muted": false,
              "percent": 100
            }
          },
          "connected": true,
          "host": {
            "arch": "arm64-v8a",
            "ip": "192.168.1.131",
            "mac": "00:00:00:00:00:00",
            "name": "ONEPLUS A3010",
            "os": "Android 11"
          },
          "id": "ONEPLUS A3010",
          "lastSeen": {
            "sec": 1656691950,
            "usec": 271847
          },
          "snapclient": {
            "name": "Snapclient",
            "protocolVersion": 2,
            "version": "0.25.0"
          }
        }
      ],