[Archive] SAP Cloud Platform Internet of Things
This library has been archived and is no longer supported.
This snippet provides a function to send IoT data to SAP Cloud Platform Internet of Things.
Resources used: HTTPS x 1
or MQTTS x 1
Details
The send_sap
function can be used to POST the passed sensor data object 'payload' to an SAP IoT device 'sensor capability' using its REST API, over HTTPS. The result (error/response) is then passed to the callback function.
The mqtt_sap
function returns an MQTT client object connected to the SAP IoT MQTT broker. The user can use the client to PUBLISH/SUBSCRIBE to an SAP IoT device topic, over MQTTS.
To start using this snippet, HOST
(Address of the SAP Cloud IoT Instance), DEVICE_ALTERNATE_ID
(Alternate ID of the Device), CERT
(Device Certificate), KEY
(Un-encrypted Private Key), and CA
are required to be configured by the user.
The certificates downloaded from the SAP IoT device management page has both, the certificate, and the private key which is encrypted by default. To be used with this snippet, the password must be removed from the private key. It can be done with openSSL using the following command.
openssl rsa -in encrypted_privatekey.pem -out un-encrypted_privatekey.pem
NOTE: The provided function can handle data sizes up to 4KB. To handle larger data sizes, please refer to divided writing for https objects in the neqto.js documentation.
Click here to learn how to get a CA.
var CA = "-----BEGIN CERTIFICATE-----\n...<CA>...\n-----END CERTIFICATE-----"
HTTPS (REST)
//=================================================================
// SAP HTTP SNIPPET
//=================================================================
//=================================================================
// The following configuration are MANDATORY. Set by user.
//=================================================================
// The address of the SAP Cloud Internet of Things instance.
var HOST = '<YOUR_HOST>';
// Alternate ID of the device.
// eg. xxxxxx
var DEVICE_ALTERNATE_ID = '<YOUR_DEVICE_ALTERNATE_ID>';
// The public certificate part of the device certificate obtained from the device management page.
// eg. '-----BEGIN CERTIFICATE-----\n...<CERT>...\n-----END CERTIFICATE-----'
var CERT = '<YOUR_CERT>';
// The private key part of the device certificate (un-encrypted) obtained from the device management page.
// eg. '-----BEGIN RSA PRIVATE KEY-----\n...<KEY>...\n-----END RSA PRIVATE KEY-----'
var KEY = '<YOUR_KEY>';
// Public certificate of the certificate authority that signed the SAP server certificate for SSL/TLS handshake.
// eg. '-----BEGIN CERTIFICATE-----\n...<CA>...\n-----END CERTIFICATE-----'
var CA = '<YOUR_CA>';
//=================================================================
/**
* Post data to SAP Cloud Internet of Things using client based authentication.
* https://developers.sap.com/tutorials/iot-cf-send-data-rest.html
* @function send_sap
* @param {number} sensorAlternateId - Alternate ID of the sensor, as a Number.
* @param {number} capabilityAlternateId - Alternate ID of the capability, as a Number.
* @param {Array} payload - The data to be sent to SAP, as either an Array of arrays of specified measures, or as an Array of JSON objects where the name of each property defined in the capability is the key.
* @param {function} callback - User callback to return the result (error/response).
* @returns {undefined}
*/
var send_sap = function (sensorAlternateId, capabilityAlternateId, payload, callback) {
var body = JSON.stringify({
"sensorAlternateId": sensorAlternateId,
"capabilityAlternateId": capabilityAlternateId,
"measures": payload
});
var options = {
"method": 'POST',
"host": HOST,
"path": `/iot/gateway/rest/measures/${DEVICE_ALTERNATE_ID}`,
"headers": {
"Content-Type": 'application/json',
"Content-Length": body.length.toString()
},
"cert": CERT,
"key": KEY,
"ca": CA
};
var request = https.request(options, function (response) {
response.on('end', function () {
callback(null, { "statusCode": response.statusCode, "statusMessage": response.statusMessage, "body": response.read() });
});
});
request.on('error', function () {
callback({ "errCode": request.errCode }, null);
});
request.end(body.toString(), function () {
print("[request] SUCCESS");
});
}
MQTTS
//=================================================================
// SAP MQTT SNIPPET
//=================================================================
//=================================================================
// The following configuration are MANDATORY. Set by user.
//=================================================================
// The address of the SAP Cloud Internet of Things instance.
var HOST = '<YOUR_HOST>';
// Alternate ID of the device.
// eg. xxxxxx
var DEVICE_ALTERNATE_ID = '<YOUR_DEVICE_ALTERNATE_ID>';
// The public certificate part of the device certificate obtained from the device management page.
// eg. '-----BEGIN CERTIFICATE-----\n...<CERT>...\n-----END CERTIFICATE-----'
var CERT = '<YOUR_CERT>';
// The private key part of the device certificate (un-encrypted) obtained from the device management page.
// eg. '-----BEGIN RSA PRIVATE KEY-----\n...<KEY>...\n-----END RSA PRIVATE KEY-----'
var KEY = '<YOUR_KEY>';
// Public certificate of the certificate authority that signed the SAP server certificate for SSL/TLS handshake.
// eg. '-----BEGIN CERTIFICATE-----\n...<CA>...\n-----END CERTIFICATE-----'
var CA = '<YOUR_CA>';
//=================================================================
/**
* Create an MQTT Client connected to SAP Cloud Internet of Things using client based authentication.
* https://developers.sap.com/tutorials/iot-cf-send-data-mqtt.html
* @function mqtt_sap
* @param {object} options - MQTT Configuration for connecting to the broker, as an Object.
* @returns {(Client|undefined)} - {Client} : Generated MQTT {Client} | undefined : {Client} generate failed due to invalid arguments or insufficient resources.
*/
var mqtt_sap = function (options) {
mqtt.set('ssl.ca', CA);
mqtt.set('ssl.key', KEY);
mqtt.set('ssl.cert', CERT);
return mqtt.connect(`mqtts://${HOST}:8883`, options);
}
Function Usage Example
Sample 1
This is a sample to send data to the server using the send_sap
function.
/*
<INSERT ABOVE SNIPPET HERE WITH SET CONFIGURATIONS>
*/
//=================================================================
log.setLevel(-1); //-1:NONE 0:ERROR 1:WARNING 2:DEBUG 3:TRACE
log.printLevel(2); //0:DISABLE 1:LOG 2:CONSOLE 3:BOTH
//=================================================================
// MAIN SCENARIO
//=================================================================
/**
* Callback to fetch error/response from the request.
* @function callback
* @param {object} err - Error returned if the request failed. Has one property - `errCode`.
* @param {object} data - Response returned by a successfully completed request. Has three properties - `statusCode`, `statusMessage`, and `body`.
*/
var callback = function (err, data) {
if (err) {
print("[error]", err.errCode);
} else {
print("[status]", data.statusCode, data.statusMessage);
print("[response]", data.body);
}
}
var sensorAlternateId = 123;
var capabilityAlternateId = 123456;
var payload = [
{
"testProperty": 'Hello from NEQTO Device' // "property": '<DATA>'
}
];
send_sap(sensorAlternateId, capabilityAlternateId, payload, callback);
Sample 2
This is a sample to publish and subscribe using the client returned from the mqtt_sap
function, with automatic reconnection enabled. After connection, loopback test of transmission and reception is performed.
/*
<INSERT ABOVE SNIPPET HERE WITH SET CONFIGURATIONS>
*/
//=================================================================
log.setLevel(-1); //-1:NONE 0:ERROR 1:WARNING 2:DEBUG 3:TRACE
log.printLevel(2); //0:DISABLE 1:LOG 2:CONSOLE 3:BOTH
//=================================================================
// MAIN SCENARIO
//=================================================================
var sensorAlternateId = 5;
var capabilityAlternateId = 123456;
var sub_topic = `ack/${DEVICE_ALTERNATE_ID}`;
var pub_topic = `measures/${DEVICE_ALTERNATE_ID}`;
var client = mqtt_sap({
"clientId": DEVICE_ALTERNATE_ID.toString(), // MANDATORY
"reconnectCount": 1855
});
if (!client) {
throw 'Failed to create mqtt instance';
}
var registerEventHandlers = function () {
if (!client) {
return;
}
client.on('error', function (err) {
print('ERROR: ' + err.code + ' ERRNO: ' + client.get('errnoConnect'));
//TODO: Error handling
});
client.on('message', function (topic, message) {
print('TOPIC: ' + topic + ' MESSAGE: ' + message);
//TODO: Message handling
});
client.on('close', function () {
print("DISCONNECTED");
});
client.on('connect', function () {
print('CONNECTED');
client.subscribe(sub_topic, { qos: 1 }, function (err) {
if (err.code > 0) {
print('MQTT SUBSCRIBE ERROR', err.code);
//TODO: Error handling
}
});
});
};
registerEventHandlers();
setInterval(function () {
if (client.canPublish()) {
var payload = [
{
"testProperty": 'Hello from NEQTO Device' // "property": '<DATA>'
}
];
var body = JSON.stringify({
"sensorAlternateId": sensorAlternateId,
"capabilityAlternateId": capabilityAlternateId,
"measures": payload
});
client.publish(pub_topic, body, { qos: 1 }, function (err) {
if (err.code == 0) {
print('Publish OK');
} else {
print('Publish failed');
//TODO: Error handling
}
});
} else {
print('Cannot publish');
}
}, 15000);
Sample 3
This is a sample to publish and subscribe using the client returned from the mqtt_sap
function, with manual reconnection. If the reconnects fail consecutively, the instance is released and recreated.
/*
<INSERT ABOVE SNIPPET HERE WITH SET CONFIGURATIONS>
*/
//=================================================================
log.setLevel(-1); //-1:NONE 0:ERROR 1:WARNING 2:DEBUG 3:TRACE
log.printLevel(2); //0:DISABLE 1:LOG 2:CONSOLE 3:BOTH
//=================================================================
// MAIN SCENARIO
//=================================================================
var sensorAlternateId = 5;
var capabilityAlternateId = 123456;
var sub_topic = `ack/${DEVICE_ALTERNATE_ID}`;
var pub_topic = `measures/${DEVICE_ALTERNATE_ID}`;
var client = mqtt_sap({
"clientId": DEVICE_ALTERNATE_ID.toString() // MANDATORY
});
if (!client) {
throw 'Failed to create mqtt instance';
}
var registerEventHandlers = function () {
var reconnectAttempts = 0;
var maxReconnectAttempts = 24;
if (!client) {
return;
}
client.on('error', function (err) {
print('ERROR: ' + err.code + ' ERRNO: ' + client.get('errnoConnect'));
if (err.code == 1) { //Connection failed
if (reconnectAttempts++ < maxReconnectAttempts) {
print('reconnectAttempts:', reconnectAttempts);
client.reconnect();
} else {
print('ABORT');
reconnectAttempts = 0;
client.end(); //Release mqtt instance
client = undefined;
}
}
});
client.on('message', function (topic, message) {
print('TOPIC: ' + topic + ' MESSAGE: ' + message);
//TODO: Message handling
});
client.on('close', function () {
print("DISCONNECTED");
client.reconnect();
});
client.on('connect', function () {
reconnectAttempts = 0;
print("CONNECTED");
client.subscribe(sub_topic, { qos: 1 }, function (err) {
if (err.code > 0) {
print("MQTT SUBSCRIBE ERROR", err.code);
//TODO: Error handling
}
});
});
};
registerEventHandlers();
setInterval(function () {
if (!client) {
print('Recreating MQTT Instance');
client = mqtt_sap({
"clientId": DEVICE_ALTERNATE_ID.toString() // MANDATORY
});
registerEventHandlers();
}
if (client) {
if (client.canPublish()) {
var payload = [
{
"testProperty": 'Hello from NEQTO Device' // "property": '<DATA>'
}
];
var body = JSON.stringify({
"sensorAlternateId": sensorAlternateId,
"capabilityAlternateId": capabilityAlternateId,
"measures": payload
});
client.publish(pub_topic, body, { qos: 1 }, function (err) {
if (err.code == 0) {
print('Publish OK');
} else {
print('Publish Failed');
//TODO: Error handling
}
});
}
} else {
print('Cannot Publish');
}
}, 15000);