{"id":15291365,"url":"https://github.com/azure/iot-central-bidirectional-device-bridge","last_synced_at":"2025-08-08T02:18:42.512Z","repository":{"id":40232050,"uuid":"330036503","full_name":"Azure/iot-central-bidirectional-device-bridge","owner":"Azure","description":"The Device Bridge enables the connection of devices to Azure IoT Central in scenarios where it's not possible to use the Azure IoT Device SDKs.","archived":false,"fork":false,"pushed_at":"2025-04-14T18:58:51.000Z","size":115150,"stargazers_count":16,"open_issues_count":0,"forks_count":13,"subscribers_count":12,"default_branch":"main","last_synced_at":"2025-08-07T00:38:36.971Z","etag":null,"topics":["amqp","containers","csharp","docker","iot","iot-central"],"latest_commit_sha":null,"homepage":"","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/Azure.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":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-01-15T22:30:43.000Z","updated_at":"2025-04-14T18:58:46.000Z","dependencies_parsed_at":"2025-04-14T19:47:45.165Z","dependency_job_id":null,"html_url":"https://github.com/Azure/iot-central-bidirectional-device-bridge","commit_stats":null,"previous_names":["iot-for-all/iotc-device-bridge"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Azure/iot-central-bidirectional-device-bridge","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Azure%2Fiot-central-bidirectional-device-bridge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Azure%2Fiot-central-bidirectional-device-bridge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Azure%2Fiot-central-bidirectional-device-bridge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Azure%2Fiot-central-bidirectional-device-bridge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Azure","download_url":"https://codeload.github.com/Azure/iot-central-bidirectional-device-bridge/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Azure%2Fiot-central-bidirectional-device-bridge/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269352000,"owners_count":24402699,"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","status":"online","status_checked_at":"2025-08-08T02:00:09.200Z","response_time":72,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","containers","csharp","docker","iot","iot-central"],"created_at":"2024-09-30T16:12:10.425Z","updated_at":"2025-08-08T02:18:42.487Z","avatar_url":"https://github.com/Azure.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Azure IoT Central Device Bridge (Send and Receive Data with AMQP)\nThe Device Bridge enables the connection of devices to Azure IoT Central in scenarios where it's not possible to use the Azure IoT Device SDKs.\nThe solution in this repository deploys a set of resources to your Azure Subscription. Once deployed, it exposes a simple, yet powerful, HTTP interface\nthat can be used for sending and receiving* data between devices and Azure IoT. The solution can be used *as is* or customized with additional components,\nsuch as data transformation and protocol adapter modules.\n\n\u003e \\* If you only need to send data, look at https://github.com/Azure/iotc-device-bridge.  It sends data using HTTP and can run in an Azure Function.\n\n- [Deployment instructions](#deployment-instructions)\n  * [1 - Build and push the Docker image](#1---build-and-push-the-docker-image)\n  * [2 - Open the deployment template in Azure Portal](#2---open-the-deployment-template-in-azure-portal)\n  * [3 - Deployment parameters](#3---deployment-parameters)\n    + [3.1 Bridge name](#31-bridge-name)\n    + [3.2 IoTC SAS key and Id scope](#32-iotc-sas-key-and-id-scope)\n    + [3.3 API key](#33-api-key)\n    + [3.4 SQL credentials](#34-sql-credentials)\n    + [3.5 Log Analytics workspace credentials](#35-log-analytics-workspace-credentials)\n    + [3.6 Image and Azure Container Registry credentials](#36-image-and-azure-container-registry-credentials)\n  * [4 - Create resources](#4---create-resources)\n- [What is being provisioned](#what-is-being-provisioned)\n  * [Pricing](#pricing)\n- [HTTP API](#http-api)\n  * [Device to cloud messages](#device-to-cloud-messages)\n  * [Get device twin](#get-device-twin)\n  * [Update reported properties](#update-reported-properties)\n  * [Subscribing to events](#subscribing-to-events)\n    + [Methods](#methods)\n    + [C2D messages](#c2d-messages)\n    + [Desired property updates](#desired-property-updates)\n  * [Device connection status](#device-connection-status)\n    + [Subscribing to connection status change events](#subscribing-to-connection-status-change-events)\n    + [Connection retries](#connection-retries)\n    + [Restarting stopped subscriptions and forcing device reconnection](#restarting-stopped-subscriptions-and-forcing-device-reconnection)\n  * [Device provisioning](#device-provisioning)\n  * [Subscription callback retries](#subscription-callback-retries)\n- [Load and performance](#load-and-performance)\n  * [Instance restarts and reconnection speed](#instance-restarts-and-reconnection-speed)\n  * [Multiplexing and connection pool](#multiplexing-and-connection-pool)\n- [Monitoring](#monitoring)\n- [Encryption key rotation](#encryption-key-rotation)\n- [SSL and HTTPS](#ssl-and-https)\n- [Custom adapters](#custom-adapters)\n\n## Deployment instructions\nTo use the device bridge solution, you will need the following:\n- an Azure account. You can create a free Azure account from [here](https://aka.ms/aft-iot)\n- an Azure IoT Central application to connect the devices. Create a free app by following [these instructions](https://docs.microsoft.com/en-us/azure/iot-central/quick-deploy-iot-central)\n\n### 1 - Build and push the Docker image\nFirst, using the Docker CLI, run the `docker build .` command in the solution folder to build the Device Bridge image. Second, you'll need to\ntag and push the image to a private container registry, such as Azure Container Registry (ACR). Instructions on how to build, tag, and push an\nimage to ACR can be found [here](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-get-started-docker-cli).\nNote the image name and the ACR credentials, which are necessary in the next steps.\n\n### 2 - Open the deployment template in Azure Portal\nUse the button below to open the deployment template in the Azure Portal:\n\n[![Deploy to Azure](http://azuredeploy.net/deploybutton.png)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fiot-for-all%2Fiotc-device-bridge%2Fmain%2Fazuredeploy.json)\n\n### 3 - Deployment parameters\n\n#### 3.1 Bridge name\nIn the `Bridge-name` parameter, enter the name for the new Bridge instance. This name will be part of the HTTPS endpoint\nfor your instance, so it may only contain letters, numbers, and dashes.\n\n#### 3.2 IoTC SAS key and Id scope\nThese parameters link your new Bridge instance to a specific Azure IoT Central application. Go to your IoT Central\napplication and navigate to the Administration \u003e Device Connection area. Copy the `ID Scope` field and paste it into\nthe `iotc-id-scope` parameter in the template.\nIn the same page, under Enrollment groups, open the `SAS-IoT-Devices` group. In the group page, copy either the `Primary key` or\n`Secondary key` and paste it in the `Iotc-dps-sas-key` parameter of the template (this key will be stored in a Key Vault provisioned with the solution).\n\n![Scope Id and key](Docs/Assets/scope_id_and_key.png \"scope id and key\")\n![Enrollment group](Docs/Assets/sas_enrollment_group.png \"enrollment group\")\n\n#### 3.3 API key\nIn the `Api-key` parameter, define a strong (and preferably randomly generated) API key. This key will be used to protect the HTTP API and must be included in the\n`x-api-key` header of every request to the Bridge.\n\n#### 3.4 SQL credentials\nIn the `Sql-username` and `Sql-password` parameters, enter an admin login and password for the Azure SQL instance that will be provisioned\nby the solution. The password must follow the [SQL Server password policy](https://docs.microsoft.com/en-us/sql/relational-databases/security/password-policy?view=sql-server-ver15#password-complexity).\n\n#### 3.5 Log Analytics workspace credentials\nBy default, the Bridge will publish logs to a Log Analytics workspace of your choice. In the `Log-analytics-workspace-id` and `Log-analytics-workspace-key`\nparameters, provide the credentials of your workspace (instructions to obtain the credentials of your Log Analytics workspace can be found [here](https://docs.microsoft.com/en-us/azure/container-instances/container-instances-log-analytics#get-log-analytics-credentials)).\n\n#### 3.6 Image and Azure Container Registry credentials\nIn this step you need to grant the solution access to the Docker image that you built and pushed in step 1.\nIn the `Bridge-image` enter the name of the image that you pushed to your private ACR. In the `Acr-server`,\n`Acr-username`, and `Acr-password` parameters provide the credentials of your ACR instance.\n\n#### 4 - Create resources\nAfter providing all necessary parameters, click the `Review+create` button. The deployment may take a few minutes. Once finished,\nyou can find the newly provisioned resources in the target resource group.\n\n## What is being provisioned\nThe template in this solution will provision the following resources to your Azure subscription:\n- Azure Storage Account - for persistent volumes\n- Key Vault - to store all secrets\n- Azure SQL - to store device and subscription data\n- Azure container instance - main solution\n- Azure container instance - setup - (only runs during the solution setup phase)\n\n### Pricing\nThe main pricing components for the resources published by the ARM template in this repository are the Azure Container Instance that\nhosts the core Bridge (1 CPU and 3 GB of memory - see [Container Instances pricing](https://azure.microsoft.com/en-us/pricing/details/container-instances/)\nfor an estimate) and the Azure SQL Database (Basic tier, 5 DTUs - see [Azure SQL pricing](https://azure.microsoft.com/en-us/pricing/details/sql-database/single/) for more details).\n\n## HTTP API\nOnce deployed, the solution will expose an HTTPS endpoint at `https://\u003cbridge-name\u003e.\u003cregion\u003e.azurecontainer.io`. This endpoint can also be found by navigating to\nthe Device Bridge container group deployed to your subscription \u003e `Properties` \u003e `FQDN`.\n\nThe HTTP endpoints are protected by the API key provided when the solution was provisioned. For every request, include an `x-api-key` header containing the key.\n\nIn what follows we give a quick overview of the functionalities available through the API. For a full description of the\nendpoints and data types as well as sample requests and responses, refer to the API swagger under `Docs/swagger.json`.\n\n\u003e NOTE: the API operations below will cause the target device to be automatically registered in IoT Central.\nFor more information about device registration see the [device provisioning section](#device-provisioning).\n\n### Device to cloud messages\nThe Bridge can send messages to Azure IoT on behalf of a device.\nThe main component of a message is the `data` field. Optionally, the request can include `componentName`, `properties`, and a `creationTimeUtc`.\nHere's an example of a request to send a message:\n\n```json\nPOST /devices/{deviceId}/messages/events\n{\n    \"data\": {\n        \"temperature\": 4.8,\n        \"humidity\": 31\n    },\n    \"properties\": {\n        \"prop1\": \"abc\"\n    },\n}\n```\n\n### Get device twin\nThe device twin will include the latest version of desired and reported properties of a device.\nBelow is an example of the response returned by the service when fetching the latest twin for a device:\n\n```json\n{\n    \"twin\": {\n        \"properties\": {\n            \"desired\": {\n                \"fanSpeed\": 30,\n                \"$version\": 2\n            },\n            \"reported\": {\n                \"threshold\": 4.8,\n                \"LastReported\": \"2021-01-10T00:35:00.388Z\",\n                \"$version\": 5\n            }\n        }\n    }\n}\n```\n\n### Update reported properties\nTo update reported properties in a device twin, include a patch in the request body, as the example below:\n\n```json\nPATCH /devices/{deviceId}/twin/properties/reported\n{\n    \"patch\": {\n        \"fanSpeed\": 35,\n        \"serial\": \"ABC\"\n    }\n}\n```\n\n### Subscribing to events\nYou can subscribe to get notified of cloud-to-device events (methods, C2D messages, and desired property updates). To create a subscription,\nyou need to provide the callback URL that the service will send a `POST` request to when a notification is available. Only one subscription of each type can exist at a time\n(e.g., issuing a new subscription creation request of the same type will update the callback URL of the existing subscription).\n\n#### Methods\nMethod subscriptions will emit an event whenever a new direct method invocation is issues by the cloud. The following is\nan example of a method invocation event:\n\n```json\n{\n    \"eventType\": \"DirectMethodInvocation\",\n    \"deviceId\": \"my-device\",\n    \"deviceReceivedAt\": \"2020-12-04T01:06:14.251Z\",\n    \"methodName\": \"increaseTemperature\",\n    \"requestData\": {\n        \"celsius\" : 2\n    }\n}\n```\n\nThe callback may return an optional response body, which will be sent to IoTHub as the method response.\nBelow is an example of a response:\n\n```json\n{\n    \"status\": 200,\n    \"payload\": {\n        \"newTemperature\": 24\n    }\n}\n```\n\n#### C2D messages\nWhen the device receives a new C2D message from IoTHub, the service will send an event to the desired callback URL as in the example below:\n\n```json\n{\n    \"eventType\": \"C2DMessage\",\n    \"deviceId\": \"my-device\",\n    \"deviceReceivedAt\": \"2020-12-04T01:06:14.251Z\",\n    \"messageBody\": {\n        \"someField\": 20.2\n    },\n    \"properties\": {\n        \"prop1\": \"val1\",\n        \"prop2\": \"val2\",\n    },\n    \"messageId\": \"abc\",\n    \"expirtyTimeUtC\": \"2020-12-04T01:06:14.251Z\"\n}\n```\n\nThe response status code of the callback URL will determine how the service will acknowledge a message:\n- Response code between 200 and 299: the service will `complete` the message.\n- Response code between 400 and 499: the service will `reject` the message.\n- Any other response status: the service will `abandon` the message, causing IotHub to redeliver it.\n\nFor a detailed overview of C2D messages, see https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-messages-c2d.\n\n#### Desired property updates\nWhen the device receives a new desired property change from IoT Hub, the service will send an event to the desired callback URL. Example event:\n\n```json\n{\n    \"eventType\": \"DesiredPropertyUpdate\",\n    \"deviceId\": \"my-device\",\n    \"deviceReceivedAt\": \"2020-12-04T01:06:14.251Z\",\n    \"desiredProperties\": {\n        \"prop1\": \"string\",\n        \"prop2\": 12,\n        \"prop3\": {},\n    }\n}\n```\n\n\u003e NOTE: desired property updates are only received while the device is connected to IoT Hub. For this reason, property updates\nmight not be received while, for instance, the device is internally reconnecting due to a transient network error. To mitigate scenarios like this,\nyou can listen to internal connection events, as described in the next section, and get the latest device twin whenever the `Connected` event\nis received.\n\n### Device connection status\nInternally, the Device Bridge connects devices to Azure IoT through AMQP using connection multiplexing. It transparently manages\nthe life cycle of all connections (i.e., connecting, disconnecting, and retrying on errors). When you issue a command,\nsuch as sending a message or getting the device twin, the Bridge opens\na temporary connection for the device that is set to live between 9 to 11 minutes and is renewed as requests come. For subscriptions,\nthe Bridge will open a permanent connection for the device. This connection will last until the last subscription is deleted.\n\nDepending on the connection status of a device, it's subscriptions may have one of the following status:\n- `Starting`: initial status after a subscription is created and before the device has been connected internally.\nThis status may also represent that the Bridge is reconnecting the device after the service restarts.\n- `Running`: the device is connected and events are flowing.\n- `Stopped`: the device is disconnected due to a failure and events are not flowing. Failure scenarios can include transient issues,\nsuch as network unavailability, or permanent problems, as credentials no longer valid.\n\n#### Subscribing to connection status change events\nIn many situations it may be useful to react to changes in the underlying device connection status. For instance,\nyou may want to fetch the latest device twin whenever the device reconnects internally. Alternatively, you may want to\nbe notified when a device experiences a failure, such as credentials expired. For these scenarios you can subscribe\nto connection status changes.\n\nWhenever the device internally connects or reconnects, a `Connected` event will be sent. If the device fails to connect or the connection is dropped,\na `Disconnected` event will be emitted, including an associated failure reason. Other possible statuses are `Disabled` (the connection has\nbeen closed properly) and `Disconnected_Retrying` (the service is retrying to connect the device due to a transient error).\nFor a detailed description of all status and reasons, see https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.devices.client.connectionstatus?view=azure-dotnet.\n\n#### Connection retries\nOn a connection failure or connection drop scenario, the Bridge will keep retrying to connect the device internally\nregardless of the error reason. Transient errors, such as network unavailability are first retried for 5 minutes by the\nAzure IoT Device SDK builtin retries. Once SDK retries expire or a non-transient error happens, the Bridge will attempt a new DPS\nregistration and connection for the device. Retry attempts are made 5, 10, 15, 15, 20, 25, and 30 minutes apart. After that, an\nattempt will be made every 30 minutes, until the device successfully connects.\n\n#### Restarting stopped subscriptions and forcing device reconnection\nIssuing a call to the `resync` endpoint will cause the Bridge to attempt to reconnect any device right away.\nIf the device reconnection is successful, all stopped subscriptions will be back to a running state.\nYou may want to issue this command, for instance, if you don't want to wait for the builtin retries.\n\n### Device provisioning\nBy default, issuing a command to the Bridge on behalf of a device will cause it to be automatically provisioned. The device\nis provisioned using the SAS key provided during the solution deployment and will not be assigned to any particular model.\nThe Bridge provides an endpoint to optionally provision a device to a specific model ahead of time. The registration result is\ninternally cached to be used in future connections.\n\nTo access advanced registration features, including sending custom registration payload and getting the assigned hub,\nplease use the DPS REST API (https://docs.microsoft.com/en-us/rest/api/iot-dps/).\n\n\u003e NOTE: DPS registration is a long-running operation, so calls to this route may take a long time to return (in the order of seconds).\nIf this is a concern, use the DPS REST API directly, which provides support for long-running operation status lookup.\n\n### Subscription callback retries\nThe solution will automatically retry if a transient error happens when calling a subscription callback endpoint. By default, it will\nretry 5 times with an exponentially increasing interval (total 30 seconds). This number can be customized by overriding the `HTTP_RETRY_LIMIT`\nenvironment variable in the provisioning template. For `HTTP 429s`, the service will respect the `Retry-After` header, if one is available.\n\n\u003e NOTE: if needed, the solution code can be modified to add HTTP circuit-breaking be following the instructions on https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/implement-circuit-breaker-pattern.\n\n## Load and performance\nThe default setup provisioned by the ARM template in this repository was tested with up to 50,000 devices simultaneously connected.\nIn this scenario, we were able to send 10,000 device to cloud messages (telemetry) per minute through the Bridge. For cloud to device\nevents (including C2D messages, method invocations, and desired property updates combined), the Bridge was able to receive and forward 5,000\nevents per minute.\n\nThis test was performed in a constant-rate scenario, where all devices were already internally connected. Numbers may greatly vary depending\non different usage patterns, such as how often devices send or subscribe to events, which affects how often they are internally reconnected.\nThe specific setup being provisioned (e.g., different container sizes) will also directly influence the results. When deploying a new setup,\nmake sure you evaluate the performance considerations described in the following sections.\n\n### Instance restarts and reconnection speed\nIf the service instance restarts, the Bridge will automatically reconnect any devices with an active subscription. During this period,\nall subscriptions will have a `Starting` status. The speed at which the Bridge reconnects devices is set by default to 150 connections per second.\nThis means that, in the event of a container restart, it would take around one minute to reconnect 10,000 devices.\n\n\u003e NOTE: this number can be customized through `DEVICE_CONNECTION_BATCH_SIZE` and `DEVICE_CONNECTION_BATCH_INTERVAL_MS` environment variables.\nHowever, before adjusting this values it's important to perform a load test to make sure that the service can support the desired reconnection speed.\nFactors that may influence this speed is the size of the hosting container, number of devices, and desired number of connections in the multiplexing pool.\n\n### Multiplexing and connection pool\nBy default, the Bridge is configured to use a pool of 50 active AMQP connections. This amount allows around 50K devices to be connected\nsimultaneously. This number can be configured through the `MAX_POOL_SIZE` environment variable, however increasing this value may require\ndecreasing the default device reconnection speed, or else the Bridge may fail to reconnect devices in the event of a container restart.\nFor more details about connection pooling and multiplexing, see https://github.com/Azure/azure-iot-sdk-csharp/blob/master/iothub/device/devdoc/amqpstack.md.\n\n\u003e NOTE: this solution is meant to run as a single instance. Deploying more than one instance of the service pointing to the same\nAzure IoT Central application will potentially cause duplicate device connections, as instances are not aware of each other. This will\nresult in connection drops, as each device can only have a single active AMQP link to IoT Hub at all times.\n\n## Monitoring\nService logs are emitted to the Log Analytics Workspace provided during deployment. You can use the logs to query device events as well as\nbuild monitors for specific scenarios. Below is an example query that shows all device events in the past hour:\n\n```\nContainerInstanceLog_CL\n| where TimeGenerated \u003e= ago(1h)\n| where ContainerGroup_s == \"\u003ccontainer-group-name\u003e\"\n| extend log = parse_json(Message)\n| extend deviceId = tostring(log.deviceId)\n| extend _message = tostring(log.message)\n| where deviceId != \"\"\n| distinct TimeGenerated, deviceId, _message\n```\n\n## Encryption key rotation\nWhen a new subscription is created, the provided callback URL is stored in the database in an encrypted format. This provides an\nextra layer of security, as these URLs may contain sensitive data, such as access keys or tokens in the query parameters. The\nencryption key used in this scenario is automatically generated when the solution is deployed and stored in the Key Vault.\n\nTo rotate this encryption key, simply start the setup container provisioned to the same resource group (the container group name\nstarts with `iotc-container-groups-setup-`). Once started, the setup container will automatically generate a new encryption key and \nuse it to reencrypt all subscriptions stored in the database (you can follow the progress in the container logs `Container group \u003e Containers \u003e Logs`).\nOnce reencryption has finished, you can restart the main Bridge container (the container group name starts with `iotc-container-groups-`)\nto make sure that it starts using the new key for new subscriptions.\n\n## SSL and HTTPS\nThe Caddy webserver deployed in the solution uses [Let's Encrypt](https://letsencrypt.org/) to automatically obtain an HTTPS certificate.\nThis service is free. If desired, you may use a different\n[certificate authority and webserver configuration](https://docs.microsoft.com/en-us/azure/container-instances/container-instances-container-group-ssl).\n\nTo reduce the amount of logs stored in the Log Analytics workspace, the Caddy webserver output is redirected to a file.\nTo inspect the webserver logs, navigate to the Bridge container group in Azure Portal (whose name starts with `iotc-container-groups-`), under `Containers` select the `caddy-ssl-server` container. Click the `Connect` tab and select `/bin/sh`. The logs\nwill be in the `/tmp/caddy.log` file. To see the last 10 lines of logs, use the command `tail -n 10 /tmp/caddy.log`, as in the image below:\n\n![Webserver logs](Docs/Assets/caddy-logs.png \"webserver logs\")\n\n## Custom adapters\nOne of the possible ways to extend the functionality of this Bridge is through a custom adapter deployed as a sidecar container.\nWith this type of adapter, which can be written in the language and runtime of your choice, you can for instance transform\nthe data before it reaches or leaves the Bridge and connect to different data sources. Under the `Samples/SampleTypeScriptAdapter`\nfolder we provide an example of a custom adapter written in TypeScript that forwards cloud-to-device messages to an EventHub.\nThis adapter uses a client automatically generated with [AutoRest](https://github.com/Azure/autorest) using the Bridge swagger available\nunder `Docs/swagger.json`. The example also contains the necessary ARM template to deploy it as a sidecar with the Bridge.\n\nFor scenarios that require JSON to JSON transformation of telemetry payloads and changes to the main telemetry API\n(e.g., exposing different telemetry endpoints, accepting the device Id and API key in different formats), we provide a\nparametrized adapter under [Samples/custom-transform-adapter](https://github.com/iot-for-all/iotc-device-bridge/tree/main/Samples/custom-transform-adapter)\nthat requires no additional code. This adapter can be customized through a simple configuration JSON file. This component might\nbe useful, for instance, in a scenario where device payloads can't be modified in the source and can only be sent to a fixed URL\n(i.e., that doesn't include a variable parameter, such as device Id).\n\nWe also provide an example of how to deploy multiple adapters (`Samples/MultipleAdapterDeployment`). In this setup,\neach adapter is deployed as a separate container and requests are routed based on the path.\n\nThe diagrams below illustrate the original Bridge architecture and how a custom adapter fits into it:\n\n![Original architecture](Docs/Assets/original-architecture.png \"original architecture\")\n![Adapter architecture](Docs/Assets/adapter-architecture.png \"adapter architecture\")\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fazure%2Fiot-central-bidirectional-device-bridge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fazure%2Fiot-central-bidirectional-device-bridge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fazure%2Fiot-central-bidirectional-device-bridge/lists"}