-
Notifications
You must be signed in to change notification settings - Fork 1
9. Developing symbIoTe enabled apps
This tutorial covers the development of symbIoTe-compliant web apps. It provides hands-on examples for application developers showing how to query resources in the symbIoTe core, gathering information on sensors and finally retrieving data from specific sensors.
This tutorial uses Python 3.6 as example, though the code given can easily be extended to other platforms as well.
While other symbIoTe core servers are available, this tutorial references the open server available at http://symbiote-open.man.poznan.pl. For the sake of readability, we subsequently reference this server as "symbIoTe core". symbIoTe core is essentially a registry for available sensor data, where sensors are references as "resources" subsequently. Please note, that symbIoTe core does not store actual sensor data (e.g. temperature sensor readings) but only meta-data on the sensors itself.
In this tutorial, you will learn to:
- Perform authentication against symbIoTe core
- Perform queries for (public) resources on symbIoTe core
- Fetch data from this resource using the reverse access proxy
The easiest way to perform authentication, is to acquire a guest security token from symbIoTe core and to build a so-called security header afterwards. First we acquire the guest token, by placing a HTTP-POST request at following end-point:
import time
import json
import requests
_response = requests.post("https://symbiote-open.man.poznan.pl/coreInterface/aam/get_guest_token")_
_x_auth_token = response.headers["x-auth-token"]_
As you can see, the guest token can be retrieved from the HTTP response headers. Using this token we are now ready to build the full HTTP security header:
x_auth = {
"token" : x_auth_token,
"authenticationChallenge":"",
"clientCertificate":"",
"clientCertificateSigningAAMCertificate":"",
"foreignTokenIssuingAAMCertificate":""
}
security_header = {
"x-auth-timestamp" : str(int(round(time.time()*1000))),
"x-auth-size" : "1",
"x-auth-1" : json.dumps(x_auth_1)
}
We are now ready to perform queries for resources at symbIoTe core.
The endpoint for querying resources at symbIoTe core is https://symbiote-open.man.poznan.pl/coreInterface/query. It accepts a couple of HTTP GET parameters as query parameters:
- platform_id (String)
- platform_name (String)
- owner (String)
- name (String)
- id (String)
- description (String)
- location_name (String)
- location_lat (Double)
- location_long (Double)
- max_distance (Integer)
- observed_property (List of Strings)
- resource_type (String)
- should_rank (Boolean)
location_lat, location_long and max_distance provide end-users with the opportunity to search for resources geographically. should_rank is enabled by default and ranks the search results by a ranking score with the highest score representing the closest match to the query.
In order to perform the query, the HTTP security headers created before, needs to be passed to the query:
response = requests.get("https://symbiote-open.man.poznan.pl/coreInterface/query",headers=security_header)
symbIoTe core returns all resources matching the query in JSON format:
{
"resources" : [
{
"platformId" : "test1Plat",
"platformName" : "Test 1 Plat",
"owner" : null,
"name" : "Statonary1",
"id" : "591ae23eb80b283c012fdf26",
"description" : "This is statonary 1",
"locationName" : "Any city",
"locationLatitude" : 25.864716,
"locationLongitute" : 5.349014,
"locationAltitude" : 35,
"observedProperties" : ["temperature","humidity"],
"resourceType" : ["http://www.symbiote-h2020.eu/ontology/core#StationarySensor"],
"ranking" : 0.2
}
]
}
As said earlier, symbIoTe core does not store any sensor data. These need to be retrieved a so-called reverse-access-proxy (RAP). The RAP URL can be acquired using following endpoint:
import requests
response = requests.get("https://symbiote-open.man.poznan.pl/coreInterface/resourceUrls?id=591ae23eb80b283c012fdf26",header=security_header)
As you can see, we retrieve the RAP URL using the official symbIoTe ID as returned by the query earlier. You can query several ids at once by separating them using a comma. This is what the response will look like:
{
"body" : { "https://enviro5.ait.ac.at/symbiote/rap/Sensors('591ae23eb80b283c012fdf26')" },
"message" : 'Success !',
"serviceResponse" : 'eyJHbGciiOiJFUzI1NiJ9.e',
"status" : 200
}
Now we are ready to actually retrieve the sensor values:
import requests
requests.get("https://enviro5.ait.ac.at/symbiote/rap/Sensors('591ae23eb80b283c012fdf26')",headers=security_headers)
The response will look like this:
[
{
"resourceId" : "591ae23eb80b283c012fdf26",
"location" : {
"@c" : ".WS84Location",
},
}
]
Java developers can make use of the AbstractSymbIoTeClientFactory provided in the symbIoTeLibraries version 5.21+. An example project making use of this factory can be found here. Below, we present 2 examples for L1 clients; one with home token acquisition and one with guest token. Both examples present the process of getting the necessary clients and query sequentially Core Search in order to find resources, CRAM in order to get the resource urls and finally RAP in order to get observations:
package eu.h2020.symbiote.client;
import eu.h2020.symbiote.client.interfaces.CRAMClient;
import eu.h2020.symbiote.client.interfaces.RAPClient;
import eu.h2020.symbiote.client.interfaces.SearchClient;
import eu.h2020.symbiote.core.ci.QueryResponse;
import eu.h2020.symbiote.core.internal.CoreQueryRequest;
import eu.h2020.symbiote.core.internal.cram.ResourceUrlsResponse;
import eu.h2020.symbiote.model.cim.Observation;
import eu.h2020.symbiote.security.commons.exceptions.custom.SecurityHandlerException;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import static eu.h2020.symbiote.client.AbstractSymbIoTeClientFactory.*;
public class ClientWithHomeToken {
public static void main(String[] args) {
/*
Get the factory and the component clients
*/
// FILL ME
// mandatory to run
String coreAddress = "https://symbiote-open.man.poznan.pl";
String keystorePath = "testKeystore";
String keystorePassword = "testKeystore";
String exampleHomePlatformIdentifier = "exampleHomePlatformIdentifier";
Type type = Type.FEIGN;
// Get the configuration
Config config = new Config(coreAddress, keystorePath, keystorePassword, type);
// Get the factory
AbstractSymbIoTeClientFactory factory;
try {
factory = getFactory(config);
// OPTIONAL section... needs to be run only once
// - per new platform
// and/or after revoking client certificate in an already initialized platform
// ATTENTION: This MUST be an interactive procedure to avoid persisting credentials (password)
// Here, you can add credentials FOR MORE THAN 1 platforms
Set<HomePlatformCredentials> platformCredentials = new HashSet<>();
// example credentials
String username = "userNameInHomePlatform";
String password = "passwordInHomePlatform";
String clientId = "exampleClientId";
HomePlatformCredentials exampleHomePlatformCredentials = new HomePlatformCredentials(
exampleHomePlatformIdentifier,
username,
password,
clientId);
platformCredentials.add(exampleHomePlatformCredentials);
// Get Certificates for the specified platforms
factory.initializeInHomePlatforms(platformCredentials);
// end of optional section..
// After running it the first time and creating the client keystore you should comment out this section.
} catch (SecurityHandlerException | NoSuchAlgorithmException e) {
e.printStackTrace();
return;
}
// Get the necessary component clients
SearchClient searchClient = factory.getSearchClient();
CRAMClient cramClient = factory.getCramClient();
RAPClient rapClient = factory.getRapClient();
// The set of platforms from which we are going to request credentials for our requests
Set<String> platformIds = new HashSet<>(Collections.singletonList(exampleHomePlatformIdentifier));
/*
Search for resources in Core
*/
// Create the request
// Here, we specify just one search criteria, which is the platform id. You can add more criteria, such as
// platform name, location, etc. You can check what the CoreQueryRequest.Builder supports
CoreQueryRequest coreQueryRequest = new CoreQueryRequest.Builder()
.platformId("fer1")
.build();
// Send the request and validate the Search response
QueryResponse queryResponse = searchClient.search(coreQueryRequest, true, platformIds);
/*
Ask CRAM for the specific resource url
*/
// Here, we request the url of only the first resource contained in the Search response. We also validate the
// CRAM response
String resourceId = queryResponse.getResources().get(0).getId();
ResourceUrlsResponse resourceUrlsResponse = cramClient.getResourceUrl(resourceId, true, platformIds);
String resourceUrl = resourceUrlsResponse.getBody().get(resourceId);
/*
Get observations from RAP
*/
// Here, we just request the latest observation from RAP
Observation observation = rapClient.getLatestObservation(resourceUrl, true, platformIds);
System.out.println(observation);
}
}
package eu.h2020.symbiote.client;
import eu.h2020.symbiote.client.interfaces.CRAMClient;
import eu.h2020.symbiote.client.interfaces.RAPClient;
import eu.h2020.symbiote.client.interfaces.SearchClient;
import eu.h2020.symbiote.core.ci.QueryResponse;
import eu.h2020.symbiote.core.internal.CoreQueryRequest;
import eu.h2020.symbiote.core.internal.cram.ResourceUrlsResponse;
import eu.h2020.symbiote.model.cim.Observation;
import eu.h2020.symbiote.security.commons.exceptions.custom.SecurityHandlerException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import static eu.h2020.symbiote.client.AbstractSymbIoTeClientFactory.*;
public class ClientWithGuestToken {
public static void main(String[] args) {
/*
Get the factory and the component clients
*/
// FILL ME
String coreAddress = "https://symbiote-open.man.poznan.pl";
String keystorePath = "testKeystore";
String keystorePassword = "testKeystore";
Type type = Type.FEIGN;
// Get the configuration
Config config = new Config(coreAddress, keystorePath, keystorePassword, type);
// Get the factory
AbstractSymbIoTeClientFactory factory;
try {
factory = getFactory(config);
} catch (SecurityHandlerException | NoSuchAlgorithmException e) {
e.printStackTrace();
return;
}
// Get the necessary component clients
SearchClient searchClient = factory.getSearchClient();
CRAMClient cramClient = factory.getCramClient();
RAPClient rapClient = factory.getRapClient();
/*
Search for resources in Core
*/
// Create the request
// Here, we specify just one search criteria, which is the platform id. You can add more criteria, such as
// platform name, location, etc. You can check what the CoreQueryRequest.Builder supports
CoreQueryRequest coreQueryRequest = new CoreQueryRequest.Builder()
.platformId("fer1")
.build();
// Send the request and validate the Search response
QueryResponse queryResponse = searchClient.searchAsGuest(coreQueryRequest, true);
/*
Ask CRAM for the specific resource url
*/
// Here, we request the url of only the first resource contained in the Search response. We also validate the
// CRAM response
String resourceId = queryResponse.getResources().get(2).getId();
ResourceUrlsResponse resourceUrlsResponse = cramClient.getResourceUrlAsGuest(resourceId, true);
String resourceUrl = resourceUrlsResponse.getBody().get(resourceId);
/*
Get observations from RAP
*/
// Here, we request the latest 10 observations from RAP
List<Observation> observations = rapClient.getTopObservationsAsGuest(resourceUrl, 10, true);
System.out.println(observations);
}
}
- https://github.com/symbiote-h2020/ - symbIoTe source code
- https://github.com/symbiote-h2020/symbioteFXClient - similar example in Java
- https://symbiotedemo.slack.com/ - online support
- https://github.com/symbiote-h2020/SymbIoTeAndroidClient - simple Android example
Getting Started
Migration to 3.0.0
Migration to Docker
-
Preparation steps
1.1. Register user and configure platform in symbIoTe Core
1.2. Installation of required tools for symbIoTe platform components
1.3. Downloading jars
1.4. Downloading sources -
Configuring and starting components
2.1. Configuration of NGINX
2.2. Starting third party tools that are prerequisite for symbIoTe
2.3. Starting (generic) symbIoTe Cloud components
2.4. Configuration of cloud components
2.4.1. Starting symbIoTe Cloud components
2.5. Setting up the Platform Authentication and Authorization Manager (PAAM)
2.6. Starting Registration Handler and resource management
2.7. Set up of Resource Access Proxy
2.8. Manage resources
2.9. Set up of the Monitoring component
2.10. Other configuration topics -
Test integrated resource
3.1. Security
3.2. Search for resources
3.3. Obtaining resource access URL
3.4. Accessing the resource and actuating and invoking service for default (dummy) resources -
Creating RAP plugin
4.1. Customizing internal RAP plugin
4.2. Using RAP plugin starter
4.3. Creating RAP plugin in other languages -
Resource Description Examples
5.1. JSON Description Examples
5.2. RDF Description Examples - Preparation for L2 compliance
-
Configuring and starting components for L2
7.1. Starting Federation Manager
7.2. Starting Subscription Manager
7.3. Starting Platform Registry
7.4. Starting Trust Manager
7.5. Starting Bartering And Trading
7.6. Starting SLA Manager
7.7. Create a federation
7.8. Manage resources in L2
7.9. Register Subscription - Test Integrated L2 Resources
- Developing symbIoTe enabled apps