static async Task <int> MainAsync() { Console.WriteLine($"{DateTime.Now.ToLocalTime()}>\t The PumpSimulator Main() has started."); SetupTelemetry(); try { RetrieveSettingsFromConfig(); var simulatorParameters = SimulatorParameters.Create(); (CancellationTokenSource cts, ManualResetEventSlim completed, Option <object> handler) = ShutdownHandler.Init(TimeSpan.FromSeconds(5), null); Console.WriteLine( $"Initializing simulated sensor to send {(SendUnlimitedMessages(messageCount) ? "unlimited" : messageCount.ToString())} " + $"messages, at an interval of {messageDelay.TotalSeconds} seconds.\n" + $"To change this, set the environment variable {MessageCountConfigKey} to the number of messages that should be sent (set it to -1 to send unlimited messages)."); moduleClient = await ModuleUtil.CreateModuleClientAsync( protocol, ModuleUtil.DefaultTimeoutErrorDetectionStrategy, ModuleUtil.DefaultTransientRetryStrategy); ModuleClient userContext = moduleClient; reportedProperties = new TwinCollection(); await moduleClient.SetDesiredPropertyUpdateCallbackAsync(OnDesiredPropertiesUpdated, userContext); await moduleClient.SetMethodHandlerAsync("reset", ResetMethod, null); await moduleClient.SetMethodHandlerAsync("ping", PingMethod, null); await moduleClient.SetMethodHandlerAsync("check", CheckMethod, null); await moduleClient.SetInputMessageHandlerAsync("control", ControlMessageHandle, userContext); await RetrieveSettingsFromTwin(moduleClient); await SendEvents(moduleClient, messageCount, simulatorParameters, cts); await cts.Token.WhenCanceled(); completed.Set(); handler.ForEach(h => GC.KeepAlive(h)); Console.WriteLine("SimulatedTemperatureSensor Main() finished."); return(0); } catch (System.Exception ex) { Console.WriteLine($"{DateTime.Now.ToLocalTime()}>\t PumpSimulator Main() error."); Console.WriteLine(ex.Message); var telemetry = new ExceptionTelemetry(ex); telemetryClient.TrackException(telemetry); return(-1); } }
/// <summary> /// Module behavior: /// Sends data periodically (with default frequency of 5 seconds). /// Data trend: /// - Temperature regularly rises from 21C to 100C in regularly with jitter /// - Pressure correlates with Temperature 1 to 10psi /// - Suction Pressure stable around 5psi /// - Discharge Pressure stable around 5psi /// - Ambient temperature stable around 21C /// - Flow is stable with tiny jitter around 25% /// Method for resetting the data stream /// </summary> static async Task SendEvents( ModuleClient moduleClient, int messageCount, SimulatorParameters sim, CancellationTokenSource cts) { int count = 1; double currentTemp = sim.TempMin; double normal = (sim.PressureMax - sim.PressureMin) / (sim.TempMax - sim.TempMin); while (!cts.Token.IsCancellationRequested && (SendUnlimitedMessages(messageCount) || messageCount >= count)) { if (Reset) { currentTemp = sim.TempMin; Reset.Set(false); } if (currentTemp > sim.TempMax) { currentTemp += Rnd.NextDouble() - 0.5; // add value between [-0.5..0.5] } else { currentTemp += -0.25 + (Rnd.NextDouble() * 1.5); // add value between [-0.25..1.25] - average +0.5 } if (sendData) { var events = new List <MessageEvent>(); var deviceId = Environment.MachineName + "-" + Environment.GetEnvironmentVariable("DEVICE"); // Add Desired Number of Events into the Message for (int i = 0; i < eventCount; i++) { events.Add(new MessageEvent { DeviceId = deviceId + "-" + i, TimeStamp = DateTime.UtcNow, Temperature = new SensorReading { Value = currentTemp, Units = "degC", Status = 200 }, Pressure = new SensorReading { Value = sim.PressureMin + ((currentTemp - sim.TempMin) * normal), Units = "psig", Status = 200 }, SuctionPressure = new SensorReading { Value = sim.PressureMin + 4 + ((currentTemp - sim.TempMin) * normal), Units = "psig", Status = 200 }, DischargePressure = new SensorReading { Value = sim.PressureMin + 1 + ((currentTemp - sim.TempMin) * normal), Units = "psig", Status = 200 }, Flow = new SensorReading { Value = Rnd.Next(78, 82), Units = "perc", Status = 200 } }); currentTemp += -0.25 + (Rnd.NextDouble() * 1.5); } var msgBody = new MessageBody { Asset = Environment.GetEnvironmentVariable("ASSET") ?? "whidbey", Source = Environment.MachineName, Events = events }; string dataBuffer = JsonConvert.SerializeObject(msgBody); var eventMessage = new Message(Encoding.UTF8.GetBytes(dataBuffer)); eventMessage.Properties.Add("sequenceNumber", count.ToString()); eventMessage.Properties.Add("batchId", BatchId.ToString()); eventMessage.Properties.Add("asset", msgBody.Asset); var size = eventMessage.GetBytes().Length; if (debug) { Console.WriteLine($"\t{DateTime.Now.ToLocalTime()}> Sending message: {count}, Size: {size}, Body: [{dataBuffer}]"); } else { Console.WriteLine($"\t{DateTime.Now.ToLocalTime()}> Sending message: {count}, Size: {size}"); } try { if (insights) { telemetryClient.GetMetric("SendMessage").TrackValue(1); telemetryClient.Context.Operation.Name = "Special Operation"; Metric sizeStats = telemetryClient.GetMetric("Special Operation Message Size"); sizeStats.TrackValue(size); } await moduleClient.SendEventAsync("temperatureOutput", eventMessage); } catch (Microsoft.Azure.Devices.Client.Exceptions.MessageTooLargeException exception) { Console.WriteLine(exception.Message); if (insights) { telemetryClient.GetMetric("MessageSizeExceeded").TrackValue(1); } } count++; } await Task.Delay(messageDelay, cts.Token); } if (messageCount < count) { Console.WriteLine($"Done sending {messageCount} messages"); } }