When I got the Phillips Hue starter kit for Christmas, I was excited about the possibilities. about using it with Amazon Echo. But then I learned you could connect with IFTTT and do other things. However I quickly became annoyed by the limits of IFTTT. I wanted the lights to come on a half-hour before sunset rather than at sunset (I noticed that by the time the lights came on it was already pretty dark in the house). I wanted the porch light to come on when my phone's wifi connected to it, but not at 3 in the morning if my phone happened to drop and reconnect. I wanted the porch light to stay on for 20 minutes but I didn't want to have to remember to turn it off. Much of the problem is the "Then" in IFTTT, its immediate, not delayed.
Then I discovered that Phillips Hue had its own API and I realized that I had a Raspberry PI 1 B+ that I wasn't using. I also learned that IFTTT had the Maker Channel which would send a GET or POST command to a web site. I realized with a little programming, I could get everything I wanted.
The work flow looks like this.
INPUT ---> IFTTT Trigger ---> Maker Channel ----> Raspberry Pi
Immediate / \ Delayed
Action / \ Action
Phillips HUE API Python Scheduler
Phillips HUE API
So take for instance my goal of turning on the lights 30 minutes before sunset. At some point during the day (I selected 4 pm), IFTTT gets the time for sunset from the Weather Channel and then uses the Maker Channel to pipe that time to my Raspberry PI which subtracts 30 minutes from the time and then sets a job to run which turns on the three main lights in my home that I want on. That executes on time, and "There was light, and it was good."
To put this together I need several things. Most of which were software for the Raspberry PI. I started with Debian on the RPI and used Python as my programming language for two reasons 1) its prominently supported in RPI Debian (Idle has a quick link on the desktop) and 2) there is a tremendous amount of packages and support for it including several wrappers to access the Philips Hue API.
Once, I got started then I need the following components:
1) a simple interface to receive http commands from IFTTT -- I used Flask
2) a scheduler to deal with delayed events. -- I chose Advanced Python Scheduler
3) a python wrapper to access the Phillips Hue API -- I used pyhue by aleroddepaz, the documentation on this is very slim, but it made the most intuitive sense to me and was the easiest to use.
4) I also need a dynamic dns to connect to the raspberry pi -- I used one through no-ip that was supported by my router. And then I port forwarded to the RPI.
5) Finally, I had to setup the IFTTT Maker Channel receipe to send the command to the RPI.
I will talk about my struggles with each of these, and what I learned in the process.
1) Flask: I looked at several different web micro frameworks. I ultimately wanted something that required no configuration and would just work. Ultimately it was this tutorial that was directed specifically at the RPI that made my decision. I decided I was only going to use GET commands to make this easiest. When IFTTT sends a command, the webpage returns the command sent which allows IFTTT to acknowledge everything worked.
2) Python Advanced scheduler - This has more power than I need. Essentially the way it works is you pass a function name to it, give it a trigger (in my case 'date') and then an id, and the date. The documentation was not as clear as I would like and how to pass it the actual date was in the class part of the API documentation and not the method. You have to set the date using "date_run" argument. Understanding all that, I set it up as a background scheduler and then add the job.
scheduler = BackgroundScheduler() scheduler.add_job(sunsetLights, 'date', run_date=sunset_py_time, id='sunsetsched', replace_existing=True) scheduler.start()
Since the webserver will run continuously, I give the job a name that then is replaced each day. These are stored in memory so if the power goes out the job is lost.
The run date is a datetime variable. I had to convert what the Weather Channel sent me into a datetime variable. Then I subtracted 30 minutes from sunset time using the timedelta method. Note that I have imported datetime and timedelta from datetime. Datetime is a funny object, in my code strptime (which formats the variable) is a method of the datetime object in the datetime class. So if I only imported datetime, I would write the code "datetime.datetime.strptime". Since I have imported the datetime object from the datetime class I still have use "datetime.strptime" but for timedelta, I can just invoke it.
from datetime import datetime, timedelta #convert date format sunset_py_time=datetime.strptime(sunsettime, '%B %d, %Y at %I:%M%p')-timedelta(minutes=30)
Once done however, I can now use it in the run_date argument above.
3) pyhue is a nice python wrapper for the Phillips Hue API. After setting up the bridge variable with ip and user name which is a long string Phillips gives you when you register your bridge, you have access to several collections: lights, groups and schedules. For the purposes of my project however, I really only need the lights collection. The property "on" is a boolean that indicates whether the light is on (true). I'm also using the "name" property. It is additionally possible to set the brightness with the "bri" property, though I did not.
Because I'm adding lights to my system, I chose to search each time by name and turn them on.
def sunsetLights(): for light in bridge.lights: if light.name=='Office lamp': light.on=True elif light.name=='Corner lamp': light.on=True elif light.name=='Reading lamp': light.on=True
4) Flask automatically runs on port 5000, so I also needed to set up a port forwarding on port 5000. With the dynamic dns it will forward to my router and then from my router port 5000 will go to the RPI.
5) Which brings me to the IFTTT code. For my purposes I wanted to make this as simple as possible so I set up everything in the URL. I tried mucking about with the body and content type parameters but it made it more complicated than I needed. So in the end I simply appended the information I needed to a GET command. I indicate the command with the keyword "?Command=" and then any parameters (different events may or may not need them) pass with "&arguement_name="
I retrieve the command with:
I can later in script get the parameters in the same way.
In the case above, I am passing sunset time that is an "ingredient" from the weather channel. When it reaches the RPI, it reads the "Command" variable which is "sunset". It then gets the "sunsetat" parameter. The program converts the time to a datetime variable, subtracts 30 minutes and then sets up the scheduler job.
Different commands activate different parts of the script which may or may not take parameters (see the full code).
In the end then, what I have is a program that connects the Phillips Hue with IFTTT but is not bound to the simplicity of IFTTT. I can do multiple step responses, I can set up delayed actions, all of which I cannot do natively with IFTTT but with the Raspberry PI as intermediary there is no limit.
Sample RPI Phillips Hue Connector Python
#RPI connector between IFTTT Maker channel and Phillips Hue # I write a lot of stuff to the console to act as a log from __future__ import print_function from flask import Flask, request import sys import pyhue from time import sleep from datetime import datetime, timedelta from apscheduler.schedulers.background import BackgroundScheduler # with out this "No handlers could be found for logger error" occurs import logging logging.basicConfig() bridge=pyhue.Bridge('126.96.36.199','username') def sunsetLights(): for light in bridge.lights: if light.name=='Office lamp': light.on=True elif light.name=='Corner lamp': light.on=True elif light.name=='Reading lamp': light.on=True app = Flask(__name__) @app.route('/') def index(): return 'Hello world' @app.route('/lights', methods=['GET','POST']) def lights(): lcommand=request.args.get('Command') print (lcommand, file=sys.stderr) if lcommand=='sunset': #turn on lights 30 minutes before sunset sunsettime=request.args.get('sunsetat') print (sunsettime, file=sys.stderr) #convert date format sunset_py_time=datetime.strptime(sunsettime, '%B %d, %Y at %I:%M%p')-timedelta(minutes=30) cur_time=datetime.now() print (sunset_py_time, file=sys.stderr) #schedule job scheduler = BackgroundScheduler() scheduler.add_job(sunsetLights, 'date', run_date=sunset_py_time, id='sunsetsched', replace_existing=True) print ('sunset lights scheduled', file=sys.stderr) print (sunset_py_time, file=sys.stderr) scheduler.start() elif lcommand=='wificonnect': #on wifi connect, turn on porch light if its after 4pm and before midnight cur_time=datetime.now().time() if cur_time.hour>16 and cur_time.hour<24: for light in bridge.lights: if light.name=="Porch light": light.on=True print (cur_time.hour, filesys.stderr) print ('porch light on in window', file=sys.stderr) else: print('porch light command not in window', file=sys.stderr) return stuff if __name__ == '__main__': app.run(debug=True, host='0.0.0.0')
Did you replicate this project? Share it!I made one
Love this project? Think it could be improved? Tell us what you think!