Supply Chain Management Blogs by SAP
Expand your SAP SCM knowledge and stay informed about supply chain management technology and solutions with blog posts by SAP. Follow and stay connected.
cancel
Showing results for 
Search instead for 
Did you mean: 

Introduction


In the first part of the blog post series we will create a few Indicators, an Indicator Group, a Model Template and a Model. All this can be done from the UI of PdMS using a web browser but I prefer to use the APIs. We will use curl, but feel free to use any REST Client of your choice.

Pre-Requisites



  1. Bash Terminal

  2. Following command line tools installed: curl, jq

  3. Access to PdMS CE System


Authentication and Authorization for API Access


During tenant onboarding the administrator of the tenant receives the oauth client credentials. With these credentials and the client_credentials flow, it's possible to request a JWT token from the CF UAA. We are not going to do this in this blog post.

Currently the easiest way to use the APIs is to copy the User Cookie from the Chrome Developer Console and use it when doing requests with curl.

Login to the PdMS Launchpad, in the Chrome Developer Console go to the Network tab, click on any request and copy the Cookie from the Request Headers.

Create a new file, headers.txt, and add the following line where {Cookie} is the copied Cookie.
Cookie: {Cookie}

For example:
Cookie: JSESSIONID=s%3A7p3OOhM_sqNialZP2FrRffSDkRc8Df_j.rLd%2BKRj1zyrBW4spZRrCu%2B3APQ%2FR03ZFtBdVqe1u39E; __VCAP_ID__=b9bc469b-2975-4d4b-72f1-2798

You need to make sure that while you follow along the blog post you are not logged out from PdMS, so please refresh the Launchpad in regular intervals. There is a nice Chrome Add-on called Auto Refresh [1] which might help you with that.

 

Having said that, let's open the terminal and request a csrf-token for doing POST or PUT Requests. (If you use a JWT token instead of the Cookie and send the requests directly to the PdMS Backend, you can skip the csrf-token steps.)

First, export the base url as environment variable, make sure to adjust it to your instance:
export PDMS_BASE_URL="https://pdms-prep.pdms-at.cfapps.sap.hana.ondemand.com"

Get the CSRF Token Header and add it to headers.txt with the following command:
curl -s -I -X GET -H 'x-csrf-token:fetch' -H @headers.txt "${PDMS_BASE_URL}"/ain/services/api/v1/indicators | grep "X-Csrf-Token:" >> headers.txt

The file headers.txt should now contain two lines, one that starts with Cookie, one that starts with X-Csrf-token.

You can check the content of headers.txt, it should look similar to this:
➜  ~ cat headers.txt
Cookie: JSESSIONID=s%3A7p3OOhM_sqNialZP2FrRffSDkRc8Df_j.rLd%2BKRj1zyrBW4spZRrCu%2B3APQ%2FR03ZFtBdVqe1u39E; __VCAP_ID__=b9bc469b-2975-4d4b-72f1-2798
X-Csrf-Token: e1e10f58e77dded7-MBul2yGuf0LAzxhkcFEWhivEvYA

Now, let's do a quick sanity check and retrieve the list of available Indicators in the system:
curl -H @headers.txt \
"${PDMS_BASE_URL}"/ain/services/api/v1/indicators

On a fresh tenant, this should return an empty array []. Make sure there is no http error.

Indicators


Now, we can start to create Indicators which will represent and hold the sensor data to upload. We will also create Indicators which will hold the results of the Machine Learning Algorithms, which we call scores.

The API description for Indicator Creation is available [2] in the help portal.

We are creating the following Indicators:

  • Temperature

    • dataType: numeric

    • dimension: TEMP

    • indicatorCategory: 1 (Continuous)

    • indicatorUom: GC (Degree Celsius)

    • indicatorType: 1 (Measured)

    • expectedBehaviour: 4 (None)

    • aggregationConcept: 6 (Last available Value)



  • Pressure

    • dataType: numeric

    • dimension: PRESS

    • indicatorCategory: 1 (Continuous)

    • indicatorUom: HPA (Hecto Pascal)

    • indicatorType: 1 (Measured)

    • expectedBehaviour: 4 (None)

    • aggregationConcept: 6 (Last available Value)



  • Humidity

    • dataType: numeric

    • dimension: PROPOR

    • indicatorCategory: 1 (Continuous)

    • indicatorUom: % (Percentage)

    • indicatorType: 1 (Measured)

    • expectedBehaviour: 4 (None)

    • aggregationConcept: 6 (Last available Value)



  • Score

    • dataType: numeric

    • dimension: null

    • indicatorCategory:1 (Continuous)

    • indicatorUom: null

    • indicatorType: 2 (Calculated)

    • expectedBehaviour: 4 (None)

    • aggregationConcept: 2 (Maximum)




  • Normalized Score

    • dataType: numeric

    • dimension: null

    • indicatorCategory:1 (Continuous)

    • indicatorUom: null

    • indicatorType: 2 (Calculated)

    • expectedBehaviour: 4 (None)

    • aggregationConcept: 2 (Maximum)




