Twinkly christmas lights integration

Hi, this is not a binding or java so far. I just tried the python with my new twinkly - and even if I never worked with python, it worked somehow:
I’ve installed python3 on my NAS via the Qnap-App-Store. Then I copied the script in a .py-file and with running the command from above it switches the Twinkly.
Now I have to find out how to run a .py-file via the webserver and then it should work with the http-binding. There won’t be a state information available - I guess, but switching on/off will be a good first start.

Hm, thank you for your answer…
If I got you correct, there’s still missing one step to connect it to openhab?
I asked the twinkly support team, too. Almost same words like in the upper comment. Here‘s their answer…
“Certainly not this year, I’ll pass your suggestion to our developers team.”

Cause, to be honest… just switching on/off you could solve for the few xmas weeks by using a sonoff S20.

Hi Steffen,
You could use a sonoff/smart plug, but then your on/off times will be further delayed. The device would need to boot up and connect to wifi, then your app would need to find the twinkly dwevice, then you could control it.

It isn’t hard to set up.
Copy the script to a location accessable by openhab. If using Raspberry pi/ openhabian / linux, it is likely /var/lib/openhab2 . Finally, ensure you have python3 installed. You probably do if using openhabian.

Next, figure out the IP address of your twinkly device. I logged into my router to do this. If you can reserve that IP address within your router’s system, this may help ensure the IP address doesn’t change in the future.

Then, go to a rule. I use text rules, and can’t give direction to any of the graphical/new interfaces.
You can certainly get much more complicated (and I did a bit), but in the rule you can add:

executeCommandLine("python3 on")  // turn the christmas tree on

(replacing the with the IP address of your system)

For myself, I created a summy switch called twinklyTree, and then used the following rule to control the device in a much more ‘normal’ manner elsewhere:

default.items (or whatever .items file you wish, located in openhab’s items directory)

Switch twinklyTree "Twinkly Christmas Tree" <light>

yourRules.rules (or whatever .rules file you wish, located in openhabs rules directory. Remember to edit the IP address)

