Thngs, Properties, and Actions

After all the preparation, this is the key section for setting up the weather station and getting data from it into the EVRYTHNG Platform. The Thngs will represent the devices, and property updates will allow it to post sensor readings for use in the mobile app by users. Lastly, actions will introduce a mechanism for recording discrete events, such as extreme weather.


Creating some Thngs

Each weather station deployed in the field will be given its own Thng resource, which is the principle data type within the EVRYTHNG Platform. Thngs represent single instances of a class of object, and so are created with a link to the product representing their object type. For example, your first Thng will reference the “Atmospheric Evaluator” product you just created, and will be performed by making a POST /thngs request.

Like the product creation request, this should also be scoped to the correct project using the project query parameter. However, this time the request should be made with the Application User API Key, since the user associated with the key will be the owner and maintainer of the devices themselves.

Substitutions: :projectId, productId

curl -H "Content-Type: application/json" \
  -H "Authorization: $APPLICATION_USER_API_KEY" \
  -X POST 'https://api.evrythng.com/thngs?project=:projectId' \
  -d '{
    "name": "South Fields Station",
    "description": "The weather station located in the South Fields area.",
    "product": ":productId"
  }'
{
  "id": "U3fxbt2EBDPRQpRwRDNWFeWb",
  "createdAt": 1498488711596,
  "updatedAt": 1498488711596,
  "name": "South Fields Station",
  "description": "The weather station located in the South Fields area.",
  "product": "UGfRNStEVDPat5waamA9gtXr"
}

Optionally, repeat this request a couple more times to model additional weather stations in different locations, such as ‘North Fields’, and ‘City Center’. Once these Thngs have been created, the Application User API Key can be used to read them all back, and make sure they look OK by making a GET /thngs request.

Substitutions: :projectId

curl -H "Authorization: $APPLICATION_USER_API_KEY" \
  -X GET 'https://api.evrythng.com/thngs?project=:projectId'
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "createdAt": 1498470030091,
    "customFields": {},
    "description": "The weather station located in the City Center area.",
    "id": "UGCaNgFPVDsatpwRwXeMRgpq",
    "identifiers": {},
    "name": "City Center Station",
    "product": "UGfRNStEVDPat5waamA9gtXr",
    "properties": {},
    "updatedAt": 1498478906739
  },
  {
    "createdAt": 1498469954642,
    "customFields": {},
    "description": "The weather station located in the North Fields area.",
    "id": "Umfw7XByBgPaQKaawD5wAkYs",
    "identifiers": {},
    "name": "North Fields Station",
    "product": "UGfRNStEVDPat5waamA9gtXr",
    "properties": {},
    "updatedAt": 1498478912606
  },
  {
    "createdAt": 1498469827515,
    "customFields": {},
    "description": "The weather station located in the South Fields area.",
    "id": "U3CarWMdBXPRQ5awwheMEmYg",
    "identifiers": {},
    "name": "South Fields Station",
    "product": "UGfRNStEVDPat5waamA9gtXr",
    "properties": {},
    "updatedAt": 1498478918106
  }
]

The mobile application can use the user’s Application User API Key on their behalf to update the metadata on each of these devices, as well as add or remove additional devices, at any time. These API interactions should be made as part of the mobile app’s user experience.


## Updating Properties

Now that all the basic Platform resources have been created and users can begin using them, we can move on to some more interesting interactions. For example, modelling how each weather station out in the field reports its findings back to the Platform through the API.

In addition to the simple metadata items (such as name, description, photos, etc.), Thngs can also store identifiers (such as serial or part numbers), custom fields (constant items of metadata), and properties (the historical and latest state of the device). We will focus on the last of these three types of data to reflect the latest weather measurements the station has observed.

There is another type of API key available to developers when the only privileges required are that the device can update its own state in the Platform - the Device API Key. Each Thng can be given its own Device API Key by an account Operator, or Application User. Make a POST /auth/evrythng/thngs request, including the ID of one of your “Atmospheric Evaluator” Thngs, and use the Application User API Key acquired earlier.

Substitutions: :thngId

curl -H "Content-Type: application/json" \
  -H "Authorization: $APPLICATION_USER_API_KEY" \
  -X POST 'https://api.evrythng.com/auth/evrythng/thngs' \
  -d '{
    "thngId": ":thngId"
  }'
HTTP/1.1 201 Created
Content-Type: application/json

{
  "thngId": "UGCaNgFPVDsatpwRwXeMRgpq",
  "thngApiKey": "GoX5PjASW1yi8CiQOD4Vnnztbxl71hs7Jbd24bu..."
}

The thngApiKey returned is the unique Device API Key that can be used to allow this Thng to update its own data.

The device itself should update its Thng properties as and when is appropriate so that the data can be accessed, modelled, and integrated into other systems. For example, the weather station may update its measurements in the Platform every five minutes using property updates.

The simple Python script below shows an example implementation of what could be running on the device, but using random values instead of real sensor values. Note that the Device API Key is the key used to allow the weather station to update its own cloud state.

import random
import requests
import time
 
DEVICE_API_KEY = "$DEVICE_API_KEY"  # Thng's Device API Key
THNG_ID = ":thngId"                 # ID of the Thng itself
 
def update():
  properties = [
    { "key": "wind_speed_mph", "value": random.randint(0, 90)   }, 
    { "key": "humidity_gm3",   "value": random.randint(0, 28)   },
    { "key": "temp_celsius",   "value": random.randint(-20, 40) },
    { "key": "rainfall_mm",    "value": random.randint(0, 200)  }
  ]
  headers = {
    "Content-Type": "application/json",
    "Authorization": DEVICE_API_KEY
  }
  url = "https://api.evrythng.com/thngs/{}/properties".format(THNG_ID)
  r = requests.post(url, json=properties, headers=headers)
  print(r.text)
 
def main():
  while True:
    update()
    time.sleep(5 * 60)
 
if __name__ == "__main__": 
  main()

## Creating Actions

Actions are the Platform resource model for simple notifications, and serve as a lasting record of discrete events that can occur in a variety of types. They can also contain custom data fields to be used to drive business logic. In our weather station scenario, a station may emit an action if it detects conditions that could lead to extreme weather, such as flooding or storms.

Each action created must have a type. This is a similar relationship of Thngs and products, but the difference is that it is mandatory. There are also four built-in action types, which you can view by making a GET /actions request using the Operator API Key. For this scenario, create a new action type to represent extreme weather events.

📘

Note

It is a requirement that custom action types start with an underscore.

Substitutions: :projectId

curl -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X POST 'https://api.evrythng.com/actions?project=:projectId' \
  -d '{
    "name": "_ExtremeWeatherAlert"
  }'
HTTP/1.1 201 Created
Content-Type: application/json

{
  "id": "UmCxAa4eBgPRtKaRaXNnVfDa",
  "createdAt": 1498493092255,
  "updatedAt": 1498493092255,
  "name": "_ExtremeWeatherAlert"
}

With this new action type in place, it can be used by the device as part of its on-board program to report to the cloud when an extreme weather event occurs. To actually create an action of this type, perform a POST /actions/_ExtremeWeatherAlert request as the device with the Application User API Key as shown below:

Substitutions: :productId

curl -H "Content-Type: application/json" \
  -H "Authorization: $APPLICATION_USER_API_KEY" \
  -X POST 'https://api.evrythng.com/actions/_ExtremeWeatherAlert' \
  -d '{
    "type": "_ExtremeWeatherAlert",
    "product": ":productId"
  }'
HTTP/1.1 201 Created
Content-Type: application/json

{
  "id": "UGDtAWQpBXPRt5wawXK5Hgrr",
  "createdAt": 1500460539488,
  "timestamp": 1500460539488,
  "type": "_ExtremeWeatherAlert",
  "user": "U3Carr4FBDPw9pwRaDpb4s6s",
  "location": {
    "latitude": 51.45,
    "longitude": 0.2167,
    "position": {
      "type": "Point",
      "coordinates": [
        0.2167,
        51.45
      ]
    }
  },
  "locationSource": "geoIp",
  "context": {
    "city": "Dartford",
    "region": "England",
    "countryCode": "GB",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
    "timeZone": "Europe/London"
  },
  "createdByProject": "UmCa6NYaVDswQpwRaD4sGtMs",
  "createdByApp": "UmCa68aRBgPw95wwwDnPpmEb",
  "product": ":productId"
}

Another Python example is shown below to mock the device firmware, demonstrating the creation of an instance of the new action type. Also included is some extra event-specific data in the action’s customFields property describing the type of extreme weather the device is reporting.

import requests

OPERATOR_API_KEY = "$OPERATOR_API_KEY"
THNG_ID = ":thngId"
PROJECT_ID = ":projectId"
ACTION_TYPE = "_ExtremeWeatherAlert"

def alert():
  action = {
    "type": ACTION_TYPE,
    "thng": THNG_ID,
    "customFields": {
      "weatherType": "storm",
      "severity": "amber"
    }
  }
  headers = {
    "Content-Type": "application/json",
    "Authorization": OPERATOR_API_KEY
  }
  url = "https://api.evrythng.com/actions/{}?project={}".format(ACTION_TYPE, PROJECT_ID)
  r = requests.post(url, json=action, headers=headers)
  print(r.text)

if __name__ == "__main__": 
  alert()

More Action Types

In the next section, we will look at how to consume the data collected with these actions. To make the results more interesting and realistic, create a few new action types with the following names: _HeatwaveObserved, _FloodingObserved, _LightningStrikeObserved to respect these types of weather events respectively.

Finally, create a few actions of each of these types, over the course of a few days if possible, as this will create a better result when viewed through Dashboard widgets, which will be covered in the next section.