Let's start a conversation

A feature we had to sacrifice on the “getting done in time” altar was the downstream messaging (ie sending messages to the devices, not just receiving). We had a clear idea on how we should do it, but our main focus was to get the essentials up and running so we had to postpone it a bit.

As with any LPWAN technology the first thing you’ll try is to get bytes through the system, then something slightly more useful like monitoring data but after a while you realise that you’ll need downstream messaging to really make it a useful technology.

Naturally we had to implement it so here it is. The current implementation is experimental. We won’t remove it, we might change it slightly and it might not be perfect – in other words it is a work in progress.

Testing it

Let’s start with the simplest possible - through a serial emulator. Wire up your board with a USB to serial cable and connect to the device. Verify that you are on the correct APN and that you’ve got an IP address. You won’t get an IP address unless the device is registered in the Telenor IoT console:

AT+CGDCONT?

+CGDCONT: 0,"IP","mda.ee",,0,0,,,,,0

OK
AT+CGPADDR

+CGPADDR: 0,"10.1.0.13"

OK

This looks fine, so let’s send a test message to verify that the upstream data works OK. First off we need a simple hex string. If you have Python available you can use this script to convert a string into a hex string (it assumes that the socket number is 0 but if you have more than one socket you have to change the socket number to the correct one):

import sys
import binascii
hex_str = binascii.hexlify(sys.argv[1].encode('utf-8'))
len = len(sys.argv[1])
print('AT+NSOST=0,"127.16.15.14",1234,%d,"%s"' % (len, hex_str.decode('utf-8')))

Create a socket with the last parameter to 1 in the NSOST command is important - this will create *URC*s (aka “Unsolicited Response Codes”) when you receive data from the backend. More on that later.

AT+NSOCR="DGRAM",17,8888,1

0

OK
AT+NSOST=0,"172.16.15.14",1234,21,"4C6F6F6B73206C696B65207468697320776F726B73"

0,21

OK

You should see the message in the console:

Upstream message

Let’s send something back to the device. If you haven’t done so create an API token with write permissions to the device you’re using in the console. Let’s make sure the token works by querying the device. Copy and paste the API token and the collection ID to the command line:

$ curl -HX-API-Token:{your API token} https://api.nbiot.telenor.io/collections/{collection id}/devices
{
  "deviceId": "{the device id}",
  "collectionId": "{the collection id}",
  "imei": "{imei of your device}",
  "imsi": "{imsi of your device}",
  "tags": {
    "name": "{The name you used for your device}"
  }
}

The returned list of devices should contain among other things the device id of your device. Use this ID to send a packet to port 8888 on the device using the to resource. The POST verb is used to send a JSON message looking like this

{
    "port": <port number for message>,
    "payload": "<base64 encoded message>"
}

If you have Python available you can use that to encode the base64 string:

import sys
import base64

print('%s = %s' % (sys.argv[1], base64.standard_b64encode(sys.argv[1])))

Putting it all together into one cURL command we get this:

curl -HX-API-Token:{API token} \
    -XPOST -d'{"port":8888,"payload":"QSB0ZXN0IG1lc3NhZ2U="}' \
    https://api.nbiot.telenor.io/collections/{collection id}/devices/{device id}/to

The API expects a JSON object with two fields – port which is the port you’ll be sending data to – the same port used in the NSOCR command above and payload` which is a base64-encoded payload.

If everything works you should see an URC in the serial terminal:

+NSONMI: 0,14

Use NSORF (aka “socket receive from”) to retrieve the data from the server:

AT+NSORF=0,14

0,"172.16.7.197",32977,14,"412074657374206D657373616765",0

OK

As with NSOST the payload is hex encoded.

Broadcasting to all devices in a collection

Broadcasting a message to all devices in a collection is done the same way as for a single device, just with a different reosurce. Similar to the downstream messages to a single device you have to specify a port and a payload.

This means that all of the devices in a collection have to listen to the same port if they should receive broadcast messages. POST to https://api.nbiot.telenor.io/collection/{id}/to to send the messages.

The response shows any errors, number of messages sent and number of failures:

{
    "errors": [{"deviceId": "<device id>", "message": "<error message>"}],
    "sent": <number of successful messages>,
    "failed": <number of failed messages>
}

A message will usually fail if the device isn’t online (or haven’t been online at all). Devices in power saving mode will receive the messages when they go online.

A note on power saving

If your module has power saving enabled it won’t listen continously for data but rather listen for a short while before disconnecting from the network. The net result is that the module won’t receive downstream messages instantly but only when it goes online. Usually this is triggered by a NSOST command. At first glance this looks like a firewall issue but in reality it isn’t. To make sure the power saving features of the module doesn’t interfere you can turn off power saving entirely by running AT+CPSMS=0. This will disable all power saving features.

Message buffering

The network will buffer a limited number of downstream (aka outgoing) messages to the device so if your device is in a power saving mode and isn’t connected to the network it will recieve the message when it reconnects with the network.

Note that the device must have an open socket to receive messages. If you close the socket it won’t receive downstream messages. If you power off the device any open sockets will be closed.

Since only one message can be read back via the NSORF command at a time you have to process them in series; you won’t receive the next message unless you’ve read the preceeding message.

Enjoy the conversation!