Skip to content
This repository has been archived by the owner on Nov 9, 2021. It is now read-only.

Commit

Permalink
Example command and control application for the Bosch IoT Hub
Browse files Browse the repository at this point in the history
  • Loading branch information
Sandy Meier authored and Sandy Meier committed Dec 11, 2018
1 parent 32d967d commit fc7357e
Show file tree
Hide file tree
Showing 8 changed files with 327 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ The example code provided here shows a selection of the Bosch IoT Hub service fu
### Example Consumer Application
The example consumer application shows how to connect Hono client to the IoT Hub messaging (consumer) endpoint and create a telemetry consumer in order to consume telemetry messages. For details on how to build and start the example consumer application, please consult the example application [readme](example-consumer/README.md).

### Example Command & Control Application
The application shows how to connect to the IoT Hub messaging endpoint and send a command to a device in one-way mode.
See specific [readme](command-and-control/README.md) for more details.

## Acknowledgments
The IoT Hub examples make use of the following open source software:

Expand Down
54 changes: 54 additions & 0 deletions command-and-control/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Command & Control Application

The application shows how to connect to the IoT Hub messaging endpoint and send a command to a device in one-way mode.
It sends automatically a "switchLight" command with the payload "On" to a device which must be connected.

For a more complex example see the [Hono example application](https://github.com/eclipse/hono/tree/master/example)
The guide only works for Linux & Mac systems, for MS Windows you have to adapt the paths and options.

# Prerequisites

following software must be installed:

* Java 8 (Oracle JDK or OpenJDK) or newer
* maven 3.5.2 or newer
* [mosquitto_sub](https://mosquitto.org/) for subscribing to receive commands


An existing IoT Hub service instance and a valid tenant ID are needed to run the application.
Please consult [IoT Hub documentation](https://docs.bosch-iot-hub.com/booktenant.html) on how to book a IoT Hub service instance.
In the 'Credentials' information of a IoT Hub service subscription information, you will find the 'tenant-id', the 'messaging-username' and 'messaging-password'.
Please register a device and setup password credentials. You will need the 'device-id', 'auth-id' and the matching secret for the 'auth-id'.

## Subscribe to receive commands

To receive commands, a device must subscribe to a specific control topic.
As exemplary device the Eclipse Mosquitto MQTT client is used. Please make sure auth-id and the matching secret is set correctly.

~~~
mosquitto_sub -d -h mqtt.bosch-iot-hub.com -p 8883 -u {auth-id}@{tenant-id} -P {secret} --capath /etc/ssl/certs/ -t control/+/+/req/#
~~~

## Send commands

To build and package the application as a runnable JAR file run:

~~~
mvn clean package -DskipTests
~~~

The command application needs a few parameters set to run. Please make sure the following are set correctly:

* `messaging-username`: the username for the IoT Hub messaging endpoint (messaging@tenant-id)
* `messaging-password`: the password for the IoT Hub messaging endpoint
* `tenant-id`: the tenant ID
* `device-id`: a device ID to send command


To start the application, run:

~~~
java -jar target/command-and-control-1.0-SNAPSHOT.jar --hono.client.tlsEnabled=true --hono.client.username={messaging-username} --hono.client.password={messaging-password} --tenant.id={tenant-id} --device.id={device-id}
~~~

The application will connect to the IoT Hub and send the command to a subscribed device. You should see the received command in the 'mosquitto_sub' output.
103 changes: 103 additions & 0 deletions command-and-control/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.bosch.iothub</groupId>
<artifactId>iot-hub-examples</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>command-and-control</artifactId>
<name>Bosch IoT Hub - Command &amp; Control</name>
<version>1.0-SNAPSHOT</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemProperties>
<property>
<name>iot-hub.messaging.host</name>
<value>messaging.bosch-iot-hub.com</value>
</property>
<property>
<name>hono.client.user</name>
<value>UNSET</value>
</property>
<property>
<name>hono.client.password</name>
<value>UNSET</value>
</property>
<property>
<name>iot-hub.tenant.id</name>
<value>UNSET</value>
</property>
</systemProperties>
<includes>
<include>**/*Test.java</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.hono</groupId>
<artifactId>hono-client</artifactId>
<version>0.8</version>
</dependency>
<!-- testing dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-unit</artifactId>
<version>3.5.4</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2018 Bosch Software Innovations GmbH ("Bosch SI"). All rights reserved.
*/
package com.bosch.iothub.examples;

import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.core.dns.AddressResolverOptions;
import org.eclipse.hono.client.HonoClient;
import org.eclipse.hono.client.impl.HonoClientImpl;
import org.eclipse.hono.config.ClientConfigProperties;
import org.eclipse.hono.connection.ConnectionFactory;
import org.eclipse.hono.connection.impl.ConnectionFactoryImpl;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* Configuration for Example application.
*/
@Configuration
public class AppConfiguration {

private static final int DEFAULT_ADDRESS_RESOLUTION_TIMEOUT = 2000;

/**
* Exposes a Vert.x instance as a Spring bean.
*
* @return The Vert.x instance.
*/
@Bean
public Vertx vertx() {
VertxOptions options = new VertxOptions()
.setAddressResolverOptions(new AddressResolverOptions()
.setCacheNegativeTimeToLive(0) // discard failed DNS lookup results immediately
.setCacheMaxTimeToLive(0) // support DNS based service resolution
.setRotateServers(true)
.setQueryTimeout(DEFAULT_ADDRESS_RESOLUTION_TIMEOUT));
return Vertx.vertx(options);
}

/**
* Exposes client configuration properties as a Spring bean.
*
* @return The properties.
*/
@ConfigurationProperties(prefix = "hono.client")
@Bean
public ClientConfigProperties honoClientConfig() {
return new ClientConfigProperties();
}

/**
* Exposes a factory for connections to the Hono server
* as a Spring bean.
*
* @return The connection factory.
*/
@Bean
public ConnectionFactory honoConnectionFactory() {
return new ConnectionFactoryImpl(vertx(), honoClientConfig());
}


/**
* Exposes a {@code HonoClient} as a Spring bean.
*
* @return The Hono client.
*/
@Bean
public HonoClient honoClient() {
return new HonoClientImpl(vertx(), honoConnectionFactory(), honoClientConfig());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright 2018 Bosch Software Innovations GmbH ("Bosch SI"). All rights reserved.
*/
package com.bosch.iothub.examples;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2018 Bosch Software Innovations GmbH ("Bosch SI"). All rights reserved.
*/
package com.bosch.iothub.examples;

import io.vertx.core.Future;
import io.vertx.core.buffer.Buffer;
import io.vertx.proton.ProtonClientOptions;
import org.eclipse.hono.client.CommandClient;
import org.eclipse.hono.client.HonoClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

@Component
public class OneWayCommand {
private static final Logger LOG = LoggerFactory.getLogger(OneWayCommand.class);

@Value(value = "${tenant.id}")
protected String tenantId;

@Value(value = "${device.id}")
protected String deviceId;

private final HonoClient client;
private final ApplicationContext appContext;

@Autowired
public OneWayCommand(HonoClient client, ApplicationContext appContext) {
this.client = client;
this.appContext = appContext;
}

@PostConstruct
private void start() {
LOG.info("Connecting to IoT Hub messaging endpoint...");
client.connect(new ProtonClientOptions()).compose(connectedClient -> {
LOG.info("Connected to IoT Hub messaging endpoint.");
final Future<CommandClient> commandClientFuture = connectedClient.getOrCreateCommandClient(tenantId, deviceId);
commandClientFuture.setHandler(commandClientResult -> {
final CommandClient commandClient = commandClientResult.result();
sendOneWayCommand(commandClient);
});
return Future.succeededFuture();
}).otherwise(connectException -> {
LOG.info("Connecting or creating a command client failed with an exception: ", connectException);
return null;
});
}

private void sendOneWayCommand(CommandClient commandClient) {
LOG.info("Send command (one-way mode) to device '{}'", deviceId);
commandClient.setRequestTimeout(TimeUnit.SECONDS.toMillis(2)); // increase to avoid errors with 200 ms default timeout
final Buffer data = Buffer.buffer("on");
final Future<Void> commandResult = commandClient.sendOneWayCommand("switchLight", data);
commandResult.setHandler(result -> {
if (result.succeeded()) {
LOG.info("Command successfully send");
SpringApplication.exit(appContext, (ExitCodeGenerator) () -> 0);
} else {
LOG.error("Command not successfully send: {}", result.cause().getMessage());
SpringApplication.exit(appContext, (ExitCodeGenerator) () -> 1);
}
});
}
}
3 changes: 3 additions & 0 deletions command-and-control/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
hono:
client:
host: messaging.bosch-iot-hub.com
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

<modules>
<module>example-consumer</module>
<module>command-and-control</module>
</modules>
<build>
<plugins>
Expand Down

0 comments on commit fc7357e

Please sign in to comment.