How to integrate Nanoleaf without binding(!)

Hi all,

I integrated my Nanoleaf lamps without a proper binding and it works fine. ON/OFF, brightness, colors etc. is all working properly. To achieve this a virtual item is required - in my case its name is f0_nanoleaf:

items file:

Color f0_nanoleaf "Nanoleaf" <colorlight> ["Lighting"]

Next a rule is required - within this rule the commands for the virtual color item will be splitted in 4 cases:

  • ON
  • OFF
  • change color
  • change brightness

When these commands are detected properly they will be provided to the Nanoleaf API. Therefore a shellscript (nanoleaf.sh) will take care about the webservice requests.

Important: Please do not forget to insert your nanoleaf auth token wihtin the nanoleaf.sh file! To receive your auth token hold the on-off button down for 5-7 seconds until the LED starts flashing in a pattern. Next send a POST request to the authorization endpoint http://NANOLEAFIP/api/v1/new within 30 seconds. As a response you will receive the auth token.

Maybe that helps somebody who likes to integrate his nanoleaf lights into the openhab world :wink:

nanoleaf.rules file:

rule "f0_nanoleaf"
when 
	 Item f0_nanoleaf received command
then
	logInfo("f0_nanoleaf", "state changed to: " + receivedCommand)

    var cmd = "/Users/jakez/openhab/conf/shellscripts/nanoleaf.sh "

    switch(receivedCommand) {
        case receivedCommand instanceof OnOffType: cmd = cmd + receivedCommand
        case receivedCommand instanceof HSBType: cmd = cmd + "COLOR " + receivedCommand.toString.replace(",", " ")
        case receivedCommand instanceof PercentType: cmd = cmd + "DIM " + receivedCommand
    }

 	logInfo("nanoleaf", "cmd : " + cmd)
    val results = executeCommandLine(cmd, 1000)
 	//logInfo("nanoleaf", "res: " + results)
end

nanoleaf.sh file:

#!/bin/sh
if [ "$1" = "ON" ]; then
    echo "switch on"
    curl -X PUT -H "Content-Type: application/json" -d '{"on" : {"value":true}}' "http://10.10.10.166:16021/api/v1/[YOURAPIKEY]/state/"
elif [ "$1" = "OFF" ]; then
    echo "switch off"
    curl -X PUT -H "Content-Type: application/json" -d '{"on" : {"value":false}}' "http://10.10.10.166:16021/api/v1/[YOURAPIKEY]/state/"
elif [ "$1" = "DIM" ]; then
    echo "dim to $2"
    curl -X PUT -H "Content-Type: application/json" -d '{"brightness" : {"value":'$2'}}' "http://10.10.10.166:16021/api/v1/[YOURAPIKEY]/state/"
elif [ "$1" = "HUE" ]; then
    echo "hue to $2"
    curl -X PUT -H "Content-Type: application/json" -d '{"hue" : {"value":'$2'}}' "http://10.10.10.166:16021/api/v1/[YOURAPIKEY]/state/"
elif [ "$1" = "SAT" ]; then
    echo "sat to $2"
    curl -X PUT -H "Content-Type: application/json" -d '{"sat" : {"value":'$2'}}' "http://10.10.10.166:16021/api/v1/[YOURAPIKEY]/state/"
elif [ "$1" = "COLOR" ]; then
    echo "hue to $2"
    echo "sat to $3"
    echo "dim to $4"
    curl -X PUT -H "Content-Type: application/json" -d '{"sat" : {"value":'$3'}, "hue" : {"value":'$2'}, "brightness" : {"value":'$4'}}' "http://10.10.10.166:16021/api/v1/[YOURAPIKEY]/state/"
fi

updated thanks to rlkoshak’s comments!

4 Likes

Good job man!

I like the rules + script combo! It can be re-used in many similar use-cases (e.g. http + json)

Nice tutorial.

A few of comments, mostly quibbles.

I’m usually the first person to say that efficiency is not something we need to worry about in this context. But it is slightly more efficient to use the enum types instead of Strings in the comparisons.

