How to handle LoRA messages from thethingsnetwork from JavaEE with TTNClientJ2
10 Apr 2019 - tsp
Last update 16 Apr 2019
4 mins
Note: The TTNClientJ2 library described herein is in no way
associated with thethingsnetwork or their official software.
It is my own implementation to handle messages received from
them via MQTT.
Why?
The basic idea is to include the MQTT client that received messages
from thethingsnetwork into the JavaEE application and run the client
inside the same servlet container. The primary advantage over an
extra application is that one has an self contained application archive
that one can deploy via the simple deployment techniques of JavaEE (simply
copying the web application archive inside the webapps folder of
Apache Tomcat when automatic extraction
is enable - as it is by default) to deploy the whole application including
the MQTT client. It also allows to keep the configuration for the
whole project in a single place. The only externally required component
may be a database server although one could even bundle an SQLite
database with the web application if one only has to store really small
amounts of data.
How?
The usage of TTNClientJ2 is really
simple. Just add the JAR files for
to the WebContent/WEB-INF/lib
folder (and if using an IDE
update your local build path to search these libraries for classes)
Create an Handler that will receive messages from the TTN. The handler
has to implement TTNMessageHandler
. This interface provides
two functions - the main handleTTNMessage
function, that is called
whenever a message (or an device event) is received, and the an
additional initializeHandler
function that gets called whenever
the JavaEE context gets initialized. The latter function allows one
to access the servlet context in case one requires initialization
parameters (for example to initialize a database, etc.).
The most basic (test) handler might look like the following:
package at.tspi.examples.ttnclientj2.handler;
import javax.servlet.ServletContextEvent;
import at.tspi.ttnclientj2.client.TTNClient;
import at.tspi.ttnclientj2.client.TTNMessageHandler;
import at.tspi.ttnclientj2.messages.TTNMessage;
public class ExampleHandler implements TTNMessageHandler {
public ExampleHandler() { }
@Override
public boolean initializeHandler(ServletContextEvent sce) {
/*
We just signal that we have successfully initialized
ourself
*/
return true;
}
@Override
public boolean handleTTNMessage(TTNMessage msg, TTNClient cli) {
System.out.println("Message received: ");
System.out.println(msg);
System.out.println("\n\n");
// To filter only upstream messages (no device events)
if(msg instanceof TTNMessageUplink) {
// Really a data containing message
} else {
// Device event or downlink status change
}
return true;
}
}
Then one has to add configuration options to the WebContent/WEB-INF/web.xml
configuration file.
The configuration is pretty simple. There are three basic configuration parameters.
The first context parameter is ttnconnections. It contains a comma separated list
of names of connections that should be automatically established on context
initialization (i.e. most of the time this is equivalent to the deployment of
the application container).
<context-param>
<param-name>ttnconnections</param-name>
<param-value>con1</param-value>
</context-param>
For every named connection there is an url and handler parameter. The URL
parameter contains protocol, application ID and authentication information as
well as the region that the client should connect to. To connect to an
application in the EU region the URI would look like the following:
<context-param>
<param-name>con1-url</param-name>
<param-value>mqtt://your-app-id:ttn-account-v2.theauthtoken-that-issupplied-by-ttn@eu:8883</param-value>
</context-param>
The handler specifies which class should be instantiated and invoked whenever
a message arrives via this connection. This is the previously generated
class:
<context-param>
<param-name>con1-handler</param-name>
<param-value>at.tspi.examples.ttnclientj2.handler.ExampleHandler</param-value>
</context-param>
Now everything is ready and one can simply build and deploy the web
application archive.
Message types
The packets received by the TTN are passed as TTNMessage. Various
types of messages exist:
- TTN Device Events:
- TTNDeviceEventActivation is invoked whenever an device is activated (for example via OTAA)
- TTNDeviceEventCreated is invoked whenever a new device is created in the console or via the API
- TTNDeviceEventDeleted is the counterpart to the created event.
- TTNDeviceEventUpdated is always received when a device configuration has changed
- TTNDeviceEventDownlinkAck is sent after a downlink packet has been acknowledged by the device
- TTNDeviceEventDownlinkSheduled is sent whenever a downlink packet has been received by the TTN and has been sheduled for transmission on the next downlink timeslot
- TTNDownlinkSent is sent whenever a downlink message has been sent (this does not imply it has been acknowledged)
- TTNDeviceEventErrorActivation in case of an activation error
- TTNDeviceEventErrorDownlink in case of a downlink error
- TTNDeviceEventErrorUplink in case of an error during an uplink message
- TTNMessageUplink is the message container that contains a normal received message as well as all associated metadata (inside an UplinkMetadata object
- TTNMessageDownlink is the only container that gets instantiated by the application itself - it is used by the send routine of the TTNClient implementations.
This article is tagged: