Skip to Content

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.

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.

Hardware

Below you will find example code for posting to this application from different hardware devices. 3 That we have focused on are:

  • Raspberry Pi Model B

    /wp-content/uploads/2014/12/rpi_603762.jpg

  • Beagle Bone Black

    /wp-content/uploads/2014/12/bbb_603763.jpg

  • Tessel

    Tessel.png

Circuit

/wp-content/uploads/2014/12/led_temp_603765.png

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.

/wp-content/uploads/2014/12/round_trip_603791.png

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!!

To report this post you need to login first.

6 Comments

You must be Logged on to comment or reply to a post.

  1. Ajay Nayak

    Hello Craig,

    Good Article , here in india some of my friends have tried Raspberry pie with Node.js and they say it is lot less complicated that way , as i am also working in SAP UI5 and other open source JavaScript  technology would you agree that it would be better if we have a common standard like javascript only .

    Also what would be good business use cases with these.

    -Ajay

    (0) 
    1. Craig Cmehil Post author

      With everything you have options, my opinion you use the ones that fit your skill set or business case best. As for business cases – there are tons of them!

      (0) 
  2. Zoltan Desztics

    Hi Craig,

    Excellent article! Let me ask you: in case of the BBB, what has to be done to be able to use HTTPS \ which authentication method is the preferred one?

    (0) 

Leave a Reply