public async Task DeleteAllDevicesAsync(SimulationIoTHubOptions simulationIoTHubOptions)
        {
            var deleteDevicesActor    = ActorProxy.Create <IDeviceSimulator>(new ActorId(Guid.NewGuid().ToString()), deviceActorApplicationUri);
            var deviceServiceSettings = new DeviceServiceSettings()
            {
                IoTHubConnectionString = simulationIoTHubOptions.IotHubConnectionString,
                IoTHubName             = simulationIoTHubOptions.IoTHubName,
            };

            await deleteDevicesActor.CleanDevicesAsync(deviceServiceSettings, CancellationToken.None);
        }
        public async Task RunSimulationAsync(string simulationId, string simulationName, IEnumerable <SimulationItem> simulationItems, SimulationIoTHubOptions simulationIoTHubOptions)
        {
            var linkOptions = new DataflowLinkOptions {
                PropagateCompletion = true
            };
            var addDeviceBlock = new TransformBlock <DeviceBlockInformation, DeviceBlockInformation>(async(deviceBlockInformation) =>
            {
                await deviceBlockInformation.DeviceSimulatorActor.AddDeviceAsync(deviceBlockInformation.DeviceSettings.DeviceServiceSettings, CancellationToken.None);
                return(deviceBlockInformation);
            }, new ExecutionDataflowBlockOptions()
            {
                MaxDegreeOfParallelism = 4
            });

            var createTwinBlock = new TransformBlock <DeviceBlockInformation, DeviceBlockInformation>(async(deviceBlockInformation) =>
            {
                await deviceBlockInformation.DeviceSimulatorActor.CreateDeviceTwinAsync(deviceBlockInformation.DeviceSettings.DeviceServiceSettings, CancellationToken.None);
                return(deviceBlockInformation);
            });

            var connectToHubBlock = new TransformBlock <DeviceBlockInformation, DeviceBlockInformation>(async(deviceBlockInformation) =>
            {
                await deviceBlockInformation.DeviceSimulatorActor.ConnectToHubAsync(deviceBlockInformation.DeviceSettings, CancellationToken.None);
                return(deviceBlockInformation);
            });

            ActionBlock <DeviceBlockInformation> sendEventBlock = null;

            sendEventBlock = new ActionBlock <DeviceBlockInformation>(async(deviceBlockInformation) =>
            {
                await deviceBlockInformation.DeviceSimulatorActor.SendEventAsync();
                await Task.Delay(deviceBlockInformation.DeviceSettings.DeviceServiceSettings.DeviceInterval);
            });

            addDeviceBlock.LinkTo(createTwinBlock, linkOptions);
            createTwinBlock.LinkTo(connectToHubBlock, linkOptions);
            connectToHubBlock.LinkTo(sendEventBlock, linkOptions);

            // Enumerate the simulations and begin to stand up device instances for each one
            foreach (var simulationItem in simulationItems)
            {
                // Begin producing
                var deviceItems = Enumerable.Range(0, simulationItem.NumberOfDevices);
                foreach (var deviceIndex in deviceItems)
                {
                    // Generate a unique id for this device
                    var deviceNumber = deviceIndex.ToString("000000");
                    var deviceId     = $"{simulationName}_{simulationItem.DeviceType}_{deviceNumber}";

                    var deviceSimulatorActor = ActorProxy.Create <IDeviceSimulator>(new ActorId(deviceId), deviceActorApplicationUri);
                    var deviceSettings       = new DeviceSettings()
                    {
                        InitialStateJson   = simulationItem.InitialState,
                        Script             = simulationItem.Script,
                        MessageType        = simulationItem.MessageType,
                        SimulationSettings = new SimulationSettings()
                        {
                            SimulationId   = simulationId,
                            SimulationName = simulationName
                        },
                        Properties            = simulationItem.Properties,
                        DeviceServiceSettings = new DeviceServiceSettings()
                        {
                            DeviceType             = simulationItem.DeviceType,
                            DeviceName             = deviceId,
                            IoTHubConnectionString = simulationIoTHubOptions.IotHubConnectionString,
                            IoTHubName             = simulationIoTHubOptions.IoTHubName,
                            DeviceInterval         = simulationItem.Interval,
                        }
                    };

                    await addDeviceBlock.SendAsync(new DeviceBlockInformation()
                    {
                        DeviceSimulatorActor = deviceSimulatorActor,
                        DeviceSettings       = deviceSettings,
                    });
                }
            }

            // Signal that we've completed adding all the devices
            addDeviceBlock.Complete();

            // Wait for all the devices to be running their simulations
            await sendEventBlock.Completion;
        }