The Texting Tree

Posted on .

The Texting Tree

Last weekend I built a mini Christmas Tree that changes its colors. The fun part? The changes in color are controlled by text messages, and it happens almost instantaneously. This started out as a fun little project hacked together in an afternoon, but when I brought it to work I was really exhilarated by everyone's excitement. I added a few features and worked out the bugs as my colleagues played with it. This weekend I sat down, cleaned up the code, and wrote up everything involved so that you can make one too. There are a lot of little components working together to make this happen, and I'll take you through each one.

Here's a demo showing you what you'll end up with (large gif, please click to view): View the Demo

What You'll Need

This project involves a healthy mixture of things you need to buy, services you need to sign up for, and code you need to write. The Hardware section outlines your bill of materials (total cost is around $100 as of December 2014), and the Software section is just meant to give you an idea of what we'll be writing and what services you'll need to sign up for.

Hardware

Software

  • Spark.io account to trigger functions on your registered Spark Core via the API
  • Firmware running on Spark Core
  • Twilio Account (Free tier is fine!), and 1 phone number with SMS capabilities
  • 1 app to process incoming text messages and trigger functions on your Spark Core (this tutorial uses Python, if you want to use another language, go for it!)
  • Heroku account (to run the app -- again, free tier works!)

A little background and a few starting notes

When I first started this project, I spent a few hours searching around for a tutorial that would get me on the right track. Unfortunately, I didn't come up with anything. That's one of the biggest reasons why I'm writing this. I think projects like this should be more accessible.

There are a lot of components to make this work, and I may not go into enough detail on everything for everyone. If you get stuck somewhere, reach out to me on Twitter @willdages and let me know; I'll do my best to answer your question.

This project was originally hacked together quickly and I made plenty of mistakes along the way, which meant I had to do lots of troubleshooting. I didn't go into this project knowing how to make it work, and that was half the fun. Once you complete the tutorial, keep going! Add new features. Put easter eggs in the code. Make things blink, turn rainbow-colored, alternate colors, and anything else you can think of! There's so much potential to keep having run with this, and it's fun to figure out new things!

The Tutorial!

Step 0: Understand what we're building

I'll be easier to follow along if you completely understand the final product. Here's the full user flow along with an architecture diagram of the finished project:

  1. Someone texts a color to the tree's phone number
  2. The text message is routed to an application
  3. The application parses the text in the text message and determines if it's a valid color
  4. If it's a valid color, it's converted to RGB
  5. The RGB color is formatted in a way the microcontroller (Spark Core) can understand
  6. The color is sent to the microcontroller via the Spark API
  7. The microcontroller processes the color and triggers a function to change the color of the lights

The Texting Tree Architecture Diagram

Step 1: Hook up the LEDs to the Spark Core

Here's the Adafruit tutorial I used to identify the input end of the LED strand:

Adafruit: 12mm LED Pixels, Wiring

Read through this and follow it until you get to the "Connecting to Arduino" section. We're using the Spark Core instead of an Arduino, so those pins are different.

Connect the 4 main wires on the input end of the LED strand to the Spark Core with jumper cables:

  • GND : Blue Wire (Ground)
  • VIN : Red Wire (+5V Power)
  • A5 : Yellow Wire (Serial Data)
  • A3 : Green Wire (Serial Clock)

Hooking up the jumper wires to the LED strand

Hooking up the jumper wires to the Spark Core

Just use the 4 main wires that lead to the mating connector. The extra blue and red wires that are coming off the end are for power and will be addressed in the next step.

Step 2: Power the LEDs

Here's the page of the Adafruit tutorial I used to power the LEDs:

Adafruit: 12mm LED Pixels, Power

Note that you can power the LEDs from either end of the strand. For this application, attach the power supply to the same end as the INPUT side of the strand (the end you plugged into the Spark Core in Step 1). We don't want the power supply hanging off the top of the tree.

The power supply was also enough to power the Spark Core on the board. This means you don't need to power the Spark Core through the USB port or a power shield or anything, you can just plug one thing in and the whole thing powers up. Convenience!

Connecting the power wires to the power adapter

