Starkiller
programming and such
Posted on 10 March 2015

Spark creates low-cost, WiFi-enabled hardware devices that pair with a flexible, easy-to-use cloud platform for interacting with the physical world. Their current device, the Spark Core, is a postage-stamp-sized platform that opens up the world of hardware hacking in a tiny package.

Spark's Cloud API allows developers to easily trigger remote execution of code on any of their Spark Core devices through a simple HTTP call. However, developers have always been limited in their options to make callouts to other web APIs. The Spark Core does not support encrypted HTTP communication, which many APIs require, and the built-in HTTP client does not implement all of HTTP 1.1. Developers looking to integrate their Spark devices with external APIs were required to stand up separate proxy servers that would translate a Spark core HTTP request to an encrypted request to external services.

Spark recently announced webhook support for their Cloud API. With this feature, developers can define calls to external HTTP services when specific events occur on their Spark devices. Essentially, Spark has stood up their own proxy server that developers can now tie into with a declarative interface.

Enter Twilio

A long standing desire of mine is to be able to send a text message from my Spark device when a certain event occurs. Imagine receiving a text when your doorbell is rung or there is a knock on your door and you are not home, or perhaps receiving a warning message when the moisture level of the soil for your outdoor garden falls below a certain threshold. Twilio provides a simple HTTP API for sending text messages, but unfortunately, Twilio requires encrypted HTTP communication which the Spark Core does not support.

With Spark's webhook support, however, we can directly tie events that occur on my Spark device to Twilio's API!

Define the Webhook

The first step is to define the webhook. Spark defines webhooks with a JSON with a number of optional fields; while I will cover many fields, all of the options can be found in Spark's webhook documentation.

Let's take a look at the definition for a Twilio webhook with Spark:

{
    "eventName": "twilio",
    "url": "https://api.twilio.com/2010-04-01/Accounts/ACCOUNT_SID/Messages",
    "requestType": "POST",
    "auth": {
        "username": "ACCOUNT_SID",
        "password": "AUTH_TOKEN"
    },
    "form": {
        "From" : "FROM_TWILIO_NUMBER",
        "To" : "TO_NUMBER",
        "Body" : "{{SPARK_EVENT_VALUE}}",
        "MediaUrl" : "https://dl.dropboxusercontent.com/u/10931735/big_spark-mark-400px.png"
    },
    "mydevices": true
}

The eventName is the event prefix that this webhook will listen to and fire on. Since we're listening for "twilio", any event that my device fires that begins with "twilio" will cause this webhook to be executed.

The url is the HTTP endpoint that we want our endpoint to hit. In this case, you will need to replace ACCOUNT_SID with your Twilio account sid, available from the Twilio account portal.

The requestType defines the HTTP method invoked to execute the webhook.

The auth section defines any HTTP Basic Authentication tokens that will be required to access the URL. For this example, you will need to replace the ACCOUNT_SID and AUTH_TOKEN with your Twilio credentials, available from the Twilio account portal.

The form section defines any form parameters that should be sent with your webhook. When set, the request is made with the Content-Type: application/x-www-form-urlencoded header. For this example, the FROM_TWILIO_NUMBER is your Twilio number you want to send from, the TO_NUMBER is the phone number you want to send the message to, and Body is the body of the text message. The {{SPARK_EVENT_VALUE}} is a template placeholder, and the value of this is replaced by data sent from your Spark device. The final field, MediaUrl, is a URL to an image that I want to send along with my message.

The mydevices ensures that this webhook is only fired when a matching event occurs from one of your devices; you can actually trigger webhooks on events from any Spark device that publishes to the public stream!

Upload the Webhook

Save the above JSON to a file called twilio.json.

To upload the webhook, you need to have Node.js installed. While Spark did a great job integrating webhook support into their SparkCLI, there is a current bug that does not allow form data to be declared with the webhook JSON. I have an open pull request to fix this issue, but until then you can install my fork of SparkCLI using the following:

$ npm install -g git+https://github.com/hoxworth/spark-cli.git

Once installed, you can upload your webhook with the following command:

$ spark webhook create twilio.json

If successful, you should see output like the following:

Using settings from the file twilio.json
Sending webhook request  { uri: 'https://api.spark.io/v1/webhooks',
  method: 'POST',
  json: true,
  form:
   { event: 'twilio',
     url: 'https://api.twilio.com/2010-04-01/Accounts/ACCOUNT_SID/Messages',
     deviceid: undefined,
     access_token: 'ACCESS_TOKEN',
     requestType: 'POST',
     headers: undefined,
     json: undefined,
     query: undefined,
     auth:
      { username: 'ACCOUNT_SID',
        password: 'AUTH_TOKEN' },
     mydevices: true,
     form:
      { From: 'FROM_TWILIO_NUMBER',
        To: 'TO_NUMBER',
        Body: '',
        MediaUrl: 'https://dl.dropboxusercontent.com/u/10931735/big_spark-mark-400px.png' } } }
Successfully created webhook!

Hooray, the webhook is created! Now any time an event from "twilio" is fired from one of your devices, the webhook will execute.

Invoke the Webhook

Now that we have the webhook completed, let's write some basic code for our Spark device to create an event that will cause the callback to be executed. I'll simply write a Spark function that can be called from the Cloud API for easy testing; in a real world setting, we more than likely would trigger events on sensor readings, periodic functions, or some other real world event.

int sendMessage(String command);

void setup()
{
    Spark.function("sendMessage", sendMessage);
}

int sendMessage(String command)
{
    Spark.publish("twilio", "Ahoy there! This is a message sent from your Spark Core device!", 60, PRIVATE);
}

Save this and flash your Spark device with this project. We can now invoke the function using the SparkCLI:

$ spark call DEVICE_ID sendMessage

If successful, you should have received a new message on your phone! Yay!