T-Mobile IoT Creators
Learn how to integrate Withthegrid platform with IoT Creators.

Connecting a device

In the following tutorial, temperature & humidity sensor Dragino - N95S31B will be connected to the platform.
How to connect a Dragino N95S31B via T-Mobile IoT creators to the Withthegrid monitoring platform.

Sending downlinks

Downlinks are way to send messages to the device. This could be an instruction to reset the device or change its reporting interval.

Register application URL

In order to be able to send commands to devices via IoT Creators API, we first need to register the application URL from previous tutorial as described in the IoT Creators documentation. In our case, the following request will return { "msg": "Success", "code": 1000 }, which means the request was successful.
curl -X PUT
--header 'Content-Type: application/json'
--header 'Accept: application/json'
--header 'Authorization: Basic <your Base64 encoded username:password>'
-d '{
"headers": {"authorization":"Basic <your Base64 encoded username:password>},
"url": "<your webhook URL>"
}' http://api.scs.iot.telekom.com/m2m/applications/registration

Create new commands

For more information refer to Command types.

Update the device type

In order to process a command, we need to extend the code we previously implemented. The way commands are processed and sent can be implemented in the corresponding device type. The following code will in case of a newCommand:
  • Optional: Verify a command is valid
  • Create a command-specific payload as defined by the Dragino - N95S31B documentation
  • Send downlink request with required payload to IoT Creators
  • Mark command as sent
  • Optional: update a device field with additional information (e.g. new reporting interval)
// define the hashIds of commands this device type is expected to handle
const setIntervalCommandHashId = 'TO DO';
const resetDeviceCommandHashId = 'TO DO';
// define the hashId of the reportType
// will be known at step 8
const reportTypeHashId = 'pd72ry';
// IoT Creators connection settings
const iotCreatorsBaseUrl = 'https://api.scs.iot.telekom.com/m2m/endpoints/';
// credential from https://portal.iotcreators.com/projects/<yourp_roject>/credentials as username:password to base64 with prefix Basic
const iotCreatorsToken = 'Basic <your Base64 encoded username:password>';
/**
* Handle is the required function. It has two overloads, one for incoming HTTP requests and one for internal events
* When this function is called for an incoming HTTP requests, the function should return information about the response
* that should be returned.
*/
function handle(args: ArgumentsForIncomingRequestEvent, exec: Exec): IncomingRequestResponse;
function handle(args: ArgumentsForEventWithoutResponse, exec: Exec): void;
function handle(args: Arguments, exec: Exec): IncomingRequestResponse | void {
if (args.event.type === 'incomingRequest' || args.event.type === 'newCommand' || args.event.type === 'deletedCommand' || args.event.type === 'commandDue') {
/**
* Filter commands and send commands
*/
sendCommands(exec, args, filterCommands(exec, args));
}
if (args.event.type === 'incomingRequest') {
const request = args.event.webRequest;
if (request.method === 'POST' && request.url.path === '/') {
if (args.device.supplierDeviceIdentifier === 'iot-creators-registration') {
return { statusCode: 204 };
}
// the device is submitting a condition report
if (request.body === undefined || request.body.type !== 'json') {
return {
statusCode: 400,
body: ['parameter_error', 'Body is not of type JSON'],
};
}
// Set receive timestamp
let generatedAt = new Date();
generatedAt.setMilliseconds(0);
// pass parsing of the report to the right report type parser
exec.parseReport({
reportTypeHashId,
payload: JSON.stringify({
generatedAt,
payload: request.body.data,
}),
});
return { statusCode: 204 };
}
return {
statusCode: 404,
body: ['not_found_error', 'Route cannot be found'],
};
}
}
function filterCommands(exec: Exec, args: Arguments): Command[] {
const scheduledCommands = args.scheduledCommands.filter((sC) => {
let endOfCommand: Date | undefined;
if (sC.endAt !== null) {
endOfCommand = sC.endAt;
} else if (sC.startAt !== null) {
endOfCommand = sC.startAt;
} else if (sC.sentAt !== null) {
endOfCommand = new Date(sC.sentAt.valueOf() + sC.delay * 1000);
}
if (endOfCommand !== undefined && endOfCommand.valueOf() <= Date.now()) {
// drop and do not send commands scheduled in the past
exec.addLog(sC.hashId);
exec.dropCommand(sC.hashId);
return false;
}
if (sC.sentAt === null && sC.deletedAt !== null) {
// drop and do not send commands that were deleted before they were sent.
exec.dropCommand(sC.hashId);
return false;
}
return true;
});
return scheduledCommands;
}
function sendCommands(exec: Exec, args: Arguments, scheduledCommands: Command[]) {
scheduledCommands.forEach((sC) => {
let payload: string;
let requestbody: string;
let url: string;
// complete serialnumber of the device, including eventual leading "IMEI:" prefix.
let deviceId: string = 'IMEI:'+args.device.supplierDeviceIdentifier;
exec.addLog("Commande Type hash id = " + sC.commandTypeHashId);
if (sC.commandTypeHashId === setIntervalCommandHashId && sC.fields !== null) {
// Set Reporting Interval command
if (typeof sC.fields.interval !== 'number') {
throw new Error(`interval is a ${typeof sC.fields.interval}`);
}
// exec.setDeviceFields([{ key: 'reportInterval', value: <FieldToServerFull>sC.fields.interval }]);
payload = createHexString(1, 2) + createHexString(sC.fields.interval, 6);
payload = exec.uInt8ArrayToBase64(hexToBytes(payload));
requestbody = '{"resourceValue" : "' + payload + '"}';
url = iotCreatorsBaseUrl + deviceId + "/downlinkMsgBase64/0/data";
} else if (sC.commandTypeHashId === resetDeviceCommandHashId) {
// Reset device command
payload = "04ff";
payload = exec.uInt8ArrayToBase64(hexToBytes(payload));
requestbody = '{"resourceValue" : "' + payload + '"}';
url = iotCreatorsBaseUrl + deviceId + "/downlinkMsgBase64/0/data";
} else {
throw new Error(`Cannot parse commandTypeHashId ${sC.commandTypeHashId}`);
}
const header = {
"Authorization": iotCreatorsToken,
"Content-Type": "application/json",
"Content-Length": "" + requestbody.length,
"Host": "api.scs.iot.telekom.com"
}
let response = exec.sendRequest({ url: url, method: "put", body: requestbody, headers: header });
if (response === null || response.statusCode < 200 || response.statusCode > 299) {
throw new Error(`Schedule downlink failed with code ${response?.statusCode}`);
}
exec.markCommandAsSent(sC.hashId);
});
}
function createHexString(value: any, width: number): string {
if (value === null || width === null) {
throw new Error("Create Hex String failed!");
}
value = value.toString(16);
width -= value.length;
if (width > 0) {
return new Array(width + (/\./.test(value) ? 2 : 1)).join('0') + value;
}
return value;
}
function hexToBytes(hex: string): Uint8Array {
for (var bytes = [], c = 0; c < hex.length; c += 2)
bytes.push(parseInt(hex.substr(c, 2), 16));
return Uint8Array.from(bytes);
}
Copy link
On this page
Connecting a device
Sending downlinks
Register application URL
Create new commands
Update the device type