Welcome to the WoTKit¶
The WoTKit is a web-centric toolkit that helps organizations manage sensors and actuators to collect, aggregate, store and process sensor data and react to changes in the physical and virtual world.
To get started quickly, see the Quick Start guide. For more information see consult the V1 API Reference.
Please send any questions and feedback to info@sensetecnic.com.
Guide¶
WoTKit API Guides¶
In this section we have listed tutorials which guide users through the API. For reference documentation, refer to Sensor Data.
Organizations for Privacy and Visibility¶
WoTKit organizations are used to group sensors owned by an organization, and restrict the visibility of sensors and groups to other users in the system who are members of the same organization.
Organization members may have different roles: OWNER, ADMIN, and MEMBER.
- MEMBER - a member can view private sensors and groups in the organization. They cannot add sensors or groups to the organization, modify organization membership or roles, or delete the organization.
- ADMIN - an admin is a MEMBER who can add or remove members, and add or remove sensors and groups to an organization. They have read and write priveledges to sensors and groups.
- OWNER - an owner is an ADMIN who owns the organization and can delete the organization.
Private Sensors and Groups¶
When group or sensor is marked as private, it can only be viewed by organization members.
Note: when a group contains a mix of private and public sensors from different organizations, some sensors in a group may not be visible to all users in a given organization.
Creating an Organization¶
When you create an organization, you are the owner of that organization. As owner, you can add members, and assign roles.
Querying Sensor Data¶
WoTKit provides flexibility in how you want to query your data. In the following section, we walk through the different ways of building a query to get sensor data out of wotkit. The queries are constructed using query parameters which you append to a URL endpoint.
Generally, the use cases of the data api is to query for the raw time-series data of a sensor or group of sensors. There are two different types of queries: Recent Queries and Time Range Queries.
Recent Queries are used to easily look at recent information. The API provides parameters for you to either:
- get n most recent sensor_data
- get sensor_data since t milliseconds in the past
- Time Range Queries are useful for going through data in the past.
- These queries allow you to page through data by specifying a start & end point in time.
The following document will walk through some examples of how to take advantage of Recent Queries and Time Range Queries
Recent Queries¶
In this section we’ll dive in quickly and briefly show an example of Recent Num Queries and Recent Time Queries.
Recent Num Queries¶
By default, the data endpoint will return the 100 most recent queries. Try it using a URL like this:
http://wotkit.sensetecnic.com/api/v2/sensors/sensetecnic.mule1/data
The response should look similar to the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | {
"numFound": 100564,
"data": [
{
"id": 47902511,
"timestamp": "2013-11-29T00:46:36.056Z",
"sensor_id": 1,
"sensor_name": "sensetecnic.mule1",
"value": 69,
"lng": -123.17608,
"lat": 49.14103
},
{
"id": 47902514,
"timestamp": "2013-11-29T00:46:39.556Z",
"sensor_id": 1,
"sensor_name": "sensetecnic.mule1",
"value": 52,
"lng": -123.17599,
"lat": 49.13919
},
... // more data
],
"query": {
"limit": 100,
"recent_n": 100
}
}
|
The data is returned in JSON. Generally, all list responses are returned in this container to aid paging and debugging.
Field | Description |
---|---|
numFound | The total number of elements matching this query |
data | The enclosed sensor_data. Always sorted from oldest to newest timestamp |
query | Contains the interpreted query from the request. For debugging. |
metadata | Extra information. Depends on use case. |
The query field is particularly interesting because it tells you how the query was interpreted. In this case, the query has a limit of 100 and a recent_n of 100. A recent_n query fetches the n most recent items. This is useful when API users want to peek at the recent data without having to construct complex queries.
In essence, the query we ran is a convenient default for the explicit version:
http://wotkit.sensetecnic.com/api/v2/sensors/sensetecnic.mule1/data?limit=100&recent_n=100
Next we can try a recent_t query, which looks up the timestamp
Recent Time Queries¶
Recent Time are very similar to Recent Num Queries. The difference is that Recent Num Queries look at data count i.e. the last 10 elements, or the last 50 elements. Recent Time queries look at the timestamp instead. So, it’s useful for where we’re interested in the elements from the last hour, or the 12 hours.
Request
http://wotkit.sensetecnic.com/api/v2/sensors/sensetecnic.mule1/data?recent_t=10000
Response
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | {
"numFound": 3,
"data": [
{
"id": 47967438,
"timestamp": "2013-11-29T18:34:09.557Z",
"sensor_id": 1,
"sensor_name": "sensetecnic.mule1",
"value": 62,
"lng": -123.14509,
"lat": 49.186
},
{
"id": 47967445,
"timestamp": "2013-11-29T18:34:13.059Z",
"sensor_id": 1,
"sensor_name": "sensetecnic.mule1",
"value": 53,
"lng": -123.1454,
"lat": 49.18565
},
{
"id": 47967446,
"timestamp": "2013-11-29T18:34:16.557Z",
"sensor_id": 1,
"sensor_name": "sensetecnic.mule1",
"value": 67,
"lng": -123.14844,
"lat": 49.18323
}
],
"query": {
"limit": 100,
"recent_t": 10000
}
}
|
Looking at the query field this time, we can see it was interpreted as a recent_t query. The query looked for items up to 10 seconds ago (10000 milliseconds). You can verify this by inspecting the timestamp of the data.
Note
When accessing WoTKit anonymously, the date string is set to UTC. If you access it an api-key, the timezone will be set based on the account’s settings.
We’ve just shown you how to run both Recent Queries. One parameter to make note of is the limit parameter. At the moment, limit is capped at 100 – which restricts how much data you get in recent_n and recent_t queries. To overcome this we will look into paging through historical data next.
Time Range Queries¶
At the end of the last section, we noted that there is a weakness in the recent queries which limit your ability to sift through historical data. So, to look through historical data, you can page through historical data using the following query parameters. For the remainder of this, we will be working with the sensor rymndhng.sdq-test.
Querying with Start and End¶
We’ll start with a simple practical example. We have a defined starting time and ending time where we want to get all the data in between. I want to know what data was there between start: "2013-11-21T11:00:51.000Z" to end: "2013-11-29T22:59:54.862Z"
Note
It’s important to note that start is exclusive and end is inclusive. i.e. for start=100 and end=200, then the query does the following:
start < sensor_data.timestamp <= end
Query Parameters
Query Parameter | Value |
---|---|
start | 1385031651000 (2013-11-21T11:00:51.000Z) |
end | 1385765994862 (2013-11-29T22:59:54.862Z) |
Translating those two strings to milliseconds, we end up with the request below. Execute it and follow the response.
Request
http://wotkit.sensetecnic.com/api/v2/sensors/rymndhng.sdq-test/data?start=1385031651000&end=1385765994862
Response
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | {
"numFound": 5,
"data": [
{
"id": 48232725,
"timestamp": "2013-11-29T22:59:09.472Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"valua": 81
},
{
"id": 48232726,
"timestamp": "2013-11-29T22:59:09.472Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"valua": 53
},
{
"id": 48232727,
"timestamp": "2013-11-29T22:59:19.633Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"valua": 0
},
{
"id": 48232728,
"timestamp": "2013-11-29T22:59:24.715Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"valua": 56
},
{
"id": 48232729,
"timestamp": "2013-11-29T22:59:54.862Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"value": 97
}
],
"query": {
"end": 1385765994862,
"start": 1385031651000,
"limit": 100
}
}
|
Once again, let’s look at the query parameter in the response to see what was interpreted. We can see that start/end was interpreted in the query. Inspect the timestamps of of both data points, we can see it’s between the start/end points, specifically start < data[0].timestamp < ... < data[4].timestamp < end.
Paging Through Data¶
In the previous section, we gave a very naive example. In this case, only two elements were in the range and therefore all the relevent data was returned. Very often this isn’t the case – and you may want to sift through thousands of entries at a time. To do this, we enabled paging through data entries. We’ll also specify limit to 10 to make the Response more comprehenedable.
Let’s try to query all the data by choosing start: 0 and and a really large end: 2000000000000.
Query Parameters
Query Parameter | Value |
---|---|
start | 0 (1970-01-01T00:00:00.000Z) |
end | 2000000000000 (2033-05-18T03:33:20.000Z) |
limit | 3 |
Request
http://wotkit.sensetecnic.com/api/v2/sensors/rymndhng.sdq-test/data?start=0&end=2000000000000&limit=3
Response
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | {
"numFound": 9,
"data": [
{
"id": 48232722,
"timestamp": "2013-11-21T10:58:51.000Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"value": 6.7
},
{
"id": 48232723,
"timestamp": "2013-11-21T10:59:51.000Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"value": 6.8
},
{
"id": 48232724,
"timestamp": "2013-11-21T11:00:51.000Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"value": 6.9
}
],
"query": {
"end": 2000000000000,
"start": 0,
"limit": 3
}
}
|
So this time, first we look at the query parameter. As mentioned previously, the limit is currently capped at 3. So how do we know if we there’s more data? Well, there is another field in the response which can help us: numFound. numFound counts all the data found within the data range from start to end. In this example, we know there’s more data because data.length < numFound.
Given this information, we can now continue paging data by setting offset. We can retrieve the next page by choosing offset = data.size, in this case, data.size is 10. Generally, we can page by specifying offset = prev_offset + data.size. We can also figure out if we’re at the end of the data range generally by testing that data.size + offset < numFound.
Now, let’s rerun the last query with an offset.
Query Parameters
Parameter | Value |
---|---|
start | 0 (same as before |
end | 2000000000000 (same as before) |
limit | 10 |
offset | 3 |
Request
http://wotkit.sensetecnic.com/api/v2/sensors/rymndhng.sdq-test/data?start=0&end=2000000000000&limit=3&offset=3
Response
{
"numFound": 9,
"data": [
{
"id": 48232725,
"timestamp": "2013-11-29T22:59:09.472Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"valua": 81
},
{
"id": 48232726,
"timestamp": "2013-11-29T22:59:09.472Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"valua": 53
},
{
"id": 48232727,
"timestamp": "2013-11-29T22:59:19.633Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"valua": 0
}
],
"query": {
"offset": 3,
"end": 2000000000000,
"start": 0,
"limit": 3
}
}
Once again, looking at the query, we can now see that offset is specfied as 3. We can also verify that an offset was used by looking at id and timestamp of the two responses. The last element of the first response has id: 48232724 and timestamp: "2013-11-21T11:00:51.000Z". The first element in the second response has id: 48232725 and timestamp: "2013-11-29T22:59:09.472Z". You can easily verify that they are in sequence.
Advanced Time Range Queries¶
In general, using start, end, offset provides enough flexibility. However, sensors are allowed to have multiple data on the same timestamp. This can easily happen when historical data is PUT into the system. In other words, you cannot expect timestamp to be unique for sensor data (generally they are good enough). So, we introduce the idea of start_id and end_id to allow precise selection of start and end elements.
We’ll start off with our first query .. code-block:: javascript
Response
{
"numFound": 9,
"data": [
{
"id": 48232722,
"timestamp": "2013-11-21T10:58:51.000Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"value": 6.7
},
{
"id": 48232723,
"timestamp": "2013-11-21T10:59:51.000Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"value": 6.8
},
{
"id": 48232724,
"timestamp": "2013-11-21T11:00:51.000Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"value": 6.9
},
{
"id": 48232725,
"timestamp": "2013-11-29T22:59:09.472Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"valua": 81
}
],
"query": {
"start": 0,
"limit": 4
}
}
Now sometime in the future, we want to rerun the query using the information we had previously. So, we’ll use the last item’s timestamp (2013-11-29T22:59:09.472Z) as the start value.
Request
http://wotkit.sensetecnic.com/api/v2/sensors/rymndhng.sdq-test/data?start=1385765949472&limit=4
Response
{
"numFound": 4,
"data": [
{
"id": 48232727,
"timestamp": "2013-11-29T22:59:19.633Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"valua": 0
},
{
"id": 48232728,
"timestamp": "2013-11-29T22:59:24.715Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"valua": 56
},
{
"id": 48232729,
"timestamp": "2013-11-29T22:59:54.862Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"value": 97
},
{
"id": 48232730,
"timestamp": "2013-11-29T23:00:24.862Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"value": 6.7
}
],
"query": {
"start": 1385765949472,
"limit": 4
}
}
Everything looks fine and dandy doesn’t it? The timestamps are incremental, and therefore all is well is it? Well, no it actually isn’t. There’s a problem which we are unaware of. We’ve actually skipped an element because of duplicate timestamps.
Run this request which querys the entire range and look at the data.
Request
http://wotkit.sensetecnic.com/api/v2/sensors/rymndhng.sdq-test/data
Response
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | {
"numFound": 9,
"data": [
{
"id": 48232722,
"timestamp": "2013-11-21T10:58:51.000Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"value": 6.7
},
{
"id": 48232723,
"timestamp": "2013-11-21T10:59:51.000Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"value": 6.8
},
{
"id": 48232724,
"timestamp": "2013-11-21T11:00:51.000Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"value": 6.9
},
{
"id": 48232725,
"timestamp": "2013-11-29T22:59:09.472Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"valua": 81
},
{
"id": 48232726,
"timestamp": "2013-11-29T22:59:09.472Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"valua": 53
},
{
"id": 48232727,
"timestamp": "2013-11-29T22:59:19.633Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"valua": 0
},
{
"id": 48232728,
"timestamp": "2013-11-29T22:59:24.715Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"valua": 56
},
{
"id": 48232729,
"timestamp": "2013-11-29T22:59:54.862Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"value": 97
},
{
"id": 48232730,
"timestamp": "2013-11-29T23:00:24.862Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"value": 6.7
}
],
"query": {
"limit": 100,
"recent_n": 10
}
}
|
The highlighted lines for id: 48232726 did not exist in either of our queries. In Querying with Start and End, we specified the second query did exactly what you asked for: Query sensor data after timestamp 1385765949472 limit 3. So, to solve this, we introduce a new parameter start_id. This parameter can be used in conjuction with start to specify specify which data element’s id to start with. Essentially, sensor_data are uniquely identified using this tuple (timestamp, id). So, let’s rerun the second query with start_id: 48232725 from the first query.
Request
http://wotkit.sensetecnic.com/api/v2/sensors/rymndhng.sdq-test/data?start=1385765949472&limit=4&start_id=48232725
Response
{
"numFound": 5,
"data": [
{
"id": 48232726,
"timestamp": "2013-11-29T22:59:09.472Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"valua": 53
},
{
"id": 48232727,
"timestamp": "2013-11-29T22:59:19.633Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"valua": 0
},
{
"id": 48232728,
"timestamp": "2013-11-29T22:59:24.715Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"valua": 56
},
{
"id": 48232729,
"timestamp": "2013-11-29T22:59:54.862Z",
"sensor_id": 531,
"sensor_name": "rymndhng.sdq-test",
"value": 97
}
],
"query": {
"start": 1385765949472,
"limit": 4,
"start_id": 48232725
}
}
There, we got the response with id: 48232726. The start_id allowed us to filter ids greater than 3. end_id works the same way as start_id if you really need fine-grained control over the range of a data query.
Summary of Time Range Data Query¶
With all the information given, we can really condense the query parameters into the following query. data_ts is the sensor data’s timestamp, and data_id is the data’s id element.
Without start_id or end_id, the query range is done like this.
start < data_ts <= end
With start_id and/or end_id, the query range adds extra checks near the bounds
(start < data_ts <= end)
OR (data_ts = start AND data_id > start_id)
OR (data_ts = end AND data_id <= end_id)
Below is a quicky summary of what query parameter means:
Parameter | Type | Description |
---|---|---|
start | timestamp | The absolute starting point (in milliseconds since Jan 1, 1970). |
start_id | id | The starting id of sensor_data at timestamp start. Used for paging. |
end | timestamp | The absolute ending timestamp (in milliseconds since Jan 1, 1970) |
end_id | timestamp | The end id of sensor_data with timestamp end. Used for paging. |
Sensor Data Query Recipes¶
In this section, we will highlight some novel ways of combining the information above to query the data.
Use start_id instead of start for start of query¶
In the documentation, we used start_id alongisde start, but actually, this is optional. If you use start_id without start, we will actually lookup the timestamp of the element with id start_id, and then use that as the starting timestamp.
Making Start Inclusive¶
From Summary of Time Range Data Query, it shows the start range is exclusive. But, there is a way to make this inclusive. If you set start_id: 0, it will make the data range inclusive.
V1 API Reference¶
This section contains API References for V1 of WoTKit’s API. In addition to the documentation posted here, our API can be explored using Swagger with the following URL http://wotkit.sensetecnic.com/api/api-docs?path=v1.
Authentication¶
The WoTKit API supports three forms of authentication to control access to a user’s sensors and other information on the WoTKit.
- Basic authentication using the user’s name and password
- Basic authentication with Keys (key id and key password)
- OAuth2 authorization of server-based Applications
Using the WoTKit portal, developers can create keys for use by one or more sensor gateways or scripts. Users can also register new server side applications and then authorize these applications to allow them to access a user’s sensors on their behalf.
Note
Most examples in this document use basic authentication with keys or WoTKit username and passwords. However, OAuth2 authorization is also possible by removing the id and password and by appending an access_token parameter. See apps-oauth-label for details.
Methods privacy¶
Some API methods are private and will return an HTTP status code of 403 Forbidden if accessed without authenticating the request, while others are completely private or are restricted to certain users. (Currently only system administrators have access to ALL methods),
Every method has a description of its private level in one of the following forms:
Public accessible to all
Private accessible only to authenticated users
Public or Private accessible to all, but might return different results to authenticated users.
- Example of different results is the “get sensors” method, which might return a user’s private sensors when the method is called as an authenticated user.
Admin accessible only to authenticated admin users
Keys and Basic Authentication¶
Keys are created on the WoTKit UI (http://wotkit.sensetecnic.com/wotkit/keys) and are unique to each user.
To grant a client access to your sensors, you can create a key. The client can then be supplied the auto-generated ‘key id’ and ‘key password’. These will act as username and password credentials, using basic authentication to access sensors on the user’s behalf.
For instance, the following curl command uses a ‘key id’ and ‘key password’ to get information about the sensor sensetecnic.mule1.
(Please replace the {key_id} and {key_password} in the code with appropriate values copied from the WoTKit UI.)
example
curl --user {key_id}:{key_password} "http://wotkit.sensetecnic.com/api/sensors/sensetecnic.mule1"
This returns:
{
"name":"mule1",
"fields":[
{"name":"lat","value":49.20532,"type":"NUMBER","index":0,
"required":true,"longName":"latitude","lastUpdate":"2012-12-07T01:47:18.639Z"},
{"name":"lng","value":-123.1404,"type":"NUMBER","index":1,
"required":true,"longName":"longitude","lastUpdate":"2012-12-07T01:47:18.639Z"},
{"name":"value","value":58.0,"type":"NUMBER","index":2,
"required":true,"longName":"Data","lastUpdate":"2012-12-07T01:47:18.639Z"},
{"name":"message","type":"STRING","index":3,
"required":false,"longName":"Message"}
],
"id":1,
"visibility":PUBLIC,
"owner":"sensetecnic",
"description":"A big yellow taxi that travels from
Vincent's house to UBC and then back.",
"longName":"Big Yellow Taxi",
"latitude":51.060386316691,
"longitude":-114.087524414062,
"lastUpdate":"2012-12-07T01:47:18.639Z"}
}
Registered Applications and OAuth2¶
The WoTKit supports the OAuth2 authorization framework as described in RFC 6749.
Applications are registered on the WoTKit UI (http://wotkit.sensetecnic.com/wotkit/apps) by an application developer. Applications can be installed by many users, but the application credentials called the client_id and client_secret are unique to that application.
Once registered, the client application then uses its ‘Client ID’ and generated ‘Application Secret’ as credentials in the OAuth2 authorization process to request permission to access WoTKit resources on a user’s behalf by generating an access token. Using an access token, the application can them make API calls to the WoTKit on behalf of the user – no further id/passwords are needed.
For example, the following curl command uses an access token to get information about the sensor sensetecnic.mule1.
example
curl "http://wotkit.sensetecnic.com/api/sensors/sensetecnic.mule1?access_token={access_token}"
The first step of OAuth 2 is to get authorization from the user. The WoTKit supports two grant types:
- Authorization Code for apps running on a web server
- Password for logging in with a username and password
Authorization Code Grant¶
In order to obtain an access token for a web server application using the Authorization Code grant, the following needs to be done:
Request an authorization code by providing the ‘Client ID’ as follows:
http://wotkit.sensetecnic.com/api/oauth/authorize?client_id={application client id} &response_type=code&redirect_uri={redirect uri}
If the user has not previously logged into the WoTKit authorization server, a login page will be presented. A WoTKit user must first log in.
Once logged in, a prompt will ask the user to authorize the ‘application client id’ to act on their behalf. Once authorized, an ‘authorization code’ is provided.
Using the application credentials, this authorization code is exchanged for an access token used to access the WoTKit API.
Example: PHP file pointed to by {redirect_uri}
<?php
$code = $_GET['code'];
$access_token = "none";
$ch = curl_init();
if(isset($code)) {
// try to get an access token
$params = array("code" => $code,
"client_id"=> {application client id},
"client_secret" => {application secret},
"redirect_uri" => {redirect uri},
"grant_type" => "authorization_code");
$data = ArraytoNameValuePairs ($params);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, "http://wotkit.sensetecnic.com/api/oauth/token");
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$access_token = json_decode($response)->access_token;
}
?>
Password Grant¶
The password grant type can be used to exchange the user name and password for an access token directly. This is generally used by applications that are part of the WoTKit service, since they need to collect the user’s name and password.
To use the password grant type, you simply POST the name and password along with the client id and secret directly, in response you will receive an access token.
example
curl -d "grant_type=password&username={username}&password={password}&client_id={clientid}&client_secret={clientsecret}&scope=all" https://wotkit.sensetecnic.com/api/oauth/token
returns:
{
"access_token":"{access_token}",
"token_type":"bearer",
"refresh_token":"{refresh_token}",
"expires_in":43199,
"scope":"all"
}
Access Token Facts¶
When obtaining an access token, the ‘response’ field holds the following useful information:
response->access_token
response->expires_in
- default value is approx. 43200 seconds (or 12 hrs)
Error Reporting¶
Errors are reported with an HTTP status code accompanied by an error JSON object. The object contains the status, an internal error code, user-displayable message, and an internal developer message.
For example, when a sensor cannot be found, the following error is returned:
HTTP/1.1 404 Not Found
{
"error": {
"status": 404,
"code": 0,
"message": "No thing with that id or name",
"developerMessage": ["my_sensor"]
}
}
Sensors¶
A sensor represents a physical or virtual sensor or actuator. It contains a data stream made up of fields.
A sensor has the following attributes:
Name | Value Description |
---|---|
id | the numeric id of the sensor. This may be used in the API in place of the sensor name. |
name ** |
|
description ** | a description of the sensor for text searches. |
longName ** | longer display name of the sensor. |
url | deprecated |
latitude |
|
longitude |
|
lastUpdate |
|
visibility | PUBLIC: The sensor is publicly visible
ORGANIZATION: The sensor is visible to everyone in the same organization as the sensor
PRIVATE: The sensor is only visible to the owner. In any case posting data to the sensor is restricted to the sensor’s owner.
|
owner | the owner of the sensor |
fields | the expected data fields, their type (number or string), units and if available, last update time and value. |
tags | the list of tags for the sensor |
data | sensor data (not shown yet) |
** Required when creating a new sensor.
Querying Sensors¶
A list of matching sensors may also be queried by the system.
The current query parameters are as follows:
Name | Value Description |
---|---|
scope | all - all sensors the current user has access to
subscribed - the sensors the user has subscribed to
| contributed - the sensors the user has contributed to the system.
|
tags | list of comma separated tags |
orgs | list of comma separated organization names |
private |
|
visibility | filter by the visibility of the sensors, either of public, organization, or private |
text | text to search for in the name, long name and description |
active | when true, only returns sensors that have been updated in the last 15 minutes. |
offset | offset into list of sensors for paging |
limit | limit to show for paging. The maximum number of sensors to display is 1000. |
location |
|
To query for sensors, add query parameters after the sensors URL as follows:
URL | http://wotkit.sensetecnic.com/api/sensors?{query} |
Privacy | Public or Private |
Format | json |
Method | GET |
Returns | On error, an appropriate HTTP status code; On success, OK 204 and a list of sensor descriptions matching the query. |
example
curl --user {id}:{password} "http://wotkit.sensetecnic.com/api/sensors?tags=canada"
Output:
[
{
"tags":["data","vancouver","canada"],
"latitude":0.0,
"longitude":0.0,
"longName":"api-data-test-1",
"lastUpdate":"2013-01-26T01:55:36.514Z",
"name":"api-data-test-1",
"fields":
[{"required":true, "longName":"latitude",
"lastUpdate":"2013-01-26T01:55:36.514Z",
"name":"lat", "value":39.0, "type":"NUMBER","index":0},
{"required":true,"longName":"longitude",
"lastUpdate":"2013-01-26T01:55:36.514Z",
"name":"lng","value":85.0,"type":"NUMBER","index":1},
{"required":true,"longName":"Data",
"lastUpdate":"2013-01-26T01:55:36.514Z
"name":"value","value":20.0,"type":"NUMBER","index":2},
{"required":false,"longName":"Message",
"lastUpdate":"2013-01-26T01:55:36.514Z",
"name":"message","value":"test message to be active 164",
"type":"STRING","index":3}],
"id":69,
"visibility":"PUBLIC",
"owner":"roseyr",
"description":"api-data-test-1"
},
{
"tags":["data","canada","edmonton"],
"latitude":0.0,
"longitude":0.0,
"longName":"api-data-test-2",
"lastUpdate":"2013-01-26T01:55:42.400Z",
"name":"api-data-test-2",
"fields":
[{"required":true,"longName":"latitude",
"lastUpdate":"2013-01-26T01:55:37.537Z",
"name":"lat","value":65.0,"type":"NUMBER","index":0},
{"required":true,"longName":"longitude",
"lastUpdate":"2013-01-26T01:55:37.537Z",
"name":"lng","value":74.0,"type":"NUMBER","index":1},
{"required":true,"longName":"Data",
"lastUpdate":"2013-01-26T01:55:37.537Z",
"name":"value","value":82.0,"type":"NUMBER","index":2},
{"required":false,"longName":"Message",
"lastUpdate":"2013-01-26T01:55:37.537Z",
"name":"message","value":"test message to be active 110",
"type":"STRING","index":3}],
"id":70,
"visibility":"PUBLIC",
"owner":"roseyr",
"description":"api-data-test-1"
},
{
"tags":["data","canada","winnipeg"],
"latitude":0.0,
"longitude":0.0,
"longName":"api-data-test-3",
"lastUpdate":"2013-01-26T01:55:34.488Z",
"name":"api-data-test-3",
"fields":
[{"required":true,"longName":"latitude","name":"lat","value":0.0,
"type":"NUMBER","index":0},
{"required":true,"longName":"longitude","name":"lng","value":0.0,
"type":"NUMBER","index":1},
{"required":true,"longName":"Data","name":"value","value":0.0,
"type":"NUMBER","index":2},
{"required":false,"longName":"Message","name":"message",
"type":"STRING","index":3}],
"id":71,
"visibility":"PUBLIC",
"owner":"roseyr",
"description":"api-data-test-3"
}
]
Viewing a Single Sensor¶
To view a single sensor, query the sensor by sensor name or id as follows:
URL | http://wotkit.sensetecnic.com/api/sensors/{sensorname} |
Privacy | Public or Private |
Format | json |
Method | GET |
Returns | Appropriate HTTP status code; OK 200 - if successful |
example
curl --user {id}:{password} "http://wotkit.sensetecnic.com/api/sensors/sensetecnic.mule1"
Output:
{
"name":"mule1",
"fields":[
{"name":"lat","value":49.20532,"type":"NUMBER","index":0,
"required":true,"longName":"latitude",
"lastUpdate":"2012-12-07T01:47:18.639Z"},
{"name":"lng","value":-123.1404,"type":"NUMBER","index":1,
"required":true,"longName":"longitude",
"lastUpdate":"2012-12-07T01:47:18.639Z"},
{"name":"value","value":58.0,"type":"NUMBER","index":2,
"required":true,"longName":"Data",
"lastUpdate":"2012-12-07T01:47:18.639Z"},
{"name":"message","type":"STRING","index":3,
"required":false,"longName":"Message"}
],
"id":1,
"visibility":"PUBLIC",
"owner":"sensetecnic",
"description":"A big yellow taxi that travels
from Vincent's house to UBC and then back.",
"longName":"Big Yellow Taxi",
"latitude":51.060386316691,
"longitude":-114.087524414062,
"lastUpdate":"2012-12-07T01:47:18.639Z"}
}
Creating/Registering a Sensor¶
To register a sensor, you POST a sensor resource to the url /sensors.
- The sensor resources is a JSON object.
- The “name”, “longName”, and “description” fields are required when creating a sensor.
- The “latitude” and “longitude” fields are optional and will default to 0 if not provided.
- The “visibility” field is optional and will default to “PUBLIC” if not provided.
- The “tags”, “fields” and “organization” information are optional.
- If “visibility” is set to ORGANIZATION, a valid “organization” must be supplied.
- The sensor name must be at least 4 characters long, contain only lowercase letters, numbers, dashes and underscores, and can start with a lowercase letter or an underscore only.
To create a sensor:
URL | http://wotkit.sensetecnic.com/api/sensors |
Privacy | Private |
Format | json |
Method | POST |
Returns | HTTP status code; Created 201 if successful; Bad Request 400 if sensor is invalid; Conflict 409 if sensor with the same name already exists |
example
curl --user {id}:{password} --request POST --header "Content-Type: application/json" --data-binary @test-sensor.txt 'http://wotkit.sensetecnic.com/api/sensors'
For this example, the file test-sensor.txt contains the following. This is the minimal information needed to register a sensor resource.
{
"visibility":"PUBLIC",
"name":"taxi-cab",
"description":"A big yellow taxi.",
"longName":"Big Yellow Taxi",
"latitude":51.060386316691,
"longitude":-114.087524414062
}
Creating/Registering multiple Sensors¶
To register multiple sensors, you PUT a list of sensor resources to the url /sensors.
- The sensor resources is a JSON list of objects as described in Creating/Registering a Sensor.
- Limited to 100 new sensors per call. (subject to change)
URL | http://wotkit.sensetecnic.com/api/sensors |
Privacy | Private |
Format | json |
Method | PUT |
Returns | HTTP status code; Created 201 if successful; Bad Request 400 if sensor is invalid; Conflict 409 if sensor with the same name already exists ; On Created 201 or some errors (not all) you will receive a JSON dictionary where the keys are the sensor names and the values are true/false depending on whether creating the sensor succeeded. For Created 201 all values will be true. |
Updating a Sensor¶
Updating a sensor is the same as registering a new sensor other than PUT is used and the sensor name or id is included in the URL.
Note that all top level fields supplied will be updated.
- You may update any fields except “id”, “name” and “owner”.
- Only fields that are present in the JSON object will be updated.
- If “visibility” is set to ORGANIZATION, a valid “organization” must be supplied.
- If “tags” list or “fields” list are included, they will replace the existing lists.
- If “visibility” is hardened (that is, the access to the sensor becomes more restrictive) then all currently subscribed users are automatically unsubscribed, regardless of whether they can access the sensor after the change.
To update a sensor owned by the current user:
URL | http://wotkit.sensetecnic.com/api/sensors/{sensorname} |
Privacy | Private |
Format | json |
Method | PUT |
Returns | HTTP status code; No Content 204 if successful |
For instance, to update a sensor description and add tags:
example
curl --user {id}:{password} --request PUT --header "Content-Type: application/json" --data-binary @update-sensor.txt 'http://wotkit.sensetecnic.com/api/sensors/taxi-cab'
The file update-sensor.txt would contain the following:
{
"visibility":"PUBLIC",
"name":"taxi-cab",
"description":"A big yellow taxi. Updated description",
"longName":"Big Yellow Taxi",
"latitude":51.060386316691,
"longitude":-114.087524414062,
"tags": ["big", "yellow", "taxi"]
}
Deleting a Sensor¶
Deleting a sensor is done by deleting the sensor resource.
To delete a sensor owned by the current user:
URL | http://wotkit.sensetecnic.com/api/sensors/{sensorname} |
Privacy | Private |
Format | not applicable |
Method | DELETE |
Returns | HTTP status code; No Response 204 if successful |
example
curl --user {id}:{password} --request DELETE 'http://wotkit.sensetecnic.com/api/sensors/test-sensor'
Sensor Subscriptions¶
Sensor subscriptions are handled using the /subscribe URL.
Get Sensor Subscriptions¶
To view sensors that the current user is subscribed to:
URL | http://wotkit.sensetecnic.com/api/subscribe |
Privacy | Private |
Format | json |
Method | GET |
Returns | Appropriate HTTP status code; OK 200 - if successful |
Subscribe¶
To subscribe to a non-private sensor or private sensor owned by the current user:
URL | http://wotkit.sensetecnic.com/api/subscribe/{sensorname} |
Privacy | Private |
Format | json |
Method | PUT |
Returns | HTTP status code; No Content 204 if successful |
Unsubscribe¶
To unsubscribe from a sensor:
URL | http://wotkit.sensetecnic.com/api/subscribe/{sensorname} |
Privacy | Private |
Format | json |
Method | DELETE |
Returns | HTTP status code; No Content 204 if successful |
Sensor Fields¶
Sensor fields are the fields of data saved in a sensor stream. Together they make up the sensor schema.
Each sensor has the following default fields:
Field Name | Information |
---|---|
value | The numerical data for the sensor. Required. |
lat | The latitude of the sensor. Required. |
lng | The longitude of the sensor. Required. |
message | The string message for the sensor. Not Required. |
Each sensor field consists of the following:
Field Name | Information |
---|---|
name | The unique name for the sensor field. It is required when creating/updating/deleting a field and cannot be changed. |
longName | The display name for the field. |
type | Can be “NUMBER” or “STRING”. It is required when creating/updating a field. |
required | Is a boolean field. If true, data sent to a sensor must include this field or an error will result. Optional. |
units | Is a string. Optional. |
index | The numerical index of the field used to maintain ordering. This field is automatically generated by the system and is read only. |
value | The last value of this sensor field received by the sensor when sending data. This is a read only field set when the sensor receives data for this field. |
lastUpdate | The time stamp of the last value sent to the field. This is a read only field set when the sensor receives data for this field. |
Querying Sensor Fields¶
To retrieve the sensor fields for a specific sensor:
URL | http://wotkit.sensetecnic.com/api/sensors/{sensorname}/fields |
Privacy | Public or Private |
Format | json |
Method | GET |
Returns | Appropriate HTTP status code; OK 200 - if successful |
To query a single sensor field for a specific sensor:
URL | http://wotkit.sensetecnic.com/api/sensors/{sensorname}/fields/{fieldName} |
Privacy | Public or Private |
Format | json |
Method | GET |
Returns | Appropriate HTTP status code; OK 200 - if successful |
Updating a Sensor Field¶
You can update or add a sensor field by performing a PUT operation to the specified field. The field information is supplied in a JSON format.
If the sensor already has a field with the given name, it will be updated with new information. Otherwise, a new field with that name will be created.
Notes:
- When inputting field data, the sub-fields “name” and “type” are required-both for adding a new field or updating an existing one.
- Read only sub-fields such as index, value and lastUpdate should not be supplied.
- The “name” sub-field of an existing field cannot be updated.
- For user defined fields, the “longName”, “type”, “required”, and “units” sub-fields may be updated.
- You cannot change the index of a field. If a field is deleted, the index of the following fields will be adjusted to maintain the field order.
To update/add a sensor field:
URL | http://wotkit.sensetecnic.com/api/sensors/{sensorname}/fields/{fieldname} |
Privacy | Private |
Format | json |
Method | PUT |
Returns | HTTP status code; No Content 204 if successful |
For instance, to create a new field called “test-field”:
example
curl --user {id}:{password} --request POST --header "Content-Type: application/json" --data-binary @field-data.txt 'http://wotkit.sensetecnic.com/api/sensors/test-sensor/fields/test-field'
The file field-data.txt could contain the following. (This is the minimal information needed to create a new field.)
{
"name":"test-field",
"type":"STRING"
}
To then update “test-field” sub-fields, the curl command would be used to send a PUT request.
example
curl --user {id}:{password} --request PUT --header "Content-Type: application/json" --data-binary @field-data.txt 'http://wotkit.sensetecnic.com/api/sensors/test-sensor/fields/test-field'
And ‘’field-data.txt’’ could now contain the following.
{
"name":"test-field",
"type":"NUMBER",
"longName":"Test Field",
"required":true,
"units":"mm"
}
Deleting a Sensor Field¶
You can delete an existing sensor field by performing a DELETE and including the field name in the URL.
To delete a sensor field:
URL | http://wotkit.sensetecnic.com/api/sensors/{sensorname}/fields/{fieldname} |
Privacy | Private |
Format | n/a |
Method | DELETE |
Returns | HTTP status code; No Content 204 if successful |
Sensor Data¶
In the WoTKit, sensor data consists of a timestamp followed by one or more named fields. There are a number of reserved fields supported by the WoTKit:
Reserved field name | Description |
---|---|
timestamp | the time that the sensor data was collected. This is a long integer representing the number of milliseconds from Jan 1, 1970 UTC. Optional; if not supplied, a server-supplied timestamp will be used. |
id | a unique identifier for the data reading. This is to distinguish one reading from another when they share the same timestamp. Read only; This field is read only and should not be sent by the client when sending new data. |
sensor_id | the globally unique sensor id that produced the data. Read only; This is a read only field generated by the wotkit that should not be sent by a client when sending new data. |
sensor_name | the globally unique sensor name, in the form {username}.{sensorname}. Read only; This is a read only field and should not be sent by the client when sending new data. |
When a new sensor is created, a number of default fields are created by the wotkit for a sensor as follows. Note that these can be changed by editing the sensor fields.
In addition to these reserved fields, additional required or optional fields can be added by updating the sensor fields in the WoTKit UI or sensor_fields in the API.
Note
* Python’s time.time() function generates the system time in seconds, not milliseconds.
To convert this to an integer in milliseconds use int(time.time()*1000). Using Java: System.currentTime().
Sending New Data¶
To send new data to a sensor, POST name value pairs corresponding to the data fields to the /sensors/{sensorname}/data URL.
There is no need to provide a timestamp since it will be assigned by the server. Data posted to the system will be processed in real time.
To send new data:
URL | http://wotkit.sensetecnic.com/api/sensors/{sensorname}/data |
Privacy | Private |
Format | not applicable |
Method | POST |
Returns | HTTP status code; No Response 201 (Created) if successful |
example
curl --user {id}:{password} --request POST -d value=5 -d lng=6 -d lat=7 'http://wotkit.sensetecnic.com/api/sensors/test-sensor/data'
Sending Bulk Data¶
To send a range of data, you PUT data (rather than POST) data into the system. Note that data PUT into the WoTKit will not be processed in real time, since it occurred in the past
- The data sent must contain a list of JSON objects containing a timestamp and a value.
- If providing a single piece of data, existing data with the provided timestamp will be deleted and replaced. Otherwise, the new data will be added.
- If providing a range of data, any existing data within this timestamp range will be deleted and replaced by the new data.
To update data:
URL | http://wotkit.sensetecnic.com/api/sensors/{sensorname}/data |
Privacy | Private |
Format | JSON |
Method | PUT |
Returns | HTTP status code; No Response 204 if successful |
Example of valid data:
[{"timestamp":"2012-12-12T03:34:28.626Z","value":67.0,"lng":-123.1404,"lat":49.20532},
{"timestamp":"2012-12-12T03:34:28.665Z","value":63.0,"lng":-123.14054,"lat":49.20554},
{"timestamp":"2012-12-12T03:34:31.621Z","value":52.0,"lng":-123.14063,"lat":49.20559},
{"timestamp":"2012-12-12T03:34:35.121Z","value":68.0,"lng":-123.14057,"lat":49.20716},
{"timestamp":"2012-12-12T03:34:38.625Z","value":51.0,"lng":-123.14049,"lat":49.20757},
{"timestamp":"2012-12-12T03:34:42.126Z","value":55.0,"lng":-123.14044,"lat":49.20854},
{"timestamp":"2012-12-12T03:34:45.621Z","value":56.0,"lng":-123.14215,"lat":49.20855},
{"timestamp":"2012-12-12T03:34:49.122Z","value":55.0,"lng":-123.14727,"lat":49.20862},
{"timestamp":"2012-12-12T03:34:52.619Z","value":59.0,"lng":-123.14765,"lat":49.20868}]
example
curl --user {id}:{password} --request PUT --data-binary @data.txt 'http://wotkit.sensetecnic.com/api/sensors/test-sensor/data'
where data.txt contains JSON data similar to the above JSON array.
Deleting Data¶
Currently you can only delete data by timestamp, where timestamp is in numeric or ISO form. Note that if more than one sensor data point has the same timestamp, they all will be deleted.
To delete data:
URL | http://wotkit.sensetecnic.com/api/sensors/{sensorname}/data/{timestamp} |
Privacy | Private |
Format | not applicable |
Method | DELETE |
Returns | HTTP status code; No Response 204 if successful |
Raw Data Retrieval¶
To retrieve raw data use the following:
URL | http://wotkit.sensetecnic.com/api/sensors/{sensor-name}/data?{query-params} |
Privacy | Public or Private |
Format | json |
Method | GET |
Returns | On success, OK 200 with a list of timestamped data records. |
The query parameters supported are the following:
Name | Value Description |
---|---|
start | the absolute start time of the range of data selected in milliseconds. (Defaults to current time.) May only be used in combination with another parameter. |
end | the absolute end time of the range of data in milliseconds |
after | the relative time after the start time, e.g. after=300000 would be 5 minutes after the start time (Start time MUST also be provided.) |
afterE | the number of elements after the start element or time. (Start time MUST also be provided.) |
before | the relative time before the start time. E.g. data from the last hour would be before=3600000 (If not provided, start time default to current time.) |
beforeE | the number of elements before the start time. E.g. to get the last 1000, use beforeE=1000 (If not provided, start time default to current time.) |
reverse | true: order the data from newest to oldest; false (default):order from oldest to newest |
Note
These queries looks for timestamps > “start” and timestamps <= “end”
Formatted Data Retrieval¶
To retrieve data in a format suitable for Google Visualizations, we support an additional resource for retrieving data called the dataTable.
URL | http://wotkit.sensetecnic.com/api/sensors/{sensor-name}/dataTable?{query-params} |
Privacy | Public or Private |
Format | json |
Method | GET |
Returns | On success, OK 200 with a list of timestamped data records. |
In addition to the above query parameters, the following parameters are also supported:
tqx | A set of colon-delimited key/value pairs for standard parameters, defined here. |
tq | A SQL clause to select and process data fields to return, explained here. |
Note
When using tq sql queries, they must be url encoded. When using tqx name/value pairs, the reqId parameter is necessary.
For instance, the following would take the “test-sensor”, select all data where value was greater than 20, and display the output as an html table.
example
curl --user {id}:{password} http://wotkit.sensetecnic.com/api/sensors/test-sensor/ dataTable?tq=select%20*%20where%20value%3E20&reqId=1&out=html
Aggregated Data Retrieval¶
Aggregated data retrieval allows one to receive data from multiple sensors, queried using the same parameters as when searching for sensors or sensor data. The query must be specified using one of the following 5 patterns.
Pattern 1 - With Start/End
start | The most recent starting time of the query. This value is optional and defaults to the current time. |
end | A timestamp before the start time. |
limit | Specifies the limit to return. This value is optional, with a default value of 1000. |
offset | Specifies the offset to return. This value is optional, with a default value of 0. |
Pattern 2 - With Start/After
start | A starting timestamp. |
after | A relative timestamp after start. |
limit | Specifies the limit to return. This value is optional, with a default value of 1000 |
offset | Specifies the offset to return. This value is optional, with a default value of 0 |
Pattern 3 - With Start/Before
start | A starting timestamp. |
before | A relative timestamp before start. |
limit | Specifies the limit to return. This value is optional, with a default value of 1000 |
offset | Specifies the offset to return. This value is optional, with a default value of 0 |
Pattern 4 - With Start/BeforeE
start | A starting timestamp. |
beforeE | The number of elements to return before start |
offset | Specifies the offset to return. This value is optional, with a default value of 0 |
Pattern 5 - With Start/AfterE
start | A starting timestamp. |
afterE | The number of elements to return after start |
offset | Specifies the offset to return. This value is optional, with a default value of 0 |
The following parameters may be added to any of the above patterns: * scope * tags * private (deprecated, use visibility instead) * visibility * text * active * orderBy * sensor: which groups data by sensor_id * time (default): which orders data by timestamp, regardless of the sensor it comes from.
To receive data from more that one sensor, use the following:
URL | http://wotkit.sensetecnic.com/api/data?{query-param}={query-value}&{param}={value}... |
Privacy | Public or Private |
Format | json |
Method | GET |
Returns | On success, OK 200 with a list of timestamped data records. |
example
curl --user {id}:{password} "http://wotkit.sensetecnic.com/api/data?subscribed=all&beforeE=20&orderBy=sensor"
Sensor Control Channel: Actuators¶
An actuator is a sensor that uses a control channel to actuate things. Rather than POSTing data to the WoTKit, an actuator script or gateway polls the control URL for messages to affect the actuator, to do things like move a servo motor, turn a light on or off, or display a message on a screen.
To demonstrate actuators, the control visualization that comes with the WoTKit sends three type of events to the sensor control channel:
button | ‘on’ or ‘off’ to control a light, or switch. |
message | text message for use by the actuator, for example to be shown on a message board or display. |
slider | a numeric value to affect the position of something, such as a server motor. |
Any name/value pair can be sent to an actuator in a message, these are just the names sent by the visualization.
Sending Actuator Messages¶
To send a control message to a sensor (actuator), POST name value pairs corresponding to the data fields to the /sensors/{sensorname}/message URL.
URL | http://wotkit.sensetecnic.com/api/sensors/{sensorname}/message |
Privacy | Public or Private |
Format | json |
Method | POST |
Returns | On success, OK 200 (no content). |
Receiving Actuator Messages¶
In order to receive messages from an actuator, you must own that actuator.
Subscribing to an Actuator Controller¶
First, subscribe to the controller by POSTing to /api/control/sub/{sensor-name}. In return, we receive a json object containing a subscription id.
URL | http://wotkit.sensetecnic.com/api/control/sub/{sensor-name} |
Privacy | Private |
Format | json |
Method | POST |
Returns | On success, OK 200 with JSON containing subscription id. |
Example subscription id returned:
{
"subscription":1234
}
Query an Actuator¶
Using the subscription id, then poll the following resource: /api/control/sub/{subscription-id}?wait=10. The wait specifies the time to wait in seconds for a control message. If unspecified, a default wait time of 10 seconds is used. The maximum wait time is 20 seconds. The server will respond on timeout, or when a control messages is received.
URL | http://wotkit.sensetecnic.com/api/control/sub/{subscription-id}?wait={wait-time} |
Privacy | Private |
Format | json |
Method | GET |
Returns | On success, OK 200 with JSON containing control messages. |
To illustrate, the following code snippet uses HTTP client libraries to subscribe and get actuator messages from the server, and then print the data. Normally, the script would change the state of an actuator like a servo or a switch based on the message received.
# sample actuator code
import urllib
import urllib2
import base64
import httplib
try:
import json
except ImportError:
import simplejson as json
#note trailing slash to ensure .testactuator is not dropped as a file extension
actuator="mike.testactuator/"
# authentication setup
conn = httplib.HTTPConnection("wotkit.sensetecnic.com")
base64string = base64.encodestring('%s:%s' % ('{id}', '{password}'))[:-1]
authheader = "Basic %s" % base64string
headers = {'Authorization': authheader}
#subscribe to the controller and get the subscriber ID
conn.request("POST", "/api/control/sub/" + actuator, headers=headers)
response = conn.getresponse()
data = response.read()
json_object = json.loads(data)
subId = json_object['subscription']
#loop to long poll for actuator messages
while 1:
print "request started for subId: " + str(subId)
conn.request("GET", "/api/control/sub/" + str(subId) + "?wait=10", headers=headers)
response = conn.getresponse()
data = response.read()
json_object = json.loads(data)
# change state of actuator based on json message received
print json_object
Tags¶
You can get a list of tags, either the most used by public sensors or by a sensor query.
Querying Sensor Tags¶
A list of matching tags. The query parameters are as follows:
Name | Value Description |
---|---|
scope | all-all tags used by sensors that the current user has access to;
| subscribed-tags for sensors the user has subscribed to;
| contributed-tags for sensors the user has contributed to the system.
|
private |
|
visibility | filter by the visibility of the sensors, either of public, organization or private |
text | text to search in the sensors’s name, long name and description |
active | when true, only returns tags for sensors that have been updated in the last 15 minutes. |
offset | offset into list of tags for paging |
limit | limit to show for paging. The maximum number of tags to display is 1000. |
location |
|
To query for tags, add query parameters after the sensors URL as follows:
URL | http://wotkit.sensetecnic.com/api/tags?{query} |
Privacy | Public or Private |
Format | json |
Method | GET |
Returns | On error, an appropriate HTTP status code; On success, OK 200 and a list of tag count objects matching the query. |
example
curl --user {id}:{password} "http://wotkit.sensetecnic.com/api/sensors/tags?text=bicycles"
Output:
[
{
'name': 'bicycle',
'count': 3,
'lastUsed': 1370887340845
},{
'name': 'bike',
'count': 3,
'lastUsed': 1350687440754
},{
'name': 'montreal',
'count': 1,
'lastUsed': 1365857340341
}
]
The lastUsed field represents the creation date of the newest sensor that uses this tag.
Users¶
Admins can list, create and delete users from the system.
List/Query Users¶
A list of matching user may be queried by the system. The optional query parameters are as follows:
Name | Value Description |
---|---|
text | text to search for in the username, first name and/or last name |
reverse | true to get the oldest users first; false (default) to get newest first |
offset | offset into list of users for paging |
limit | limit to show for paging. The maximum number of users to display is 1000. |
To query for users, add query parameters after the sensors URL as follows:
URL | http://wotkit.sensetecnic.com/api/users?{query} |
Privacy | Admin |
Format | json |
Method | GET |
Returns | On error, an appropriate HTTP status code; On success, OK 200 and a list of users matching the query. |
Viewing a Single User¶
To view a single user, query by username or id as follows:
URL | http://wotkit.sensetecnic.com/api/users/{username} |
Privacy | Admin |
Format | json |
Method | GET |
Returns | Appropriate HTTP status code; OK 200 - if successful |
example
curl --user {id}:{password} "http://wotkit.sensetecnic.com/api/users/1"
Output:
{
'id': 1,
'username': 'sensetecnic',
'email': 'info@sensetecnic.com',
'firstname': 'Sense',
'lastname': 'Tecnic',
'enabled': True,
'accountNonExpired': True,
'accountNonLocked': True,
'credentialsNonExpired': True
}
Creating/Registering a User¶
To register a user, you POST a user resource to the url /users.
- The user resources is a JSON object.
- The “username”, “firstname”, “lastname”, “email”, and “password” fields are required when creating a user.
- The “timeZone” field is optional and defaults to UTC.
- The username must be at least 4 characters long.
To create a user:
URL | http://wotkit.sensetecnic.com/api/users |
Privacy | Admin |
Format | json |
Method | POST |
Returns | HTTP status code; Created 201 if successful; Bad Request 400 if user is invalid; Conflict 409 if user with the same username already exists |
Updating a User¶
- You may only update the following fields: “firstname”, “lastname”, “email”, “timeZone” and “password”.
- Only fields that will be present in the JSON object will be updated. The rest will remain unchanged.
To update a user:
URL | http://wotkit.sensetecnic.com/api/users/{username} |
Privacy | Admin |
Format | json |
Method | PUT |
Returns | HTTP status code; No Content 204 if successful |
Deleting a User¶
Deleting a user is done by deleting the user resource.
To delete a user:
URL | http://wotkit.sensetecnic.com/api/users/{username} |
Privacy | Admin |
Format | not applicable |
Method | DELETE |
Returns | HTTP status code; No Response 204 if successful |
Organizations¶
All users can see all organizations, and admins can manipulate them.
List/Query Organizations¶
A list of matching organizations may be queried by the system. The optional query parameters are as follows:
Name | Value Description |
---|---|
text | text to search for in the name, long name and/or description |
offset | offset into list of organizations for paging |
limit | limit to show for paging. The maximum number of organizations to display is 1000. |
To query for organizations, add query parameters after the sensors URL as follows:
URL | http://wotkit.sensetecnic.com/api/orgs?{query} |
Privacy | Public |
Format | json |
Method | GET |
Returns | On error, an appropriate HTTP status code; On success, OK 200 and a list of organizations matching the query from newest to oldest. |
Viewing a Single Organization¶
To view a single organization, query by name:
URL | http://wotkit.sensetecnic.com/api/orgs/{org-name} |
Privacy | Public |
Format | json |
Method | GET |
Returns | Appropriate HTTP status code; OK 200 - if successful |
example
curl "http://wotkit.sensetecnic.com/api/orgs/electric-inc"
Output:
{
"id": 4764,
"name": "electric-inc",
"longName": "Electric, Inc.",
"description": "Electric, Inc. was established in 1970.",
"imageUrl": "http://www.example.com/electric-inc-logo.png"
}
Creating/Registering an Organization¶
To register a new organization, you POST an organization resource to the url /org.
- The organization resources is a JSON object.
- The “name” and “longName” fields are required and must both be at least 4 characters long.
- The “imageUrl” and “description” fields are optional.
To create an organization:
URL | http://wotkit.sensetecnic.com/api/orgs |
Privacy | Admin |
Format | json |
Method | POST |
Returns | HTTP status code; Created 201 if successful; Bad Request 400 if organization is invalid; Conflict 409 if an organization with the same name already exists |
Updating an Organization¶
- You may update any fields except “id” and “name”.
- Only fields that are present in the JSON object will be updated.
To update an organization:
URL | http://wotkit.sensetecnic.com/api/orgs/{org-name} |
Privacy | Admin |
Format | json |
Method | PUT |
Returns | HTTP status code; No Content 204 if successful |
Deleting an Organization¶
Deleting an organization is done by deleting the organization resource.
To delete a user:
URL | http://wotkit.sensetecnic.com/api/orgs/{org-name} |
Privacy | Admin |
Format | not applicable |
Method | DELETE |
Returns | HTTP status code; No Content 204 if successful |
Organization Membership¶
List all members of an Organization¶
To query for organization members:
URL | http://wotkit.sensetecnic.com/api/orgs/{org-name}/members |
Privacy | Admin |
Format | not applicable |
Method | GET |
Returns | On error, an appropriate HTTP status code; On success, OK 200 and a list of organization members. |
Add new members to an Organization¶
To add new members to an organization, post a JSON array of usernames:
URL | http://wotkit.sensetecnic.com/api/orgs/{org-name}/members |
Privacy | Admin |
Format | json |
Method | POST |
Returns | On error, an appropriate HTTP status code; On success, OK 204. |
Usernames that are already members, or usernames that do not exist, will be ignored.
For instance, to add the users “abe”, “beth”, “cecilia” and “dylan” to the organization “electric-inc”:
example
curl --user {id}:{password} --request POST --header "Content-Type: application/json" --data-binary @users-list.txt 'http://wotkit.sensetecnic.com/api/orgs/electric-inc/members'
The file users-list.txt would contain the following.
["abe", "beth", "cecilia", "dylan"]
Remove members from an Organization¶
To remove members from an organization, DELETE a JSON array of usernames:
URL | http://wotkit.sensetecnic.com/api/orgs/{org-name}/members |
Privacy | Admin |
Format | json |
Method | DELETE |
Returns | On error, an appropriate HTTP status code; On success, OK 204. |
Usernames that are not members, or usernames that do not exist, will be ignored.
Sensor Groups¶
Sensor Groups are used to logically organize related sensors. A Sensors can be a member of many groups.
Currently, all Sensor Groups have public visibility, but only the owner (creator) can add/remove sensors from the group.
Sensor Groups can be manipulated using a REST API in the following section
Sensor Group Format¶
All request body and response bodies use JSON. The following fields are present:
Field Name | Type | Required | Notes |
---|---|---|---|
id | Integer | true | The id contains a unique number which is used to identify the group |
name | String[4,50] | true | The name is a system-unique string identifier for the group. Names must be lowercase containing alphanumeric, underscores or hyphens [a-z0-9_-]. The first character must be an alphabetic character |
longName | String[,255] | optional | A readable name used for visual interfaces. |
owner | String[4,50] | true | The name of the group’s owner. This field is set by the system and cannot be modified. |
description | String[,255] | optional | A simple description of the group |
imageUrl | String[,255] | optional | A string url to an image which can be used to represent this group |
sensors | Array[Sensor] | optional | Contains a JSON list of sensors. This field is only useful for viewing sensors. To append/remove sensors from Sensor Groups, refer to Adding a Sensor to Sensor Group. |
An example of a Sensor Group JSON would be follows:
{
id: 49,
name: "water-sensor",
longName: "A water sensor",
owner: "robertl",
description: "This is a short description",
imageUrl: "http://someurl.com/water-sensor.jpg"
sensors: []
}
List Groups¶
Provides a list of groups on the system as an array using the JSON format specified in Sensor Group Format
URL | http://wotkit.sensetecnic.com/api/groups/ |
Method | GET |
Returns | OK 200, along with list |
example
curl --user {id}:{password} --request GET 'http://wotkit.sensetecnic.com/api/groups'
Viewing a Single Sensor Group¶
Similar to listing a group, but retrieving only a single sensor. Replace {group-name} with group.id or group.name. The API accepts both formats
URL | http://wotkit.sensetecnic.com/api/groups/{group-name} |
Method | GET |
Returns | OK 200 |
example
curl --user {id}:{password} --request GET 'http://wotkit.sensetecnic.com/api/groups'
Creating a Sensor Group¶
To create a sensor group, append the Sensor Group contents following Sensor Group Format.
On creation, the id and owner fields are ignored because they are system generated.
URL | http://wotkit.sensetecnic.com/api/groups |
Method | POST |
Returns | If a sensor with the same name exists, ERROR 409. Otherwise, OK 204. |
Modifying Sensor Group Fields¶
Modifying is similar to creation, the content is placed in the response body
Again, the id and owner fields in the JSON object are ignored if they are modified. The Sensor Group is specified by substituting {group-name} in the URL with either group.id or group.name. The API accepts both formats.
URL | http://wotkit.sensetecnic.com/api/groups/{group-name} |
Method | PUT |
Returns | If user has no permissions to edit group, returns UNAUTHORIZED 401, otherwise OK 204 |
Deleting a Sensor Group¶
Deleting a Sensor Group is fairly trivial, assuming you are the owner of the group. A request body is unnecessary.
URL | http://wotkit.sensetecnic.com/api/groups/{group-name} |
Method | DELETE |
Returns | If user has no permissions to edit group, returns UNAUTHORIZED 401, otherwise OK 204 |
Adding a Sensor to Sensor Group¶
This is done by invoking the URL by replacing the specified parameters where {group-name} can be group.id or group.name. {sensor-id} should be sensor.id.
URL | http://wotkit.sensetecnic.com/api/groups/{group-name}/sensors/{sensor-id} |
Method | POST |
The response will contain one of the following response codes.
Return Code | Description |
---|---|
OK 204 | No Content is given. |
400 | Sensor is already a member of sensor group |
401 | User is unauthorized to edit group. |
Removing a Sensor from Sensor Group¶
The format is the same as Adding a Sensor to Sensor Group except replacing method with DELETE
URL | http://wotkit.sensetecnic.com/api/groups/{group-name}/sensors/{sensor-id} |
Method | DELETE |
The response will contain one of the following codes.
Return Code | Description |
---|---|
OK 204 | No Content is given. If a sensor does not exist in a group, this is also returned. |
401 | User is unauthorized to edit group |
News¶
To get “news” (a list of interesting recent things that happened in the system):
URL | http://wotkit.sensetecnic.com/api/news |
Privacy | Public |
Format | not applicable |
Method | GET |
Returns | Appropriate HTTP status code; OK 200 - if successful |
example
curl "http://wotkit.sensetecnic.com/api/news"
Output:
[{
'timestamp': 1370910428123,
'title': u'The sensor "Light Sensor" has updated data.',
'url': u'/sensors/5/monitor'
},{
'timestamp': 1370910428855,
'title': u'The sensor "api-data-test-1" has updated data.',
'url': u'/sensors/40/monitor'
}]
Statistics¶
To get some statistics (eg. number of public sensors, active sensors, new sensors, etc...):
URL | http://wotkit.sensetecnic.com/api/stats |
Privacy | Public |
Format | not applicable |
Method | GET |
Returns | Appropriate HTTP status code; OK 200 - if successful |
example
curl "http://wotkit.sensetecnic.com/api/stats"
Output:
{
'total': 65437,
'active': 43474,
'new': {
'day': 53,
'week': 457,
'month': 9123,
'year': 40532
}
}
V2 API Reference¶
This documentation is a work in process. It’s not production ready yet – but feel free to look around.
Sensor Data¶
In the WoTKit, sensor data consists of a timestamp followed by one or more named fields. There are a number of reserved fields supported by the WoTKit:
Reserved field name | Description |
---|---|
timestamp | the time that the sensor data was collected. This is a long integer representing the number of milliseconds from Jan 1, 1970 UTC. Optional; if not supplied, a server-supplied timestamp will be used. |
id | a unique identifier for the data reading. This is to distinguish one reading from another when they share the same timestamp. Read only; This field is read only and should not be sent by the client when sending new data. |
sensor_id | the globally unique sensor id that produced the data. Read only; This is a read only field generated by the wotkit that should not be sent by a client when sending new data. |
sensor_name | the globally unique sensor name, in the form {username}.{sensorname}. Read only; This is a read only field and should not be sent by the client when sending new data. |
When a new sensor is created, a number of default fields are created by the wotkit for a sensor as follows. Note that these can be changed by editing the sensor fields.
Default field name | Description |
---|---|
lat | the current latitude location of the sensor in degrees (number). Needed for map visualizations. |
lng | the current longitude location of the sensor in degrees (number). Needed for map visualizations. |
value | the primary value of the sensor data collected (number). Needed for most visualizations. |
message | a text message, for example a twitter message (text). Needed for text/newsfeed visualizations. |
In addition to these default fields, additional fields can be added by updating the sensor fields in the WoTKit UI or Sensor Fields in the API.
Note
Python’s time.time() function generates the system time in seconds, not milliseconds. To convert this to an integer in milliseconds use int(time.time()*1000).
In Javascript: var d = new Date(); d.getTime();
In Java: System.currentTime().
Sending New Data¶
To send new data to a sensor, POST name value pairs corresponding to the data fields to /sensors/{sensorname}/data. There is no need to supply the sensor id, or sensor name fields since the sensor is specified in the URL.
If a timestamp is not provided in the request body, it will be set to the current time by the the server.
To send new data:
URL | http://wotkit.sensetecnic.com/api/v2/sensors/{sensorname}/data |
Privacy | Private |
Format | not applicable |
Method | POST |
Returns | HTTP status code; No Response 201 (Created) if successful |
Example
curl --user {id}:{password} --request POST -d value=5 -d lng=6 -d lat=7 'http://wotkit.sensetecnic.com/api/sensors/test-sensor/data'
Updating a Range of Historical Data¶
To insert or update a range of historical data, you PUT data (rather than POST) data into the system. Note that data PUT into the WoTKit will not be processed in real time, since it occurred in the past.
- The request body must be a list of JSON objects containing a timestamp value.
- Any existing data within this timestamp range will be deleted and replaced by the data supplied.
To update data:
URL | http://wotkit.sensetecnic.com/api/v2/sensors/{sensorname}/data |
Privacy | Private |
Format | JSON |
Method | PUT |
Returns | HTTP status code; No Response 204 if successful |
Example of valid data:
[{"timestamp":"2012-12-12T03:34:28.626Z","value":67.0,"lng":-123.1404,"lat":49.20532},
{"timestamp":"2012-12-12T03:34:28.665Z","value":63.0,"lng":-123.14054,"lat":49.20554},
{"timestamp":"2012-12-12T03:34:31.621Z","value":52.0,"lng":-123.14063,"lat":49.20559},
{"timestamp":"2012-12-12T03:34:35.121Z","value":68.0,"lng":-123.14057,"lat":49.20716},
{"timestamp":"2012-12-12T03:34:38.625Z","value":51.0,"lng":-123.14049,"lat":49.20757},
{"timestamp":"2012-12-12T03:34:42.126Z","value":55.0,"lng":-123.14044,"lat":49.20854},
{"timestamp":"2012-12-12T03:34:45.621Z","value":56.0,"lng":-123.14215,"lat":49.20855},
{"timestamp":"2012-12-12T03:34:49.122Z","value":55.0,"lng":-123.14727,"lat":49.20862},
{"timestamp":"2012-12-12T03:34:52.619Z","value":59.0,"lng":-123.14765,"lat":49.20868}]
example
curl --user {id}:{password} --request PUT --data-binary @data.txt 'http://wotkit.sensetecnic.com/api/sensors/test-sensor/data'
where data.txt contains JSON data similar to the above JSON array.
Retrieving a Single Data Item¶
If you know the data element’s id, you can query for a single data element using the following query.
URL | http://wotkit.sensetecnic.com/api/v2/sensors/{sensor-name}/data/{data_id} |
Privacy | Public or Private, depending on sensor privacy |
Format | json |
Method | GET |
Returns | On success, OK 200 with a list of timestamped data records. |
Retrieving Data Using Query¶
To retrive sensor data over a time range you can use the following endpoint. An interactive guide on how to use this endpoint is available at: Querying Sensor Data.
URL | http://wotkit.sensetecnic.com/api/v2/sensors/{sensor-name}/data |
Privacy | Public or Private, depending on sensor privacy |
Format | json |
Method | GET |
Returns | On success, OK 200 with a list of timestamped data records. |
The query parameters supported are the following. They can only be used together if they appear in the same Group below.
Parameter | Group | Type | Description |
---|---|---|---|
recent_t | 1 | integer | Gets the elements up to recent_t milliseconds ago |
recent_n | 2 | integer | Gets the n recent elements |
start | 3 | timestamp | The absolute starting point (in milliseconds since Jan 1, 1970). |
start_id | 3 | id | The starting id of sensor_data at timestamp start. Used for paging and to distinguish data elements that share the same timestamp. |
end | 3 | timestamp | The absolute ending timestamp (in milliseconds since Jan 1, 1970) |
end_id | 3 | timestamp | The end id of sensor_data with timestamp end. Used for paging. |
limit | [2,3] | integer | specifies how many datapoints to see on each response |
Delete Data by Id¶
Same as Retrieving a Single Data Item instead using HTTP Delete.
URL | http://wotkit.sensetecnic.com/api/v2/sensors/{sensorname}/data/{data_id} |
Privacy | Private |
Format | not applicable |
Method | DELETE |
Returns | HTTP status code; No Response 204 if successful |
Delete Data using Data Query¶
Can delete using query parameters in Retrieving Data Using Query with the restriction on only using group 3 parameters.
URL | http://wotkit.sensetecnic.com/api/v2/sensors/{sensorname}/data |
Privacy | Private |
Format | not applicable |
Method | DELETE |
Returns | HTTP status code; No Response 204 if successful |
Alerts¶
An alert is set up by an user for notification purpose. Multiple conditions can be attached to an alert. Each condition is associated with a sensor field. An alert fires and sends a message to the owner’s inbox and email (if email functionality is enabled) when all of its attached conditions are satisfied. Currently, each user is limited to have a maximum of 20 alerts.
An alert has the following attributes:
Name | Value Description |
---|---|
id | the numeric id of the alert. It is automatically assigned when alert is created. |
name ** | the name of the alert. |
longName | longer display name of the alert. |
description ** | a description of the alert. |
owner | the user that creates the alert. The value of this field is automatically assigned as a user creates an alert. |
disabled |
|
inProgress |
|
template ** | The message template that is sent to the inbox when alert is fired. |
sendEmail ** | A boolean to enable/disable send email functionaity. |
conditions | the list of alert conditions |
** Required when creating a new alert.
An alert condition is composed of a sensor field, an operator for evaluation, and a value. It has the following attributes:
Name | Value Description |
---|---|
sensorId | the ID of the sensor associated with the condition |
field | the field name to be compared of the chosen sensor |
operator |
|
value | value that the operator compares with |
Listing Alerts of an User¶
To view a list of “alerts” created by an user:
URL | http://wotkit.sensetecnic.com/api/v2/alerts |
Privacy | Private |
Format | JSON |
Method | GET |
Returns | Appropriate HTTP status code; OK 200 - if successful |
example
curl --user {id}:{password} "http://wotkit.sensetecnic.com/api/v2/alerts"
Sample Output:
[{
"id": 6,
"owner": "crysng",
"name": "temperature-alert",
"longName": "Temperature Alert",
"description": "This alert notifies user when Hydrogen Sulfide content and Wind speed is too high at Burnaby Burmount. ",
"disabled": false,
"inProgress": false,
"template": "Hydrogen Sulfide and wind speed is high!",
"sendEmail": true,
"email": "rottencherries@hotmail.com",
"conditions": [
{
"sensorId": 241,
"field": "h2s",
"operator": "GT",
"value": 10
},
{
"sensorId": 241,
"field": "wspd",
"operator": "GE",
"value": 50
}
]
},
{
"id": 5,
"owner": "crysng",
"name": "test",
"longName": "Moisture Sensor Alert",
"description": "This alert fires when moisture level is too low. ",
"disabled": false,
"inProgress": false,
"template": "Moisture level is too low, water the plant now!",
"sendEmail": true,
"email": "someone@email.com",
"conditions": [
{
"sensorId": 504,
"field": "value",
"operator": "LT",
"value": 3
}
]
}]
Viewing an Alert¶
To view an alert, query the alert by its id as followed:
URL | http://wotkit.sensetecnic.com/api/v2/alerts/{alert id} |
Privacy | Private |
Format | json |
Method | GET |
Returns | Appropriate HTTP status code; OK 200 - if successful |
example
curl --user {id}:{password} "http://wotkit.sensetecnic.com/api/v2/alerts/5"
Output:
{
"id": 5,
"owner": "crysng",
"name": "test",
"longName": "Moisture Sensor Alert",
"description": "This alert fires when moisture level is too low. ",
"disabled": false,
"inProgress": false,
"template": "Moisture level is too low, water the plant now!",
"sendEmail": true,
"email": "someone@email.com",
"conditions": [
{
"sensorId": 504,
"field": "value",
"operator": "LT",
"value": 3
}
]
}
Creating Alerts¶
To create an alert, you POST an alert resource to the url /v2/alerts.
- The alert resource is a JSON object.
- The “name”, “description”, “template”, and “sendEmail” fields are required when creating an alert.
- The alert name must be at least 4 characters long, contain only lowercase letters, numbers, dashes and underscores, and can start with a lowercase letter or an underscore only.
To create an alert:
URL | http://wotkit.sensetecnic.com/api/v2/alerts |
Privacy | Private |
Format | json |
Method | POST |
Returns | HTTP status code; Created 201 if successful; Bad Request 400 if sensor is invalid; Conflict 409 if alert with the same name already exists |
example1
curl --user {id}:{password} --request POST --header "Content-Type: application/json" --data-binary @test-alert.txt 'http://wotkit.sensetecnic.com/api/v2/alerts'
For this example, the file test-alert.txt contains the following. This is the minimal information needed to create an alert.
{
"name":"test alert",
"description":"A test alert.",
"template":"Template for test alert",
"sendEmail":false
}
example2
Now, let’s create an alert with additional information and conditions. The file test-alert.txt contains the following.
{
"name": "test alert 2",
"longName": "Test Alert 2",
"description": "This is test 2. ",
"disabled": false,
"template": "The alert test 2 has fired!! ",
"sendEmail": true,
"email": "someone@email.com",
"conditions": [
{
"sensorId": 504,
"field": "value",
"operator": "LT",
"value": 3
},
{
"sensorId": 24,
"field": "data",
"operator": "NOTNULL"
}
]
}
Updating Alerts¶
Updating an alert is the same as creating a new alert other than PUT is used and the alert id is included in the URL.
Note that all top level fields supplied will be updated.
- You may update any fields except “id”, and “owner”.
- Only fields that are present in the JSON object will be updated.
To update an alert owned by the current user:
URL | http://wotkit.sensetecnic.com/api/v2/alerts/{alert id} |
Privacy | Private |
Format | json |
Method | PUT |
Returns | HTTP status code; No Content 204 if successful |
For instance, to update an alert:
example
curl --user {id}:{password} --request PUT --header "Content-Type: application/json" --data-binary @update-alert.txt 'http://wotkit.sensetecnic.com/api/v2/alerts/{alert id}'
The file update-alert.txt would contain the following:
{
"longName": "New Alert Name",
"description":"Updated Description"
}
Deleting Alerts¶
Deleting an alert is done by deleting the alert resource.
To delete an alert owned by the current user:
URL | http://wotkit.sensetecnic.com/api/v2/alertss/{alert id} |
Privacy | Private |
Format | not applicable |
Method | DELETE |
Returns | HTTP status code; No Response 204 if successful |
example
curl --user {id}:{password} --request DELETE 'http://wotkit.sensetecnic.com/api/v2/alerts/{alert id}'
Inbox¶
The Inbox is the storage place for inbox messages that are sent by an alert firing event.
An inbox message has the following attributes:
Name | Value Description |
---|---|
id | the numeric id of the message. It is automatically generated. |
timestamp | the time that the message is sent to inbox. |
title | title of the inbox message |
message | the message content |
sendEmail | the boolean variable of whether email functionality is enabled |
read | the flag of whether the message is read |
sent | the flag of whether an email is sent |
Listing Inbox Messages of an User¶
To view a list of “inbox messages” of an user:
URL | http://wotkit.sensetecnic.com/api/v2/inbox |
Privacy | Private |
Format | JSON |
Method | GET |
Returns | Appropriate HTTP status code; OK 200 - if successful |
example
curl --user {id}:{password} "http://wotkit.sensetecnic.com/api/v2/inbox"
Sample Inbox Messages Output:
[
{
"id": 5,
"timestamp": "2014-04-17T00:51:41.701Z",
"title": "Moisture Sensor Alert",
"message": "Moisture level is too low, water the plant now!",
"sendEmail": true,
"email": "someone@email.com",
"read": false,
"sent": false
}
]