| author | SoniaLopezBravo | |||||
|---|---|---|---|---|---|---|
| ms.author | sonialopez | |||||
| ms.service | azure-iot-hub | |||||
| ms.devlang | java | |||||
| ms.topic | include | |||||
| ms.date | 12/19/2024 | |||||
| ms.custom |
|
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 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;A device app can authenticate with IoT Hub using the following methods:
- Shared access key
- X.509 certificate
[!INCLUDE iot-authentication-device-connection-string.md]
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
DeviceClientconnection can use one of the following IoTHubClientProtocol transport protocols.AMQPis the most versatile, allows for checking messages frequently, and allows for message rejection and cancel. MQTT doesn't support message rejection or abandon methods:AMQPSAMQPS_WSHTTPSMQTTMQTT_WS
For example:
static string connectionString = "{IOT hub device connection string}";
static protocol = IotHubClientProtocol.AMQPS;
DeviceClient client = new DeviceClient(connectionString, protocol);[!INCLUDE iot-hub-howto-auth-device-cert-java]
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. Usenullif 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.ABANDONthe message. IoT hub requeues it and sends it again later.IotHubMessageResult.REJECTthe message. IoT hub doesn't requeue the message and permanently removes the message from the message queue.
- Clients using
MQTTorMQTT_WScannotABANDONorREJECTmessages.
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.DISCONNECTEDIotHubConnectionStatus.DISCONNECTED_RETRYINGIotHubConnectionStatus.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;You can connect a backend service to IoT Hub using the following methods:
- Shared access policy
- Microsoft Entra
[!INCLUDE iot-authentication-service-connection-string.md]
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.
IotHubServiceClientProtocol protocol = IotHubServiceClientProtocol.AMQPS;Create the ServiceClient object, supplying the IoT Hub connection string and protocol.
String connectionString = "{yourhubconnectionstring}";
ServiceClient serviceClient (connectionString, protocol);open the AMQP sender connection. This method creates the connection between the application and IoT Hub.
serviceClient.open();[!INCLUDE iot-hub-howto-connect-service-iothub-entra-java]
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());
}There are two send message samples:
- Service client sample - Send message example, #1.
- Service client sample - Send message example, #2.