Blog

Ship IoT with Particle.io's Photon and Bip.io

Aug 2015/ Posted By: wotio team

<h2 id="gettingstartedwiththephoton">Getting Started with the Photon</h2>
<p>The <a href="https://www.particle.io/">Particle</a> <a href="https://store.particle.io/?product=particle-photon">Photon</a> is a small open source WiFi dev board with an embedded STM32 ARM Cortex M3 microcontroller:</p>
<p><a href="https://www.particle.io/prototype#photon"><img title="" src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/photon-new-3e010e9f-1.jpg" alt="" /></a></p>
<p>It supports a number of analog and digital inputs, and with some work can communicate with devices via TWI, I2C, or SPI. For this example, we're going to connect it to a triple axis accelerometer breakout board from Sparkfun:</p>
<p><a href="https://www.sparkfun.com/products/12756?gclid=CJ-G3LrpnscCFYORHwodpwgCgA"><img title="" src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/12756-00-1.jpg" alt="" /></a></p>
<p>This board has a Freescale MMA8452Q accelerometer which supports an I2C interface. The total component cost of these two prototyping boards is about $30USD, making it rather inexpensive.</p>
<p>For our development environment, we will need both the <a href="https://www.particle.io/prototype#particle-dev">Particle Dev</a> and <a href="https://www.particle.io/prototype#cli">Particle CLI</a> tools. All of the device driver code will be developed in the IDE, and the CLI will be used to setup the web hook to send our event data to Bip.io.</p>
<h3 id="writingadevicedriver">Writing a Device Driver</h3>
<p>The Particle firmware mimics the Arduino API in a lot of ways, but there are some significant differences. These differences largely take three forms:</p>
<ul>
<li>new methods specific to the Photon's hardware</li>
<li>different header files which need to be included</li>
<li>compiler is remote in the cloud!</li>
</ul>
<p>The fact that your compiler is not local to your machine means you need to bundle your projects in a Particle Dev specific way. All of your files must live in the same directory and are sent via HTTP to the compiler via a multi-part mime document POST request. This means you must supply all of your library code each time you compile or make a change.</p>
<p>The code for this device driver can be found at:</p>
<p><a href="https://github.com/WoTio/shipiot-photon-mma8452Q">https://github.com/WoTio/shipiot-photon-mma8452Q</a></p>
<p>And you can get it via git clone using:</p>
<p><code>git clone https://github.com/WoTio/shipiot-photon-mma8452Q</code></p>
<p>The data sheet for the MMA8452Q can be found at:</p>
<p><a href="http://www.freescale.com/files/sensors/doc/data_sheet/MMA8452Q.pdf">http://www.freescale.com/files/sensors/doc/data_sheet/MMA8452Q.pdf</a></p>
<p>And it goes without saying, but you should download and save the data sheet somewhere for future reference. This chip has a lot of features that we aren't going to use or cover, and the data sheet provides information on using it for a wide range of applications including: tap detection, portrait vs. landscape orientation detection, and freefall detection.</p>
<p>The first file we're going to look at is the mma8452.h file:</p>
<script src="https://gist.github.com/cthulhuology/84cce6b10c71bd961b09.js"></script>
<p>Here we define a C++ class that will model the state of our MMA8452 accelerometer. Our default constructor will set the I2C bus address to 0x1d. If you jumper the pads on the bottom of the accelerometer board, you can change the address to 0x1c. If you do this, you will need to supply that address to the constructor.</p>
<p>In our initial setup phase, we will call <code>begin</code> which will initialize the I2C interface, place the board into standby mode, and then set the scale and data rate to their default values. Finally it will turn the data output on by exiting standby mode:</p>
<script src="https://gist.github.com/cthulhuology/efb3815a136a5b883255.js"></script>
<p>Setting the board to standby mode is done by clearing the low bit on the register 0x2a:</p>
<script src="https://gist.github.com/cthulhuology/89eb54ccc5842f39fb2c.js"></script>
<p>We start data flow by toggling this bit back to one:</p>
<script src="https://gist.github.com/cthulhuology/83d68a6a2c05198d5cf3.js"></script>
<p>The Freescale MMA8452 needs to be in standby mode to modify any of the control registers. To modify the data rate, we can write a rate factor to the control register 0x2a:</p>
<script src="https://gist.github.com/cthulhuology/16ba412036766b0235a2.js"></script>
<p>The rate factor defaults to 000 which per table 55 of the data sheet amounts to 800Hz. Our wire speeds on the Photon has two settings 100kHz or 400kHz, both of which are more than sufficient by a couple orders of magnitude to support the output data of our device. And since we're going to drive this off of a 5V 1A mains wired power supply, we're not going to worry about the low power modes. We could easily lower the sample rate, as we are unlikely to update the web API that frequently. Changing the output data rate to something closer to 2x your polling frequency should be adequate.</p>
<p>To configure the scale (multiple in G over which our 12bits represent) of the x, y, and z components, we need to write to the low two bits of the register at address 0x0e.</p>
<script src="https://gist.github.com/cthulhuology/8d5b1a1e4234ec7e7a6a.js"></script>
<p>These bits per table 16 set 2G (00), 4G (01), or 8G (10). Currently the value of 11 is reserved, and should not be supplied. Since we're unlikely to swing this around like a dead cat, 2G is sufficient for testing. If you'd like to handle larger swings, feel free to bump the rate up to 8G!</p>
<p>Finally, we need a way to test for the availability of data, and a way to retrieve that data once we have some. To test for availability of xyz data, we check bit 3 of the status register at address 0x00.</p>
<script src="https://gist.github.com/cthulhuology/de2389e97cea0a8b548e.js"></script>
<p>If we were only interested in the fact that one axis changed, or only wanted to look for movement in one direction, we could query other status register bits, but this is good enough for now.</p>
<p>Then to read the data once available, we can make a call to read the 6 bytes starting at address 0x01. This will give us X,Y,Z in MSB order, wherein we need to trim the bottom 4 bits of the LSB byte (as the sample size is 12 bits).</p>
<script src="https://gist.github.com/cthulhuology/7d4453d6d218e59349ad.js"></script>
<p>The actual input and output is done by a pair of routines which simply write the request and destination register and a input or output byte array and length. The <code>available</code> and <code>read</code> methods use the <code>in</code> method:</p>
<script src="https://gist.github.com/cthulhuology/4d3782687fe4b4a796ce.js"></script>
<p>Whereas the <code>standby</code>, <code>start</code>, <code>scale</code> and <code>rate</code> methods use the <code>out</code> method to update the register values:</p>
<script src="https://gist.github.com/cthulhuology/174258832ba544677e38.js"></script>
<h3 id="writingasketch">Writing a Sketch</h3>
<p>The application we're going to use to forward our accelerometer data to our web application will simply initialize the accelerometer and then publish an event every second with the most recent values of x, y, and z.</p>
<script src="https://gist.github.com/cthulhuology/8b7709d0d10a5e9f73a4.js"></script>
<p>For sake of our sanity, we can also log the x,y,z values to the Serial interface, which will allow us to record the values as we see them. If you supply power to the Photon via your computer's USB, the Serial interface can be discovered as usb modem / serial device.</p>
<p>You can understand the <code>setup()</code> and <code>loop()</code> functions in the context of the <a href="https://github.com/spark/firmware/blob/master/src/main.cpp">main.cpp</a> file from the firmware. The .ino files get translated to C++, it adds some header files, and is referenced in the <code>main()</code> function. The activities taken by <code>main()</code> are:</p>
<ul>
<li>setup the WLAN interface</li>
<li>waits until WLAN is ready</li>
<li>first loop through, it calls <code>setup()</code></li>
<li>then it calls <code>loop()</code> each iteration forever</li>
</ul>
<p>Should the WLAN interface fail to connect, the system will stay in the wait state, which means the LED will continue to blink green, and your application will not run.</p>
<h2 id="wiringuptheboard">Wiring up the Board</h2>
<p>Now that we have our software ready for testing on hardware, it is a good idea to wire up the nets on a breadboard for testing.</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/board.jpg" alt="breadboard" /></p>
<p>For testing we connect the USB to our computer so we can watch the Serial output. For the pins we connect from the Photon to the breakout board:</p>
<ul>
<li>3.3V to 3.3V</li>
<li>GND to GND</li>
<li>D0 to SDA</li>
<li>D1 to SCL</li>
</ul>
<p>Following Sparkfun's app note, I'm using 2 x 330&Omega; resistors between D0 and SDA and D1 and SCL. You should see roughly 3.3V on pins 4 and 5 of the breakout board when the application is idle (I2C is active low). If you have a raw MMA8452Q, look at figure 4 on the data sheet. To wire it up, you will need:</p>
<ul>
<li>2 x 4.7k&Omega; pull up resistors tied to 3.3V from pin 4 (SDA) and pin 6 (SCL)</li>
<li>a 0.1&micro;F bypass capacitor attached to pins 1 (VDDIO)</li>
<li>a 0.1&micro;F capacitor tied to GND and pin 2 (BYP)</li>
<li>a 4.7&micro;F bypass capacitor attached to pin 14 (VDD)</li>
</ul>
<p>As we're going to wave the accelerometer around, I am going to fix mine to a perma-proto board. We can use a fairly simple setup:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/setup.png" alt="ciruit diagram" /></p>
<p>Here I'm using:</p>
<ul>
<li>5 x 6 pin female headers</li>
<li>2 x 330&Omega; resistors for current limiting</li>
<li>22 guage wire jumpers</li>
</ul>
<p>For the wiring, I'm going to:</p>
<ul>
<li>jumper pin 1 of SV3 to pin 6 of SV1</li>
<li>jumper pin 4 of SV3 to pint 1 of SV1</li>
<li>tie one resistor to pin 6 of SV2</li>
<li>tie the other resistor to pin 5 of SV2</li>
<li>jumper the resistor tied to pin 6 of SV2 to pin 5 of SV1</li>
<li>jumper the resistor tied to pin 5 of SV2 to pin 4 of SV1</li>
</ul>
<p>This way I can replace both the breakout board the the Photon or simply reuse them on other projects. I've also added a 6th header on the other side of my board so I can setup a second app with some analog sensors on the right side:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/IMG_6613.jpg" alt="perma-proto board top" /></p>
<p>The bottom of the board looks like:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/IMG_6614.jpg" alt="perma-proto board bottom" /></p>
<p>As you can probably tell, I've reused this board for a few other projects, but that has mostly had to do with resoldering the the jumpers for the I2C pins.</p>
<p>The this point, you should be able to setup your WiFi connection using the Particle phone app, or you can use the <code>particle setup wifi</code> CLI command to configure your board. Once your board is connected to your WiFi, you can use the <code>compile and upload code using the cloud</code> button to flash your device with the app.</p>
<h2 id="configuringyourworkflow">Configuring your workflow</h2>
<p>Over at <a href="http://shipiot.net">Shipiot.net</a>, you can sign up for a free bip.io account. Bip.io is a data service that provides integrations into a number of web applications. It allows you to create automated workflows that are attached to your device's data.</p>
<p>For this tutorial, we will connect our data to a web based graph. We will use this graph to visualize the data. Later we could attach actions based on patterns we discover in the data. For example, if we attached the Photon and accelerometer to an object, each time the object moved, we could have Twilio send a text message to our phone, and we could record each movement to a Google Spreadsheet for later analysis.</p>
<p>Once you click the <code>Create A Bip</code> button, you will be taken to a blank workflow canvas:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/blank-1.png" alt="blank canvas" /></p>
<p>If you click on the center circle, you will be able to <code>Select Event Source</code>:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/webhook-selection.png" alt="select event source" /></p>
<p>For integrating with the Particle.io's Cloud API, we will select <code>Incoming Web Hook</code> which will allow us to process each event that is sent by their webhook to our workflow. After selecting <code>Incoming Web Hook</code>, your canvas should look like this:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/webhooked.png" alt="incoming web hook" /></p>
<p>Above the canvas, there is a URL bar with a path component set to <code>Untitled</code>. Change this to <code>accel</code> so that we can have a path that looks like:</p>
<p><code>http://&lt;your_username&gt;.api.shipiot.net/bip/http/accel</code></p>
<p>We will need this URL to setup the webhook on the the Particle.io Cloud API. Before we do that, however, we should finish configuring the remainder of the workflow so that the Cloud API doesn't error out while attempting to connect to an endpoint that doesn't exist!</p>
<p>Next we'll add a chart to visualize the data coming in off of the X and Y components of the accelerometer. First thing to do is click <code>Add An Action</code>, and it will bring you to an action selection panel:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/data-viz-1.png" alt="action selection panel" /></p>
<p>Here we will select <code>Data Visualization</code>, which will enable us to plot the values sent by the device. Click it will bring us to a subpanel:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/view-chart-1.png" alt="action behavior selection panel" /></p>
<p>To view the data in chart form we'll obviously pick <code>View Chart</code>, but we could as easily generated a visualization that would have allowed us to view the data as JSON or simply see the raw data as it enters the system. This is very handy for debugging communications between elements in our workflow.</p>
<p>Once we've selected the <code>View Chart</code> option, we will be presented with a canvas with two nodes on it:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/two-nodes-1.png" alt="webhook + data visualization" /></p>
<p>Now by dragging and dropping from the <code>Incoming Web Hook</code> icon to the <code>Data Visualization</code> icon, we can create a data flow from one to the other:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/link-creation.png" alt="data flow" /></p>
<p>Now all of the messages that come in at our URL will be sent to the chart. But in order for us to plot the data, we need to describe the contents of the message. Clicking on the <code>Parser</code> tab will bring you to a two panel interface that looks like this:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/parser-1.png" alt="parser interface" /></p>
<p>Into the left panel, we will enter some JSON that looks like the JSON that our application sent to the API:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/parser-with-json.png" alt="json in parser interface" /></p>
<p>We then click the <code>Parse</code> button to generate the associated JSON schema:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/parser-with-results.png" alt="json schema" /></p>
<p>We can now use these values as inputs to our chart. If we double click on the icon for the data visualizer, it will bring up a control panel for setting a number of values. Scroll down to the bottom of the panel and you'll see entries for setting the value of X, Y1, and Y2. For the X value we'll use the time of the incoming request:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/invoke-time.png" alt="setting X" /></p>
<p>We can then set the Y1 and Y2 values to the accelerometer's x and y values respectively:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/both-data-points.png" alt="setting y1" /></p>
<p>Once you click <code>OK</code> it will save the configuration. Double clicking the icon again will present you additional tabs including one for the <code>Chart</code>:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/chart-url.png" alt="chart tab" /></p>
<p>Here we can copy the URL and open it up in a new browser window to see the data as it comes in.</p>
<p>The last thing we need to do before saving our workflow is setup some credentials for the webhook. By selecting the <code>Auth</code> tab under the webhook panel, we can change the authentication to <code>Basic Auth</code>, and in my case I'm going to use test:test for submitting data to my webhook:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/auth.png" alt="auth" /></p>
<p>We will also need the <code>Authorization</code> header later to configure the webhook on the Cloud API side of things. Clicking <code>Save</code> or <code>Save and Close</code> will start your workflow running!</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/running.png" alt="running" /></p>
<h2 id="configuringthecloudapi">Configuring the Cloud API</h2>
<p>For the remainder of the setup, we will use the particle CLI tool to interact with the device and the Particle Cloud API. The <code>particle</code> CLI tool allows us to do basically everything we need including flashing the chip.</p>
<p>To compile our source code we can use the <code>particle compile command</code>:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/Screen-Shot-2015-08-11-at-3-14-18-PM.png" alt="particle compile photon *" /></p>
<p>This will save our firmware image to a .bin file in the local directory. We can flash this via USB or over WiFi. To flash over WiFi, we need the device ID from the listing which we can get with <code>particle list</code></p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/particle-list.png" alt="particle list" /></p>
<p>Here I'll flash my device <code>darkstar02</code> using the <code>particle flash</code> command:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/flash.png" alt="particle flash" /></p>
<p>Being able to flash your device remotely is really handy when you've installed the device somewhere. You can also provide the source files to the <code>particle flash</code> command, and the cloud will attempt to compile it and flash it too, but I like having a copy of the firmware for flashing again at a later date.</p>
<p>Once the device is done flashing and LED is breathing teal, we can attach to the serial monitor using the <code>particle serial monitor</code> command:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/serial-monitor.png" alt="serial monitor" /></p>
<p>As you can see I shook the device a couple times to make sure it was working. If you don't see any serial output, that probably means your sketch isn't working. Unfortunately, debugging via the serial monitor doesn't have a full debugger support.</p>
<p>Assuming you are seeing data in the serial monitor, you can then setup the Particle Cloud API webhook. Edit the <code>accel.json</code> file to contain your device details:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/accel-json.png" alt="accel.json" /></p>
<p>Once you've setup your <code>device</code> and <code>url</code> settings, you can create the webhook using the <code>particle webhook create</code> command:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/create-webhook.png" alt="particle web create accel.json" /></p>
<p>This webhook forwards all of the events published to the <code>accel</code> events to the url specified in our <code>accel.json</code> file. We can sample these events using the <code>particle subscribe</code> command to view the messages as they arrive from the device:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/partcle-subscribe.png" alt="particle subscribe" /></p>
<p>Because the webhook has the <code>json</code> line in it, the data sent to our URL will have the x, y, and z values extracted from the <code>data</code> field and placed in the top level of the event. The json sent to the webhook also contains device details, ttl, etc. as well.</p>
<h2 id="viewingthedata">Viewing the Data</h2>
<p>If you remember the URL of the chart URL, you can after a few seconds pop over to the chart and see the new data as it comes in. You will need to be logged into shipiot.net to view the data. Here's a sample with me shaking the device:</p>
<p><img src="http://idfiles.leveelabs.com/55bd0288af0b0930ba599bd0c4b7ca38/resources/img_new/labs_wot_io/results.png" alt="results" /></p>
<p>At this point, you can go back and add new actions to your workflow, and have them trigger based on changes in the state of your device. Send a tweet. SMS your friends. Record your shaking to a spreadsheet.</p>