{"id":19991425,"url":"https://github.com/fbeltrao/IoTHubGateway","last_synced_at":"2025-05-04T10:31:35.190Z","repository":{"id":129020757,"uuid":"125173989","full_name":"fbeltrao/IoTHubGateway","owner":"fbeltrao","description":"Azure IoT Gateway using AMQP Multiplex to send device to cloud messages","archived":false,"fork":false,"pushed_at":"2018-06-07T19:26:46.000Z","size":439,"stargazers_count":15,"open_issues_count":0,"forks_count":9,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-27T16:42:51.269Z","etag":null,"topics":["amqp","azure-iothub","csharp","dotnet-core","iot","iothub"],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"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/fbeltrao.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2018-03-14T07:39:54.000Z","updated_at":"2023-08-29T11:07:19.000Z","dependencies_parsed_at":"2023-04-29T18:01:53.405Z","dependency_job_id":null,"html_url":"https://github.com/fbeltrao/IoTHubGateway","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fbeltrao%2FIoTHubGateway","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fbeltrao%2FIoTHubGateway/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fbeltrao%2FIoTHubGateway/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fbeltrao%2FIoTHubGateway/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fbeltrao","download_url":"https://codeload.github.com/fbeltrao/IoTHubGateway/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252320331,"owners_count":21729107,"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":["amqp","azure-iothub","csharp","dotnet-core","iot","iothub"],"created_at":"2024-11-13T04:51:45.010Z","updated_at":"2025-05-04T10:31:35.174Z","avatar_url":"https://github.com/fbeltrao.png","language":"C#","funding_links":[],"categories":["C\\#"],"sub_categories":[],"readme":"# Azure IoT Hub AMQP Server Gateway Sample\r\n\r\nTravis: [![Travis](https://travis-ci.org/fbeltrao/IoTHubGateway.svg?branch=master)](https://travis-ci.org/fbeltrao/IoTHubGateway)\r\n\r\n## Introduction\r\n\r\nThe best way to connect any device to IoT Hub when building an IoT solution is to directly connect it using one of the provided [Microsoft Azure IoT Device SDKs](https://github.com/Azure/azure-iot-sdks).\r\n\r\nAzure IoT Hub supports multiple protocols and offers extensive developer integration from REST API to [full device and service SDKs](https://github.com/Azure/azure-iot-sdks) in C, Python, Node.js, Java and .NET. In most cases, there is no need to build your own integration code from scratch.\r\n\r\nIn some cases however, for example when you need to do protocol translation or your client devices are simply not capable to connect directly to IoT hub, you need a gateway to bridge the gap.\r\n\r\nIf you just need to do protocol translation the right approach is to create a gateway as documented here: https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-protocol-gateway \r\n\r\nIf you need a gateway on the edge then the best way to implement this gateway scenario is to use IoT Edge as outlined in these [use cases and patterns](https://docs.microsoft.com/en-us/azure/iot-edge/iot-edge-as-gateway).\r\n\r\nThere is another scenario which we want to discuss here and which is not covered in the articles above, where you need to implement an application gateway at the server level and not at the Edge or the gateway may not support IoT Edge due to processing power or memory constraints or due to the lack of container support.\r\n\r\nOne of these cases could be a migration scenario where you are unable to change the code running on the devices. In this case you need to implement an intermediary gateway that the devices can connect to without knowing about IoT hub.\r\n\r\n![Migration Scenario](./images/migration-scenario.png \"Migration Scenario\")\r\n\r\nAnother use for the server gateway for example is to act as a [LoRaWAN](https://www.lora-alliance.org/technology) to IoT Hub connector. The LoRaWAN network server could include this gateway code to forward all the messages from the connected LoRa devices to IoT Hub.\r\n\r\n![Network Server Scenario](./images/network-server-scenario.png \"Network Server Scenario\")\r\n\r\n## Note\r\n\r\nThe code provided in this sample is not production ready and was built for demonstration and illustration purposes. Hence, the code has sample quality. We have done some basic and scalability testing but no in depth validation.\r\n\r\n## Solution Approach\r\n\r\nIn this sample, we created an ASP.NET Core solution to serve as our gateway.\r\n\r\nIt is crucial that a gateway solution should be able to multiplex device connections instead of creating single connections to IoT Hub per device. IoT Hub supports multiplexing only over HTTP and AMQP. For our sample gateway, we decided to use AMQP for its efficiency. The [Azure IoT Hub SDK for .NET](https://github.com/Azure/azure-iot-sdk-csharp) already implements support for connection pooling. Support for the other language SDKs are planned.\r\n\r\nAn alternative solution is to implement the same pattern without the use of the SDK and working directly at the AMQP level, here you can find a Node.js implementation: https://github.com/vjrantal/azure-iot-multiplexing-gateway  \r\n\r\n## Flow\r\n\r\nWhen a device first wants to send a message through the gateway, in our example it calls a REST API, but this could be achieved using any accessible endpoint or protocol that the gateway supports. At this point, the gateway creates a new [DeviceClient](https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.devices.client.deviceclient?view=azure-dotnet) in order to connect to IoT Hub using the connection pool settings \"Pooling = true\" in [AmqpConnectionPoolSettings](https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.devices.client.amqpconnectionpoolsettings?view=azure-dotnet).\r\n\r\n```csharp\r\nvar newDeviceClient = DeviceClient.Create(\r\n    this.gatewayOptions.IoTHubHostName,\r\n    auth,\r\n    new ITransportSettings[]\r\n    {\r\n        new AmqpTransportSettings(TransportType.Amqp_Tcp_Only)\r\n        {\r\n            AmqpConnectionPoolSettings = new AmqpConnectionPoolSettings()\r\n            {\r\n                Pooling = true\r\n            }\r\n        }\r\n    }\r\n);\r\n```\r\n\r\nThis forces every device client to share the same connection. By default, 995 devices are supported per connection. The SDK will add additional connections to the pool automatically if needed.\r\n\r\nAt this point, we are ready to send the message from the gateway to IoT Hub. \r\n\r\nTo further optimize our sample, we don't want to create a new [DeviceClient](https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.devices.client.deviceclient?view=azure-dotnet) for every subsequent message the device wants to send. Instead, we keep it in a cache with a time to live (TTL) we can specify. If no new message comes in within this specified time, 1 hour in our case, the cache system will remove the [DeviceClient](https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.devices.client.deviceclient?view=azure-dotnet) from the cache.\r\n\r\n## Authentication\r\n\r\nIn our example, we support two authentication mechanisms. In both cases, Iot Hub will see the message as being sent by the device itself rather than by the gateway.\r\n\r\n### Authentication using a Shared Access Policy Key\r\n\r\nUsing the authentication method [DeviceAuthenticationWithSharedAccessPolicyKey](https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.devices.client.deviceauthenticationwithsharedaccesspolicykey?view=azure-dotnet) A single connection string allows the gateway to forward messages from all clients to IoT hub without individual authentication for each of the devices. In this case, the gateway authenticates in behalf of the devices but does not impersonate them. This is the simplest solution, but it's not secure. \r\n\r\nYou need to have a custom authentication mechanism in place between the devices and the gateway in this scenario to ensure security. This is useful in the scenario of a LoRaWAN network server, where an authenticaiton mechanism is already in place between the LoRa devices and their LoRaWAN gateway or server.\r\n\r\n### Authentication using Tokens\r\n\r\nUsing the authentication method [DeviceAuthenticationWithToken](https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.devices.client.deviceauthenticationwithtoken?view=azure-dotnet) allows every device to authenticate to IoT hub directly, while still retaining the ability to share the connection among devices with pooling. In this case, the device has the SAS Key and generates a temporary token that it sends through the gateway to IoT Hub. IoT Hub is authenticating the device and not the gateway itself, effectively making it an end-to-end authentication. The  time-to-live set for the caching needs to be the same as the one for the SAS token.\r\n\r\n## Sending messages from Cloud to Devices\r\n\r\n### Direct Method\r\n\r\nIoT Hub allows to do a callback to the connected device by calling a method on the device. For more information see [\"Use direct methods\"](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-csharp-csharp-direct-methods).\r\n\r\nIn the gateway it's possible to listen for this event called by IoT hub. This call is synchronous. Depending on the protocol and the connection between device and our gateway, you need to implement your own callback solution which varies greatly based on the solution architecture and hence is out of the scope of this sample. For demonstration purposes, we simply log the method call to the console. For example, you could call the REST API of the LoRaWAN server from this event handler and pass the message downstream to the device.\r\n\r\n### Cloud to Device Messages\r\n\r\nFor details Cloud to Device messages, see [\"Send messages from the cloud to your device with IoT Hub\"](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-csharp-csharp-c2d)\r\n\r\nWe have implemented a basic Cloud to Device message handling, but this implementation is not optimal as the more devices that are connected the slower it will become. We have run a quick test with 5’000 DeviceClient instances.  It is an approach that might not be advised for large device deployments.\r\n\r\n### Device Twins\r\n\r\nFor details on how Device Twins work, see [\"Understand and use device twins in IoT Hub\"](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-device-twins)\r\n\r\nSupport is not implemented in this gateway sample at the moment.\r\n\r\n## Scaling\r\n\r\nThis solution was tested in a single instance, connecting 20'000 devices, sending and receiving messages. No problems were found. Since we open a device connection and keep in memory you should use affinity if you deploy the application in multiple instances, so that each device always communicates with the same instance.\r\n\r\nIf you enable cloud to device messages pay attention to the option \"CloudMessageParallelism\", as it dictate how fast your deployment will handle cloud messages. Direct methods don't have the same problem as the IoT SDK notifies when a direct method call is received.\r\n\r\n## Configuration Options\r\n\r\nCustomization of the gateway is available through the configuration. The available options are:\r\n\r\n|Setting|Description|Default|\r\n|--|--|--|\r\n|DeviceOperationTimeout|Device operation timeout (in milliseconds)|10 seconds (10'000)|\r\n|IoTHubHostName|IoT Hub host name. Something like xxxxx.azure-devices.net|\"\"|\r\n|AccessPolicyName|The IoT Hub access policy name. A common value is iothubowner|\"\"|\r\n|AccessPolicyKey|The IoT Hub access policy key. Get it from Azure Portal|\"\"|\r\n|MaxPoolSize|The maximum pool size|ushort.MaxValue|\r\n|SharedAccessPolicyKeyEnabled|Allows or not the usage of shared access policy keys.If you enable it make sure that access to the API is protected otherwise anyone will be able to impersonate devices|false|\r\n|DefaultDeviceCacheInMinutes|Default device client cache in duration in minutes|60 minutes|\r\n|DirectMethodEnabled|Enable/disables direct method (cloud -\u003e device)|false|\r\n|DirectMethodCallback|Gets/sets the callback to handle device direct methods|null|\r\n|CloudMessagesEnabled|Enable/disables cloud messages in the gateway. Cloud messages are retrieved in a background job|false|\r\n|CloudMessageParallelism|Degree of parallelism used to check for cloud messages|10|\r\n|CloudMessageCallback|Gets/sets the callback to handle cloud messages|null|\r\n## Contributors\r\n\r\nSascha Corti, Ronnie Saurenmann, Francisco Beltrao\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffbeltrao%2FIoTHubGateway","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffbeltrao%2FIoTHubGateway","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffbeltrao%2FIoTHubGateway/lists"}