Azure IOT PnP Digital Twin API/SDK to retrieve Property, Command and Telemetry definitions for Device/Twin - azure

I am currently learning about Azure IOT Plug and Play and Digital Twins.
I am running the following Device Sample: Azure\IOT Plug and Play\azure-iot-samples-csharp\iot-hub\Samples\device\PnpDeviceSamples\Thermostat
and the corresponding Service Example: Azure\IOT Plug and Play\azure-iot-samples-csharp\iot-hub\Samples\service\PnpServiceSamples\Thermostat
To interact with the Thermostat: https://github.com/Azure/opendigitaltwins-dtdl/blob/master/DTDL/v2/samples/Thermostat.json
I would like to discover what Properties, Telemetry and Commands are available for a device/twin through an API/SDK based on the twin ID, However I notice that the Microsoft.Azure.Devices.Device and Microsoft.Azure.Devices.Shared.Twin classes only contain Property information and don't define Commands or Telemetry.
Microsoft.Azure.Devices.RegistryManager registryManager = _registryManager;
Microsoft.Azure.Devices.Device device = await registryManager.GetDeviceAsync(_digitalTwinId);
Microsoft.Azure.Devices.Shared.Twin twin = await _registryManager.GetTwinAsync(_digitalTwinId);
Can someone please tell me how I can get the Command and Telemetry definitions please?

To discover all the details of the device model dynamically in your application should do the following:
identify the device's model-id
resolve it to the model file from the repository
parse the model file
See documentation here:
https://learn.microsoft.com/en-us/azure/iot-pnp/concepts-model-discovery
To parse the model you can read the json directly, or use the model parser library to get a rich object model for the device model. See docs here:
https://learn.microsoft.com/en-us/azure/iot-pnp/concepts-model-parser

Related

OpenAPI Generator issue with Destination service API specification

I want to get all destinations on subaccount and instance level. In SAP API business Hub, I found the API information and "SAP Cloud SDK" tab to generate code by OpenAPI generator.
https://api.sap.com/api/SAP_CP_CF_Connectivity_Destination/overview
I downloaded the API specification and added dependencies into Cloud SDK for Java project. The code is generated successfully with some errors (unknown models)in generated api classes.
For example in DestinationsOnSubaccountLevelApi.class, model OneOfDestinationNameOnly is imported and used in method but it is not generated in model package.
I looked into API specification and found that there were two types of response entity. That is the reason why the code could not be generated properly. I can modify the API specification to make it work but it should not be the long term solution. Is there any other way to fix this issue?
Unfortunately the SAP Cloud SDK Generator for Open API services is not yet able to understand oneOf relationship that is modeled in the specification.
As an alternative, would you consider using the DestinationAccessor API for resolving single destinations?
You can also directly instantiate an ScpCfDestinationLoader, which allows for querying all destinations:
ScpCfDestinationLoader loader = new ScpCfDestinationLoader();
DestinationOptions options = DestinationOptions
.builder()
.augmentBuilder(ScpCfDestinationOptionsAugmenter.augmenter().retrievalStrategy(ScpCfDestinationRetrievalStrategy.ALWAYS_SUBSCRIBER))
.build();
Try<Iterable<ScpCfDestination>> destinations = loader.tryGetAllDestinations(options);
Similar to the default behavior of DestinationAccessor API, in the code above only the subscriber account will be considered. Other options are:
ScpCfDestinationRetrievalStrategy.ALWAYS_SUBSCRIBER
ScpCfDestinationRetrievalStrategy.ALWAYS_PROVIDER
ScpCfDestinationRetrievalStrategy.SUBSCRIBER_THEN_PROVIDER

How to automatically associate a device with a device template?

I want to automatically associate my device with its template. There is an article about this here:
https://learn.microsoft.com/en-us/azure/iot-central/core/concepts-get-connected#automatically-associate-with-a-device-template
the sample code for this is in JS and says to include iotcModelId: '< this is the URN for the capability model>'; OR '__iot:interfaces': { CapabilityModelId: <this is the URN for the capability model> }
I can see in the python device SDK documentation on keyword args available during client creation.
https://github.com/Azure/azure-iot-sdk-python/wiki/key-word-arguments-during-client-creations
But I don't see anything in those keywords about the device template. I've tried a couple of permutations on my own, but nothing seems to work as I'm registering my device using ProvisioningDeviceClient.create_from_x509_certificate.
Anyone know the correct way to include the device template in the registration?
Once you have created your ProvisioningDeviceClient you need to set the provisioning_payload property to the JSON string that contains your model-id per documentation you have linked above.
There's a tutorial and sample on Microsoft Docs that illustrates this using Python: Tutorial: Create and connect a client application to your Azure IoT Central application.

