© John C. Shovic 2016

John C. Shovic, Raspberry Pi IoT Projects, 10.1007/978-1-4842-1377-3_5

5. Connecting an IOT Device to a Cloud Server - IOTPulse

John C. Shovic

(1)Liberty Lake, Washington, USA

Chapter Goal: Build a Portable IOT Device for Reading Your Pulse

Topics Covered in This Chapter:

  • IOT on a Global Network

  • Bluemix and the Internet Of Things

  • The IOTPulse Design

  • Building the IOTPulse Device

  • Connecting and testing the hardware and software for IOTPulse

  • Setting up IBM Bluemix and Connecting IOTPulse

  • Examining Results and Advanced Features

This chapter will show the reader how to connect an IOT device to a cloud server, IBM Bluemix. The complexity in this chapter is not building the device, but rather navigating the setup process for adding your device to the cloud.

A major part of designing devices that will connect with the IOT is to determine what to do with the data after you have gathered it. A huge amount of data and no way to store it or analyze it is not very useful. An IOT project device generally is very CPU limited and also only has a limited amount of storage available. You generally have to send the data collected by a sensor-filled IOT device up to a bigger computer and storage cloud to perform complex analysis and determine actions on that data.

In this chapter, we are building a device to collect the pulse rate from a person, and then periodically (every 10 seconds) send it up to a cloud-based storage and analysis system called the IBM Bluemix IOT Foundation.

Before we selected the IBM Bluemix for this chapter, we also looked at three other providers. We determined that the Amazon IOT solution was too “heavy” for these small devices because of the protocol and encryption required. The two other smaller vendors were rejected because of length of time in existence and limited analysis functionality. It should be pointed out that the smaller vendors had distinctly superior display capabilities out of the box from either of the two majors.

The IBM Bluemix system brought a good mix of flexible protocols, a “light” method for sending data, and an amazing collection of analytical tools. Ramifications of the IBM Bluemix methodology on encryption versus the Amazon IOT solution will be discussed in Chapter 7, “Computer Security and the IOT.”

IOT Characterization of This Project

As we discussed in Chapter 1, the first thing to do to understand an IOT project is to look at our six different aspects of IOT shown in Table 5-1. IOTPulse is a more complex project than LightSwarm and is much closer to a production IOT device.

Table 5-1. IOTPulse Characterization (CPLPFC )

Aspect

Rating

Comments

Communications

9

WiFi connection to Internet -

Processor Power

7

80MHz XTensa Harvard Architecture CPU, ∼80KB Data RAM / ∼35KB of Instruction RAM / 200K ROM

Local Storage

8

4MB Flash (or 3MB file system!)

Power Consumption

8

∼200mA transmitting, ∼60mA receiving, noWiFi ∼15mA, Standby ∼1mA

Functionality

7

Partial Arduino Support (limited GPIO/Analog Inputs)

Cost

9

< $10 and getting cheaper

Ratings are from 1–10, 1 being the least suitable for IOT and 10 being the most suitable for IOT applications.

This gives us a CPLPFC rating of 8.0. Great for learning and experimenting, and it could be deployed for some market applications.

The ESP8266 provides a WiFi transmitter/receiver, a TCP/IP stack, and firmware to support direction connections to a local WiFi access point, which then can connect to the Internet. The data generated by the IOTPulse design will be sent to IBM’s Bluemix Cloud IOT site.

The Internet Of Things on the Global Network

As was stated in the introduction, what do you do with all this data you are gathering? Whether it is the age of your milk in the refrigerator, your current blood sugar or pulse rate, or your home security system, the data needs to be stored and analyzed; or what is the point of gathering it?

Sometimes you don’t need to store the data. Sometimes the local devices can do the necessary actions (like in the LightSwarm project in Chapter 2), but there are many applications that require more computing resources than might be available among the local IOT devices.

This is the situation that has led to the development of server-based (often on a computing cloud) support software for the upcoming IOT explosion. In Chapter 2, we used a Raspberry Pi to gather the data from the LightSwarm and log the rather complex behavior of the cooperative swarm itself for later analysis. If you have a thousand devices, you most likely are not going to be able to host your server on a Raspberry Pi, which has limited CPU power and storage. Another major problem with basing your system on physical servers that you control (like Raspberry Pis, but also rack mount servers with much larger CPU and memory capabilities) is that of scalability. If suddenly you have 10,000 devices connecting to your servers instead of 1,000 devices, you need to be able to scale quickly and effectively.

It is this realization that IOT systems need to scale quickly and efficiently that has moved the IOT back-end applications into the realm of cloud computing. For an IOT application, there are three main areas that need to be addressed. They are the following: Cloud Computing, Application Builders, and Report and Generation software.

Cloud Computing

Cloud computing is evolving quickly to morph into more services, ubiquitous back ends, high-speed network connectivity, and multiple languages and solutions. The National Institute of Science and Technology (NIST) provides a document that defines cloud computing for government purposes [ http://csrc.nist.gov/publications/nistpubs/800-145/SP800-145.pdf ]. While parts of it are already outdated, it does give a good base definition of cloud computing.

NIST defines cloud computing as this: “Cloud computing is a model for enabling ubiquitous, convenient, on-demand network access to a shared pool of configurable computing resources (e.g., networks, servers, storage, applications, and services) that can be rapidly provisioned and released with minimal management effort or service provider interaction.”

The essential characteristics of cloud computing are the following:

  1. On-Demand - User can provision computing services as needed without requiring interaction with service provider.

  2. High Internet Connectivity - Cloud capabilities are available over the network and accessed through mechanisms that promote multiple platform usage (not just desktops, but many other types of computers and devices).

  3. Ability to Pool Resources - Resources such as memory, CPU power, and storage are pooled to support multiple users and customers according to user demand.

  4. Rapid Scaling - Capabilities and resources can be provisioned and released automatically or under user control. With the proper system and software, the cloud can look to be virtually unlimited to the user or application.

  5. Ability to Limit (or Meter) Resources - A cloud will be able to limit resources and optimize resource use at several levels of abstraction.

  6. Ability to Charge for Service - A cloud service is able to account for resource usage, be able to monitor those resources, and report usage in a transparent manner for both the supplier and the user of the system.

Application Builders

There is no way that a cloud provider can anticipate every application or use for data that an IOT provider will need. A good cloud provider will support major types of databases and a variety of standard software Application Programming Interfaces (APIs ). It will provide analytical tools for the data and a variety of different services for manipulating that data. A cloud application (or cloud app) is a program that runs in a cloud environment. It has some aspects of a pure local app (for an iPad or a desktop) and some aspects of a pure web-based app. A local app will reside entirely on your local computer, while a web app is generally stored entirely on a remote computer and is delivered via a browser interface. There are web apps that are a hybrid (such as WebEx) that have a very light client on the browser side (still an app, but a small one) that connects up via an API to a much more complex program on the server side. The application builders in IBM Bluemix have a heavier client (running the graphics and editing part of the application) and then deliver the user design to the servers via an API.

In the IOT world, an application often has both aspects, where the local computer contains part of the application (say sensor data gathering) and the cloud contains the back-end heavy metal processing for the full application. The IOTPulse project is one of these mixed types of applications.

Display and Report Generation

Displaying pertinent information to the user about the user’s IOT devices and what actions they are performing on the user’s behalf is an important aspect that will lead to the adoption of widespread IOT applications. It is argued by some that it is important not to overwhelm the user with data about what is going on. However, we believe that the “overwhelming” part of the IOT can be handled with hierarchical interfaces. The top-most level of the user interface may only display the very basic information needed by the user (say temperature and furnace status). The author attended an early meeting on what was to become the IOT at Microsoft in Redmond, Washington, and the speaker called the most basic mode “Grandma Mode” because he felt there was a need to support substantially every type of user that was going to be using the product with a simple interface.

We felt this was true as far as it went, but with the IOT, the ability for a device and software interface to show what is going on with the data being gathered is paramount. A method and interface needs to be provided for the user to really drill down and look at what is happening inside his network and device at several different levels. Not as part of the “Grandma Mode” interface, but another set of interfaces that are accessible to any user if the user should wish.

Doing this hierarchical interface is a key part of establishing the necessary trust between the user and the IOT device.

A well-designed cloud-based application and report generation system needs to provide the application developer many different ways of analyzing the data, acting on the data, and displaying the data. The cloud developer will never be able to supply all the possible build interfaces that the app developer will need for every application.

The IBM Bluemix Internet Of Things Solution

Bluemix (Figure 5-1) is an IOT-focused implementation of IBM's Open Cloud Architecture that enables you to create, deploy, and manage cloud applications for the Internet Of Things.

A367492_1_En_5_Fig1_HTML.jpg
Figure 5-1. The IBM Bluemix Logo

There is a growing ecosystem of runtime frameworks and services, including non-IBM third-party solutions and applications. Bluemix provides a dashboard for you to create, view, and manage your applications, IOT devices, and desired services The Bluemix dashboards also provide the ability to manage organizations, spaces, and (very importantly!) user access.

We did find that the “dashboard” paradigm in the Bluemix system somewhat of a misnomer and a bit confusing. Instead of having one dashboard, you have dashboards for every service that you attach. It's easy to get lost in the sequence. But with some perseverance we got through the learning curve.

Bluemix provides access to a wide variety of services that can be incorporated into an application from multiple vendors.

For more complex applications than the IOTPulse device, you have a set of application libraries that you can build your applications connecting to a variety of databases functions and frameworks. Here are some of the more common ones:

  • Node.js

  • PHP

  • Python

  • Ruby

All in all, Bluemix is a good implementation of a cloud-based IOT platform to build upon.

Note that Bluemix is an evolving platform, and there will be changes going forward in their product maturation process.

There are many features that are free for prototypes (such as IOTPulse), and all of the features mentioned in this chapter are free for use on Bluemix. Looking through the paid services and rates, it seems that they are reasonable for both small and large applications .

The IOTPulse Design

The IOTPulse design consists of three blocks. The first block is the ESP8266 and the 9V battery, which contains the computer; the WiFi interface; and a single Analog to Digital Converter (ADC ) pin, called A on the ESP8266 board and A0 inside the Arduino IDE software. The ESP8266 is responsible for doing the signal processing and translation of the incoming analog heartbeat signal to a digital heartbeats per minute (BPM) and then will periodically send the latest BPM up to the Bluemix IOT cloud.

The second block is the Pulse Sensor Amped, which is an open source hardware design by www.pulsesensor.com . Figure 5-2 shows the schematic for the Pulse Sensor. The key thing to take away from the pulse sensor is that it is designed to get an approximate measure of heart rate through the skin in a non-invasive way. It works by shining a bright green LED into your skin and then detecting the relative changes in light intensity to the sensor. With a small amount of signal shaping, you can detect pulse rate via an analog output signal.

A367492_1_En_5_Fig2_HTML.jpg
Figure 5-2. Schematic for the Pulse Sensor

For more information on the technique, see photoplethysmogram [ https://en.wikipedia.org/wiki/Photoplethysmogram ].

The third block is a resistor-based voltage divider. The issue that we are solving with this voltage divider is that the signal output from the Pulse Sensor is about 1.5V and the ADC input on the ESP8266 only goes up to 1V. For a full description on how a voltage divider works, check out the Wikipedia article [ https://en.wikipedia.org/wiki/Voltage_divider ].

We need to take 1.5V down to about 0.6V for the ESP8266 and the software to work. The Pulse Sensor provides a signal that on the average is about 1.5V, which is too high for the ESP8266 ADC to work correctly. With the choice of a 26K Ohm resistor for R1 in Figure 5-3 and an 18K Ohm resistor for R2 in Figure 5-3, we get the following ratio of input to output voltage:

A367492_1_En_5_Fig3_HTML.jpg
Figure 5-3. Simple Voltage Divider
Vout = Vin * R2/(R1 + R2)

Vout = 1.5V * 18K/(26K + 18K) = 0.6V

The 0.6V is comfortably in the 0.0 - 1.0V range of the ESP8266 ADC and works well. There is virtually no current drain through this voltage divider because of the high resistance of the voltage divider (44K Ohms).

Why does this work? It is because the software in the ESP8266 is calculating the heartbeat by looking at relative changes in the light intensity and not the absolute voltage. As long as the input value is changing, the ESP8266 will pick up the pulse.

If we did not put the voltage divider on the output of the Pulse Sensor, then the ADC in the ESP8266 would always be pegged to the highest level (1.0V) and the sensor software would not be able to pick up a pulse.

Because the ESP8266 ADC is so limited, there are better solutions out there for an ADC. Two of the easier to use boards are these:

Figure 5-4 shows the block diagram, including the voltage divider, of the IOTPulse project. The completed IOTPulse device, including the 3D Printed case is shown in Figure 5-5.

A367492_1_En_5_Fig4_HTML.jpg
Figure 5-4. Block Diagram of IOTPulse
A367492_1_En_5_Fig5_HTML.jpg
Figure 5-5. IOTPulse in Case

Building the IOTPulse

The parts list is shown in Table 5-2, followed by the wiring list. The parts for the IOTPulse device are readily available and only the voltage divider will require any soldering.

Table 5-2. Parts List

Part Number

Count

Description

Approximate Cost per Board

Source

ESP8266 Huzzah Board

1

CPU / WiFi board

$10

http://www.adafruit.com/products/2471

Pulse Sensor Amped

1

I2C Light Sensor

$25

www.Pulsesensor.com

FTDI Cable

1

Cable for programming the ESP8266 from PC/Mac

$11

http://www.switchdoc.com/inexpensive-ftdi-cable-for-arduino-esp8266-includes-usb-cable/

26K Ohm Resistor

1

1/4 watt

$17 for a large mix of resistors (Joe Knows Electronics)

http://​amzn.​to/​1QCASLB

18K Ohm Resistor

1

1/4 watt

$17 for a large mix of resistors (Joe Knows Electronics)

http://amzn.to/1QCASLB

Plugging the FTDI Cable into the ESP8266

An FTDI cable is plugged into the end of the Adafruit Huzzah ESP8266. Make sure you align the GND pin on the FTDI Cable with the GND pin on the ESP8266 breakout board as shown in Figure 5-6.

A367492_1_En_5_Fig6_HTML.jpg
Figure 5-6. FTDI Cable Plugged into the Huzzah Board. Note GND Connection

Table 5-3 contains the wiring list for the IOTPulse project.

Table 5-3. IOTPulse Wiring List

From

To

Description

 

ESP8266/GND

PulseSensor / GND (Black Wire)

Ground for Pulse Sensor

 

ESP8266/3V

PulseSensor / 3.3V (Red Wire)

3.3V Power for Pulse Sensor

 

PulseSensor/Output (Purple Wire)

26K / Port A

Top of the Resistor Divider

 

26K/Port B

18K / Port A

Middle of the Resistor Divider

 

18K/Port A

ESP8266 / GND

Ground for bottom of Resistor Divider

 

26K/Port B

ESP8266 / A0

A0 - Analog to Digital Converter input on ESP8266

 

3D Printing Files for the IOT Case

Finding a case for a custom project can always be a problem. All of the projects in the chapters have suggested using 3D Printing to build cases that fit the project, and the IOTPulse project is no different. The most interesting part of this case is the way we designed a bevel that goes around the base so the top case will snap onto the bottom case (Figure 5-7).

A367492_1_En_5_Fig7_HTML.jpg
Figure 5-7. IOT Case

We have introduced openSCAD , a free code-based 3D Modeler in previous chapters. There are hundreds of example models on Thingverse.com and the openSCAD web site to choose from and to learn from. Listing 5-1 contains the code that builds the case shown in Figure 5-7.

Listing 5-1. openSCAD code for the IOT Case
//
// IOTPulse Case
//
// SwitchDoc Labs
// August 2015
//


include <RoundedRect.scad>

module rcube(size=[30, 20, 10], radius=[3, 2, 1], center=true)
    hull() {
        translate( center ? [0,0,0] : size/2 ) {
            cube(size-2*radius+[2*radius[0],0,0],center=true);
            cube(size-2*radius+[0,2*radius[1],0],center=true);
            cube(size-2*radius+[0,0,2*radius[2]],center=true);


            for(x = [-0.5,0.5], y = [-0.5,0.5], z = [-0.5,0.5])
                translate([x * ( size[0] - 2*radius[0]),
                           y * ( size[1] - 2*radius[1]),
                           z * ( size[2] - 2*radius[2])])
                    scale([radius[0], radius[1], radius[2]])
 //                       sphere(1.0,$fn=4*4);
                       sphere(1.0,$fn=6*6);
        }
    }


module IOTPulseTopCase()
{


    difference()
    {
        //cube([82,62,25]);


        rcube(size=[82,62,30],radius=[5,5,5],center=false);

        #translate([2,2,2])
        cube([78,58,25]);


        #translate([-10,-10,25])
        cube( [100,100,50]);


        // hole for pulse meter 18mm

        translate([-5,62/2,12.5])
        #rotate([0,90,0])
        cylinder(h=10,r=10,10);


        // hole for seeing light
        #translate([82-20,10,-2])
        cylinder(h=10,r=5,10);


        // hole for seeing wifi light
        #translate([82-43,10,-2])
        cylinder(h=10,r=5,10);


    }

}

union()
{


    cube([78,58,4]);
    translate([-2,-2,0])
    cube([82,62,2]);


    // Mount for Battery

    translate([40-2,2,0])
    cube([40-2,1.35,20]);
    translate([40-2,26.10+3.3,0])
    cube([40-2,1.5,20]);


    // lips for battery
    translate([79-2,3,0])
    cube([1,28,6]);


    // plyons for ESP8266

    translate([70-1.0,35,0])
    cylinder(h=10,r1=2.2, r2=1.35/2, $fn=100);
    translate([70-1.0,56,0])
    cylinder(h=10,r1=2.2, r2=1.35/2, $fn=100);
    translate([70-34,35,0])
    cylinder(h=10,r1=2.2, r2=1.35/2, $fn=100);
    translate([70-34,56,0])
    cylinder(h=10,r1=2.2, r2=1.35/2, $fn=100);


    // plyons for resistors for divider

    // gap of 2.3mm

    translate([15,35,2])
    cube([1,5,5]);


    translate([15+3,35,2])
    cube([1,5,5]);


   translate([15,45,2])
    cube([1,5,5]);


    translate([15+3,45,2])
    cube([1,5,5]);


   // top case

    translate([0,70,0])
    IOTPulseTopCase();
}

The code for the IOTPulse case is broken into two main sections. The main program builds the lower part of the case while the top of the case is located in the function IOTPulseTopCase(). When building models with openSCAD, it is a good idea to break different parts into functions even if you are only calling them once. It simplifies the code. Now, let us look at the software for IOTPulse.

Software Needed

For you to program the IOT Pulse board you will need a Mac or PC to program the ESP8266 via the Arduino IDE. See Chapter 2 for how to set up the Arduino IDE with the ESP8266 libraries.

The IOTPulse Code

There are three files that are part of the build for the IOTPulse software. The IOTPulse.ino is the main Arduino IDE file (in the C language), and the other two files (Interrupt.h and AllSerialHandling.h) are included in the main file. While the code is fairly straightforward, comments need to be made for each module.

IOTPulse.ino

IOTPulse.ino is the main program for IOTPulse (Listing 5-2). It consists of two major functions, setup() and loop() . The setup() function initializes the ESP8266 WiFi code, reads an IP address using DCHP from the local wireless access point, and initializes variables for containing micros(), which is a function returning the number of microseconds since the reboot of the ESP8266 micros() is a timekeeping function. Note that the ESP8266 does not have a real-time clock on board and really doesn’t know what time it is. It only knows how long it has been running. If you wish to set the time of day in the ESP8266, please check out the NTP protocol in this Instructable[ http://www.instructables.com/id/Internet-time-syncronized-clock-for-Arduino/ ].

In the IOTPulse project, we really don’t care what time it is. When we send a sample to the Bluemix IOT Platform, our friend IBM will timestamp the reception of the data. If we cared about our time, we could build an NTP receiver and synchronize it to network time at a specific NTP server. We are much more interested in intervals of time (specifically 2 milliseconds and 10 seconds intervals) rather than absolute time.

The loop() function contains the code for ongoing operation of the IOTPulse data-gathering operation. We basically do four things in the loop() function:

  • We check the value of QS. If QS is true, then the software in Interrupt.h has found a BPM (Beats Per Minute) and IBI (Interval Between beats) value for the current pulse rate for our PulseSensor connected to your ear.

  • Next, if 10 seconds have elapsed (10,000,000 microseconds), we send the current value of BPM and IBI up to the IBM Bluemix IOT cloud. We then reset the time to wait for the next 10-second interval, which is stored in the oldIOTTime variable. The actual time for the next interval is oldIOTTime + 10 seconds (10,000,000 microseconds) .

  • If 2 milliseconds have elapsed since oldPulseTime variable (initialized in loop()), we call the timerCallback() function defined in Interrupt.h. We then reset the oldPulseTime variable and wait for another 2ms.

Note at the end of the loop() function, there is a yield() function. This MUST be called periodically for the ESP8266 software to continue running the WiFi interface and other housekeeping functions. Remember, unlike a regular Arduino, there is a great deal going on in the background to keep this chip running and connected to the network.

One limitation of the current ESP8266 software is that you can’t use the timers [ http://www.switchdoc.com/2015/10/iot-esp8266-timer-tutorial-arduino-ide/ ] to generate interrupts without causing the WiFi to fail and stop connecting to the local WiFI access point and the Internet.

This makes it very difficult to generate an interrupt to the computer every 2ms as is called for by the PulseSensor. You could generate an interrupt every 2ms by using an external hardware timer and then connecting the output of the hardware timer to one of the GPIO pins on the ESP8266, which can all be programmed to generate an interrupt to the CPU.

To solve this issue, we use a scheduling technique that is more CPU intensive (read uses more power) than the interrupt scheme. We check the time periodically and run the PulseSensor software every 2ms and also connect to the IBM Bluemix every 10 seconds.

The biggest disadvantage of this is that we cannot “sleep” the processor very easily. We are looking for an alternative architecture for this problem and are watching the ESP8266 development web sites for solutions.

However, with the exception of power consumption, the current solution works well.

Listing 5-2. IOTPulse.ino
/*
    SwitchDoc Labs Code for IOT Pulse
    Connects Pulse detector to the IBM Bluemix IoT using a ESP8266 processor
    based on pulsecounting code from www.pulsesensor.com
    November 2015


  ----------------------  Notes ----------------------  ----------------------
  This code:
  1) Blinks an LED to User's Live Heartbeat   PIN 0


  2) Determines BPM

  3) Sends information to the IBM Bluemix IOT
*/


extern "C" {
#include "user_interface.h"
}
#include <ESP8266WiFi.h>
#include <PubSubClient.h> // https://github.com/knolleary/pubsubclient/releases/tag/v2.3


//----------------------------------------------------------------------
//Local WiFi Variables


const char* ssid = "yourssid";
const char* password = "yourpassword";


#define IOTPULSEVERSION 004

// IBM BlueMix IOT Foundation Data

#define ORG "XXXXX"
#define DEVICE_TYPE "IOTPulse-01"
#define DEVICE_ID "1"
#define TOKEN "YYYYYYYYY"


// setup for IOT IBM

char server[] = ORG ".messaging.internetofthings.ibmcloud.com";
char topic[] = "iot-2/evt/status/fmt/json";
char authMethod[] = "use-token-auth";
char token[] = TOKEN;
char clientId[] = "d:" ORG ":" DEVICE_TYPE ":" DEVICE_ID;


//----------------------------------------------------------------------

//  Variables
int pulsePin = A0;                  // Pulse Sensor purple wire connected to analog pin 0
int blinkPin = 0;                   // pin to blink led at each beat
int fadePin = 5;                    // pin to do fancy classy fading blink at each beat
int fadeRate = 0;                   // used to fade LED on with PWM on fadePin


// Volatile Variables, used in the interrupt service routine!
volatile int BPM;                   // int that holds raw Analog in 0. updated every 2mS
volatile int Signal;                // holds the incoming raw data
volatile int IBI = 600;             // int that holds the time interval between beats! Must be seeded!
volatile boolean Pulse = false;     // "True" when User's live heartbeat is detected. "False" when not a "live beat".
volatile boolean QS = false;        // becomes true when Arduoino finds a beat.


// Regards Serial OutPut  -- Set This Up to your needs
static boolean serialData = true;   // Set to 'false' by Default.  Re-set to 'true' to see Arduino Serial Monitor data


#include "AllSerialHandling.h"
#include "Interrupt.h"


void callback(char* topic, byte* payload, unsigned int length) {
  Serial.println("callback invoked from IOT BlueMix");
}


WiFiClient wifiClient;
PubSubClient client(server, 1883, callback, wifiClient);


unsigned long oldPulseTime;
unsigned long oldIOTTime;


void setup() {

  pinMode(blinkPin, OUTPUT);        // pin that will blink to your heartbeat!

  Serial.begin(115200);             // we agree to talk fast!

  Serial.println("----------------");
  Serial.println("IOTPulse IBM Bluemix IOT");
  Serial.println("----------------");


  Serial.print("Connecting to ");
  Serial.print(ssid);


  // NOTE below:  Newer versions of the ESP8266 Libraries may require the following statement
  // instead of the other statement.  WiFi.SSID() has changed definitions in new versions
  // if (strcmp (WiFi.SSID().c_str(), ssid) != 0) {


  if (strcmp (WiFi.SSID(), ssid) != 0) {
    WiFi.begin(ssid, password);
  }
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");


  Serial.print("Local WiFi connected, IP address: ");
  Serial.println(WiFi.localIP());


  // interruptSetup();                 // sets up to read Pulse Sensor signal every 2mS
  // Note:  Interrupts based on os_timer seems to break the ESP8266 WiFi.  Moving to micros() polling methodology
  oldPulseTime = micros();
  oldIOTTime = micros();
}


int sampleCount = 0;
int beatCount = 0;


int beatValue = 0;
unsigned long newPulseDeltaTime;
unsigned long newIOTDeltaTime;


//  Where the Magic Happens
void loop() {


  //serialOutput() ;

  if (QS == true) {    // A Heartbeat Was Found
    // BPM and IBI have been Determined
    // Quantified Self "QS" true when arduino finds a heartbeat
    digitalWrite(blinkPin, LOW);    // Blink LED, we got a beat.
    beatCount++;


    serialOutputWhenBeatHappens();   // A Beat Happened, Output that to serial.
    QS = false;                     // reset the Quantified Self flag for next time
  }


  newPulseDeltaTime = micros() - oldPulseTime; // doing this handles the 71 second rollover because of unsighned arithmetic

  newIOTDeltaTime = micros() - oldIOTTime; // doing this handles the 71 second rollover because of unsighned arithmetic

  // do this every ten seconds
  if (newIOTDeltaTime > 10000000)  // check for 10sec work to be done
  {


    Serial.print("IOT Delta time =");
    Serial.println(newIOTDeltaTime);
    sampleCount++;


    // Sending payload: {"d":{"IOTPulse":"IP1","VER":2"SC":0,"BPM":235,"IBI":252}}

    String payload = "{"d":{"IOTPulse":"IP1",";
    payload += ""VER":";
    payload += IOTPULSEVERSION;
    payload += ","SC":";
    payload += sampleCount;
    payload += ","BPM":";
    payload += BPM;
    payload += ","IBI":";
    payload += IBI;
    payload += ","BC":";
    payload += beatCount;
    payload += "}}";


    if (!!!client.connected()) {
      Serial.print("Reconnecting client to ");
      Serial.println(server);
      while (!!!client.connect(clientId, authMethod, token)) {
        Serial.print(".");
        delay(500);
      }
      Serial.println();
    }


    Serial.print("Sending IOTPulse payload: ");
    Serial.println(payload);


    if (client.publish(topic, (char*) payload.c_str())) {
      Serial.println("BlueMix IOT Publish ok");
    } else {
      Serial.println("BlueMix IOT Publish failed");
    }
    oldIOTTime = micros();


    // restart the pulse counter
    restartPulse();
  }


  //Serial.print("micros()=");
  //Serial.println(micros());


  if (newPulseDeltaTime > 2000)  // check for 2ms work to be done
  {


    //Serial.print("Pulse Delta time =");
    //Serial.println(newPulseDeltaTime);
    // do the work for pulse calculation
    timerCallback(NULL);


    oldPulseTime = micros();
  }


  yield(); //  take a break
}

AllserialHandling.h (Listing 5-3) contains the serial output debugging routines that are useful when modifying the code.

Listing 5-3. AllSerialHandling.h
//////////
/////////  All Serial Handling Code,
/////////  It's Changeable with the 'serialVisual' variable
/////////  Set it to 'true' or 'false' when it's declared at start of code.
/////////


void sendDataToSerial(char symbol, int data );

void serialOutput() {  // Decide How To Output Serial.

    sendDataToSerial('S', Signal);     // goes to sendDataToSerial function
}


//  Decides How To OutPut BPM and IBI Data
void serialOutputWhenBeatHappens() {
  if (serialData == true) {           //  Code to Make the Serial Monitor Visualizer Work
    Serial.print("*** Heart-Beat Happened *** ");  //ASCII Art Madness
    Serial.print("BPM: ");
    Serial.print(BPM);
    Serial.print(" IBI: ");
    Serial.print(IBI);
    Serial.println("  ");
  }
}


//  Sends Data to Pulse Sensor Processing App, Native Mac App, or Third-party Serial Readers.
void sendDataToSerial(char symbol, int data ) {
  Serial.print(symbol);


  Serial.println(data);
}

Interrupt.h (Listing 5-4) is called this because the original PulseSensor software used an Arduino timer to generate a 2ms interrupt. As is explained above, the ESP8266 is not currently capable of doing the same thing while maintaining a functional WiFi interface. The function timerCallback() in Interrupt.h is now called at a scheduled time by the loop() function in the IOTPulse.ino file.

Basically, timerCallback() acts as a detector and averaging filter that detects the upswing on the PulseSensor output and then builds a set of times for IBI (Interval Between beats) and provides an average. It adjusts to the recorded levels coming from the PulseSensor because the actual level is not as important as the time interval between adjusted pulses from the PulseSensor. The software acts as a peak and trough detector with an average system that removes high-frequency noise.

Listing 5-4. Interrupt.h
volatile int rate[10];                    // array to hold last ten IBI values
volatile unsigned long sampleCounter = 0;    // used to determine pulse timing
volatile unsigned long lastBeatTime = 0;     // used to find IBI
volatile int P = 680;                     // used to find peak in pulse wave, seeded 512
volatile int T = 680;                     // used to find trough in pulse wave, seeded 512
volatile int thresh = 700;                // used to find instant moment of heart beat, seeded 525
volatile int amp = 100;                   // used to hold amplitude of pulse waveform, seeded
volatile boolean firstBeat = true;        // used to seed rate array so we startup with reasonable BPM
volatile boolean secondBeat = false;      // used to seed rate array so we startup with reasonable BPM


void restartPulse()
{


  sampleCounter = 0;          // used to determine pulse timing
  lastBeatTime = 0;           // used to find IBI
  P = 680;                    // used to find peak in pulse wave, seeded 512
  T = 680;                    // used to find trough in pulse wave, seeded 512
  thresh = 700;               // used to find instant moment of heart beat, seeded 525
  amp = 100;                  // used to hold amplitude of pulse waveform, seeded
  firstBeat = true;           // used to seed rate array so we startup with reasonable BPM
  secondBeat = false;


}
void timerCallback(void *pArg);


// Timer  makes sure that we take a reading every 2 miliseconds
void timerCallback(void *pArg) {              // triggered on interrupts
  //cli();                                    // disable interrupts while we do this
  Signal = analogRead(pulsePin);              // read the Pulse Sensor
  //Serial.print("Signal-A0-:");
  //Serial.println(Signal);


  sampleCounter += 2;                         // keep track of the time in mS with this variable
  int N = sampleCounter - lastBeatTime;       // monitor the time since the last beat to avoid noise


  //  find the peak and trough of the pulse wave
  if (Signal < thresh && N > (IBI / 5) * 3) { // avoid dichrotic noise by waiting 3/5 of last IBI
    if (Signal < T) {                         // T is the trough
      T = Signal;                             // keep track of lowest point in pulse wave
    }
  }


  if (Signal > thresh && Signal > P) {        // thresh condition helps avoid noise
    P = Signal;                               // P is the peak
  }                                           // keep track of highest point in pulse wave


  //  NOW IT'S TIME TO LOOK FOR THE HEART BEAT
  // signal surges up in value every time there is a pulse
  if (N > 250) {                             // avoid high frequency noise
    if ( (Signal > thresh) && (Pulse == false) && (N > (IBI / 5) * 3) ) {
      Pulse = true;                          // set the Pulse flag when we think there is a pulse
      digitalWrite(blinkPin, LOW);           // turn on  LED
      IBI = sampleCounter - lastBeatTime;    // measure time between beats in mS
      lastBeatTime = sampleCounter;          // keep track of time for next pulse


      if (secondBeat) {                      // if this is the second beat, if secondBeat == TRUE
        secondBeat = false;                  // clear secondBeat flag
        for (int i = 0; i <= 9; i++) {       // seed the running total to get a realisitic BPM at startup
          rate[i] = IBI;
        }
      }


      if (firstBeat) {                       // if it's the first time we found a beat, if firstBeat == TRUE
        firstBeat = false;                   // clear firstBeat flag
        secondBeat = true;                   // set the second beat flag
        //sei();                             // enable interrupts again
        return;                              // IBI value is unreliable so discard it
      }


      // keep a running total of the last 10 IBI values
      word runningTotal = 0;                 // clear the runningTotal variable


      for (int i = 0; i <= 8; i++) {         // shift data in the rate array
        rate[i] = rate[i + 1];               // and drop the oldest IBI value
        runningTotal += rate[i];             // add up the 9 oldest IBI values
      }


      rate[9] = IBI;                         // add the latest IBI to the rate array
      runningTotal += rate[9];               // add the latest IBI to runningTotal
      runningTotal /= 10;                    // average the last 10 IBI values
      BPM = 60000 / runningTotal;            // how many beats can fit into a minute? that's BPM!
      // reduce to 83% based on comparison
      BPM= (BPM * 83)/100;
      QS = true;                             // set Quantified Self flag
      // QS FLAG IS NOT CLEARED INSIDE THIS ISR
    }
  }


  if (Signal < thresh && Pulse == true) {  // when the values are going down, the beat is over
    digitalWrite(blinkPin, HIGH);          // turn off pin 13 LED
    Pulse = false;                         // reset the Pulse flag so we can do it again
    amp = P - T;                           // get amplitude of the pulse wave
    thresh = amp / 2 + T;                  // set thresh at 50% of the amplitude
    P = thresh;                            // reset these for next time
    T = thresh;
  }


  if (N > 2500) {                          // if 2.5 seconds go by without a beat
    thresh = 512;                          // set thresh default
    P = 512;                               // set P default
    T = 512;                               // set T default
    lastBeatTime = sampleCounter;          // bring the lastBeatTime up to date
    firstBeat = true;                      // set these to avoid noise
    secondBeat = false;                    // when we get the heartbeat back
  }


  //sei();                                 // enable interrupts when youre done!
}// end isr

Reviewing the Arduino IDE Serial Monitor Results

Listing 5-5 shows the output from the Serial Monitor on the Arduino IDE as you run the software. Note that this code was run after joining the IBM Bluemix IOT as shown later in this chapter. If you haven’t joined the Bluemix IOT yet, then you will see an “authentication failed” error every time that the IOTPulse software tries to contact Bluemix.

Listing 5-5. Serial Monitor Output
IOTPulse IBM Bluemix IOT
----------------
Connecting to gracie........
Local WiFi connected, IP address: 192.168.1.117
*** Heart-Beat Happened *** BPM: 92 IBI: 534  
*** Heart-Beat Happened *** BPM: 91 IBI: 630  
*** Heart-Beat Happened *** BPM: 92 IBI: 468  
*** Heart-Beat Happened *** BPM: 91 IBI: 590  
*** Heart-Beat Happened *** BPM: 92 IBI: 516  
*** Heart-Beat Happened *** BPM: 91 IBI: 548  
*** Heart-Beat Happened *** BPM: 91 IBI: 530  
*** Heart-Beat Happened *** BPM: 91 IBI: 556  
*** Heart-Beat Happened *** BPM: 91 IBI: 540  
*** Heart-Beat Happened *** BPM: 91 IBI: 530  
*** Heart-Beat Happened *** BPM: 90 IBI: 586  
*** Heart-Beat Happened *** BPM: 92 IBI: 538  
*** Heart-Beat Happened *** BPM: 90 IBI: 540  
*** Heart-Beat Happened *** BPM: 91 IBI: 564  
IOT Delta time =10000002
Reconnecting client to 4183lj.messaging.internetofthings.ibmcloud.com
.
Sending IOTPulse payload: {"d":{"IOTPulse":"IP1","VER":4,"SC":1,"BPM":91,"IBI":564,"BC":14}}
BlueMix IOT Publish ok
*** Heart-Beat Happened *** BPM: 87 IBI: 564  
*** Heart-Beat Happened *** BPM: 87 IBI: 574  
*** Heart-Beat Happened *** BPM: 87 IBI: 546  
*** Heart-Beat Happened *** BPM: 87 IBI: 566  
*** Heart-Beat Happened *** BPM: 87 IBI: 572  
*** Heart-Beat Happened *** BPM: 87 IBI: 584  
*** Heart-Beat Happened *** BPM: 87 IBI: 570  
*** Heart-Beat Happened *** BPM: 87 IBI: 582  
*** Heart-Beat Happened *** BPM: 87 IBI: 590  
*** Heart-Beat Happened *** BPM: 86 IBI: 582  
*** Heart-Beat Happened *** BPM: 86 IBI: 572  
*** Heart-Beat Happened *** BPM: 85 IBI: 610  
*** Heart-Beat Happened *** BPM: 85 IBI: 572  
IOT Delta time =10000009
Reconnecting client to 4183lj.messaging.internetofthings.ibmcloud.com
.
Sending IOTPulse payload: {"d":{"IOTPulse":"IP1","VER":4,"SC":2,"BPM":85,"IBI":572,"BC":27}}
BlueMix IOT Publish ok
*** Heart-Beat Happened *** BPM: 108 IBI: 456  
*** Heart-Beat Happened *** BPM: 106 IBI: 562  
*** Heart-Beat Happened *** BPM: 103 IBI: 568  
*** Heart-Beat Happened *** BPM: 101 IBI: 574  
*** Heart-Beat Happened *** BPM: 98 IBI: 576  
*** Heart-Beat Happened *** BPM: 96 IBI: 582  

Figure 5-8 shows the completed IOTPulse device in the case. Note the holes on the top to view the LEDs on the ESP8266 board. Figure 5-9 shows the pulse sensor clipped on an ear. Notice the green LED used for sensing the pulse rate in the ear.

A367492_1_En_5_Fig8_HTML.jpg
Figure 5-8. IOTPulse in Case
A367492_1_En_5_Fig9_HTML.jpg
Figure 5-9. IOTPulse Sensor on Ear

Joining IBM Bluemix and the IoT Foundation

The IBM BlueMix and the IoT Foundation are the two key IOT cloud services we will be using to connect up the IOTPulse device to the cloud. The tasks that need to be done to connect up mostly have to do with setting up user accounts and putting billing information into the system. Note that we are using the free levels of the Bluemix system, but IBM still requires billing information. The most important technical information we will gather is how to authenticate our IOT device to the IBM cloud. Figure 5-10 describes the overall architecture of the Bluemix/IoT Foundation cloud application.

A367492_1_En_5_Fig10_HTML.jpg
Figure 5-10. IBM Bluemix Block Diagram

The IoT Foundation is the IBM Bluemix service that we will need to hook up the ESP8266 to the Bluemix cloud service. You will need to create an IBM ID account. You can do so on the Bluemix home page shown in Figure 5-11.

A367492_1_En_5_Fig11_HTML.jpg
Figure 5-11. IBM Bluemix First Page

The steps to join IBM Bluemix are the following:

  1. Create an IBM ID account here;

  2. Validate your account through the IBM sent e-mail;

  3. Go to the IBM Bluemix site and click Log In;

  4. Sign in on the login page;

  5. Go to the Bluemix Dashboard;

  6. Click USE SERVICES OR APIS;

  7. Add the Internet of Things Foundation Service (It is WAY down at the bottom of the list on the web page).

You should then have a screen similar to the one in Figure 5-12, with the exception of the “IoT Real-Time Insights” panel, which will be added to your Bluemix account later in this chapter.

A367492_1_En_5_Fig12_HTML.jpg
Figure 5-12. Bluemix Dashboard

Sending your Data to Bluemix

First of all, what do we send up to Bluemix from the ESP8266? It turns out the data protocols are pretty straightforward There are two major protocols that require descriptions.

MQTT and JSON.

MQTT

MQTT is a publish-subscribe-based "light weight" messaging protocol for use on top of the TCP/IP protocol, such as the WiFi packets that we are using in this project. It is designed for connections with remote locations where a "small code footprint" is required or the network bandwidth is limited. Both of these conditions are met with an ESP8266 IOT design, so it makes sense to use. There is also an excellent library available for MQTT for the Arduino IDE [ https://github.com/knolleary/pubsubclient ]. The publish-subscribe messaging pattern requires a message broker. The broker is responsible for distributing messages to interested clients based on the topic of a message (Figure 5-13) .

A367492_1_En_5_Fig13_HTML.jpg
Figure 5-13. MQTT Publish-Subscribe Protocol

Publish-subscribe is a pattern where senders of messages, called publishers (in this case our ESP8266 is the publisher), don't program the messages to be sent directly to subscribers, but instead characterize message payloads into classes without the specific knowledge of which subscribers the messages are sent to. Similarly, subscribers (the IBM Bluemix IOT in this case) will only receive messages that are of interest without specific knowledge of which publishers there are. The IBM Bluemix operates as the broker in this system and routes the published data to the appropriate subscribers inside of Bluemix.

JSON Data Payload

JSON is an open standard format that uses human-readable text to transmit data objects consisting of attribute–value pairs. It is the primary data format used for asynchronous browser/server communication, largely replacing XML. XML is a "heavier" protocol that is also hierarchical in nature, but with a great deal more redundancy that JSON. Yes, there are class wars going on for people that advocate JSON over XML, but in today’s world of higher speed communication, it rarely matters. You can make the argument that the higher data density of JSON is a better choice for IOT applications.

Here is an example of the data packet we are using in the ESP8266 Bluemix code in JSON for the LightSwarm data payload:

{"d":
      {
         "LightSwarm IOT":"LS1",
         "sampleCount":2118,
         "lightValue":383
      }
}

Authentication

We need to have a secure method of authenticating that our ESP8266 device is allowed to put data into the right slots inside the IBM Bluemix. This is done in our case by exchanging a cryptographic token that was generated by Bluemix and included in our ESP8266 code.

To do this we need to go back to the Bluemix account that you set up in the previous posting and complete the following steps:

  1. Click the Internet of Things Foundation icon on the Bluemix dashboard.

  2. Next, click the Launch dashboard button under “Connect your devices” (Figure 5-14).

    A367492_1_En_5_Fig14_HTML.jpg
    Figure 5-14. Connect your Devices to Bluemix
  3. Go to the Devices Tab and “Add Device” down at the bottom of the page.

  4. Click “Create Device Type,” and the screen in Figure 5-15 appears .

    A367492_1_En_5_Fig15_HTML.jpg
    Figure 5-15. Create Bluemix Device Type

We would suggest you use IOTPulse-01 for the name of the device type.

Move through the rest of the steps. There are many configuration options that nearly all can be left blank in our current application. You are required to have a device type and a device ID.

When the device has been created, you’ll see the Device Credentials page. Be sure to save those details, as they are used to authenticate your ESP8266 Arduino IDE sketch in in the next step (we have not found any way of recovering these credentials from the Bluemix system). Obviously, don't use the credentials in Figure 5-16. They will not work. You need to create your own.

A367492_1_En_5_Fig16_HTML.jpg
Figure 5-16. Bluemix Credential Screen

Displaying Real-Time Data on the IBM Bluemix IOT Platform

In order to get a display going in the Bluemix platform, we need to connect our device to the IoT Real-Time Insights service on Bluemix. The following sections discuss this.

Adding Real-Time Insights

Step 1: Add the IoT Real-Time Insights service to your Bluemix dashboard. Open the Bluemix dashboard (the first dashboard after login) and click “USE SERVICES OR APIS” and add the IoT Real-time Insights as a service. It is way down at the bottom of the page. You will then see the screen in Figure 5-17.

A367492_1_En_5_Fig17_HTML.jpg
Figure 5-17. IoT Real-Time Insights

Step 2: Connect our device to the IoT Real-Time Insights Page by generating an API key and then generating a data source. Click the IoT Real-Time Insights block shown in Figure 5-16.

Step 3: Generate the API keys for using the Data Source and create API keys to connect the two services (IoT Foundation and IoT Real-Time Display):

  1. From the Bluemix dashboard, click the Internet of Things tile.

  2. Click Launch dashboard to open the Internet of Things Foundation dashboard.

  3. Navigate to Access > API Keys.

  4. Click Generate API Key.

  5. Make a note of the API Key, Authentication Token, and the Organization ID that is displayed at the top of the IoT Foundation dashboard. You use this information in IoT Real-Time Insights to connect the services. These keys will remain displayed in the data source.

Adding the Data Source

Adding the data source (our IOTPulse device) consists of the following (Figure 5-18):

A367492_1_En_5_Fig18_HTML.jpg
Figure 5-18. Adding the Data Source
  1. Go to Devices > Manage Schemas and click Add new message schema.

  2. Enter a name for the message schema: for example, IOTMessageSchema.

  3. Click Link new data source and select the data source and device type that corresponds to your IoT Foundation instance and device. Event types for your device are here.

  4. Add one or more data points that you want to include in the device dashboards (sampleCount and lightValue in our example).

  5. The available data points are defined in the JSON payload of the messages that are sent by a device.

  6. Click Select from connected device.

  7. In the Add data points dialog, select one or more data points to add, and then click OK.

  8. The selected data points are added with the description set to the name of the data point.

  9. Then click the green arrow (on the left side of the screen) to save the information and create the data source .

Once all of the configuration data is in place and the authentication information is in place in the IOTPulse program, data should start to flow as shown in Figure 5-19.

A367492_1_En_5_Fig19_HTML.jpg
Figure 5-19. IOT Data Starts to Flow

Now we add the displays to visualize our data.

Adding the Dashboard to the IoT Real-Time Display

From the screen in Figure 5-20, click Launch IoT Real-Time Insights Dashboard in the lower right-hand column.

A367492_1_En_5_Fig20_HTML.jpg
Figure 5-20. IoT Real-Time Insights

Click dashboard and browse dashboards. Add a new dashboard. Then do the following:

  1. Add new component;

  2. Select chart;

  3. Add line to the chart;

  4. Select your device and then select lightValue as the parameter;

  5. Click the green arrow.

Figure 5-21 shows the IBM BlueMix screen for laying out your dashboard interface.

A367492_1_En_5_Fig21_HTML.jpg
Figure 5-21. Building your IoT Real-TimeDashboard

If your ESP8266 is running and sending data up to the IBM Bluemix IOT, then you will see the values start to populate the graph, as shown in Figure 5-22.

A367492_1_En_5_Fig22_HTML.jpg
Figure 5-22. Bluemix IoT Real-Time Dashboard Operational

Advanced Topics

The IBM cloud offerings have literally hundreds of options and possibilities for bringing your IOT data to the cloud. Below we show a few of these “apps” available on the Bluemix system. We will show how to graph your historical IOT data and introduce a complex, but very powerful, programming system, Node-RED.

Historical Data

Non-real-time historical data can also be viewed in Bluemix (Figure 5-23). This requires you to build an app (not as complex as you might think) and then deploy the app. A good tutorial for this is located on the IBM Bluemix web site [ https://www.ng.bluemix.net/docs/starters/install_cli.html ]. It does require you to install a command-line interface for Cloud Foundry on your computer.

A367492_1_En_5_Fig23_HTML.jpg
Figure 5-23. Historical IOTPulse Data

One thing this historical data graph of our pulse rate does show is that the data from IOTPulse could be improved by more filtering. The average of the heart rate looks good, but the jumps up and down look like noise, especially earlier in the graph.

Node-RED Applications

Node-RED is a graphical tool for wiring together devices, external APIs, and online services. You use a browser-based flow editor that makes it simple to wire together flows from an extensive library And it is easy to add your own nodes.

Node-RED is fully supported by IBM Bluemix. It is primarily an event-based software generation system. If an event happens (such as IOTPulse sending data), you can take that data and process it in various ways, send it to other applications, and store it in databases. Other inputs can cause displays to be updated, queries to be sent to databases, and many other events .

We built a small Node-RED application for IOTPulse shown in Figure 5-24.

A367492_1_En_5_Fig24_HTML.jpg
Figure 5-24. Node-RED Application Flow for IOTPulse

Watson Applications

One of the more exciting class of applications that can be built in Bluemix are those utilizing the IBM Watson software. All of the Watson services on the Bluemix platform are accessed via HTTP transfers known as REST services. REST stands for Representation State Transfer and is a common way of accessing web-based services.

Watson supports a number of very sophisticated services all available to your device and applications in Bluemix:

  • Speech to Text

  • Text to Speech

  • Language Translation

  • Support for User Dialogs

  • Determining the “Tone” for Text

  • Visual Recognition

  • Image Analysis - Objects, People, and Text

Conclusion

The future of the IOT is data: how to gather it, how to transmit it, how to analyze and display it, and how to act on it. The IOTPulse project shows how to gather data and how to send it up to a cloud computing system for analysis and actions.

With a proper sensor, the IOTPulse project could be a commercial product. The sensor and analysis of the heart rate are definitely not medical grade, but still illustrates the principles of the IOT device and the device relationship with the IOT cloud.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.19.162