Device Management

Use the REST API to manage edge devices and firmwares (PHP)

This Guide provides information on how to manage devices and firmwares.

When creating objects such as devices and firmwares using the REST API, it is important to ensure that valid combinations of property values are submitted. While the REST API does extensive validation on the server side, the calling code should always ensure that valid data is sent.

1. Basic Object Types

1.1. Device Object

An edge device that operates within the RIoT Secure Platform consists of two microcontrollers:

  • Application Microcontroller (up to four application microcontrollers are supported)
  • Core Microcontroller (modem)

Using two independently operating boards ensures a very high level of security and stability.

The Modem runs the RIoT Secure Core Firmware, which handles communication with the server cloud, and handles updates of the application firmware running on the application board.

The Application Microcontroller of the device has one up to four microcontrollers running Application Firmware.

The Device object in the server cloud maintains information about the core firmware and the application firmware that is deployed on the physical edge device.

The microcontroller sub-object of the device object holds the application firmware name.

Devices are owned by a Tenant.

The above components have representations in the REST API and can be accessed and updated using API calls.

1.2. Firmware Assets

The Core Firmware asset type contains the binary core firmware file. Core Firmware is a global asset type.

The Application Firmware asset type contains the binary application firmware file. Appication Firmware is an asset type owned by a Tenant.

1.3. Tenant Object

The Tenant Object represents the home for users, devices, and application firmwares. Deleting a tenant will delete all of these objects.

By comparison, Core Firmwares will not be deleted when deleting a tenant, since they are global assets.

2. Device Management Library

The code example discussed on this page use a PHP library for device and firmware management. This is an add-on to the REST API library.

The library handles operations on device objects and firmwares. There are functions for creating and deleting application firmwares and device objects. Devices and firmwares are intimately connected - firmware files require a device to execute on, and devices need firmware to operate.

There are two kinds of firmware: Core Firmware and Application Firmware. Core firmwares are managed by the platform administrator, while application firmwares are created and managed by tenant users. In this guide, the focus is on application firmware management.

The code for the device management library is in file tools/lib/device_lib.php. The REST API library file tools/lib/rest_api_lib.php must be included before this file.

Here is the code for the library (click to view):

Click to view device management library source code
File: tools/lib/device_lib.php

<?php
/*
Library of functions for managing devices and firmwares.

NOT for production use. Intended for educational purposes.
*/

require_once __DIR__ . "/rest_api_lib.php";

// --------------------------------------------------------------
// DEVICE FUNCTIONS
// --------------------------------------------------------------

/*
Example of call to device_create():

$network_settings           = new stdClass();
$network_settings->SSID     = "MY WIFI NAME";
$network_settings->password = "MY PASSWORD";

$gps_settings               = new stdClass();
$gps_settings->latitude     = "59.916675";
$gps_settings->longitude    = "18.950068";

$response = device_create(
    $tenant_id,
    "Test Device",                      // device_name,
    "MKR WiFi 1010",                    // modem_name,
    "RIoT Fusion Shield - Arduino UNO", // hardware_interface_name,
    "1_0_0_16-riot-MKRWIFI1010",        // firmware_core_name,
    "WiFi",                             // network_type,
    $network_settings,
    $gps_settings);
*/

// Create a new device object
// Return query response
function device_create(
  $tenant_id,
  $device_name,
  $modem_name,
  $hardware_interface_name,
  $firmware_core_name,
  $network_type,
  $network_settings = null,
  $static_gps_settings = null)
{
  // Find modem identifier
  $modem = modem_find($modem_name);
  $modem_identifier = $modem->keys->identifier;

  // Create device object and set fields
  $device_obj = new stdClass();
  $device_obj->keys = new stdClass();
  $device_obj->keys->name = $device_name;
  $device_obj->keys->modem = $modem_name;
  $device_obj->keys->identifier = $modem_identifier;
  $device_obj->keys->interface = $hardware_interface_name;
  $device_obj->keys->firmware_core = $firmware_core_name;
  $device_obj->keys->integration = false;
  $device_obj->keys->network = $network_type;

  // Set network fields ("Ethernet" network type has no settings)
  if ($network_type !== "Ethernet")
  {
    $device_obj->keys->settings = $network_settings;
  }

  // Set static GPS fields
  if (null !== $static_gps_settings)
  {
    $device_obj->keys->gps = $static_gps_settings;
  }

  $data = json_encode($device_obj);

  $response = rest_api_post(
    "/tenant/{$tenant_id}/device",
    $data,
    "application/json");

  return $response;
}

