Accessing Asset data from Everyware Cloud 4

This guide shows how to interact with a Asset instances available on an ESF device using the Everyware Cloud 4 /devices/sendRequest REST API.

Everyware Cloud 5 offers more user friendly REST APIs than /devices/sendRequest to perform operations on the Assets available on a device, and also allows to perform such operations directly from the Web console.

The /devices/sendRequest REST API allows to interact directly with the request handlers on the device. Request handlers (or Cloudlets) are ESF components that allow to perform operations on the device remotely, transferring requests and responses from/to the cloud platform.

In order to interact with the Assets on the device, the ASSET-V1 request handler should be used.
A description of the protocol used by ASSET-V1 is available in ESF documentation.

ASSET-V1 requests and responses are specified using the JSON format. In order to include them in /devices/sendRequest request and responses, they are encoded in base64 and inserted into sendRequest message body.

The shell script below illustrates the required encoding/decoding steps, it accepts as parameters the ASSET-V1 resource (an URL-like string that identifies the operation to be performed) and the ASSET-V1 JSON request, and prints the received response on the standard output.

The script uses the curl binary for transferring the requests and the xmllint binary to extract information from the responses returned by the cloud.
The ACCOUNT_NAME, PASSWORD and TARGET_CLIENT_ID variables must be modified and filled with own credentials.

#!/bin/sh

ENDPOINT="https://api-sandbox.everyware-cloud.com/v2/devices/sendRequest.xml"   # for sandbox instance
# ENDPOINT="https://api.everyware-cloud.com/v2/devices/sendRequest.xml"         # for production instance

ACCOUNT_NAME=""                   # enter your account name here
USER_NAME=${ACCOUNT_NAME}         # enter your user name here
PASSWORD=""                       # enter your password here
TARGET_CLIENT_ID=""               # enter the client id of the target device

# ASSET-V1 namespace resource expected as first argument
ASSET_V1_RESOURCE=$1
# ASSET-V1 namespace request expected as second argument
ASSET_V1_REQUEST=$2


if ! [[ ${ASSET_V1_REQUEST} == "" ]]
then
  # encode the request in base64
  BODY=$(echo ${ASSET_V1_REQUEST} | base64)

  # EDC /devices/sendRequest request
  # It must include the ASSET-V1 full request topic and the request
  # in the body, encoded in base64
  REST_MESSAGE="<?xml version=\"1.0\" encoding=\"UTF-8\"?>
  <message xmlns=\"http://eurotech.com/edc/2.0\">
    <topic>\$EDC/${ACCOUNT_NAME}/${TARGET_CLIENT_ID}/ASSET-V1/${ASSET_V1_RESOURCE}</topic>
    <payload>
      <body>${BODY}</body>
    </payload>
  </message>"
else
  # EDC /devices/sendRequest request
  # If the request body is empty, it is enough to specify the topic only
  REST_MESSAGE="<?xml version=\"1.0\" encoding=\"UTF-8\"?>
  <message xmlns=\"http://eurotech.com/edc/2.0\">
    <topic>\$EDC/${ACCOUNT_NAME}/${TARGET_CLIENT_ID}/ASSET-V1/${ASSET_V1_RESOURCE}</topic>
  </message>"
fi

REST_RESPONSE=$(curl --data "${REST_MESSAGE}" \
          --user "${USER_NAME}:${PASSWORD}" \
          -H "Accept: application/xml" \
          -H "Content-Type: application/xml" \
          -X POST \
          ${ENDPOINT})

RESULT=$?

if [ ${RESULT} -ne 0 ]; then
  echo "request failed, response"
  echo ${REST_RESPONSE}
  exit ${RESULT}
fi

# helper function for extracting elements from the received XML response
# using the xmllint tool and xpath selectors
# removes the XML namespace in order to use simpler selectors
extract() {
  # xpath selector is expected as first argument
  SELECTOR=$1
  sed 's/xmlns=".*"//g' | xmllint -xpath ${SELECTOR} - 2> /dev/null
}

# print raw response
# echo ${REST_RESPONSE}
# pretty print response
# echo ${REST_RESPONSE} | xmllint --format -

# extract response code, it is the value of the response.code metric
RESPONSE_CODE=$(echo ${REST_RESPONSE} | extract "//metric/name[text()=\"response.code\"]/following-sibling::value/text()")
# extract and decode the response, it is encoded in base64 in the response body
RESPONSE_BODY=$(echo ${REST_RESPONSE} | extract "/edcResponsePayload/body/text()" | base64 -D)

echo "=============== response code ==============="
echo ${RESPONSE_CODE}
echo "=============== response      ==============="
echo ${RESPONSE_BODY}

The script below performs the example requests shown in the guide about the ASSET-V1 protocol using the previous script.
It assumes that the previous script is saved in the same folder and named sendrequest-asset.sh.

#!/bin/sh

# get the list of assets on a device

ASSET_V1_RESOURCE="GET/assets"
ASSET_V1_REQUEST=""

./sendrequest-asset.sh "${ASSET_V1_RESOURCE}" "${ASSET_V1_REQUEST}"

# get information about the channels defined on specific assets

ASSET_V1_RESOURCE="GET/assets"
ASSET_V1_REQUEST="[
  {
    \"name\": \"asset1\"
  },
  {
    \"name\": \"otherAsset\"
  }
]"

./sendrequest-asset.sh "${ASSET_V1_RESOURCE}" "${ASSET_V1_REQUEST}"

# read channel data

ASSET_V1_RESOURCE="EXEC/read"
ASSET_V1_REQUEST="[
  {
    \"name\": \"asset1\",
    \"channels\": [
      {
        \"name\": \"channel1\"
      },
      {
        \"name\": \"channel2\"
      },
      {
        \"name\": \"otherChannel\"
      }
    ]
  },
  {
    \"name\": \"otherAsset\"
  }
]"

./sendrequest-asset.sh "${ASSET_V1_RESOURCE}" "${ASSET_V1_REQUEST}"

# write channel data

ASSET_V1_RESOURCE="EXEC/write"
ASSET_V1_REQUEST="[
  {
    \"name\": \"asset1\",
    \"channels\": [
      {
        \"name\": \"first_channel\",
        \"type\": \"INTEGER\",
        \"value\": \"432\"
      },
      {
        \"name\": \"second_channel\",
        \"type\": \"BOOLEAN\",
        \"value\": \"true\"
      },
      {
        \"name\": \"binary_channel\",
        \"type\": \"BYTE_ARRAY\",
        \"value\": \"dGVzdCBzdHJpbmcK\"
      }
    ]
  }
]"

./sendrequest-asset.sh "${ASSET_V1_RESOURCE}" "${ASSET_V1_REQUEST}"