I am trying to connect a Minew BLE Gateway Device (https://en.minewtech.com/gateway.html) to azure IOT Central. The device template has a prebuilt for this device named as FM 201 BLE and I just went along with it. The gateway requires you connect it thru the X509(ECC) certificates and so I created some selfsigned certificates and uploaded them to the gateway device and uploaded it from it's dashboard
I grabbed the URL from here
Is there anything I'm doing wrong? I'm expecting something in the analtyics of my iotcentral application or atleast a log file from BLE Gateway somewhere if the authentication with certificates failed. Any lead will be highly appreciated. Ive spent hours on the web trying to get this working
I do recommend the following steps before connecting the real device to the IoT Central:
Create 3 devices (e.g. device1, device2 and device3) each with the different authentication type such as sas, selfSigned and certificateAuthority on the IoT Hub (you can used also the Free tier)
Create the simulated device (console program) for each authentication type, connect them to the IoT Hub and send couple messages.
I believe that all devices will work properly (like in my test), so the authentication through a CA certificate (and the leaf certificate) and self signed certificate are OK.
Note, that the above steps passed in my test using a C# simulated devices (.Net SDK) and also with a MQTT direct protocol with my Azure IoT Hub Tester.
Once your simulated devices are working, this step is to replace them (except the sas device) with your real device. This is a critical step, which will prove it that your real device can be connected to the Azure IoT Hub.
In this step, we are going to replace the IoT Hub by IoT Central Application. You can create a free preview application. You can upload the device template such as FM-201 IoT Gateway and create the 3 devices like in the step1 from this template. Note, use the same device ids like in the step1, we can use the same device leaf certificate.
Using the tool dps_cstr we can get the device connection string for underlying IoT Hub of the IoTC App.
Replace the hostname in your simulated devices and also you need to create the sas token from this connection string for the device authenticate with the sas token.
Run the simulated devices connected to the IoTC App.
Based on my recently test, you will see, that only sas device is working, the others such as certificate devices are failed for authentication error.
This step is for troubleshooting why the X509 simulated devices switching to the IoTC App doesn't authenticate with the same certificates. There is no properly document for this case and I hope that some one from the IoT Central team will answer it if we can switch the X509 device between the IoT Hub and IoTC App like we can do it for sas device.
Update:
Based on the Provisioning Device Client Sample - Microsoft Azure IoT SDK for .NET the steps 6 and 7 are fine for sas device, where the utility dps_cstr will registered a device for a SecurityProviderSymmetricKey. Once the device has been registered and provisioned with this security provider, the real device(s) must be connected using this way, only. That's the reason why we getting an error for simulated x509 devices. So, the following step is an example of the provisioning a X509 device with a leaf certificate (device3.pfx). Note, that the CA certificate must be uploaded to the IoTC Application.
6a. Registering the device3 (from the step1) to the IoTC App
string GlobalDeviceEndpoint = "global.azure-devices-provisioning.net";
string idScope = "<idScope_IoTCapp>";
string certificateFileName = #"<your path>\device3.pfx";
//
var cert = new X509Certificate2(certificateFileName, "1234");
var securityProvider = new SecurityProviderX509Certificate(cert);
var transport = new ProvisioningTransportHandlerMqtt(TransportFallbackType.TcpOnly);
var provClient = ProvisioningDeviceClient.Create(GlobalDeviceEndpoint, idScope, securityProvider, transport);
var result = provClient.RegisterAsync().Result;
string hostname = result.AssignedHub;
string deviceId = result.DeviceId;
In this point, the device status in the IoTC App is Provisioned and the simulated or real device can be connected.
6b. You can use for a device provisioning to the IoT Central App also the REST APIs. The following screen snippets show provisioning the X509 device3 authenticated by its leaf certificate using the Postman:
In prior of using the REST calls, we have to add the device3 leaf certificate to the Postman:
Now, we can call a provisioning service:
PUT https://global.azure-devices-provisioning.net/0ne000AA0F5/registrations/device3/register?api-version=2019-03-31
To get the registrationState object:
GET https://global.azure-devices-provisioning.net/0ne000AA0F5/registrations/device3/operations/{operationId}?api-version=2019-03-31
As you can see the above picture, the IoTC application is ready for connection with a real X509 device.
"registrationState": {
"x509": {
"enrollmentGroupId": "fa472b95-b5f6-47af-a4ef-9490f45c3961"
},
"registrationId": "device3",
"createdDateTimeUtc": "2020-01-04T17:09:15.5147034Z",
"assignedHub": "iotc-bceedf66-9792-4f32-b49f-7674a6aa09ff.azure-devices.net",
"deviceId": "device3",
"status": "assigned",
"substatus": "initialAssignment",
"lastUpdatedDateTimeUtc": "2020-01-04T17:09:15.6947214Z",
"etag": "IjBmMDA3YTgzLTAwMDAtMGMwMC0wMDAwLTVlMTBjNmJiMDAwMCI="
}
Note, that in the case of provisioning a sas device (such as a device1 in this test) using the REST calls, the Authorization header must be configured with a sas token:
string sas = generateSASToken($"{scopeId}/registrations/{deviceId}", deviceKey, "registration");
7a. The following code snippet is an example of the sending a telemetry data from the X509 device with its leaf certificate (device3.pfx):
using (var dc = DeviceClient.Create(hostname, new DeviceAuthenticationWithX509Certificate(deviceId, cert), Microsoft.Azure.Devices.Client.TransportType.Mqtt))
{
var telemetryDataPoint = new { bleCnt = 50, telemetryLocation = new { lat = 49.85, lon = 20.99, alt = 29.41 } };
dc.OpenAsync().ConfigureAwait(false);
dc.SendEventAsync(new Message(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(telemetryDataPoint)))).ConfigureAwait(false);
dc.CloseAsync().ConfigureAwait(false);
}
Also, using my Azure IoT Hub Tester which is based on the M2Mqtt library the device3 with a leaf certificate device3.pfx has been successful connected to the IoTC app.
Based on the above update, I would like to correct the step 10. It looks like, the devices (such as the sas and X509) can be switched between the Azure IoT Hub and IoT Central Application once the devices have been provisioned on the IoTC App. In other words, the hostname (e.g. from my test IoTC App preview iotc-bceedf66-9792-4f32-b49f-7674a6aa09ff.azure-devices.net) from the provisioning process is a valid device facing endpoint.
Also my test shown that the device with MQTT direct protocol using a leaf certificate (device3.pfx) for connection to the IoTC app is working very well both directions included a PnP model.
The following screen snippets show the device side and IoTC application:
publishing some telemetry data:
showing telemetry data on the dashboard:
and the root CA certificate on the IoTC app:
I am following the next tutorial to add new real device on Azure IoT Central.
https://learn.microsoft.com/en-us/azure/iot-central/tutorial-add-device
I want to use a node red flow to upload data, using the Azure IoT Hub flow, but in the tutorial is not very clear how generate the connection string. I can not find the dps_cstr tool for Windows...
Do you know how I can generate the connection string to upload data from Node-Red to Azure IoT Central?
Thanks
The tutorial has a mistake.
With the dps-keygen we can generate the connection String. I use, -di,-dk,-si
dps-keygen <args>
args:
-di:<deviceId> : device id
-dk:<deviceKey> : device primary or secondary key
-mk:<masterKey> : admin primary or secondary key
-si:<scopeId> : scope id
-mr:<uri> : model repository uri
-mc:<uri> : model capability uri. Leave blank if its value is similar to model rep. uri.
-mi:<modelId> : model id
I have seen code for individual enrollment but I can't find any for group enrollment. I need to bulk enroll a thousand devices to Azure IOT Hub and was thinking of group enrollment.Any sample code will be appreciated.
It should be possible both with group enrollment and bulk individual enrollments. From the samples related to How to manage device enrollments with Azure Device Provisioning Service SDKs:
Bulk Individual Enrollments
public async Task<List<IndividualEnrollment>> CreateBulkIndividualEnrollmentsAsync()
{
Console.WriteLine("\nCreating a new set of individualEnrollments...");
List<IndividualEnrollment> individualEnrollments = new List<IndividualEnrollment>();
foreach (var item in _registrationIds)
{
Attestation attestation = new TpmAttestation(item.Value);
individualEnrollments.Add(new IndividualEnrollment(item.Key, attestation));
}
Console.WriteLine("\nRunning the bulk operation to create the individualEnrollments...");
BulkEnrollmentOperationResult bulkEnrollmentOperationResult =
await _provisioningServiceClient.RunBulkEnrollmentOperationAsync(BulkOperationMode.Create, individualEnrollments).ConfigureAwait(false);
Console.WriteLine("\nResult of the Create bulk enrollment.");
Console.WriteLine(bulkEnrollmentOperationResult);
return individualEnrollments;
}
Create Enrollment Group
public async Task CreateEnrollmentGroupAsync()
{
Console.WriteLine("\nCreating a new enrollmentGroup...");
Attestation attestation = X509Attestation.CreateFromRootCertificates(_groupIssuerCertificate);
EnrollmentGroup enrollmentGroup =
new EnrollmentGroup(
EnrollmentGroupId,
attestation);
Console.WriteLine(enrollmentGroup);
Console.WriteLine("\nAdding new enrollmentGroup...");
EnrollmentGroup enrollmentGroupResult =
await _provisioningServiceClient.CreateOrUpdateEnrollmentGroupAsync(enrollmentGroup).ConfigureAwait(false);
Console.WriteLine("\nEnrollmentGroup created with success.");
Console.WriteLine(enrollmentGroupResult);
}
Update
Take a look at the device samples. You don't need to specify the enrollment type (individual/group) when registering the device. the correlation to the defined enrollment in the portal is done using the certificate the device uses when it registers.
Update 2
See Quickstart: Control a device connected to an IoT hub (.NET) to see how to communicate with a device that was already enrolled to IoT Hub
Hope it helps!
I have a Azure device provisioning service setup entitled "myDPS" and below IoT hubs are linked.
IoTHub-Dev-Asia
IoTHub-Prod-Europe
Currently there are no enrollment list. The below c# code I am using to enroll the device
private const string RegistrationId = "TestRegID";
private const string OptionalDeviceId = "Device1";
private const ProvisioningStatus OptionalProvisioningStatus = ProvisioningStatus.Enabled;
private const string SampleTpmEndorsementKey = "***"// Key generated using TPM Simulator
static async Task SetRegistrationDataAsync()
{
Console.WriteLine("Starting SetRegistrationData");
Attestation attestation = new TpmAttestation(SampleTpmEndorsementKey);
IndividualEnrollment individualEnrollment = new
IndividualEnrollment(RegistrationId, attestation);
individualEnrollment.DeviceId = OptionalDeviceId;
individualEnrollment.ProvisioningStatus = OptionalProvisioningStatus;
Console.WriteLine("\nAdding new individualEnrollment...");
var serviceClient = ProvisioningServiceClient.CreateFromConnectionString(ServiceConnectionString);
IndividualEnrollment individualEnrollmentResult =
await serviceClient.CreateOrUpdateIndividualEnrollmentAsync(individualEnrollment).ConfigureAwait(false);
Console.WriteLine("\nIndividualEnrollment created with success.");
Console.WriteLine(individualEnrollmentResult);
}
The above code successfully enrolls the device to the DPS but status shows as unassigned
Issue#1 - Enrollment status unassigned, sometimes shows FAILED
Status: failed
Error code: 404201
Issue#2
Once above issue resolved, then I would like to have some configuration where I can specify which device should map to which IoT, so that device can automatically decide it's target IoT hubs.
Example:
Device1->IoTHub-Dev-Asia
Device2->IoTHub-Dev-Asia
Device3->IoTHub-Dev-Europe
I assume Static configuration via the enrollment list can help but not sure how to use it?
The three supported allocation policies determine how devices are assigned to an IoT hub:
Lowest latency: Devices are provisioned to an IoT hub based on the hub with the lowest latency to the device.
Evenly weighted distribution (default): Linked IoT hubs are equally likely to have devices provisioned to them. This is the default setting. If you are provisioning devices to only one IoT hub, you can keep this setting.
Static configuration via the enrollment list: Specification of the desired IoT hub in the enrollment list takes priority over the DPS-level allocation policy.
If you need to assign the device ,you should use a single call to the ProvisioningDeviceClient.RegisterAsync() API. You can refer to the sample.In the sample, you need to replace the RegistrationId with that your created before.
I'm building the app based on AzureMobileServices. But I meet the following problem.
For some reasons I need few hubs per one AzureMobileService app (it will be used by few iOS apps so there is necessary to use different APNS certificates).
I have implemented logic for send notification via necessary hub, but the device registration continue to use connection string from web.config.
Is it any way to handle device registration process to make device registrated for necessary hub?
multi-tenancy is supported through Notification Hubs directly, so client will need to connect to various hubs directly when operations are performed. If the device registration is using the same connection string, it is likely that you are using Mobile Services' (Mobile Apps) push client. Do you mind checking?
The get started iOS tutorial has a snippet that could help out:
SBNotificationHub* hub = [[SBNotificationHub alloc] initWithConnectionString:
#"<connection string>" notificationHubPath:#"mynh"];
[hub registerNativeWithDeviceToken:deviceToken tags:nil completion:^(NSError* error) {
if (error != nil) {
NSLog(#"Error registering for notifications: %#", error);
}
}];