Technical Articles
Invoke several APIs within SAP Leonardo IoT Rules and Actions
In my last blog post I’ve explained how to create a ticket for a service request in SAP Cloud for Customer within an SAP Leonardo IoT action.
Today I would like to show how to invoke APIs from different endpoints while using the SAP Leonardo IoT actions focusing on the fact that it’s possible to invoke more than one action per event.
Let’s assume that your Thing is already configured and SAP Leonardo IoT is currently ingesting data correctly for your asset.
The SAP Cloud Platform Internet of Things device has already been onboarded and is currently communicating with the platform. It will be given just a short overview on the device modelling.
Use case 1
The scenario I’d like to explain in this first use case is a Rule that trigger an Action to send a command to a physical end-device.
The command is sent to the end-device by using the SAP Cloud Platform Internet of Thing APIs.
The story
Our device is a vital part of an equipment in the railway environment that is called in short git; it is in redundancy with at least one replica, and is able to monitor his own status. In case of failure certain actions must be invoked for security reasons.
In particular our device is currently sending as measurement to SAP Cloud Platform IoT Service and SAP Leonardo IoT a counter with the number of errors and problems detected from the startup of the physical device. If this number is higher than a fixed threshold, we would like to invoke one of the available device commands (for example the reboot command or the stop).
Device modelling
The device provisioned into the SAP Cloud Platform Internet of Things instance have only one Sensor. His sensor is described by the Sensor Type named gitSensorType that is composed of the following Capabilities:
- git: this is the number of the rotations of the current git sensor, that is the physical measurement
- errors: it contains the device error counters of and the type of the errors. This value will be evaluated within the Rule of SAP Leonardo IoT
The Sensor Type gitSensorType contains also a Capability with type command:
- commands: this is the command we are going to invoke within the SAP Leonardo IoT Action.
In particular the command has 3 Properties:
- Reboot
- Stop
- SystemFailure
All the properties are of type Boolean and are evaluated with a prioritization schema. If more than one is set to true only the one with the higher priority is computed and his related command invoked.
In the next part, SAP Leonardo IoT uses the SAP Cloud Platform Cockpit Destinations to invoke the HTTP calls. It means that a new destination to connect the Action with SAP Cloud Platform Internet of Things Device Management module needs to be created, to issue correctly the command.
Destination
To complete this step, you need to open into the Cloud Platform cockpit, your Cloud Foundry subaccount, then press “Destination” in the menu on the left, under “Connections” and create a new Connection with the following details:
- Name: any name (i.e.: “IoTS_rail_commands”)
- Type: HTTP
- URL: using as reference the IoTS API Docs the call is a POST to the endpoint with the following format: https://{hostname}/{instanceid}/iot/core/api/v1/tenant/{tenantId}/devices/{deviceId}/commands (the address used in this example to have a connection with my device is https://160bee76-3185-40da-9e14-696e48a9ac51.eu10.cp.iot.sap/160bee76-3185-40da-9e14-696e48a9ac51/iot/core/api/v1/tenant/1773169968/devices/04bd1748-e7d2-43b1-a504-3341b8c9e9c2/commands)
- Proxy Type: Internet
- Authentication: BasicAuthentication
- User: <use your IoT Service username>
- Password: <use your IoT Service password>
Note: Ensure that in the URL the deviceId is used and not the deviceAlternateId, otherwise the command will not be invoked correctly.
Rule
In this step I’ll show you how to configure the Rule Context and the Rule.
First of all, open the Rule Contexts tile of your SAP Leonardo IoT Fiori launchpad and create a new Rule Context linked to the Thing Type and Properties which you have already onboarded before (not explained in this blog post, please refer to the official tutorial).
The Rule Context used is built over the git Thing Type and is using the nError property
Now we can proceed with Rule modelling: open the Rules tile in the Fiori launchpad and create a New Rule of type “Streaming”.
After the specification of a rule name and, optionally a description, navigate the tab editor and as Rule Context select the one created in the step before, to enable the usage of the property nErrors in the condition of your rule.
The purpose of the rule is to notify when a certain number of errors have been detected (10 is the threshold).
In fact the condition “nErrors of the measures is greater than 10” will raise an event called “rebootRequired” that will be used to fire action in the next step.
After the creation press the Activate button to start the scheduling of the rule.
Action
Open the Actions tile of SAP Leonardo IoT Fiori Launchpad and press “New” to create a record.
This action is using the HTTP cloud destination created before to invoke the POST API to send a command to the device.
The parameters of the Action are:
- a name for the action, e.g. Reboot_caused_by_errors
- triggered by “Event from Rule”
- Use the rule at the previous step as “Rule”
- Action Type: HTTP
- In the drop down of the destination, use the destination you have created for your deviceId in the Cloud Cockpit
- Invocation Type: Auto
- Method: POST
- Trigger subsequent event: checked; leave it checked to permit others to consume the event
- Response Payload Type: XML
- For the request body put a JSON object such as:
{
"capabilityId": "5c4f6359-d97e-4e1f-9159-3c5dfda65409",
"command": {
"Reboot": true,
"Stop": false,
"SystemFailure": false
},
"sensorId": "b6e98738-bb04-41a6-846c-1106569fc4f0"
}
The capabilityId is the id (and not the alternateId) of the capability commands; you can discover it directly with the Internet of Things Cockpit.
Similarly, you have to detect the sensorId of the sensor git.
Verification
Our device is going to consume the command specified into the payload and the native reboot will be invoked.
Let’s assume that the status of the device is logged with a serial port, that means we will have a feedback of the device status and the executed operations.
Unfortunately in the example we are not using a real device, but a simulator, so we can simulate a certain numbers of errors , that will cause an increment of the nErrors value and all the consumed commands are logged directly into a file, like for the real device but without using any serial port.
After we have simulated 11 anomalies the nErrors counter is over the threshold. It means that the action has been triggered and the reboot command invoked.
This is the content of the log file:
//.....................//
INFO [git] --- git1-1 --- Received command for git: git1-1. Arguments: "Reboot": true, "Stop": false, "SystemFailure": false
INFO [git] --- git1-1 --- Processing Command: "SystemFailure": false -- Nothing to do
INFO [git] --- git1-1 --- Processing Command: "Stop": false -- Nothing to do
INFO [git] --- git1-1 --- Processing Command: "Reboot": true -- Invoking command...
INFO [git] --- git1-1 --- Reboot command sent
WARN [git] --- git1-1 --- SIGTERM
INFO [git] --- git1-1 --- Bootup of git1-1...
//.....................//
Use case 2
One common question: is it possible to call more than one action with just one rule? Or am I forced to duplicate the rule in case the scenario requires to be executed more than one action for certain conditions?
SAP Leonardo IoT Rules and Actions are in a 1:n ratio. It means that it’s possible to invoke more than one action with just one rule.
In this second part, as extension of the first use case of this blog post, the same rule created in the first part will also call a second action which invokes an API of SAP Leonardo IoT to create a Custom Event.
Scenario
The device is in a critical status, too many errors have been generated: we would like to reboot it and save a custom SAP Leonardo IoT event that collect several non-standard properties.
The first part has already been implemented in the use case 1, let’s now focus on the creation of the custom event.
Event Type
First of all there is the creation of a custom event type. Since it’s an operation that is executed just one time, in this post we are using Postman to create it. Any other rest client could be used instead (for example curl).
To proceed with the next steps you need to discover what is you oData event endpoint and your oAuth2 authentication details.
oAuth2 Details
To discover them go to SAP Cloud Platform Cockpit and open the Cloud Foundry subaccount; go to Spaces and navigate the space where the instance of SAP Leonardo IoT has been created during the onboarding phase.
Click Service Instances and open the instance with Service name “iotae” and then Service Keys.
In the JSON of your keys copy the address of “events-sap” that will be used later to invoke the event type creation (e.g.: “events-sap”: https://events-sap.cfapps.eu10.hana.ondemand.com)
Now copy the oAuth2 details that are in the uua subpart; in particular we need to use the following fields:
- “url” (e.g: https://iotpmdemosenv.authentication.eu10.hana.ondemand.com)
- “clientid” (it identifys the tenant e.g.: “sb-dba6b987-9dc2-4e92-983a-06c7bccd5fa1!b11300|iotae_service!b5”)
- “clientsecret”
Create Property Set
Open Postman and create a new call with type POST.
In the authorization tab select oAuth2 compile the form to Get New Access Token.
The access token url is the url taken from your SAP Cloud Platform Cockpit by adding at the end of the address /oauth/token (e.g: https://iotpmdemosenv.authentication.eu10.hana.ondemand.com/oauth/token)
In the header section of the request add a new header with:
- Key: “Content-Type”
- Value: “application/json”
Now let’s compile the body of the POST and the address:
- Address: <“event-sap” endpoint>/ES/v1/EventPropertySetTypes (e.g. https://events-sap.cfapps.eu10.hana.ondemand.com/ES/v1/EventPropertySetTypes )
- Body:
{
"Name": "iot.iotpmdemosenv.rail:gitCriticalStatusSet",
"PackageName": "iot.iotpmdemosenv.rail",
"Descriptions": [{
"LanguageCode": "en",
"Description": "gitCriticalStatusSet"
}, {
"LanguageCode": "it",
"Description": "gitCriticalStatusSet"
}],
"DataCategory": "EventData",
"Properties": [{
"Name": "gitCriticalStatus",
"Type": "String",
"PropertyLength": "127",
"Descriptions": [{
"LanguageCode": "en",
"Description": "git critical status"
}, {
"LanguageCode": "it",
"Description": "Stato critic per il git"
}]
}]
}
Press Send to create it. An HTTP status 201 of the response identify a success.
The events name are always categorized the fully qualified package name format (<qualified_tenant_name>.<package> : iot.iotpmdemosenv.rail)
Create EventType
Use the same oAuth token and headers of the step before, and compile the POST method with the following details:
- Address: <“event-sap” endpoint>/ES/v1/EventTypes (e.g. https://events-sap.cfapps.eu10.hana.ondemand.com/ES/v1/EventTypes )
- Body:
{
"Name": "iot.iotpmdemosenv.rail:gitCritical",
"EventTypeState": "Mutable",
"Descriptions": [{
"LanguageCode": "en",
"Description": "Event type for gitCritical"
}, {
"LanguageCode": "it",
"Description": "Event type gitCritical"
}],
"PackageName": "iot.iotpmdemosenv.rail",
"PropertySetId": "gitCriticalStatusSet",
"PropertySetType": "iot.iotpmdemosenv.rail:gitCriticalStatusSet",
"PropertySetDescriptions": [{
"LanguageCode": "en",
"Description": "git property set type"
}],
"Statuses": [{
"EventStatus": "New",
"Descriptions": [{
"LanguageCode": "en",
"Description": "New event: git status critical"
}]
}, {
"EventStatus": "Reboot",
"Descriptions": [{
"LanguageCode": "en",
"Description": "Invoked reboot for the git"
}]
}, {
"EventStatus": "Stop",
"Descriptions": [{
"LanguageCode": "en",
"Description": "Invoked the STOP for the git"
}]
}, {
"EventStatus": "GeneralFailure",
"Descriptions": [{
"LanguageCode": "en",
"Description": "git general failure"
}]
}, {
"EventStatus": "Done",
"Descriptions": [{
"LanguageCode": "en",
"Description": "Completed git status critical"
}]
}, {
"EventStatus": "RebootDone",
"Descriptions": [{
"LanguageCode": "en",
"Description": "git reboot completed"
}]
}, {
"EventStatus": "StopDone",
"Descriptions": [{
"LanguageCode": "en",
"Description": "git STOP completed"
}]
}],
"Severities": [{
"EventSeverity": 1,
"Descriptions": [{
"LanguageCode": "en",
"Description": "High"
}]
}, {
"EventSeverity": 2,
"Descriptions": [{
"LanguageCode": "en",
"Description": "Medium"
}]
}, {
"EventSeverity": 3,
"Descriptions": [{
"LanguageCode": "en",
"Description": "Low"
}]
}],
"Codes": [{
"EventCode": "EQ12",
"Descriptions": [{
"LanguageCode": "en",
"Description": "Event Code 12"
}]
}]
}
The EventTypeState is set to Mutable. This means that you will be able to modify or remove the events. If this field is not specified in the JSON or specified as Immutable there is no way to modify or remove the created events.
Press Send to create it. An HTTP status 201 of the response identify a success.
Destination
In order to invoke an API of SAP Leonardo IoT you need to create a new connection in SAP Cloud Cockpit Destinations with the following details:
- Name: any name (i.e.: “IoTS_rail_commands”)
- Type: HTTP
- URL: it must be the final url of the Events endpoint that is with the following format: <“event-sap” endpoint>/ES/EventType/<event type name>/v1/Events (in the example it is https://events-sap.cfapps.eu10.hana.ondemand.com/ES/EventType/iot.iotpmdemosenv.rail:gitCritical/v1/Events)
- Proxy Type: Internet
- Authentication: OAuth2UserTokenExchange
- Client ID: <use the client id copied before>
- Client Secret: <use the client secret copied before>
- Token Service URL: <use the same value used in Postman for the oAuth2 authentication>
A new Action
Open the Actions tile of SAP Leonardo IoT Fiori Launchpad and press “New” to create another action.
The parameters of the Action are:
- a name for the action, e.g. CustomEvent_caused_by_errors
- triggered by “Event from Rule”
- Use the rule at the previous step as “Rule”
- Action Type HTTP
- In the drop down of the destination, use the destination you have created for the Events in the SAP Cloud Cockpit
- Invocation Type: Auto
- Method: POST
- Trigger subsequent event: checked; leave it checked to permit others to consume the event
- Response Payload Type: XML
- For the request body put a JSON object such as:
{
"BusinessTimestamp": "${event.time}",
"Type": "Alert",
"EventInfo": "Alert on git",
"EventStatus": "New",
"EventSeverity": 1,
"EventCode": null,
"EventSource": null,
"ThingId": "${thing.id}",
"ThingProperty": "Too many errors for the git",
"ExternalId": "gitError"
}
Verification
To verify the behavior we have to force again the triggering of the Rule.
First of all we can verify that the action of the use case 1 is still executed; as expected the log identify again that a reboot have been invoked.
Open again Postman and create a GET Method.
Use the same oAuth token and headers used for the EventType creation and use the following address: <“event-sap” endpoint>/ES/EventType/<event type name>/v1/Events (the address for our example is: https://events-sap.cfapps.eu10.hana.ondemand.com/ES/EventType/iot.iotpmdemosenv.rail:gitCritical/v1/Events)
In case of success, the result of the HTTP request is 200, and in the body of the response you can verify the presence of one Event, created by the action.
Conclusion
In this blog post I’ve shown how to invoke more than one action and both the actions where invoking an SAP services. In a similar way it’s possible to invoke also 3rd party endpoints.
Hello Marco
This really nice blog …!! Make very ease to trigger Action based on rule .
Suppose use case where i have Alexa send Instruction to device ( Robot as device in IoT service Cockpit ) – Based on Alexa instruction robot change his position . If i am not wrong this be the case to invoke also 3rd party endpoints to send command to device using Rule and action .
Appreciate how this can integrate/Configure in SAP IoT Leonardo with all step involoved – Alexa send Instruction to device ( Robot as device in IoT service Cockpit ) – Based on Alexa instruction robot change his position .
Thanks~
Vivek Gupta
Hi Vivek Gupta,
I don't have a deep knowledge of Alexa and we might extend a little bit the analysis of the scenario to identify better what is the final goal and how would you like to achieve it.
In particular, what are the steps that you would like to execute and who should be the actor?
By the way, let me try to figure two possible scenarios that can fit with your use case.
If you would like to invoke within the action an endpoint exposed by Alexa (or any other endpoint), you need to configure it in the cloud destination, like I've done here in my example:
Then you just have to use this endpoint in the action (with the expected payload).
In case you need to downlink the command from Alexa to the end device (connected to SCP Internet of Things) by using the Internets of Things capabilities, I suggest to have a look into the official documentation:
https://help.sap.com/viewer/643f531cbf50462c8cc45139ba2dd051/Cloud/en-US/3ded56a44f3a45ae9e39a19a6d8a0b0e.html
https://help.sap.com/viewer/643f531cbf50462c8cc45139ba2dd051/Cloud/en-US/c327148f820e4d3888fb4b73c7f0ef80.html
https://help.sap.com/viewer/643f531cbf50462c8cc45139ba2dd051/Cloud/en-US/46ba4bea0dd940a19e2892834d434dcd.html
that means in short:
In case the situation is different and you would like to use Alexa to downlink commands to a device connected to SCP Internet of Things, your use case perfectly fits with the "use case 1". It basically means that your measurements are forwarded by Alexa into the data ingestion pipeline, and the action should trigger the reboot of the robot directly within an action.
To downlink the command you just have to follow what is specified above.
In case the scenario is different, please add all the missing information, then we can figure it out how to apply it in your scenario.
Hello Everyone,
We cannot find the HTTP action type in the Action Tab. Is it removed by SAP?
Hi, thanks for your feedback.
The current action is "Service Integration".
Please let me know if it helps!
Best Regards
Marco