DIY Ambilight Integration with Python

A while back I saw a video on a custom Ambilight project using some ws2812b’s and an arduino nano.

After building it I saw that the windows software that controls it (Prismatik) has an API that you can access with telnet.

Since I had no idea how to get this working, it took way to long to get to where I am now.
So I figured I would share my setup to justify the time spent. :smirk:

First we should save some profiles in Prismatik that will be referenced later.

The Ambilight profile is in screen grabbing mode to do what an Ambilight should do, mirror the colors on the screen to the leds.

The Moodlight profile is in Mood Light Mode that cycling through colors.

The Visualizer profile is set to a sound visualizer that is a cool effect that dances the LEDS to the sound source you have it set to. I have it set to my main sound cards “What U Hear” channel.

The ColorSelect profile is the last profile and the main attraction, but is really just a dummy profile. It is set to sound visualization mode, but on a channel on my computer that is never used.


I learned that if you use the API to change colors of the LEDS, while you are in a mode that is actively controlling the leds you run into problems. As soon as you logout of the API, it goes back to what it was doing before you logged in.

So if we put it in visualization mode and make it listen to an unused device than it doesn’t clear out the commands we send to over the API.

After the Profiles are setup, click on the Experimental tab and enable the API. Now we can move on to OpenHAB.

We define some items and expose the main color item to Google Assistant so we can have voice control over it.

*.items

//Ambilight
Color           Ambi_Color              "Ambilight"                 {ga="Light"}
Switch          Ambi_OnOff              "Ambilight Power"
Number          Ambi_Mode               "Ambilight Mode"

And here is the sitemap for the above items.

*.sitemap

//Ambilight
        Text item=Ambi_OnOff label="Ambilight" icon="switch" {
            Switch item=Ambi_OnOff label="Power" icon="switch"
            Colorpicker item=Ambi_Color label="Ambilight Color"
            Selection item=Ambi_Mode label="Modes" mappings=[0=Ambilight, 1=Moodlight, 2=Visualizer] icon="rgb"
        }

Since the items are just dummies we have to do everything with a rule and python scripts.

In the rule we first transform the HSB color of the Ambi_Color item to the RGB that Prismatik expects.
We then can run a script with an RGB code as an argument.

Everything else just fires a python script to change the various profiles.

Ambilight.rules

//												Variables
var HSBType hsb_am
var red_am = 0
var green_am = 0
var blue_am = 0
//												Ambilight
rule "Ambilight Color"
	when
		Item Ambi_Color received update
	then
		hsb_am = Ambi_Color.state as HSBType
		red_am   = (hsb_am.red * 2.55).intValue
		green_am = (hsb_am.green * 2.55).intValue
		blue_am  = (hsb_am.blue * 2.55).intValue
		executeCommandLine("python /openhab/conf/scripts/setcolor.py " + red_am + "," + green_am + "," + blue_am)
		Ambi_OnOff.postUpdate(ON)
end
rule "Ambilight Color On"
	when
		Item Ambi_Color received command ON 
	then
		Ambi_OnOff.sendCommand(ON)
end
rule "Ambilight On/Off"
	when
		Item Ambi_OnOff received command
	then
		if (receivedCommand == OFF) {
			executeCommandLine("python /openhab/conf/scripts/ambilight_off.py")
		}
		if (receivedCommand == ON) {
			executeCommandLine("python /openhab/conf/scripts/ambilight.py")
		}
end
rule "Ambilight Mode"
	when
		Item Ambi_Mode received command
	then
		if (receivedCommand == 0) {
			executeCommandLine("python /openhab/conf/scripts/ambilight.py")
		}
		if (receivedCommand == 1) {
			executeCommandLine("python /openhab/conf/scripts/moodlight.py")
		}
		if (receivedCommand == 2) {
			executeCommandLine("python /openhab/conf/scripts/visualizer.py")
		}
end

Scripts

The important script is setcolor.py, it first checks the profile looking for ColorSelect, If it finds it it sends the color, If it doesn’t it enables ColorSelect, and sends the color.

setcolor.py