When we create the indicators, the system generates a unique ID and returns this along with the other payload. We will extract those IDs using jq from the response JSON and save them into environment variables for later usage.

Run the following curl commands to create the Indicators:
export TEMPERATURE_INDICATOR_ID=`curl -X POST \
"${PDMS_BASE_URL}"/ain/services/api/v1/indicators \
-H @headers.txt \
-H 'Content-Type: application/json' \
-d '{"aggregationConcept":"6","dataType":"numeric","description":{"short":"Temperature"},"dimension1":"TEMP","expectedBehaviour":"4","internalId":"Temperature","indicatorCategory":"1","indicatorType":[{"code":"1"}],"indicatorUom":"GC"}' \
| jq -r '.id'`

export PRESSURE_INDICATOR_ID=`curl -X POST \
"${PDMS_BASE_URL}"/ain/services/api/v1/indicators \
-H @headers.txt \
-H 'Content-Type: application/json' \
-d '{"aggregationConcept":"6","dataType":"numeric","description":{"short":"Pressure"},"dimension1":"PRESS","expectedBehaviour":"4","internalId":"Pressure","indicatorCategory":"1","indicatorType":[{"code":"1"}],"indicatorUom":"HPA"}' \
| jq -r '.id'`

export HUMIDITY_INDICATOR_ID=`curl -X POST \
"${PDMS_BASE_URL}"/ain/services/api/v1/indicators \
-H @headers.txt \
-H 'Content-Type: application/json' \
-d '{"aggregationConcept":"6","dataType":"numeric","description":{"short":"Humidity"},"dimension1":"PROPOR","expectedBehaviour":"4","internalId":"Humidity","indicatorCategory":"1","indicatorType":[{"code":"1"}],"indicatorUom":"%"}' \
| jq -r '.id'`

export SCORE_INDICATOR_ID=`curl -X POST \
"${PDMS_BASE_URL}"/ain/services/api/v1/indicators \
-H @headers.txt \
-H 'Content-Type: application/json' \
-d '{"aggregationConcept":"2","dataType":"numeric","description":{"short":"Score"},"dimension1":null,"expectedBehaviour":"4","internalId":"Score","indicatorCategory":"1","indicatorType":[{"code":"2"}],"indicatorUom":null}' \
| jq -r '.id'`

export NORMALIZED_SCORE_INDICATOR_ID=`curl -X POST \
"${PDMS_BASE_URL}"/ain/services/api/v1/indicators \
-H @headers.txt \
-H 'Content-Type: application/json' \
-d '{"aggregationConcept":"2","dataType":"numeric","description":{"short":"Normalized Score"},"dimension1":null,"expectedBehaviour":"4","internalId":"Normalized_Score","indicatorCategory":"1","indicatorType":[{"code":"2"}],"indicatorUom":null}' \
| jq -r '.id'`

Check, that the IDs are available in the environment variables. In my case, this looks like this:
➜  ~ echo $TEMPERATURE_INDICATOR_ID
A079F81505EF4E1D9C9051A27FA50198
➜ ~ echo $PRESSURE_INDICATOR_ID
DD6162EFA3414924BE8C63DB8F24F4CB
➜ ~ echo $HUMIDITY_INDICATOR_ID
9EE9B2BFDDE047F195A6E8C521CA7E99
➜ ~ echo $SCORE_INDICATOR_ID
C58A2FEDE87F4001A5D46F34F4C5C0D4
➜ ~ echo $NORMALIZED_SCORE_INDICATOR_ID
A8A8DA94C9544519B6B8C8985EDAC795

You can also repeat the GET call from above to retrieve the list of available indicators in the system, which should now return your Indicators instead of an empty array.

Indicator Groups


We are now going to group the Indicators into two Indicator Groups, one for the sensor measurements (Temperature, Pressure, Humidity) and one for the output of the machine learning algorithms (Score, Normalized Score).

The API description for Indicator Group Creation is available [3] in the help portal.

Run the following snippets to create Indicator Groups 'Measurements' and 'Scores':
export MEASUREMENTS_INDICATOR_GROUP_ID=`curl -X POST \
"${PDMS_BASE_URL}"/ain/services/api/v1/indicatorgroups \
-H @headers.txt \
-H 'Content-Type: application/json' \
-d '{"internalId":"Measurements","description":{"short":"Measurements"}}' \
| jq -r '.id'`

