How come a call to Twin.DeviceId is null after provisioning is successful in IoT Hub using DPS? - azure-iot-hub

I have the following code:
DeviceRegistrationResult dpsRegistrationWithEnrollmentGroupResult = await ProvisionDeviceViaEnrollmentGroupAsync(parameters, devicePrimaryKey, deviceSecondaryKey, cancellationToken);
// Create Device Client
var authMethodWithEnrollmentGroup = new DeviceAuthenticationWithRegistrySymmetricKey(dpsRegistrationWithEnrollmentGroupResult.DeviceId, devicePrimaryKey);
var options = new ClientOptions
{
ModelId = modelId,
};
DeviceClient deviceClient = DeviceClient.Create(hostname, authenticationMethod, TransportType.Mqtt, options);
var twin = await deviceClient .GetTwinAsync();
DeviceId = twin.DeviceId;
The device is provisioned but the DeviceId is null.
What do I need to do to get the actual DeviceId?

Twin.DeviceId is null on the device IoT hub SDK because it is a shared type (lives in Microsoft.Azure.Devices.Shared.dll) that is used by the IoT hub service SDK and the provisioning service SDK as well. The Twin class has a superset of all the available properties in all 3 scenarios.
The device IoT hub API only has access to the desired and reported properties of a twin.
If you want to know the device Id, it should have been provided in the DPS registration call in DeviceRegistrationResult.DeviceId.
In the v2 preview, the shared assembly is removed because this is a bad experience. Each SDK package has its own types that only contain the properties and functionality relevant to that package.
The client method has changed from GetTwinAsync(...) to GetTwinPropertiesAsync(...) and the return type is now called TwinProperties with only two child properties: Desired and Reported.
If you are up for it, please give the preview a try and let us know how it goes for you. The migration guide can help you with breaking changes.

Related

Can Azure.Identity be used with WindowsAzure.Storage?

Is it safe (from a protocol/compatibiltiy point of view) to retrieve an access token using Azure.Identity and use it with WindowsAzure.Storage?
I am working on an application which use WindowsAzure.Storage to communicate with Azure Storage (blobs+queues). Currently the application use Account Name/AccessKey to authenticate.
I want to migrate from using AccountName/Access Keys to use Managed Service Identity, Interactive Browser Login or Certificate (depending on where the application is running). Main reason bing simplifying credential rotation.
I think the (deprecated) library Microsoft.Azure.Services.AppAuthentication could be used to accomplish this, but I wonder if it's safe to use Azure.Identity to perform the retrieval of the authentication token instead. Microsoft recommends to use Azure.Identity with new applications, but this library seems to be primarily focused on the new Azure.* client SDK:s (as opposed to WindowsAzure.Storage which I am using).
The below code works fine in a simple test, but I don't know if there would be any issues doing this:
var resourceId = "https://storage.azure.com/";
// Request access token via interactive browser
var browserCredential = new InteractiveBrowserCredential();
var accessToken = await browserCredential.GetTokenAsync(
new TokenRequestContext(scopes: new string[] { resourceId + "/.default" }) { }
);
// Use the access token to access Azure Storage
var tokenCredential = new TokenCredential(accessToken.Token);
var storageCredentials = new StorageCredentials(tokenCredential);
var account = new CloudStorageAccount(storageCredentials,"<mystorageaccount>","core.windows.net", true);
var queueClient = account.CreateCloudQueueClient();
var queue = queueClient.GetQueueReference("myqueue");
I know WindowsAzure.Storage is also deprecated and applications should upgrade to Azure.Storage, but it's not something I have to do a bit furher down the road (large application and the above has higher prio).

Agora - Is there anyway I can know how many users currently joined in channel?

I would like to know the total number of users currently in the same channel. This is a crucial information I believe.
Scenario
Caller initiates call by joining the channel -> A push goes to receiver -> Caller decides to leave call/channel before receiver joins. When the receiver reacts to push and joins the channel, sees no one in that channel. If I had a way to tell the receiver that there's no one in that channel at the moment then the receiver could be notified with dialog or some sort.
Note: without using the RTM library. Can this be done with RTC only?
You can use the RESTful API to get a list of users in the channel: https://docs.agora.io/en/Agora%20Platform/dashboard_restful_communication?platform=All%20Platforms#gets-the-user-list-in-a-channel-get
You can also implement the Agora RTM SDK together with Agora RTC SDK and implement the logic for users to join the same channel as using Agora RTC SDK. And call getMembers method to get a list of users in the RTM channel.
Here is the API document for getMembers method: https://docs.agora.io/en/Real-time-Messaging/API%20Reference/RTM_java/classio_1_1agora_1_1rtm_1_1_rtm_channel.html#a567aca5f866cf71c3b679ae09b4bf626
Here is a quick start guide for the RTM SDK: https://docs.agora.io/en/Real-time-Messaging/messaging_android?platform=Android
While using agora rtm for messaging,We can use getMembers() functionality which is provided by agora to get the active people in a channel in agora.I am defining it using javascript below for reference.
In javascript,Define a function GetMembers()-->
name='The channel Name of your channel';
function GetMembers(name)
{
rtm.channels[name].channel.getMembers().then((memberNames)=>{
/* memberNames contains an array of the names of the members*/
})
}
Call the GetMembers() function wherever it is required to get the names of the active members.
You can get the list of joined members using getMembers method of agora rtm. Remember it also gives your own id if you are logged in. This method return array.
GetChannelMembersList()
{
channel.getMembers().then(async (memberNames)=>{
console.log(memberNames, 'memberNames');
for (let index = 0; index < memberNames.length; index++) {
const user = await rtm.client.getUserAttributes(memberNames[index].toString());
console.log(user, 'user'); // To find more details of joined user
}
})
}

How to include information about iotEdge capability in device created event in IoT Hub?

I am wondering if it is possible to include information if device is an edge device in Microsoft.Devices.DeviceCreated event data? I receive those events for both type of devices but I am not able to distinguish them and say oh yeah this one is an edge device.
I can see that device twin which I receive is a little bit different than the one I can see in portal. In portal twin contains information about capabilities which say iotEdge: true for edge and false for directly connected devices.
Basically, there are two ways to handle this issue:
The subscriber event handler (EventGridTrigger function) will pull up the full device twins info like you can see on the portal.
Using the Bulk Create or Update REST API call for creating devices with an additional information in the tags. I do recommend this way and based on my answer here, the following is an example of the payload POST:
[
{
"id":"TD_0001",
"importMode":"create",
"status":"enabled",
"tags":{
"capabilities":{
"iotEdge":false
}
}
},
{
"id":"TD_0002",
"importMode":"create",
"status":"enabled",
"tags":{
"capabilities":{
"iotEdge":true
}
},
"capabilities":{
"iotEdge":true
}
}
]
As you can see, the capabilities property has been added in the tags. Basically, you can initialized any device twins properties included a reported property.
The Azure IoT Hub Notification to the AEG is almost immediately and the following screen snippet shows an example of the event message:
and the azure portal screen:

IoT Hub route query does not match on message body

I'm facing some issues with filtering on message body in the Azure IoT Hub. Is this still not supported? The tests go through, but when I try real messages from the device everything is hitting the fallback and not the intended route.ยจ
In other words:
//this is working when adding property to message in the device code
temperature > 30
//this is not working when message contains json object without using any properties
$body.temperature > 30
Do we still need to use the message properties?
This feature (such as a filtering on the $body) requires setup the following message system properties:
message.ContentType = "application/json";
message.ContentEncoding = "utf-8";
See more details here.

DeviceClient.GetTwinAsync() returns null?

I've created an IotHub, added a device, created a UWP app which uses the DeviceClient to successfully connect to the hub.
I can send telemetry as expected, and see the results in the Device Explorer.
However, when I try to fetch the device twin, I'm returned a null.
var deviceClient = DeviceClient.CreateFromConnectionString(deviceConnectionString, TransportType.Amqp);
var twin = await deviceClient.GetTwinAsync(); // <<<< returns null
Are there any common scenarios that might cause this? Such as creating the IoTHub & device before Twin's were released. Or, not having set any desired properties before hand? Or, using the wrong shared access key? (etc.)
-John
SOLUTION: Twin capabilities requires the MQTT protocol, I was using AMQP.
I'm sure there is a mention of this buried somewhere, but after spinning on this for hours I can safely say it wasn't obvious.
On a more practical note: it would probably be helpful to throw an exception in the GetTwinAsync() method, if it is called on a connection that is not capable of supporting Twin.
Hopefully this post will help the next person.
-John