IoT

Temboo ignited with a Spark

This is a re-post of an article I wrote as a guest blogger for Temboo’s blog.
I am working with connected devices and was looking for a cloud service. While surveying the field Temboo caught my eye because of the large number of supported premium web sites and the promise to connect IoT devices to the Internet in a breeze.
spark_size The connected device I am using is a Spark Core. The Spark Core is a sleek small board that offers a powerful 32 bit ARM CPU paired with WiFi. The product grew out of a Kickstarter campaign and is rapidly gaining in popularity. The Spark is nicely priced and everything is open source. The team supporting the Spark Core is smart and supportive and made a great choice to port most of the main Arduino APIs to their platform.
As outline in a blog post here migrating Arduino Libraries to the Spark Core often turns out to be pretty easy. With Temboo providing an open source library for Arduino I was tempted to give it a try. However, I had no Temboo-Arduino setup so I was not sure how hard it would be to get it all up and running.
Well, I am happy to report that is was easier than expected. Temboo’s code is well written. I only had to work around some AVR specific optimizations that Temboo did to save program memory. As the Spark Core is built around a STM32F103 chip resources are not as tight as with the AVR so I simply bypassed these optimizations.
Here are some brief instructions how to install the Temboo Arduino Library. The instructions use the Spark command line SDK setup:

  1. Download the modified Temboo Arduino Library source code from github:
    mkdir temboo
    cd temboo
    git clone https://github.com/bentuino/temboo.git
  2. Get the Spark Core firmware:
    git clone https://github.com/spark/core-firmware.git
    git clone https://github.com/spark/core-common-lib.git
    git clone https://github.com/spark/core-communication-lib.git
    // Merge the two source codes
    cp -fr core-* temboo
    rm -fr core-*
  3. In older Spark firmware there is a small problem that the spark team already fixed. Open the file core-firmware/inc/spark_wiring_ipaddress.h and uncomment the line 54 with your favorite editor:
    // Overloaded cast operator to allow IPAddress objects to be used where a pointer
    // to a four-byte uint8_t array is expected
    //operator uint32_t() { return *((uint32_t*)_address); };
    bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); };
    bool operator==(const uint8_t* addr);
  4. Save your TembooAccount.h you generated with DeviceCoder to temboo-arduino-library-1.2\Temboo
  5. Now it is time to build the Spark application:
    cd temboo/core-firmware/build
    make -f makefile.temboo clean all
  6. Connect your Spark Core to your computer via a USB cable
  7. Push both buttons, release Reset button and continue holding the other button until RGB-LED lights up yellow
  8. Download application into Spark Core
    make -f makefile.temboo program-dfu

Temboo Examples

Two simple Spark application examples are included:

  • core-firmware/src/application_gxls.cpp – Example demonstrates the Temboo library with Google Spreadsheet
  • core-firmware/src/application_gmail.cpp – Example demonstrates the Temboo library with Gmail

to change the example that is built, edit the first line in the core-firmware/src/build.mk file:

CPPSRC += $(TARGET_SRC_PATH)/application_gxls.cpp

or

CPPSRC += $(TARGET_SRC_PATH)/application_gmail.cpp

Building this code was tested under Windows 8.1 using cygwin and the MINGW version of the ARM GCC compiler tool chain. It should be easy to use this Temboo Library with the Spark Cloud based SDK. To configure the Library to support Spark all the is required is to define the following label:

CFLAGS += -DSPARK_PRODUCT_ID=$(SPARK_PRODUCT_ID)

or add a

#define SPARK_PRODUCT_ID SPARK_PRODUCT_ID

to the source code. Temboo support for the Spark Core is a lot of fun. It is easy to setup your own Temboo account and compile the Temboo Arduino Library that now supports the Spark Core platform. To learn more about similar projects please visit my blog at http://bentuino.com.

Google polls Spark Core

appsIn a previous blog post I was describing an example of how a Spark Core can be used to read weather sensors. The setup was really no different from any simple Arduino Uno setup. It only demonstrated how easy it is to port Arduino Sketches to a Spark Core.
With the integrated WLAN I was interested to connect the Spark Core to the internet cloud. One of the simplest ways I found, was using Google’s Spreadsheet service. I stumbled over this idea in this Spark forum post.
Here is how it works: a Google Script is periodically reading data from the Spark Core via the RESTful Spark API and then appends the data to a Spreadsheet. The code below is a minimalistic Spark code to test the such a setup:

int variable = 1634;
void setup() {
  Spark.variable("variable", &variable, INT);
}
void loop() {
  variable++;
  delay(5000);
}

It publishes a variable for cloud access and then increments it in regular intervals. Together with the following Google script I was able to quickly pull data from my core.

function collectData() {
  var  sheet = SpreadsheetApp.getActiveSheet();
  var sensor = UrlFetchApp.fetch("https://api.spark.io/v1/devices/<id>7/variable?access_token=<token>");
  // parse the JSON the Core API created
  var sensor = JSON.parse(sensor.getContentText());
  // you'll need to unescape before your parse as JSON
  var sensor_result = unescape(sensor.result);
  // create a time stamp
  var d = new Date();
  // append data to spreadsheet
  sheet.appendRow([d, sensor_result]);
}

