Back to top

Wattsense API - beta

The Wattsense API provides a two way communication channel with devices managed by the platform.

Note The Wattsense API is in beta, additions and/or improvements to the API should be expected.

Base URL

All the paths in this documentation are relative to the base path:

https://api.wattsense.com/

We only support HTTPS, all HTTP requests are rejected.

Authentication

All our endpoints are protected with HTTP basic authentication. They are also protected using an API-Key mechanism, except User related endpoints.

HTTP basic authentication

In summary, this uses your username and password for each request you make, for example:

curl -u <username>:<password> https://api.wattsense.com/v1/user

or in Python, using requests:

from requests.auth import HTTPBasicAuth
requests.get('https://api.wattsense.com/v1/user', auth=HTTPBasicAuth('<username>', '<password>'))

API Key authentication

Using our management console, you can create an API Key with an access to your subscriptions. An API Key can have access to multiple subscriptions with each its level of access. The possible levels are:

  • READ_ONLY where the API Key only allows access to GET endpoints

  • READ_WRITE where the API Key also gives access to the PUT endpoints (such as setting a property on a device) Each API Key comes with an API Secret used to sign the messages you send.

To authenticate, you must add to your request the header X-API-Auth containing the API Key and a message signature:

X-API-Auth: <your-api-key>:<request-hmac-512-authentication-code>

The authentication code of the request is computed by applying a HMAC_SHA512 on the request you’re about to send to the server. The message to authenticate has to respect the following specification (in pseudo code):

messageToSign = HttpMethod + '\n'
                RelativePath + '\n'
                CanonicalQuery + '\n'
                Body + '\n'
                Timestamp

where:

  • HttpMethod: Can be either GET, POST or PUT, mandatory in all requests

  • RelativePath: is a canonical url stripped of the base path, i.e. if you request https://api.wattsense.com/v1/devices that would be /v1/devices, mandatory in all requests

  • CanonicalQuery: the encoded query, to be provided only if there is indeed a query, for example:

property=temperature&since=1286705410000
  • Body: the exact json body to be sent, to be provided only if there is a body to send

  • TIMESTAMP: in milliseconds. If provided, the request will only be valid for 60 seconds after this timestamp. It has to be provided in the header in X-API-Timestamp.

This message is then authenticated using HMAC_SHA512 and its result base64 encoded. The final result is what we previously called request-hmac-512-authentication-code, or in short a “signature”. For example, in Python, that would be:

hmac_digest = hmac.new(api_secret, message.encode(), hashlib.sha512).digest()
signature = base64.b64encode(hmac_digest).decode()

For simplicity, we provide the following example that does everything we described above:

#!/usr/bin/python3
import requests
import urllib3
import base64
import hashlib
import hmac
import time
from urllib import parse
import json

url = 'https://api.wattsense.com'
api_key = '132BA4C2309A9E069BDF129138680F89'
api_secret = 'ZTgwZTliMWJhZmQ4NmFhMmM2M2U5MjdkMTI1MzliYzFmMTYyMWZkMzcyOTIxMzRkNzA0MTQ5ZWRmY2JiMDc3Yg=='
sub_id = '7b7690a2-9d09-4518-909d-83c24f7874eb'

def request(method, path, headers=None, payload=None, query=None):
    timestamp = int(time.time() * 1000)
    message = '\n'.join([str(e) for e in [method, path,
                        (parse.urlencode(query) if query else None),
                        (json.dumps(payload) if payload else None),
                        timestamp] if e != None])
    
    hmac_hash = base64.b64encode(hmac.new(api_secret.encode(), message.encode(),
                                 hashlib.sha512).digest()).decode()

    if headers is None:
        headers = {}

    headers['X-API-Auth'] = '{}:{}'.format(api_key, hmac_hash)
    headers['X-API-Timestamp'] = str(timestamp)

    return requests.request(method, url + path, headers=headers,
                            params=query, json=payload)

if __name__ == '__main__':
    print('Getting devices')
    req = request('GET', '/v1/devices', query={'subscriptionId': sub_id.encode()})
    print(req.json())

    device_id = req.json()[0]['deviceId']

    print('Setting a property on a device')
    req = request('PUT', '/v1/devices/' + device_id + '/properties/prop_1',
                payload={'payload': '33'})
    print(req.json())

Device

The Wattsense Box is designated as device in all this API. This resource has the following attributes:

  • deviceId, is a unique id assigned by Wattsense upon activation of the device.

  • subscriptionId, the id of the subscription this device belongs to

  • status, the status of the device (ONLINE or OFFLINE)

  • metadata, not implemented and is subject to change

Device information

Get a specific device info
GET/v1/devices/{deviceId}

This endpoint allows you to get the information about a device using its id.

Example URI

GET https://api.wattsense.com/v1/devices/deviceId
URI Parameters
HideShow
deviceId
string (required) 
Response  200
HideShow
Headers
Content-Type: application/json
Body
{
  "deviceId": "unique id",
  "subscriptionId": "uuid",
  "metadata": {
    "meta-key": "value"
  },
  "status": "ONLINE"
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "deviceId": {
      "type": "string",
      "description": "a unique id assigned by Wattsense on activation of the device"
    },
    "subscriptionId": {
      "type": "string",
      "description": "the id of the subscription this device belongs to"
    },
    "metadata": {
      "$ref": "#/definitions/meta-key",
      "description": "not implemented and is subject to change"
    },
    "status": {
      "type": "string",
      "enum": [
        "ONLINE",
        "OFFLINE",
        "UNKOWN"
      ],
      "description": "The status of the device"
    }
  },
  "definitions": {
    "meta-key": {
      "type": "object",
      "patternProperties": {
        "": {
          "type": "string"
        }
      }
    }
  }
}
Response  400
HideShow

Something is wrong with your request

Headers
Content-Type: application/json
Body
{
  "status": 400,
  "message": "unable to parse",
  "errors": {
    "json-field-name": "reason"
  },
  "timestamp": 10000000
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "status": {
      "type": "number",
      "description": "HTTP status code"
    },
    "message": {
      "type": "string",
      "description": "The reason the request failed"
    },
    "errors": {
      "$ref": "#/definitions/json-field-name",
      "description": "An object containing a message for each field that raised this error"
    },
    "timestamp": {
      "type": "number",
      "description": "The time at which this error was raised"
    }
  },
  "definitions": {
    "json-field-name": {
      "type": "object",
      "patternProperties": {
        "": {
          "type": "string"
        }
      }
    }
  }
}
Response  401
HideShow

Check your credentials

Headers
Content-Type: application/json
Response  403
HideShow

Nothing to see here

Headers
Content-Type: application/json
Response  404
HideShow

Device not found

Headers
Content-Type: application/json

List devices for a subscription
GET/v1/devices{?subscriptionId,page,size}

This endpoint allows you to list all the devices belonging to a subscription. The id of the subscription is an UUID and has to be passed by query parameter.

This endpoint returns paginated results. The pagination uses Link header for defining next, perv, first and last links. It is presented as a list of links separated by a comma, as defined in RCF5988, following the pattern: </v1/devices?subscriptionId=sub&page=2>; rel="next", </v1/devices?subscriptionId=sub&page=4>; rel="last".

Parsing the header could be done either manually or using a library such as Python’s requests:

import requests

result = requests.get("https://api.wattsense.com/v1/devices", ...)

if res.links.get('next'):
    # get next page
    res = requests.get(res.links['next']['url'], ...)

The pagination is one-based, i.e. the first page is 1. After the last page we return an empty list with a status code 204 (NO_CONTENT). This could be used as an off-by-one stop as the absence of the next url in the header is enough to indicate that there would be no more content after this.

Example URI

GET https://api.wattsense.com/v1/devices?subscriptionId=uuid-of-subscription&page=1&size=10
URI Parameters
HideShow
subscriptionId
UUID (required) Example: uuid-of-subscription

The id of the subscription for which to list the devices

page
number (optional) Example: 1

The page number of the results to get. One based, i.e. [1…N]

size
number (optional) Default: 20 Example: 10

The number of records to recover, maximum is 1000.

Response  200
HideShow
Headers
Content-Type: application/json
Link: <url?page=1>; rel="first"; <url?page=2>; rel="next", <url?page=4>; rel="last"
Body
[
  {
    "deviceId": "unique id",
    "subscriptionId": "uuid",
    "metadata": {
      "meta-key": "value"
    },
    "status": "ONLINE"
  }
]
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "deviceId": {
        "type": "string",
        "description": "a unique id assigned by Wattsense on activation of the device"
      },
      "subscriptionId": {
        "type": "string",
        "description": "the id of the subscription this device belongs to"
      },
      "metadata": {
        "$ref": "#/definitions/meta-key",
        "description": "not implemented and is subject to change"
      },
      "status": {
        "type": "string",
        "enum": [
          "ONLINE",
          "OFFLINE",
          "UNKOWN"
        ],
        "description": "The status of the device"
      }
    }
  },
  "definitions": {
    "meta-key": {
      "type": "object",
      "patternProperties": {
        "": {
          "type": "string"
        }
      }
    }
  }
}
Response  204
HideShow

No more content. This happens if the list of devices is empty, or you are trying to fetch a page out of limits.

Response  400
HideShow

Something is wrong with your request

Headers
Content-Type: application/json
Body
{
  "status": 400,
  "message": "unable to parse",
  "errors": {
    "json-field-name": "reason"
  },
  "timestamp": 10000000
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "status": {
      "type": "number",
      "description": "HTTP status code"
    },
    "message": {
      "type": "string",
      "description": "The reason the request failed"
    },
    "errors": {
      "$ref": "#/definitions/json-field-name",
      "description": "An object containing a message for each field that raised this error"
    },
    "timestamp": {
      "type": "number",
      "description": "The time at which this error was raised"
    }
  },
  "definitions": {
    "json-field-name": {
      "type": "object",
      "patternProperties": {
        "": {
          "type": "string"
        }
      }
    }
  }
}
Response  401
HideShow

Check your credentials

Headers
Content-Type: application/json
Response  403
HideShow

Nothing to see here

Headers
Content-Type: application/json
Response  404
HideShow

Subscription not found

Headers
Content-Type: application/json

Device properties

Query device properties
GET/v1/devices/{deviceId}/properties{?property,since,until,page,size,sort}

This endpoint allows you to search for measurements sent by a device. If no parameter is passed, it returns all the values for all the properties of the device during the last 24 hours.

This endpoint returns paginated results. The pagination uses Link header for defining next, perv, first and last links. It is presented as a list of links separated by a comma, as defined in RCF5988, following the pattern: </v1/devices/deviceId/properties?page=2>; rel="next". For performance reasons, there is no last item provided. You can use the absence of next or a status 204 (NO CONTENT) as a stop.

Parsing the header could be done either manually or using a library such as Python’s requests:

import requests

result = requests.get("https://api.wattsense.com/v1/devices/my-device/properties", ...)

if res.links.get('next'):
    # get next page
    res = requests.get(res.links['next']['url'], ...)

The pagination is one-based, i.e. the first page is 1. After the last page we return an empty list with a status code 204 (NO_CONTENT). This could be used as an off-by-one stop as the absence of the next url in the header is enough to indicate that there would be no more content after this.

IMPORTANT: This endpoints allows you to query the last 21 days with short delay, for older data you should increase the timeout of your request as it could last up to a few minutes to get the result.

For simplicity, we provide the following example to query data on a custom time range:

import requests
import base64
import time
import datetime
from urllib.parse import urlparse, parse_qs
requests.packages.urllib3.disable_warnings()

# import the request function defined earlier
from sign_request import request

url = 'https://api.wattsense.com'
api_key = '132BA4C2309A9E069BDF129138680F89'
api_secret = 'ZTgwZTliMWJhZmQ4NmFhMmM2M2U5MjdkMTI1MzliYzFmMTYyMWZkMzcyOTIxMzRkNzA0MTQ5ZWRmY2JiMDc3Yg=='
sub_id = '7b7690a2-9d09-4518-909d-83c24f7874eb'

def get_data(device_id, since, until, property_name=None, size_per_request=500):
    params = {'since': int(time.mktime(datetime.datetime.strptime(since, "%Y-%m-%d %H:%M").timetuple()) * 1000),
              'until': int(time.mktime(datetime.datetime.strptime(until, "%Y-%m-%d %H:%M").timetuple()) * 1000),
              'size': size_per_request }

    if property_name:
        params['property'] = property_name

    elements = []

    res = request('GET', '/v1/devices/' + device_id + '/properties', query=params)
    while res.status_code == 200:
        elements = elements + res.json()
        if res.links.get('next'):
            next_url_query = urlparse(res.links['next']['url']).query
            # parse next url query parameters
            params = dict(x.split('=') for x in next_url_query.split('&'))

            res = request('GET', '/v1/devices/' + device_id + '/properties', query=params)
        else:
            break
    return elements


# you can then call it using:
result = get_data("dev-one", "2018-07-12 00:00", "2018-07-13 23:59", size_per_request=10)

# if you have python-tabulate
from tabulate import tabulate
print(tabulate([[e['property'],
                 datetime.datetime.fromtimestamp(e['timestamp'] / 1000),
                 e['payload']] for e in result], headers=['property', 'date', 'value']))

which (if you have the library tabulate) will yield a result similar to this:

property    date                          value
----------  --------------------------  -------
temp2       2018-07-12 13:26:12.679000  20.8968
temp2       2018-07-12 13:26:12.578000  20.5863
temp2       2018-07-12 13:26:12.478000  20.7995
temp2       2018-07-12 13:26:12.376000  20.239
temp2       2018-07-12 13:26:12.277000  20.5092
temp2       2018-07-12 13:26:12.175000  20.7335
temp2       2018-07-12 13:26:12.073000  19.0188
temp2       2018-07-12 13:26:11.974000  20.8744
temp2       2018-07-12 13:26:11.871000  20.1135
temp1       2018-07-12 13:26:11.792000  59.3164
temp2       2018-07-12 13:26:11.771000  20.8935
temp1       2018-07-12 13:26:11.690000  59.8559
temp2       2018-07-12 13:26:11.669000  19.5403
temp1       2018-07-12 13:26:11.590000  60.7562
temp2       2018-07-12 13:26:11.570000  19.1456
temp1       2018-07-12 13:26:11.488000  60.3213
temp2       2018-07-12 13:26:11.467000  20.3842
temp1       2018-07-12 13:26:11.389000  60.4053

Example URI

GET https://api.wattsense.com/v1/devices/deviceId/properties?property=&since=1286705410000&until=1531440000000&page=1&size=500&sort=timestamp,desc
URI Parameters
HideShow
deviceId
string (required) 
property
string (optional) 

if not provided will list all available properties for that device

since
number (optional) Example: 1286705410000

the timestamp from which to start getting data

  • Default 24 hours before the value of until
until
number (optional) Example: 1531440000000

the timestamp to which to get data

  • Default current epoch timestamp in milliseconds
page
number (optional) Example: 1

The page number of the results to get. One based, i.e. [1…N]

size
number (optional) Default: 20 Example: 500

The number of records to recover, maximum is 1000.

sort
string (optional) Example: timestamp,desc

The sort parameter and direction of data. Example: ?sort=timestamp,asc will order data by timestamp in ascending order. Other possible attributes for sorting are property and payload.

Response  200
HideShow

The properties

Headers
Content-Type: application/json
Body
[
  {
    "property": "temperature",
    "deviceId": "device_one",
    "payload": 33.1,
    "timestamp": 1
  }
]
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "property": {
        "type": "string",
        "description": "the property name"
      },
      "deviceId": {
        "type": "string",
        "description": "a unique id assigned by WattSense on activation of the device"
      },
      "payload": {
        "anyOf": [
          {
            "type": "number",
            "enum": [
              33.1
            ]
          },
          {
            "type": "string",
            "enum": [
              "on"
            ]
          }
        ],
        "description": "the value sent by the device"
      },
      "timestamp": {
        "type": "number",
        "description": "the timestamp sent by the device"
      }
    }
  }
}
Response  204
HideShow

No more content. This happens if there is no data for this time range or property, or you are trying to fetch a page out of limits.

Response  400
HideShow

Something is wrong with your request

Headers
Content-Type: application/json
Body
{
  "status": 400,
  "message": "unable to parse",
  "errors": {
    "json-field-name": "reason"
  },
  "timestamp": 10000000
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "status": {
      "type": "number",
      "description": "HTTP status code"
    },
    "message": {
      "type": "string",
      "description": "The reason the request failed"
    },
    "errors": {
      "$ref": "#/definitions/json-field-name",
      "description": "An object containing a message for each field that raised this error"
    },
    "timestamp": {
      "type": "number",
      "description": "The time at which this error was raised"
    }
  },
  "definitions": {
    "json-field-name": {
      "type": "object",
      "patternProperties": {
        "": {
          "type": "string"
        }
      }
    }
  }
}
Response  401
HideShow

Check your credentials

Headers
Content-Type: application/json
Response  403
HideShow

Nothing to see here

Headers
Content-Type: application/json
Response  404
HideShow

Device not found

Headers
Content-Type: application/json

Get the latest value for a specific property of a device
GET/v1/devices/{deviceId}/properties/{property}

This endpoint allows you to get the latest measurements sent by a device for a specific property. If the property is not available on the device, a 404 will be returned.

Example URI

GET https://api.wattsense.com/v1/devices/deviceId/properties/property
URI Parameters
HideShow
deviceId
string (required) 
property
string (required) 
Response  200
HideShow

The latest measurement of a property

Headers
Content-Type: application/json
Body
{
  "property": "temperature",
  "deviceId": "device_one",
  "payload": 33.1,
  "timestamp": 1
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "property": {
      "type": "string",
      "description": "the property name"
    },
    "deviceId": {
      "type": "string",
      "description": "a unique id assigned by WattSense on activation of the device"
    },
    "payload": {
      "anyOf": [
        {
          "type": "number",
          "enum": [
            33.1
          ]
        },
        {
          "type": "string",
          "enum": [
            "on"
          ]
        }
      ],
      "description": "the value sent by the device"
    },
    "timestamp": {
      "type": "number",
      "description": "the timestamp sent by the device"
    }
  }
}
Response  400
HideShow

Something is wrong with your request

Headers
Content-Type: application/json
Body
{
  "status": 400,
  "message": "unable to parse",
  "errors": {
    "json-field-name": "reason"
  },
  "timestamp": 10000000
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "status": {
      "type": "number",
      "description": "HTTP status code"
    },
    "message": {
      "type": "string",
      "description": "The reason the request failed"
    },
    "errors": {
      "$ref": "#/definitions/json-field-name",
      "description": "An object containing a message for each field that raised this error"
    },
    "timestamp": {
      "type": "number",
      "description": "The time at which this error was raised"
    }
  },
  "definitions": {
    "json-field-name": {
      "type": "object",
      "patternProperties": {
        "": {
          "type": "string"
        }
      }
    }
  }
}
Response  401
HideShow

Check your credentials

Headers
Content-Type: application/json
Response  403
HideShow

Nothing to see here

Headers
Content-Type: application/json
Response  404
HideShow

Device not found or no such property on the device

Headers
Content-Type: application/json

Set a specific property on a device
PUT/v1/devices/{deviceId}/properties/{property}

This endpoint allows you to set the value of a specific property on the device.

The request must contain a payload that can be either string or a number. This operation returns a commandId that can be used to check the status of the operation using Get a specific command sent to a device

Example URI

PUT https://api.wattsense.com/v1/devices/deviceId/properties/property
URI Parameters
HideShow
deviceId
string (required) 
property
string (required) 
Request
HideShow
Headers
Content-Type: application/json
Body
{
  "payload": 33
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "payload": {
      "anyOf": [
        {
          "type": "number",
          "enum": [
            33
          ]
        },
        {
          "type": "string",
          "enum": [
            "on"
          ]
        }
      ],
      "description": "the value to set on the device"
    }
  },
  "required": [
    "payload"
  ]
}
Response  200
HideShow

OK

Headers
Content-Type: application/json
Body
{
  "commandId": "hexstringvalue",
  "status": "NEW"
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "commandId": {
      "type": "string",
      "description": "The id of this command"
    },
    "status": {
      "type": "string",
      "enum": [
        "NEW",
        "SENT",
        "RECEIVED",
        "RETRY_SEND",
        "ERROR_NOT_RECEIVED"
      ],
      "description": "The status of the command"
    }
  }
}
Response  400
HideShow

Something is wrong with your request

Headers
Content-Type: application/json
Body
{
  "status": 400,
  "message": "unable to parse",
  "errors": {
    "json-field-name": "reason"
  },
  "timestamp": 10000000
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "status": {
      "type": "number",
      "description": "HTTP status code"
    },
    "message": {
      "type": "string",
      "description": "The reason the request failed"
    },
    "errors": {
      "$ref": "#/definitions/json-field-name",
      "description": "An object containing a message for each field that raised this error"
    },
    "timestamp": {
      "type": "number",
      "description": "The time at which this error was raised"
    }
  },
  "definitions": {
    "json-field-name": {
      "type": "object",
      "patternProperties": {
        "": {
          "type": "string"
        }
      }
    }
  }
}
Response  401
HideShow

Check your credentials

Headers
Content-Type: application/json
Response  403
HideShow

Nothing to see here

Headers
Content-Type: application/json
Response  404
HideShow

Device not found

Headers
Content-Type: application/json

Device configuration

The device uses two configuration files to get the job done, a network and a data configuration file.

Update network configuration
PUT/v1/devices/{deviceId}/config/network

IMPORTANT: once the configuration has been updated. You need to order the device to restart the client for the configuration to be taken into account.

IMPORTANT: before restarting the client on the device, ensure you have updated both configuration files (if needed). For instance, if you add a new variable that depends on a network that is not configured yet, ensure that you update the network configuration before running the restart.

networks configuration file

IMPORTANT: once the configuration has been updated. You need to order the device to restart the client for the configuration to be taken into account.

IMPORTANT: before restarting the client on the device, ensure you have updated both configuration files (if needed). For instance, if you add a new variable that depends on a network that is not configured yet, ensure that you update the network configuration before running the restart.

The networks configuration file network-configuration.json defines a list of networks, its schema is

{
    "format_version": "1.1.0",
    "networks": [
        { (network1) }, (...)
    ]
}

where each (networkn) is a list of parameters.

Note: There exists a network named "platform" used internally for sending properties to the platform. As network names are unique, you should not create a network with that name.

The networks configuration file max length is 65536 bytes

The networks parameters are as follows:

networks parameters

network type parameter value JSON type min max default mandatory
any name a unique network name string - - - yes
any protocol the high level protocol name among websockets, modbus or bacnet string - - - yes
any type the low level network type among RS485, MSTP, IP (1) string - - - yes
type RS485 or MSTP device the serial device among rs485_1, rs485_2 or rs232 string - - - yes
type RS485 or MSTP config the serial device config formatted like baudrate_BPN, with B=‘5’, ‘6’, ‘7’ or ‘8’ (nb data bits), P=‘N’, ‘E’ or ‘O’ (parity) and N=‘1’ or ‘2’ (nb stop bits) string - - - yes
type IP address See (5) string - - - yes
any inter_frame_delay_us delay in µs to wait after a frame is sent number 0 1000000 0 no
any response_timeout_us serial request response timeout in µs number 100 1000000 500000 no
any retry_nb nb of send retries over the serial request was lost number 0 1000000 0 no
protocol modbus subtype If type is set to ‘RS485’ settles the transmission mode. If type is ‘IP’ settles the network and transport layers (3) string - - See (3) no
protocol modbus and type RS485 sniffing declare this network as sniffing an existing modbus RTU network, see (4) number 0 1 0 no

(1) The following protocol/type pairs are allowed:

network protocol allowed type
“websockets” “IP”
“modbus” “RS485” or “IP”
“bacnet” “MSTP” or “IP”

(2) In these strings the substring "<device id>" may be used to represent the unique id of the device

(3) Modbus has a great variety of configurations over serial communications and over Internet. One mismatch on the configuration of the sensors can lead to unexpected errors.

(4) Sniffing a modbus network means intercepting all the communications on an existing modbus network. In that case the box behaves like a modbus server accepting all slave ids but not replying to the requesting master. Sniffed variables must be declared on the network. These variables can be redirected as normal variables.

Ex: a sniffing network:

(...)
    {
        "name": "modbus_2",
        "protocol": "modbus",
        "type": "RS485",
        "config": "115200_8N1",
        "device": "rs485_2",
        "sniffing": 1
    }
(...)

and its data configuration:

(...)
    {"name": "sniffed_one", "network": "modbus_2", "slave": 1, "function": 3, "address" : 1 },
    {"name": "sniffed_two", "network": "modbus_2", "slave": 3, "function": 4, "address" : 72, "data_format" : "float_cdab" },
(...)

(5) The field address can have multiple interpretations according to the protocol used:

Protocol interpretation
websocket the websockets backend URI as defined in RFC3986.
modbus <IPv4|IPv6|domain name>[:<TCP port>] *
bacnet <Network Interface | IPv4 address >:<UDP port> **

* Default TCP Port: 502

** One should use either the network interface name or the IPv4 address of the box. The former option is useful when the IPv4 address is assigned by means of a DHCP server while the latest is valid for static assignation.

The following table shows the current names of the interfaces supported by the box.

Network Interface value Meaning
“et1” right ethernet port
“eth0” right ethernet port
“et2” left ethernet port
“eth1” left ethernet port

BACnet IP is making use of a “virtual” data-link which combines the IPv4 with the UDP port. Expected UDP port values are between 47808 to 47817 (0xBAC0 - 0xBAC9).

RS485

When a serial connection is used, the transmission can be settled to ASCII or RTU Valid entries for subtype are:

Value Description
“rtu” (default) A Modbus RTU message must be transmitted continuously without inter-character hesitations. Modbus messages are framed (separated) by idle (silent) periods.
“ascii” Modbus ASCII messages are framed by leading colon ("😊 and trailing newline (CR/LF).

NOTE: Support for ASCII is in progress

Internet

As the Internet has been evolving, Modbus has been adapted to it. Valid entries for subtype are:

Value Description
“ip/tcp” (default) Supports TCP over IPv6 or IPv4
“ip/udp” Support for UDP is in progress

Example URI

PUT https://api.wattsense.com/v1/devices/deviceId/config/network
URI Parameters
HideShow
deviceId
string (required) 
Request
HideShow
Headers
Content-Type: application/json
Body
{
  "format_version": "1.1.0",
  "networks": [
    {
      "name": "modbus_1",
      "protocol": "modbus",
      "type": "RS485",
      "device": "rs485_1",
      "config": "115200_8N1",
      "inter_frame_delay_us": 10000,
      "response_timeout_us": 10000,
      "retry_nb": 2
    },
    {
      "name": "modbus_2",
      "protocol": "modbus",
      "type": "RS485",
      "device": "rs485_1",
      "config": "115200_8N1",
      "inter_frame_delay_us": 10000,
      "response_timeout_us": 10000,
      "retry_nb": 2
    }
  ]
}
Response  200
HideShow

OK

Headers
Content-Type: application/json
Body
{
  "commandId": "hexstringvalue",
  "status": "NEW"
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "commandId": {
      "type": "string",
      "description": "The id of this command"
    },
    "status": {
      "type": "string",
      "enum": [
        "NEW",
        "SENT",
        "RECEIVED",
        "RETRY_SEND",
        "ERROR_NOT_RECEIVED"
      ],
      "description": "The status of the command"
    }
  }
}
Response  400
HideShow

Something is wrong with your request

Headers
Content-Type: application/json
Body
{
  "status": 400,
  "message": "unable to parse",
  "errors": {
    "json-field-name": "reason"
  },
  "timestamp": 10000000
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "status": {
      "type": "number",
      "description": "HTTP status code"
    },
    "message": {
      "type": "string",
      "description": "The reason the request failed"
    },
    "errors": {
      "$ref": "#/definitions/json-field-name",
      "description": "An object containing a message for each field that raised this error"
    },
    "timestamp": {
      "type": "number",
      "description": "The time at which this error was raised"
    }
  },
  "definitions": {
    "json-field-name": {
      "type": "object",
      "patternProperties": {
        "": {
          "type": "string"
        }
      }
    }
  }
}
Response  401
HideShow

Check your credentials

Headers
Content-Type: application/json
Response  403
HideShow

Nothing to see here

Headers
Content-Type: application/json
Response  404
HideShow

Device not found

Headers
Content-Type: application/json

Update data configuration
PUT/v1/devices/{deviceId}/config/data

IMPORTANT: once the configuration has been updated. You need to order the device to restart the client for the configuration to be taken into account.

IMPORTANT: before restarting the client on the device, ensure you have updated both configuration files (if needed). For instance, if you add a new variable that depends on a network that is not configured yet, ensure that you update the network configuration before running the restart.

data configuration file

The data configuration file data-configuration.json defines lists of variables, timers and redirections, its schema is

{
    "format_version": "1.1.0",
    "variables" : [
        { (variable1) }, (...)
    ],
    "gateway" : [
        { (redirection1) }, (...)
    ],
    "timers" : [
        {
            "period_in_seconds" : "<period>",
            "send_request" : [
                "variable1", (...)
            ]
        },
        (...)
    ]
}

The data configuration file max length is 131072 bytes

The data objects are defined in the following chapters:

variables configuration

Each variable is configured as follows

variable parameter value JSON type mandatory default value
all name the variable name, must be unique all over this configuration file string yes -
all network the network name where the variable belongs, taken from the network list in network config file. Use platform for sending this value to WattSense cloud and make it accessible through API string yes -
modbus network slave the modbus slave id from 1 to 247 (1) number (1) -
modbus network function the modbus function (1)(2) number yes -
modbus network address the modbus register number (1) number yes -
modbus network data_type the modbus register data type among uint16, uint32, uint32_abcd, uint32_cdab, float_abcd, float_badc, float_cdab, float_dcba (3) string no uint16
BACnet network device-inst Remote device instance ID number No(4) -
BACnet network obj-inst Remote Object Instance ID Number yes -
BACnet network obj-type Remote Object type Number Yes -
BACnet network prop-id Remote Property ID Number Yes -
BACnet network mac Remote BACnet MAC address String No (4) -
BACnet network data-type Expected format for the BACnet data number No (5) -
BACnet network priority Priority for the WriteProperty Number No 8

(1) The “slave” parameter is mandatory for RS485 modbus networks and optional for TCP/IP modbus networks (set to 255 if not defined, according to the protocol), some modbus devices still needing this parameter. Setting a “slave” value of 0 is allowed, meaning broadcast, but the modbus slaves you drive must be compatible with this value.

All modbus related definitions can be found in MODBUS Application Protocol 1.1b

(2) Allowed modbus functions are related to values reading and writing, they are the following

modbus function modbus designation meaning
1 Read Coils reading digital registers
2 Read Discrete Inputs reading digital registers
3 Read Holding Registers reading 16 bits registers
4 Read Input Registers reading 16 bits registers
5 Write Single Coil writing digital registers
6 Write Single Register writing 16 bits registers
15 Write Multiple Coil writing digital registers
16 Write Multiple Register writing 16 bits registers

(3) Standard modbus exchanges data as 16 bits unsigned integers, transmitted most significant bit first (MSB first), see MODBUS Application Protocol 1.1b. Some extended modbus implementations may propose other formats implemented by the exchange of multiple contiguous 16 bits registers. wsgateway implements the most popular once. In the following array the symbols a, b, c and d represent respectively the 1st, 2nd, 3rd and 4th bytes read on the bus in chronological order.

data_type field meaning
“uint16” standard modbus uint16 format
“uint32_abcd” 32 bit unsigned integer, words MSB first, bytes MSB first
“uint32_cdab” 32 bit unsigned integer, words LSB first, bytes MSB first
“float_abcd” 32 bit IEEE-754 floating point, words MSB first, bytes MSB first
“float_badc” 32 bit IEEE-754 floating point, words MSB first, bytes LSB first
“float_cdab” 32 bit IEEE-754 floating point, words LSB first, bytes MSB first
“float_dcba” 32 bit IEEE-754 floating point, words LSB first, bytes LSB first

(4) Currently, only mac is used. In future releases the parameter device-inst will have priority over mac.

(5) The parameter data-type is used when writing requests is sent to the box. This parameter reflects the BACnet data types. The ones that are currently supported by our box are:

BACnet Data Type Code value Current Support
Invalid -1 -
NULL 0 No
BOOLEAN 16 Yes
UNSIGNED 32 Yes
SIGNED 48 Yes
REAL 64 Yes
DOUBLE 80 Yes
OCTET STRING 96 No
CHAR STRING 112 No
BIT STRING 128 No
ENUMERATED 144 Yes
DATE 160 No
TIME 176 No
OBJECT IDENTIFIER 192 No
BACnetPriorityValue 256 No
BACnetAddress 257 No
BACnetDateTime 258 No
BACnetObjectPropertyReference 259 No
BACnetPropertyStates 260 No
BACnetEventParameter 261 No
BACnetDateRange 262 No
BACnetWeekNDay 263 No
BACnetCalendarEntry 264 No
BACneTime 265 No
BACnetSpecialEvent 266 No
BACnetPropertyValue 267 No
BACnetRecipient 268 No
BACnetSetpointReference 269 No
BACnetDestination 270 No
BACnetDailySchedule 271 No
BACnetTimeStamp 272 No
BACnetPropertyReference 273 No
BACnetAddressBinding 274 No
BACnetDeviceObjectPropertyReference 275 No
BACnetClientCOV 276 No
BACnetLogRecord 277 No
BACnetActionList 278 No
BACnetListOfReadAccessSpecifications 279 No
BACnetPropertyAccessResult 280 No
BACnetCOVSubscription 281 No
BACnetDeviceObjectReference 282 *
BACnetDeviceObjectPropertyValue 283 *
BACnetAccumulatorRecord 284 No
BACnetPrescale 285 No
BACnetScale 286 No
BACnetEventLogRecord 287 *
BACnetLogMultipleRecord 288 No
BACnetShedLevel 289 *
BACnetAuthenticationPolicy 290 No
BACnetAuthenticationFactor 291 No
BACnetCredentialAuthenticationFactor 292 No
BACnetAccessRule 293 No
BACnetAssignedAccessRights 294 No
BACnetAuthenticationFactorFormat 295 No
BACnetOptionalCharacterString 296 No
BACnetPropertyAccessResult 297 No
BACnetVTSession 298 *
BACnetSessionKey 299 **
BACnetNetworkSecurityPolicy 300 *
BACnetKeyIdentifier 301 *
BACnetSecurityKeySet 302 No
BACnetLightingCommand 303 No
BACnetChannelValue 304 No
BACnetEventNotificationSubscription 305 No
BACnetProcessIdSelection 306 *
BACnetPortPermission 307 No
BACnetFaultParameter 308 *
BACnetRecipientProcess 309 *

* These data types are not intended to be supported.

redirections configuration

Each redirection is configured as follows

parameter value JSON type mandatory
from the variable name (as defined above) to be redirected string yes
to the destination variable name (as defined above) to redirect value to string yes

timers configuration

Each timer is configured as follows

parameter value JSON type mandatory
period_in_seconds the period the timer requests variables in s number yes
send_request the variables list to request, the variables must have been declared above string list yes

Example URI

PUT https://api.wattsense.com/v1/devices/deviceId/config/data
URI Parameters
HideShow
deviceId
string (required) 
Request
HideShow
Headers
Content-Type: application/json
Body
{
  "format_version": "1.1.0",
  "variables": [
    {
      "name": "temperature1",
      "network": "platform"
    },
    {
      "name": "temperature2",
      "network": "platform"
    },
    {
      "name": "set_temperature",
      "network": "platform"
    },
    {
      "name": "modbus_T1",
      "network": "modbus_1",
      "slave": 1,
      "function": 3,
      "address": 71
    },
    {
      "name": "modbus_T2",
      "network": "modbus_1",
      "slave": 1,
      "function": 3,
      "address": 73
    },
    {
      "name": "order",
      "network": "modbus_1",
      "slave": 1,
      "function": 6,
      "address": 10
    }
  ],
  "gateway": [
    {
      "from": "modbus_T1",
      "to": "temperature1"
    },
    {
      "from": "modbus_T2",
      "to": "temperature2"
    },
    {
      "from": "set_temperature",
      "to": "order"
    }
  ],
  "timers": [
    {
      "period_in_seconds": 600,
      "send_request": [
        "modbus_T1",
        "modbus_T2"
      ]
    }
  ]
}
Response  200
HideShow

OK

Headers
Content-Type: application/json
Body
{
  "commandId": "hexstringvalue",
  "status": "NEW"
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "commandId": {
      "type": "string",
      "description": "The id of this command"
    },
    "status": {
      "type": "string",
      "enum": [
        "NEW",
        "SENT",
        "RECEIVED",
        "RETRY_SEND",
        "ERROR_NOT_RECEIVED"
      ],
      "description": "The status of the command"
    }
  }
}
Response  400
HideShow

Something is wrong with your request

Headers
Content-Type: application/json
Body
{
  "status": 400,
  "message": "unable to parse",
  "errors": {
    "json-field-name": "reason"
  },
  "timestamp": 10000000
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "status": {
      "type": "number",
      "description": "HTTP status code"
    },
    "message": {
      "type": "string",
      "description": "The reason the request failed"
    },
    "errors": {
      "$ref": "#/definitions/json-field-name",
      "description": "An object containing a message for each field that raised this error"
    },
    "timestamp": {
      "type": "number",
      "description": "The time at which this error was raised"
    }
  },
  "definitions": {
    "json-field-name": {
      "type": "object",
      "patternProperties": {
        "": {
          "type": "string"
        }
      }
    }
  }
}
Response  401
HideShow

Check your credentials

Headers
Content-Type: application/json
Response  403
HideShow

Nothing to see here

Headers
Content-Type: application/json
Response  404
HideShow

Device not found

Headers
Content-Type: application/json

Update network interfaces configuration
PUT/v1/devices/{deviceId}/config/inet/{interface}

Send a network interface configuration to the device. The json contains a single field body in which the configuration has to be set.

Example URI

PUT https://api.wattsense.com/v1/devices/deviceId/config/inet/interface
URI Parameters
HideShow
deviceId
string (required) 

The id of the device to which send the configuration

interface
string (required) 

The interface to configure

Request
HideShow
Headers
Content-Type: application/json
Body
{
  "body": "key=val\nkey2=val2"
}
Response  200
HideShow

OK

Headers
Content-Type: application/json
Body
{
  "commandId": "hexstringvalue",
  "status": "NEW"
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "commandId": {
      "type": "string",
      "description": "The id of this command"
    },
    "status": {
      "type": "string",
      "enum": [
        "NEW",
        "SENT",
        "RECEIVED",
        "RETRY_SEND",
        "ERROR_NOT_RECEIVED"
      ],
      "description": "The status of the command"
    }
  }
}
Response  400
HideShow

Something is wrong with your request

Headers
Content-Type: application/json
Body
{
  "status": 400,
  "message": "unable to parse",
  "errors": {
    "json-field-name": "reason"
  },
  "timestamp": 10000000
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "status": {
      "type": "number",
      "description": "HTTP status code"
    },
    "message": {
      "type": "string",
      "description": "The reason the request failed"
    },
    "errors": {
      "$ref": "#/definitions/json-field-name",
      "description": "An object containing a message for each field that raised this error"
    },
    "timestamp": {
      "type": "number",
      "description": "The time at which this error was raised"
    }
  },
  "definitions": {
    "json-field-name": {
      "type": "object",
      "patternProperties": {
        "": {
          "type": "string"
        }
      }
    }
  }
}
Response  401
HideShow

Check your credentials

Headers
Content-Type: application/json
Response  403
HideShow

Nothing to see here

Headers
Content-Type: application/json
Response  404
HideShow

Device not found

Headers
Content-Type: application/json

Device commands

All operations you send to a device are considered as commands. Therefore, are more or less handled the same on our side. Among these commands, we have setting a property, sending a configuration file, restaring the device.

Send a management command to a device
PUT/v1/devices/{deviceId}/command

It is possible to send a management commands to the device. The current supported commands are:

  • RESTART to restart the services on the device, this is not a hardware restart.

  • DISCOVER run a network discovery on the device. This command needs a network name to be passed in the arguments.

Example URI

PUT https://api.wattsense.com/v1/devices/deviceId/command
URI Parameters
HideShow
deviceId
string (required) 
Request
HideShow
Headers
Content-Type: application/json
Body
{
  "command": "DISCOVER",
  "arguments": [
    "network_to_discover"
  ]
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "command": {
      "type": "string",
      "enum": [
        "DISCOVER",
        "RESTART"
      ],
      "description": "the value to set on the device"
    },
    "arguments": {
      "type": "array",
      "description": "arguments to the previous command"
    }
  },
  "required": [
    "command"
  ]
}
Response  200
HideShow

OK

Headers
Content-Type: application/json
Body
{
  "commandId": "hexstringvalue",
  "status": "NEW"
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "commandId": {
      "type": "string",
      "description": "The id of this command"
    },
    "status": {
      "type": "string",
      "enum": [
        "NEW",
        "SENT",
        "RECEIVED",
        "RETRY_SEND",
        "ERROR_NOT_RECEIVED"
      ],
      "description": "The status of the command"
    }
  }
}
Response  400
HideShow

Something is wrong with your request

Headers
Content-Type: application/json
Body
{
  "status": 400,
  "message": "unable to parse",
  "errors": {
    "json-field-name": "reason"
  },
  "timestamp": 10000000
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "status": {
      "type": "number",
      "description": "HTTP status code"
    },
    "message": {
      "type": "string",
      "description": "The reason the request failed"
    },
    "errors": {
      "$ref": "#/definitions/json-field-name",
      "description": "An object containing a message for each field that raised this error"
    },
    "timestamp": {
      "type": "number",
      "description": "The time at which this error was raised"
    }
  },
  "definitions": {
    "json-field-name": {
      "type": "object",
      "patternProperties": {
        "": {
          "type": "string"
        }
      }
    }
  }
}
Response  401
HideShow

Check your credentials

Headers
Content-Type: application/json
Response  403
HideShow

Nothing to see here

Headers
Content-Type: application/json
Response  404
HideShow

Device not found

Headers
Content-Type: application/json

Listing the commands that were sent to a device
GET/v1/devices/{deviceId}/commands{?status,commandType,page,size,sort}

List all the commands sent by the user. This includes setting a property, sending a configuration file, restaring the device. See the schema on the right for the different response values.

You can use this endpoint to find the latest network configuration received by the device, for example: /v1/devices/{deviceId}/commands?status=RECEIVED&commandType=NETWORK_CONFIG&size=1.

Example URI

GET https://api.wattsense.com/v1/devices/deviceId/commands?status=&commandType=&page=1&size=500&sort=timestamp,desc
URI Parameters
HideShow
deviceId
string (required) 
commandType
string (optional) 

if not provided will list all types of commands

  • SET_PROPERTY (string) - set a property on the device

  • RESTART (string) - restart the device

  • DISCOVER (string) - a network discovery command

  • NETWORK_CONFIG (string) - send network configuration to the device

  • DATA_CONFIG (string) - send data configuration to the device

  • INET_CONFIG (string) - send network interfaces configuration to the device

status
string (optional) 

if not provided will list commands regardless of their status

  • NEW (string) - Command is valid and stored on the cloud platform

  • SENT (string) - The command was sent to the device, we did not receive a confirmation from the device yet

  • RECEIVED (string) - The command was received by the device

  • RETRY_SEND (string) - The command was not received yet by the device, we’ll retry soon

  • ERROR_NOT_RECEIVED (string) - The command was not received by the device even after multiple retries

page
number (optional) Example: 1

The page number of the results to get. One based, i.e. [1…N]

size
number (optional) Default: 20 Example: 500

The number of records to recover, maximum is 1000.

sort
string (optional) Example: timestamp,desc

The sort parameter and direction of data. Example: ?sort=timestamp,asc will order data by timestamp in ascending order. Other possible attributes for sorting are status and commandType.

Response  200
HideShow

The properties

Headers
Content-Type: application/json
Body
[
  {
    "commandId": "hexstringvalue",
    "deviceId": "deviceId",
    "commandType": "SET_PROPERTY",
    "body": "content",
    "status": "NEW",
    "retryCount": 1,
    "timestamp": 150000000,
    "lastUpdateTimestamp": 150000000
  }
]
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "commandId": {
        "type": "string",
        "description": "The id of this command"
      },
      "deviceId": {
        "type": "string",
        "description": "the id of the device receving the commnad"
      },
      "commandType": {
        "type": "string",
        "enum": [
          "SET_PROPERTY",
          "RESTART",
          "NETWORK_CONFIG",
          "DATA_CONFIG"
        ],
        "description": "the type of command"
      },
      "body": {
        "type": "string",
        "description": "the body of the command sent to the device, this could be the property value or the configuration content"
      },
      "status": {
        "type": "string",
        "enum": [
          "NEW",
          "SENT",
          "RECEIVED",
          "RETRY_SEND",
          "ERROR_NOT_RECEIVED"
        ],
        "description": "The status of the command"
      },
      "retryCount": {
        "type": "number",
        "description": "the number of retries to send the command"
      },
      "timestamp": {
        "type": "number",
        "description": "the timestamp of when the command was created (in milliseconds)"
      },
      "lastUpdateTimestamp": {
        "type": "number",
        "description": "the timestamp of when the command's status was last changed (in milliseconds)"
      }
    }
  }
}
Response  204
HideShow

No more content. This happens if there is no data for this time range or property, or you are trying to fetch a page out of limits.

Response  400
HideShow

Something is wrong with your request

Headers
Content-Type: application/json
Body
{
  "status": 400,
  "message": "unable to parse",
  "errors": {
    "json-field-name": "reason"
  },
  "timestamp": 10000000
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "status": {
      "type": "number",
      "description": "HTTP status code"
    },
    "message": {
      "type": "string",
      "description": "The reason the request failed"
    },
    "errors": {
      "$ref": "#/definitions/json-field-name",
      "description": "An object containing a message for each field that raised this error"
    },
    "timestamp": {
      "type": "number",
      "description": "The time at which this error was raised"
    }
  },
  "definitions": {
    "json-field-name": {
      "type": "object",
      "patternProperties": {
        "": {
          "type": "string"
        }
      }
    }
  }
}
Response  401
HideShow

Check your credentials

Headers
Content-Type: application/json
Response  403
HideShow

Nothing to see here

Headers
Content-Type: application/json
Response  404
HideShow

Device not found

Headers
Content-Type: application/json

Get a specific command sent to a device
GET/v1/devices/{deviceId}/commands/{commandId}

Returns the command information using its id.

Example URI

GET https://api.wattsense.com/v1/devices/deviceId/commands/commandId
URI Parameters
HideShow
deviceId
string (required) 
commandId
string (required) 
Response  200
HideShow

The properties

Headers
Content-Type: application/json
Body
{
  "commandId": "hexstringvalue",
  "deviceId": "deviceId",
  "commandType": "SET_PROPERTY",
  "body": "content",
  "status": "NEW",
  "retryCount": 1,
  "timestamp": 150000000,
  "lastUpdateTimestamp": 150000000
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "commandId": {
      "type": "string",
      "description": "The id of this command"
    },
    "deviceId": {
      "type": "string",
      "description": "the id of the device receving the commnad"
    },
    "commandType": {
      "type": "string",
      "enum": [
        "SET_PROPERTY",
        "RESTART",
        "NETWORK_CONFIG",
        "DATA_CONFIG"
      ],
      "description": "the type of command"
    },
    "body": {
      "type": "string",
      "description": "the body of the command sent to the device, this could be the property value or the configuration content"
    },
    "status": {
      "type": "string",
      "enum": [
        "NEW",
        "SENT",
        "RECEIVED",
        "RETRY_SEND",
        "ERROR_NOT_RECEIVED"
      ],
      "description": "The status of the command"
    },
    "retryCount": {
      "type": "number",
      "description": "the number of retries to send the command"
    },
    "timestamp": {
      "type": "number",
      "description": "the timestamp of when the command was created (in milliseconds)"
    },
    "lastUpdateTimestamp": {
      "type": "number",
      "description": "the timestamp of when the command's status was last changed (in milliseconds)"
    }
  }
}
Response  400
HideShow

Something is wrong with your request

Headers
Content-Type: application/json
Body
{
  "status": 400,
  "message": "unable to parse",
  "errors": {
    "json-field-name": "reason"
  },
  "timestamp": 10000000
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "status": {
      "type": "number",
      "description": "HTTP status code"
    },
    "message": {
      "type": "string",
      "description": "The reason the request failed"
    },
    "errors": {
      "$ref": "#/definitions/json-field-name",
      "description": "An object containing a message for each field that raised this error"
    },
    "timestamp": {
      "type": "number",
      "description": "The time at which this error was raised"
    }
  },
  "definitions": {
    "json-field-name": {
      "type": "object",
      "patternProperties": {
        "": {
          "type": "string"
        }
      }
    }
  }
}
Response  401
HideShow

Check your credentials

Headers
Content-Type: application/json
Response  403
HideShow

Nothing to see here

Headers
Content-Type: application/json
Response  404
HideShow

Device or command not found

Headers
Content-Type: application/json

Config discovery

Getting bacnet discovery of a network
GET/v1/devices/{deviceId}/discovery/bacnet/{network}

Gives the BACnet discovery of a specific network.

We return the discovery per network, hence the response will always contain the network name in the json response. In the response we list all BACnet devices in bacnetDevices, in each BACnet device we list the objects available in bacnetObject.

As defined in the schema, whenever we reference a BACnet id (object, unit or property), we will include a name if we were able to map that id, its value will be null otherwise. In the case of objects, the names are prefixed with OBJ_, properties are prefixed with PROP_, and units are prefixed with UNIT_.

Example URI

GET https://api.wattsense.com/v1/devices/deviceId/discovery/bacnet/network
URI Parameters
HideShow
deviceId
string (required) 

the device id

network
string (required) 

the network name

Response  200
HideShow

The properties

Headers
Content-Type: application/json
Body
{
  "deviceId": "deviceId",
  "timestamp": 150000000,
  "network": "network_name",
  "bacnetDevices": [
    {
      "id": 11,
      "name": "counter_1",
      "description": "a module",
      "vendorIdentifier": 0,
      "vendorName": "vendor",
      "applicationSoftwareVersion": "version 1.1",
      "firmwareRevision": "2.3",
      "location": "Hello, world!",
      "bacnetObjects": [
        {
          "instance": 0,
          "name": "AO-1",
          "description": "voltmeter",
          "type": {
            "id": 1,
            "name": "OBJ_ANALOG_OUTPUT"
          },
          "units": {
            "id": 124,
            "name": "UNIT_MILLIVOLTS"
          },
          "propertyList": [
            {
              "id": 85,
              "name": "PROP_PRESENT_VALUE",
              "dataType": "INTEGER"
            }
          ]
        }
      ]
    }
  ]
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "deviceId": {
      "type": "string",
      "description": "the id of the device"
    },
    "timestamp": {
      "type": "number",
      "description": "the timestamp of when the discovery was sent (in milliseconds)"
    },
    "network": {
      "type": "string",
      "description": "the name of the network corresponding to this discovery"
    },
    "bacnetDevices": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "number",
            "description": "the id of this bacnet device"
          },
          "name": {
            "type": "string",
            "description": "the name of this device"
          },
          "description": {
            "type": "string",
            "description": "the description of this device"
          },
          "vendorIdentifier": {
            "type": "number",
            "description": "the vendor id"
          },
          "vendorName": {
            "type": "string",
            "description": "the name of the vendor"
          },
          "applicationSoftwareVersion": {
            "type": "string",
            "description": "the version of the software on that device"
          },
          "firmwareRevision": {
            "type": "string",
            "description": "the firmware revision"
          },
          "location": {
            "type": "string",
            "description": "the value of location property"
          },
          "bacnetObjects": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "instance": {
                  "type": "number",
                  "description": "the instance number of this object"
                },
                "name": {
                  "type": "string",
                  "description": "the name of this object"
                },
                "description": {
                  "type": "string",
                  "description": "the description of this object"
                },
                "type": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "number",
                      "description": "the BACnet id for this object"
                    },
                    "name": {
                      "type": "string",
                      "description": "the name of this BACnet object from the specs, null if it's an unkown object"
                    }
                  },
                  "description": "the type of this object"
                },
                "units": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "number",
                      "description": "the BACnet id for the units"
                    },
                    "name": {
                      "type": "string",
                      "description": "the name of this units value from the specs, null if it's an unkown unit"
                    }
                  },
                  "description": "the units for this object"
                },
                "propertyList": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "number",
                        "description": "the BACnet id for this property"
                      },
                      "name": {
                        "type": "string",
                        "description": "the name of this BACnet property from the specs, null if it's an unkown property"
                      },
                      "dataType": {
                        "type": "string",
                        "description": "the datatype of this BACnet property"
                      }
                    }
                  },
                  "description": "the list of properties available on this object"
                }
              }
            },
            "description": "the bacnet objects of this device"
          }
        }
      },
      "description": "the bacnet devices of this network"
    }
  }
}
Response  404
HideShow

Device or bacnet discovery for that network not found

Headers
Content-Type: application/json

Device events

Listing the events related to a device
GET/v1/devices/{deviceId}/events{?code,property,page,size,sort}

List all the events related to a specific device, i.e. the events sent by a device. This include:

  • Network config related errors (codes 2xxx)

  • Data config related errors (codes 3xxx)

  • Property related error (codes 4xxx), for example:

    • Unable to read a property (code 4001)
    • Unable to set a property (code 4002)
    • Property write error (code 4003)

Every event comes with a description message field and a property field if this event is related to a property.

Example URI

GET https://api.wattsense.com/v1/devices/deviceId/events?code=&property=&page=1&size=500&sort=timestamp,desc
URI Parameters
HideShow
deviceId
string (required) 
code
string (optional) 

list only events with this code

property
string (optional) 

list only events related to this specific property

page
number (optional) Example: 1

The page number of the results to get. One based, i.e. [1…N]

size
number (optional) Default: 20 Example: 500

The number of records to recover, maximum is 1000.

sort
string (optional) Example: timestamp,desc

The sort parameter and direction of data. Example: ?sort=timestamp,asc will order data by timestamp in ascending order. Other possible attributes for sorting are code and property.

Response  200
HideShow

The properties

Headers
Content-Type: application/json
Body
[
  {
    "eventId": "hexstringvalue",
    "deviceId": "deviceId",
    "code": 4002,
    "message": "Unable to set property",
    "property": "prop",
    "timestamp": 150000000
  }
]
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "eventId": {
        "type": "string",
        "description": "The id of this event"
      },
      "deviceId": {
        "type": "string",
        "description": "the id of the device sending the event"
      },
      "code": {
        "type": "number",
        "description": "the code of this event"
      },
      "message": {
        "type": "string",
        "description": "The message associated with this event"
      },
      "property": {
        "type": "string",
        "description": "the property associated with this event"
      },
      "timestamp": {
        "type": "number",
        "description": "the timestamp of when the event was sent (in milliseconds)"
      }
    }
  }
}
Response  204
HideShow

No more content. This happens if there is no data for this time range or property, or you are trying to fetch a page out of limits.

Response  400
HideShow

Something is wrong with your request

Headers
Content-Type: application/json
Body
{
  "status": 400,
  "message": "unable to parse",
  "errors": {
    "json-field-name": "reason"
  },
  "timestamp": 10000000
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "status": {
      "type": "number",
      "description": "HTTP status code"
    },
    "message": {
      "type": "string",
      "description": "The reason the request failed"
    },
    "errors": {
      "$ref": "#/definitions/json-field-name",
      "description": "An object containing a message for each field that raised this error"
    },
    "timestamp": {
      "type": "number",
      "description": "The time at which this error was raised"
    }
  },
  "definitions": {
    "json-field-name": {
      "type": "object",
      "patternProperties": {
        "": {
          "type": "string"
        }
      }
    }
  }
}
Response  401
HideShow

Check your credentials

Headers
Content-Type: application/json
Response  403
HideShow

Nothing to see here

Headers
Content-Type: application/json
Response  404
HideShow

Device not found

Headers
Content-Type: application/json

User

APIs to query the user and subscriptions.

Note These endpoints are valid only when authenticating using basic authentication. API keys do not have access to these resources.

Get the current user's subscriptions

Get the current user's subscriptions
GET/v1/subscriptions

Returns the basic information about the subscriptions the user has access to.

Example URI

GET https://api.wattsense.com/v1/subscriptions
Response  200
HideShow

OK

Headers
Content-Type: application/json
Body
[
  {
    "id": "uuid",
    "name": "a short name",
    "accountId": "uuid",
    "description": "a long description"
  }
]
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "id": {
        "type": "string",
        "description": "of-my-subscription (string) - a unique uuid"
      },
      "name": {
        "type": "string",
        "description": "The name of the subscription"
      },
      "accountId": {
        "type": "string",
        "description": "The account this subscription belongs to"
      },
      "description": {
        "type": "string",
        "description": "A description of the subscription"
      }
    }
  }
}

Get the current user's information

Get the current user's information
GET/v1/user

Returns the basic information about the current user and its roles in the different subscriptions they have access to.

Example URI

GET https://api.wattsense.com/v1/user
Response  200
HideShow

OK

Headers
Content-Type: application/json
Body
{
  "username": "user@company.tld",
  "accountId": "uuid",
  "isAccountAdmin": false,
  "roles": {
    "subscriptionId": "SUBSCRIPTION_ADMIN"
  }
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "username": {
      "type": "string",
      "description": "the user's username"
    },
    "accountId": {
      "type": "string",
      "description": "the account the user belongs to"
    },
    "isAccountAdmin": {
      "type": "boolean",
      "description": "whether the user is the admin of his account or not"
    },
    "roles": {
      "$ref": "#/definitions/subscriptionId"
    }
  },
  "definitions": {
    "subscriptionId": {
      "type": "object",
      "patternProperties": {
        "": {
          "type": "string",
          "enum": [
            "SUBSCRIPTION_ADMIN",
            "REGULAR_USER",
            "READ_ONLY_USER"
          ]
        }
      }
    }
  }
}

List users of the same account

List users of the same account
GET/v1/users

Returns the basic information about the users belonging to the same account as the current user.

Example URI

GET https://api.wattsense.com/v1/users
Response  200
HideShow

OK

Headers
Content-Type: application/json
Body
[
  {
    "username": "user@company.tld",
    "accountId": "uuid",
    "isAccountAdmin": false,
    "roles": {
      "subscriptionId": "SUBSCRIPTION_ADMIN"
    }
  }
]
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "username": {
        "type": "string",
        "description": "the user's username"
      },
      "accountId": {
        "type": "string",
        "description": "the account the user belongs to"
      },
      "isAccountAdmin": {
        "type": "boolean",
        "description": "whether the user is the admin of his account or not"
      },
      "roles": {
        "$ref": "#/definitions/subscriptionId"
      }
    }
  },
  "definitions": {
    "subscriptionId": {
      "type": "object",
      "patternProperties": {
        "": {
          "type": "string",
          "enum": [
            "SUBSCRIPTION_ADMIN",
            "REGULAR_USER",
            "READ_ONLY_USER"
          ]
        }
      }
    }
  }
}

Generated by aglio on 11 Dec 2018