Close

Bridging BLE to Internet via an iPhone

A project log for analog.io - A full stack IoT platform

A full stack project dedicated to easily collecting, analyzing and sharing IoT sensor data.

Luke Beno 09/18/2015 at 04:300 Comments

In the analog.io quarter finals video, I demonstrated an MSP430 Sensor node measuring temperature and humidity then transmitting the data via BLE. I then was using an iPhone to collect the BLE beacons and push them to the internet.

In this project update I will document the design for this demo. First let's take a look at the firmware. This code is written in Energia, it is the Arduino equivalent for TI MSP430.

The code uses the Soft I2C library to communicated with a Si7020 sensor. the data from the sensor is then put into a BLE packet and sent off.

Here is the Energia/Arduino code:

#include <analog_io.h>
#include <SPI.h>
#include "I2C_SoftwareLibrary.h"

analog_io radio(P3_5, P3_6, P2_5);  // P2.0=CE, P2.1=CSN, P2.2=IRQ
const uint8_t txaddr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x01 };

#define SCL_PIN P2_4 ///< pin for SCL
#define SDA_PIN P2_3 ///< pin for SDA
SoftwareWire Wire(SDA_PIN, SCL_PIN); 

struct ble_payload
{
  uint16_t temp;
  uint16_t humidity;
};

struct ble_payload payload;

void setup()
{
  pinMode(RED_LED, OUTPUT); 
  digitalWrite(RED_LED, LOW);
  
  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(MSBFIRST);

  radio.begin();  // Defaults 1Mbps, channel 0, max TX power

  radio.setTXaddress((void*)txaddr);
}

void loop()
{
  // request temp 
  i2cWrite(_address,0x03,0x11);
  
  // wait for it...
  while ((i2cRead(_address,0x00) & 0x01) == 0x01);
  
  payload.temp = i2cRead(_address,0x01)<<8;
  payload.temp += i2cRead(_address,0x02);
  
  // request humidity 
  i2cWrite(_address,0x03,0x01);
  // wait for it...
  while ((i2cRead(_address,0x00) & 0x01) == 0x01);
  
  payload.humidity = i2cRead(_address,0x01)<<8;
  payload.humidity += i2cRead(_address,0x02);
  
  radio.bleSingleTransmit("ANALOG", (unsigned char*) payload, sizeof(payload));
  
  delay(6000);    // Send every minute

}

uint16_t requestTemp(){
  i2cWrite(_address,0x03,0x11);
  delay(2);
  while ((i2cRead(_address,0x00) & 0x01) == 0x01);
  return ((i2cRead(_address,0x01)<<6) + (i2cRead(_address,0x02)>>2));
}

int i2cWrite(unsigned char address,unsigned char reg,unsigned char data){
  Wire.beginTransmission(address);
  Wire.write(reg);
  Wire.write(data);
  Wire.endTransmission();
}

uint8_t i2cRead(unsigned char address,unsigned char reg){
  Wire.beginTransmission(address);
  Wire.write(reg);
  Wire.endTransmission(false);
  Wire.requestFrom(address, 1);
  while (Wire.available() < 1);
  return Wire.read();
}

Now let's take a look at the prototype iPhone app. Writing for iPhone an app is an uphill process so I was looking for a temporary alternate way to quickly prototype the iPhone as a wireless bridge to the internet. After doing some research I discovered TechBasic from Byte Works. It struck my interest because it enabled me to write code, running on the iPhone and had an API that worked with the iPhone BLE stack.

I purchased the app and here is the code that I came up with on the iPhone side to receive the BLE beacons from the sensor node and forward them on to a datastream at data.sparkfun.com.

BLE.startBLE

DIM uuid(0) AS STRING
DIM x AS STRING
DIM rh, t AS DOUBLE
DIM watch_dog as INTEGER
DIM host, public_key, private_key AS STRING

host        = "data.sparkfun.com"
public_key  = "<public_key_here>"
private_key = "<private_key_here>"

BLE.startScan(uuid)

SUB BLEDiscoveredPeripheral (time AS DOUBLE, peripheral AS BLEPeripheral, services() AS STRING, advertisements(,) AS STRING, rssi)
  IF peripheral.blename = "ANALOG" THEN
    FOR i = 1 TO UBOUND(advertisements,1)
      IF advertisements(i,1) = "kCBAdvDataManufacturerData" THEN
        x = advertisements(i,2)
        rh = VAL("0x"&MID(x, 2, 2)&MID(x,6,2))
        t = VAL("0x"&MID(x, 11, 2)&MID(x,15,2))

        t=((175.72*t)/65536-46.85)*9/5+32
        rh=(125*rh)/65536-6

        Comm.readHTTP(1,"http://"&host&"/input/"&public_key&"?private_key="&private_key&"&temp="&MID(STR(t),1,6)&"&humidity="&MID(STR(rh),1,6),"GET","","head","")
        WHILE NOT EOF(1)
          LINE INPUT #1, a$
          PRINT a$
        WEND
        CLOSE #1
        PRINT MID(STR(rh),1,6)&" , "&MID(STR(t),1,6)
        watch_dog = 0
      END IF
    NEXT
  END IF
END SUB

SUB nullEvent (time AS DOUBLE)
  watch_dog=watch_dog+1
  IF watch_dog>30 THEN
    BLE.startScan(uuid)
    watch_dog=0
  END IF
END SUB

Discussions