Just a note: I didn't buy the mating connector the first time around. I had another 5V 2A power adapter laying around that had separate power and ground wires leading to the plug, so I just cut the connector end off, separated and stripped the wires, attached them to the power wires on the LED strand, and secured them with some electrical tape. This probably isn't recommended, but it could work in a pinch, and if you have an extra power adapter you don't mind destroying. I much prefer using the real-deal female power adapter I listed above. It also lets you detach the tree from the power supply when not in use, and makes it much more portable.

You'll also note that in the bill of materials above, I mention a small box to hide everything in. I'm not going to elaborate too much in the tutorial, but it keeps things neater, and preserves some magic if you hide the electronics. Make it look like a present under the tree for extra bonus points. Avoid metal boxes since you're relying on a Wi-Fi signal. I'd also wait until everything is done before introducing the box, to make changes easier while you're in development.

Step 3: Prepare the application to run on the Spark Core

Now that we have all those LEDs connected and powered up, we want to see some colors. Nothing will probably happen when you plug the adapter into the wall (occasionally the first LED would flicker for a second or two for me, but I'm not really sure what that's all about).

To control those LEDs, we need to create a new app to load onto our Spark Core. At this point, I'm going to assume that you've done the following:

First, we're going to need a library that lets us control the LEDs. It's pretty technical stuff that's over my head, but luckily some other smart people have already done that heavy lifting for us. Adafruit wrote a library for the Arduino, and someone else ported it over the Spark core. I used this file that was linked to in Roman Mueller's Weather Moodlight tutorial. I originally just copy-pasted that whole file into the Spark IDE, but when I started writing this tutorial I decided to make it into a real Spark Library. We'll include this library in our project so that we can keep our application code cleaner and separated from all the low-level stuff.

Create the app

Start by logging into the Spark IDE and creating a new app. Call the app "Texting Tree" and make sure you hit save.

Find the library

Icon for Libraries in the Spark IDE

Now go to "Libraries" on the left hand navigation and search for WS2801. Click on the library and then scroll down to the "Include in App" button. Click that and select your "Texting Tree" project. The Spark IDE will automatically include headers to the library at the top of your texting-tree.ino file.

If that doesn't work, or the library isn't listed for some reason, add it manually by clicking on 'contribute library' and entering willdages/WS2801 in the box. This doesn't actually submit the library or make it public (which is not intuitive from the label on the button).

Icon for Verify in the Spark IDE

At this point, click the "Verify" button to make sure you can compile without any errors.

Add application code

This is the code we're actually writing, so I'll explain this step-by-step as we add to the textingtree.ino file in the Spark IDE.

Start by making sure we're importing the appropriate header files:

#include "WS2801/WS2801.h"
#include "application.h"

Next, let's initialize our LED strip (what we're using the library for). If you want to dig into everything this library can do, poke around the source code in the GitHub repo.

Start by defining how many LEDs you are controlling. I'm just doing a single strip of 25. Notice that we pass in numPixel when creating strip:

const int numPixel = 25;
Adafruit_WS2801 strip = Adafruit_WS2801(numPixel);

Now we can interact with our LEDs through strip.

Next we're going to add a setup() function, which gets called automatically. Let's start by defining our Spark Cloud function. We want to use the color function to change the color of our lights, so we need to define it in our setup function. We'll also call the strip.begin() method which sets up the serial interface to the LED strip.

void setup() {
    Spark.function("color", color);
    strip.begin();
}

Let's take a minute to pause and reflect on the Spark.function(). This is really what separates the Spark Core from the other microcontrollers I've seen and played with. What this is doing is setting up our color function, which (once we write it) will run on this microcontroller, and let it be triggered from anywhere in the world, at any time, by interacting with an API that is already set up, running, and managed by Spark. Just by hitting an HTTP endpoint with valid credentials, a request zips through network layers right to your device, where the function is called. This is incredibly powerful, and is saving us an enormous amount of time and complexity in getting this project up and running!

Ok, now let's write this color function. Spark functions only accept string inputs, so we'll need to deliver the color in a way that makes it relatively easy to parse. The format we're using here is a format I've seen in other similar Spark LED projects. I'm not overly excited about it, but it works well, so we'll go with it.

