Tag Archives: Music

Philips Hue Entertainment setup and testing

Now that Philips has launched its Entertainment facility for the Hue lights, it’s time to implement and test the features.

What is Entertainment?

It’s a new method for the Bulbs to communicate, meaning that light effects and changes can be synchronised to the split second. This means that the bulbs can react to films, broadcasts, games and music without any lag.  The instructions are sent out in bursts and then carried out all at the same time by the bulbs themselves.  This, in the purest form, means that the bulbs are truly “smart”.

Setting an Entertainment area

You need to tell Hue where your entertainment area(s) are.  An entertainment area is a collection of lights that you want to join together when you’re doing an activity that will use Hue Entertainment – such as playing a video game or watching a film.  You set this up through the Hue app.  Open the app, go to Settings (the gears icon) then choose Entertainment areas.

Select a room or rooms where the entertainment area is to be set up.

HueEnt-01

Select the lights that will be used in your entertainment area.  Notice that Hue recommends the ones that will work best with this feature.  The recommended ones have increased range for brightness and can also show all colours more vividly.

HueEnt-02

Your selected lights appear on a pretend ‘map’ of your entertainment area.  Drag each one into where it is physically positioned in the room.  As you drag, the light in your room will flash so you know which one you are moving on the screen.  Each one will turn from orange to green once you have moved it.

HueEnt-03

When you have positioned the lights on the screen to match where they are, press Test area.

HueEnt-04

The lights will all change colour at the same time, to match the colours showing on the app.

HueEnt-05

Finally, the app will flash each light separately.

Once set up, the area is stored in the bridge’s memory for use later.  At this time the bridge also works out which bulb in the entertainment area should be used as the first point of contact to send out messages to the other bulbs in the area.  You can change this in the app but the automatic decision seems to work well.

Testing the Entertainment area

At the time of writing this entry, there is only one Entertainment partner available on the app – this is Razer hardware (a gaming hardware company).  However, there’s another way to test your new Entertainment area.

A reddit user called CrustaceanSoup has developed a Windows app called Huestacean which can be downloaded and run easily.  The app samples what is displayed on the screen and then converts this to colours in the entertainment area.  For example, you can watch a film or a YouTube video on your computer and your Hue lights sync perfectly to the action on screen.

Thoughts

Thanks to people like CrustaceanSoup we can see the potential for this amazing immersive experience.  The level of synchronicity takes my breath away.

I cannot wait to see how other partners join in with this.  More than merely matching what is on screen, I can see streamed films coming with encoded Hue light programs and live broadcasts sending their stage lighting to Hue to recreate in your living room.

For now, I would be really happy if Hue extended their already strong partnership with Apple and brought a similar screen-mirroring function to the Apple TV, this would mean that practically everything we watch could be extended outwards into the whole living room.

Advertisement

Syncing your Hue lights to Sonos – part 2

I successfully built a program to sync up Phillips Hue lights with Sonos in this post.  Unfortunately the Echonest API is no longer in use and I have run up to difficulties with authorising the replacement Spotify API (any help with that is gratefully received!).

I’ve also always fancied myself as a lighting technician and the responsiveness of the Hue lights got me thinking that there might be a way to sync my lights to a specific track or a bunch of tracks.  Imagine a party where the lights “do their own thing” until a track comes on that is recognised, and then the lights sync up in exactly the way you have programmed them.

I wanted to make the program do as a minimum the following:

  • Have a “default” setting where the lights change in a generic but random way
  • When a track starts, to detect that the track has “light cues” associated with it and to start playing the light cues alongside the track
  • To be synced to the second, so that the lights always “keep up” with the track
  • To be able to “join in” and catch up with the track, even if it is paused or rewound (completely or partly)

The attached files are small, and are by no means polished, but they do the job and the program can run all night successfully changing between “I don’t know this song so I’ll just do a random light show” to “Oooh! I know this song, let me load up the light cues and join in!”.

There are two parts: and Excel spreadsheet where the lights are encoded, and a small python program that is run to manage the current playing track and loading of the associated light cues if they exist.

