NAV Navbar
Logo
javascript python (2.x)

Introduction

The sensemetrics API provides direct access to device and sensor information, as well as raw and processed observation data that exist in our Cloud application or your Enterprise server.

We use the socket protocol to establish and authenticate all API requests and provide a two-way, real-time data connection between your client and our server.

We have included working code samples in JavaScript and Python (2.x) to demonstrate our API in action. You are not limited to using Javascript or Python in your application and can use any language that supports sockets.

Authentication

Our API uses API keys to authenticate socket connections. You can generate and view your unique API key by doing the following:

  1. Log in to our Cloud application (app.sensemetrics.com) or your Enterprise server.
  2. Navigate to Settings by clicking the gear icon at the top right.
  3. Select Account from the left-side menu to view or re-generate your API key.

API keys do not expire, however you can re-generate your key if you believe the old one has been compromised.

Also note that your API key will allow you to access only the objects and data that is accessible to you within our Cloud application or your Enterprise server. Our API cannot be used to modify access permissions at this time.

Managing Connections

Opening a Connection

Open and authenticate a new socket connection, listen for messages and events:

var socket,
    connected,
    authenticating,
    nextId = 0,
    host = "app.sensemetrics.com",
    port = 4201,
    apiKey = "YourAPIKey";

// Open a new socket connection
socket = new WebSocket("wss://" + host + ":" + port + "/");

// Listen for socket open events
socket.onopen = function(event) {

    console.log("Socket opened with " + host + ":" + port);

    // Perform socket authentication
    authenticating = true;
    sendRequest("authenticate", {
        "code": apiKey
    }, function(result) {

        console.log("Authentication successful");

        // Save the next request id
        nextId = result.nextId;

        // Set connection flags
        connected = true;
        authenticating = false;
    });
};

// Listen for socket close events
socket.onclose = function() {

    console.log("Socket closed");

    // Set connection flags
    connected = authenticating = false;

    // Clear the socket object and reset request id
    socket = undefined;
    nextId = 0;
};

// Listen for socket messages
socket.onmessage = function(event) {
    onMessage(event.data);
};
import socket, json
from dateutil import parser

host = "app.sensemetrics.com"
port = 4200
apiCode = "YourAPIKey"

# Open a new socket connection
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))

# Send the authentication request
handshake = json.dumps({
    "jsonrpc": "2.0",
    "method": "authenticate",
    "params": {
        "code" : apiCode
    },
    "id": 0
})
s.send(handshake)

# Parse the response
jsonFrame = decodeOneJsonFrame(s)
response = json.loads(jsonFrame)
print("\r\nHandshake Exchange:\r\n" + "     --> " + handshake + "\r\n" + "     <-- " + jsonFrame)

# Close the socket connection
s.close()

Our API is built on the JSON-RPC 2.0 specification, a simple and lightweight remote procedure call protocol.

Its general mechanism consists of two peers establishing a data connection. During the lifetime of a connection, peers may invoke methods provided by the other peer. To invoke a remote method, a request is sent. Unless the request is a notification, it must be replied to with a response.

Before using any API calls, you must establish and authenticate a socket connection between your client and our server using your unique API key.

You will need the following to open a connection:

Parameter Example Description
host app.sensemetrics.com The URL of the server that you are connecting to.
port 4201 The socket connection port. Should be 4201 for WebSocket connections and 4200 for all other socket connections.
code A8345HJBWW45939KUIYB Your unique API key.

After the connection has been established and authenticated, you can begin sending API requests and receiving responses from the server.

Sending Requests

A generic function for sending requests via a socket:

var callbacks = {}

function sendRequest(request, params, callback) {

    // Get the request id to use
    var requestId = nextId;

    // Send the request message
    socket.send(JSON.stringify({
        "jsonrpc": "2.0",
        "method": request,
        "id": requestId,
        "params": params
    }));

    // Save the response callback for later
    callbacks[requestId] = callback;

    // Increment the id for future requests
    nextId++;

    return requestId;
};
callbacks = {}