However when I setup a time trigger to run the script in regular intervals I found the setup to be very unreliable. This is discussed and documented by several Spark Users and as of this writing I have not seen a fix for this problem.
One thing to note is, that this approach is pulling data from the Spark Core rather than the core pushing them to the cloud. This has a significant flaw as we cannot put the core into standby between the measurement intervals. Therefore this solution is anyway not a good choice for low power applications.
So stay tuned, I am experimenting with a better solution that I will blog about in my next post.

RedBear BLE Module

Bluetooth Low Energy (BLE) transceiver board. BLE is a new protocol introduced in the 4.0 revision of the Bluetooth standard. It is a wireless personal area network (PAN) technology aimed at novel applications in the healthcare, fitness, security, and home entertainment industries.  BLE is not backward-compatible with the previous Bluetooth protocol. However it uses the same 2.4 GHz frequency bands but a simpler modulation scheme. The picture below shows the RedBearLab BLE Mini Board.MKRBL2-2T
The module is a combo of a RBT01 BLE module featuring the Ti CC2540 Single chip Bluetooth (SoC) and a breakout board that offers a micro USB connector and a 3.3Volt UART connectors. The main reason this board caught my attention is the fact that it also has solder points for additional GPIOs on the back of the board. These GPIOs can be custom programed. So it should be possible to hook up  I2C or SPI sensors to the board and with a bit of software be able to monitor them.
Using such a BLE board  is not exactly an IoT solution as the connectivity to the cloud would have to be implemented with for example a Wireless enhanced Gallileo. Also the BLE’s range is rather limited. However when it comes to power consumption BLE has a leg up as it was specifically designed for very low power.

Windows for Galileo

Wintel
According to HotHardware.com there are signs that Microsoft will start supporting Galileo with a new “Windows on Devices” version that targets IoT and other smart devices.  Why is this noteworthy?  Well, this would in fact mean that the PC-era “Wintel” team is entering the Maker scene with their newly paired product offerings supporting an Arduino Maker platform.
This is certainly a welcome move as it broadens the choice of platforms and products Makers have to use in their project.

Spark Core Weather Station

In my previous blog post I described my first encounter with the Spark Core. Today I want to demonstrate a first simple code example. For this I connected the Spark Core to a Weather Shield from Sparkfun. The shield offers sensors for light, humidity, temperature and pressure. It can even be extended with rain and wind sensors as well as GPS.
.Spark Core Weather
The shield comes with a nice set of libraries and examples that I used as a starting point. To keep things really simple, I combine the entire Weather Shield source with the sensor library functions and the setup() and loop() into a single file. This did not take long and compiled quickly. I also removed the wind and rain related functionality as I did not plan to use those. The source code below takes measurements every second and writes the them to the USB serial port.