// Delete a device
// Return query response
function device_delete($tenant_id, $device_id)
{
  $response = rest_api_delete("/tenant/{$tenant_id}/device/{$device_id}");
  return $response;
}

// Download an install file for use with an SD card
// Return binary data
function device_download_sdupdate($tenant_id, $device_id)
{
  $response = rest_api_get("/tenant/{$tenant_id}/device/{$device_id}/download");
  return $response;
}

// Download an install sketch for use with the Arduino IDE
// Return binary data with a zip file
function device_download_installer_sketch($tenant_id, $device_id)
{
  $response = rest_api_get("/tenant/{$tenant_id}/device/{$device_id}/download_installer");
  return $response;
}

// Get device by id
// Return device object on success, or false on error
function device_get($tenant_id, $device_id)
{
  $response = rest_api_get_expand("/tenant/{$tenant_id}/device/{$device_id}");
  if (200 === rest_api_get_http_response_code())
  {
    return json_decode($response);
  }
  else
  {
    return false;
  }
}

// Return the device object with the given name (assumes device has unique name)
// Return false if not found
function device_find($tenant_id, $device_name)
{
  // Get all devices
  $response_json = rest_api_get_expand("/tenant/{$tenant_id}/device");
  if (200 !== rest_api_get_http_response_code())
  {
    return false;
  }

  $device_array = json_decode($response_json);

  foreach ($device_array as $device)
  {
    if ($device_name == $device->keys->name)
    {
      // Found device - return device object
      return $device;
    }
  }

  // Not found
  return false;
}

// $device_obj is a PHP object; it can be a partial
// device object that contains the keys to be updated
// Return query response on success, false on error
function device_update($tenant_id, $device_id, $device_obj)
{
  $data = json_encode($device_obj);

  $response = rest_api_put(
    "/tenant/{$tenant_id}/device/{$device_id}",
    $data,
    "application/json"
  );

  if (202 === rest_api_get_http_response_code())
  {
    return $response;
  }
  else
  {
    return false;
  }
}

// $device_obj is a PHP object; it can be a partial
// device object that contains the keys to be updated
// Return query response on success, false on error
function device_update_firmware_appl($tenant_id, $device_obj, $firmware_name, $microcontroller_index = 0)
{
  // Update firmware of the microcontroller with the given index
  $microcontroller_array = $device_obj->keys->microcontroller;
  $microcontroller_obj = $microcontroller_array[$microcontroller_index];
  $microcontroller_obj->firmware_appl = $firmware_name;

  // Create device update object that contains only the microcontroller array
  $device_new = new stdClass();
  $device_new->keys = new stdClass();
  $device_new->keys->microcontroller = $microcontroller_array;

  // For debugging
  //var_dump($device_new);

  // Update device
  $device_id = $device_obj->id;
  $response = device_update($tenant_id, $device_id, $device_new);

  return $response;
}

function device_time_last_connect($tenant_id, $device_id)
{
  $response_json = rest_api_get_expand("/tenant/{$tenant_id}/device/{$device_id}");
  $device = json_decode($response_json);
  return $device->info->ts_comms;
}

// --------------------------------------------------------------
// FIRMWARE FUNCTIONS
// --------------------------------------------------------------

// Create application firmware
// Return false on error
function firmware_appl_create(
  $tenant_id,
  $firmware_name,
  $firmware_microcontroller,
  $firmware_version,
  $firmware_description,
  $firmware_absolute_path)
{
  // Get microcontroller identifier
  $microcontroller = microcontroller_find($firmware_microcontroller);
  if (false === $microcontroller)
  {
    echo "[ERROR] firmware_appl_create: microcontroller not found" . PHP_EOL;
    return false;
  }
  $microcontroller_identifier = $microcontroller->keys->identifier;

  // Create handle to firmware file
  $firmware_file_handle = curl_file_create($firmware_absolute_path, "application/octet-stream");

  // Set POST data
  $post_data =
  [
    "name"            => $firmware_name,
    "microcontroller" => $firmware_microcontroller,
    "identifier"      => $microcontroller_identifier,
    "version"         => $firmware_version,
    "description"     => $firmware_description,
    "asset"           => $firmware_file_handle
  ];

  // Make the POST request to create the firmware object
  $response = rest_api_post(
    "/tenant/" . $tenant_id. "/firmware_appl",
    $post_data,
    "multipart/form-data");

  if (201 !== rest_api_get_http_response_code())
  {
    echo "[ERROR] firmware_appl_create: POST failed" . PHP_EOL;
    echo $response . PHP_EOL;
    return false;
  }
  else
  {
    return $response;
  }
}

