How do I connect Minew BLE Gateway with Azure Iot Central? - azure

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:

Related

Registering a device on Azure IoT-hub programatically using mqtt

Is there anyway to register the new device onto the azure iot-hub programmatically using the self/CA created certificates?
For example say, I want to register my raspberry pi on to my newly created IOT-HUB from the same rasp pi. I know we can do it using the AZ Cli. What I am looking for is there a way to do it programmatically, using MQTT/REST?.
Thanks in advance.
Regards,
Pradeep
You can make use of the device provisioning service - DPS. The DPS is another service whose purpose is to identify your device, and in case that the device identification is recognized by the DPS, the DPS will create an identity in your IoT Hub.
You set the DPS in a way that you create either individual enrollment(for individual device onboarding) or a group enrollment(for a group of the devices, typically if you use certificates or shared access key authentication type).
Enrollments typically contain an identification type that the device should present, and IoT Hub to which the device with the presented identification should be assigned.
The typical flow is that the device reaches out to the DPS with some public identification(certificate chain, TPM registration id, or SAS key). Then internally, the DPS can challenge the device(proof-of-possesion in case of CA certificates), and if the device successfully solves the challenge, that means that the device contains a specific secret(private key in case of CA certs) that identifies that device, so the DPS will create the device identity to the assigned hub in that specific enrollment. This process is called attestation.
As a result, on the device side, you receive at least the IoT Hub endpoint, and the device Id which you use to communicate with the IoT Hub.
Below are the code snippets of how you can do this with CA certificates and C#:
var certificate = new X509Certificate2(leafCertificatePath, leafCertificatePassword);
using (var security = new SecurityProviderX509Certificate(certificate))
using (var transport = new ProvisioningTransportHandlerMqtt(TransportFallbackType.TcpOnly))
{
ProvisioningDeviceClient provClient =
ProvisioningDeviceClient.Create(GlobalDeviceEndpoint, dpsScope, security, transport);
var deviceAuthentication = await GetDeviceRegistrationResultAsync(provClient, security);
var auth = new DeviceAuthenticationWithX509Certificate(deviceAuthentication.DeviceId, security.GetAuthenticationCertificate());
var deviceClient = DeviceClient.Create(hostname: deviceAuthentication.AssignedHub,
authenticationMethod: auth,
transportType: TransportType.Mqtt);
if (deviceClient == null)
{
Console.WriteLine("Failed to create DeviceClient!");
}
else
{
SendEvents(deviceClient, MESSAGE_COUNT).Wait();
}
}
Method for getting the device registration result from the DPS:
static async Task<DeviceRegistrationResult> GetDeviceRegistrationResultAsync(ProvisioningDeviceClient provClient, SecurityProviderX509 security)
{
DeviceRegistrationResult result = await provClient.RegisterAsync().ConfigureAwait(false);
if (result.Status != ProvisioningRegistrationStatusType.Assigned)
{
throw new Exception("Device not assigned");
}
return result;
}
Official example from MSFT you can find here
Here is how you can create and verify certificates with IoT Hub and DPS.
Just to clarify, 'registering' a device in IoTHub/DPS is kind of an overloaded term, and may mean different things to different people. If you are using self-signed certs, it's a two step process.
First, you need to enroll the device in DPS, which lets DPS know that sometime in the future, a device may show up with that name and that certificate. That is generally a backend process typically NOT done from the device itself. Technically, there's nothing stopping you from calling the REST APIs to do so from the device, but since you need some pretty powerful credentials to do so, it's not recommended to have them on your device. This cannot be done over MQTT. You can avoid having to enroll every individual device by uploading, verifying, and using a CA-signed cert, though.
Once that's done, the device can now/later register itself, which is the act of actually having DPS create the device registration record in IoT Hub. The device "phones home" to DPS, authenticates itself using the cert you provided in the enrollment, and registers itself, getting the IoT Hub connection information it needs back from DPS. That process can be done over MQTT and you can find step by step the process on my blog -> http://busbyland.com/azure-device-provisioning-server-over-mqtt-using-x509-certificates
Provisioning a device in IoTHub from the device itself is not recommended, as it will then require IoTHub registry write permission and use of service SDK.
The recommended approach is to use Device Provisioning Service, you can create individual or group enrollment with X509 and it will automatically provision the device in target IoTHub.
The device just needs
mechanism to attest its identity
DPS global endpoint
ID Scope to identify your instance of DPS.
Check this - https://learn.microsoft.com/en-us/azure/iot-dps/concepts-x509-attestation

Azure IoT Central Connect Real Device. (Connection String problems)

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

Xamarin iOS Push notifications do not work in Production but work fine in Development

I have a Web API hosted in Azure. The web API features a POST method and when using Postman to post with a string body message to the web API url, the message is sent to the mobile devices perfectly in Development. Here is the code for it:
[Authorize]
[HttpPost, Route("send")]
public async Task<NotificationOutcome> Post([FromBody]string message)
{
string hubName = "hubname";
string hubNameDefaultShared = "endpointAddress";
NotificationHubClient hub = NotificationHubClient
.CreateClientFromConnectionString(hubNameDefaultShared, hubName, enableTestSend: true);
string installationId = string.Empty;
var templateParams = new Dictionary<string, string>
{
["messageParam"] = message
};
NotificationOutcome result = null;
if (string.IsNullOrWhiteSpace(installationId))
{
result = await hub.SendTemplateNotificationAsync(templateParams).ConfigureAwait(false);
}
else
{
result = await hub.SendTemplateNotificationAsync(templateParams, "$InstallationId:{" + installationId + "}").ConfigureAwait(false);
}
return result;
}
When I switch to Production and dowload the app from the store, there are no push notifications received when using Postman to post to the Web API above:
The steps I already completed:
App Id for both the mobile app and the Notification Service Extension.
Enabled Push Notifications on both and created Development SSL Push Notif certificate and Production Push Notif Certificate on the Apple Developer Website for both.
In my Keychain, I right clicked the "Apple Push Services: MyMobileApp" (Production) and exported the p12.
Upload the p12 certificate to Azure Notification Hub under APNS, and set the Notification Hub switch from Sandbox to Production.
Created Provisioning profiles for both Development and Productions for both the mobile app and the Notification Service Extension.
Edited the Entitlement.plist of both the Mobile app and the Notification Extension Service and set "aps-environment" to "production"
In info.plist selected the production certificate and production provisioning for each.
Created the ipa file and uploaded to the store.
Is there anything I have to do to the web API to set it to production regarding the notification hub? Are these all the steps to set the Notification Hub to production with the p12 certificate or have I missed something?
I think I figured it out. What the problem seems to be is that I used my phone for testing in development mode. My phone has registered with a development device token. When downloading the app form the store in production mode, that token is no longer valid and my phone does not receive the notification. Somehow my device stayed associated with a development token even after erasing app that was installed with Visual Studio and downloading the app from the store.
I found this on the Azure documentation website link here:
https://learn.microsoft.com/en-us/azure/notification-hubs/notification-hubs-push-notification-faq
"If your hub was originally configured with an Apple sandbox certificate and then was reconfigured to use an Apple production certificate, the original device tokens are invalid. Invalid tokens cause pushes to fail. Separate your production and test environments, and use different hubs for different environments."
So it is best practice to have two notifications hubs, one for development and another for production.

How do I map IoTHub in Device Provisioning Service enrollment list? - Enrollment status "unassigned"

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.

Azure Mobile Services PushNotifications Device registration

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);
}
}];

Resources