int color(String command) {
    // format is [RRR,GGG,BBB]
    // ie: red is [255,000,000]
    int red = command.substring(1,4).toInt();
    int green = command.substring(5,8).toInt();
    int blue = command.substring(9,12).toInt();
    int i;

    for (i=0; i < strip.numPixels(); i++) {
        strip.setPixelColor(i, red, green, blue);
        strip.show();
        delay(50);
    }
}

Alright, so what we're doing there is accepting a string that looks like [RRR,GGG,BBB]. We're using a strand of RGB LEDs, so our colors are made by mixing Red, Green, and Blue light together. These 3 sets of values note the intensity of each (256 possibilities per color, ranging from 000 to 255, dimmest to brightest). So [255,000,000] means full red, no green, no blue. We'll let our Python application take care of figuring out how those values should be mixed together.

When this string is passed to the color function, we assume it to be in the standard, agreed-upon format of [RRR,GGG,BBB], so we use substrings to extract the values and convert them to integers. The for loop then iterates over all the pixels in our strand (25) and sets each pixel individually, delaying execution by 50 milliseconds between each one to give a one-after-the-other look that spirals up the tree. You can play with the delay to find a value you like.

Step 4: Flash the firmware and see some colors

That's it for the code on the Spark Core! Not much, right? It's all we need. Verify the code in the Spark IDE and make sure everything compiles. If it does, go ahead and flash it onto your spark core.

At this point, because of the pure awesomeness of the Spark API, we can start watching our tree changing colors already. Eventually we're going to be hooking up an application to trigger the changing colors, but we can manually trigger it before we write the next piece of code to make sure everything is working.

You'll need a utility to make HTTP requests. This could be something like the Advanced REST Client Chrome App, or curl.

The specifics on how to interact with the Spark API are documented here. Basically, you're going to need 2 things to construct your request:

  • Your Device ID (in "Cores" in the Web IDE)
  • Your Secret Access Key (in "Settings" in the Web IDE)

Here's what your request is going to look like (replace device_id and access_token with your credentials) for cURL:

$ curl https://api.spark.io/v1/devices/device_id/color -d access_token=access_token -d 'command=[255,000,000]'

Here's what it'll look like if you're using Advanced REST Client:

Screenshot of Advanced REST Client

Go ahead and send the request. Did you see it happen? Are you excited? You should be. You just make some lights change color from your terminal. That's amazing! And the most exciting part is that it's really easy to make network calls like that from inside applications and websites, so now you've gotten far enough that you can control these lights from anywhere! Next, we'll give our tree a phone number and wire it up to trigger this API call.

Step 5: Set up Infrastructure

You'll need to create your own accounts on a few free services to complete the tutorial. Keep in mind that you can get this working on the free or trial tiers of each plan, but you'll be responsible for any charges or overages you incur by going over the free limits (which are always subject to change). As of now, this means scaling up beyond 1 dyno on Heroku, paying for Twilio to remove a prefix on any sent SMS messages, or keeping your Twilio phone number longer than 45 days (the holidays will be long gone by then). There aren't any limits (as far as I can see) on the number of incoming SMS messages with Twilio, so that shouldn't be an issue.

Twilio: For the phone number

We'll use Twilio to give our Christmas Tree a phone number. Twilio is a service that lets you programmatically interact with SMS and Voice messages. When you sign up (even with a free trial account) they give you a local number to use for 45 days, and you can set up an HTTP endpoint to be hit when a message or call is received. We'll be writing a small Python application to process those messages, and we'll deploy it on Heroku so it has a public URL and is always available.

Go ahead and set up your Twilio account here, and come back when you have a phone number.

We'll need to set up the endpoint to hit when an SMS is received, but we can't do that yet because we aren't sure what that URL will be. We're going to use Heroku to host our application, and they give you a random URL when you start a project. We'll come back here once we know what that URL is.

Heroku: For the Python application hosting

Heroku is an application hosting platform that lets you scale up and down easily. They have a nice free tier that we'll be using for the Python app we're writing soon. To make sure we're ready to write that code, sign up for a free Heroku account and then go through the first 2 steps in Heroku's Getting Started Guide (Introduction and Set Up). This will make sure you're ready to go with Python and Heroku. You can work through the rest of the tutorial if you're interested, but getting through Set Up is all you need for this.