// Delete application firmware
// Return true on success, false on error
function firmware_appl_delete($tenant_id, $firmware_name)
{
  // Make request to delete the firmware object
  rest_api_delete("/tenant/{$tenant_id}/firmware_appl/{$firmware_name}");
  if (204 === rest_api_get_http_response_code())
  {
    return true;
  }
  else
  {
    return false;
  }
}

// Get application firmware
// Return false on error or if firmware not found
function firmware_appl_get($tenant_id, $firmware_name)
{
  // Get firmware object
  $response = rest_api_get_expand(
    "/tenant/{$tenant_id}/firmware_appl/{$firmware_name}");
  if (200 === rest_api_get_http_response_code())
  {
    $firmware_obj = json_decode($response);
    return $firmware_obj;
  }
  else
  {
    return false;
  }
}

// --------------------------------------------------------------
// MODEM FUNCTIONS
// --------------------------------------------------------------

// Return the modem with the given name
// Return false if not found
function modem_find($modem_name)
{
  $response = rest_api_get_expand("/modem");
  $modem_array = json_decode($response);
  foreach ($modem_array as $modem)
  {
    if ($modem->keys->name === $modem_name)
    {
      return $modem;
    }
  }

  // Not found
  return false;
}

// --------------------------------------------------------------
// MICROCONTROLLER FUNCTIONS
// --------------------------------------------------------------

// Return the microcontroller with the given name
// Return false if not found
function microcontroller_find($microcontroller_name)
{
  $response = rest_api_get_expand("/microcontroller");
  $microcontroller_array = json_decode($response);
  foreach ($microcontroller_array as $microcontroller)
  {
    if ($microcontroller->keys->name === $microcontroller_name)
    {
      return $microcontroller;
    }
  }

  // Not found
  return false;
}

// It is considered best practice to not close the <?php tag
// in a PHP-only file.

Below follows several code examples that shows how to use the functions in the library. Developers can also tweak the library to their own needs.

3. Firmware Management

The following sections contain code examples that illustrate how to manage application firmwares by using GET, POST, and DELETE requests. (The application firmware object has type “asset”, which cannot be updated and therefore does not support PUT requests.)

Application firmwares belong to the tenant object, and application firmware routes are thus part of the tenant family of routes.

3.1. GET Application Firmwares

This a basic command-line tool that lists available application firmware assets:

File: guide/device_mgmt/firmware_appl_get.php

<?php
/*
File: firmware_appl_get.php

This example shows how to get a list of available application firmwares.

The returned JSON data is parsed and the firmware name and version is printed.

Usage:

    php firmware_appl_get.php LOGINFILE

Example:

    php firmware_appl_get.php mylogin.json
*/

require_once __DIR__ . "/../../tools/lib/rest_api_lib.php";

// Read config file with user credentials
if ($argc == 2)
{
  $login_config_file = $argv[1];

  // Read login file
  $config_path = get_absolute_path($login_config_file);
  rest_api_read_login_config($config_path);
}
else
{
  echo "USAGE" . PHP_EOL;
  echo "php firmware_appl_get.php LOGINFILE" . PHP_EOL;
  echo "EXAMPLE:" . PHP_EOL;
  echo "php firmware_appl_get.php mylogin.json" . PHP_EOL;
  die();
}

// Get a list of firmware objects
$tenant_id = rest_api_tenant_get_id();
$response_json = rest_api_get_expand("/tenant/{$tenant_id}/firmware_appl");
$firmware_array = json_decode($response_json);

// Print firmwares
echo "AVAILABLE APPLICATION FIRMWARES:\n";
foreach ($firmware_array as $firmware)
{
  echo "{$firmware->name} {$firmware->info->version} {$firmware->info->microcontroller}" . PHP_EOL;
}

Example:

Terminal Window: GET Application Firmwares