/*
MPL3115A2 Barometric Pressure Sensor Library
By: Nathan Seidle
SparkFun Electronics
Date: September 22nd, 2013
License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
This library allows an Arduino to read from the MPL3115A2 low-cost high-precision pressure sensor.
If you have feature suggestions or need support please use the github support page: https://github.com/sparkfun/MPL3115A2_Breakout
Hardware Setup: The MPL3115A2 lives on the I2C bus. Attach the SDA pin to A4, SCL to A5. Use inline 10k resistors
if you have a 5V board. If you are using the SparkFun breakout board you *do not* need 4.7k pull-up resistors
on the bus (they are built-in).
Link to the breakout board product:
Software:
.begin() Gets sensor on the I2C bus.
.readAltitude() Returns float with meters above sealevel. Ex: 1638.94
.readAltitudeFt() Returns float with feet above sealevel. Ex: 5376.68
.readPressure() Returns float with barometric pressure in Pa. Ex: 83351.25
.readTemp() Returns float with current temperature in Celsius. Ex: 23.37
.readTempF() Returns float with current temperature in Fahrenheit. Ex: 73.96
.setModeBarometer() Puts the sensor into Pascal measurement mode.
.setModeAltimeter() Puts the sensor into altimetery mode.
.setModeStandy() Puts the sensor into Standby mode. Required when changing CTRL1 register.
.setModeActive() Start taking measurements!
.setOversampleRate(byte) Sets the # of samples from 1 to 128. See datasheet.
.enableEventFlags() Sets the fundamental event flags. Required during setup.
*/
/*******************************************************************************************/
//#include "MPL3115A2.h"
/*******************************************************************************************/
#define MPL3115A2_ADDRESS 0x60 // Unshifted 7-bit I2C address for sensor
#define STATUS 0x00
#define OUT_P_MSB 0x01
#define OUT_P_CSB 0x02
#define OUT_P_LSB 0x03
#define OUT_T_MSB 0x04
#define OUT_T_LSB 0x05
#define DR_STATUS 0x06
#define OUT_P_DELTA_MSB 0x07
#define OUT_P_DELTA_CSB 0x08
#define OUT_P_DELTA_LSB 0x09
#define OUT_T_DELTA_MSB 0x0A
#define OUT_T_DELTA_LSB 0x0B
#define WHO_AM_I 0x0C
#define F_STATUS 0x0D
#define F_DATA 0x0E
#define F_SETUP 0x0F
#define TIME_DLY 0x10
#define SYSMOD 0x11
#define INT_SOURCE 0x12
#define PT_DATA_CFG 0x13
#define BAR_IN_MSB 0x14
#define BAR_IN_LSB 0x15
#define P_TGT_MSB 0x16
#define P_TGT_LSB 0x17
#define T_TGT 0x18
#define P_WND_MSB 0x19
#define P_WND_LSB 0x1A
#define T_WND 0x1B
#define P_MIN_MSB 0x1C
#define P_MIN_CSB 0x1D
#define P_MIN_LSB 0x1E
#define T_MIN_MSB 0x1F
#define T_MIN_LSB 0x20
#define P_MAX_MSB 0x21
#define P_MAX_CSB 0x22
#define P_MAX_LSB 0x23
#define T_MAX_MSB 0x24
#define T_MAX_LSB 0x25
#define CTRL_REG1 0x26
#define CTRL_REG2 0x27
#define CTRL_REG3 0x28
#define CTRL_REG4 0x29
#define CTRL_REG5 0x2A
#define OFF_P 0x2B
#define OFF_T 0x2C
#define OFF_H 0x2D
class MPL3115A2 {
public:
MPL3115A2();
//Public Functions
bool begin(); // Gets sensor on the I2C bus.
float readAltitude(); // Returns float with meters above sealevel. Ex: 1638.94
float readAltitudeFt(); // Returns float with feet above sealevel. Ex: 5376.68
float readPressure(); // Returns float with barometric pressure in Pa. Ex: 83351.25
float readTemperature(); // Returns float with current temperature in Celsius. Ex: 23.37
float readTemperatureF(); // Returns float with current temperature in Fahrenheit. Ex: 73.96
void setModeBarometer(); // Puts the sensor into Pascal measurement mode.
void setModeAltimeter(); // Puts the sensor into altimetery mode.
void setModeStandby(); // Puts the sensor into Standby mode. Required when changing CTRL1 register.
void setModeActive(); // Start taking measurements!
void setOversampleRate(byte); // Sets the # of samples from 1 to 128. See datasheet.
void enableEventFlags(); // Sets the fundamental event flags. Required during setup.
//Public Variables
private:
//Private Functions
void toggleOneShot();
byte IIC_Read(byte regAddr);
void IIC_Write(byte regAddr, byte value);
//Private Variables
};
/*******************************************************************************************/
MPL3115A2::MPL3115A2()
{
//Set initial values for private vars
}
//Begin
/*******************************************************************************************/
//Start I2C communication
bool MPL3115A2::begin(void)
{
Wire.begin();
}
//Returns the number of meters above sea level
//Returns -1 if no new data is available
float MPL3115A2::readAltitude()
{
toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
//Wait for PDR bit, indicates we have new pressure data
int counter = 0;
while( (IIC_Read(STATUS) & (1<<1)) == 0)
{
if(++counter > 600) return(-999); //Error out after max of 512ms for a read
delay(1);
}
// Read pressure registers
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(OUT_P_MSB); // Address of data to get
Wire.endTransmission(false); // Send data to I2C dev with option for a repeated start. THIS IS NECESSARY and not supported before Arduino V1.0.1!
Wire.requestFrom(MPL3115A2_ADDRESS, 3); // Request three bytes
//Wait for data to become available
counter = 0;
while(Wire.available() < 3)
{
if(counter++ > 100) return(-999); //Error out
delay(1);
}
byte msb, csb, lsb;
msb = Wire.read();
csb = Wire.read();
lsb = Wire.read();
// The least significant bytes l_altitude and l_temp are 4-bit,
// fractional values, so you must cast the calulation in (float),
// shift the value over 4 spots to the right and divide by 16 (since
// there are 16 values in 4-bits).
float tempcsb = (lsb>>4)/16.0;
float altitude = (float)( (msb << 8) | csb) + tempcsb;
return(altitude);
}
//Returns the number of feet above sea level
float MPL3115A2::readAltitudeFt()
{
return(readAltitude() * 3.28084);
}
//Reads the current pressure in Pa
//Unit must be set in barometric pressure mode
//Returns -1 if no new data is available
float MPL3115A2::readPressure()
{
//Check PDR bit, if it's not set then toggle OST
if(IIC_Read(STATUS) & (1<<2) == 0) toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
//Wait for PDR bit, indicates we have new pressure data
int counter = 0;
while(IIC_Read(STATUS) & (1<<2) == 0)
{
if(++counter > 600) return(-999); //Error out after max of 512ms for a read
delay(1);
}
// Read pressure registers
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(OUT_P_MSB); // Address of data to get
Wire.endTransmission(false); // Send data to I2C dev with option for a repeated start. THIS IS NECESSARY and not supported before Arduino V1.0.1!
Wire.requestFrom(MPL3115A2_ADDRESS, 3); // Request three bytes
//Wait for data to become available
counter = 0;
while(Wire.available() < 3)
{
if(counter++ > 100) return(-999); //Error out
delay(1);
}
byte msb, csb, lsb;
msb = Wire.read();
csb = Wire.read();
lsb = Wire.read();
toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
// Pressure comes back as a left shifted 20 bit number
long pressure_whole = (long)msb<<16 | (long)csb<<8 | (long)lsb;
pressure_whole >>= 6; //Pressure is an 18 bit number with 2 bits of decimal. Get rid of decimal portion.
lsb &= 0b00110000; //Bits 5/4 represent the fractional component
lsb >>= 4; //Get it right aligned
float pressure_decimal = (float)lsb/4.0; //Turn it into fraction
float pressure = (float)pressure_whole + pressure_decimal;
return(pressure);
}
float MPL3115A2::readTemperature()
{
if(IIC_Read(STATUS) & (1<<1) == 0) toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
//Wait for TDR bit, indicates we have new temp data
int counter = 0;
while( (IIC_Read(STATUS) & (1<<1)) == 0)
{
if(++counter > 600) return(-999); //Error out after max of 512ms for a read
delay(1);
}
// Read temperature registers
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(OUT_T_MSB); // Address of data to get
Wire.endTransmission(false); // Send data to I2C dev with option for a repeated start. THIS IS NECESSARY and not supported before Arduino V1.0.1!
Wire.requestFrom(MPL3115A2_ADDRESS, 2); // Request two bytes
//Wait for data to become available
counter = 0;
while(Wire.available() < 2)
{
if(counter++ > 100) return(-999); //Error out
delay(1);
}
byte msb, lsb;
msb = Wire.read();
lsb = Wire.read();
toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
//Negative temperature fix by D.D.G.
short foo = 0;
bool negSign = false;
//Check for 2s compliment
if(msb > 0x7F)
{
foo = ~((msb << 8) + lsb) + 1; //2’s complement
msb = foo >> 8;
lsb = foo & 0x00F0;
negSign = true;
}
// The least significant bytes l_altitude and l_temp are 4-bit,
// fractional values, so you must cast the calulation in (float),
// shift the value over 4 spots to the right and divide by 16 (since
// there are 16 values in 4-bits).
float templsb = (lsb>>4)/16.0; //temp, fraction of a degree
float temperature = (float)(msb + templsb);
if (negSign) temperature = 0 - temperature;
return(temperature);
}
//Give me temperature in fahrenheit!
float MPL3115A2::readTemperatureF()
{
return((readTemperature() * 9.0)/ 5.0 + 32.0); // Convert celsius to fahrenheit
}
//Sets the mode to Barometer
//CTRL_REG1, ALT bit
void MPL3115A2::setModeBarometer()
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting &= ~(1<<7); //Clear ALT bit
IIC_Write(CTRL_REG1, tempSetting);
}
//Sets the mode to Altimeter
//CTRL_REG1, ALT bit
void MPL3115A2::setModeAltimeter()
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting |= (1<<7); //Set ALT bit
IIC_Write(CTRL_REG1, tempSetting);
}
//Puts the sensor in standby mode
//This is needed so that we can modify the major control registers
void MPL3115A2::setModeStandby()
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting &= ~(1<<0); //Clear SBYB bit for Standby mode
IIC_Write(CTRL_REG1, tempSetting);
}
//Puts the sensor in active mode
//This is needed so that we can modify the major control registers
void MPL3115A2::setModeActive()
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting |= (1<<0); //Set SBYB bit for Active mode
IIC_Write(CTRL_REG1, tempSetting);
}
//Call with a rate from 0 to 7. See page 33 for table of ratios.
//Sets the over sample rate. Datasheet calls for 128 but you can set it
//from 1 to 128 samples. The higher the oversample rate the greater
//the time between data samples.
void MPL3115A2::setOversampleRate(byte sampleRate)
{
if(sampleRate > 7) sampleRate = 7; //OS cannot be larger than 0b.0111
sampleRate <<= 3; //Align it for the CTRL_REG1 register
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting &= 0b11000111; //Clear out old OS bits
tempSetting |= sampleRate; //Mask in new OS bits
IIC_Write(CTRL_REG1, tempSetting);
}
//Enables the pressure and temp measurement event flags so that we can
//test against them. This is recommended in datasheet during setup.
void MPL3115A2::enableEventFlags()
{
IIC_Write(PT_DATA_CFG, 0x07); // Enable all three pressure and temp event flags
}
//Clears then sets the OST bit which causes the sensor to immediately take another reading
//Needed to sample faster than 1Hz
void MPL3115A2::toggleOneShot(void)
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting &= ~(1<<1); //Clear OST bit
IIC_Write(CTRL_REG1, tempSetting);
tempSetting = IIC_Read(CTRL_REG1); //Read current settings to be safe
tempSetting |= (1<<1); //Set OST bit
IIC_Write(CTRL_REG1, tempSetting);
}
// These are the two I2C functions in this sketch.
byte MPL3115A2::IIC_Read(byte regAddr)
{
// This function reads one byte over IIC
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(regAddr); // Address of CTRL_REG1
Wire.endTransmission(false); // Send data to I2C dev with option for a repeated start. THIS IS NECESSARY and not supported before Arduino V1.0.1!
Wire.requestFrom(MPL3115A2_ADDRESS, 1); // Request the data...
return Wire.read();
}
void MPL3115A2::IIC_Write(byte regAddr, byte value)
{
// This function writes one byto over IIC
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(regAddr);
Wire.write(value);
Wire.endTransmission(true);
}
/*
HTU21D Humidity Sensor Library
By: Nathan Seidle
SparkFun Electronics
Date: September 22nd, 2013
License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
This library allows an Arduino to read from the HTU21D low-cost high-precision humidity sensor.
If you have feature suggestions or need support please use the github support page: https://github.com/sparkfun/HTU21D
Hardware Setup: The HTU21D lives on the I2C bus. Attach the SDA pin to A4, SCL to A5. If you are using the SparkFun
breakout board you *do not* need 4.7k pull-up resistors on the bus (they are built-in).
Link to the breakout board product:
Software:
Call HTU21D.Begin() in setup.
HTU21D.ReadHumidity() will return a float containing the humidity. Ex: 54.7
HTU21D.ReadTemperature() will return a float containing the temperature in Celsius. Ex: 24.1
HTU21D.SetResolution(byte: 0b.76543210) sets the resolution of the readings.
HTU21D.check_crc(message, check_value) verifies the 8-bit CRC generated by the sensor
HTU21D.read_user_register() returns the user register. Used to set resolution.
*/
//#include <Wire.h>
/*******************************************************************************************/
//#include "HTU21D.h"
/*******************************************************************************************/
#define HTDU21D_ADDRESS 0x40 //Unshifted 7-bit I2C address for the sensor
#define TRIGGER_TEMP_MEASURE_HOLD 0xE3
#define TRIGGER_HUMD_MEASURE_HOLD 0xE5
#define TRIGGER_TEMP_MEASURE_NOHOLD 0xF3
#define TRIGGER_HUMD_MEASURE_NOHOLD 0xF5
#define WRITE_USER_REG 0xE6
#define READ_USER_REG 0xE7
#define SOFT_RESET 0xFE
class HTU21D {
public:
HTU21D();
//Public Functions
bool begin();
float readHumidity(void);
float readTemperature(void);
void setResolution(byte resBits);
//Public Variables
private:
//Private Functions
byte read_user_register(void);
byte check_crc(uint16_t message_from_sensor, uint8_t check_value_from_sensor);
//Private Variables
};
/*******************************************************************************************/
HTU21D::HTU21D()
{
//Set initial values for private vars
}
//Begin
/*******************************************************************************************/
//Start I2C communication
bool HTU21D::begin(void)
{
Wire.begin();
}
//Read the humidity
/*******************************************************************************************/
//Calc humidity and return it to the user
//Returns 998 if I2C timed out
//Returns 999 if CRC is wrong
float HTU21D::readHumidity(void)
{
//Request a humidity reading
Wire.beginTransmission(HTDU21D_ADDRESS);
Wire.write(TRIGGER_HUMD_MEASURE_NOHOLD); //Measure humidity with no bus holding
Wire.endTransmission();
//Hang out while measurement is taken. 50mS max, page 4 of datasheet.
delay(55);
//Comes back in three bytes, data(MSB) / data(LSB) / Checksum
Wire.requestFrom(HTDU21D_ADDRESS, 3);
//Wait for data to become available
int counter = 0;
while(Wire.available() < 3)
{
counter++;
delay(1);
if(counter > 100) return 998; //Error out
}
byte msb, lsb, checksum;
msb = Wire.read();
lsb = Wire.read();
checksum = Wire.read();
/* //Used for testing
byte msb, lsb, checksum;
msb = 0x4E;
lsb = 0x85;
checksum = 0x6B;*/
unsigned int rawHumidity = ((unsigned int) msb << 8) | (unsigned int) lsb;
if(check_crc(rawHumidity, checksum) != 0) return(999); //Error out
//sensorStatus = rawHumidity & 0x0003; //Grab only the right two bits
rawHumidity &= 0xFFFC; //Zero out the status bits but keep them in place
//Given the raw humidity data, calculate the actual relative humidity
float tempRH = rawHumidity / (float)65536; //2^16 = 65536
float rh = -6 + (125 * tempRH); //From page 14
return(rh);
}
//Read the temperature
/*******************************************************************************************/
//Calc temperature and return it to the user
//Returns 998 if I2C timed out
//Returns 999 if CRC is wrong
float HTU21D::readTemperature(void)
{
//Request the temperature
Wire.beginTransmission(HTDU21D_ADDRESS);
Wire.write(TRIGGER_TEMP_MEASURE_NOHOLD);
Wire.endTransmission();
//Hang out while measurement is taken. 50mS max, page 4 of datasheet.
delay(55);
//Comes back in three bytes, data(MSB) / data(LSB) / Checksum
Wire.requestFrom(HTDU21D_ADDRESS, 3);
//Wait for data to become available
int counter = 0;
while(Wire.available() < 3)
{
counter++;
delay(1);
if(counter > 100) return 998; //Error out
}
unsigned char msb, lsb, checksum;
msb = Wire.read();
lsb = Wire.read();
checksum = Wire.read();
/* //Used for testing
byte msb, lsb, checksum;
msb = 0x68;
lsb = 0x3A;
checksum = 0x7C; */
unsigned int rawTemperature = ((unsigned int) msb << 8) | (unsigned int) lsb;
if(check_crc(rawTemperature, checksum) != 0) return(999); //Error out
//sensorStatus = rawTemperature & 0x0003; //Grab only the right two bits
rawTemperature &= 0xFFFC; //Zero out the status bits but keep them in place
//Given the raw temperature data, calculate the actual temperature
float tempTemperature = rawTemperature / (float)65536; //2^16 = 65536
float realTemperature = -46.85 + (175.72 * tempTemperature); //From page 14
return(realTemperature);
}
//Set sensor resolution
/*******************************************************************************************/
//Sets the sensor resolution to one of four levels
//Page 12:
// 0/0 = 12bit RH, 14bit Temp
// 0/1 = 8bit RH, 12bit Temp
// 1/0 = 10bit RH, 13bit Temp
// 1/1 = 11bit RH, 11bit Temp
//Power on default is 0/0
void HTU21D::setResolution(byte resolution)
{
byte userRegister = read_user_register(); //Go get the current register state
userRegister &= 0b01111110; //Turn off the resolution bits
resolution &= 0b10000001; //Turn off all other bits but resolution bits
userRegister |= resolution; //Mask in the requested resolution bits
//Request a write to user register
Wire.beginTransmission(HTDU21D_ADDRESS);
Wire.write(WRITE_USER_REG); //Write to the user register
Wire.write(userRegister); //Write the new resolution bits
Wire.endTransmission();
}
//Read the user register
byte HTU21D::read_user_register(void)
{
byte userRegister;
//Request the user register
Wire.beginTransmission(HTDU21D_ADDRESS);
Wire.write(READ_USER_REG); //Read the user register
Wire.endTransmission();
//Read result
Wire.requestFrom(HTDU21D_ADDRESS, 1);
userRegister = Wire.read();
return(userRegister);
}
//Give this function the 2 byte message (measurement) and the check_value byte from the HTU21D
//If it returns 0, then the transmission was good
//If it returns something other than 0, then the communication was corrupted
//From: http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html
//POLYNOMIAL = 0x0131 = x^8 + x^5 + x^4 + 1 : http://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checks
#define SHIFTED_DIVISOR 0x988000 //This is the 0x0131 polynomial shifted to farthest left of three bytes
byte HTU21D::check_crc(uint16_t message_from_sensor, uint8_t check_value_from_sensor)
{
//Test cases from datasheet:
//message = 0xDC, checkvalue is 0x79
//message = 0x683A, checkvalue is 0x7C
//message = 0x4E85, checkvalue is 0x6B
uint32_t remainder = (uint32_t)message_from_sensor << 8; //Pad with 8 bits because we have to add in the check value
remainder |= check_value_from_sensor; //Add on the check value
uint32_t divsor = (uint32_t)SHIFTED_DIVISOR;
for (int i = 0 ; i < 16 ; i++) //Operate on only 16 positions of max 24. The remaining 8 are our remainder and should be zero when we're done.
{
//Serial.print("remainder: ");
//Serial.println(remainder, BIN);
//Serial.print("divsor: ");
//Serial.println(divsor, BIN);
//Serial.println();
if( remainder & (uint32_t)1<<(23 - i) ) //Check if there is a one in the left position
remainder ^= divsor;
divsor >>= 1; //Rotate the divsor max 16 times so that we have 8 bits left of a remainder
}
return (byte)remainder;
}
/*
Weather Shield Example
By: Nathan Seidle
SparkFun Electronics
Date: November 16th, 2013
License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
Much of this is based on Mike Grusin's USB Weather Board code: https://www.sparkfun.com/products/10586
This code reads all the various sensors (wind speed, direction, rain gauge, humidty, pressure, light, batt_lvl)
and reports it over the serial comm port. This can be easily routed to an datalogger (such as OpenLog) or
a wireless transmitter (such as Electric Imp).
Measurements are reported once a second but windspeed and rain gauge are tied to interrupts that are
calcualted at each report.
This example code assumes the GPS module is not used.
*/
//#include <Wire.h> //I2C needed for sensors
//#include "MPL3115A2.h" //Pressure sensor
//#include "HTU21D.h" //Humidity sensor
MPL3115A2 myPressure; //Create an instance of the pressure sensor
HTU21D myHumidity; //Create an instance of the humidity sensor
//Hardware pin definitions
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// digital I/O pins
const byte STAT1 = 6; // Blue User LED
const byte STAT2 = 7;
// analog I/O pins
const byte REFERENCE_3V3 = A3;
const byte LIGHT = A1;
const byte BATT = A2;
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//Global Variables
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long lastSecond; //The millis counter to see when a second rolls by
byte seconds; //When it hits 60, increase the current minute
byte seconds_2m; //Keeps track of the "wind speed/dir avg" over last 2 minutes array of data
byte minutes; //Keeps track of where we are in various arrays of data
byte minutes_10m; //Keeps track of where we are in wind gust/dir over last 10 minutes array of data
//These are all the weather values that wunderground expects:
float humidity = 0; // [%]
float temp_p = 0; // [pressure sensor temperature C]
float temp_h = 0; // [humidity sensor temperature C]
//float baromin = 30.03;// [barom in] - It's hard to calculate baromin locally, do this in the agent
float pressure = 0;
//float dewptf; // [dewpoint F] - It's hard to calculate dewpoint locally, do this in the agent
float battery = 11.8; //[analog value from 0 to 1023]
float light = 455; //[analog value from 0 to 1023]
//Returns the voltage of the light sensor based on the 3.3V rail
//This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V)
float get_light_level()
{
float operatingVoltage = analogRead(REFERENCE_3V3);
float lightSensor = analogRead(LIGHT);
operatingVoltage = 3.3 / operatingVoltage; //The reference voltage is 3.3V
lightSensor = operatingVoltage * lightSensor;
return(lightSensor);
}
//Returns the voltage of the raw pin based on the 3.3V rail
//This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V)
//Battery level is connected to the RAW pin on Arduino and is fed through two 5% resistors:
//3.9K on the high side (R1), and 1K on the low side (R2)
float get_battery_level()
{
float operatingVoltage = analogRead(REFERENCE_3V3);
float rawVoltage = analogRead(BATT);
operatingVoltage = 3.30 / operatingVoltage; //The reference voltage is 3.3V
rawVoltage = operatingVoltage * rawVoltage; //Convert the 0 to 1023 int to actual voltage on BATT pin
rawVoltage *= 4.90; //(3.9k+1k)/1k - multiple BATT voltage by the voltage divider to get actual system voltage
return(rawVoltage);
}
//Calculates each of the variables that wunderground is expecting
void calcWeather()
{
//Calc humidity
humidity = myHumidity.readHumidity();
//Calc temperature from pressure sensor
temp_p = myPressure.readTemperature();
temp_h = myHumidity.readTemperature();
//tempf = ((tempc * 9.0)/ 5.0 + 32.0); // Convert celsius to fahrenheit
//Calc pressure
pressure = myPressure.readPressure();
//Calc light level
light = get_light_level();
//Calc battery level
battery = get_battery_level();
Serial.println();
Serial.print(",humidity=");
Serial.print(humidity, 1);
Serial.print(",temp_h=");
Serial.print(temp_h, 1);
Serial.print(",temp_p=");
Serial.print(temp_p, 1);
Serial.print(",pressure=");
Serial.print(pressure, 2);
Serial.print(",battery=");
Serial.print(battery, 2);
Serial.print(",light=");
Serial.print(light, 2);
Serial.print(",");
Serial.println("#");
}
/*******************************************************************************************/
// MAIN
/*******************************************************************************************/
void setup()
{
Serial.begin(9600);
while(!Serial.available()); // Wait here until the user presses ENTER in the Serial Terminal
Serial.println("Weather Shield Example");
pinMode(STAT1, OUTPUT); //Status LED Blue
pinMode(STAT2, OUTPUT); //Status LED Green
pinMode(REFERENCE_3V3, INPUT);
pinMode(LIGHT, INPUT);
//Configure the pressure sensor
myPressure.begin(); // Get sensor online
myPressure.setModeBarometer(); // Measure pressure in Pascals from 20 to 110 kPa
myPressure.setOversampleRate(7); // Set Oversample to the recommended 128
myPressure.enableEventFlags(); // Enable all three pressure and temp event flags
//Configure the humidity sensor
myHumidity.begin();
seconds = 0;
lastSecond = millis();
Spark.variable("pressure", &pressure, INT);
Spark.variable("humidity", &humidity, INT);
Spark.variable("light", &light, INT);
Spark.variable("battery", &battery, INT);
Spark.variable("temp_p", &temp_p, INT);
Spark.variable("temp_h", &temp_h, INT);
// Serial.println("Weather Shield online!");
}
void loop()
{
//Keep track of which minute it is
if(millis() - lastSecond >= 1000)
{
digitalWrite(STAT1, HIGH); //Blink stat LED
lastSecond += 1000;
//Report all readings every second
//printWeather();
calcWeather(); //Go calc all the various sensors
digitalWrite(STAT1, LOW); //Turn off stat LED
}
delay(1000);
}