#Set Color of Ambilight. Must be run with a RGB Color Code as an argument (like 255,0,0)
import telnetlib, time, sys
color=sys.argv[1]
#color="255,0,0"
colorchange=(("setcolor:1-" + color + ";2-" + color + ";3-" + color + ";4-" + color + ";5-" + color + ";6-" + color + ";7-" + color + ";8-" + color + ";9-" + color + ";10-" + color + ";11-" + color + ";12-" + color + ";13-" + color + ";14-" + color + ";15-" + color + ";16-" + color + ";17-" + color + ";18-" + color + ";19-" + color + ";20-" + color + ";21-" + color + ";22-" + color + ";23-" + color + ";24-" + color + ";25-" + color + ";26-" + color + ";27-" + color + ";28-" + color + ";29-" + color + ";30-" + color + ";31-" + color + ";32-" + color + ";33-" + color + ";34-" + color + ";35-" + color + ";36-" + color + ";37-" + color + ";38-" + color + ";39-" + color + ";40-" + color + ";41-" + color + ";42-" + color + ";43-" + color + ";44-" + color + ";45-" + color + ";46-" + color + ";47-" + color + ";48-" + color + ";49-" + color + ";50-" + color + ";51-" + color + ";52-" + color + ";53-" + color + ";54-" + color + ";55-" + color + ";56-" + color + ";57-" + color+ ";"))
HOST = "10.10.0.2"
PORT = "3636"
try:
    telnetlib.Telnet(HOST,PORT,.01)
except:
    print ("the thing is missing")
    exit()
tn=telnetlib.Telnet(HOST,PORT, .1)
tn.write(("getprofile" + "\r\n").encode('ascii'))
status, match, previous_text = tn.expect([b'profile:ColorSelect'], .1)
if status == 0:
    print ("Already in ColorSelect, Changing Color to " + color)
    tn.write(("lock" + "\n").encode('ascii'))
    tn.write(("setstatus:on" + "\n").encode('ascii'))
    tn.write((colorchange + "\n").encode('ascii'))
    tn.write(("unlock" + "\n").encode('ascii'))
    tn.write(("exit" + "\n").encode('ascii'))
    exit()
else:
    print ("Not in ColorSelect, Continuing")
tn.write(("lock" + "\n").encode('ascii'))
tn.write(("setstatus:on" + "\n").encode('ascii'))
tn.write(("setprofile:ColorSelect" + "\n").encode('ascii'))
tn.write(("unlock" + "\n").encode('ascii'))
status, match, previous_text = tn.expect([b'unlock:success'], .1)
if status == 0:
    print ("unlock:success")
    time.sleep(.1)
else:
    exit()
time.sleep(.1)
tn.write(("lock" + "\n").encode('ascii'))
status, match, previous_text = tn.expect([b'lock:success'], .1)
if status == 0:
    print ("lock:success")
else:
    exit()
tn.write((colorchange + "\n").encode('ascii'))
tn.write(("unlock" + "\n").encode('ascii'))
tn.write(("exit" + "\n").encode('ascii'))
exit()

The ambilight_off script effectively needs to be turned off twice if you are in Ambilight mode.If I just send the setstatus:off command it would stop updating but not be completely black, so after some fiddling around I landed on the 2 profile changes surrounding the off command, it seems to reliably turn it off.

#Turn Ambilight Off.
import telnetlib, time
HOST = "10.10.0.2"
PORT = "3636"
try:
    telnetlib.Telnet(HOST,PORT,.01)
except:
    print ("the thing is missing")
    exit()
tn=telnetlib.Telnet(HOST,PORT)
tn.write(("lock" + "\n").encode('ascii'))
# tn.write(("setprofile:Ambilight" + "\n").encode('ascii'))
tn.write(("setprofile:Visualizer" + "\n").encode('ascii'))
tn.write(("setstatus:off" + "\n").encode('ascii'))
tn.write(("setprofile:Ambilight" + "\n").encode('ascii'))
tn.write(("unlock" + "\n").encode('ascii'))
status, match, previous_text = tn.expect([b'unlock:success'], .1)
if status == 0:
    print ("unlock:success")
    time.sleep(.1)
else:
    exit()
time.sleep(.1)
tn.write(("exit" + "\n").encode('ascii'))
exit()

And the rest
.
ambilight.py (Also acts as The ON state)