Sending C2D message to Azure IoT Edge

I know C2D is not supported in Azure IoT Edge and an option is to use Direct Method.
Is that can I use Module Client code and send message to a Module ?
I have a ModuleA which has output1 and ModuleB has a Handler input1.
I have a route as below
"ModuleAToModuleB": "FROM /messages/modules/ModuleA/outputs/output1 INTO BrokeredEndpoint(\"/modules/ModuleB/inputs/input1\")",
And I use the below code from a console app and send message to a specific module based on the connection string of the specific Module (ModuleA connection string)
string dataString = JsonConvert.SerializeObject(jData);
byte[] dataBytes = Encoding.UTF8.GetBytes(dataString);
var pipeMessage = new Message(dataBytes);
var moduleClient = ModuleClient.CreateFromConnectionString("HostName=xxx.azure-devices.net;DeviceId=xxx-01;ModuleId=ModuleA;SharedAccessKey=XXXXXXX", TransportType.Mqtt);
await moduleClient.SendEventAsync("output1", pipeMessage);
Will this code work, Will it send the Message from ModuleA to ModuleB ?
If you want to send anything frfom your laptop/pc in a console app to your IoT Edge device, you will need to use direct methods, like you mentioned in your question. To do that, you can use the Service SDK and use the following method:
InvokeDeviceMethodAsync(string deviceId, string moduleId, CloudToDeviceMethod cloudToDeviceMethod);
In your sample, you suggested using the ModuleClient to send a message to your module. This will not work, ModuleClient is designed to be used only in the Azure IoT Edge runtime, and the method you are using (ModuleClient.CreateFromConnectionString), is one that the runtime will use to set up a connection, using the environment variables available on the device.
With the Service SDK, you can send a direct method to your Module A, and nothing is stopping you to forward the payload of that method into Module B. You already have set up your route correctly.
You need to call function like InvokeMethodAsync which is direct method from moduleA to moduelB can be called. In the example you showed it seems you are calling sendEventAsync which might not work. Example is here in C#.
Also please go through this link which also suggests another method for module to module communication.
In addition to using direct methods, it's also possible for two
modules to communicate directly with each other, bypassing the Edge
Hub. The runtime, via Docker's networking capabilities, manages the
DNS entries for each module (container). This allows one module to
resolve the IP address of another module by its name.
For an example of this in action, you can follow the SQL tutorial
here:
https://learn.microsoft.com/en-us/azure/iot-edge/tutorial-store-data-sql-server.
This tutorial uses a module to read data out of the Edge Hub and write
it into another module hosting SQLServer using the SQLServer client
SDK. This interaction with SQLServer does not use the Edge Hub for
communicating

GetTwinAsync returns a device with null properties

I'm trying to read the twin of my device from the registry manager. This is my code:
DeviceClient client =
DeviceClient.CreateFromConnectionString(DeviceConnectionString,
TransportType.Mqtt);
Twin deviceTwin = await deviceClient.GetTwinAsync();
Console.WriteLine(deviceTwin.ToJson());
However, the Json I'm getting is the following.
{"deviceId":null,"etag":null,"version":null,"properties":{"desired":{"$version":1},"reported":{"$version":1}}}
I reproduced your issue.
For this problem, you can open an issue on azure-iot-sdk-csharp repository.
For workarounds, you can either use REST API like this:
Or use Azure IoT Service SDK like this:
using Microsoft.Azure.Devices;
...
var client = RegistryManager.CreateFromConnectionString(IoTHubConnectionString);
var twinData = await client.GetTwinAsync(deviceId);
Console.WriteLine(twinData.ToJson());
This is not an issue and/or workaround. Documentation states:
Retrieve the device twin properties for the current device. For the complete device twin object, use Microsoft.Azure.Devices.RegistryManager.GetTwinAsync(string deviceId).

What is metadata? How do I create a metadata and how do I associate it to a Cloud target using Vuforia?

