author | ms.author | ms.service | ms.devlang | ms.topic | ms.date | ms.custom | ||||
---|---|---|---|---|---|---|---|---|---|---|
kgremban |
kgremban |
iot-hub |
java |
include |
06/20/2024 |
|
This section describes how to receive cloud-to-device messages using the DeviceClient class from the Azure IoT SDK for Java.
For a Java-based device application to receive cloud-to-device messages, it must connect to IoT Hub, then set up a callback listener and message handler to process incoming messages from IoT Hub. The device application should also be able to detect and handle disconnects in case the device-to-IoT Hub message connection is broken.
The code referenced in this article uses these SDK libraries.
import com.microsoft.azure.sdk.iot.device.*;
import com.microsoft.azure.sdk.iot.device.exceptions.IotHubClientException;
import com.microsoft.azure.sdk.iot.device.transport.IotHubConnectionStatus;
The DeviceClient object instantiation requires these parameters:
- connString - The IoT device connection string. The connection string is a set of key-value pairs that are separated by ';', with the keys and values separated by '='. It should contain values for these keys:
HostName, DeviceId, and SharedAccessKey
. - Transport protocol - The
DeviceClient
connection can use one of the following IoTHubClientProtocol transport protocols.AMQP
is the most versatile, allows for checking messages frequently, and allows for message rejection and cancel. MQTT doesn't support message rejection or abandon methods:AMQPS
AMQPS_WS
HTTPS
MQTT
MQTT_WS
For example:
static string connectionString = "{a device connection string}";
static protocol = IotHubClientProtocol.AMQPS;
DeviceClient client = new DeviceClient(connectionString, protocol);
Use the setMessageCallback method to define a message handler method that is notified when a message is received from IoT Hub.
setMessageCallback
includes these parameters:
callback
- The callback method name. Can benull
.context
- An optional context of typeobject
. Usenull
if unspecified.
In this example, a callback
method named MessageCallback
with no context parameter is passed to setMessageCallback
.
client.setMessageCallback(new MessageCallback(), null);
A callback message handler receives and processes an incoming message passed from the IoT Hub messages queue.
In this example, the message handler processes an incoming message and then returns IotHubMessageResult.COMPLETE. A IotHubMessageResult.COMPLETE
return value notifies IoT Hub that the message is successfully processed and that the message can be safely removed from the device queue. The device should return IotHubMessageResult.COMPLETE
when its processing successfully completes, notifying IoT Hub that the message should be removed from the message queue, regardless of the protocol it's using.
protected static class MessageCallback implements com.microsoft.azure.sdk.iot.device.MessageCallback
{
public IotHubMessageResult onCloudToDeviceMessageReceived(Message msg, Object context)
{
System.out.println(
"Received message with content: " + new String(msg.getBytes(), Message.DEFAULT_IOTHUB_MESSAGE_CHARSET));
// Notify IoT Hub that the message
return IotHubMessageResult.COMPLETE;
}
}
Though the vast number of incoming messages to a device should be successfully received and result in IotHubMessageResult.COMPLETE
, it may be necessary to abandon or reject a message.
- With AMQP and HTTPS, but not MQTT, an application can:
IotHubMessageResult.ABANDON
the message. IoT hub requeues it and sends it again later.IotHubMessageResult.REJECT
the message. IoT hub doesn't requeue the message and permanently removes the message from the message queue.
- Clients using
MQTT
orMQTT_WS
cannotABANDON
orREJECT
messages.
If something happens that prevents the device from completing, abandoning, or rejecting the message, IoT Hub will, after a fixed timeout period, queue the message for delivery again. For this reason, the message processing logic in the device app must be idempotent, so that receiving the same message multiple times produces the same result.
For more information about the cloud-to-device message lifecycle and how IoT Hub processes cloud-to-device messages, see Send cloud-to-device messages from an IoT hub.
Note
If you use HTTPS instead of MQTT or AMQP as the transport, the DeviceClient instance checks for messages from IoT Hub infrequently (a minimum of every 25 minutes). For more information about the differences between MQTT, AMQP, and HTTPS support, see Cloud-to-device communications guidance and Choose a communication protocol.
An application can use registerConnectionStatusChangeCallback to register a callback method to be executed when the connection status of the device changes. This way the application can detect a downed messages connection and attempt to reconnect.
In this example, IotHubConnectionStatusChangeCallbackLogger
is registered as the connection status change callback method.
client.registerConnectionStatusChangeCallback(new IotHubConnectionStatusChangeCallbackLogger(), new Object());
The callback is fired and passed a ConnectionStatusChangeContext
object.
Call connectionStatusChangeContext.getNewStatus()
to get the current connection state.
IotHubConnectionStatus status = connectionStatusChangeContext.getNewStatus();
The connection state returned can be one of these values:
IotHubConnectionStatus.DISCONNECTED
IotHubConnectionStatus.DISCONNECTED_RETRYING
IotHubConnectionStatus.CONNECTED
Call connectionStatusChangeContext.getNewStatusReason()
to get the reason for the connection status change.
IotHubConnectionStatusChangeReason statusChangeReason = connectionStatusChangeContext.getNewStatusReason();
Call connectionStatusChangeContext.getCause()
to find the reason for the connection status change. getCause()
may return null
if no information is available.
Throwable throwable = connectionStatusChangeContext.getCause();
if (throwable != null)
throwable.printStackTrace();
See the HandleMessages sample listed in the SDK receive message sample section of this article for a complete sample showing how to extract the status change callback method connection status change status, reason why the device status changed, and context.
Use open to create a connection between the device and IoT Hub. The device can now asynchronously send and receive messages to and from an IoT Hub. If the client is already open, the method does nothing.
client.open(true);
HandleMessages: a sample device app included with the Microsoft Azure IoT SDK for Java, which connects to your IoT hub and receives cloud-to-device messages.
This section describes how to send a cloud-to-device message using the ServiceClient class from the Azure IoT SDK for Java. A solution backend application connects to an IoT Hub and messages are sent to IoT Hub encoded with a destination device. IoT Hub stores incoming messages to its message queue, and messages are delivered from the IoT Hub message queue to the target device.
A solution backend application can also request and receive delivery feedback for a message sent to IoT Hub that is destined for device delivery via the message queue.
Add the dependency to use the iothub-java-service-client package in your application to communicate with your IoT hub service:
<dependency>
<groupId>com.microsoft.azure.sdk.iot</groupId>
<artifactId>iot-service-client</artifactId>
<version>1.7.23</version>
</dependency>
Add these import statements to use the Azure IoT Java SDK and exception handler.
import com.microsoft.azure.sdk.iot.service.*;
import java.io.IOException;
import java.net.URISyntaxException;
Use IotHubServiceClientProtocol to define the application-layer protocol used by the service client to communicate with an IoT Hub.
IotHubServiceClientProtocol
only accepts the AMQPS
or AMQPS_WS
enum.
private static final IotHubServiceClientProtocol protocol =
IotHubServiceClientProtocol.AMQPS;
Create the ServiceClient object, supplying the Iot Hub connection string and protocol.
private static final String connectionString = "{yourhubconnectionstring}";
private static final ServiceClient serviceClient (connectionString, protocol);
open the AMQP sender connection. This method creates the connection between the application and IoT Hub.
serviceClient.open();
You can use a FeedbackReceiver to get sent message delivery to IoT Hub feedback. A FeedbackReceiver
is a specialized receiver whose Receive
method returns a FeedbackBatch
instead of a Message
.
In this example, the FeedbackReceiver
object is created and the open()
statement is called to await feedback.
FeedbackReceiver feedbackReceiver = serviceClient
.getFeedbackReceiver();
if (feedbackReceiver != null) feedbackReceiver.open();
You can optionally use setProperties to add message properties. These properties are included in the message sent to the device and can be extracted by the device application upon receipt.
Map<String, String> propertiesToSend = new HashMap<String, String>();
propertiesToSend.put(messagePropertyKey,messagePropertyKey);
messageToSend.setProperties(propertiesToSend);
The Message object stores the message to be sent. In this example, a "Cloud to device message" is delivered.
Use setDeliveryAcknowledgement to request delivered/not delivered to IoT Hub message queue acknowledgment. In this example, the acknowledgment requested is Full
, either delivered or not delivered.
Use SendAsync to send an asynchronous message from the client to the device. Alternatively, you can use the Send
(not async) method, but this function is synchronized internally so that only one send operation is allowed at a time. The message is delivered from the application to IoT Hub. IoT Hub puts the message into the message queue, ready to be delivered to the target device.
Message messageToSend = new Message("Cloud to device message.");
messageToSend.setDeliveryAcknowledgementFinal(DeliveryAcknowledgement.Full);
serviceClient.sendAsync(deviceId, messageToSend);
After a message is sent from the application, the application can call receive with or without a timeout value. If a timeout value is not supplied, the default timeout is used. This passes back a FeedbackBatch object that contains message delivery feedback properties that can be examined.
This example creates the FeedbackBatch
receiver and calls getEnqueuedTimeUtc, printing the message enqueued time.
FeedbackBatch feedbackBatch = feedbackReceiver.receive(10000);
if (feedbackBatch != null) {
System.out.println("Message feedback received, feedback time: "
+ feedbackBatch.getEnqueuedTimeUtc().toString());
}
-
Service client sample - Send message example, #1.
-
Service client sample - Send message example, #2.