For debugging I used the Serial Communication link over USB. Windows users have to install a COM driver. However, MAC and Linux support the Spark Core USB functionality out of the box.
I was really pleased to see how well the Spark Core supports Arduino libraries and well written legacy code. With only a few code modifications I had the sensors up and running.
The setup is now streaming values over a USB cable to a PC. There I captured the values with Tera Term and created a Weather Graph from the comma separated values (CVS). The example below shows the pressure curve of a Bay Area Storm passing by at end of February 2014.
CA Storm
This setup is a somewhat trivial example that a basic Arduino can also do. The project really does not take advantage of the Spak Core’s connectivity to the internet. So stay tuned for my next blog post where I will add internet connectivity to the setup.

Encounter with a Spark

I have tested several IoT platforms over the last couple of weeks. So I was not too keen to checkout yet another one. However, when I got the annoucement that the Spark Core is shipping I could not resist and ordered one. It arrive in the mail today so I thought I will take it for a spin.
The Spark Core comes in a very stylish little box.
Spark Box
Figure1: Spark Box
To my surprise the box did even includes a breadboard:
spark2spark3
Figure 2: Open Spark Core Box
Overall, the box contains the Spark Core board, a breadboard, a micro-USB cable and Spark sticker.
spark4
Figure 3: Box Content
It is amazingly simple to get the board up and running. By following these few simple steps:

  1. Download the Spark App for iPhone or Android
  2. Setup an account by register at spark.io
  3. Power up the Spark Core over the USB cable
  4. Start Spark App and log into your wireless network

If everything works well you will get rewarded with the RGB-LED on the Spark board flashing in rainbow colors. Once the Spark Core is connected to you WiFi and paired with the Spark cloud, it took me only a few minutes to get an on-board blue LED blinking.
It very quickly becomes obvious that the Spark team has done a great job setting up an entire end-to-end IoT solution consisting of:

  1. Spark Hardware
  2. Cloud based IDE
  3. Arduino compatible API
  4. Free for life cloud back-end service with a RESTful API

All the Spark Core software is open source. The board uses a CC3000 WiFi Module from TI combined with a 32-bit ARM Cortex-M3 powered STM32F103 from ST Microelectronics. The Spark team has come up with a nice integration of this hardware and the cloud server back end. It is based on the CoAP protocol specification and allows for an easy and energy efficient integrated IoT solution.
The cloud API offers over-the-air (OTA) firmware updating where the input can either be c/c++ source code or binaries. For those that don’t want to use Spark Builder, their cloud based IDE the web site also promises support for desktop IDEs like Eclipse.
So much for today, I will cover more details in future blogs.

Do you need WiFi Connectivity in your project?

There are a lot of WiFi solutions for Makers out there. However many are either expensive, big or outdated. So it is refreshing to look at the technical data of the little known WiFi module available by the name of RTX4100  from RTX Telecom. You may never have heard of RTX Telecom but this Danish design service company specialized in wireless has been around for many years.  The module is hardly bigger than a Bluetooth module.
RTX_BT1
Figure1: on the left a simple Bluetooth HC-5 module and on the right the RTX4100 WiFi Module.
The RTX41xx uses latest WiFi System in a Package (SiP) technology. It features a Nordic Semiconductors 32-bit ARM Cortex-M3  based low power microcontroller.  The WiFi is based on a AR41xx SiP from one of the leading WiFi chip manufacturer  Qualcomm – Atheros.
The 32-bit application processor is responsible for all the WiFi driver related duties. But an API allows to program custom application into the module. RTX calls the custom programs Co-Located Application or CoLA.  Besides the RTX4100 that offers 24 kBytes flash memory and 3 kBytes RAM for custom applications. RTX also offers a pin compatible RTX4140 that provides much more programmable memory for CoLA applications, 512 kBytes flash and 64 kBytes RAM.
CoLa
The SDK can be downloaded from RTX’s web site together with a comprehensive set of documents and CoLA examples.
On the Hardware side the module offers 30 solder pins that support a variety of  I/O functionality:

  • ADC ports, DAC ports
  • GPIO ports
  • UART, SPI, I2C
  • Timers