3.2. Create Application Firmware

This is a command-line tool used to create an new application firmware asset:

File: guide/device_mgmt/firmware_appl_create.php

<?php
/*
File: firmware_appl_create.php

This example uses the library file device_lib.php to create a new
application firmware asset.

Usage:

    php firmware_appl_create.php LOGINFILE FIRMWARENAME MICROCONTROLLER VERSION DESCRIPTION FIRMWAREPATH

Example:

    php firmware_appl_create.php mylogin.json BlinkTest ATmega328P "100.0.0.1" "LED Blink Test" Blink.ino.hex
*/

require_once __DIR__ . "/../../tools/lib/rest_api_lib.php";
require_once __DIR__ . "/../../tools/lib/device_lib.php";

// Set command params and read login config file
if ($argc == 7)
{
  $login_config_file        = $argv[1]; // absolute or relative path to config file
  $firmware_name            = $argv[2]; // firmware name
  $firmware_microcontroller = $argv[3]; // microcontroller name
  $firmware_version         = $argv[4]; // firmware version
  $firmware_description     = $argv[5]; // firmware description
  $firmware_file            = $argv[6]; // absolute or relative path of firmware file

  // Read login file
  $config_path = get_absolute_path($login_config_file);
  rest_api_read_login_config($config_path);
}
else
{
  echo "USAGE:" . PHP_EOL;
  echo "php firmware_appl_create.php LOGINFILE FIRMWARENAME MICROCONTROLLER VERSION DESCRIPTION FIRMWAREPATH" . PHP_EOL;
  echo "EXAMPLE:" . PHP_EOL;
  echo "php firmware_appl_create.php mylogin.json \"BlinkTest\" \"ATmega328P\" \"100.0.0.1\" \"LED Blink Test\" Blink.ino.hex" . PHP_EOL;
  die();
}

// Get tenant id
$tenant_id = rest_api_tenant_get_id();

// Get absolute path to application firmware file
$firmware_absolute_path = get_absolute_path($firmware_file);

$response = firmware_appl_create(
  $tenant_id,
  $firmware_name,
  $firmware_microcontroller,
  $firmware_version,
  $firmware_description,
  $firmware_absolute_path);

// Check response
if (201 === rest_api_get_http_response_code())
{
  $firmware_name = $response;
  echo "FIRMWARE CREATED: {$firmware_name}" . PHP_EOL;
}
else
{
  echo "ERROR: COULD NOT CREATE FIRMWARE" . PHP_EOL;
  if ($response)
  {
    echo $response . PHP_EOL;
  }
  if (rest_api_get_curl_errno() > 0)
  {
    echo "CURL ERROR: " . rest_api_get_curl_error() . " " . rest_api_get_curl_errno() . PHP_EOL;
  }
}

3.3. Delete Application Firmware

This is a command-line tool used to delete an application firmware asset:

File: guide/device_mgmt/firmware_appl_delete.php

<?php
/*
File: firmware_appl_delete.php

This example shows how to delete an application firmware entry
using the library file device_lib.php.

Usage:

    php firmware_appl_delete.php LOGINFILE FIRMWARENAME

Example:

  php firmware_appl_delete.php mylogin.json BlinkTest
*/

require_once __DIR__ . "/../../tools/lib/rest_api_lib.php";
require_once __DIR__ . "/../../tools/lib/device_lib.php";

// Set command params and read login config file
if ($argc == 3)
{
  $login_config_file = $argv[1]; // absolute or relative path to config file
  $firmware_name     = $argv[2]; // firmware name is the id of the firmware

  // Read login file
  $config_path = get_absolute_path($login_config_file);
  rest_api_read_login_config($config_path);
}
else
{
  echo "USAGE:" . PHP_EOL;
  echo "php firmware_appl_delete.php LOGINFILE FIRMWARENAME" . PHP_EOL;
  echo "EXAMPLE:" . PHP_EOL;
  echo "php firmware_appl_delete.php mylogin.json \"BlinkTest\"" . PHP_EOL;
  die();
}

// Get tenant id
$tenant_id = rest_api_tenant_get_id();

// Make request to delete the firmware object
$response = firmware_appl_delete($tenant_id, $firmware_name);

