Getting Started

Getting access

In order to get programmatic access to the data from the devices an API key is needed.

Alternatively user credentials to our admin interface can be used.

API keys and user credentials can be obtained from NNNCo by getting in touch with one of our sales rep or emailing n2n-dl-support@nnnco.com.au.

In the following examples we assume that the following test API key: 8a0892e3aedbe2f2ade4bd727d4725e0c639d021 - which is no longer valid - is linked to an enterprise called nnn.client1.

More information on authentication is available in the API structure page

N2N-DL in a nutshell

In N2N-DL devices are enrolled and owned by enterprises (aka clients) and send raw data and network metadata to our platform (LoRaWAN only).

Our platform parses the data (optionally) to generate readings with a normalised data model and (optionally) stores the raw data and the readings (if any).

Clients can create data subscriptions to receive raw data, readings and network metadata in their application.

Enrol a new LoRaWAN device

Let’s start by enrolling a OTAA device:


curl -X POST \
  https://www.nnnco.io/v3/api/core/devices \
  -u api:8a0892e3aedbe2f2ade4bd727d4725e0c639d021 \
  -H 'Content-Type: application/json' \
  -d '{
	"deviceId": "477b41f200300034",
	"enterpriseId": "nnn.client1",
	"name": "test-device-otaa",
	"enrolment": {
		"class": "A",
		"mode": "otaa",
		"otaa": {
			"appEui": "0000000000000000",
			"appKey": "2b7e151628aed2a6abf7158809cf4f3c"
		}
	}
}'

which should return something like

{
    "deviceId": "477B41F200300034",
    "enterpriseId": "nnn.client1",
    "name": "test-device-otaa",
    "groupIdList": [
        "nnn.client1.master"
    ]
}

ABP devices can be enrolled in a similar way:

curl -X POST \
  https://www.nnnco.io/v3/api/core/devices \
  -u api:8a0892e3aedbe2f2ade4bd727d4725e0c639d021 \
  -H 'Content-Type: application/json' \
  -d '{
	"deviceId": "A81758FFFE0311EF",
	"enterpriseId": "nnn.canegrowers",
	"name": "test-abp-device",
	"enrolment": {
		"class": "A",
		"mode": "abp",
		"abp": {
			"nwAddress": "FE0311EF",
			"nwKey": "00000000000000000000000000000000",
			"appSKey": "00000000000000000000000000000000"
		}
	}
}'

If we specify no AppSKey the payload from ABP devices remains encrypted and needs decryption at an application level.

Otherwise the decryption is carried out by our network server (as mandated by LoRaWAN specifications)

Payload decoding

N2N-DL supports multiple device payloads for automatic parsing into readings.

If a device has no device type associated OR a device type for which N2N-DL has no parser, no parsing is attempted.

The full list of devices currently supported is available here TODO.

Get a list of devices that belong to your account

Let’s not get a list of devices associated to our account

curl -X GET \
  'https://www.nnnco.io/v3/api/core/devices' \
  -u api:8a0892e3aedbe2f2ade4bd727d4725e0c639d021

Here we get 2 devices: 0018B20000002594 for which no device type is specified and 393435376A377906 which is a parametric pcr2 device.

As a consequence device 393435376A377906 also shows the latest values from the parsed readings from the device under channelList.

Instead for device 0018B20000002594 no channelList is present.

