State Registration and Retrieval

You can register the thing's latest state to Thing Interaction Framework. Once registered, the state will be stored in Thing Interaction Framework and can be browsed by other devices (e.g., mobile applications and web applications).

See State Registration and Retrieval for the overview.

The following operations are available:

Registering State

The following is an example of uploading a thing state.

curl -v -X PUT \
  -H "Authorization: Bearer {ACCESS_TOKEN}" \
  -H "X-Kii-AppID: {APP_ID}" \
  -H "X-Kii-AppKey: {APP_KEY}" \
  -H "Content-Type: application/json" \
  "https://api.kii.com/thing-if/apps/{APP_ID}/targets/thing:{THING_ID}/states" \
  -d '{
    "power":true,
    "presetTemperature":25,
    "fanspeed":5,
    "currentTemperature":28,
    "currentHumidity":65
  }'

Please set the access token of the thing or thing owner. Also please replace the placeholder {THING_ID} with the thingID of the target thing. As shown in the sample, the state is to be represented in a JSON format.

The maximum size of a state is 10 KB. This size is when the key-values of the state are represented in JSON format.

You can set a nested JSON data as a state. In this case, the following restrictions apply:

  • You can only use the top-level fields of the state when setting the filed conditions for aggregating the state history.
  • You can only use the top-level fields of the state when setting the state conditions of the trigger execution conditions.

If the state registration succeeds, you will get a 201 or 204 response (201 if this is the first time uploading the state, otherwise 204).

Setting Timestamp on Thing

All registered states will be timestamped. Thing Interaction Framework basically set the timestamp automatically. If you wish, you can also set the timestamp explicitly on the thing side.

The following is an example of setting the timestamp on the thing side. As shown in the example, please set the timestamp (UNIX time in msec in UTC) in the "_created" field when registering the state.

curl -v -X PUT \
  -H "Authorization: Bearer {ACCESS_TOKEN}" \
  -H "X-Kii-AppID: {APP_ID}" \
  -H "X-Kii-AppKey: {APP_KEY}" \
  -H "Content-Type: application/json" \
  "https://api.kii.com/thing-if/apps/{APP_ID}/targets/thing:{THING_ID}/states" \
  -d '{
    "power":true,
    "presetTemperature":25,
    "fanspeed":5,
    "currentTemperature":28,
    "currentHumidity":65,
    "_created": 1469158821211
  }'

Please note that there is a limit in the difference between the timestamp set on the thing and the time when the state is actually registered. See Managing State History for more details.

Browsing Latest State

The following is an example of browsing the latest thing state.

curl -v -X GET \
  -H "Authorization: Bearer {ACCESS_TOKEN}" \
  -H "X-Kii-AppID: {APP_ID}" \
  -H "X-Kii-AppKey: {APP_KEY}" \
  -H "Content-Type: application/json" \
  "https://api.kii.com/thing-if/apps/{APP_ID}/targets/thing:{THING_ID}/states"

Please set the access token of the thing or thing owner. Also please replace the placeholder {THING_ID} with the thingID of the target thing.

You will get the latest state in a 200 response as follows:

HTTP/1.1 200 OK
Content-Type: application/json
{
  "power":true,
  "presetTemperature":25,
  "fanspeed":5,
  "currentTemperature":28,
  "currentHumidity":65
}

The "latest" state means the one that has been registered most recently. When you are setting the timestamp on the thing side, please be careful that the "latest" state is not determined by the timestamp given on the state.

Querying and Retrieving State History

To retrieve the state history, you will specify search conditions for filtering the history, just like when you retrieve objects by querying.

You can specify the following search conditions:

When getting the search result, you can select if you want to get the grouped result or not. If you select to get the grouped result, you can further select if you want to get the past states themselves or their aggregated result. Please read Getting Search Result for more details.

You can find some example of querying and retrieving state history in Examples section.

To query and retrieve thing state history, you need to set the grouping interval for storing the history when you onboard the thing.

Time Range

Please specify the time range of the states you want to retrieve in the withinTimeRange condition. This condition is mandatory.

{
  "type": "withinTimeRange",
  "lowerLimit": 1467000000000,
  "upperLimit": 1467003000000
}

Please set the lower and upper bound of the target states in the lowerLimit and upperLimit, respectively. Both timestamps are to be set in UNIX time (msec) in UTC.

The actual state history retrieval is performed in group units. If you set Time Range A illustrated in the next figure, for example, all states in Group #1 will be retrieved as the history. If you set Time Range B, all states in Group #1 and #2 will be retrieved.

If the specified lower or upper bound is exactly equal to the boundary of a group, this group is included in the target for the state history retrieval.

You cannot set the time range that goes over 60 groups. If you try to set such a time range, you will get an error.

For the overview of the state history timestamping and grouping, see this page.

Field conditions

You can set the field conditions for filtering the state history. The field condition is optional.

You can use the same search conditions as that of the object querying. You cannot, however, use the GeoBoxClause and GeoDistance conditions.

Note that if the state is a nested JSON data, you can use only the top-level fields for setting the field condition.

When setting the field condition, please concatenate it with the time range condition using the andClause, as shown in the following example:

{
  "type": "and",
  "clauses": [
    {
      "type": "range",
      "field": "currentTemperature",
      "lowerLimit": 32
    },
    {
      "type": "withinTimeRange",
      "lowerLimit": 1467000000000,
      "upperLimit": 1467003000000
    }
  ]
}

Getting Search Result

The state history is returned as the search result.

You can select how you want to get the search result as follows:

Get the grouped result? Aggregation? How you will get the state history
No No The state history that matches with the given search condition(s). The history is sorted in the ascending order based on the state timestamp by default.
Yes No The state history that matches with the given search condition(s). The history is organized by group and will be always sorted in the ascending order based on the state timestamp.
Yes Yes The aggregated result of the state history that matches with the given condition. The state history is aggregated per group.

Getting State History without Grouping

When getting the state history without grouping, you can sort the history by specifying the orderBy and descending conditions, just like when you do the object querying. If the orderBy condition is not specified, the history is sorted in the ascending order based on the timestamp.

You can also use the pagination feature by leveraging the bestEffortLimit and paginationKey.

Getting State History with Grouping

To get the grouped result, please set the following parameter in the search condition.

{"grouped": true}

When getting the state history with grouping, you cannot sort the history. The state history is always sorted in the ascending order based on the timestamp. You cannot use the pagination feature either.

Getting Aggregated Result of State History

To get the aggregated result of the state history per group, please specify the aggregation rule in addition to the "grouped": true mentioned above.

The aggregation rule is to be set in the aggregations, like in the following example:

{
  "aggregations": [
    {
      "field": "temperature",
      "fieldType": "DECIMAL",
      "type": "MAX",
      "putAggregationInto": "max"
    }
  ]
}

You can set only one aggregation rule per query (multiple aggregation rules in one query will be supported in the future).

To define the aggregation rule, please specify the following information:

  • field: The target field of the state for the aggregation.
  • fieldType: The data type of the target field. You can select one of the followings: STRING, INTEGER, DECIMAL, or BOOLEAN.
  • type: The aggregation function to use. You can select one of the followings:

    • COUNT: The number of states that have a non-null value in the target field.
    • SUM: The sum of the target value.
    • MAX: The maximum value of the target field.
    • MIN: The minimum value of the target field.
    • MEAN: The average value of the target field.
  • putAggregationInto: The label you want to put on the aggregation result. In the above aggregation rule definition, for example, the maximum value of the "temperature" field will be returned as follows:

    {
      "aggregations" : [ {
        "value": 35,
        "name": "max"
      } ]
    }
    

Examples

We will now present some examples of querying and retrieving state history.

Time Range Only

The first example only specifies the time range of the target states. This one corresponds to Example 1 in the feature guide.

curl -v -X POST \
  -H "Authorization: Bearer {ACCESS_TOKEN}" \
  -H "X-Kii-AppID: {APP_ID}" \
  -H "X-Kii-AppKey: {APP_KEY}" \
  -H "Content-Type: application/json" \
  "https://api.kii.com/thing-if/apps/{APP_ID}/targets/thing:{THING_ID}/states/query" \
  -d '{
    "query": {
      "clause": {
        "type": "withinTimeRange",
        "lowerLimit": 1467000000000,
        "upperLimit": 1467003000000
      },
      "grouped": true
    }
  }'

The above request contains "grouped": true, so the state history is returned by group as follows:

HTTP/1.1 200 OK
Content-Type: application/json
{
  "queryDescription" : "WHERE withinTimeRange(1467000000000, 1467003000000)",
  "groupedResults" : [ {
    "range" : {
      "from" : 1467000000000,
      "to" : 1467000900000
    },
    "objects" : [ {
      "currentTemperature" : 32,
      "fanspeed" : 5,
      "_created" : 1467000010000,
      "currentHumidity" : 72,
      "presetTemperature" : 25,
      "power" : true
    }, {
      "currentTemperature" : 31,
      "fanspeed" : 5,
      "_created" : 1467000374001,
      "currentHumidity" : 70,
      "presetTemperature" : 25,
      "power" : true
    }, {
      "currentTemperature" : 29,
      "fanspeed" : 5,
      "_created" : 1467000384970,
      "currentHumidity" : 72,
      "presetTemperature" : 25,
      "power" : true
    }, {
      "currentTemperature" : 32,
      "fanspeed" : 5,
      "_created" : 1467000460422,
      "currentHumidity" : 72,
      "presetTemperature" : 25,
      "power" : true
    } ]
  }, {
    "range" : {
      "from" : 1467000900000,
      "to" : 1467001800000
    },
    "objects" : [ {
      "currentTemperature" : 31,
      "fanspeed" : 5,
      "_created" : 1467001000000,
      "currentHumidity" : 72,
      "presetTemperature" : 25,
      "power" : true
    }, {
      "currentTemperature" : 31,
      "fanspeed" : 5,
      "_created" : 1467001221211,
      "currentHumidity" : 72,
      "presetTemperature" : 25,
      "power" : true
    } ]
  }, {
    "range" : {
      "from" : 1467001800000,
      "to" : 1467002700000
    },
    "objects" : [ ]
  }, {
    "range" : {
      "from" : 1467002700000,
      "to" : 1467003600000
    },
    "objects" : [ {
      "currentTemperature" : 31,
      "fanspeed" : 5,
      "_created" : 1467003321211,
      "currentHumidity" : 72,
      "presetTemperature" : 25,
      "power" : true
    } ]
  } ]
}

If the request does not contain "grouped": true, the search result will not be grouped; the state history is returned in the ascending order by the timestamp as follows. This one corresponds to Example 2 in the feature guide.

HTTP/1.1 200 OK
Content-Type: application/json
{
  "queryDescription" : "WHERE withinTimeRange(1467000000000, 1467003000000)",
  "results" : [ {
    "currentTemperature" : 32,
    "fanspeed" : 5,
    "_created" : 1467000010000,
    "currentHumidity" : 72,
    "presetTemperature" : 25,
    "power" : true
  }, {
    "currentTemperature" : 31,
    "fanspeed" : 5,
    "_created" : 1467000374001,
    "currentHumidity" : 70,
    "presetTemperature" : 25,
    "power" : true
  }, {
    "currentTemperature" : 29,
    "fanspeed" : 5,
    "_created" : 1467000384970,
    "currentHumidity" : 72,
    "presetTemperature" : 25,
    "power" : true
  }, {
    "currentTemperature" : 32,
    "fanspeed" : 5,
    "_created" : 1467000460422,
    "currentHumidity" : 72,
    "presetTemperature" : 25,
    "power" : true
  }, {
    "currentTemperature" : 31,
    "fanspeed" : 5,
    "_created" : 1467001000000,
    "currentHumidity" : 72,
    "presetTemperature" : 25,
    "power" : true
  }, {
    "currentTemperature" : 31,
    "fanspeed" : 5,
    "_created" : 1467001221211,
    "currentHumidity" : 72,
    "presetTemperature" : 25,
    "power" : true
  }, {
    "currentTemperature" : 31,
    "fanspeed" : 5,
    "_created" : 1467003321211,
    "currentHumidity" : 72,
    "presetTemperature" : 25,
    "power" : true
  } ]
}

Time Range + Field Condition (without Aggregation)

The next example specifies a field condition in addition to the time range condition. This one corresponds to Example 3 in the feature guide.

curl -v -X POST \
  -H "Authorization: Bearer {ACCESS_TOKEN}" \
  -H "X-Kii-AppID: {APP_ID}" \
  -H "X-Kii-AppKey: {APP_KEY}" \
  -H "Content-Type: application/json" \
  "https://api.kii.com/thing-if/apps/{APP_ID}/targets/thing:{THING_ID}/states/query" \
  -d '{
    "query": {
      "clause": {
        "type": "and",
        "clauses": [
          {
            "type": "range",
            "field": "currentTemperature",
            "lowerLimit": 32
          },
          {
            "type": "withinTimeRange",
            "lowerLimit": 1467000000000,
            "upperLimit": 1467003000000
          }
        ]
      },
      "grouped": true
    }
  }'

The above request adds the field condition "the 'currentTemperature' field is greater than or equal to 32" in addition to the time range set in the previous example. The search result is grouped, so the state history will be returned as follows:

HTTP/1.1 200 OK
Content-Type: application/json
{
  "queryDescription" : "WHERE ( ( 32 <= currentTemperature ) AND withinTimeRange(1467000000000, 1467003000000) )",
  "groupedResults" : [ {
    "range" : {
      "from" : 1467000000000,
      "to" : 1467000900000
    },
    "objects" : [ {
      "currentTemperature" : 32,
      "fanspeed" : 5,
      "_created" : 1467000010000,
      "currentHumidity" : 72,
      "presetTemperature" : 25,
      "power" : true
    }, {
      "currentTemperature" : 32,
      "fanspeed" : 5,
      "_created" : 1467000460422,
      "currentHumidity" : 72,
      "presetTemperature" : 25,
      "power" : true
    } ]
  }, {
    "range" : {
      "from" : 1467000900000,
      "to" : 1467001800000
    },
    "objects" : [ ]
  }, {
    "range" : {
      "from" : 1467001800000,
      "to" : 1467002700000
    },
    "objects" : [ ]
  }, {
    "range" : {
      "from" : 1467002700000,
      "to" : 1467003600000
    },
    "objects" : [ ]
  } ]
}

Time Range + Field Condition (with Aggregation)

The last example presents how to aggregate the state history for each group.

In the next example, we are sending the same request as the previous example. This time, we also specify COUNT as the aggregation function. This request will allow us to get the number of states that have the "currentTemperature" greater than or equal to 32. This one corresponds to Example 4 in the feature guide.

curl -v -X POST \
  -H "Authorization: Bearer {ACCESS_TOKEN}" \
  -H "X-Kii-AppID: {APP_ID}" \
  -H "X-Kii-AppKey: {APP_KEY}" \
  -H "Content-Type: application/json" \
  "https://api.kii.com/thing-if/apps/{APP_ID}/targets/thing:{THING_ID}/states/query" \
  -d '{
    "query": {
      "clause": {
        "type": "and",
        "clauses": [
          {
            "type": "range",
            "field": "currentTemperature",
            "lowerLimit": 32
          },
          {
            "type": "withinTimeRange",
            "lowerLimit": 1467000000000,
            "upperLimit": 1467003000000
          }
        ]
      },
      "grouped": true,
      "aggregations": [
        {
          "field": "currentTemperature",
          "fieldType": "INTEGER",
          "type": "COUNT",
          "putAggregationInto": "state_count"
        }
      ]
    }
  }'

The result will be as follows. The number of the states that match with the specified condition is returned per group. Please notice that the state history itself is not returned.

HTTP/1.1 200 OK
Content-Type: application/json
{
  "queryDescription" : "SELECT count(currentTemperature) as state_count WHERE ( ( 32 <= currentTemperature ) AND withinTimeRange(1467000000000, 1467003000000) )",
  "groupedResults" : [ {
    "range" : {
      "from" : 1467000000000,
      "to" : 1467000900000
    },
    "aggregations" : [ {
      "value" : 2,
      "name" : "state_count"
    } ]
  }, {
    "range" : {
      "from" : 1467000900000,
      "to" : 1467001800000
    },
    "aggregations" : [ { } ]
  }, {
    "range" : {
      "from" : 1467001800000,
      "to" : 1467002700000
    },
    "aggregations" : [ { } ]
  }, {
    "range" : {
      "from" : 1467002700000,
      "to" : 1467003600000
    },
    "aggregations" : [ { } ]
  } ]
}

Here is another example. This one specifies MIN function without any field condition. The request will aggregate the state history so as to give us the smallest "currentHumidity" value in each group.

curl -v -X POST \
  -H "Authorization: Bearer {ACCESS_TOKEN}" \
  -H "X-Kii-AppID: {APP_ID}" \
  -H "X-Kii-AppKey: {APP_KEY}" \
  -H "Content-Type: application/json" \
  "https://api.kii.com/thing-if/apps/{APP_ID}/targets/thing:{THING_ID}/states/query" \
  -d '{
    "query": {
      "clause": {
        "type": "withinTimeRange",
        "lowerLimit": 1467000000000,
        "upperLimit": 1467003000000
      },
      "grouped": true,
      "aggregations": [
        {
          "field": "currentHumidity",
          "fieldType": "INTEGER",
          "type": "MIN",
          "putAggregationInto": "minimum_humidity"
        }
      ]
    }
  }'

The result is returned as follows. This time, the state with the smallest "currentHumidity" value will be uniquely identified in each group, so the corresponding state is also returned in the "object" field. This one corresponds to Example 5 in the feature guide.

HTTP/1.1 200 OK
Content-Type: application/json
{
  "queryDescription" : "SELECT min(currentHumidity) as minimum_humidity WHERE withinTimeRange(1467000000000, 1467003000000)",
  "groupedResults" : [ {
    "range" : {
      "from" : 1467000000000,
      "to" : 1467000900000
    },
    "aggregations" : [ {
      "value" : 70,
      "name" : "minimum_humidity",
      "object" : {
        "currentTemperature" : 31,
        "fanspeed" : 5,
        "_created" : 1467000374001,
        "currentHumidity" : 70,
        "presetTemperature" : 25,
        "power" : true
      }
    } ]
  }, {
    "range" : {
      "from" : 1467000900000,
      "to" : 1467001800000
    },
    "aggregations" : [ {
      "value" : 72,
      "name" : "minimum_humidity",
      "object" : {
        "currentTemperature" : 31,
        "fanspeed" : 5,
        "_created" : 1467001000000,
        "currentHumidity" : 72,
        "presetTemperature" : 25,
        "power" : true
      }
    } ]
  }, {
    "range" : {
      "from" : 1467001800000,
      "to" : 1467002700000
    },
    "aggregations" : [ { } ]
  }, {
    "range" : {
      "from" : 1467002700000,
      "to" : 1467003600000
    },
    "aggregations" : [ {
      "value" : 72,
      "name" : "minimum_humidity",
      "object" : {
        "currentTemperature" : 31,
        "fanspeed" : 5,
        "_created" : 1467003321211,
        "currentHumidity" : 72,
        "presetTemperature" : 25,
        "power" : true
      }
    } ]
  } ]
}