def sendRequest(request, params, callback):

    # Get the request id to use
    requestId = nextId

    # Send the request message
    socket.send(json.dumps({
        "jsonrpc": "2.0",
        "method": request,
        "id": requestId,
        "params": params
    }))

    # Save the response callback for later
    callbacks[requestId] = callback

    # Increment the id for future requests
    nextId = nextId + 1

    return requestId;

Once a connection has been established and authenticated, you can begin to send requests to our server.

Each request should be in valid JSON format and contain the following properties:

Property Example Description
jsonrpc 2.0 The JSON-RPC protocol version. We use version 2.0.
method getSensors The name of the API request being sent.
id 5 The sequential API request id.
params {"sensors": ["sensorId1"]} Any required or optional API request parameters.

The method and params fields will change depending on the API request being performed. Some API requests have required parameters, others have optional parameters.

The numeric id field should be sequentially incremented with each new API request. When you authenticate a new connection, the response will contain a nextId field that should become the starting id for all future requests through that connection.

The responses you will receive from our server will include the original request id, allowing you to correctly route response messages to their request callbacks.

Receiving Responses

A generic function for processing socket responses:

function onMessage(message) {

    // Parse the JSON message body
    var response = JSON.parse(message);

    if ("result" in response) {

        // Request succeeded without errors
        callbacks[response.id](response.result);

    } else if ("error" in response) {

        // Request resulted in an error
        if ("id" in response) {

            // Send error information to original callback for handling
            callbacks[response.id](response.error);

        } else {

            // Log all other socket errors
            console.error("Received API error message: ", response.error);
        }
    }
};
# Gets one JSON frame from the TCP stream
# Extremely slow and not reliable, shown for example only
def decodeOneJsonFrame(socket):
    frame = ""
    count = 0
    while True:
        byte = socket.recv(1)
        if byte == "{":
            count = count + 1
        elif byte == "}":
            count = count - 1
        frame = frame + byte
        if count == 0:
            return frame;

API responses which you receive back from the server will be in JSON format and will contain a data object with the following properties:

Property Example Description
id 5 The id of the original API request. Can be used for routing responses to their request callbacks.
result {...} The data returned by the API response. The contents of this will depend on the original API request.
error {...} If the API request resulted in error, this optional field will contain the error code and information.

Working With Entities

Introduction

Example connection (node) object:

{
    "id": "/fn/6C4F6D/node",
    "type": "THREAD",
    "props": {
        "ACCESSIBLE": true,
        "DEVICE_GROUP": "/fn/6C4F6D/node",
        "GATEWAY": "/fn/6B652F/node",
        "LAST_COMM": "2016-10-18T22:26:24.818Z",
        "LOCATION": {
            "coordinates": [
                -53.900861,
                30.602073
            ]
        },
        "NAME": "North Sector THREAD #1",
        "OBSERVATION_COUNT": 16521,
        "POWER_MODE": "HIGH_POWER"
    }
}

Example device object:

{
    "id": "/fn/6C4F6D/node/dgsimlogger/032432/device",
    "type": "DGSI_M_LOGGER",
    "props": {
        "ACCESSIBLE": true,
        "EXTERNAL_PORT": 1,
        "LAST_OBSERVATION": {
            "timestamp": "2016-06-24T18:01:00.000Z"
        },
        "LOCATION": {
            "coordinates": [
                -53.900861,
                30.602073,
                -17.24
            ]
        },
        "MODE": "IPI_BIAXIAL",
        "NAME": "North Sector Logger 2",
        "NODE_ID": "/fn/6C4F6D/node",
        "OBSERVATION_COUNT": 8832,
        "SAMPLING_RATE_MAX": 0.0011111111111111111,
        "SENSOR_GROUP": "/fn/6C4F6D/node/dgsimlogger/032432/device",
        "SIZE": 4,
        "ZERO_DATE": "2016-03-22T07:00:00.000Z"
    }
}

