This past few months have been heavily focused on SAP HANA and Internet of Things (IoT) for me and the SAP Developer Relations team. The result from Las Vegas, Berlin and just last week at the ThingMonk 2014 event in London is a nice little collection of code making up a new example application that will be present in the next version of the SAP HANA Developer Edition (SPS9) in the next weeks. Ideally this project will be embedded in the next HANA Dev Edition but also available on GitHub in the next weeks.
The goal of this example is to show how easily one can read data from an external hardware device with a sensor such as temperature sensor and store, visualize and access the data via a SAP HANA XS application.
- Hardware such as Raspberry Pi, Beagle Bone, and Tessel
- Circuit
- Some code for hardware devices using Bonescript, Python and Javascript
This example application also allows for display of the values entered via those devices.
- Dynamic Chart of current postings
- Line chart of all data
- Heat map of all data
No example is complete without showing the complete "round trip", this example also provides the ability to retrieve values from SAP HANA and use them in the hardware side.
- Control value from server
- Complete Round Trip
Hardware
Below you will find example code for posting to this application from different hardware devices. 3 That we have focused on are:
Circuit

Creating the circuit on the breadboard is extremely simply.
- Connect a black jumper wire to the GND
- Connect a red jumper wire to the 3.3 V
- Place an LED in the breadboard
- Place a 220 Ohm Resister from GND to the short leg of the LED
- Place a jumper wire from the long leg of the LED to the GPIO pin 18
- Repeat the process for the second LED and connect to GPIO pin 22
- Place the digital temperature sensor on the bread board, we are using DS18B20
- From the "left" leg of the sensor we run a black jumper wire to GND
- From the "right" leg of the sensor we run a red jumper wire to 3.3v
- From the "center" leg of the sensor we run a jumper wire to the GPIO pin 16
- Between the "right" and "center" legs we place a 4.7K Ohm resistor
Coding
Basically any type of hardware device that can do a JSON based HTTP post can submit data to the server using Content-Type": "application/json".
var jsonData = { "ID": 1, "SNAME": "Tessel", "STYPE": "Temp", "SVALUE": ""+temp+"", "TDATE": "/Date("+timeStamp+")/" }
Python for the Raspberry Pi
import os
import glob
import json
import urllib2
import time
import RPi.GPIO as GPIO
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'
hanaposts = 0
hanaposts2 = 0
# to use Raspberry Pi board pin numbers
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
# set up GPIO output channel
GPIO.setup(18, GPIO.OUT)
GPIO.setup(22, GPIO.OUT)
def blink(pin):
GPIO.output(pin,GPIO.HIGH)
time.sleep(1)
GPIO.output(pin,GPIO.LOW)
time.sleep(1)
return
def basic_authorization(user, password):
s = user + ":" + password
return "Basic " + s.encode("base64").rstrip()
def read_temp_raw():
f = open(device_file, 'r')
lines = f.readlines()
f.close()
return lines
def read_temp():
lines = read_temp_raw()
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = read_temp_raw()
equals_pos = lines[1].find('t=')
if equals_pos != -1:
temp_string = lines[1][equals_pos+2:]
temp_c = float(temp_string) / 1000.0
temp_f = temp_c * 9.0 / 5.0 + 32.0
return temp_c
while True:
hanaposts += 1
txtTemp = read_temp()
txtDate = '/Date(' + str(int(time.time())) + ')/'
url = 'http://[SERVER IP]:[SERVER PORT]/sap/devs/iot/services/iot_input.xsodata/sensor'
params = {"ID": "1", "TDATE": txtDate, "SVALUE": str(txtTemp), "SNAME": "Craig", "STYPE": "Temp" }
req = urllib2.Request(url,
headers = {
"Authorization": basic_authorization('[USER]', '[PASSWORD]'),
"Content-Type": "application/json",
"Accept": "*/*",
}, data = json.dumps(params))
f = urllib2.urlopen(req)
# LED
if hanaposts == 25:
hanaposts = 0
hanaposts2 += 1
blink(22)
if hanaposts2 == 50:
hanaposts2 = 0
blink(18)
time.sleep(1)
Bonescript for the Beagle Bone
var b = require('bonescript'); var temperatureSensor = "P9_40" setInterval(readTemperature, 1000); function readTemperature() { b.analogRead(temperatureSensor, writeTemperature); } // The MCP9700A provides 500mV at 0C and 10mV/C change. function writeTemperature(x) { //console.log("temp value: "+x.value); var millivolts = x.value * 3300; // Only outputs 1.8v, so must adjust accordingly var temp_c = (millivolts - 500) / 100; var temp_f = (temp_c * 9 / 5) + 32; //console.log("Millivolts: " + millivolts + ", temp_c: " + temp_c + ", temp_f: " + temp_f); var timeStamp = new Date().getTime(); //console.log(new Date()); writeToScreen(temp_c); writeToHana(temp_c,timeStamp); } function writeToHana(temp, timeStamp) { var http = require('http'); var options = { host: '[SERVER IP]', port: [SERVER PORT], path: '/sap/devs/iot/services/iot_input.xsodata/sensor', method: 'POST', headers: { 'Authorization': '[AUTH STRING]' , 'Content-Type':'application/json' } }; var req = http.request(options, function(res) { res.setEncoding('utf-8'); var responseString = ''; res.on('data', function(data) { responseString += data; // Do something when a value is there //console.log("Response: " + responseString); }); res.on('end', function() { //var resultObject = JSON.parse(responseString); }); }); req.on('error', function(e) { console.log("error found"); console.error(e); }); var jsonData = { "ID": 1, "SNAME": "Craig", "STYPE": "Temp", "SVALUE": ""+temp+"", "TDATE": "/Date("+timeStamp+")/" } var strData = JSON.stringify(jsonData); //console.log(strData); req.write(strData); req.end(); }
Javascript for the Tessel
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/publicdomain/zero/1.0/
/*********************************************
This basic climate example logs a stream
of temperature and humidity to the console.
*********************************************/
var tessel = require('tessel');
// if you're using a si7020 replace this lib with climate-si7020
var climatelib = require('climate-si7020');
var climate = climatelib.use(tessel.port['A']);
climate.on('ready', function () {
console.log('Connected to si7020');
// Loop forever
setImmediate(function loop () {
climate.readTemperature('c', function (err, temp) {
climate.readHumidity(function (err, humid) {
console.log('Degrees:', temp.toFixed(4) + 'C', 'Humidity:', humid.toFixed(4) + '%RH');
var timeStamp = new Date().getTime();
writeToHana(temp.toFixed(4),timeStamp);
setTimeout(loop, 1000);
});
});
});
});
climate.on('error', function(err) {
console.log('error connecting module', err);
});
function writeToHana(temp, timeStamp) {
var http = require('http');
var options = {
host: '[SERVER IP]',
port: [SERVER PORT],
path: '/sap/devs/iot/services/iot_input.xsodata/sensor',
method: 'POST',
headers: {
'Authorization': '[AUTH STRING]' ,
'Content-Type':'application/json'
}
};
var req = http.request(options, function(res) {
res.setEncoding('utf-8');
var responseString = '';
res.on('data', function(data) {
responseString += data;
// Do something when a value is there
//console.log("Response: " + responseString);
});
res.on('end', function() {
//var resultObject = JSON.parse(responseString);
});
});
req.on('error', function(e) {
console.log("error found");
console.error(e);
});
var jsonData = {
"ID": 1,
"SNAME": "Tessel",
"STYPE": "Temp",
"SVALUE": ""+temp+"",
"TDATE": "/Date("+timeStamp+")/"
}
var strData = JSON.stringify(jsonData);
//console.log(strData);
req.write(strData);
req.end();
}
Control Values
Using an HTTP GET using Content-Type": "application/json" we can retrieve values from our "control" table.
Python for the Raspberry Pi
import RPi.GPIO as GPIO
import time
import urllib2
import json
# convert string to number
def num(s):
try:
return int(s)
except ValueError:
return float(s)
# blinking function
def blink(pin):
GPIO.output(pin,GPIO.HIGH)
time.sleep(1)
GPIO.output(pin,GPIO.LOW)
time.sleep(1)
return
# Get values from server
def getServerResponse(url):
req = urllib2.Request(url)
opener = urllib2.build_opener()
f = opener.open(req)
return json.loads(f.read())
###### Initialize Program ######
# surpress warnings
GPIO.setwarnings(False)
# to use Raspberry Pi board pin numbers
GPIO.setmode(GPIO.BOARD)
# set up GPIO output channel
GPIO.setup(18, GPIO.OUT)
GPIO.setup(16, GPIO.OUT)
GPIO.setup(22, GPIO.OUT)
# fetch control variables
jsonStr = getServerResponse("http://[SERVER IP]/sap/devs/iot/services/iot_control.xsodata/control?$format=json&$filter=SCONTROL%20eq%20%27HOT%27")
hotTemp = jsonStr['d']['results'][0]['SVALUE']
jsonStr = getServerResponse("http://[SERVER IP]/sap/devs/iot/services/iot_control.xsodata/control?$format=json&$filter=SCONTROL%20eq%20%27COLD%27")
coldTemp = jsonStr['d']['results'][0]['SVALUE']
# Now loop and check for action
while True:
jsonStr = getServerResponse("http://[SERVER IP]/sap/devs/iot/services/iot.xsodata/IOT?$orderby=ID%20desc&$top=1&$select=SVALUE&$filter=SNAME%20eq%20%27Ian%27&$format=json")
currentTemp = jsonStr['d']['results'][0]['SVALUE']
if num(currentTemp) < num(coldTemp):
print "Under, " + currentTemp + " is less than " + coldTemp
for i in range(0,50):
blink(18)
else:
if num(currentTemp) > num(hotTemp):
print "Over, " + currentTemp + " is more than " + hotTemp
for i in range(0,50):
blink(22)
else:
print "Within range"
time.sleep(5)
GPIO.cleanup()
Round Trip
Using an HTTP GET using Content-Type": "application/json" we can retrieve values from our "control" table.
This round trip uses a fan, fan and "led" as a heater. The fan is a small 4V fan using the 5V power and a transistor on board. The idea here is that when the fan reaches the "HOT" value from the control table the program would start the fan to cool it back down and when it reaches the "COLD" value the "heater" would start to heat of the environment.
Python for the Raspberry Pi
import os
import glob
import json
import urllib2
import time
import RPi.GPIO as GPIO
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'
maxtemp = 0
mintemp = 0
# to use Raspberry Pi board pin numbers
GPIO.setmode(GPIO.BOARD)
# set up GPIO output channel
GPIO.setup(12, GPIO.OUT)
GPIO.setup(13, GPIO.OUT)
GPIO.setup(15, GPIO.OUT)
GPIO.setup(16, GPIO.OUT)
GPIO.setup(18, GPIO.OUT)
def blink(pin):
GPIO.output(pin, GPIO.HIGH)
time.sleep(0.5)
GPIO.output(pin, GPIO.LOW)
time.sleep(0.5)
return
def temp_low():
GPIO.output(12, GPIO.HIGH)
GPIO.output(13, GPIO.LOW)
GPIO.output(15, GPIO.HIGH)
GPIO.output(16, GPIO.LOW)
return
def temp_high():
GPIO.output(12, GPIO.LOW)
GPIO.output(13, GPIO.HIGH)
GPIO.output(15, GPIO.HIGH)
GPIO.output(16, GPIO.LOW)
return
def temp_ok():
GPIO.output(12, GPIO.LOW)
GPIO.output(13, GPIO.LOW)
GPIO.output(15, GPIO.LOW)
GPIO.output(16, GPIO.HIGH)
return
# Get values from server
def getServerResponse(url):
req = urllib2.Request(url)
opener = urllib2.build_opener()
f = opener.open(req)
return json.loads(f.read())
def basic_authorization(user, password):
s = user + ":" + password
return "Basic " + s.encode("base64").rstrip()
def read_temp_raw():
f = open(device_file, 'r')
lines = f.readlines()
f.close()
return lines
def read_temp():
lines = read_temp_raw()
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = read_temp_raw()
equals_pos = lines[1].find('t=')
if equals_pos != -1:
temp_string = lines[1][equals_pos+2:]
temp_c = float(temp_string) / 1000.0
temp_f = temp_c * 9.0 / 5.0 + 32.0
return temp_c
jsonStr = getServerResponse("http://[SERVER IP]/sap/devs/iot/services/iot_control.xsodata/control?$format=json&$filter=SCONTROL%20eq%20%27COLD%27")
mintemp = jsonStr['d']['results'][0]['SVALUE']
print ('MIN Temp is set at ' + mintemp + 'c')
jsonStr = getServerResponse("http://[SERVER IP]/sap/devs/iot/services/iot_control.xsodata/control?$format=json&$filter=SCONTROL%20eq%20%27HOT%27")
maxtemp = jsonStr['d']['results'][0]['SVALUE']
print ('MAX Temp is set at ' + maxtemp + 'c')
while True:
# Value of Sensor
txtTemp = read_temp()
# Timestamp
txtDate = '/Date(' + str(int(time.time())) + ')/'
# HTTP Post to HANA
url = 'http://[SERVER IP]/sap/devs/iot/services/iot_input.xsodata/sensor'
params = {"ID": "1", "TDATE": txtDate, "SVALUE": str(txtTemp), "SNAME": "Ian", "STYPE": "Temp" }
# print(params)
req = urllib2.Request(url,
headers = {
"Authorization": basic_authorization('[USER]', '[PASSWORD]'),
"Content-Type": "application/json",
"Accept": "*/*",
}, data = json.dumps(params))
f = urllib2.urlopen(req)
blink(18)
# fetch the url
# url2 = "http://[SERVER IP]/sap/devs/iot/services/iot.xsodata/IOT?$orderby=ID%20desc&$top=1&$select=SVALUE&$filter=SNAME%20eq%20%27Ian%27&$format=json"
# req2 = urllib2.Request(url2)
# opener2 = urllib2.build_opener()
# f2 = opener2.open(req2)
# json2 = json.loads(f2.read())
# currtemp = json2['d']['results'][0]['SVALUE']
jsonStr = getServerResponse("http://[SERVER IP]/sap/devs/iot/services/iot.xsodata/IOT?$orderby=ID%20desc&$top=1&$select=SVALUE&$filter=SNAME%20eq%20%27Ian%27&$format=json")
currtemp = jsonStr['d']['results'][0]['SVALUE']
#print currtemp
if (float(currtemp) <= float(maxtemp)):
if (float(currtemp) < float(mintemp)):
print ('>>> HEATER ON ' + currtemp + "c lower than MIN temp of " + str(mintemp) + "c")
temp_low()
else:
print ('HEATER/FAN OFF ' + currtemp + "c within bounds")
temp_ok()
else:
print ('>>> FAN ON ' + currtemp + "c exceeds MAX temp of " + str(maxtemp) + "c")
temp_high()
# Loop to next reading
time.sleep(3)
** Be sure on your spacing for your code, for some reason formatting here is horrid!!