RTX has also teamed up with some cloud services. The currently supported cloud partners are: 2lemetryExositeNabto and Sensinode.
For simple applications like WiFi sensors or actors that require a limited set of IOs and CPU/Memory resources RTX41xx modules can be used stand alone. They are also a great choice for embedded projects based on Arduino that need WiFi.  Similar to some of the popular Bluetooth modules you only need a spare UART or SPI interface to talk to the RTX4100.
Unlike Electric Imp that offers you a fully integrated platform form the module all the way up to the cloud, RTX is a much more open and flexible platform where you retain control. However this control also comes at the price that you have to do more software work. The good news is that you don’t have to start from scratch, RTX supports you with quite a bit of Software.

Another IoT Platform – WICED

Broadcom is also jumping on the IoT wagon with the WICED  platform.  The platform is targeting Bluetooth and WiFi applications. The WiFi modules feature the BCM43362 WiFi chip integrated into a System in a Package (SiP) module. The Image below shows a WiFI WICED PCB module with a Murata WiFi SiP Module and a STM32F205 microcontroller. Murata also offers SiP modules that have the ARM microcontroller built in.
wiced_BCM943362WCD4
On the software side the platform is supported by a feature rich SDK and support for OSs:

  • WICED Application Framework including bootloader, flash storage API, over-the-air (OTA) upgrades, factory reset, and system monitor.
  • An open source build system and toolchain based on GNU make (native IAR support coming soon!).
  • A GUI Development Environment based on Eclipse CDT that seamlessly integrates with a JTAG programmer and single-step, thread-aware debugger based on OpenOCD and gdb.
  • A software stack with a choice of several RTOS/TCP stack options including ThreadX/NetXThreadX/NetX Duo and FreeRTOS/LwIP.
  • Support for security and networking features such as SSL/TLS, IPv4/IPv6 networking, and mDNS (Bonjour) device discovery.
  • Simple out-of-box device setup using Apple-licensed MFi technology or via a web browser and softAP/web server.

Broadcom also make a set of software examples available that help getting started quickly:

  • Production ready sample applications.
  • Lots of application snippets demonstrating how to use the rich WICED API feature set.
  • Various test applications to aid manufacturing and certification.
  • All documentation included inside the WICED SDK.