I modified sample CloudRecog code for my own code. I created cloud database and get AccessKeys then copied this keys to CloudReco.cpp file. What should i use for metadata. I didn't understand this. Then when i was reading sample code i saw this line: private static final String mServerURL = "https://ar.qualcomm.at/samples/cloudreco/json/". How to get my metaData url?
The Vuforia Cloud Recognition Service enables new types of applications in retail and publishing. An application using Cloud Recognition will be able to query a Cloud Database with camera images (actual recognition happens in the cloud), and then handle the matching results returned from the cloud to perform local detection and tracking.
Also, every Cloud Image Target can optionally have an associated Metadata; a target metadata is essentially nothing else than a custom user-defined blob of data that can be associated to a target and filled with custom information, as long as the data size does not exeed the allowed limits (up to 1MB per target).
Therefore, you can use the metadata as a way to store additional content that relates to a specific target, that your application will be able to process using some custom logic.
For example, your application may use the metadata to store:
a simple text message that you want your app to display on the screen of your device when the target is detected, for example:
“Hello, I am your cloud image target XYZ, you have detected me :-) !”
a simple URL string (for instance “http://my_server/my_3d_models/my_model_01.obj”) pointing to a custom network location where you have stored some other content, like a 3D model, a video, an image, or any other custom data, so that for each different image target, your application may use such URL to download the specific content;
more in general, some custom string that your application is able to process and use to perform specific actions
a full 3D model (not just the URL pointing to a model on a server, but the model itself), for example the metadata itself could embed an .OBJ 3D model, provided that the size does not exceed the allowed limits (up to 1MB)
and more ...
How do I create/store metadata for a Cloud target ?
Metadata can be uploaded together with an image target at the time you create the target itself in your Cloud Database; or you can also update the metadata of an existing target, at a later time; in either case, you can use the online TargetManager, as explained here:
https://developer.vuforia.com/resources/dev-guide/managing-targets-cloud-database-using-target-manager
or you can proceed programmatically using the VWS API, as explained here:
https://developer.vuforia.com/resources/dev-guide/managing-targets-cloud-database-using-developer-api
How can I get the metadata of a Cloud target when it is recognized ?
The Vuforia SDK offers a dedicated API to retrieve the metadata of a target in your mobile application. When a Cloud target is detected (recognized), a new TargetSearchResult is reported to the application, and the metadata can be obtained using one of these methods:
Vuforia Native SDK - C++ API: TargetSearchResult::getMetaData() - const char*
Vuforia Native SDK - Java API: TargetSearchResult.getMetaData() - String
Vuforia Unity Extension - C# API: TargetSearchResult.Metadata - string
See also the API reference pages:
https://developer.vuforia.com/resources/api/classcom_1_1qualcomm_1_1vuforia_1_1_target_search_result
https://developer.vuforia.com/resources/api/unity/struct_target_finder_1_1_target_search_result
Sample code:
For a reference sample code in native Android, see the code in the Books.java in the "Books-2-x-y" sample project.
For a reference sample code in native iOS, see the code in the BooksEAGLView.mm file in the "Books-2-x-y" sample project.
For a reference sample code in Unity, see the CloudRecoEventHandler.cs script (attached to theCloudRecognition prefab) in the Books sample; in particular, the OnNewSearchResult method shows how to get a targetSearchResult object (from which you can then get the metadata, as shown in the example code).
EDIT: this is in response to the first part of your question,: "What should i use for metadata" (not the second part about how to find the URL)
Based on their documentation (https://developer.vuforia.com/resources/dev-guide/cloud-targets):
The metadata is passed to the application whenever the Cloud Reco
target is recognized. It is up to the developer to determine the
content of this metadata – Vuforia treats it as a blob and just passes
it along to the application. The maximum size of the uploadable
metadata is 150kByte.
I added some debugging in their CloudRecognition app and saw that the payload (presumably the meta-data) they return when "recognizing" an image is:
{
"thumburl": "https://developer.vuforia.com/samples/cloudreco/thumbs/01_thumbnail.png",
"author": "Karina Borland",
"your price": "43.15",
"title": "Cloud Recognition in Vuforia",
"average rating": "4",
"# of ratings": "41",
"targetid": "a47d2ea6b762459bb0aed1ae9dbbe405",
"bookurl": "https://developer.vuforia.com/samples/cloudreco/book1.php",
"list price": "43.99"
}
The MetaData, uploaded along with your image-target in the CloudReco database, is a .txt-file, containing whatever you want.
What pherris linked, as payload from the sample-application, is in fact the contents of a .json-file that the given image-target's metadata links to.
In the sample application, the structure is as follows:
The application activates the camera and recognizes an image-target
The application then requests that specific image-target's metadata
In this case, the metadata in question is a .txt-file with the following content:
http://www.link-to-a-specific-json-file.com/randomname.json
The application then requests the contents of that specific .json-file
The specific .json-file looks as the copy-pasted text-data that pherris linked
The application uses the text-data from the .json-file to fill out the actual content of the sample application

Resources