[
    {
        "enterpriseId": "nnn",
        "lastOnline": 1580451305156,
        "location": {
            "latitude": 33.863,
            "longitude": 151.208833,
            "type": "gps"
        },
        "deviceId": "0018B20000002594",
        "network": {
            "type": "loraWan",
            "source": "actility",
            "loraWan": {
                "lrrTs": 1580451305156,
                "loraPort": 1,
                "uplinkCnt": 174,
                "adrBit": null,
                "mType": 4,
                "downlinkCnt": 1318,
                "lrcId": "00000231",
                "rssi": -62,
                "snr": 13.5,
                "spFact": 10,
                "subBand": "G0",
                "lrrCnt": 2,
                "lrrId": "004A1C4A",
                "late": false,
                "lrrLat": -33.862549,
                "lrrLong": 151.209793,
                "lrrList": [
                    {
                        "lrrId": "004A1C4A",
                        "chain": 0,
                        "rssi": -62,
                        "snr": 13.5,
                        "esp": -62.189785
                    },
                    {
                        "lrrId": "004A1C22",
                        "chain": 0,
                        "rssi": -118,
                        "snr": -0.75,
                        "esp": -121.401474
                    }
                ]
            }
        },
        "groupIdList": [
            "nnn.master"
        ]
    },
    {
        "lastOnline": 1581487940278,
        "deviceType": "parametricPcr2",
        "enterpriseId": "nnn",
        "network": {
            "type": "loraWan",
            "source": "actility",
            "loraWan": {
                "lrrTs": 1581487940278,
                "loraPort": 14,
                "uplinkCnt": 12133,
                "adrBit": 1,
                "mType": 4,
                "downlinkCnt": 12518,
                "lrcId": "00000231",
                "rssi": -84,
                "snr": 6.75,
                "spFact": 7,
                "subBand": "G0",
                "lrrCnt": 1,
                "lrrId": "004A1C4A",
                "late": false,
                "lrrLat": -33.862549,
                "lrrLong": 151.209793,
                "lrrList": [
                    {
                        "lrrId": "004A1C4A",
                        "chain": 0,
                        "rssi": -84,
                        "snr": 6.75,
                        "esp": -84.832695
                    }
                ]
            }
        },
        "deviceId": "393435376A377906",
        "channelList": [
            {
                "channelId": 0,
                "type": "digital",
                "value": 0,
                "label": "count-left-to-right"
            },
            {
                "channelId": 1,
                "type": "digital",
                "value": 1,
                "label": "count-right-to-left"
            },
            {
                "channelId": 2,
                "type": "temperature",
                "value": 31,
                "unit": "°C"
            }
        ],
        "groupIdList": [
            "nnn.master"
        ]
    }
]

Retrieve some data from a device

Retrieving data from a device is as easy as calling:

curl -X GET \
  'https://www.nnnco.io/v3/api/core/devices/393435376A377906/messages' \
  -u api:8a0892e3aedbe2f2ade4bd727d4725e0c639d021
[
    {
        "hexPayload": "0a000016000001013a",
        "type": "uplink",
        "deviceId": "393435376A377906",
        "port": 14,
        "ts": 1581488300304,
        "network": {
            "type": "loraWan",
            "source": "actility",
            "loraWan": {
                "lrrTs": 1581488300304,
                "loraPort": 14,
                "uplinkCnt": 12135,
                "adrBit": 1,
                "mType": 4,
                "downlinkCnt": 12520,
                "lrcId": "00000231",
                "rssi": -89,
                "snr": 5.75,
                "spFact": 7,
                "subBand": "G0",
                "lrrCnt": 1,
                "lrrId": "004A1C4A",
                "late": false,
                "lrrLat": -33.862549,
                "lrrLong": 151.209793,
                "lrrList": [
                    {
                        "lrrId": "004A1C4A",
                        "chain": 0,
                        "rssi": -89,
                        "snr": 5.75,
                        "esp": -90.02459
                    }
                ]
            }
        },
        "readingList": [
            {
                "channelId": 0,
                "type": "digital",
                "value": 0,
                "label": "count-left-to-right"
            },
            {
                "channelId": 1,
                "type": "digital",
                "value": 0,
                "label": "count-right-to-left"
            },
            {
                "channelId": 2,
                "type": "temperature",
                "value": 31.4,
                "unit": "°C"
            }
        ]
    }
]

The payload includes parsed data, raw data and network metadata.

Accessing only parsed readings

If we are interested in parsed readings only (and no raw data or network metadata) we can call instead:

curl -X GET \
  'https://www.nnnco.io/v3/api/core/devices/393435376A377906/readings' \
  -u api:8a0892e3aedbe2f2ade4bd727d4725e0c639d021
[
    {
        "ts": 1581396315287,
        "values": [
            {
                "channelId": 0,
                "type": "digital",
                "value": 2,
                "label": "count-left-to-right"
            },
            {
                "channelId": 1,
                "type": "digital",
                "value": 0,
                "label": "count-right-to-left"
            },
            {
                "channelId": 2,
                "type": "temperature",
                "value": 30.4,
                "unit": "°C"
            }
        ]
    },
    {
        "ts": 1581396495290,
        "values": [
            {
                "channelId": 0,
                "type": "digital",
                "value": 0,
                "label": "count-left-to-right"
            },
            {
                "channelId": 1,
                "type": "digital",
                "value": 0,
                "label": "count-right-to-left"
            },
            {
                "channelId": 2,
                "type": "temperature",
                "value": 30.7,
                "unit": "°C"
            }
        ]
    }
]

Create a data subscription

Simple HTTP/s

curl -X POST \
  https://www.nnnco.io/v3/api/core/subscriptions \
  -H 'Content-Type: application/json' \
  -u api:8a0892e3aedbe2f2ade4bd727d4725e0c639d021 \
  -d '{
	"enterpriseId": "nnn",
	"type": "http",
	"endpoint": {
		"url": "https://hookb.in/yDd0ewyzp9tO7OPzdQVe"
	},
	"pushInterval": 10
}'
{
    "enterpriseId": "nnn",
    "type": "http",
    "endpoint": {
        "url": "https://hookb.in/yDd0ewyzp9tO7OPzdQVe"
    },
    "pushInterval": 10,
    "format": "json",
    "subscriptionId": 42,
    "deliveries": 0,
    "pending": 0
}

Debugging a data subscription

We can inspect the items that are currently pending on the delivery queue by calling

curl -X GET \
  https://www.nnnco.io/v3/api/core/subscriptions/42/pending \
  -u api:8a0892e3aedbe2f2ade4bd727d4725e0c639d021 \
  -H 'Content-Type: application/json'
[
    {
        "subId": 42,
        "deviceId": "70B3D5A9F0019902",
        "deviceType": "aradGladiator",
        "hexPayload": "9aa86416d6080000000807",
        "readingList": [
            {
                "channelId": 0,
                "type": "digital",
                "value": 226.2,
                "label": "meter-reading",
                "unit": "m3"
            }
        ],
        "port": 1,
        "ts": 1581556484889,
        "type": "downlink",
        "network": {
            "type": "loraWan",
            "source": "actility",
            "loraWan": {
                "lrrTs": 1581556484889,
                "loraPort": 1,
                "uplinkCnt": 415,
                "adrBit": 1,
                "mType": 4,
                "downlinkCnt": 415,
                "lrcId": "00000231",
                "rssi": -90,
                "snr": 9,
                "spFact": 7,
                "subBand": "G0",
                "lrrCnt": 1,
                "lrrId": "C00019BC",
                "late": false,
                "lrrLat": -33.742016,
                "lrrLong": 150.62085,
                "lrrList": [
                    {
                        "lrrId": "C00019BC",
                        "chain": 0,
                        "rssi": -90,
                        "snr": 9,
                        "esp": -90.514969
                    }
                ]
            }
        }
    }
]

as well as the latest deliveries:

curl -X GET \
  'https://www.nnnco.io/v3/api/core/subscriptions/42/deliveries' \
  -u api:8a0892e3aedbe2f2ade4bd727d4725e0c639d021 \
  -H 'Content-Type: application/json'
[
    {
        "enterpriseId": "nnn",
        "subscriptionId": 42,
        "response": {
            "data": "{\"success\":false,\"message\":\"404 Not Found\"}",
            "headers": {
                "server": "nginx",
                "date": "Thu, 13 Feb 2020 01:31:06 GMT",
                "content-type": "application/json; charset=utf-8",
                "content-length": "43",
                "connection": "close",
                "cache-control": "no-cache, no-store, must-revalidate",
                "pragma": "no-cache",
                "expires": "Fri, 31 Dec 1998 12:00:00 GMT",
                "x-ratelimit-limit": "300",
                "x-ratelimit-reset": "5",
                "x-ratelimit-remaining": "234",
                "etag": "W/\"2b-TsMtXpt9QO/RWSxmyL7EEhm+8t4\""
            },
            "status": 404,
            "statusText": "Not Found"
        },
        "startedTs": 1581557465344,
        "deliveryId": "42-1581557465",
        "payload": {
            "byteSize": 22623,
            "numItems": 40,
            "format": "json"
        },
        "result": "ERROR",
        "errorMessage": "Http call failed 404 / {\"success\":false,\"message\":\"404 Not Found\"}",
        "completedTs": 1581557466530
    }
]