question

yjay-4307 avatar image
0 Votes"
yjay-4307 asked yjay-4307 answered

Auto connect multiple devices

We have successfully connected a device to IoT central but we are wondering how we can connect multiple devices automatically?

So far we have bulk imported our devices using a csv following Manage devices in your Azure IoT Central application

We are able to auto generate the SaS Token but we are still manually inputting the connection string.

 private static String connString = "HostName=iotc-XXXXXX.azure-devices.net;DeviceId=testAll;SharedAccessKey=XXXXXXXXXX";

We are wondering if there is a way to auto generate the connection string or other ways to connect multiple devices without having to customize our app for every device(200+ devices)?

Thanks so much!

Here is the code that auto generates the SaS Token and sends data to IoT central:

 public class MyConnection {
    
     //Based on https://github.com/Azure/azure-iot-sdk-java/blob/master/device/iot-device-samples/send-receive-sample/src/main/java/samples/com/microsoft/azure/sdk/iot/SendReceive.java
    
     private static String myData = null;
    
     // 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 = "HostName=iotc-XXXXXX.azure-devices.net;DeviceId=testAll;SharedAccessKey=XXXXXXXXXX";
    
     // Using the HTTPS protocol to connect to IoT Hub
     private static IotHubClientProtocol protocol = IotHubClientProtocol.HTTPS;
     private static DeviceClient client;
    
     //Constructor
     public MyConnection(String hrData) throws IOException, URISyntaxException {
         this.myData = myData;
     }
     // Specify the telemetry to send to your IoT hub.
     private static class TelemetryDataPoint {
         public String Temp;
         // Serialize object to JSON format.
         public String serialize() {
             Gson gson = new Gson();
             return gson.toJson(this);
         }
     }
     private static final int D2C_MESSAGE_TIMEOUT = 100; //miliseconds, to send data
     private static final List<String> failedMessageListOnClose = new ArrayList<>(); // List of messages that failed on close
     /** Used as a counter in the message callback. */
     protected static class Counter
     {
         protected int num;
    
         public Counter(int num)
         {
             this.num = num;
         }
         public int get()
         {
             return this.num;
         }
         public void increment()
         {
             this.num++;
         }
         @Override
         public String toString()
         {
             return Integer.toString(this.num);
         }
     }
     protected static class MessageCallback
             implements com.microsoft.azure.sdk.iot.device.MessageCallback
     {
         public IotHubMessageResult execute(Message msg,
                                            Object context)
         {
             Counter counter = (Counter) context;
             System.out.println(
                     "Received message " + counter.toString()
                             + " with content: " + new String(msg.getBytes(), Message.DEFAULT_IOTHUB_MESSAGE_CHARSET));
             for (MessageProperty messageProperty : msg.getProperties())
             {
                 System.out.println(messageProperty.getName() + " : " + messageProperty.getValue());
             }
             int switchVal = counter.get() % 3;
             IotHubMessageResult res;
             switch (switchVal)
             {
                 case 0:
                     res = IotHubMessageResult.COMPLETE;
                     break;
                 case 1:
                     res = IotHubMessageResult.ABANDON;
                     break;
                 case 2:
                     res = IotHubMessageResult.REJECT;
                     break;
                 default:
                     // should never happen.
                     throw new IllegalStateException(
                             "Invalid message result specified.");
             }
    
             System.out.println(
                     "Responding to message " + counter.toString()
                             + " with " + res.name());
    
             counter.increment();
    
             return res;
         }
     }
     //comment
     protected static class EventCallback implements IotHubEventCallback
     {
         public void execute(IotHubStatusCode status, Object context)
         {
             Message msg = (Message) context;
             System.out.println("IoT Hub responded to message "+ msg.getMessageId()  + " with status " + status.name());
             if (status==IotHubStatusCode.MESSAGE_CANCELLED_ONCLOSE)
             {
                 failedMessageListOnClose.add(msg.getMessageId());
             }
         }
     }
    
     //comment
     protected static class IotHubConnectionStatusChangeCallbackLogger implements IotHubConnectionStatusChangeCallback
     {
         @Override
         public void execute(IotHubConnectionStatus status, IotHubConnectionStatusChangeReason statusChangeReason, Throwable throwable, Object callbackContext)
         {
             System.out.println();
             System.out.println("CONNECTION STATUS UPDATE: " + status);
             System.out.println("CONNECTION STATUS REASON: " + statusChangeReason);
             System.out.println("CONNECTION STATUS THROWABLE: " + (throwable == null ? "null" : throwable.getMessage()));
             System.out.println();
    
             if (throwable != null)
             {
                 throwable.printStackTrace();
             }
    
             if (status == IotHubConnectionStatus.DISCONNECTED)
             {
                 System.out.println("The connection was lost, and is not being re-established." +
                         " Look at provided exception for how to resolve this issue." +
                         " Cannot send messages until this issue is resolved, and you manually re-open the device client");
             }
             else if (status == IotHubConnectionStatus.DISCONNECTED_RETRYING)
             {
                 System.out.println("The connection was lost, but is being re-established." +
                         " Can still send messages, but they won't be sent until the connection is re-established");
             }
             else if (status == IotHubConnectionStatus.CONNECTED)
             {
                 System.out.println("The connection was successfully established. Can send messages.");
             }
         }
     }
    
     //main, call all methods
     public void main() throws IOException, URISyntaxException {
    
         // Connect to the IoT hub.
         client = new DeviceClient(connString, protocol);
    
         MessageCallback callback = new MessageCallback();
         Counter counter = new Counter(0);
         client.setMessageCallback(callback, counter);
    
         System.out.println("Successfully set message callback.");
    
         // Set your token expiry time limit here
         long time = 60; //seconds or miliseconds?
         client.setOption("SetSASTokenExpiryTime", time);
    
         client.registerConnectionStatusChangeCallback(new IotHubConnectionStatusChangeCallbackLogger(), new Object());
    
         client.open();
    
         System.out.println("Opened connection to IoT Hub.");
    
         System.out.println("Beginning to receive messages...");
    
         System.out.println("Sending the following event messages: ");
    
         System.out.println("Updated token expiry time to " + time);
    
         //Create the telemetry data
         TelemetryDataPoint telemetryDataPoint = new TelemetryDataPoint();
         telemetryDataPoint.Temp = temp;
         //Serialize the telemetry data
         String msgStr = telemetryDataPoint.serialize();
    
         try
         {
             //Create the payload
             Message msg = new Message(msgStr); //create the message
             msg.setContentTypeFinal("application/json"); //Content type
             msg.setMessageId(java.util.UUID.randomUUID().toString()); //message id
             msg.setExpiryTime(D2C_MESSAGE_TIMEOUT); //message expire in D2C_MESSAGE_TIMEOUT seconds
             System.out.println(msgStr);
             EventCallback eventCallback = new EventCallback();
             client.sendEventAsync(msg, eventCallback, msg); //send message
         }
         catch (Exception e)
         {
             e.printStackTrace(); // Trace the exception
         }
    
         System.out.println("Wait for " + D2C_MESSAGE_TIMEOUT / 1000 + " second(s) for response from the IoT Hub...");
    
         // Wait for IoT Hub to respond.
         try
         {
             Thread.sleep(D2C_MESSAGE_TIMEOUT);
         }
         catch (InterruptedException e)
         {
             e.printStackTrace();
         }
    
         System.out.println("In receive mode. Waiting for receiving C2D messages (only for MQTT and AMQP). Press ENTER to close. To recieve in Https, send message and then start the sample.");
    
         // close the connection
         System.out.println("Closing");
         client.closeNow();
    
         if (!failedMessageListOnClose.isEmpty())
         {
             System.out.println("List of messages that were cancelled on close:" + failedMessageListOnClose.toString());
         }
    
         System.out.println("Shutting down...");
     }
 }