Note: Heroku will spin down your server after 1 hour of inactivity when you're on the free tier, but it spins back up fairly quickly on the next request and doesn't lose any data, so that just means the first request of the day can take 5-10 seconds instead of under a second. You can sign up for a service like Pingdom or New Relic to get around this. These services ping your server every x minutes, so Heroku won't put it to sleep. As an added bonus, you'll get notified about any errors or downtime you might have.

Step 6: The Application Code

I'm going to give you two options here. Maybe you just want to get this up and running, and don't care about how it works. In that case, follow Step 6a. It will be the minimal amount of work, and basically just let you copy the code in and deploy it. You can also follow Step 6a if you're familiar enough with programming (and Python) that you can glance at this repo and know what's up. I don't want to waste your time.

If, however, you'd like the step-by-step instructions on how to do this yourself, and in the process learn how to structure and deploy a Python application, skip right to Step 6b.

Step 6a: Quick Setup

You're in step 6a because you know what's up. That means you get less-thorough instructions and no pictures. That's just the way it is. Here you go:

New! Want to keep it even simpler? Click the Heroku button below and the application will automatically launch and deploy. This replaces steps 1-8!

Deploy

Or:

  1. Clone this repo: $ git clone https://github.com/willdages/The-Texting-Tree.git
  2. From the command line, $ cd The-Texting-Tree and initialize Heroku by running $ heroku create
  3. Copy the .env-sample file and rename the new file to .env -- this will hold your environment variables. Fill in your Spark tokens and save the file.
  4. Install a plugin to sync these environment variables with Heroku: $ heroku plugins:install git://github.com/ddollar/heroku-config.git
  5. Sync the credentials by running $ heroku config:push
  6. Deploy the code to Heroku $ git push heroku master
  7. When that finishes, open the application to make sure it's running. $ heroku open will open your application in the web browser -- you should see the text Merry Christmas.
  8. Copy the URL in your browser and paste it into the Messaging Request URL in Twilio (click on your number from the Twilio dashboard, or go to Numbers > Twilio Numbers > [Your Number]). The endpoint for receiving SMS messages in our app is /sms so make sure you add that onto the end of your URL. Also make sure that the method is set to HTTP POST. Save your changes.
  9. Send a text message to your Twilio phone number with a color like Red. The Python application uses a CSS parser, so any valid CSS color value will work (including HEX values, as long as your include the #).
  10. If something isn't working, you can check the logs by running $ heroku logs --tail. You should see the body of the text message print out in the logs when you send a text message.

Note that there are a few extra steps if you'd like to develop and test features locally. You should create a virtual environment, activate it, install requirements with $ pip install -r requirements.txt and then use foreman to run the app just as Heroku will (use foreman start).

Step 6b: Let's write some code!

Ok, there's a lot of little things we're going to have to do to write the project from scratch. When we're done, it should looks like this, so if you get tripped up at any point, you can reference that repo.

Please make sure you've already gone through the Heroku setup before starting this, and make sure that you have access to the Heroku toolbelt and are logged in. Reference the Heroku getting started documentation if you have any problems.

Set up the project

Make a new folder to hold your project. I named my The-Texting-Tree.

$ mkdir The-Texting-Tree
$ cd The-Texting-Tree

Initialize a git repository in this directory, so you can commit files to push to Heroku.

$ git init

Let Heroku create a new application for you.

$ heroku create

You should get a confirmation message, along with a URL, returned from the $ heroku create command. There won't actually be anything at that URL yet because we haven't pushed any code. We can always get that URL again in the future by running $ heroku open, so don't worry about remembering it or writing it down anywhere.

Link the project URL with your Twilio number

We are going to use your application URL above as the endpoint to be notified when a new message comes in. Log into your Twilio dashboard and click on your number to get to its settings page. Near the bottom, you'll see a place to input your Messaging Request URL. Paste in your Heroku project's URL, and add '/sms' to the end. Make sure the method is set to HTTP POST, and save the changes.

Screenshot of the Twilio Messaging Request URL entry

This won't work yet, but soon we'll be writing to the code to process messages at that endpoint.

Set up the project dependencies

Now that we have our project set up with git and Heroku, it's time to set up our project's dependencies. We're going to use virtualenv to isolate the dependencies for our python project. If you don't have this installed already, follow the installation instructions here.

Create a new virtual environment:

$ virtualenv venv

This will create a venv folder in your project. Next, we're going to activate the virtual environment so that none of our global packages are accessible while we're working locally on the project. This will prevent any issues from popping up later on when we deploy on Heroku, and the global packages on our machine aren't available to the application anymore.

Active the virtual environment:

$ source venv/bin/activate

You should now see (venv) before your name on each line of the terminal. This lets you know that you're operating in your sandboxed environment. Now, when we install a package, it will be scoped to our project.

We're going to install each package and import it into our application now. That means we'll need our actual Python application file. Create a new file named textingtree.py in your project directory. Add a single line to the top of the file:

import os

os is a package that's available to us without installing anything extra. We're going to use this to access our environment variables (we'll set those up after our packages). For each package we install, we're going to add another import line to the top of textingtree.py so our application can use the package we install.

The first package we're going to install is Flask, which is a "microframework" that makes running a web server really easy.

$ pip install Flask

When that's finished installing, add the following to textingtree.py:

import os
from flask import Flask, Response, request

Next, we're going to install the Requests library, a great way to interact with HTTP requests in Python. We'll be using this to make the POST request to the Spark API, which will in turn trigger the color function on the Spark Core and change the lights on the tree.

$ pip install requests

And in textingtree.py:

import os
from flask import Flask, Response, request
import requests

Finally, we're going to install tinycss2. This is what will parse the body of the incoming messages to recognize colors. Instead of manually adding a list of keynames that match up with RGB values, I'm letting this library do the work for me. As an added benefit, anyone can send any valid CSS color value to this application (including hex values like #bada55) and it'll be recognized.

$ pip install tinycss2

And in textingtree.py:

import os
from flask import Flask, Response, request
import requests
import tinycss2
from tinycss2 import color3

That's it for our project's requirements! Now, let's document these packages so that Heroku knows to install the same packages on the server when we deploy our application. The standard filename for storing these is requirements.txt, so that's what Heroku will automatically look for when it detects a Python application. Save your installed packages by running this command:

$ pip freeze > requirements.txt

You'll now have a new file in your directory named requirements.txt. If you install any more packages on your own (if you want to continue adding features yourself), make sure you regenerate this file with the above command and commit the changes before deploying the app to Heroku.

Define ignored project files with .gitignore

Now that we actually have some code, let's commit our changes. Before we do that, we need to add a .gitignore file so that the contents of the venv/ folder aren't included. Those should not be kept in source control, so we want to tell git to ignore them.

Create a new file named .gitignore (your OS may prompt you to make sure you really want to create a file that starts with a . -- confirm that you do). Add the following to your .gitignore file:

venv/
*.pyc
.env

The venv/ line makes sure git doesn't try to commit your packages. The *.pyc stops it from trying to commit any compiled python files, and the .env stops your environment variables from being committed (that's coming up next).

Once you have that file saved, add all your files and make a commit. It'll look something like this:

$ git add .gitignore textingtree.py requirements.txt
$ git commit -m "Project started and dependencies installed"
Define environment variables

Now let's add some environment variables. These are values that you don't want to hard-code into your application, so you keep them in a separate file that is easily modified. Also note that we added .env to our .gitignore file, so they won't be kept in source control. This is because these values are usually private, like access keys, and we don't want to accidentally make them public. The only values we'll need for this relate to our Spark Core, and will be used to construct the request to the Spark API.

Start by creating a .env file and adding the following 3 lines (replace access_token and core_id with your own values; you can find them in the Spark Web IDE under "Cores" and "Settings"):

PYTHONUNBUFFERED=True
SPARK_ACCESS_TOKEN=access_token
SPARK_CORE_ID=core_id

Note that the first line, PYTHONUNBUFFERED=True just lets you see Python logs when running heroku logs --tail.

Once your environment variables are saved, we need to send them to Heroku (since they aren't in the source control). To manage sending these variables to Heroku, we'll install a plugin, per the instructions in Heroku's documentation. From the command line:

$ heroku plugins:install git://github.com/ddollar/heroku-config.git

Now push the environment variables to Heroku (it automatically looks for the .env file, which is why you don't need to specify where to get the variables).

$ heroku config:push
Finally write some code

I know, that's a lot of setup. But now we're actually ready to write some code. The first step will be to set up our web server and make sure it is accepting requests. Remember, we're using Flask for our web server, and as the "microframework" promises, it really is easy to get up and running quickly. We're pulling the next steps straight from The Flask homepage.

Add the following below all the import statements:

app = Flask(__name__)

@app.route('/', methods=['GET'])
def merry_christmas():
  return 'Merry Christmas!'

if __name__ == '__main__':
  app.run()

The first and last sections just set up Flask to start listening for HTTP requests. The middle section defines a route, and what to do when Flask gets a hit there. We're saying listen for GET requests at the root directory ('/'). If we get one, run the merry_christmas(): function, which returns the text 'Merry Christmas!'. This doesn't change the Christmas Tree's color, but it gives us a good starting point to make sure our web server is working in a way that's easy to verify (by going to our Heroku URL).

Add the Procfile

Now that we have some code, we need to let Heroku know how to run it. This is done with a Procfile. Add a new file to your project named Procfile (no extension) and add the following line to it:

web: gunicorn textingtree:app --log-file=-

You can read up more on Procfiles in the Heroku Documentation.

Deploy and verify the app is running

Now let's deploy our code to Heroku. This is where all that setup we did before really pays off. Simply push the new code to Heroku and they take care of the rest. Start by committing all the changes that we want reflected in our deployment. This should just be the Procfile and textingtree.py, but you can verify that by running $ git status.

$ git add Procfile textingtree.py
$ git commit -m "Set up the web server and add a route that returns 'Merry Christmas!'"
$ git push heroku master

That last line is what pushes all your committed code to Heroku. You'll see a few status messages as it compiles the code, installs the dependencies (which we defined in our requirements.txt file), and starts the application (using the instructions in our Procfile).

When it completes, test it out by opening up the application in a web browser:

$ heroku open

Our application will open in your web browser and you should see 'Merry Christmas!' on the screen. If so, this means our web server is running!

Add the /sms endpoint

Remember when we added our application's URL to the Twilio dashboard and added /sms to the end of the URL? Well now we're going to define that route, and that's where we'll write the code to parse the message body and trigger the color function on our Spark Core. We're almost there!

Start by adding a new route and defining a new function. This is where the rest of the code we're going to write will live.

@app.route('/', methods=['GET'])
def merry_christmas():
  return 'Merry Christmas!'


@app.route('/sms', methods=['POST'])
def sms():


if __name__ == '__main__':
  app.run()

We define the accepted method for '/sms' to be POST, so that it matches with the method we chose in the Twilio dashboard. This is where text messages will arrive from Twilio.

Parse the message text

Let's catch the incoming messages by using Flask's request object (not to be confused with the requests library we installed earlier)

@app.route('/sms', methods=['POST'])
def sms():
  body = request.values.get('Body', None)

It'll be easier to work with if we don't have to deal with capitalization, so next we'll normalize everything by making the message lowercase. We'll also print it out so that we can see the contents of the text message in our logs:

@app.route('/sms', methods=['POST'])
def sms():
  body = request.values.get('Body', None)
  sms = body.lower()
  print sms

Let's deploy again and test it out. Follow the instructions above to add these changes to git, include a commit message, and run git push heroku master to deploy the code. Once it finishes, your app will have the required '/sms' endpoint and should receive text messages from your Twilio number. Run the following command so you can watch the logs in real-time and watch for the body of your text message to come through:

$ heroku logs --tail

Now send a text message to your Twilio number. Exciting, right? We are so close now to being able to make those messages control your tree. The next step will be to process those message and turn them into the RGB color format that our Spark Core can accept. If you remember above, when we wrote the Spark function to handle this, we made a promise that the incoming format would be a string that looks like [RRR,GGG,BBB]. We'll be constructing that as part of the next few steps.

Interpret the color

First, we need to get the Red, Green, and Blue values from the color name. We'll use the CSS parser for this. The CSS parser actually returns 4 values, the last being an alpha (transparency) value, but we'll just ignore that. Let's store the output of the parse_color function into an rgba variable.

@app.route('/sms', methods=['POST'])
def sms():
  body = request.values.get('Body', None)
  sms = body.lower()
  print sms

  rgba = tinycss2.color3.parse_color(sms)

If the parse_color function doesn't recognize the color, it will return None. Let's do a quick check for this so we don't try to access values that aren't there, and also notify the person who sent the message that we couldn't find a match for that color.

@app.route('/sms', methods=['POST'])
def sms():
  body = request.values.get('Body', None)
  sms = body.lower()
  print sms

  rgba = tinycss2.color3.parse_color(sms)
  if rgba is None:
      return Response("Sorry, I don't recognize that color.", mimetype='text/plain')

Here, we're using Flask's Response object to send a message back to Twilio. Twilio will take that string and reply to the original sender of the SMS. Twilio can get a little touchy about content-type, so I always specifically define the mimetype as 'text/plain' when creating a response. Note that this response will be prefixed with a "Trial Account" message as long as you're on the free tier.

If rgba isn't None, the program will continue and it'll be safe to extract the red, green, and blue values. We'll make one final check that the rgba was returned correctly by checking its length.

@app.route('/sms', methods=['POST'])
def sms():
  body = request.values.get('Body', None)
  sms = body.lower()
  print sms

  rgba = tinycss2.color3.parse_color(sms)
  if rgba is None:
    return Response("Sorry, I don't recognize that color.", mimetype='text/plain')
  
  if len(rgba) == 4:
    red = int(round(255*rgba[0]))
    green = int(round(255*rgba[1]))
    blue = int(round(255*rgba[2]))
  

Ok, we're doing a little bit more than just taking the values right from rgba -- there's a little processing we're doing there. Let's start from the inside out. If you take a look at the documentation for tinycss2, you'll notice that the parse_color method actually returns a tuple of the 4 values, but it reports each as a value between 0 and 1. Our Spark core function is looking for a color value between 0 and 255. The 0-1 value that parse_color is reporting is a percentage of the full spectrum of each channel, from 0-255, so to convert it we just need to multiply the value by 255. In other words, 100% red would be reported as 1, and 1*255=255.

Moving outwards from there, we're rounding the result because our spark function needs a whole number. If you remember in the Spark application code, we're just parsing a substring (and the color replication isn't going to be incredibly accurate anyway), so it's safe to round to the nearest whole value.

Then, the value is going to be represented as a float (like 65.0), so we're casting that result to an int to get a whole number without a decimal. This gives us 3 integer values that we're going to use to construct the string that we send to our Spark Core.

@app.route('/sms', methods=['POST'])
def sms():
  body = request.values.get('Body', None)
  sms = body.lower()
  print sms

  rgba = tinycss2.color3.parse_color(sms)
  if rgba is None:
    return Response("Sorry, I don't recognize that color.", mimetype='text/plain')
  
  if len(rgba) == 4:
    red = int(round(255*rgba[0]))
    green = int(round(255*rgba[1]))
    blue = int(round(255*rgba[2]))
    rgba_string = '[{0:03d},{1:03d},{2:03d}]'.format(red, green, blue)

This new line assembles a string that will look exactly like what the Spark Core is expecting! Notice the square brackets; those are just part of the string. The curly braces will be replaced with the red, green, and blue variables in the .format() function. Usually the string interpolations would just look like {0}, but we're taking it a step further and requiring them to print out with 3 digits. This means that if a value is 0, it'll print out as 000, and 55 will be 055. Remember, the Spark core is using substrings instead of a smarter data-type like an array or object, so we need to be careful about how the data is passed to it. We made a promise to the Spark Core's code, and this lets us keep that promise.

Notify the Spark Core

The only thing left to do is send that new rgb_string to the Spark Core. We'll do that via the Spark API by calling the color function we set up a while ago. We'll do this with the requests library and the environment variables that you set up in your .env file.

@app.route('/sms', methods=['POST'])
def sms():
  body = request.values.get('Body', None)
  sms = body.lower()
  print sms

  rgba = tinycss2.color3.parse_color(sms)
  if rgba is None:
    return Response("Sorry, I don't recognize that color.", mimetype='text/plain')
  
  if len(rgba) == 4:
    red = int(round(255*rgba[0]))
    green = int(round(255*rgba[1]))
    blue = int(round(255*rgba[2]))
    rgba_string = '[{0:03d},{1:03d},{2:03d}]'.format(red, green, blue)
    payload = {'access_token': os.environ['SPARK_ACCESS_TOKEN'], 'command': rgb_string}
    r = requests.post("https://api.spark.io/v1/devices/{0}/color".format(os.environ['SPARK_CORE_ID']), data=payload)

The first thing we're doing there is creating an object to use as the payload for the POST request. First we're setting the Access Token, which authenticates you to the Spark API (this is secret, and therefore a good reason to keep it as an environment variable). We're also passing in the rgb_string which is now nicely formatted and ready for our Spark Core.

Next, we create the HTTP request by calling requests.post and passing in the URL (constructed by interpolating your Spark Core's ID), and telling it to send our payload object along as the request's data. You can access r to assess the resulting status code and any responses, but that won't be necessary for us.

The only thing left to do is send a response back to Twilio. It doesn't really matter, but if Twilio doesn't get a response, it assumes something went wrong and will report an error. By default there are error alerts and you'll start getting emails and thinking something is going wrong. So to prevent that, add one final line:

@app.route('/sms', methods=['POST'])
def sms():
  body = request.values.get('Body', None)
  sms = body.lower()
  print sms

  rgba = tinycss2.color3.parse_color(sms)
  if rgba is None:
    return Response("Sorry, I don't recognize that color.", mimetype='text/plain')
  
  if len(rgba) == 4:
    red = int(round(255*rgba[0]))
    green = int(round(255*rgba[1]))
    blue = int(round(255*rgba[2]))
    rgba_string = '[{0:03d},{1:03d},{2:03d}]'.format(red, green, blue)
    payload = {'access_token': os.environ['SPARK_ACCESS_TOKEN'], 'command': rgb_string}
    r = requests.post("https://api.spark.io/v1/devices/{0}/color".format(os.environ['SPARK_CORE_ID']), data=payload)
    return Response(mimetype='text/plain')

Notice that the last time we returned a response to Twilio we included a string in the response object. In that case, we wanted to reply to the sender of the message, but this time we don't want to bother them because everything is ok. You could add in a string here that confirms you changed the color, but hopefully they're standing in front of the tree and can see for themselves. When you leave out the string, it tells Twilio that everything is ok, but don't reply with a message to the sender.

Conclusion

It's pretty cool to see the tree change colors when you send it a text message. I'm still surprised by how fast it reacts. That's a compliment for Heroku, Twilio, and Spark. Each request has to go through all those layers to get from your phone to your tree.

Also, I've heard the same thing probably 20 times: "You should put that thing on a webcam and send the number out to the world!" I'd like to caution this for two reasons: you're responsible for the traffic and charges from Heroku and Twilio, and if it gets popular, you'll probably be faced with either upping your Heroku dynos to handle the traffic, or leaving the free tier of Twilio and paying per message received. Also, we don't have code to deal with collisions on the Spark core with multiple requests per second, and I'm not sure how it would handle that. If this is something you'd like to do, proceed with caution. It would be wise to load test it first and set up some extra monitoring on a few of the layers so you can diagnose problems faster when they arise. I've put the tree in our office Cafe, and it's been fairly popular, receiving up to 80 color changes per day (I track these things, but thought it was outside the scope of this tutorial. I recommend Keen if you'd like an easy analytics integration with another generous free tier). The tree has been able to easily handle color changes on this scale, but your mileage may vary.

I've kind of attempted to do this a few times before, but I never made it very far. The mix of hardware and software I chose in this implementation of the idea was the biggest reason for my success. I'm blown away by how awesome it is to work with the Spark Core, and services like Twilio and Heroku. This is an awesome time to build things!

I would have never been able to even get the lights to turn on if it hadn't been for someone porting Adafruit's WS2801 library to the Spark Core. Thanks to Adafruit for writing that, and for "Technobly / BDub" for porting it over.

If you make this tree, I'd love to see it. Send me a picture on Twitter (I'm @willdages). If you have any questions, I'll do my best to answer them. If you have improvements or suggestions, please let me know, or submit a pull request to either of the repositories that hold the code for this tutorial:

Thanks for following along!