Let us get started with the configuration for the second scenario in the prototype. Configuration is required in various services of SCP for the completion of the IoT prototype.
This scenario covers the steps which can be used to set up automated reordering of material in a warehouse. There are numerous sensors available in the market to track the stock level of the raw material. When the stock goes below a certain level, the sensors can trigger a message to the IoT platform which in turn can decide the course of action depending on the rules set in the Business Rules. To demonstrate this, I have set up a couple of buttons in my Raspberry Pi and When the buttons are pressed (each button represents a different material type for simplicity), a message is sent to the SAP cloud platform and the order is generated automatically or sent to a user depending on the material type being sent.
Create two Data Objects
Input: with one attribute – materialtype
Output: with three attributes as below
ordermode – To indicate whether to place an order automatically or inform the user to place an order after confirmation.
qty – Quantity for reorder
ordertype – Type of Order
Create a Rule.
ReorderRule – This rule is constructed as a Decision Table. Depending on the material type received by the rule different order mode, order type and qty can be sent as output.
Create a RuleSet
ReorderSet – Add the Rule to the Rule set.
Create a Rule Service
ReorderService – This rule service takes the data object ‘Input’ as input and returns ‘Output’ as result.
Create a Workflow project ‘ReOrderProcess’ and create a simple workflow with a single user task – ‘Re-Order Material’. This workflow will be triggered from the IoT Java application.
http = urllib3.PoolManager()
headers = urllib3.util.make_headers(user_agent=None)
headers['Authorization'] = 'Bearer ' + config.oauth_credentials_for_device
headers['Content-Type'] = 'application/json;charset=utf-8'
url='https://iotmms' + config.hcp_account_id + config.hcp_landscape_host + '/com.sap.iotservices.mms/v1/api/http/data/'+ str(config.device_id)
urllib3.disable_warnings()
try:
while True:
if GPIO.input(buttonPin) == False:
print("low stock message sent")
time = datetime.datetime.now().time()
date = datetime.datetime.now().date()
body= '{"mode":"async", "messageType":"' + str(config.message_type_id_LOW) + '", "messages":[{"Date":'+ ' "' + str(date) + '"'+ ',"Time":'+ ' "' + str(time) + '"'+ ',"Materialtype":'+ ' "M1" }]}'
r = http.urlopen('POST', url, body=body, headers=headers)
print(body)
print(r.data)
except KeyboardInterrupt:
GPIO.cleanup()
/**
* read data from device
*
* @return
*/
private String getMaterialTypefromDevice(String deviceid) {
InitialContext ctx = null;
DataSource ds = null;
Connection con = null;
String result = null;
try {
ctx = new InitialContext();
ds = (DataSource) ctx.lookup("java:comp/env/jdbc/default");
con = ds.getConnection();
PreparedStatement query = con.prepareStatement(
"SELECT TOP 1 \"C_MATERIALTYPE\" FROM \"SYSTEM\".\"T_LS_IOTMESSAGES\" WHERE \"G_DEVICE\" = '"+deviceid+"' ORDER BY \"G_CREATED\" desc");
ResultSet rs = query.executeQuery();
while (rs.next()) {
result = rs.getString(1);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
/**
* Get the reorder type and details
*
* @param materialtype
* @return
* @throws ClientProtocolException
* @throws IOException
*/
public String getReorderDetails(String materialname, String materialtype)
throws ClientProtocolException, IOException {
HttpContext httpContext = new BasicHttpContext();
httpContext.setAttribute(HttpClientContext.COOKIE_STORE, new BasicCookieStore());
HttpPost httpPost = null;
CloseableHttpResponse response = null;
CloseableHttpClient httpClient = null;
try {
httpClient = getHTTPClient();
String rulesRuntimeUrl = "https://bpmrulesruntimebpm-s000xxxxxxxtrial.hanatrial.ondemand.com/";
String xsrfTokenUrl = rulesRuntimeUrl + "rules-service/v1/rules/xsrf-token";
String invokeUrl = rulesRuntimeUrl
+ "rules-service/v1/rules/invoke?rule_service_name=Reorder::ReorderService";
httpPost = new HttpPost(invokeUrl);
httpPost.addHeader("Content-type", "application/json");
String xsrfToken = getXSRFToken(xsrfTokenUrl, httpClient, httpContext);
if (xsrfToken != null) {
httpPost.addHeader("X-CSRF-Token", xsrfToken);
}
// replace value of authorizationHeader with base64 encoded value of
// “<user-name>:<password>”
String authorizationHeader = " <base64 encoded value of <user-name>:<password>>";
httpPost.addHeader("Authorization", "Basic " + authorizationHeader);
// construct input data to the rules service
String fact = "{ \"__type__\":\"Input\",\"materialtype\":\"" + materialtype + "\"}";
StringEntity stringEntity = new StringEntity(fact);
httpPost.setEntity(stringEntity);
response = httpClient.execute(httpPost, httpContext);
// process your response here
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
InputStream inputStream = response.getEntity().getContent();
byte[] data = new byte[1024];
int length = 0;
while ((length = inputStream.read(data)) > 0) {
bytes.write(data, 0, length);
}
String respBody = new String(bytes.toByteArray(), "UTF-8");
// The respBody is a JSON and parse is to get discount
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonObject = objectMapper.readValue(respBody, JsonNode.class);
String ordermode = jsonObject.get("ordermode").asText();
int qty = jsonObject.get("qty").asInt();
String ordertype = jsonObject.get("ordertype").asText();
if (ordermode.equalsIgnoreCase("Auto")) {
return "Order created - Material: " + materialname + ", Order Type: " + ordertype + ",Quantity: " + qty;
} else {
// trigger workflow
String id = "Order sent to workflow. Workflow instance started with ID "
+ triggerManualReOrder(materialname, materialtype, ordertype, qty);
return id;
}
} finally {
if (httpPost != null) {
httpPost.releaseConnection();
}
if (response != null) {
response.close();
}
if (httpClient != null) {
httpClient.close();
}
}
}
/**
* Gets the xsrf token for business rules/workflow
*
* @param requestURL
* @param client
* @param httpContext
* @return
* @throws ClientProtocolException
* @throws IOException
*/
private String getXSRFToken(String requestURL, CloseableHttpClient client, HttpContext httpContext)
throws ClientProtocolException, IOException {
HttpGet httpGet = null;
CloseableHttpResponse response = null;
String xsrfToken = null;
String authorizationHeader = null;
try {
httpGet = new HttpGet(requestURL);
// replace value of authorizationHeader with base64 encoded value of
// “<user-name>:<password>”
authorizationHeader = "<base64 encoded value of <user-name>:<password>>";
httpGet.addHeader("Authorization", "Basic " + authorizationHeader);
httpGet.addHeader("X-CSRF-Token", "Fetch");
response = client.execute(httpGet, httpContext);
// Fetch the token from response and return
Header xsrfTokenheader = response.getFirstHeader("X-CSRF-Token");
if (xsrfTokenheader != null) {
xsrfToken = xsrfTokenheader.getValue();
}
} finally {
if (httpGet != null) {
httpGet.releaseConnection();
}
if (response != null) {
response.close();
}
}
return xsrfToken;
}
/**
* trigger the reorder process
*
* @param temp
* @return
* @throws ClientProtocolException
* @throws IOException
*/
public String triggerManualReOrder(String materialname, String materialtype, String ordertype, int qty)
throws ClientProtocolException, IOException {
HttpContext httpContext = new BasicHttpContext();
httpContext.setAttribute(HttpClientContext.COOKIE_STORE, new BasicCookieStore());
HttpPost httpPost = null;
CloseableHttpResponse response = null;
CloseableHttpClient httpClient = null;
try {
httpClient = getHTTPClient();
String rulesRuntimeUrl = "https://bpmworkflowruntimewfs-s000xxxxxxtrial.hanatrial.ondemand.com/";
String xsrfTokenUrl = rulesRuntimeUrl + "workflow-service/rest/v1/xsrf-token";
String invokeUrl = rulesRuntimeUrl + "workflow-service/rest/v1/workflow-instances";
httpPost = new HttpPost(invokeUrl);
httpPost.addHeader("Content-type", "application/json");
String xsrfToken = getXSRFToken(xsrfTokenUrl, httpClient, httpContext);
if (xsrfToken != null) {
httpPost.addHeader("X-CSRF-Token", xsrfToken);
}
// replace value of authorizationHeader with base64 encoded value of
// “<user-name>:<password>”
String authorizationHeader = " <base64 encoded value of <user-name>:<password>>";
httpPost.addHeader("Authorization", "Basic " + authorizationHeader);
// construct input data to the workflow service to create instance
String fact = "{ \"definitionId\":\"reorder\",\"context\":{ \"materialname\":\"" + materialname
+ "\",\"materialtype\":\"" + materialtype + "\",\"ordertype\":\"" + ordertype + "\",\"qty\":" + qty
+ "}}";
StringEntity stringEntity = new StringEntity(fact);
httpPost.setEntity(stringEntity);
response = httpClient.execute(httpPost, httpContext);
// process your response here
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
InputStream inputStream = response.getEntity().getContent();
byte[] data = new byte[1024];
int length = 0;
while ((length = inputStream.read(data)) > 0) {
bytes.write(data, 0, length);
}
String respBody = new String(bytes.toByteArray(), "UTF-8");
// The respBody is a JSON and parse is to get discount
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonObject = objectMapper.readValue(respBody, JsonNode.class);
return jsonObject.get("id").asText();
} finally {
if (httpPost != null) {
httpPost.releaseConnection();
}
if (response != null) {
response.close();
}
if (httpClient != null) {
httpClient.close();
}
}
}
Finally, the glue code which calls all these functions is as below.
response.getWriter().println(getReorderDetails("Test", getMaterialTypefromDevice(deviceID)));
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
8 | |
5 | |
5 | |
4 | |
4 | |
4 | |
4 | |
3 | |
3 | |
3 |