Example sensor object:

{
    "id": "/fn/6C4F6D/node/dgsimlogger/032432/device/tilt4/sensor",
    "device": "/fn/6C4F6D/node/dgsimlogger/032432/device",
    "type": "TILT_BIAXIAL_DGSI",
    "props": {
        "ACCESSIBLE": true,
        "LAST_OBSERVATION": {
            "sensorId": "/fn/6C4F6D/node/dgsimlogger/032432/device/tilt4/sensor",
            "timestamp": "2016-06-24T18:01:00.000Z",
            "values": [
                -0.20226,
                0.17345,
                0.70659
            ]
        },
        "LOCATION": {
            "coordinates": [
                -53.900861,
                30.602073,
                -17.24
            ]
        },
        "MUX_INDEX": 4,
        "NAME": "North Sector Tilt 2-2",
        "NODE_ID": "/fn/6C4F6D/node",
        "OBSERVATION_COUNT": 2208,
        "SAMPLING_RATE_MAX": 0.0011111111111111111,
        "SIZE": 4,
        "ZERO_DATE": "2016-03-22T07:00:00.000Z"
    }
}

A sensemetrics network consists of a hierarchy of connections (also called nodes), devices and sensors. Together, we often refer to these objects as entities:

Type Example Description
connection (node) THREAD Establishes a connection to a data source or collects data from devices & sensors.
device DGSI M Logger A physical device that provides connectivity to sensors or a representation of groups of sensors.
sensor Biaxial Tilt A single physical sensor capable of recording observations.

All entities always exist in a network in a hierarchical structure:

Each entity object will typically include the following properties:

Property Example Description
id /fn/6C4F6D/node The unique id of the entity in the network. Used for retrieving, subscribing to and modifying entities.
type DGSI_M_LOGGER The type of the connection, device or sensor.
props {...} An object containing key/value pairs with configuration parameters for the entity.

API Requests

The following example illustrates retrieving a sensor object from the server and subscribing to its updates:

var sensor,
    sensorId = "/fn/6C4F6D/node/dgsimlogger/032432/device/tilt4/sensor",
    subscriptionId;

// Retrieve sensor from the server
sendRequest("getSensors", {
    "sensors": [sensorId]
}, function(result) {

    if (result.length > 0 && result[0].id === sensorId) {

        // Sensor retrieved, subscribe to its updates
        sensor = result[0];
        subscriptionId = sendRequest("subscribeSensors", {
            "sensors": [sensorId]
        }, function(updates) {

            if ("data" in updates) {

                // Update the local sensor object
                sensor = updates.data;
            }
        });

    } else {

        // Sensor could not be retrieved
        console.error("Error retrieving sensor", sensorId, ":", result);
    }
});
nextId = nextId + 1
sensor = {}
sensorId = "/fn/6C4F6D/node/dgsimlogger/032432/device/tilt4/sensor"

# Retrieve sensor object from server
s.send(json.dumps({
    "jsonrpc": "2.0",
    "method": "getSensors",
    "id": nextId,
    "params": {
        "sensors" : [sensorId]
    }
}))

# Decode server response
response = json.loads(decodeOneJsonFrame(s))
firstSensorId = response["result"][0]["id"]
if firstSensorId == sensorId:

    # Save sensor object locally
    sensor = response["result"][0]

    # Subscribe to sensor updates
    nextId = nextId + 1
    s.send(json.dumps({
        "jsonrpc": "2.0",
        "method": "subscribeSensors",
        "id": nextId,
        "params": {
            "sensors" : [sensorId]
        }
    }))

    # Handle incoming updates asynchronously
    while True:

        # Decode response
        response = json.loads(decodeOneJsonFrame(s))

        # Store the incoming observations
        if "data" in response["result"]:
            sensor = response["result"]["data"]

Several API requests are available to retrieve, subscribe to, modify, and create entities:

