Hot questions for Using Azure in azure iot sdk

Top Java Programmings / Azure / azure iot sdk

Question:

I am trying to provision my device into Azure IoT using Azure IoT Device Provisioning Service in which I am using the custom allocation policy, under manage enrollment group.

When the device registers to DPS (device provisioning service), it triggers an Azure Function in which I will decide which IoT Hub the device will be assigned to.

In my function, I have to take this decision based on some custom payload which I need to send from the device at the time of registering itself to DPS.

How will I send that custom payload from the device to the DPS at the time of registering itself, so I can get that payload in my Azure Function and can take a decision?

I am using Java as a programming language for the same.


Answer:

If you are using X.509 based authentication, your Azure Function is getting the actual certificate as part of the request (in the clientCertificate field).

Therefore, you may want to use custom fields in your certificate that you can read in your function, and then allocate your IoT Hub of choice based on their contents.

Another option, and probably more elegant as having custom fields in your certificate might expose information that'd better remain private, would be to maintain the mappings between the registrationId, customerId, customerId, etc. in a separate store, which you can query in your Azure Function.

Question:

I use the IoT Hub Java library to send messages between my devices and Microsoft Azure.

To connect I call

client = new DeviceClient(connString, protocol);
client.open();

And then, to send a message I call

client.sendEventAsync(message, callback, lockobj);

Then, my callback function is called when the message is sent.

However, and here is the problem, after calling sendEventAsync on my terminal appears infinitly the message Lost connection to the server. Reconnecting 0 time.

I've tried to close the connection after send the message and reopen it each time, but I think it's worst and the problem persists. Moreover, I've executed the test sample given by Azure (https://github.com/Azure-Samples/azure-iot-samples-java/archive/master.zip) and I have the same problem.

So my question is, is there a problem with the library (since the problem is present even with its code)? Or am I doing something wrong?

Thanks a lot!


Answer:

I found the problem: today I was testing the same code as yesterday and everything worked well. So I have logged in Azure and I found this error message:

There was an error querying devices: Forbidden:{ "Message": "ErrorCode:IotHubQuotaExceeded;Total number of messages on IotHub '[..]' exceeded the allocated quota. Max allowed message count : '8000', current message count : '20107'. Send and Receive operations are blocked for this hub until the next UTC day. Consider increasing the units for this hub to increase the quota.", "ExceptionMessage": "Tracking ID:[..]-TimeStamp:10/17/2018 08:48:37" }.

So that, the problem was that I exeeded the messages quota. However, yesterday I was confused because Azure responded me with the message "OK_EMPTY" that means that everything is ok...

Question:

I am creating IoT remote monitoring and notifications with Azure Logic Apps as per the instructions stated in https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-monitoring-notifications-with-azure-logic-apps.

Telemetry Simulator (Java using com.microsoft.azure.sdk.iot -> iot-device-client -> 1.14.0 version)

public class SimulatedDevice {
    // The device connection string to authenticate the device with your IoT hub.
    // Using the Azure CLI:
    // az iot hub device-identity show-connection-string --hub-name {YourIoTHubName}
    // --device-id MyJavaDevice --output table
    private static String connString = "#ConnectionString";

    private static IotHubClientProtocol protocol = IotHubClientProtocol.AMQPS;
    private static DeviceClient client;

    // Specify the telemetry to send to your IoT hub.
    private static class TelemetryDataPoint {
        public double temperature;
        public double humidity;
        public String isTrue = "true";

        // Serialize object to JSON format.
        public String serialize() {
            Gson gson = new Gson();
            return gson.toJson(this);
        }
    }

    // Print the acknowledgement received from IoT Hub for the telemetry message
    // sent.
    private static class EventCallback implements IotHubEventCallback {
        public void execute(IotHubStatusCode status, Object context) {
            System.out.println("IoT Hub responded to message with status: " + status.name());

            if (context != null) {
                synchronized (context) {
                    context.notify();
                }
            }
        }
    }

    private static class MessageSender implements Runnable {
        public void run() {
            try {
                // Initialize the simulated telemetry.
                double minTemperature = 20;
                double minHumidity = 60;
                Random rand = new Random();
                int i = 0;

                while (i < 100000) {
                    // Simulate telemetry.
                    double currentTemperature = minTemperature + rand.nextDouble() * 15;
                    double currentHumidity = minHumidity + rand.nextDouble() * 20;
                    TelemetryDataPoint telemetryDataPoint = new TelemetryDataPoint();
                    telemetryDataPoint.temperature = currentTemperature;
                    telemetryDataPoint.humidity = currentHumidity;

                    // Add the telemetry to the message body as JSON.
                    String msgStr = telemetryDataPoint.serialize();

                    byte[] bodyClone = msgStr.getBytes(StandardCharsets.UTF_8);
                    Message msg = new Message(bodyClone);

                    // Add a custom application property to the message.
                    // An IoT hub can filter on these properties without access to the message body.
                    msg.setProperty("temperatureAlert", (currentTemperature > 30) ? "true" : "false");
                    msg.setMessageType(MessageType.DEVICE_TELEMETRY);

                    System.out.println("Sending message string: " + msgStr);
                    System.out.println("Sending message: " + msg);

                    Object lockobj = new Object();

                    // Send the message.
                    EventCallback callback = new EventCallback();
                    client.sendEventAsync(msg, callback, lockobj);

                    synchronized (lockobj) {
                        lockobj.wait();
                    }
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                System.out.println("Finished.");
            }
        }
    }