#Set Ambilight profile to Ambilight.
import telnetlib, sys
HOST = "10.10.0.2"
PORT = "3636"
tn=telnetlib.Telnet(HOST,PORT)
tn.write(("lock" + "\n").encode('ascii'))
tn.write(("setstatus:on" + "\n").encode('ascii'))
tn.write(("setprofile:Ambilight" + "\n").encode('ascii'))
tn.write(("unlock" + "\n").encode('ascii'))
tn.write(("exit" + "\n").encode('ascii'))
sys.exit()

moodlight.py

#Set Ambilight profile to Moodlight.
import telnetlib, sys
HOST = "10.10.0.2"
PORT = "3636"
tn=telnetlib.Telnet(HOST,PORT)
tn.write(("lock" + "\n").encode('ascii'))
tn.write(("setstatus:on" + "\n").encode('ascii'))
tn.write(("setprofile:Moodlight" + "\n").encode('ascii'))
tn.write(("unlock" + "\n").encode('ascii'))
tn.write(("exit" + "\n").encode('ascii'))
sys.exit()

visualizer.py

#Set Ambilight profile to Visualizer.
import telnetlib, sys
HOST = "10.10.0.2"
PORT = "3636"
tn=telnetlib.Telnet(HOST,PORT)
tn.write(("lock" + "\n").encode('ascii'))
tn.write(("setstatus:on" + "\n").encode('ascii'))
tn.write(("setprofile:Visualizer" + "\n").encode('ascii'))
tn.write(("unlock" + "\n").encode('ascii'))
tn.write(("exit" + "\n").encode('ascii'))
sys.exit()

So much trouble for three little items.



It was a long way the the well but dammit it works, and that’s awesome.

2 Likes

I don´t know im getting thig right, but I want to read the led values from pc screen and send them to openhab to controll my lights to extend the effect.
As far as I understand with your script, you only control the Prismatik with openhab, but don´t get the color values, right?

Do you know a way to also get colors from Prismatik or an alternative?

Thanks

Yes I was only interested in controlling from openhab, not reporting to it.

With the api you can use the command getcolors and it will report back the color of every led like

colors:0-45,55,63;1-42,54,61;2-40,54,61;3-40,54,61;4-40,54,61;5-51,63,72 ...

It’s not in the original api documentation but if you log in with putty and type help it is one of the available commands.

I wanted to see if I could do this so I played around today and got this working.

It uses this python library to talk to openhab.
https://github.com/sim0nx/python-openhab

It asks prismatik what profile it is in, if it’s in the ambilight profile it sends the color of #1 led to my bedroom lamp through openhab. It loops till it isn’t in in the ambilight profile anymore (or, more likely, till something goes wrong).

I’m sure there is a cleaner what to do it, but for a guy that doesn’t know python, I just think it’s cool it works.

#Demo to Set Bedroom Lamp to current Ambilight LED #1 Color.
#python 3
import telnetlib, time, sys, re
from openhab import OpenHAB
openhab_url = 'http://10.10.0.3:8080/rest'
Prismatik_url = '10.10.0.2'
Prismatik_port = '3636'
openhab = OpenHAB(openhab_url)
items = openhab.fetch_all_items()
BrLamp = items.get('Bu_BrLamp_RGB')
try:
    telnetlib.Telnet(Prismatik_url,Prismatik_port,.01)
except:
    print ('Can\'t reach Prismatik')
    sys.exit()
tn=telnetlib.Telnet(Prismatik_url,Prismatik_port)
tn.write(('getprofile' + '\r\n').encode('ascii'))
getprofile_response = str(tn.expect([b'profile:Ambilight'],.01))
profile_current = re.search('(?<=profile:)(Ambilight)', getprofile_response)
profile = (profile_current.group(1))
while profile == "Ambilight":
    tn.write(('getcolors' + '\n').encode('ascii'))
    getcolors_response = str(tn.expect([b'(?<=;1-)(\d{1,3}),(\d{1,3}),(\d{1,3})'],.01))
    result = re.search('((?<=;1-)(\d{1,3}),(\d{1,3}),(\d{1,3}))', getcolors_response)
    newcolor = (result.group(1))   
    BrLamp.command(newcolor + ',0')
    tn.write(('getprofile' + '\r\n').encode('ascii'))
    getprofile_response = str(tn.expect([b'profile:Ambilight'],.01))
    profile_current = re.search('(?<=profile:)(Ambilight)', getprofile_response)
    profile = (profile_current.group(1))
    time.sleep(.1)
sys.exit()
1 Like