This binding allows you to control your Twinkly lights.
Readme
As of now you can switch your lamps on / off, adjust brightness and working mode. In movie mode you can also select the current video from the playlist you’ve uploaded to the device.
You can find an extended description including textual configuration on GitHub (link).
Changelog
3.2.0.202112051225
Hotfix for changing refresh rate
3.2.0.202112041151
This is a first release to be published on Marketplace.
For other releases please check the release section on GitHub (link).
Authoring and support
This binding is being developed by @Maarten_v_Hulsentop and @Pavion. It’s a small binding with limited support. If you encounter any issues, please use this thread or create an issue on GitHub (link).
thanks for taking over the development and your time to support this binding in the future.
I was using your initial proof of concept version until today and tried to switch to the latest pre-release 3.2.0.202112041151.
The poc version was throwing “Issue while polling for state” errors and sometimes the command to turn the Twinkly on or off wasn´t sent to the device.
Maybe you could think about a method to check if a command was executed correctly?
The latest pre-release can control the Twinkly but i´m not able to save the refresh rate.
When changing the refresh rate from 0 to e.g. 60, the binding throws an error.
2021-12-05 13:07:18.117 [ERROR] [st.core.internal.thing.ThingResource] - Exception during HTTP PUT request for update config at 'things/twinklytree:twinkly:balkon/config'
java.lang.NullPointerException: null
at org.openhab.binding.twinklytree.internal.TwinklyTreeHandler.dispose(TwinklyTreeHandler.java:301) ~[?:?]
at org.openhab.core.thing.binding.BaseThingHandler.handleConfigurationUpdate(BaseThingHandler.java:105) ~[?:?]
at org.openhab.core.thing.internal.ThingRegistryImpl.updateConfiguration(ThingRegistryImpl.java:94) ~[?:?]
at org.openhab.core.io.rest.core.internal.thing.ThingResource.updateConfiguration(ThingResource.java:498) ~[?:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:179) ~[bundleFile:3.4.3]
at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96) ~[bundleFile:3.4.3]
at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:201) ~[bundleFile:3.4.3]
at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:104) ~[bundleFile:3.4.3]
at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:59) ~[bundleFile:3.4.3]
at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:96) ~[bundleFile:3.4.3]
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308) ~[bundleFile:3.4.3]
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121) ~[bundleFile:3.4.3]
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:265) ~[bundleFile:3.4.3]
at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234) ~[bundleFile:3.4.3]
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208) ~[bundleFile:3.4.3]
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160) ~[bundleFile:3.4.3]
at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:225) ~[bundleFile:3.4.3]
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:298) ~[bundleFile:3.4.3]
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPut(AbstractHTTPServlet.java:234) ~[bundleFile:3.4.3]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:710) ~[bundleFile:3.1.0]
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:273) ~[bundleFile:3.4.3]
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:791) ~[bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:550) ~[bundleFile:9.4.40.v20210413]
at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:71) ~[bundleFile:?]
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) ~[bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:602) ~[bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) ~[bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235) ~[bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624) ~[bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) ~[bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1435) ~[bundleFile:9.4.40.v20210413]
at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:294) ~[bundleFile:?]
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) ~[bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501) ~[bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594) ~[bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) ~[bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1350) ~[bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) ~[bundleFile:9.4.40.v20210413]
at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:82) ~[bundleFile:?]
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) ~[bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.server.Server.handle(Server.java:516) ~[bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:388) ~[bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:633) [bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:380) [bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277) [bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) [bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) [bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104) [bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336) [bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) [bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171) [bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129) [bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:383) [bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:882) [bundleFile:9.4.40.v20210413]
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1036) [bundleFile:9.4.40.v20210413]
at java.lang.Thread.run(Thread.java:829) [?:?]
So i´m currently only able to control Twinkly but without the knowing the current state if there was a change in the app.
As answered on GitHub, when creating the Thing with no refresh rate no active communication with lights is tried so the Thing state stays UNKNOWN. Any successful command (or turning refresh on) would set the Thing to ONLINE.
I agree it’s not quite self-explaining and I might rethink it in the future
Oh sorry @Masssssy, hadn’t noticed your edit until now.
Sure there can be differences between used APIs. There seems to be no on mode, so for my lights I have to use movie mode to turn on. Perhaps your lights don’t support it.
Please ensure all your devices are up to date, please turn your refresh on (if not already), link your mode channel and note, which mode is shown when your device is powered on. You can send this mode as String to the channel then to turn your lights on.
Only tested a little bit but it seems the “Dimmer” works for both turning on and off the light.
Using the switch however does only turn it off, then it has to be started again with the dimmer.
It seems that the one that fully responds runs mode “movie” while the other one runs “effect”. I’m not sure what the difference is to be honest. The official app says effect and both run the same firmware version. Maybe effect = shades of white only for the “gold” edition?
Seems one improvement here could be for the binding to use on/off events for the dimmer. Then the switch could be scrapped altogether. Right now I can only dim using google assistant, not turn on or off.
I assume so… my device seems to ignore the effect mode.
Probably you could create a virtual Switch with a rule to send effect to the mode channel if turned on and off if turned off. You can also use a classic command options button for your sitemap (required options will be autofilled):
Sure, I will play around with it a little bit. I’m not sure if you saw the last thing I added about Google Assistant.
Now if I would add the switch I would only be able to turn on/off. If I add the dimmer I would only be able to dim, not turn on/off. The optimal would be to bind the dimmer to Google Assistant but then the binding would have to be changed to use these on/off events I think.
Because I do not need to care if it’s movie/effect when using the dimmer slider. It simply works on both devices. If that could be sorted out I think the experience would be better I can see if I have to to have a look as well some day. Time is rare…
rule "Gold Switch"
when
Item GoldSwitch received command
then
if (receivedCommand == ON) {
GoldMode.sendCommand("effect")
} else {
GoldMode.sendCommand("off")
}
end
Sorry, I couldn’t reproduce your issue on my setup. My main server is stable after many restarts, long runtime, plugging and unplugging the lights. On a clean OH 3.2 it starts with offline lights without any issues.
This binding is pretty basic and I’m not aware of any possible conflict with OH core.
Uninstalling the binding should not leave any junk behind.
As I’ve read, you had some other small issues, maybe the impossible stuff combined
If anyone else encounters the same issue, please enable debug and send me an excerpt.
Strange thing…
What happened was that I cleared away X-mas so the Twinkly became offline.
A few days later, when I was hit be JJS OOM error, I did the first reboot after removing Twinkly.
I tried numerous reboots, power-cycles. Upgraded to latest snapshot, downgraded again, because the snapshot is unstable. Many restart once again.
Always ended up in the same state:
213 │ Active │ 75 │ 3.2.0 │ openHAB Core :: Bundles :: Thing XML
214 │ Active │ 80 │ 3.2.0 │ openHAB Core :: Bundles :: Transformation Service
215 │ Active │ 80 │ 3.2.0 │ openHAB Core :: Bundles :: UI
216 │ Active │ 80 │ 3.2.0 │ openHAB Core :: Bundles :: UI Icon Support
217 │ Active │ 80 │ 3.2.0 │ openHAB Core :: Bundles :: Voice
218 │ Active │ 80 │ 3.2.0 │ openHAB UI :: Bundles :: Main UI
225 │ Active │ 80 │ 1.0.0.201802012106 │ org.osgi:org.osgi.service.jaxrs
226 │ Active │ 80 │ 1.5.0 │ ThreeTen-Extra
227 │ Active │ 80 │ 1.27.0 │ SnakeYAML
228 │ Active │ 80 │ 2.1 │ SI Units
229 │ Active │ 80 │ 2.1.0 │ SI Quantities
230 │ Active │ 80 │ 4.2.1 │ Stax2 API
231 │ Active │ 80 │ 2.1.2 │ Units of Measurement Reference Implementation
232 │ Active │ 80 │ 2.1.0 │ Units of Measurement Common Library for Java
233 │ Active │ 80 │ 1.4.18 │ XStream Core
234 │ Active │ 80 │ 3.2.0.202112051225 │ openHAB Add-ons :: Bundles :: TwinklyTree Binding
235 │ Starting │ 80 │ 5.9.0 │ jna
236 │ Resolved │ 80 │ 5.9.0 │ jna-platform
237 │ Resolved │ 80 │ 1.6.2 │ JavaMail API
238 │ Resolved │ 80 │ 1.0.1 │ IO.Socket Engine Client
239 │ Resolved │ 80 │ 1.0.1 │ IO.Socket Socket Client
240 │ Resolved │ 80 │ 20180813.0.0 │ JSON in Java
241 │ Resolved │ 80 │ 5.2.1 │ nrjavaserial
242 │ Resolved │ 80 │ 3.7.2 │ Apache Commons Net
243 │ Resolved │ 80 │ 3.8.1.1 │ Apache ServiceMix :: Bundles :: okhttp
244 │ Resolved │ 80 │ 1.13.0.1 │ Apache ServiceMix :: Bundles :: okio
245 │ Resolved │ 80 │ 2.0.0 │ Californium (Cf) Core
246 │ Resolved │ 80 │ 2.0.0 │ Californium (Cf) Element Connector
247 │ Resolved │ 80 │ 2.0.0 │ Californium (Cf) OSGi
248
As soon as I disabled the Twinkly addon in the GUI, the system jumped to life (live, no restart, just Twinkly disable), rule engine started, but many addons was still inn the Resolved state.
One thing I wonder: why did the Twinkly addon start so early, long before the other addons?
(Can’t check now since I have uninstalled it)
Since my Twinkly is now in the Attic, it is a topic for the next X-mas season
I’m still in for the coincidence theory. Bindings stuck at Resolved seems to be a known issue on old setups / upon migration: link, link, link. Perhaps the addons had been resorted upon upgrade so this binding was started before its dependencies. I don’t know… but I do hope I will be there next Christmas and able to provide you any support
Hi @Koechi
You might need to send another command to your mode Channel instead of using switch.
In your sitemap you can create a new cell with Send Command action for this Channel, which should probably be on or effect
rule "Twinkly Strings On"
when Item TwinklyString_Onoffswitch changed from OFF to ON
then
TwinklyString_Modeselection.sendCommand("effect")
end
rule "Twinkly Strings Off"
when Item TwinklyString_Onoffswitch changed from ON to OFF
then
TwinklyString_Modeselection.sendCommand("off")
end
Now it works
With the sitempap it is possible to turn it off and on too: