You are on page 1of 30

UNIVERSITY OF ILLINOIS

CHICAGO
DETECTION AND ESTIMATION
T H EO RY

TIME SERIES DATA ESTIMATION FOR


NETWORK CONNECTED MACHINETO-MACHINE (M2M) DEVICES
PRO JEC T REPO RT

G O W T H A M S I VA K U M A R
UIN:674422979

CONTENTS
Tab 1

Report Notebook

Introduction.1
The Setup ....2
API details.3
Setting up a server to handle triggers.12
Using the Flow Designer...15
Estimating Parameters..........18
Future Work..25

INTRODUCTION
M2X Data Service is a cloud-based, time series data storage solution for
network connected Machine-to-Machine (M2M) devices, applications, and services.
M2X makes it easier for developers to gather real-time data from various M2M
sources and translate it into meaningful information, making operational detections
based on the data, and share the data for estimating parameters.
Flow Designer is a cloud based, multi-tenant development and execution
service for network connected IoT devices. Flow Designer provides support for
common IoT protocols. It helps developers create custom business logic and integrate
it with external services such as analytics, visualization and other services.
The intent of this project is to gather insights on using the M2X Data Service
and Flow Designer APIs and integrate it onto IoT applications.
My execution is targeted toward developing a flow, curl and a web-based REST
client and use any programming language or REST client. In addition, I have used the
TI MSP432 LaunchPad with the CC3100MOD BoosterPack and the Flow Designer,
to connect to a network and make HTTP requests.
In order to compile the framework, I used:

A browser with an internet connection.

ATIMSP432 LaunchPad, CC3100MOD BoosterPack and micro-USB


cord(micro to regular).

A REST client, such as the Chrome app Postman.

A command line tool called curl (officially known as cURL).

THE SETUP
In order to call the M2X Data Service APIs, an M2X Beta account has to be
created. Once that is done, we can create new Devices and begin to push data into
the service.
An M2X Device defines the attributes associated with an IP enabled device,
application, or service that will be sending data to the M2X service. Once the
Device has been tested, it can be used with multiple devices of the same type,
which is accomplished through creating a Distribution and launching it.
In this project, I first set up an M2X Device and then sent data to it. Finally,
I made a request to obtain all of the data that the Device has collected.
To make HTTP requests, I used graphical client such as the Postman addon for Chrome, and the curl command line tool.
Conventions used
The following formatting conventions are used to differentiate requests:

API DETAILS
Sending Data
To send one piece of data from a Device, make an HTTP PUT request to this URL:
http://api-m2x.att.com/v2/devices/{device-ID}/streams/speed/value

where {device-ID} is the ID of the Device you created. The request contains the
following headers:

The POST body contains JSON with following parameters:

Retrieving Data
To retrieve data that was sent, make an HTTP GET request to this URL:
http://api-m2x.att.com/v2/devices/{device-ID}/streams/speed/values

where {device-ID} is the ID of the feed you created when creating the Device. The
request should contain the following header:

If successful, the returned JSON data will be:

Creating a Device
The M2X Data Service can receive, store, and react to data from a data source. In
order to prepare the service for the data source, the first step is to set up a Device,
which is a way to prototype the Device before launch.

Go to https://m2x.att.com/devices.

You will be asked to set up your first Device as either a physical device or a
virtual device. We will work on a Virtual Device.

Click on Create device and choose a device name:

The device will have a device ID and an API key associated with it:

Now we can add a data stream for the device. That is, the parameter it is estimating.

Type in presstime for the Stream ID. For the display name, type Seconds
Pressed. Then click the Aa button on the Units & Symbols line. Click the letter
S, and then choose Second.

Running the Code on the device


The following steps are done to upload the code to the device and run it. Make sure
the device is plugged into your USB drive.
From the Tools menu, select Board, and then select LaunchPad w/ msp432
EMT (48 MHz).
From the Tools menu, select Serial Port, and then select the appropriate item
in the list. (Typically the first port that starts with /dev/tty.usbmodem on a Mac
and the first port that starts with COM on a Windows computer.)

Type the following code to set up the device

/*
lab2.ino
AT&T DevLab pushbutton demo
*/
#include <aJSON.h>

#include "SPI.h"
#include "WiFi.h"

#include "M2XStreamClient.h"
char ssid[] = "MiCrOn"; // your network SSID (name)
char pass[] = "Welcome!"; // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;

// your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;