Type Example Description
retrieval getNodes
getDevices
getSensors
Retrieves all connection, device or sensor objects in their current state that match your query parameters.
subscriptions subscribeNodes
subscribeDevices
subscribeSensors
Establishes a subscription to any changes in the state of specified connections, devices or sensors. You will receive a new response message when any of the configuration parameters change. Returned subscriptionId can be used to later unsubscribe from updates.
subscription terminations unsubscribeNodes
unsubscribeDevices
unsubscribeSensors
Unsubscribe from updates using the subscriptionId returned by the subscription API request.
modification updateNode
updateDevice
updateSensor
Overwrite existing configuration parameters of a single connection, device or sensor.
creation createNode
createDevice
createSensor
Creates node, device or sensor in the sensemetrics platform. If the node, device or sensor already exists, this will return an error. See the entity object example above.

Creating Entities

Creates a connection (node), device or sensor in the sensemetrics platform. If the connection, device or sensor already exists, an error will be returned.

Create Node

Example createNode request/response:

{
   "jsonrpc": "2.0",
   "method": "createNode",
   "id": "2",
   "params": {
      "node": "/fn/02DDXX/node",
      "type": "THREAD",
      "props": {
         "NAME": "Sample thread",
         "SERIAL_NO": "02DDXX",
         "VERSION": "v4_6"
      }
   }
}

{
   "jsonrpc": "2.0",
   "id": 2,
   "result": {
      "id": "/fn/02DDXX/node",
      "type": "THREAD",
      "props": {
         "NAME": "Sample thread",
         "NODE_ID": "/fn/02DDXX/node",
         "ACCESSIBLE": true
      }
   }
}
Property Example Description
method createNode The name of method.
id 2 The sequential API request id.
params.node /fn//node/ The connection id to be created, the example format should be followed.
params.type THREAD The connection type.
params.props.SERIAL_NO 022DDXX Serial number of the connection.
params.props.VERSION v4_6 Version of the client software. Required field.

Create Device

Example createDevice request/response:

{
   "jsonrpc": "2.0",
   "method": "createDevice",
   "id": "3",
   "params": {
      "device": "/fn/02DDC5/node/demo/032432/device",
      "type": "DEMO",
      "props": {
         "NAME": "Demo device",
         "NODE_ID": "/fn/02DDC5/node"
      }
   }
}

{
   "jsonrpc": "2.0",
   "id": 3
   "result": {
      "id": "/fn/02DDC5/node/demo/032432/device",
      "type": "DEMO",
      "props": {
         "NAME": "Demo device",
         "NODE_ID": "/fn/02DDC5/node",
         "ACCESSIBLE": true
      }
   }
}
Property Example Description
method createDevice The name of method.
id 3 The sequential API request id.
params.device /fn/02DDC5/node/demo/032432/device/ The device id to be created, the example format should be followed.
params.type DEMO The device type.
params.props.NODE_ID 022DDXX Connection id to which this device should be attached. Required field.
params.props.NAME Demo device Name of the device.

Create Sensor

Example createSensor request/response:

{
   "jsonrpc": "2.0",
   "method": "createSensor",
   "id": "4",
   "params": {
      "sensor": "/instantel/3E216E/node/demo_sensor/UM9169/device/demo-1/sensor",
      "observationType": "DEMO_SENSOR",
      "type": "DEMO_SENSOR",
      "props": {
         "NAME": "Demo Sensor"
      }
   }
}

{
   "jsonrpc": "2.0",
   "id": 4
   "result": {
      "type": "DEMO_SENSOR",
      "device": "/instantel/3E216E/node/demo_sensor/UM9169/device",
      "id": "/instantel/3E216E/node/demo_sensor/UM9169/device/demo-1/sensor",
      "props": {
         "ACCESSIBLE": true,
         "SERIAL_NO": "UM9169",
         "NODE_ID": "/instantel/3E216E/node",
         "NAME": "Demo Sensor"
      }
   }
}
Property Example Description
method createSensor The name of method.
id 4 The sequential API request id.
params.sensor /instantel/3E216E/node/demo_sensor/UM9169/device/demo-1/sensor/ The sensor id to be created, the example format should be followed.
params.type DEMO_SENSOR Observation/Sensor type.
params.observationType DEMO_SENSOR Observation/Sensor type.
params.props.NAME Demo Sensor Name of the sensor.

Working with Observations

Introduction

Example data series:

{
    "2016-12-15T23:38:07.000Z": 77.53769759239933,
    "2016-12-16T07:13:07.000Z": 77.79861178632439,
    "2016-12-29T01:26:04.000Z": 77.68848770690741
}

Each sensor in the network is capable of recording observations that are stored on the server.

Observations are recorded and stored as raw numerical values in the sensor’s native metrics and units. The raw observations can often be converted to various derivative metric & unit combinations and retrieved via the API.

Each retrieved data point will be an object with the key representing the observation time stamp and the value representing the observation value:

Property Example Description
key 2016-12-15T23:38:07.000Z The time stamp of the data point, in ISO date format.
value 77.9759239933 The observation value in the metric & unit specified by the API request parameters.

If your API request found multiple observations that match your query parameters, they will be returned as a single object with the keys representing the timestamps of the observations.

Metrics

The following example illustrates retrieving metrics and units for a specific sensor:

var allMetrics = [],
    allUnits = {},
    sensorId = "/fn/6C4F6D/node/dgsimlogger/032432/device/tilt4/sensor";

// Retrieve metrics for this sensor
sendRequest("getMetrics", {
    "sensors": [sensorId]
}, function(result) {
    if (!("code" in result) && sensorId in result) {

        // Save all metrics
        allMetrics = result[sensorId];
        var firstMetric = allMetrics[0].id;

        // Retrieve units for first available metric
        sendRequest("getUnits", {
            "metrics": [firstMetric]
        }, function(result) {

            // Save the retrieved units
            allUnits[firstMetric] = result[firstMetric];
        });

    } else {
        console.warn('Error retrieving metrics:', result);
    }
});
nextId = nextId + 1
allMetrics = []
allUnits = {}
sensorId = "/fn/6C4F6D/node/dgsimlogger/032432/device/tilt4/sensor"

# Retrieve metrics for this sensor
s.send(json.dumps({
    "jsonrpc": "2.0",
    "method": "getMetrics",
    "id": nextId,
    "params": {
        "sensors" : [sensorId]
    }
}))

# Decode server response and save the metrics
response = json.loads(decodeOneJsonFrame(s))
allMetrics = response["result"][sensorId]
firstMetric = allMetrics[0]["id"]

# Retrieve the units for the first metric
nextId = nextId + 1
s.send(json.dumps({
    "jsonrpc": "2.0",
    "method": "getUnits",
    "id": nextId,
    "params": {
        "metrics" : [firstMetric]
    }
}))

# Decode server response and save the units
response = json.loads(decodeOneJsonFrame(s))
allUnits[firstMetric] = response["result"][firstMetric]

Example metric object:

{
    "defaultUnit": "m",
    "displayName": "∆ X",
    "id": "dx",
    "name": "displacement X",
    "notation": "∆x",
    "params": [
        {
            "id": "dt",
            "mandatory": false
        }, {
            "id": "START_DATE",
            "mandatory": false
        }, {
            "id": "END",
            "mandatory": false
        }, {
            "id": "ZERO_DATE",
            "mandatory": false
        }
    ]
}

Example unit object:

{
    "id": "m",
    "name": "meter",
    "notation": "m"
}

Before requesting observation data for a sensor, you must know the metrics and units applicable to that sensor.

All sensors have a set of raw metrics & units that are used to record raw observations output by the sensor. Many sensors also have derivative metrics & units that can be calculated from the sensor’s raw observations.

You can retrieve the metrics and units for each sensor using the following API requests:

Request Params Description
getRawMetrics “sensors” [array]
“types” [array]
Retrieves available raw metrics for an array of sensor id’s or sensor types. You will typically use the getMetrics API request described below in favor of this one.
getMetrics “sensors” [array] Retrieves all available metrics for an array of sensor id’s.
getUnits “metrics” [array] Retrieves all available units for an array of metric id’s.

Metric Parameters

Example metric parameters specifying reference date and sensor azimuth:

{
    "AZIMUTH_XY": {
        "value": 90
    },
    "ZERO_DATE": {
        "value": "2017-03-01T22:00:00.000Z"
    }
}

As mentioned above, derivative metrics & units are calculated from the sensor’s raw observation readings.

Some derivative metrics have required or optional parameters that can be used to fine-tune how these metrics are calculated. These parameters will be included in the params property within each metric object retrieved via the getRawMetrics or getMetrics API requests.

Each calculation parameter will be an object with the following properties:

Property Example Description
id ZERO_DATE The unique id of the metric parameter.
mandatory false Whether this metric parameter is required for the metric to be calculated correctly.

Retrieving Data

The following example illustrates retrieving data for a specific sensor:

var sensorId = "/fn/6C4F6D/node/dgsimlogger/032432/device/tilt4/sensor",
    metricId = "dx",
    unitId = "m";

// Create a local data object
var series = {
    id: sensorId,
    metric: metricId,
    data: {}
};

// Create a set of parameters for data retrieval
var retrievalParams = {
    "sensor": sensorId,
    "metric": metricId,
    "unit": unitId,
    "params": {
        "ZERO_DATE": {
            "value": "2017-03-01T22:00:00.000Z"
        }
    },
    "startDate": "2017-01-01T23:17:10.305Z",
    "endDate": "2017-01-20T23:17:10.305Z"
};

// Retrieve data from the server
sendRequest("getData", retrievalParams, function(result) {

    if ("requestStatus" in result && result.requestStatus === "finished") {

        // Data retrieval finished

    } else if ("data" in result) {

        // Save each data point locally
        for (var date in result.data) {
            if (result.data.hasOwnProperty(date)) {
                series.data[date] = result.data[date];
            }
        }

    } else if ("code" in result) {
        console.error("Error retrieving data with params", params, ":", result);
    }
});
nextId = nextId + 1
metricId = "dx"
unitId = "m"
sensorId = "/fn/6C4F6D/node/dgsimlogger/032432/device/tilt4/sensor"

# Create a local data object
series = {
    "id": sensorId,
    "metric": metricId,
    "data": {}
}

# Create a set of parameters for data retrieval
retrievalParams = {
    "sensor": sensorId,
    "metric": metricId,
    "unit": unitId,
    "params": {
        "ZERO_DATE": {
            "value": "2017-03-01T22:00:00.000Z"
        }
    },
    "startDate": "2017-01-01T23:17:10.305Z",
    "endDate": "2017-01-20T23:17:10.305Z"
};

# Retrieve data from server
s.send(json.dumps({
    "jsonrpc": "2.0",
    "method": "getData",
    "id": nextId,
    "params": retrievalParams
}))

# Handle incoming observations asynchronously
while True:

    # Decode response
    response = json.loads(decodeOneJsonFrame(s))

    # Store the incoming observations
    if "data" in response["result"]:
        for date in response["result"]["data"]:
            series["data"][date] = response["result"]["data"][date];

    # Close the socket when all observations are received
    if "requestStatus" in response["result"] and response["result"]["requestStatus"] == "finished":
        s.close()
        break

To retrieve observation data, you must always specify a sensor id, a metric id and a unit id. In addition, you can optionally include the following parameters with your API request:

Parameter Example Description
startDate 2017-01-01T23:17:10.305Z The start date for the data query, in ISO date format. If omitted, the data returned will start with the first observation.
endDate 2017-01-20T23:17:10.305Z The end date for the data query, in ISO date format. If omitted, the data returned will end with the most recent observation.
params {dt: {value: 604800}} Any mandatory or optional metric parameters, as described above. Metric parameter id’s should be used as keys of this object. Each metric parameter must have a value property and an optional unit property.
limit {function: "last", params: {size: 1}}
{function: "first", params: {size: 1}}
A configuration object that limits the number of observations returned. We currently only support retrieving a single first or last value.

Once you compile a list of data query parameters, you can retrieve the actual observations or statistical information about them using the following API requests:

Request Params Description
getData described above Retrieves a series of observations for a specific sensor that match the data query parameters.
getObservations described above Retrieves a series of observations for a specific sensor that match the data query parameters in the sensor’s raw metrics & units. Not recommended in most cases.
getObservationsSummary described above Retrieves statistical information about a series of observations. Currently returns the first and last observations that match the data query parameters.

Subscribing to New Data

The following example illustrates subscribing to a sensor’s new observations:

var sensorId = "/fn/6C4F6D/node/dgsimlogger/032432/device/tilt4/sensor",
    metricId = "dx",
    unitId = "m";

// Create a local data object
var series = {
    id: sensorId,
    metric: metricId,
    data: {}
};

// Create a set of parameters for a data subscription
var subscriptionParams = {
    "sensors": [sensorId],
    "metric": metricId,
    "unit": unitId,
    "params": {
        "ZERO_DATE": {
            "value": "2017-03-01T22:00:00.000Z"
        }
    }
};

// Subscribe to new sensor observations
var subscriptionId = sendRequest("subscribeData", subscriptionParams, function(result) {

    if ("data" in result) {

        // Save each data point locally
        for (var date in result.data) {
            if (result.data.hasOwnProperty(date)) {
                series.data[date] = result.data[date];
            }
        }
    }
});
nextId = nextId + 1
metricId = "dx"
unitId = "m"
sensorId = "/fn/6C4F6D/node/dgsimlogger/032432/device/tilt4/sensor"

# Create a local data object
series = {
    "id": sensorId,
    "metric": metricId,
    "data": {}
}

# Create a set of parameters for data subscription
subscriptionParams = {
    "sensors": [sensorId],
    "metric": metricId,
    "unit": unitId,
    "params": {
        "ZERO_DATE": {
            "value": "2017-03-01T22:00:00.000Z"
        }
    }
};

# Subscribe to new sensor observations
s.send(json.dumps({
    "jsonrpc": "2.0",
    "method": "subscribeData",
    "id": nextId,
    "params": subscriptionParams
}))

# Handle incoming updates asynchronously
while True:

    # Decode response
    response = json.loads(decodeOneJsonFrame(s))

    # Store the incoming observations
    if "data" in response["result"]:
        for date in response["result"]["data"]:
            series["data"][date] = response["result"]["data"][date];

In addition to retrieving observation data, you can subscribe to a sensor’s data stream to receive all newly recorded observations.

The data subscription API request can be performed with most of the same parameters as the observation retrieval request, so any newly recorded observations will be passed to you in the metrics & units specified (instead of the raw metrics & units they are recorded in).

You can subscribe and unsubscribe from a sensor’s observation stream using the following API requests:

Request Params Description
subscribeData “sensors” [array]
“metric” [string]
“unit” [string]
“params” [object]
Establishes a subscription to any new sensor observations. You will receive a new response message when a new observation is recorded in the metrics & units specified by the API request. Returned subscriptionId can be used to later unsubscribe from updates.
unsubscribeData “id” [integer] Unsubscribe from new observation updates using the subscriptionId returned by the subscription API request.

Uploading Data

The following example illustrates how to upload new observations for a single sensor:


var uploadDataParams = {
    "data": [
         {  
            "sensorId": "/trimble4d/nodeId/node/deviceId/device/sensorId/sensor",
            "timestamp": "2018-06-04T19:35:35.400Z",
            "values": {
               "e": 100.0,
               "e_adjusted": 101.0,
               "n": 100.0,
               "n_adjusted": 101.0,
               "h": 100.0,
               "h_adjusted": 101.0,
               "ha": 45.0,
               "za": 60.0,
               "sd": 100.0,
               "sd_corrected": 101.0,
               "T": 23.0,
               "P": 101325
            }
         }
      ]
};

sendRequest("uploadData", uploadDataParams, function(result) {
    console.log("uploadData result: ", result);
});
nextId = nextId + 1

s.send(json.dumps({
    "jsonrpc": "2.0",
    "method": "uploadData",
    "id": nextId,
    "params": {
      "data": [
         {  
            "sensorId": "/trimble4d/nodeId/node/deviceId/device/sensorId/sensor",
            "timestamp": "2018-06-04T19:35:35.400Z",
            "values": {
               "e": 100.0,
               "e_adjusted": 101.0,
               "n": 100.0,
               "n_adjusted": 101.0,
               "h": 100.0,
               "h_adjusted": 101.0,
               "ha": 45.0,
               "za": 60.0,
               "sd": 100.0,
               "sd_corrected": 101.0,
               "T": 23.0,
               "P": 101325
            }
         }
      ]
   }
}))

response = json.loads(decodeOneJsonFrame(s))
print("\r\n" + response["result"])

Example response object:

{
   "jsonrpc": "2.0",
   "result": {
      "successfullyProcessedObs": 1
   },
   "id": 4
}

In addition to retrieving observation data, you can upload new observation data for a particular sensor given it’s unique sensorId.

In order to upload new observation data for a sensor in the sensemetrics platform, that sensor must already exist in the system. See the createSensor API call described above if you need to create a new sensor first.

The values specified in the data object should have a key-value pair for each raw metric defined for this type of sensor. You can obtain the raw metric keys for a given sensor using the getRawMetrics request described above.

The response has a key successfullyProcessedObs that reflects the actual number of observations that were inserted. There is an example of this response object on the right.

Request Params Description
uploadData “data” [array]
This is an array of objects that represent a sensorId, timestamp, and the associated metrics and their values. See example object on the right.

data Object Description (all fields are mandatory):

Parameter Example Description
sensorId /trimble4d/nodeId/node/deviceId/device/sensorId/sensor The sensorId that represents the sensor you are uploading observation data for. This sensor must already exist in the system.
timestamp 2018-06-04T23:17:10.305Z The timestamp for this observation, in ISO date format.
values {"e": 100.0, "n": 200.0, "h": 300.0, ...} The key is the metric name, and the value is the value for that metric for this observation.

Utilities

Retrieve help information for all available API requests:

sendRequest("help", {}, function(result) {
    console.log("Available API requests:", result);
});
nextId = nextId + 1
s.send(json.dumps({
    "jsonrpc": "2.0",
    "method": "help",
    "id": nextId
}))
response = json.loads(decodeOneJsonFrame(s))
print("\r\n" + response["result"])

Keep a connection alive with periodic time requests:

setInterval(function() {

    // Check if a connection host has been set
    if (host !== undefined) {

        // Check if a connection is already open
        if (socket === undefined) {

            // If no connection, establish a new one

        } else {

            // Make sure we are no actively authenticating
            if (!authenticating) {

                // Refresh the connection by sending a "time" request
                sendRequest("time", {}, function() {
                    connected = true;
                });
            }
        }

    } else {

        // Set connection flags
        connected = authenticating = false;
    }
}, 5000);
nextId = nextId + 1
s.send(json.dumps({
    "jsonrpc": "2.0",
    "method":  "time",
    "id": nextId
}))
response = json.loads(decodeOneJsonFrame(s))
print("\r\nThe server time is " + parser.parse(response["result"]["time"]).strftime('%c'))

There are three utility API requests available for your convenience:

Request Parameters Description
authenticate “code” [string] Authenticates a socket connection using your unique API key. This must be the first API request after opening a new connection.
help None Retrieves information on all available API requests and their parameters.
time None Retrieves the current time from the server.