if(receivedCommand == ON) {

else if(receivedCommand == OFF) {

For the Color command you can use:

else if(receivedCommand instanceOf HSBType) {

A switch statement might be a little cleaner and easier to read.

Finally, the Rule could be shortened a little using Design Pattern: How to Structure a Rule.

These would change the Rule to something like:

    var cmd = "/Users/jakez/openhab/conf/shellscripts/nanoleaf.sh "
    switch(receivedCommand) {
        case receivedCommand instanceOf OnOffType: cmd = cmd + receivedCommand
        case receivedCommand instanceOf PercentType: cmd = cmd + "DIM " + receivedCommand
        case receivedCommand instanceOf HSBType: cmd = cmd + "COLOR " + receivedCommand.toString.replace(",", " ")
    }

    val results = executeCommandLine(cmd, 1000)

Obviously you can add logging as necessary and desired. Just add { } if you want more than one line to run as part of a given case.

Pay special attention to the HSBType because it will require you to slightly reorder the arguments expected by your script. It will print the values in hue, saturation, brightness order. but I figured needing to swap the $2 and $3 in that elif is worth the simplification in the Rule.

Note that I just typed this in and there may be errors.

There is nothing wrong with the original. Like I said, these are mere quibbles. But I like to post alternative shorter versions of code posted like this to show users ways to shorten or make their code a little clearer in some cases.

2 Likes

Rich, “the optimizer” :slight_smile: I like it :+1:
he has helped me also multiple times with my rules :bowing_man:

1 Like

Thanks Rich!!

Especially the instanceOf check for the specific types helps a lot to clean up the code and get rid of ugly checks like receivedCommand.toString.contains(",") :slight_smile:

Cheers
Dennis

Hi

I was only thinking about how this would be done yesterday, so thank you for making your work public.

Just for something to consider, have you seen this Python project?

Or this Node.js project?

Hi Dennis.
Is it possible to get the actual state of the aurora light. I have found in the api-documentation, that there are al lot of get requests like this:

curl --location --request GET "http://192.168.x.x:16021/api/v1/Add-a-user-to-generate-auth-token/state/on"
curl --location --request GET "http://192.168.x.x:16021/api/v1/Add-a-user-to-generate-auth-token/state/brightness"
curl --location --request GET "http://192.168.x.x:16021/api/v1/Add-a-user-to-generate-auth-token/state/hue"
curl --location --request GET "http://192.168.x.x:16021/api/v1/Add-a-user-to-generate-auth-token/state/sat"
curl --location --request GET "http://192.168.x.x:16021/api/v1/Add-a-user-to-generate-auth-token/state/ct"
curl --location --request GET "http://192.168.x.x:16021/api/v1/Add-a-user-to-generate-auth-token/state/colorMode"
curl --location --request GET "http://192.168.x.x:16021/api/v1/Add-a-user-to-generate-auth-token/effects/select"

But i don’t know how i can write a shellscript like yours, which actualise this values every 5 seconds for example. Would be very nice, if you can help me.
Thanks and greetings,
Markus

Okay. I made this:

#!/bin/sh
NanoStatus=`curl -X GET -H "Content-Type: application/json" -d '{"on" : {"value":true}}' "http://192.x.x.x:16021/api/v1/xxx/state/on"`
echo "NanoStatus is: "$NanoStatus
#
curl --header "Content-Type: text/plain" -H POST  "http://192.x.x.x:8080/rest/items/NanoStatus"  --data "$NanoStatus"
#
NanoSelect=`curl -X GET -H "Content-Type: application/json" -d '{"on" : {"value":true}}' "http://192.x.x.x:16021/api/v1/xxx/effects/select"`
echo "NanoSelect is: "$NanoSelect
#
curl --header "Content-Type: text/plain" -H POST  "http://192.x.x.x:8080/rest/items/NanoSelect"  --data "$NanoSelect"
#
NanoBrightness=`curl -X GET -H "Content-Type: application/json" -d '{"on" : {"value":true}}' "http://192.x.x.x:16021/api/v1/xxx/state/brightness"`
echo "NanoBrightness is: "$NanoBrightness
#
curl --header "Content-Type: text/plain" -H POST  "http://192.x.x.x:8080/rest/items/NanoBrightness"  --data "$NanoBrightness"
#

But i need to send a scene like this:

curl --location --request PUT "http://192.168.x.x:16021/api/v1/Add-a-user-to-generate-auth-token/effects" \
  --data "{\"select\" : \"Snowfall\"}"

How can i integrate this in your script?
Greetings,
Markus

Hi Markus,

what exactly you try to achieve? Can you describe this in words then hopefully I can help you here :wink:

Cheers
Dennis

Hi Dennis.
Yes of course. I want to send a scene. Like “Nemo”. If i use the light for notification warnings, change color to blinking red, it has to change back to the running scene. So i will restore the previous state to a String item and send it back.
Greetings,
Markus

The actual scene, state and brightness i already get with my script. So i only need a command to send the scene.

Ok.

I’m doing something similar with these scripts. Important note: Replace spaces with “_” in the effect name. Then you can pass the effect to the nanoleaf-effectdata.sh script.

 var String currentEffect = sendHttpGetRequest(baseUrl + "/effects/select")
 currentEffect = currentEffect.replace(' ', '_')


var effectData = executeCommandLine("/Users/jakez/openhab/conf/shellscripts/nanoleaf-effectdata.sh "+currentEffect, 1000)

nanoleaf-effectdata.sh file

#!/bin/sh

EFFECT=$(echo "$1" | tr '_' ' ')
DATA='{"write" : {"command" : "request", "animName" : "'$EFFECT'"}}'  
curl -s -X PUT -H "Content-Type: application/json" -d "$DATA" "http://10.10.10.166:16021/api/v1/APIKEY/effects"

Cheers
Dennis

Great job. Nice. I will test it.
Can you check my script. It’s copyed by some sites and i am not sure if it is perfect. But it is running.
Or is it possible, that you post your complete solution. That would be great.
Greetings,
Markus

Hi Dennis.
Cannot get it work. The script starts correctly and gives the values of the scene back. But the lights don’t change. Any ideas? Is your script running, because of firmeware changes in the last days?
Greetings,
Markus

Okay.
It was the wrong command.
To change the effect you need:

#!/bin/sh
EFFECT=$(echo "$1" | tr '_' ' ')
DATA='{"select" : "'$EFFECT'"}'  
curl -s -X PUT -H "Content-Type: application/json" -d "$DATA" "http://192.168.x.x:16021/api/v1/xxx/effects"

Greetings,
Markus

Hi guys,

I have started a Nanoleaf binding. Could you perhaps help collect use cases and requirements in my new thread?

So I found the usual trouble with DOS copy -> UNIX pasting…
So I had to clean up my .sh file now its working.

cat script.sh | sed '/\015/d' >newscript.sh