How to determine data flow between different modules on IoT Edge without having deployment manifest file - azure

Suppose I have got 5 modules installed on my IoT Edge. Is there any easy way to understand how data is flowing between these modules; i.e. data of which module is piped to which other module.
Any way to debug find this information ?

Sander van de Velde has written a nice blog post about visualizing IotEdge routes.
In that blog post he describes that the routes are part of the desired device properties of the IoT Edge EdgeHub module.
You can read them like this:
var connectionString = "HostName=[iothub].azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=[key]";
var registryManager = RegistryManager.CreateFromConnectionString(connectionString);
var twin = registryManager.GetTwinAsync("LinuxArk1123", "$edgeHub").Result;
var desired = twin.Properties.Desired;
var routes = desired["routes"];
...

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

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

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

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).

Error with multipart/form-data in express.js running on Azure

So I've got an express site running on Windows Azure. I'm currently having problems submitting forms that are marked as enctype="multipart/form-data".
The error I'm getting in the logs is: TypeError: Object # has no method 'tmpDir'
When running natively (initiated via node.exe) it works absolutely fine, its only when using the AzureEmulator or on Azure itself it fails.
Now I expect this has something to do with Azure's infrastructure, but I'm wondering whether anyone has managed to work around this?
So a multi-pronged issue here, I'll explain my findings as best as possible, please bear with me.
Connect uses node-formidable for its multipart form parsing, specifically the IncomingForm class. In the constructor of IncomingForm it sets the upload directory to be that of the parameter you pass in, or defaults to the Operating System's temp directory, defined by os.tmpDir(). However, this method is missing from the Windows implementation of node's "os" module.
After reading copious posts, threads etc, I discovered that you should be able to get around this, you need to set the uploadDir property of the bodyParser.
app.use(express.bodyParser({ uploadDir: 'path/to/dir' }));
However there is (at the time of writing) a bug in connect's implementation of multipart forms processing in that it creates an object of IncomingForm without passing any parameters into the constructor, and then setting the properties further down:
var form = new formidable.IncomingForm
, data = {}
, files = {}
, done;
Object.keys(options).forEach(function(key){
form[key] = options[key];
});
So I've forked both express & connect and updating the code to read as:
var form = new formidable.IncomingForm(options)
, data = {}
, files = {}
, done;
Object.keys(options).forEach(function(key){
form[key] = options[key];
});
You can find the forked versions here: not a shameless plug
Fix for Windows Environments (Azure web sites + node.js application).
server.js:
Make sure it does not set an upload dir or tmp dir
app.use(express.bodyParser());
packages.json:
Force node 0.10.21 or above:
"engines": { "node": "v0.10.24" }
Force express 3.4.8 or above:
"express": "3.4.8"
This should update your node to the fixed lib versions and the problem should be gone.

Resources