{"id":19244395,"url":"https://github.com/nanoframework/nanoframework.azure.devices","last_synced_at":"2025-04-21T09:33:37.919Z","repository":{"id":37978532,"uuid":"373883803","full_name":"nanoframework/nanoFramework.Azure.Devices","owner":"nanoframework","description":"📦 .NET nanoFramework Azure IoT Devices SDK","archived":false,"fork":false,"pushed_at":"2025-04-02T12:44:33.000Z","size":741,"stargazers_count":16,"open_issues_count":0,"forks_count":11,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-19T18:24:03.683Z","etag":null,"topics":["azure","csharp","dotnet","hacktoberfest","iot","nanoframework","sdk"],"latest_commit_sha":null,"homepage":"https://www.nanoframework.net","language":"C#","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nanoframework.png","metadata":{"funding":{"open_collective":"nanoframework","github":"nanoframework"},"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-06-04T15:24:40.000Z","updated_at":"2025-04-09T10:18:42.000Z","dependencies_parsed_at":"2023-10-16T03:29:10.287Z","dependency_job_id":"466f1255-b143-4a8b-b5f6-9e120fe97867","html_url":"https://github.com/nanoframework/nanoFramework.Azure.Devices","commit_stats":{"total_commits":519,"total_committers":12,"mean_commits":43.25,"dds":"0.36416184971098264","last_synced_commit":"2bb3d8393e52937ac18fd96b1a518bfd8a4b18f6"},"previous_names":[],"tags_count":238,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nanoframework%2FnanoFramework.Azure.Devices","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nanoframework%2FnanoFramework.Azure.Devices/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nanoframework%2FnanoFramework.Azure.Devices/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nanoframework%2FnanoFramework.Azure.Devices/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nanoframework","download_url":"https://codeload.github.com/nanoframework/nanoFramework.Azure.Devices/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250032504,"owners_count":21363850,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["azure","csharp","dotnet","hacktoberfest","iot","nanoframework","sdk"],"created_at":"2024-11-09T17:23:14.672Z","updated_at":"2025-04-21T09:33:37.906Z","avatar_url":"https://github.com/nanoframework.png","language":"C#","funding_links":["https://opencollective.com/nanoframework","https://github.com/sponsors/nanoframework"],"categories":[],"sub_categories":[],"readme":"[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=nanoframework_Azure.Devices\u0026metric=alert_status)](https://sonarcloud.io/dashboard?id=nanoframework_Azure.Devices) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=nanoframework_Azure.Devices\u0026metric=reliability_rating)](https://sonarcloud.io/dashboard?id=nanoframework_Azure.Devices) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![NuGet](https://img.shields.io/nuget/dt/nanoFramework.Azure.Devices.Client.svg?label=NuGet\u0026style=flat\u0026logo=nuget)](https://www.nuget.org/packages/nanoFramework.Azure.Devices.Client/) [![NuGet](https://img.shields.io/nuget/dt/nanoFramework.Azure.Devices.Client.FullyManaged.svg?label=NuGet\u0026style=flat\u0026logo=nuget)](https://www.nuget.org/packages/nanoFramework.Azure.Devices.Client.FullyManaged/) [![#yourfirstpr](https://img.shields.io/badge/first--timers--only-friendly-blue.svg)](https://github.com/nanoframework/Home/blob/main/CONTRIBUTING.md) [![Discord](https://img.shields.io/discord/478725473862549535.svg?logo=discord\u0026logoColor=white\u0026label=Discord\u0026color=7289DA)](https://discord.gg/gCyBu8T)\n\n![nanoFramework logo](https://raw.githubusercontent.com/nanoframework/Home/main/resources/logo/nanoFramework-repo-logo.png)\n\n-----\n\n# Welcome to the .NET **nanoFramework** Azure.Devices.Client Library repository\n\n## Build status\n\n| Component | Build Status | NuGet Package |\n|:-|---|---|\n| nanoFramework.Azure.Devices.Client | [![Build Status](https://dev.azure.com/nanoframework/Azure.Devices/_apis/build/status/nanoFramework.Azure.Devices?repoName=nanoframework%2FnanoFramework.Azure.Devices\u0026branchName=main)](https://dev.azure.com/nanoframework/Azure.Devices/_build/latest?definitionId=75\u0026repoName=nanoframework%2FnanoFramework.Azure.Devices\u0026branchName=main)| [![NuGet](https://img.shields.io/nuget/v/nanoFramework.Azure.Devices.Client.svg?label=NuGet\u0026style=flat\u0026logo=nuget)](https://www.nuget.org/packages/nanoFramework.Azure.Devices.Client/) |\n| nanoFramework.Azure.Devices.Client.FullyManaged | [![Build Status](https://dev.azure.com/nanoframework/Azure.Devices/_apis/build/status/nanoFramework.Azure.Devices?repoName=nanoframework%2FnanoFramework.Azure.Devices\u0026branchName=main)](https://dev.azure.com/nanoframework/Azure.Devices/_build/latest?definitionId=75\u0026repoName=nanoframework%2FnanoFramework.Azure.Devices\u0026branchName=main)| [![NuGet](https://img.shields.io/nuget/v/nanoFramework.Azure.Devices.Client.FullyManaged.svg?label=NuGet\u0026style=flat\u0026logo=nuget)](https://www.nuget.org/packages/nanoFramework.Azure.Devices.Client.FullyManaged/) |\n\n## See it in action\n\nYou can watch this video from the Microsoft [IoT Show](https://aka.ms/iotshow) featuring the Azure SDK and a real life example with .NET nanoFramework:\n\n[![IoT Show](https://img.youtube.com/vi/TLYqRdmmj5k/0.jpg)](https://youtu.be/TLYqRdmmj5k)\n\n## nanoFramework.Azure.Devices.Client vs nanoFramework.Azure.Devices.Client.FullyManaged\n\nThe `nanoFramework.Azure.Devices.Client.FullyManaged` nuget has been build to be **independent of the native hardware** you are running on. So it will not use the X509Certificate but rather a byte array. It will not use the `nanoFramework.M2Mqtt` library but rather an abstraction called `nanoFramework.M2Mqtt.Core` using an interface.\n\nThe main scenario this does allow is to bring your own MQTT broker and run on devices without System.Net so devices without any native networking. This does allow to connect through a modem implementing an MQTT client. You can reuse almost fully the same code you're using for native network enabled devices and the ones using a modem.\n\n## Usage\n\n**Important**: You **must** be connected to a network with a valid IP address **and** a valid date. Please check the examples with the Network Helpers on how to help you making sure you have both.\n\nThis Azure IoT Hub SDK is using MQTT. So you need to ensure you can connect to port 8883 using TLS protocol. If you are connected to an enterprise network, this may be blocked. In most cases, this is not an issue.\n\nThe namespaces, the name of the classes and the methods try to get close to the .NET C# Azure IoT SDK. This should allow easier portability of the code between the full .Net framework and nanoFramework environments.\n\n### Certificate\n\nYou have 2 options to provide the right Azure IoT TLS certificate:\n\n- Parse it into the constructor\n- Store it into the device\n\nThe [AzureCertificates](AzureCertificates) contains, for your convenience, the root certificate used to connect to Azure IoT. The current one,  a Baltimore Root CA is the one to use up to June 2022. Starting from June 2022, the Digicert Global Root 2 is the one to use. For more information, please read the following [blog](https://techcommunity.microsoft.com/t5/internet-of-things/azure-iot-tls-critical-changes-are-almost-here-and-why-you/ba-p/2393169).\n\n#### Through the constructor\n\nAs of October 15th, 2023, you will have to embed the new Azure [DigiCert Global Root G2 certificate](https://www.digicert.com/kb/digicert-root-certificates.htm) into your code to properly communicate with IoT hub services:\n\n```csharp\nconst string AzureRootCA = @\"-----BEGIN CERTIFICATE-----\nMIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\nMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT\nMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\nb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG\n9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI\n2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx\n1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ\nq2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz\ntCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ\nvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP\nBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV\n5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY\n1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4\nNeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG\nFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91\n8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe\npLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl\nMrY=\n-----END CERTIFICATE-----\n\";\nDeviceClient azureIoT = new DeviceClient(IotBrokerAddress, DeviceID, SasKey, azureCert: new X509Certificate(AzureRootCA));\n```\n\n\u003e Note: when using the FullyManaged library, you will have to pass a `byte[]` rather than a `X509Certificate`. The broker you'll use may or may not support PEM or DER certificate. Please make sure you will use the proper one by checking the vendor documentation. A PEM certificate is a base64 encoded version of the DER certificate, usually found with the `.crt` extension.\n\nYou can place your binary certificate in the program resources as well and just get the certificate from it:\n\n```csharp\nX509Certificate azureRootCACert = new X509Certificate(Resources.GetBytes(Resources.BinaryResources.AzureCAcertificate));\nDeviceClient azureIoT = new DeviceClient(IotBrokerAddress, DeviceID, SasKey, azureCert: azureRootCACert);\n```\n\nNote: when the certificate expires, you will have to fully reflash the device with the new certificate.\n\n#### Storing the certificate on the device\n\nYou can store the certificate on the device flash and not in the code, so if you have to change the certificate, you'll just have to clean the current store and upload the new one. Edit the network properties:\n\n[edit device network](https://raw.githubusercontent.com/yourusername/yourrepository/main/path/to/device-network.jpg)\n\nNavigate to the `General` tab:\n\n![device network certificate](https://raw.githubusercontent.com/yourusername/yourrepository/main/path/to/device-network-certificate.jpg)\n\nBrowse to choose your certificate, it can be in a binary (crt, der) or string form (pem, txt) and select ok. The certificate to connect will be selected automatically during the connection.\n\n### Creating a DeviceClient\n\nYou can connect to Azure IoT Hub using either a symmetric Key or a certificate. The following example shows how to use a symmetric key:\n\n```csharp\nconst string DeviceID = \"nanoEdgeTwin\";\nconst string IotBrokerAddress = \"youriothub.azure-devices.net\";\nconst string SasKey = \"yoursaskey\";\nDeviceClient azureIoT = new DeviceClient(IotBrokerAddress, DeviceID, SasKey);\n```\n\nNote: please see the previous section to understand how to better parse the certificate for your usage. The example shows the certificate uploaded into the device and not in the code.\n\n### Azure IoT Plug\u0026Play\n\nAzure IoT Plug\u0026Play is supported as well. You'll need to provide a model ID when creating the DeviceClient:\n\n```csharp\nDeviceClient azureIoT = new DeviceClient(IotBrokerAddress, DeviceID, SasKey, modelID:\"dtmi:com:example:Thermostat;1\");\n```\n\nNote: the model ID has to be passed at the creation of the DeviceClient, it is not possible to pass it later on.\n\n#### Reporting properties\n\nReporting Plug \u0026 Play properties is supported. He is a comprehensive example and how you can check if you have received one property that you're interested in:\n\n```csharp\nconst string TargetTemerature = \"targetTemperature\";\nDeviceClient azureIoT = new DeviceClient(Secrets.IotHub, Secrets.DeviceName, Secrets.SasKey, azureCert: new X509Certificate(Resource.GetBytes(Resource.BinaryResources.AzureRoot)), modelId: \"dtmi:com:example:Thermostat;1\");\nazureIoT.TwinUpdated += AzureTwinUpdated;\nazureIoT.Open();\n\nvoid AzureTwinUpdated(object sender, TwinUpdateEventArgs e)\n{\n    if (e.Twin.Contains(TargetTemerature))\n    {\n        // We got an update for the target temperature\n        var target = e.Twin[TargetTemerature];\n        Debug.WriteLine($\"Target temperature updated: {target}\");\n        PropertyAcknowledge targetReport = new() { Version = (int)e.Twin.Version, Status = PropertyStatus.Completed, Description = \"All perfect\", Value = target };\n        TwinCollection twin = new TwinCollection();\n        twin.Add(TargetTemerature, targetReport.BuildAcknowledge());\n        azureIoT.UpdateReportedProperties(twin);\n    }\n}\n```\n\nIn this example, the property we are interested in to receive is called `targetTemperature`. To receive its update, we are subscribing to the twin update. And we can get the value thu the `e.Twin[TargetTemerature]` once we've checked that the property exist.\n\nThe patter to publish a writable property is then quite simple. it's about building a `PropertyAcknowledge`, creating a TwinCollection, adding it to it with the property name, here our `targetTemperature`. You can add more properties to report of course. Note that what you add to the TwinCollection is not directly the object but `BuildAcknowledge()`. One done, just ask the library to update the twin through the `UpdateReportedProperties` method.\n\n#### Receiving commands\n\nAn IoT Plug \u0026 Play command is a method callback. See further in this document how you can use them. In our case, the method is called `getMaxMinReport`. The name of the method in C# **must** be the exact same as the name from the DTDL file.\n\n```csharp\nDeviceClient azureIoT = new DeviceClient(Secrets.IotHub, Secrets.DeviceName, Secrets.SasKey, azureCert: new X509Certificate(Resource.GetBytes(Resource.BinaryResources.AzureRoot)), modelId: \"dtmi:com:example:Thermostat;1\");\nazureIoT.AddMethodCallback(getMaxMinReport);\nazureIoT.Open();\n\nstring getMaxMinReport(int rid, string payload)\n{\n    TemperatureReporting reporting = new() { avgTemp = 20, maxTemp = 42, minTemp = 12.34, startTime = DateTime.UtcNow.AddDays(-10), endTime = DateTime.UtcNow };\n    return JsonConvert.SerializeObject(reporting);\n}\n```\n\nIn this example, the expected result is an object. Just populate the object and serialize it as a json as the command expect and return it. If any parameter to this command, it will be in the payload.\n\n### Getting and updating Twin\n\nYou can request your Azure IoT Twin simply by calling the `GetTwin` function.\n\n```csharp\nvar twin = azureIoT.GetTwin(new CancellationTokenSource(20000).Token);\nif (twin == null)\n{\n    Debug.WriteLine($\"Can't get the twins\");\n    azureIoT.Close();\n    return;\n}\n\nDebug.WriteLine($\"Twin DeviceID: {twin.DeviceId}, #desired: {twin.Properties.Desired.Count}, #reported: {twin.Properties.Reported.Count}\");\n```\n\nNote: it's important to use a `CancellationToken` that will be cancelled after a certain amount of time. Otherwise, this will be blocking the thread up to the point the twin is received. \n\nTwins have properties, reported and desired. They are collection and you can get or try to get any element.\n\nYou can report your Twin as simple as this:\n\n```csharp\nTwinCollection reported = new TwinCollection();\nreported.Add(\"firmware\", \"myNano\");\nreported.Add(\"sdk\", 0.2);\nazureIoT.UpdateReportedProperties(reported);\n```\n\nYou also have the option to wait for the twin update confirmation, in this case use a `CancellationToken` that can be cancelled. Otherwise the check will be ignored.\n\nNote: the function will return false if the twin reception confirmation is not checked or if it did not arrive on time.\n\nYou can also register for any twin update:\n\n```csharp\nazureIoT.TwinUpdated += TwinUpdatedEvent;\n\nvoid TwinUpdatedEvent(object sender, TwinUpdateEventArgs e)\n{\n    Debug.WriteLine($\"Twin update received: {e.Twin.Count}\");\n}\n```\n\n\u003e Note: some modem have limitations in the length of the message. The message is what contains the twins. Make sure you'll check the limitations when using the FullyManaged library.\n\n### Sending message\n\nYou have to use the `SendMessage` function to send any kind of message or telemetry to Azure IoT. As for the other function, you have the possibility to ensure delivery with a `CancellationToken` than can be cancelled. If one that can't be cancelled is used, the delivery insurance will be ignored and the function will return false.\n\n```csharp\nvar isReceived = azureIoT.SendMessage($\"{{\\\"Temperature\\\":42,\\\"Pressure\\\":1024}}\", new CancellationTokenSource(5000).Token);\nDebug.WriteLine($\"Message received by IoT Hub: {isReceived}\");\n```\n\nNote: The message will be sent with the default service quality of service you created the device with. You won't get any answer for the quality `0`. In this case, you can simplify it to:\n\n```csharp\nazureIoT.SendMessage($\"{{\\\"Temperature\\\":42,\\\"Pressure\\\":1024}}\");\n```\n\n### Cloud to device messages\n\nYou can register an event to receive Cloud to device messages:\n\n```csharp\nazureIoT.CloudToDeviceMessage += CloudToDeviceMessageEvent;\n\n// The following example shows how to display all keys in debug\nvoid CloudToDeviceMessageEvent(object sender, CloudToDeviceMessageEventArgs e)\n{\n    Debug.WriteLine($\"Message arrived: {e.Message}\");\n    foreach (string key in e.Properties.Keys)\n    {\n        Debug.Write($\"  Key: {key} = \");\n        if (e.Properties[key] == null)\n        {\n            Debug.WriteLine(\"null\");\n        }\n        else\n        {\n            Debug.WriteLine((string)e.Properties[key]);\n        }\n    }\n\n    // e.Message contains the message itself\n    if(e.Message == \"stop\")\n    {\n        ShoudIStop = true;\n    }\n}\n```\n\nNote: the `sender` is a `DeviceClient` class, you can then send a message back, a confirmation or any logic you've put in place.\n\n\u003e Note: some modem have limitations in the length of the message and topic length. The topic length is what contains the property bag. Make sure you'll check the limitations when using the FullyManaged library.\n\n### Method callback\n\nMethod callback is supported as well. You can register and unregister your methods. Here are a few examples:\n\n```csharp\nazureIoT.AddMethodCallback(MethodCallbackTest);\nazureIoT.AddMethodCallback(MakeAddition);\nazureIoT.AddMethodCallback(RaiseExceptionCallbackTest);\n\nstring MethodCallbackTest(int rid, string payload)\n{\n    Debug.WriteLine($\"Call back called :-) rid={rid}, payload={payload}\");\n    return \"{\\\"Yes\\\":\\\"baby\\\",\\\"itisworking\\\":42}\";\n}\n\nstring MakeAddition(int rid, string payload)\n{\n    Hashtable variables = (Hashtable)JsonConvert.DeserializeObject(payload, typeof(Hashtable));\n    int arg1 = (int)variables[\"arg1\"];\n    int arg2 = (int)variables[\"arg2\"];\n    return $\"{{\\\"result\\\":{arg1 + arg2}}}\";\n}\n\nstring RaiseExceptionCallbackTest(int rid, string payload)\n{\n    // This will properly return as well the exception error\n    throw new Exception(\"I got you, it's to test the 504\");\n}\n```\n\n**Important**: method names are case sensitive. So make sure you name your functions in C# use the same case.\n\n\u003e Note: some modem have limitations in the length of the message. The message is what contains the payload. Make sure you'll check the limitations when using the FullyManaged library.\n\n### Status update event\n\nA status update event is available:\n\n```csharp\nazureIoT.StatusUpdated += StatusUpdatedEvent;\n\nvoid StatusUpdatedEvent(object sender, StatusUpdatedEventArgs e)\n{\n    Debug.WriteLine($\"Status changed: {e.IoTHubStatus.Status}, {e.IoTHubStatus.Message}\");\n    // You may want to reconnect or use a similar retry mechanism\n    ////if (e.IoTHubStatus.Status == Status.Disconnected)\n    ////{\n    ////    mqtt.Open();\n    ////}\n}\n```\n\n\u003e Note: some modem have limitations in the MQTT implementation so you may not get all the updates. Make sure you'll check the limitations when using the FullyManaged library.\n\nNote that those are status change based, so once the connect or disconnect event arrives, they'll be replaced by other events as soon as something else happened like receiving a twin.\n\n### QoS Level\n\nBy default, the device SDKs connect to an IoT Hub use QoS 1 for message exchange with the IoT hub. You can change this by setting the `qosLevel` argument of the `DeviceClient` constructor.\n\nHere are existing QoS levels that you can use:\n\n- AtMostOnce: The broker/client will deliver the message once, with no confirmation.\n- AtLeastOnce: The broker/client will deliver the message at least once, with confirmation required.\n- ExactlyOnce: The broker/client will deliver the message exactly once by using a four step handshake.\n\nWhile it's possible to configure QoS 0 (AtMostOnce) for faster message exchange, you should note that the delivery isn't guaranteed nor acknowledged. For this reason, QoS 0 is often referred as \"fire and forget\".\n\n## Module support\n\nModules are supported, you will have to use the constructor to pass the module ID either with a SAS token, either with a certificate. The rest fully works like a normal device. Everything is fully supported including module direct method, telemetry and of course twins!\n\nFor example here with a SAS token. Note that the certificates are fully supported as well. And if you are not storing the Azure root certificate on the device, you'll need to pass it in the constructor.\n\n```csharp\nconst string DeviceID = \"nanoEdgeTwin\";\nconst string ModuleID = \"myModule\";\nconst string IotBrokerAddress = \"youriothub.azure-devices.net\";\nconst string SasKey = \"yoursaskey\";\nDeviceClient module = new DeviceClient(IotBrokerAddress, DeviceID, ModuleID, SasKey);\n```\n\n## Azure IoT Device Provisioning Service (DPS) support\n\nThis SDK also supports the Azure IoT Device Provisioning Service. Group and individual provisioning scenarios are supported either with a symmetric key either with certificates. To understand the mechanism behind DPS, it is recommended to read the [documentation](https://docs.microsoft.com/azure/iot-dps/).\n\n### Provisioning using symmetric key\n\nFor symmetric key provisioning you only need the following elements:\n\n- A registration ID\n- The ID Scope\n- The device name\n- The key or the derived key for group provisioning\n\nThe code is then straight forward:\n\n```csharp\nconst string RegistrationID = \"nanoDPStTest\";\nconst string DpsAddress = \"global.azure-devices-provisioning.net\";\nconst string IdScope = \"0ne01234567\";\nconst string SasKey = \"alongkeyencodedbase64\";\n\n// See the previous sections in the SDK help, you either need to have the Azure certificate embedded\n// Either passing it in the constructor\nX509Certificate azureCA = new X509Certificate(DpsSampleApp.Resources.GetBytes(DpsSampleApp.Resources.BinaryResources.BaltimoreRootCA_crt));\nvar provisioning = ProvisioningDeviceClient.Create(DpsAddress, IdScope, RegistrationID, SasKey, azureCA);\nvar myDevice = provisioning.Register(new CancellationTokenSource(60000).Token);\n\nif(myDevice.Status != ProvisioningRegistrationStatusType.Assigned)\n{\n    Debug.WriteLine($\"Registration is not assigned: {myDevice.Status}, error message: {myDevice.ErrorMessage}\");\n    return;\n}\n\n// You can then create the device\nvar device = new DeviceClient(myDevice.AssignedHub, myDevice.DeviceId, SasKey, nanoFramework.M2Mqtt.Messages.MqttQoSLevel.AtLeastOnce, azureCA);\n// Open it and continue like for the previous sections\nvar res = device.Open();\nif(!res)\n{\n    Debug.WriteLine($\"can't open the device\");\n    return;\n}\n```\n\nIn case a [DPS model](https://github.com/Azure/opendigitaltwins-dtdl/blob/master/DTDL/v2/dtdlv2.md) is going to be used, the ID of the model has to be passed to the ProvisioningDeviceClient and DeviceClient constructor.\nThe code above requires the following changes.\n\nAdd the model ID as a constant:\n\n```csharp\npublic const string ModelId = \"dtmi:orgpal:palthree:palthree_demo_0;1\";\n\n```\n\nCreate the additional payload information with the model ID to be sent along the registration with DPS and pass that to the call to `Register()`.\n\n```csharp\nvar pnpPayload = new ProvisioningRegistrationAdditionalData\n{\n    JsonData = PnpConvention.CreateDpsPayload(ModelId),\n};\n\nvar myDevice = provisioning.Register(pnpPayload, new CancellationTokenSource(60000).Token);\n\n```\n\nCreate the device client passing the model ID to the respective parameter in the constructor.\n\n```csharp\nvar device = new DeviceClient(myDevice.AssignedHub, myDevice.DeviceId, SasKey, nanoFramework.M2Mqtt.Messages.MqttQoSLevel.AtLeastOnce, azureCA, ModelId);\n```\n\nNote: like for the `DeviceClient` you need to make sure you are connected to a network properly and also have a proper data and time set on the device.\n\n### Provisioning using certificates\n\nFor symmetric key provisioning you only need the following elements:\n\n- A registration ID\n- The ID Scope\n- The device name\n- The device certificate\n- Make sure that your IoT Hub is as well aware of the root/intermediate certificate you are using otherwise you won't be able to connect to your IoT Hub once your device is provisioned\n\nThe code is then straight forward:\n\n```csharp\nconst string RegistrationID = \"nanoCertTest\";\nconst string DpsAddress = \"global.azure-devices-provisioning.net\";\nconst string IdScope = \"0ne0034F11A\";\n\nconst string cert = @\"\n-----BEGIN CERTIFICATE-----\nYour certificate\n-----END CERTIFICATE-----\n\";\n\nconst string privateKey = @\"\n-----BEGIN ENCRYPTED PRIVATE KEY-----\nthe encrypted private key\n-----END ENCRYPTED PRIVATE KEY-----\n\";\n\n// See the previous sections in the SDK help, you either need to have the Azure certificate embedded\n// Either passing it in the constructor\nX509Certificate azureCA = new X509Certificate(DpsSampleApp.Resources.GetBytes(DpsSampleApp.Resources.BinaryResources.BaltimoreRootCA_crt));\n// Note: if your private key is not protected with a password, you don't need to pass it\n// You can as well store your certificate directly in the device certificate store\n// And you can store it as a resource as well if needed\nX509Certificate2 deviceCert = new X509Certificate2(cert, privateKey, \"1234\");\n\nvar provisioning = ProvisioningDeviceClient.Create(DpsAddress, IdScope, RegistrationID, deviceCert, azureCA);\nvar myDevice = provisioning.Register(new CancellationTokenSource(60000).Token);\n\nif(myDevice.Status != ProvisioningRegistrationStatusType.Assigned)\n{\n    Debug.WriteLine($\"Registration is not assigned: {myDevice.Status}, error message: {myDevice.ErrorMessage}\");\n    return;\n}\n\n// You can then create the device\nvar device = new DeviceClient(myDevice.AssignedHub, myDevice.DeviceId, deviceCert, nanoFramework.M2Mqtt.Messages.MqttQoSLevel.AtLeastOnce, azureCA);\n// Open it and continue like for the previous sections\nvar res = device.Open();\nif(!res)\n{\n    Debug.WriteLine($\"can't open the device\");\n    return;\n}\n```\n\n### Additional payload\n\nAdditional payload is supported as well. You can set it up as as json string in the `ProvisioningRegistrationAdditionalData` class when calling the `Register` function. When the device has been provisioned, you may have as well additional payload provided.\n\n\u003e Note: some modem have limitations in the length of the message. The message is what contains the payload. Make sure you'll check the limitations when using the FullyManaged library.\n\n## Feedback and documentation\n\nFor documentation, providing feedback, issues and finding out how to contribute please refer to the [Home repo](https://github.com/nanoframework/Home).\n\nJoin our Discord community [here](https://discord.gg/gCyBu8T).\n\n## Credits\n\nThe list of contributors to this project can be found at [CONTRIBUTORS](https://github.com/nanoframework/Home/blob/main/CONTRIBUTORS.md).\n\n## License\n\nThe **nanoFramework** Class Libraries are licensed under the [MIT license](LICENSE.md).\n\n## Code of Conduct\n\nThis project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behaviour in our community.\nFor more information see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).\n\n### .NET Foundation\n\nThis project is supported by the [.NET Foundation](https://dotnetfoundation.org).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnanoframework%2Fnanoframework.azure.devices","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnanoframework%2Fnanoframework.azure.devices","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnanoframework%2Fnanoframework.azure.devices/lists"}