char deviceId[] = "50b506c6158882fed5c7e236e745df7a"; // Feed you want to post to
char m2xKey[] = "0fbeeec04ee38a8b1e3997e974d97a49"; // Your M2X access key
char streamName[] = "presstime"; // Stream you want to post to
WiFiClient client;
M2XStreamClient m2xClient(&client, m2xKey);
int btn1 = 1; // The button state
boolean pushed = false; // True when the button is pushed
int whenPushed = 0; // The time in milliseconds from when the button is pushed.
void setup() {
Serial.begin(9600);
pinMode(PUSH1, INPUT_PULLUP);
// attempt to connect to Wifi network:
Serial.print("Attempting to connect to Network named: ");
// print the network name (SSID);
Serial.println(ssid);

// Connect to

WPA/WPA2 network. Change this line if using open or WEP network:

WiFi.begin(ssid, pass);
while ( WiFi.status() != WL_CONNECTED) {
// print dots while we wait to connect
Serial.print(".");
delay(300);
}
Serial.println("\nYou're connected to the network");
Serial.println("Waiting for an ip address");
while (WiFi.localIP() == INADDR_NONE) {
// print dots while we wait for an ip addresss
Serial.print(".");
delay(300);
}
Serial.println("\nIP Address obtained");
// you're connected now, so print out the status
printWifiStatus();
}
void loop() {
// Read the pushbutton state. 1 for not pushed, 0 for pushed.
btn1 = digitalRead(PUSH1);
if (btn1 == 0 && !pushed) {
// If pushed, then store the time
pushed = true;
whenPushed = millis();
} else if (btn1 == 1 && pushed) {

10

// Reset pushed
pushed = false;
// Released. Calculate the time elapsed
double seconds = (millis() - whenPushed) / 1000.0;
Serial.print("Seconds pushed: ");
Serial.println(seconds);
// Send to M2X
int response = m2xClient.updateStreamValue(deviceId, streamName, seconds);
Serial.print("M2X client response code: ");
Serial.println(response);
// If the response is an error, then send into infinite loop to stop loop
if (response == -1)
while (1)
;
}
}
void printWifiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your WiFi shield's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
}
/*This will set the device up*/

11

From the File menu, select Upload. (Or click the Upload button. ) This
will upload the code to the device and run it. This will take a couple of minutes.
When it is done, you will see text at the bottom of the window that says Done
uploading and Success.

From the Tools menu, select Serial Monitor to check if the board is
connected to the network.

12

Position the board so that the writing is right-side-up and the micro-USB cord
is away from you. Youll see two pushbuttons on the side closest to you. Quickly
press the one on the left.

Return to the M2X website. The first point should have appeared on your
graph, indicating how long the button press lasted. Try it again, holding the
button down longer and watch as the data appears. It takes 5 to 10 seconds for
the new data to appear in the graph.

13

SETTING UP A SERVER TO HANDLE TRIGGERS


Lets take an example of a door in a controlled environment that should stay
open only for a certain amount of time. In addition to collecting data every time
the door is open, we also want to be notified every time the door is opened for
more than 5 seconds, since this requires taking immediate action. We can set up
a trigger to do this, which will make a POST request to a URL. Ultimately, we
want to do something like have the POST request result in sending a text
message so that we are informed wherever we are.
First, we need to set up a server URL to receive the notification. We can do this
by using a site called RequestBin, which allows you to set up URLs for testing
purposes. Follow these steps:

In a new browser tab or window, navigate to http://requestb.in/

Click on Create a RequestBin.

This will create a URL that we can use when creating a trigger. Save the
page so to copy and paste the URL.

14

Setting up a trigger
Now that we have a place to receive the trigger POST, lets set up the trigger.
Use the following steps to create a trigger for the condition.
In your browser, open your Device page in another tab or browser and
click the Trigger tab. Then click Add Trigger.

For the Trigger Name, type open door. For the Stream, choose
Seconds Pressed. For the Condition, choose > is greater than. For the
threshold value, type 5. For the Callback URL, copy and paste the URL from
the RequestBin page. Click Save.

15

Using a trigger
Press the button for more than 5 seconds. Check your RequestBin website
and refresh it by clicking on the circle next to your URL, in the top right corner of
the page.