azure-iot-hubazure-iot-centralazure-iotazure-iot-sdk
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

@yjay-4307 Community SME's on this topic or our team will review your scenario and circle back at the possible earliest time.

1 Vote 1 ·
SatishBoddu-MSFT avatar image
2 Votes"
SatishBoddu-MSFT answered SatishBoddu-MSFT commented

@yjay-4307 Have your referred to this document which provided information on Individual as well as Group enrollments with IoT Central.

Get connected to Azure IoT Central

74984-image.png



image.png (10.1 KiB)
· 5
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hello all,

We are investigating the issue internally and will keep you posted on this.

1 Vote 1 ·

Hi @SatishBoddu-MSFT,
Thanks for your reply!

Yes I have seen this document, we are trying to follow the SAS group enrollment. We are able to generate the individual device primary key from the group enrollment key but we need a way to do it more securely. Currently in our app we are able to put the enrollment key but this is a master key and we don't want every device to access it as that could lead to data breach.

0 Votes 0 ·

But we have seen a response:

Warning
Your device code for each device should only include the corresponding derived device key for that device. Do not include your group master key in your device code. A compromised master key has the potential to compromise the security of all devices being authenticated with it.

and

The computing of the derived symmetric key must be done before turning on your device. Your individual device shouldn't have access to the master level symmetric key.


0 Votes 0 ·
Show more comments
yjay-4307 avatar image
1 Vote"
yjay-4307 answered

@SatishBoddu-MSFT thanks so much for all your help. I had the pleasure of working with some Microsoft team members to come up with a solution. In order to not have to expose the group SaS Token we are using the Devices - Create Attestation api. We are using individual enrolment which allows us to choose our own device key by calling the attestation api. We are hashing our key in our app which then gets used in the connection string to connect the devices dynamically.

If anybody has any additional question about how we worked out this solution please feel free to tag or message me


5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.