// Check response
if (204 === rest_api_get_http_response_code())
{
  echo "FIRMWARE DELETED: {$firmware_name}" . PHP_EOL;
}
else
{
  echo "ERROR: COULD NOT DELETE FIRMWARE" . PHP_EOL;
  echo $response . PHP_EOL;
}

3.4. GET Core Firmwares

Core firmwares are created by the system administrator, but tenants can access the list of core firmwares, as is illustrated by the following script:

File: guide/device_mgmt/firmware_core_get.php

<?php
/*
File: firmware_core_get.php

This example shows how to request a list available core firmwares.

Returned JSON data is printed in raw unparsed format.

Usage:

    php firmware_core_get.php LOGINFILE

Example:

    php firmware_core_get.php mylogin.json
*/

require_once __DIR__ . "/../../tools/lib/rest_api_lib.php";

// Read config file with user credentials
if ($argc == 2)
{
  $login_config_file = $argv[1];

  // Read login file
  $config_path = get_absolute_path($login_config_file);
  rest_api_read_login_config($config_path);
}
else
{
  echo "USAGE:" . PHP_EOL;
  echo "php firmware_core_get.php LOGINFILE" . PHP_EOL;
  echo "EXAMPLE:" . PHP_EOL;
  echo "php firmware_core_get.php mylogin.json" . PHP_EOL;
  die();
}

// Get a list of core firmwares
$response = rest_api_get("/firmware_core");

// Also try:
//$response = rest_api_get_expand("/firmware_core");

echo $response . PHP_EOL;

Example:

Terminal Window: GET Core Firmwares

4. Device Management

4.1. GET Devices

This example shows how to use a GET request to retrieve a list of devices as a JSON array, and then parse and access the data. The /tenant/{id}/device route is used to retrieve information about devices for the given tenant id.

File: guide/device_mgmt/device_get.php

<?php
/*
File: device_get.php

This example uses a GET request to obtain info about the
first available device.

The returned JSON data is parsed and printed.

Usage:

    php device_get.php LOGINFILE

Example:

    php device_get.php mylogin.json
*/

require_once __DIR__ . "/../../tools/lib/rest_api_lib.php";

// Read config file with user credentials
if ($argc == 2)
{
  $login_config_file = $argv[1];
  $config_path = get_absolute_path($login_config_file);
  rest_api_read_login_config($config_path);
}
else
{
  echo "USAGE:" . PHP_EOL;
  echo "php device_get.php LOGINFILE" . PHP_EOL;
  echo "EXAMPLE:" . PHP_EOL;
  echo "php device_get.php mylogin.json" . PHP_EOL;
  die();
}

// Get id:s of all devices (returns JSON array of ids)
$tenant_id = rest_api_tenant_get_id();
$response = rest_api_get("/tenant/{$tenant_id}/device");

// Convert JSON to PHP array
$device_array = json_decode($response);

// Print device info for each device
foreach ($device_array as $device_id)
{
  // Get device data (returns JSON object)
  $response = rest_api_get_expand("/tenant/{$tenant_id}/device/{$device_id}");

  // Convert JSON to PHP object
  $device_obj = json_decode($response);

  // Print selected device data
  $date = (null != $device_obj->info->ts_comms)
    ? (DateTime::createFromFormat('U', $device_obj->info->ts_comms))->format("Y-m-d H:i:s")
    : "Unknown";

  echo "-----------------------------------" . PHP_EOL;
  echo "DEVICE ID       : {$device_obj->id}" . PHP_EOL;
  echo "DEVICE NAME     : {$device_obj->keys->name}" . PHP_EOL;
  echo "LAST SEEN       : {$date}" . PHP_EOL;

  // Print data about first microcontroller
  if (null != $device_obj->keys->microcontroller)
  {
    $microcontroller = $device_obj->keys->microcontroller[0];
    echo "MICROCONTROLLER =>" . PHP_EOL;
    echo "  NAME          : {$microcontroller->name}" . PHP_EOL;
    echo "  IDENTIFIER    : {$microcontroller->identifier}" . PHP_EOL;
    echo "  FIRMWARE_APPL : {$microcontroller->firmware_appl}" . PHP_EOL;
  }
}

// It is considered best practice to not close the <?php tag
// in a PHP-only file.

Example:

Terminal Window: Devices

4.2. Create Device

This is a script with hard-coded parameters that creates a new device:

File: guide/device_mgmt/device_create.php

<?php
/*
File: device_create.php

This script is an example of how to automate device creation.

The script takes the device name as input and creates a device
with that name.

Usage:

    php device_create.php LOGINFILE DEVICENAME

Example:

    php device_create.php mylogin.json "TEST DEVICE"

Note that all device properties execpt for the device name are
hard-coded into the script. An alternative solution is to provide
a JSON config file with the device data.

You can use this example as an inspiration for production scripts.
*/

require_once __DIR__ . "/../../tools/lib/rest_api_lib.php";
require_once __DIR__ . "/../../tools/lib/device_lib.php";

// Read config file with user credentials
if ($argc == 3)
{
  $login_config_file = $argv[1];
  $device_name       = $argv[2];

  // Read login file
  $config_path = get_absolute_path($login_config_file);
  rest_api_read_login_config($config_path);
}
else
{
  echo "USAGE:" . PHP_EOL;
  echo "php device_create.php LOGINFILE DEVICENAME" . PHP_EOL;
  echo "EXAMPLE:" . PHP_EOL;
  echo "php device_create.php mylogin.json \"Test Device\"" . PHP_EOL;
  die();
}

// Get tenant id
$tenant_id = rest_api_tenant_get_id();

// TODO: Change the device settings below as needed,
// or add command-line paramemters to the script.

// Device settings

// Network settings
$network_settings           = new stdClass();
$network_settings->SSID     = "MY WIFI NAME";
$network_settings->username = ""; // Must be set even if empty
$network_settings->password = "MY PASSWORD";

// Static GPS position (may be set to null)
$gps_settings               = new stdClass();
$gps_settings->latitude     = "59.916675";
$gps_settings->longitude    = "18.950068";

// Alternatively, static GPS position may be set to null
//$gps_settings = null;

$response = device_create(
  $tenant_id,
  $device_name,                       // device_name,
  "MKR WiFi 1010",                    // modem_name,
  "RIoT Fusion Shield - Arduino UNO", // hardware_interface_name,
  "1_0_0_16-riot-MKRWIFI1010",        // firmware_core_name,
  "WiFi",                             // network_type,
  $network_settings,                  // network_settings
  $gps_settings                       // gps_settings
);

if (201 !== rest_api_get_http_response_code())
{
  echo "ERROR: COULD NOT CREATE DEVICE" . PHP_EOL;
  echo $response . PHP_EOL;
}
else
{
  echo "SUCCESS: DEVICE CREATED WITH ID: {$response}" . PHP_EOL;
}

4.3. Delete Device

This is a command-line tool for deleting a device:

File: guide/device_mgmt/device_delete.php

<?php
/*
File: device_delete.php

This script shows an example of how to delete a device.

Usage:

    php device_delete.php LOGINFILE DEVICENAME

Example:

    php device_delete.php mylogin.json "Test Device"

The script could easily be modified to take a device id as
parameter instead of the device name.
*/

require_once __DIR__ . "/../../tools/lib/rest_api_lib.php";
require_once __DIR__ . "/../../tools/lib/device_lib.php";

// Set command params and read login config file
if ($argc == 3)
{
  $login_config_file = $argv[1]; // absolute or relative path to config file
  $device_name       = $argv[2]; // name of device to delete

  // Read login file
  $config_path = get_absolute_path($login_config_file);
  rest_api_read_login_config($config_path);
}
else
{
  echo "USAGE:" . PHP_EOL;
  echo "php device_delete.php LOGINFILE DEVICENAME" . PHP_EOL;
  echo "EXAMPLE:" . PHP_EOL;
  echo "php device_delete.php mylogin.json \"Test Device\"" . PHP_EOL;
  die();
}

// Get tenant id
$tenant_id = rest_api_tenant_get_id();

// Get the device with trhe given name
$device = device_find($tenant_id, $device_name);
if (false === $device)
{
  echo "ERROR: COULD NOT FIND DEVICE WITH NAME: " . $device_name . PHP_EOL;
  die();
}

// Delete the device
$response = device_delete($tenant_id, $device->id);

// Check response
if (204 === rest_api_get_http_response_code())
{
  echo "DEVICE DELETED: {$device_name}" . PHP_EOL;
}
else
{
  echo "ERROR: COULD NOT DELETE DEVICE" . PHP_EOL;
  echo $response . PHP_EOL;
}