Welcome to bytebang » The blog about all and nothing » Processing data from TheThingNetworks with Apache Camel

Processing data from TheThingNetworks with Apache Camel

Aug 31 2019

The Problem

In the last few articles I have shown how to transmit data from an IoT device directly to a MQTT broker or via LoRaWAN to TheThingsNetwork (also called TTN). This time I will show you how to build a simple mail service with Apache Camel which sends you a mail whenever your parking place is occupied.

The Solution

The solution is simple. So lets start with pointing out the facts

  1. The sensor transmits data to TheThingsNetwork
  2. TTN has an mqtt API which allows you to be updated as soon as data is transmitted
  3. Apache Camel has a MQTT component and a Mail component

So all we have to do is to fire up apache camel and to look if the datafield "distance" (if you have no idea where this is coming about: read my older article about TTN and decoders) is above or below a certain threshold.

If it is above the threshold -> send an email, otherwise just log it.

Setup of TTN

In order to make this example work, you will need the TTN application from the link above with a decoder that fills the datafield distance with the distance between the concrete surface and the car.

The next step is to allow users to access your data. This is usually done by granting an access key:

grant_accesskey.png

This key is generated and is used in the TTN-MQTT API as password. If you revoke it, then the data can not be accessed by MQTT anymore.

My application has the following settings:

  • Region: eu
  • Application Id: iotparkingplace
  • Device Id; 0000000000000001 (can be set in the device properties)
  • Decoded Datafield: distance

This leads to a MQTT-API which can be subscribed with the mosquitto_sub commandline client like this:

$ mosquitto_sub -h eu.thethings.network -p 1883 -t iotparkingplace/devices/0000000000000001/up/distance -u iotparkingplace -P ttn-account-v2.3N1PJ2VXngXXXXXXXX

Whenever the decoder processes a new distance, then the mqtt topic will be populated with a message.

Setup of your email provider

You need the credentials of your email provider which allows you to send emails via SMTPS. In my example I am using my google account.

The Apache Camel configuration

The mqtt2mail project on GitHub assumes that you are using Eclipse with Java8 and ANT as dependency management tool.

The file MainApp.java is just a starter for apache camel. It tells camel to read the application.properties where all necessary information can be entered. The real magic happens in the Mqtt2MailRoute.java :

// Decide if the parking lot is occupied or not
        from("mqtt:TheThingsNetwork?host=tcp://{{ttn.region}}.thethings.network:1883&subscribeTopicName={{ttn.app_id}}/devices/{{ttn.device_id}}/up/{{ttn.datafield}}&userName={{ttn.app_id}}&password={{ttn.app_key}}")
                .routeId("mqtt2mailroute").description("Translates MQTT states to emails")
                .convertBodyTo(String.class) // We get a byte[] and want a string
                .log("Parking device {{ttn.device_id}} reports a distance of ${body} cm")
                .choice()
                    .when().simple("${body} > 30").to("direct:occupied") // magic type conversion happens here
                    .otherwise().to("direct:free")
                .end();

        // What to do of a parking lot is free
        from("direct:free").routeId("FreeLot").log("Device {{ttn.device_id}} reports free parking lot").end();

        // Route for occupied parkingLot
        from("direct:occupied").routeId("OccupiedLot")
        .log("Device {{ttn.device_id}} reports occupied parking lot -> send mail to {{notification.emailadress}}")
        .process(new Processor()
        {
            @Override
            public void process(Exchange exchange) throws Exception
            {
                exchange.getOut().setHeader("to",      simple("{{notification.emailadress}}").evaluate(exchange, String.class));
                exchange.getOut().setHeader("subject", "Someone took your parkingplace");
                exchange.getOut().setBody("The distance to the car is " + new String(exchange.getIn().getBody(byte[].class)) + " cm.");
            }
        }).to("smtps://{{mail.server}}:{{mail.port}}?username={{mail.user}}&password={{mail.pass}}").end();
  • In the route mqtt2mailroute the payload is converted from a byte[] to a String (because the MQTT component gives you as body a bytearray. Then the value is compared against a fixed distance of 30cm with the use of the simple language, where the message is routed either to the FreeLot or to the OccupiedLot route.
  • The FreeLot route does just some logging.
  • The OccupiedLot route takes the message, adds some information to it (namely the notification email address, the subject and also the mail body) which is sent per mail to the smtp consumer route.

Finally - start up the application and start your car - wou will get a log like this (and of course some emails):

21:33:37.254 [main] INFO  org.apache.camel.impl.converter.DefaultTypeConverter - Type converters loaded (core: 195, classpath: 5)
21:33:37.276 [main] INFO  org.apache.camel.impl.DefaultCamelContext - Apache Camel 2.24.1 (CamelContext: camel-1) is starting
21:33:37.277 [main] INFO  org.apache.camel.management.ManagedManagementStrategy - JMX is enabled
21:33:37.599 [main] INFO  org.apache.camel.impl.DefaultCamelContext - StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html
21:33:37.644 [main] INFO  org.apache.camel.component.mqtt.MQTTEndpoint - Connecting to tcp://eu.thethings.network:1883 using 10 seconds timeout
21:33:37.817 [hawtdispatch-DEFAULT-2] INFO  org.apache.camel.component.mqtt.MQTTEndpoint - MQTT Connection connected to tcp://eu.thethings.network:1883
21:33:37.989 [main] INFO  org.apache.camel.impl.DefaultCamelContext - Route: mqtt2mailroute started and consuming from: mqtt:TheThingsNetwork?host=tcp://eu.thethings.network:1883&subscribeTopicName=iotparkingplace/devices/0000000000000001/up/distance&userName=iotparkingplace&password=xxxxxx
21:33:37.991 [main] INFO  org.apache.camel.impl.DefaultCamelContext - Route: FreeLot started and consuming from: direct://free
21:33:37.992 [main] INFO  org.apache.camel.impl.DefaultCamelContext - Route: OccupiedLot started and consuming from: direct://occupied
21:33:37.993 [main] INFO  org.apache.camel.impl.DefaultCamelContext - Total 3 routes, of which 3 are started
21:33:37.996 [main] INFO  org.apache.camel.impl.DefaultCamelContext - Apache Camel 2.24.1 (CamelContext: camel-1) started in 0.717 seconds
21:42:24.046 [hawtdispatch-DEFAULT-2] INFO  mqtt2mailroute - Parking device 0000000000000001 reports a distance of 5 cm
21:42:24.058 [hawtdispatch-DEFAULT-2] INFO  FreeLot - Device 0000000000000001 reports free parking lot
21:42:37.325 [hawtdispatch-DEFAULT-2] INFO  mqtt2mailroute - Parking device 0000000000000001 reports a distance of 52.29999923706055 cm
21:42:37.328 [hawtdispatch-DEFAULT-2] INFO  OccupiedLot - Device 0000000000000001 reports occupied parking lot -> send mail to gqsr85430@tuofs.com

Which results to an email like this:

email.png

Neat - isn't it ? ...Happy coding !

Get Social


(c) 2024, by bytebang e.U. - Impressum - Datenschutz / Nutzungsbedingungen
-