Fish with OData

Published by Tobias Hofmann on

5 min read

Rui Nogueira published a while back a blog series on SCN on how to implement an IoT scenario using a Raspberry Pi and HCP. I think the example shows very well how what the main use case of IoT is. When the blog was published, there was no SAP HCP IoT service available; if you want to implement the same example in a more correct way, you should use HCP IoT. Nevertheless, Rui`s example is easy to implement and shows how the different parts play together: client, server, user.

When I first came across Rui`s blog I noticed that he uses REST and goes through some effort to persist the data. I thought that it would be nice to adopt this to make use of OData. Took me some while to publish this blog J In the end, I did not adjusted his code, it merely served as an orientation. I wrote my own IoT server and client app. The result is a simple, clean and easy to read JEE app that uses JPA and Olingo for exposing the JPA entities and a Java client that does not need to be run on an IoT device. My user dashboard is very simple, implemented in D3.js, and only shows one sensor`s measurement data.

The client is a Java app that reads current weather data from openweathermap.org. To make this work, you`ll need an API key (free). In case you do not want this, I added a jMeter test that creates random temperature data (as seen in above picture). JMeter test file is located here: fish-with-odata\iotserver\test\jmeter\LoadData.jmx. The test is pre-configured to use localhost and port 7080. The test will run for 3 minutes as the 100 measurements are not created at once, but with a fixed time interval of 3 seconds.

The app

The source code can be found on GitHub: https://github.com/tobiashofmann/fish-with-odata

You will find two folders:

  • iotclient, containing the client app
  • iotserver, containing the server and user dashboard

Both are maven projects. It should not be a problem to transform them into Eclipse projects via mvn eclipse:eclipse, but while I developed both in Eclipse, I did not test transforming to an Eclipse project from maven. Sensor and Measurements are implemented using JPA. The relationship between both is that one sensor can have many measurement assigned, but a measurement can only be assigned to one sensor. In the Snesor class, this is done via @OneToMany

Sensor class

@Entity(name = "Sensor")
public
 class Sensor implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
     @Column(name = "ID")
     private long id;
     private String device;
     private String type;
     private String description;
     @OneToMany(mappedBy = "sensor", cascade = CascadeType.ALL)
     private List<Measurement> employees = new ArrayList<Measurement>();

Measurement class

@Entity(name = "Measurement")
public
 class Measurement implements Serializable {
     @Id
     @GeneratedValue(strategy = GenerationType.TABLE)
     @Column(name = "ID")
     private Long id;
     private String unit;
     @Temporal(TemporalType.TIMESTAMP)
     @Column(insertable = true, updatable = false)
     private Date createdAt;
     @Temporal(TemporalType.TIMESTAMP)
     @Column(insertable = false, updatable = true)
     private Date updatedAt;
     private Double value;
     @ManyToOne
     @JoinColumn(name = "SID", referencedColumnName = "ID")
     private Sensor sensor;

I am lazy so I let JPA decide when a measurement is created or updated. This may not be acceptable in most scenarios, especially when you depend on the exact time when the data was captured by the device and not when it was persisted in the DB. I implemented it that way to not have to take care of capturing the date in my client app and to keep the payload low.

Run server

To run the server:

mvn clean pre-integration-test

This will download the HCP SDK, install the server, run it on port 7080 and deploy the WAR file. After some while, the IoT server is ready.

A benefit of OData can be seen when comparing how Rui is consulting the latest added measurement for a sensor: he adds the latest measurement as an object to the sensor.

private Measurement lastMeasurement;

With OData, the latest added measurement for a sensor can be retrieved by simply adding some parameters to the URL:

$top parameter controls how many data points are returned. Beware that with OData, there is a page size defined that limits the max number of requests returned. This parameter is configurable in the class de.tobias.service.ODataSampleJPAServiceFactory

private static final int PAGE_SIZE = 50;
Assign any value to PAGE_SIZE you consider useful.

Run client

To run the client, you first must add your API key. This is done in the class de.itsfullofstars.iot. WeatherData. Add your API to APPID.

private static final String APPID = “YOUR API KEY”;

To run the client, create the jar:

mvn package
java –jar target\fishodataclient-1.0.0.jar

As an alternative, a jMeter test is included in the server: fish-with-odata\iotserver\test\jmeter\ LoadData.jmx

The final chart can be seen by accessing: http://localhost:7080/iotserver/. Depending on what data source you use, the chart will look like a flat line or like a heart attack.

Real data (Rio de Janeiro)

Fake data

Let the world know

Tobias Hofmann

Doing stuff with SAP since 1998. Open, web, UX, cloud. I am not a Basis guy, but very knowledgeable about Basis stuff, as it's the foundation of everything I do (DevOps). Performance is king, and unit tests is something I actually do. Developing HTML5 apps when HTML5 wasn't around. HCP/SCP user since 2012, NetWeaver since 2002, ABAP since 1998.

1 Comment

PUNEET JAIN · September 23, 2017 at 03:55

are you able to fix adding new measurements to existing Sensor ?
what will be odata url for it

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.