You will see the data that was posted to the URL, which will take the
following form. As you can see, it contains the device ID, the stream name, the
trigger name, the condition and threshold, as well as the value that crossed the
threshold and its timestamp. If this were a real server that it was posting data to,
you could parse the incoming data and take action.
{"trigger":"open door","timestamp":"2016-0215T21:05:31.454Z","event":"fired","device":{"id":"c656bd781d367d3
517e4f 0aa2d64b8c8","name":"MPS432
Launchpad","serial":null},"conditions":{"presstime":{"gt":5.0}},"
values ":{"presstime":{"value":6.15,"timestamp":"2016-0215T21:05:31.454Z","unit":"s or
"}},"timeframe":0,"custom_data":null}

16

USING THE FLOW DESIGNER


Projects contain the flows that together make your application. Let's start by creating
your first project:
Navigate to https://flow.att.com/
Click Login. As long as you are signed in with M2X, you will be signed into Flow
Designer. (If not, use your M2X username and password.) If this is the first time
youve logged into Flow Designer, a new Flow Designer account will be created for
you.
Click the + button to create a new project.

Give the project a name and description.

17

Navigate to the inputs to write the code.

To respond to the button trigger in M2X, the flow will look like this

18

The input HTTP node should be modified to POST the presstime.

Click on the Deploy button and wait for it to finish.

Look for the HTTPS endpoint


the right side.

field and click on the Copy button on

Copy the HTTPS URL and paste it onto the Callback URL in the M2X device.
The device has been setup to detect the parameters and trigger warnings if
there are any outliers

19

ESTIMATING THE PARAMATERS


Now that we have set the device to detect the parameters and trigger warnings, we can
use Ridge Regression to estimate the performance of the system. This would be
especially useful in complex projects such as smart cities where all the parameters
cannot be monitored at every point of time. To do the analysis, we need to first extract
the data from the M2X device in CSV format.

Using the extracted CSV file, we can use Graphlab by DATO to estimate and visualize
the data. Coding in python, this is the algorithm I used:
import graphlab
sales = graphlab.SFrame('presstime.gl/')
import numpy as np # note this allows us to refer to numpy as np instead
def get_numpy_data(data_sframe, features, output):
data_sframe['constant'] = 1 # this is how you add a constant column to an SFrame
# add the column 'constant' to the front of the features list so that we can extract it along
with the others:

20

features = ['constant'] + features # this is how you combine two lists


# select the columns of data_SFrame given by the features list into the SFrame
features_sframe (now including constant):

features_sframe = data_sframe[features]
# the following line will convert the features_SFrame into a numpy matrix:
feature_matrix = features_sframe.to_numpy()
# assign the column of data_sframe associated with the output to the SArray output_sarray
output_sarray = data_sframe['times pressed']
# the following will convert the SArray into a numpy array by first converting it to a list
output_array = output_sarray.to_numpy()
return(feature_matrix, output_array)
def predict_output(feature_matrix, weights):
# assume feature_matrix is a numpy matrix containing the features as columns and weights is
a corresponding numpy array
# create the predictions vector by using np.dot()
predictions = np.dot(feature_matrix, weights)
return(predictions)
def feature_derivative_ridge(errors, feature, weight, l2_penalty, feature_is_constant):
# If feature_is_constant is True, derivative is twice the dot product of errors and feature
if (feature_is_constant == True):
derivative = 2 * np.dot(errors, feature)
# Otherwise, derivative is twice the dot product plus 2*l2_penalty*weight

21

else:
derivative = 2 * (np.dot(errors, feature) + l2_penalty * weight)
return derivative
(example_features, example_output) = get_numpy_data(seconds, ['trigger'], 'times pressed')
my_weights = np.array([1., 10.])
test_predictions = predict_output(example_features, my_weights)
errors = test_predictions - example_output # prediction errors

# next two lines should print the same values


print feature_derivative_ridge(errors, example_features[:,1], my_weights[1], 1, False)
print np.sum(errors*example_features[:,1])*2+20.
print ''

# next two lines should print the same values


print feature_derivative_ridge(errors, example_features[:,0], my_weights[0], 1, True)
print np.sum(errors)*2.

def ridge_regression_gradient_descent(feature_matrix, output, initial_weights, step_size, l2_penalty,


max_iterations=100):
weights = np.array(initial_weights) # make sure it's a numpy array

22

iterations = 0
#while not reached maximum number of iterations:
while (iterations < max_iterations):
# compute the predictions based on feature_matrix and weights using your
predict_output() function
predictions = predict_output(feature_matrix, weights)
# compute the errors as predictions - output
errors = predictions - output
for i in xrange(len(weights)): # loop over each weight
# Recall that feature_matrix[:,i] is the feature column associated with weights[i]
# compute the derivative for weight[i].
#(Remember: when i=0, you are computing the derivative of the constant!)
if i == 0:
derivative_weight = feature_derivative_ridge(errors, feature_matrix[:,i], weights[i],
l2_penalty, True)

else:
derivative_weight = feature_derivative_ridge(errors, feature_matrix[:,i], weights[i],
l2_penalty, False)
# subtract the step size times the derivative from the current weight
weights[i] = weights[i] - (step_size * derivative_weight)

iterations += 1

23

return weights
simple_features = ['trigger']
my_output = 'time_pressed'
train_data,test_data = sales.random_split(.8,seed=0)
(simple_feature_matrix, output) = get_numpy_data(train_data, simple_features, my_output)
(simple_test_feature_matrix, test_output) = get_numpy_data(test_data, simple_features, my_output)
initial_weights = np.array([0., 0.])
step_size = 1e-12
max_iterations=1000
simple_weights_0_penalty = ridge_regression_gradient_descent(simple_feature_matrix, output,
initial_weights, step_size, 0, max_iterations)
print simple_weights_0_penalty

simple_weights_high_penalty = ridge_regression_gradient_descent(simple_feature_matrix, output,


initial_weights, step_size, 1e11, max_iterations)
print simple_weights_high_penalty
import matplotlib.pyplot as plt
%matplotlib inline
plt.plot(simple_feature_matrix,output,'k.',
simple_feature_matrix,predict_output(simple_feature_matrix, simple_weights_0_penalty),'b-',
simple_feature_matrix,predict_output(simple_feature_matrix, simple_weights_high_penalty),'r')

24

predictions_initial =

predict_output(simple_test_feature_matrix, initial_weights)

residuals = test_output - predictions_initial


rss = (residuals ** 2).sum()
print rss
predictions_weights_0_penalty = predict_output(simple_test_feature_matrix,
simple_weights_0_penalty)
residuals = test_output - predictions_weights_0_penalty
rss = (residuals ** 2).sum()
print rss, "%.1f" % predictions_weights_0_penalty[0]
predictions_weights_high_penalty = predict_output(simple_test_feature_matrix,
simple_weights_high_penalty)
residuals = test_output - predictions_weights_high_penalty
rss = (residuals ** 2).sum()
print rss, "%.1f" % predictions_weights_high_penalty[0]
model_features = ['seconds', 'average_presstime] # average_presstime is the average presstime
for the nearest 15 neighbors.
my_output = 'times_pressed'
(feature_matrix, output) = get_numpy_data(train_data, model_features, my_output)
(test_feature_matrix, test_output) = get_numpy_data(test_data, model_features, my_output)
initial_weights = np.array([0.0,0.0,0.0])
step_size = 1e-12
max_iterations = 1000

25

multiple_weights_0_penalty =
ridge_regression_gradient_descent(feature_matrix, output, initial_weights, step_size, 0.0,
max_iterations)
print multiple_weights_0_penalty
multiple_weights_high_penalty = ridge_regression_gradient_descent(feature_matrix, output,
initial_weights, step_size, 1e11, max_iterations)
print multiple_weights_high_penalty

predictions_initial = predict_output(test_feature_matrix, initial_weights)


print test_output[0] - predictions_initial[0]
residuals = test_output - predictions_initial
rss = (residuals ** 2).sum()
print rss
predictions_multiple_weights_0_penalty = predict_output(test_feature_matrix,
multiple_weights_0_penalty)
print predictions_multiple_weights_0_penalty[0]
residuals = test_output - predictions_multiple_weights_0_penalty
rss = (residuals ** 2).sum()
print rss

predictions_multiple_weights_high_penalty = predict_output(test_feature_matrix,
multiple_weights_high_penalty)

26

print

predictions_multiple_weights_high_penalty[0]

residuals = test_output - predictions_multiple_weights_high_penalty


rss = (residuals ** 2).sum()
print rss

#End code

Here, I have plotted a graph to predict outputs of presstime based on the current
dataset with different stepsizes and the RSS associated with it is estimated and the
times pressed vs the featers graph is visualized:

27

28

FUTURE WORK
This project is an MVP for my passion to integrate IoT, Analytics and Behavioral
sciences. By using the principles of lean methodologies, my next focus is on creating
an SaaS (software as a service) delivery model with mobile capabilities(as an app) that
is a culmination layer that combines lifestyle tools, health tools with work tools to
create a work-life balance for employees. In short, a solution that provides real time
insights by regressing data obtained from various IoT devices on dimensions having a
strong correlation with a holistic lifestyle.

You might also like