VoodooSpark

A RPC-over-TCP firmware for the Spark Core.
It's like being connected, but without the wire!

View the Project on GitHub voodootikigod/voodoospark

What is VoodooSpark?

VoodooSpark is a customized firmware build for the Spark Core device to allow a remote interface definition of the firmware API over a local TCP connection. The intent is to allow client-side programs to directly control the Spark Core in real-time regardless of their programming language. The interface exposed is directly mapped to the one provided by Spark available in their docs section.

The VoodooSpark uses the Spark Cloud and its REST API to provide IP address and port information to the local spark core. It will then initiate a direct connection to the host machine, on which will need to be a TCP server. Once the connection has been made, the host machine can drive the Spark Core using the binary protocol defined below to effectively execute firmware API level commands dynamically.

Loading the Firmware

With your Spark device connected to a Wifi network and having already gone through the standard "claim"/ownership process:

  1. Open the Spark.io Editor with the credentials used when going through the claiming process.
  2. Copy and paste the entire contents of src/voodoospark.cpp into the editor window.
  3. Click "Verify"
  4. Click "Flash"
  5. Once the flashing process is complete, close the Spark.io Editor.

Now your Spark Core is running VoodooSpark, lets connect to it!

Connecting to the Spark Core

The way VoodooSpark works is to use the Spark Cloud as a lookup service to find out the IP Address of the Spark Device. With that address, we open a TCP connection to the Spark Device from your host machine and send it commands. It is that simple.

In order to connect the Spark Core to your computer, you will first need to issue an HTTP GET request to the Spark Cloud. This can be done via any programming language, but for this example we are using a simple CURL command. You will need some information outlined with curly braces below, please note the {DEVICE-ID} and {ACCESS-TOKEN} are available from the Spark.io Editor

curl "https://api.spark.io/v1/devices/{DEVICE-ID}/endpoint?access_token={ACCESS-TOKEN}"

This should return a JSON document that looks similar to this:

{
  "cmd": "VarReturn",
  "name": "endpoint",
  "result": "192.168.1.10:48879",
  "coreInfo": {
    "last_app": "",
    "last_heard": "2014-05-08T02:51:48.826Z",
    "connected": true,
    "deviceID": "{DEVICE-ID}"
  }
}

The "result" value is the IP address of the Spark Device on your local network and the part after the colon (:) is the port that the server is currently listening on. This port will be 48879 (0xBEEF) by default, but can be changed in the voodoospark firmware. Please do not hardcode the port for this reason, instead just use the data returned back as the response.

With the IP Address and TCP port information, use your favorite language or TCP client to connect to the device (even telnet will work) and send it the necessary BINARY protocol commands to trigger the desired API interactions as defined in our API Command Guide below, which is just a smaller version of the Core Firmware API provided by the Spark itself.

Reference Implementations

API Command Guide

This outlines the API exposed by the VoodooSpark firmware. It requires the TCP connection to be established to the Spark Device as outlined here. All of these commands are designed to allow you to create a state change in the Spark Device. They may return information, but that is not a requirement. Please be aware that all values expressed are as single byte in length unless otherwise specified.

Pin Mode

Direction: To Spark
First Byte: 0x00
Subsequent Bytes/Parameters:
  1. Pin Number: The number of the pin whose mode you wish to set
  2. Mode: The mode to set the pin to where the following values map to the named modes:
    • 0 => INPUT
    • 1 => OUTPUT (Use for Digital, Analog and PWM writes)
    • 2 => INPUT_PULLUP
    • 3 => INPUT_PULLDOWN
    • 4 => SERVO (Use for Servo writes)
Return: None

Digital Write

Direction: To Spark
First Byte: 0x01
Subsequent Bytes/Parameters:
  1. Pin Number: The number of the pin whose value you wish to set
  2. Value: The value to set the pin.
Return: None

Analog Write

Direction: To Spark
First Byte: 0x02
Subsequent Bytes/Parameters:
  1. Pin Number: The number of the pin whose value you wish to set
  2. Value: The value to set the pin.
Return: None

Digital Read

Direction: To Spark
First Byte: 0x03
Subsequent Bytes/Parameters:
  1. Pin Number: The number of the pin whose value you wish to set
Return: 4 bytes which have 0x03 as the first byte, the pin as the second, lsb as third and msb as fourth.

Analog Read

Direction: To Spark
First Byte: 0x04
Subsequent Bytes/Parameters:
  1. Pin Number: The number of the pin whose value you wish to set
Return: 4 bytes which have 0x04 as the first byte, the pin as the second, lsb as third and msb as fourth.

Always Send Bit

Direction: To Spark
First Byte: 0x05
Subsequent Bytes/Parameters:
  1. Pin Number: The number of the pin whose value will always be sent in the continuous reporting stream.
  2. Value: The value to set the pin, 1 for digital and 2 for analog.
Return: None

Serial.begin

Direction: To Spark
First Byte: 0x10
Subsequent Bytes/Parameters:
  1. Type: 0 will use Serial and any other value will use Serial1.
  2. Speed: parameter that specifies the baud rate from the Baud Rate mapping.
Return: None

Serial.end

Direction: To Spark
First Byte: 0x11
Subsequent Bytes/Parameters:
  1. Type: 0 will use Serial and any other value will use Serial1.
Return: None

Serial.peek

Direction: To Spark
First Byte: 0x12
Subsequent Bytes/Parameters:
  1. Type: 0 will use Serial and any other value will use Serial1.
Return: 4 bytes which have 0x12 as the first byte, the pin as the second, lsb as third and msb as fourth.

Serial.available

Direction: To Spark
First Byte: 0x13
Subsequent Bytes/Parameters:
  1. Type: 0 will use Serial and any other value will use Serial1.
Return: 4 bytes which have 0x13 as the first byte, the pin as the second, lsb as third and msb as fourth.

Serial.write

Direction: To Spark
First Byte: 0x14
Subsequent Bytes/Parameters:
  1. Type: 0 will use Serial and any other value will use Serial1.
  2. Length: The length of the message to write.
  3. Data: Length total number of bytes to write to the identified serial port.
Return: None

Serial.read

Direction: To Spark
First Byte: 0x15
Subsequent Bytes/Parameters:
  1. Type: 0 will use Serial and any other value will use Serial1.
Return: 4 bytes which have 0x15 as the first byte, the pin as the second, lsb as third and msb as fourth.

Serial.flush

Direction: To Spark
First Byte: 0x16
Subsequent Bytes/Parameters:
  1. Type: 0 will use Serial and any other value will use Serial1.
Return: None

Stream Guide

Digital Read Reporting

Direction: To Host
Action: 0x03
Subsequent Bytes/Parameters:
  1. Pin Number: The number of the pin being reported
  2. LSB: bits 0-6
  3. MSB: bits 7-13

Analog Read Reporting

Direction: To Host
Action: 0x04
Subsequent Bytes/Parameters:
  1. Pin Number: The number of the pin being reported
  2. LSB: bits 0-6
  3. MSB: bits 7-13