This program also relies on the node-sonos-http-api code by Jishi available here (https://github.com/jishi/node-sonos-http-api)  with installation instructions mentioned in my previous Hue/Sonos post.  This node program should be running (it always is on my Raspberry Pi as I use it to control all Sonos throughout the flat using HTTP commands).

The Excel spreadsheet:

The spreadsheet is a macro-enabled spreadsheet that allows you to create, load, edit and save light cue files (saved as *.lig files).  Simply open the spreadsheet and listen to your music.  When you come to a part of the music that deserves a light change, you go to that line and then choose a function and type in some numbers.

At the top of the spreadsheet, type in the name of the track you want to set up a light cue datafile for.  Enter the whole location of the file but without any extension.  For example, if the track is called Like a Cat, and you want it to be saved in your C:\Users\Sample\Documents folder, in cell C5 type in C:\Users\Sample\Documents\Like a Cat

A word of caution here: run the program and change the Sonos to the track you want to encode first.  The program will show the exact name of the file it is looking for.  In order to simplify the program, it strips out brackets and hyphens, as well as commas and full stops (periods).  You may therefore end up with a track name that has a few extra spaces in it, so look out for that.

In cells C9 to L9 enter the reference numbers of each light you want to use in this song.  You can use all available lights or just some.  You don’t have to select the same lights for each song, but remember if one known song comes on after the other, some lights may remain as you left them in the first song if you don’t include them in the second song’s list.

In cell C11 enter the group number of the Hue lights you want to control.  This is useful as some of the light cues you can use address the whole group rather than individual bulbs in sequence.  You can set groups using the Hue API.

Listen to a song and then work out in your head what would be a good lighting effect.  Maybe you’d like each bulb to flick between strong random colours every 2 seconds, or maybe you want a low orange glow on all lights until the chorus, and then raise up the lights to a vivid red, maybe making them flash at just the right moment.

For each song you can enter as many or as few lines of light cues as you like, even just one at the beginning of the track, to change the lights to match the mood of the music for the whole song, or maybe an epic display matched perfectly to each bar.

Functions available are:

ALLSET which changes in sequence each light you have specified to use

CHGALL which changes the whole group of lights instead of each individual light

FLASH which pulses the lights either once or twice (depending on how fast your host machine is)

INDIV which controls one individual bulb (enter this in the Lightref/delay column). If you want to change 2 bulbs together just put two INDIV lines together, one after the other, a second apart.

ALLBRI ignores a lot of the variables supplied and just changes the whole group of lights to a specific brightness

ALLOFF and ALLON switch the whole group of lights off or on, at a transition time you specify

CHGSEQ changes each light sequentially, just like ALLSET, but waits a certain number of seconds you specify (enter this in the Lightref/delay column)

How to write a light cue line:

First choose what you want to do.  Let’s say in the very first second of the track we want to bring up all the lights to a dark, moody red colour.  Enter the following line.

hms1

I want to force the lights to one specific colour, so I have entered the same number into MinHue and MaxHue so that I am sure that colour 0 (red) will be chosen.

Then we want to spring into vibrant colours which change every 10 seconds, from the 15th second of the track.

hms2

Notice this time I have set MinHue to 0 and MaxHue to 65000 – this gives a good range of colours, in fact the whole spectrum.  I set MaxSat and MinSat to 255 as I don’t want to mix the colours with any white.  The closer you get to 0 for Sat, the more white is mixed in with the colour.  I have set TransTime to 10 because I want them to change over the period of 1 second.  I could have put 5 or 1 in there if I wanted a faster or instant response.  There is some randomness between the brightness too, from 100 (mid-dim) to 255 (bright).

I then copy this line from column D to column L and then paste into 25 seconds, 30 seconds, 35 seconds and so on.

When I get to the end of the song I just finish.  Nothing else to do unless you want to add some other flourishes.  Let’s go back to 2 minutes and 24 seconds, as there is one enormous drum solo that starts there and I would like to put pulsing white lights for 10 seconds.

hms3

Now just click the Export button at the top.  Excel won’t reportanything (I told you it wasn’t finished) but the light cue file will be saved in the location and with the name you specified in cell C5.  Make sure it has shown up.

You can quickly build up quite a catalogue of “*.lig” light cue files.

When done, copy these files to the location where you’ll be running the python program (oh, you’ll need to create or download one called “default.lig” which is the file that the program will open if the track playing does not have its own file).

Inside the python program change 192.168.1.94:5005 to the address of the server that is running for node-sonos-http-api (the address where server.js is running) and then change the Sonos zone name from “Living%20Room” to the one that will be playing the music.  If you want more than one player to play music (at a party for example) make sure the player you specify here is the “main” player and additional speakers are grouped to it.

Run the python program (in python 3) and you’ll see it start to wait for the Sonos player to start playing something.  Play one of the songs you have created a light cue file for and make sure it opens.  If it does, you’ll enjoy the fruits of your labour! If not, first check what file the program was actually looking for (each title is printed out by the program when the Sonos player changes track).

I hope you enjoy this small program and light cue creation spreadsheet.  Please let me know how you’d improve it or if you use it!  Thanks as always for your comments, they keep me writing these posts.

Downloads

Take off the “.doc” extension before using – WordPress does not allow me to upload *.py, *.xlsx or my own *.lig files.

hms.py

Default.lig

Hue Music Encoder 2.xlsm

Controlling Sonos via LightwaveRF Mood Controllers

I had a request to write about how I control my Sonos players via my LightwaveRF Mood Controllers.  Actually, it’s a good call: re-engineering the mood controllers from simple light switches to pads which can control both lighting moods and audio more closely reflects the ‘built-in’ panels found in expensive custom installs.  In fact, using the technique below there’s nothing to stop you from controlling any number of home control activities from your mood controllers or handheld remotes.

I can say with authority that without these wall-mounted controllers all over the flat, I would never have been allowed to continue developing the system.  Having a familiar controller in each room ensures that users don’t need to run to the central controller or get out their smartphones whenever they want to make quick and regular changes to the light, heating or audio settings.

What you’ll need:

A summary is that node-sonos-http-api does the vast majority of the work, by ‘listening’ to all connected Sonos controllers and controlling them by very simple http requests.  These http requests are triggered by Domoticz once a signal is received from the mood controller.

How long this will take:

  • If you already have the Pi running Domoticz, and have been using a Sonos player already, and maybe have just bought a LigtwaveRF mood controller or other wall controller compatible with Domoticz, the whole thing will take about 30-40 minutes if you take your time.

Add the mood controller to Domoticz

From the Domoticz interface select the Switches screen, then select Learn Light/Switch at the top.  You should imagine the mood controller as two distinct switches stuck together: as far as Domoticz is concerned the two largest buttons are a completely different device compared to the four smaller buttons.

Immediately press the large OFF button (marked with a zero) on the mood controller.  In the box that appears give the mood controller a name – remembering that this is only the name given to the top two buttons of the controller (e.g Bathroom Lights).

This time we’re going to learn the lower row of the mood controller (the four smaller buttons). Repeat the above by pressing Learn Light/Switch and this time immediately press any one of the smaller buttons on the controller.  Name these too (e.g. Bathroom Audio).

Back up your Domoticz database

Just in case the next step causes problems for you it might be good to back up your system.  I’ve only needed to restore the system once – when I made a complete mess of installing node and npm.

Install node-sonos-http-api

I did this to install and it worked.  You may have a different setup or you may want to select another way of doing this.

Make sure you have node and npm installed.  If you don’t, search for and follow the instructions on how to install these carefully as I have messed this up more than once, by being all “I know how to do this, I’ll just skip this step”.  When will I ever learn?!

Get to the Domoticz folder and create a folder called sonos.

In the sonos folder, clone the node-sonos-http-api program by typing


git clone https://github.com/jishi/node-sonos-http-api.git

Navigate to the new node-sonos-http-api folder and fix the dependencies by typing


npm install

You can now run the program by typing


node server.js

Now the magic starts!  Open a browser and navigate to http://192.0.0.0:5005/Kitchen/play, where 192.0.0.0 is the address of your Pi and Kitchen is the name of your Sonos speaker.

The browser will ‘open’ a blank page, but the speaker in the room will start playing (assuming something is in the play queue.  If not use http://192.0.0.0/Kitchen/playlist/My%20Playlist.  This time, the playlist “My Playlist” is selected (make sure you use hex codes such as %20 instead of spaces in the URL- this includes rooms, so Living Room becomes Living%20Room).

Use the commands listed here to control your Sonos players.

Create scripts

Consider the commands you will want to send to Sonos via the mood controllers.

In this example my room is called Bathroom and the functions I want to add to the mood controller are play, pause, Radio 4 and a playlist called Harry 1.

I’ll need to create four scripts.  The easiest way to create scripts on the Pi  is to use nano, or off the Pi I use WinSCP.

Make sure the scripts are stored in the domoticz folder (not any subfolder).

The scripts will be called Sonos-BR-Play,.sh Sonos-BR-Pause.sh, Sonos-BR-R4.sh and Sonos-BR-Harry1.sh

Sonos-BR-Play will include the following text (just one line is needed to send an http request via a command called curl):

curl http://192.0.0.0:5005/Bathroom/play

Where 192.0.0.0 is the address of the Pi and ‘Bathroom’ is the exact name of the Sonos player.

The other 3 files contain very similar commands:

curl http://192.0.0.0:5005/Bathroom/pause

curl http://192.0.0.0:5005/Bathroom/favorite/BBC%20Radio%204

and

curl http://192.0.0.0:5005/Bathroom/playlist/Harry%201

So now I have these files in the domoticz folder.  I need to make them executable by Domoticz, so in the domoticz folder type


chmod u+x *.sh

We’re coming to the last part now!

Create LUA scripts for Domoticz

We need to run the scripts we created when Domoticz detects the button being pressed on the mood controller.  Let’s imagine the 4 small buttons on the mood controller are going to control the 4 functions we’ve just created scripts for.  The four buttons change the Domoticz device to Group Off, Group Mood 1, Group Mood 2 or Group Mood 3.  You can test this by pressing the buttons and waiting to see Domoticz change the status of the device.

I’m going to imagine that the mood controller’s set of 4 buttons is called ‘Bathroom Audio’ in Domoticz.

Go to the domoticz/scripts/lua folder and create a new file called script_device_BathroomAudio.lua

In the script I’m going to put this text in (you should see by the contents how you can change this):


commandArray = {}

if devicechanged['Bathroom Audio'] == 'Group Off' then

os.execute('./Sonos-BR-Play.sh')
print ('Bathroom Play via mood controller')

elseif devicechanged['Bathroom Audio'] == 'Group Mood 1' then
os.execute('./Sonos-BR-Pause.sh')
print ('Bathroom Pause via mood controller')

elseif devicechanged['Bathroom Audio'] == 'Group Mood 2' then
os.execute('./Sonos-BR-R4.sh')
print ('Bathroom Radio 4 via mood controller')

elseif devicechanged['Bathroom Audio'] == 'Group Mood 3' then
os.execute('./Sonos-BR-Harry1.sh')
print ('Bathroom Harry Playlist via mood controller')

end

return commandArray

That’s it! You should be able to control your Sonos anywhere you can stick a LightwaveRF mood controller.  Let me know how you get on!

Homemade disco using Sonos and Hue

I’ve used Hue Disco and other apps to sync up my Philips Hue lights with my music, but what I really wanted was something that I could start during a party, and just leave to get on with it.  I wanted the lights to change reasonably often, but I wanted them to respond to the type of music being played.

This program is written in Python 3 and uses the Echonest database to get the energy and danceability, as well as the tempo of the currently plying track from the Sonos player (obtained by this great program: node-sonos-http-api.  The program then selects a brightness and saturation range and randomly changes all the hue lights you specify.  The lights change in a frequency relating to the tempo of the track playing.

The program must be started AFTER you’ve started playing a track on the Sonos, and then continuously runs until you pause the Sonos player, and then raises the lights to a medium white light, and then the program quits.

I’ve got this program running on my Raspberry Pi, and am really pleased with it, obviously more tinkering can be done, but I’ve not seen any similar apps that do this.  I have a Domoticz ‘switch’ that can start running this program, and then to end the program, you just pause playback.  But you could just run the program from the command line each time you want to have a disco!

Best used when you have a night of partying, with a large random playlist going.  Don’t forget that as long as the player you specify in the variables is part of the playing ‘group’, you can play music to different rooms and include those Hue bulbs into the list too!

You can download the code here: Hue-BR-Analyse

Here’s the code:

import urllib
from urllib import request 
from random import randint 
import base64,requests,json,time,datetime

"""
Hue Sonos Analyser by Harry Plant 2015

This program changes the hue, brightness and tempo of Philips Hue lights depending on the energy and danceability of the track,
as reported by Echonest.

Requirements:

*Philips Hue bridge and at least one Hue Light (http://www2.meethue.com/en-gb/)
*At least one Sonos player (http://www.sonos.com/)
*Python 3 (I have it installed on my Raspberry Pi)
*Echonest api key (obtainable at https://developer.echonest.com/ - click 'Get an API Key')
*node-sonos-http-api (https://github.com/jishi/node-sonos-http-api)

change the following variables to match your setup:

zone is the name of the sonos player you will be listening to
my_list is an array of the hue lights you want to control
sonosinfo is the address of the node-sonos-http-api server
hue_bridge is the address and key that you use to control the hue
echonest_apikey is the key you obtained from echonest

I have used this program with success (great parties) on multiple occasions but do not accept 
responsibility for any loss or damage caused by using this code.

"""

zone = 'Kitchen'
my_list = ['3', '4', '5', '7', '15', '17', '19', '20']
sonosinfo = 'http://192.168.1.100:5005/'
hue_bridge = 'http://192.168.1.101/api/newdeveloper/'
echonest_apikey = '02MKNPMXXXXXXXXXX'

"""
MAIN PROGRAM BELOW, YOU DON'T NEED TO CHANGE ANYTHING FROM HERE
"""

currenttrack = 'No track'
min_bri = 100
max_bri = 100
secs_waited = 0
secs_to_wait = 10
sat = 100
tt = 10
trackfound = 1
std_assumptions = 0

for r in range(1,999999):
 
 secs_waited = secs_waited + 1

 req = request.urlopen(sonosinfo + zone + '/state')
 encoding = req.headers.get_content_charset()
 obj = json.loads(req.read().decode(encoding))
 """
 print(json.dumps(obj,indent=4))
 """
 if obj['zoneState'] == 'PAUSED_PLAYBACK' or obj['zoneState'] == 'STOPPED':
 print('Player has stopped playing. Returning lights to white and exiting program.')
 my_list_len = len(my_list)
 for i in range(0,my_list_len):
 hue = 10000
 bri = 200
 sat = 50
 tt = 50
 payload = '{"on":true,"sat":' + str(sat) + ',"bri":' + str(bri) + ',"hue":' + str(hue) + ',"transitiontime":' +str(tt) + '}'
 """
 print(payload)
 """
 r = requests.put(hue_bridge + "lights/" + my_list[i] + "/state",data=payload)

 req = request.urlopen('http://192.168.1.94:8080/json.htm?type=command&param=switchlight&idx=252&switchcmd=Off')
 exit()

 track = obj['currentTrack']['title']
 artist = obj['currentTrack']['artist'] 
 elapsedtime = obj['elapsedTime']
 playing = obj['playerState']

 if track == currenttrack:
 """
 print('Waited ' + str(secs_waited) + ' out of ' + str(secs_to_wait))
 """
 if track != currenttrack:
 std_assumptions = 0
 print('This is a new track!')
 print('Now playing : ' + track + ' by '+ artist + ".")
 requeststring = 'http://developer.echonest.com/api/v4/song/search?api_key=' + echonest_apikey + '&format=json&artist=' + urllib.parse.quote(artist) + '&title=' + urllib.parse.quote(track)
 """
 print(requeststring)
 """
 req = request.urlopen(requeststring)
 encoding = req.headers.get_content_charset()
 obj = json.loads(req.read().decode(encoding))
 """
 print(obj)
 """
 if not obj['response']['songs']:
 std_assumptions = 1 
 print('Song not in database - using standard assumptions')
 
 if std_assumptions == 0:
 songid = obj['response']['songs'][0]['id']

 """
 print(songid)
 """

 requeststring = 'http://developer.echonest.com/api/v4/song/profile?api_key=' + echonest_apikey + '&id=' + songid + '&bucket=audio_summary'
 """
 print(requeststring)
 """
 req = request.urlopen(requeststring)
 encoding = req.headers.get_content_charset()
 obj = json.loads(req.read().decode(encoding))
 if not obj['response']['songs'][0]['audio_summary']:
 print('Although song was in database, there is no energy and danceability data. Using standard assumptions for this track.')
 std_assumptions = 1

 if std_assumptions == 0:

 print(obj)
 
 dancepercent = int((obj['response']['songs'][0]['audio_summary']['danceability'])*100)
 energypercent = int((obj['response']['songs'][0]['audio_summary']['energy'])*100)
 pulserate = obj['response']['songs'][0]['audio_summary']['tempo']
 print('Danceability is '+str(dancepercent) + '% and energy is ' + str(energypercent) + '% with a tempo of '+str(pulserate) +'bpm.')
 currenttrack = track

 if std_assumptions == 1:
 
 dancepercent = 50
 energypercent = 50
 pulserate = 100
 print('Danceability is '+str(dancepercent) + '% and energy is ' + str(energypercent) + '% with a tempo of '+str(pulserate) +'bpm.')
 currenttrack = track

 if pulserate < 100:
 secs_to_wait = 20
 tt = 20
 
 if pulserate > 99 and pulserate < 120:
 secs_to_wait = 6
 tt = 10
 
 if pulserate > 119 and pulserate < 160:
 secs_to_wait = 4
 tt = 7

 if pulserate > 159:
 secs_to_wait = 2
 tt = 5
 """
 
 secs_to_wait = int((pulserate/60)*2)
 """
 if energypercent < 20:
 sat = 50
 
 if energypercent > 19 and energypercent < 40:
 sat = 100

 if energypercent > 39 and energypercent < 60:
 sat = 120

 if energypercent > 59 and energypercent < 80:
 sat = 170 

 if energypercent > 59 and energypercent < 80:
 sat = 200

 if energypercent > 79:
 sat = 255

 if dancepercent < 20:
 max_bri = 60
 min_bri = 40
 
 if dancepercent > 19 and dancepercent < 40:
 max_bri = 100
 min_bri = 80

 if dancepercent > 39 and dancepercent < 60:
 max_bri = 150
 min_bri = 80

 if dancepercent > 59 and dancepercent < 80:
 max_bri = 200
 min_bri = 50 

 if dancepercent > 59 and dancepercent < 80:
 max_bri = 255
 min_bri = 50

 if dancepercent > 79:
 max_bri = 255
 min_bri = 10

 print('Changing hue lights now.')
 my_list_len = len(my_list)
 for i in range(0,my_list_len):
 hue = randint(0,65000)
 bri = randint(min_bri,max_bri)
 payload = '{"on":true,"sat":' + str(sat) + ',"bri":' + str(bri) + ',"hue":' + str(hue) + ',"transitiontime":' +str(tt) + '}'
 """
 print(payload)
 """
 r = requests.put(hue_bridge + "lights/" + my_list[i] + "/state",data=payload)
 secs_waited = 0
 
 if secs_waited >= secs_to_wait:
 print('Changing hue lights now.')
 my_list_len = len(my_list)
 for i in range(0,my_list_len):
 hue = randint(0,65000)
 bri = randint(min_bri,max_bri)
 payload = '{"on":true,"sat":' + str(sat) + ',"bri":' + str(bri) + ',"hue":' + str(hue) + ',"transitiontime":' +str(tt) + '}'
 """
 print(payload)
 """
 r = requests.put(hue_bridge + "lights/" + my_list[i] + "/state",data=payload)
 secs_waited = 0

 time.sleep(1)