curl -X PUT \
"${PDMS_BASE_URL}"/ain/services/api/v1/indicatorgroups \
-H @headers.txt \
-H 'Content-Type: application/json' \
-d '{"internalId":"Measurements","description":{"short":"Measurements"},"indicators":[{"id":"'"$TEMPERATURE_INDICATOR_ID"'"}, {"id":"'"$PRESSURE_INDICATOR_ID"'"}, {"id":"'"$HUMIDITY_INDICATOR_ID"'"}], "id": "'"$MEASUREMENTS_INDICATOR_GROUP_ID"'"}'

export SCORES_INDICATOR_GROUP_ID=`curl -X POST \
"${PDMS_BASE_URL}"/ain/services/api/v1/indicatorgroups \
-H @headers.txt \
-H 'Content-Type: application/json' \
-d '{"internalId":"Scores","description":{"short":"Scores"}}' \
| jq -r '.id'`

curl -X PUT \
"${PDMS_BASE_URL}"/ain/services/api/v1/indicatorgroups \
-H @headers.txt \
-H 'Content-Type: application/json' \
-d '{"internalId":"Measurements","description":{"short":"Measurements"},"indicators":[{"id":"'"$SCORE_INDICATOR_ID"'"}, {"id":"'"$NORMALIZED_SCORE_INDICATOR_ID"'"}], "id": "'"$SCORES_INDICATOR_GROUP_ID"'"}'

To verify that everything worked, query the API with HTTP Method GET:
curl -H @headers.txt \
"${PDMS_BASE_URL}"/ain/services/api/v1/indicatorgroups

This should not return an empty array. In addition, verify that the environment variables are populated. In my case, this returns the following:
➜  ~ echo $MEASUREMENTS_INDICATOR_GROUP_ID
B0D200C0011A9A2F16006F02A49D4058
➜ ~ echo $SCORES_INDICATOR_GROUP_ID
B1D200C0011A9A2F16006F02A49D4058

Model Template


Create a Model Template with the name 'Weather Station Template'. Feel free to modify the names of the Objects.
export MODEL_TEMPLATE_ID=`curl -X POST \
"${PDMS_BASE_URL}"/ain/services/api/v1/template \
-H @headers.txt \
-H 'Content-Type: application/json' \
-d '{"internalId":"Weather_Station_Template","description":{"short":"Weather Station Template"},"type":"3","indicatorGroups":[{"id":"'"$MEASUREMENTS_INDICATOR_GROUP_ID"'"}, {"id":"'"$SCORES_INDICATOR_GROUP_ID"'"}]}' \
| jq -r '.[].id'`

The Indicator Groups are both added to the Model Template, because we specified them in the indicatorGroups element in the JSON payload. Verify that the Model Template has been created:
➜  ~ echo $MODEL_TEMPLATE_ID
14D700C0011A9A2F16006F02A49D4058

Model


To create a Model, we first need to get the organisation ID of a Manufacturer (To quote the documentation: "Business partner ID of model manufacturer / system provider") present in the system:
curl -H @headers.txt \
"${PDMS_BASE_URL}/ain/services/api/v1/organizations/byrole?roleid=1"

If this returns an empty array, you can change the role of your tenant to include Manufacturer by:

Launchpad -> Company Profile -> Edit (right top corner) -> Roles -> Add Manufacturer -> Save.

Now, re-run the query from above and export the organisation id as environment variable:
➜  ~ export ORG_ID="FA5C6E05E9584B05B7399F48A46534CB"

Now, we are able to create the Model with name 'Weather Station':
export MODEL_ID=`curl -X POST \
"${PDMS_BASE_URL}"/ain/services/api/v1/models \
-H @headers.txt \
-H 'Content-Type: application/json' \
-d '{"internalId":"Weather_Station","organizationID":"'"$ORG_ID"'","description":{"short":"Weather Station"},"equipmentTracking":"1","templates":[{"id":"'"$MODEL_TEMPLATE_ID"'","primary":true}]}' \
| jq -r '.modelId'`

If everything went well, you should have the Model Id as environment variable:
➜  ~ echo $MODEL_ID
992BF5A057C840A893FE736BD01BA4A3

In the Model Application, you can have a look at the Model and verify that the Indicators are present in the Indicator Tab.

That's it for this blog post. In the next part of the series we will create an Equipment from the Model, verify that all external objects have been created and analyse how the objects of PdMS are mapped to objects of IoT AE and IoT Services. Furthermore, we are going to upload sensor data.
3 Comments