rule "Twinkly Christmas Tree Power State"
  Item twinklyTree received command
  if (receivedCommand == ON) {
    executeCommandLine("python3 on")  // turn the christmas tree on
  else {
    executeCommandLine("python3 off")  // turn the christmas tree off

Finally, I simply toggle the twinklyTree switch in PaperUI, HabPanel, or send a command with twinklyTree.sendCommand(ON) or twinklyTree.sendCommand(OFF).

This should provide a complete and working implementation.

It doesn’t take long at all, you don’t need to buy anything extra (and flash then configure it). Much faster overall. I have several other rules that then turn the tree on or off as needed. I have a simple 433mHz button for the kids to toggle it on / off, and my script to shut everything off at the end of the day turns its lights off. The wake up rule in the morning turns it on.

If you wanted to go above and beyond, you could change the item to be a dimmer instead of a switch, and then send the off command if brightness 0, and otherwise send on and the brightness for all other values - if using Jeroen’s modified twinkly script above.

Edit: updated the rule to use the receivedCommand to reliably use the new command, not the possibly old switch state.


I’m using the Twinkly v1 and tried to implement it into OH.

My approach is not via python, but via the OH rules.
For me the use case was mostly turning it OFF and ON.
Started with the dimmer part, but somehow the commands are not working yet.
I also stopped using the twinkly app, because it invalidates the token used in OH :wink:

If anyone is interested, here are my files:


String    TW_Token
Switch    TW_TokenValid

Switch    TW_Power


var String twinklyAddress = "http://ip.of.your.twinkly/xled/v1"
var Timer renewTokenTimer
var String token

rule "Token expiration"
    System started or
    Item TW_TokenValid changed to OFF

    if (renewTokenTimer !== null) {
        renewTokenTimer = null

    logDebug("rules.twinkly", "twinkly address: {}", twinklyAddress)
    val loginResponse = sendHttpPostRequest(twinklyAddress + "/login", "application/json", "{\"challenge\": \"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=\"}")
    logDebug("rules.twinkly", "login response: {}", loginResponse)
    token = transform("JSONPATH", "$.authentication_token", loginResponse)
    val String challengeResponse = transform("JSONPATH", "$.challenge_response", loginResponse)
    val String tokenExpiration = transform("JSONPATH", "$.authentication_token_expires_in", loginResponse)
    val headers = newHashMap("X-Auth-Token" -> token)
    logDebug("rules.twinkly", "headers: {}", headers)
    val verifyResponse = sendHttpPostRequest(twinklyAddress + "/verify", "application/json", "{\"challenge-response\": \"" + challengeResponse + "\"}", headers, 1000)
    logDebug("rules.twinkly", "verify response: {}", verifyResponse)
    renewTokenTimer = createTimer(now.plusSeconds(Integer.parseInt(tokenExpiration))) [|


rule "Turn on christmas lights"
    Item TW_Power changed to ON
    logInfo("rules.twinkly", "Turn christmas lights on")

    if (token === null) {

    val headers = newHashMap("X-Auth-Token" -> token)
    logInfo("rules.twinkly", "headers: {}", headers)
    val response = sendHttpPostRequest(twinklyAddress + "/led/mode", "application/json", "{\"mode\": \"movie\"}", headers, 1000)
    logInfo("rules.twinkly", "response: {}", response)
    logInfo("rules.twinkly", "Christmas lights are on")

    val brightnessResponse = sendHttpGetRequest(twinklyAddress + "/led/out/brightness", headers, 1000)  
    logInfo("rules.twinkly", "brightness response: {}", brightnessResponse)
    TW_Brightness.postUpdate(transform("JSONPATH", "$.value", brightnessResponse))  

rule "Turn off christmas lights"
    Item TW_Power changed to OFF
    logInfo("rules.twinkly", "Turn christmas lights off")

    if (token === null) {
    val headers = newHashMap("X-Auth-Token" -> token)
    val response = sendHttpPostRequest(twinklyAddress + "/led/mode", "application/json", "{\"mode\": \"off\"}", headers, 1000)
    logInfo("rules.twinkly", "response: {}", response)
    logInfo("rules.twinkly", "Christmas lights are off")

    // update brightness value

Using the switch TW_Power turns your twinkly on / off


Interesting implementation, and it’s fascinating to see it fit entirely within openhab rules.

For what it’s worth, for any others deciding on which path to use, the Python script does not invalidate the twinkly app (at least for me).
I also just stumbled across this fascinating read:

Lots to go on here.

Hi Ben,

thank you very much for your detailed explanation.
You are right, it needs bit more time by using an sonoffS20, but its just for 4 weeks in that use;-)
but you are right, its much comfortable to communicate with twinkly directly.

My OH runs on a Synology, but no big problem to fit your explanation to this circumstances.

With this, it runs. On/off… next step will be to implement the brigthness.

Regards and have a relaxing xmas time,

“just for 4 weeks”

Do you mind if I use this rationale with my family? :laughing:
I can’t claim complete innocence, though, as I may have been involved in making some decorations more extravagant than they needed-to, per say.

All the best

Hi there!

Your implementation seems like an easy way to get some kind of ON / OFF functionality working without the hassle to get into python.

I tried to use the code pretty much as is, just replacing the IP to the twinkly and i seem to get a token. So far so good. But… It throws an error in the console and it’s not really working.

[ERROR] [untime.internal.engine.RuleEngineImpl] - Rule ‘Turn off christmas lights’: An error occurred during the script execution: Could not invoke method: org.eclipse.smarthome.model.script.actions.HTTP.sendHttpPostRequest(java.lang.String,java.lang.String,java.lang.String,int) on instance: null

Any ideas here?

Best regards,

Ah yes, forgot about that!

The sendHttpPostRequest method which includes the headers is available from OH 3.0
Since I am running 2.5 is used a work around.
You need to put the following jar in your addons folder:

Thanks to @JimT in this topic:

1 Like

Thank’s a bunch! I can confirm that works. Great! :+1:

1 Like

I copied the to /var/lib/openhab and /var/lib/openhab2 (I’m running openhab3 with openhabian).
Running the python command in the commandline works.
But from the rule I got an error:

2020-12-18 08:34:36.819 [WARN ] [] - Error occurred when executing commandLine '[python3 /var/lib/openhab/ on]' Cannot run program "python3 /var/lib/openhab/ on": error=2, No such file or directory

I tried it with and without fullpath.

Which is the starting folder if I don’t use a full path?
And what is not foud? python or the script?

Have you confirmed the paths that openhab uses in your installation?
It sounds like a case for those more familliar with openhab3, unfortunately.

For anybody who used my rule above, my initial post incorrectly used the twinklyTree.state, which doesn’t reliably get updated in time for the rule operation. I have now updated it to use receivedCommand instead, and the rule seems to reliably function as intended now.

rule "Twinkly Christmas Tree Power State"
  Item twinklyTree received command
  if (receivedCommand == ON) {
    executeCommandLine("python3 on")  // turn the christmas tree on
  else {
    executeCommandLine("python3 off")  // turn the christmas tree off

So, here’s brightness functionality, I use a slider just with the item below:

Number twinklyTree_Brigthness “Brightness Twinkly Christmas Tree”

rule “Twinkly Christmas Tree Brightness”

Item twinklyTree_Brigthness changed
executeCommandLine("python3 brightness " + twinklyTree_Brigthness.state.toString)}


If twinkly is off, it switches automatically on, when changing brightness. but its only one-way. if you change it in the app, theres no state for openhab. And if you set 0 for brightness, it switches twinkly off.

Works good.


1 Like


~$ which python3

Ha, Worked straight out of your ‘box’.
Still on 2.5.11, so the python route is fine.

Good to hear you can use it. That was my intention why I shared it, so people could use it!

I noticed when I wrote the rules, when I control Twinkly brightness from the app on my Android phone, it sends something like: 35.0, in stead of 35. And the Twinkly api doesn’t accept ‘.0’ at the end, and the brightness wouldn’t change. On my laptop from the Basic UI I don’t have this problem.

So a made a workaround in my rules, i’m not so good at python to fix this so i did it from within the Openhab rules :slight_smile: .

rule "Twinkly Brightness"
    Item Twinkly_brightness changed
    var Number numValue = (Twinkly_brightness.state as DecimalType).intValue
    executeCommandLine("python3 brightness " + numValue)

My Tinkly_brightness item is a dimmer item, not sure if i done something wrong there.

1 Like

Hi All,

I have created a very basic native Twinkly binding. It currently only supports ON/OFF. It is my first ever binding so i have learned a lot while developing, and there is probably a lot more to improve.

However, it seems to work for me. The sources can be found on openhab-addons/bundles/org.openhab.binding.twinklytree at twinklytree · mvanhulsentop/openhab-addons · GitHub

It is branched from the 2.5 tree, because that’s the version i use. 3.0 branch suggests to me interface breaks, and my main objective was to make it work on my own setup. But now i’m having trouble performing a succesful complete build. It does build my own project so that’s good enough for me.

So if you’re interested, you can try to build yourself from source, or you can send me an e-mail. I would not mind publishing the jar but i don’t know where.

Kind regards,


1 Like

thanks, Maarten.
It woul be great, if you could send me the jar to


Just posting the OH3 flavour:

executeCommandLine("/usr/bin/python3", "/home/omr/", "", "off");