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
- The sensor transmits data to TheThingsNetwork
- TTN has an mqtt API which allows you to be updated as soon as data is transmitted
- 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:
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:
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 :
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.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:
Neat - isn't it ? ...Happy coding !