Client API

Thingstream uses a publish/subscribe model to allow devices to send and receive data from the server platform. The platform does not provide any kind of 'socket-oriented' view of communication. Data must be packaged into discrete messages, for example, a sensor reading. The complete API is defined in the C header file client_api.h.


Topics


Thingstream does not allow clients to send messages directly to one another. Instead, one client will create a message and publish it to a topic on the server. Topics can be defined by the callers themselves or by admin interfaces in the platform. The server will look to see whether there are any clients who are listening (subscribing) to messages on that topic, and will then deliver the message to all of those who are. So, notionally, if you want to send a message from device A to device B, you could:



Topics in Thingstream behave just like MQTT topics, because they are! The Thingstream platform is based on MQTT server-side and it is important to understand how MQTT topics can be structured and how they work to get the most from Thingstream.


Variable substitution


The Thingstream Client API supports variable substitution for topics which can be used for both publish and subscribe operations  in the following ways:


All Things have a unique device ID which you can find in the Thing Details page of the Thingstream management console.  Clients can refer to this id in the topic structure by using {device} e.g. "readings/{device}/temp" would resolve on the server as "readings/device:nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn/temp". 

In addition to the device ID, all SN Things have a network identity with the format "identity:nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn".  This identity is used in the "self" topic which all SN Things are implicitly subscribed to, but can also be used in your own topic structure by using {identity} e.g. "readings/{identity}/temp" would resolve on the server as "readings/identity:nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn/temp". 

It is also possible to refer to the value of a tag in the topic structure by using {tag:tagname}.  You would need to add a tag to the Thing via the Thing Details page of the Thingstream management console which holds both the tag title and value e.g. "topic=tagtopic".  If you were to use "readings/{tag:topic}/temp", this would resolve on the sever as "readings/topic/temp".


Sending data


Clients and other server-side components publish (send) messages to topics. This is done by calling the function Client_publish() and passing a number of arguments, in particular a pointer to the data to be sent (the payload) and the length of the data.


Receiving data


Data is received by the client by subscribing to one or more topics. Because this operation is asynchronous (that is, the caller does not have to wait for incoming data) the caller application must supply a callback function which will be called by the Thingstream client when a new message arrives. This callback is also passed details of the topic the message relates to, so that it can handle it appropriately. The callback function must be registered before subscribing to any topics.


To register a callback function, call:

void Client_set_subscribe_callback(Client *client, Subscribe_callback callback, void *cookie);


supplying a pointer to an appropriate callback function. For example:

void myhandler(void *cookie, Topic topic, QOS qos, uint8_t *payload, uint16_t payloadlen) {


    // we're only interested in messages on topic id 123

    if (topic.topicAlias == 123) {

        printf("I have a message, it's %d bytes long!\n", payloadlen);

    }


}


...


void initialise() {


    Client_set_subscribe_callback(client, &myhandler, NULL);


}


Aliases


Topic aliases are used to reduce the number of bytes that need to be sent over the air.  There are different types of alias:


Normal Alias

In this case we may wish to define a custom path to publish on e.g. "/example/simple/regtest"

The client would 'REGISTER' in order to have a topicId allocated and the client and server would then use the topicId (alias) as an identifier.


const char* topicName = "/example/simple/regtest";

Topic topic;

ClientResult  cr = Client_register(client, topicName, &topic);

topic will comprise

{

  .topicType = topicTypeNormal,

  .topicId = <agreed TopicId (alias)>

};


Pre-defined Alias

A Pre-defined topic id (alias) is one whose mapping to a topic (path) are known in advance.  There is no REGISTER call required with a Pre-defined alias.

A pre-defined alias can be created in the  Topics section of the Thingstream console.  The user creates a topic in the portal using the 'Create Topic' button and can then assign it an alias by selecting the topic in the list and then selecting 'Add alias' from the details page.  This pre-defined alias can then be used in the client.

As of v1.36 the client API contains a macro to assist with defining such a topic - MAKE_PREDEFINED_TOPIC(id)

e.g. 

Topic predefinedTopic = MAKE_PREDEFINED_TOPIC(107);

This results in a Thingstream Topic called 'predefinedTopic' that comprises

{

  .topicType = topicTypePredefined,

  .topicId = <107>

};

This can then be used to subscribe and publish with...


ClientResult cr = Client_subscribeTopic(client, predefinedTopic, MQTT_QOS1);


cr = Client_publish(client, predefinedTopic, MQTT_QOS1, false, (uint8_t*)msg1, strlen(msg1), NULL);


Short Topic 

A  short topic type uses a two character identifier stored in the 16-bits of the topicId, there is no REGISTER call required for a Short Topic.

The client API contains a macro to assist with defining such a topic - MAKE_SHORT_TOPIC()

for example - create a short topic, subscribe and publish to that topic

Topic shortTopic = MAKE_SHORT_TOPIC('x','y');


ClientResult cr = Client_subscribeTopic(client, shortTopic, MQTT_QOS1);

cr = Client_publish(client, shortTopic, MQTT_QOS1, false, (uint8_t*)msg1, strlen(msg1), NULL);



Still need help?

If you need more help or have any questions, please send an email to support@thingstream.io.