For C2D messaging to work a device must have a DeviceClient “connection” established to the Azure IoT Hub which is a problem for irregularly connect devices. Sometimes establishing a connection on the first D2C messages is sufficient, especially for devices which only support D2C messaging. An Identity Translation Gateway establishes a connection for each device (see discussion about AMQP Connection multiplexing) so that C2D messages can be sent immediately.
I initially tried building a cache loader with BackgroundService so that the DeviceClient cache would start loading as the application started but interdependencies became problem.
public partial class Connector
{
[Function("BumblebeeHiveCacheRefresh")]
public async Task<IActionResult> BumblebeeHiveCacheRefreshRun([HttpTrigger(AuthorizationLevel.Function, "get")] CancellationToken cancellationToken)
{
_logger.LogInformation("BumblebeeHiveCacheRefresh start");
await _swarmSpaceBumblebeeHive.Login(cancellationToken);
foreach (SwarmSpace.BumblebeeHiveClient.Device device in await _swarmSpaceBumblebeeHive.DeviceListAsync(cancellationToken))
{
_logger.LogInformation("BumblebeeHiveCacheRefresh DeviceId:{DeviceId} DeviceName:{DeviceName}", device.DeviceId, device.DeviceName);
Models.AzureIoTDeviceClientContext context = new Models.AzureIoTDeviceClientContext()
{
// TODO seems a bit odd getting this from application settings
OrganisationId = _applicationSettings.OrganisationId,
//UserApplicationId = device.UserApplicationId, deprecated
DeviceType = (byte)device.DeviceType,
DeviceId = (uint)device.DeviceId,
};
switch (_azureIoTSettings.ApplicationType)
{
case Models.ApplicationType.AzureIotHub:
switch (_azureIoTSettings.AzureIotHub.ConnectionType)
{
case Models.AzureIotHubConnectionType.DeviceConnectionString:
await _azureDeviceClientCache.GetOrAddAsync<DeviceClient>(device.DeviceId.ToString(), (ICacheEntry x) => AzureIoTHubDeviceConnectionStringConnectAsync(device.DeviceId.ToString(), context));
break;
case Models.AzureIotHubConnectionType.DeviceProvisioningService:
await _azureDeviceClientCache.GetOrAddAsync<DeviceClient>(device.DeviceId.ToString(), (ICacheEntry x) => AzureIoTHubDeviceProvisioningServiceConnectAsync(device.DeviceId.ToString(), context, _azureIoTSettings.AzureIotHub.DeviceProvisioningService));
break;
default:
_logger.LogError("Azure IoT Hub ConnectionType unknown {0}", _azureIoTSettings.AzureIotHub.ConnectionType);
throw new NotImplementedException("AzureIoT Hub unsupported ConnectionType");
}
break;
case Models.ApplicationType.AzureIoTCentral:
await _azureDeviceClientCache.GetOrAddAsync<DeviceClient>(device.DeviceId.ToString(), (ICacheEntry x) => AzureIoTHubDeviceProvisioningServiceConnectAsync(device.DeviceId.ToString(), context, _azureIoTSettings.AzureIoTCentral.DeviceProvisioningService));
break;
default:
_logger.LogError("AzureIoT application type unknown {0}", _azureIoTSettings.ApplicationType);
throw new NotImplementedException("AzureIoT unsupported ApplicationType");
}
}
_logger.LogInformation("BumblebeeHiveCacheRefresh finish");
return new OkResult();
}
}
The HTTP WEBSITE_WARMUP_PATH environment variable is used to call the Azure HTTPTrigger Function and this is secured with an x-functions-key header.
In the short-term loading the cache with a call to an Azure HTTPTrigger Function works but may timeout issues. When I ran the connector with my 100’s of devices simulator the function timed out every so often.