    public static void main(String[] args) throws IOException, URISyntaxException {

        // Connect to the IoT hub.
        client = new DeviceClient(connString, protocol);
        client.open();

        // Create new thread and start sending messages
        MessageSender sender = new MessageSender();
        ExecutorService executor = Executors.newFixedThreadPool(1);
        executor.execute(sender);

        // Stop the application.
        System.out.println("Press ENTER to exit.");
        System.in.read();
        executor.shutdownNow();
        client.closeNow();
    }
}

For QueryString - temperatureAlert = "true" - everything is working fine. But for query string - $body.temperature > 30 - then I don't receive any messages.


Answer:

In order for IoT Hub to know whether the message can be routed based on its body contents, the message must contain specific headers which describe the content and encoding of its body. In particular, messages must have both these headers for routing on message body to work:

  1. Content type of "application/json"
  2. Content encoding must match one of:
    • "utf-8"
    • "utf-16"
    • "utf-32"

Here add below two lines just below the syntax to create Message object:

msg.setContentEncoding("utf-8");
msg.setContentType("application/json");

Question:

I am new to azure iot. and i am trying to create shared access policies in azure iot hub using its rest api.

 https://management.azure.com/subscriptions/{subscription-Id}/resourceGroups/{group-name}/providers/Microsoft.Devices/IotHubs/{hub-name}?api-version=2016-02-03");

and my java code is

     String policyold = "{\"tags\" : {}, \"location\": \"East Asia\",\"properties\" : \"authorizationPolicies\" : [{\"name\" : \"policy-namw\", \"primaryKey\" : \"{mykey}\" ,\"secondaryKey\" : \"secondary-key\" ,\"permissions\" :[\"ServiceConnect\" ,\"RegistryRead\" ,\"RegistryWrite\" ,\"DeviceConnect\"]}],\"eventHubEndpoints\" : { \"events\" : {\"messageRetentionInDays\":\"2\"}}}";


    StringEntity input1 = new StringEntity(policyold);
    input1.setContentType("application/json");
    input1.setContentEncoding("UTF8");
    put.setEntity(input1);

    put.setHeader("Authorization", token);
    HttpResponse r2 = httpclient2.execute(put);
    System.out.println(r2.getStatusLine());
    String content2 = EntityUtils.toString(r2.getEntity());
    org.json.JSONObject recvObj2 = new org.json.JSONObject(content2);

but i am facing the followiing error.

 HTTP/1.1 400 Bad Request  {"error":{"code":"InvalidRequestContent","message":"The request content was invalid and could not be deserialized: 'Error converting value \"authorizationPolicies\" to type 'System.Collections.Generic.Dictionary`2[System.String,Newtonsoft.Json.Linq.JToken]'. Path 'properties', line 1, position 76.'."}}

Moreover i am using this tutorial.https://msdn.microsoft.com/en-us/library/mt589015.aspx

Can any one help me in solving this?


Answer:

According to the offical document Common error codes for Azure IoTHub, the error code 400 means "The body of the request is not valid; for example, it cannot be parsed, or the object cannot be validated.".

I checked the policyold string value in your code, then I found the json string missed the required elements Sku name & Units. Please carefully see the table of the elements below the end of the Json request content.

An Azure IoTHub can own multiple shared access policies.

So if creating shared access policy while creating new IoTHub, please use the REST API Create a new IoT Hub, else use the REST API Update metadata on an existing IoT Hub to add a new one for an existing IoTHub.

Question:

I have an Azure Iot Hub setup with a few devices and a Java service connected. I would like to be able to retrieve the traffic statistics (i.e. number of device to cloud messages in a particular time window).

The Azure portal is able to display the overall traffic data (but not on a per device basis), but I haven't found any way of accessing that data, nor seeing a breakdown of the traffic for each device on the portal.

I've looked into the REST API that Azure supports, including the Java Azure SDK, but couldn't find anything relating to IoT network traffic.


Answer:

Azure IoT Hub's metrics (the data you see on the portal) cannot be broken down to a device level directly. To get traffic statistics for a device or a set of devices, you would need to set up an additional service to consume and count the messages. One way to do it is to use Azure Stream Analytics and count up the messages using the IoTHub.ConnectionDeviceId field.