public void LogDataLightSensor(LightSensorReading reading) { LoggingFields loggingFields = new LoggingFields(); loggingFields.AddString("Timestamp", reading.Timestamp.ToString()); loggingFields.AddDouble("IlluminanceInLux", reading.IlluminanceInLux); rootPage.loggingChannelView.LogEvent("LightSensorData", loggingFields); }
private void SensorValueupload(object state) { try { // Air sensor readings double temperatureCelsius = bme280Sensor.Temperature.DegreesCelsius; double temperatureFahrenheit = bme280Sensor.Temperature.DegreesFahrenheit; double humidity = bme280Sensor.Humidity; double pressure = bme280Sensor.Pressure.Kilopascals; double lightLevel = GroveBaseHatAnalogPorts.Read(AnalogPorts.AnalogPort.A0); double soilMoisture1 = GroveBaseHatAnalogPorts.Read(AnalogPorts.AnalogPort.A2); double soilMoisture2 = GroveBaseHatAnalogPorts.Read(AnalogPorts.AnalogPort.A4); LoggingService.Log(string.Format("C {0:0.0}° F {1:0.0}° H {2:0}% P {3:0.000}kPa L {4:0}% Soil1 {5:0}% Soil2 {6:0}% ", temperatureCelsius, temperatureFahrenheit, humidity, pressure, lightLevel, soilMoisture1, soilMoisture2)); // Setup for the the logging of sensor values var loggingData = new LoggingFields(); // Construct Azure IoT Central friendly payload var telemetryDataPoint = new TelemetryDataPoint(); telemetryDataPoint.Celsius = temperatureCelsius; loggingData.AddDouble(nameof(telemetryDataPoint.Celsius), temperatureCelsius); telemetryDataPoint.Fahrenheit = temperatureFahrenheit; loggingData.AddDouble(nameof(telemetryDataPoint.Fahrenheit), temperatureFahrenheit); telemetryDataPoint.Humidity = humidity; loggingData.AddDouble(nameof(telemetryDataPoint.Humidity), humidity); telemetryDataPoint.Pressure = pressure; loggingData.AddDouble(nameof(telemetryDataPoint.Pressure), pressure); telemetryDataPoint.Light = lightLevel; loggingData.AddDouble(nameof(telemetryDataPoint.Light), lightLevel); telemetryDataPoint.SoilMoisture1 = soilMoisture1; loggingData.AddDouble(nameof(telemetryDataPoint.SoilMoisture1), soilMoisture1); telemetryDataPoint.SoilMoisture2 = soilMoisture2; loggingData.AddDouble(nameof(telemetryDataPoint.SoilMoisture2), soilMoisture2); // Log the sensor values to ETW logging LoggingService.LogEvent("Sensor readings", loggingData, LoggingLevel.Verbose); using (var message = new Message(Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(telemetryDataPoint)))) { LoggingService.Log("AzureIoTHubClient SendEventAsync starting"); azureIoTHubClient.SendEventAsync(message).Wait(); LoggingService.Log("AzureIoTHubClient SendEventAsync finished"); } } catch (Exception ex) { LoggingService.Error("Failed to send telemetry", ex); } }
public void Run(IBackgroundTaskInstance taskInstance) { StorageFolder localFolder = ApplicationData.Current.LocalFolder; try { // see if the configuration file is present if not copy minimal sample one from application directory if (localFolder.TryGetItemAsync(ConfigurationFilename).AsTask().Result == null) { StorageFile templateConfigurationfile = Package.Current.InstalledLocation.GetFileAsync(ConfigurationFilename).AsTask().Result; templateConfigurationfile.CopyAsync(localFolder, ConfigurationFilename).AsTask(); } // Load the settings from configuration file exit application if missing or invalid StorageFile file = localFolder.GetFileAsync(ConfigurationFilename).AsTask().Result; applicationSettings = (JsonConvert.DeserializeObject <ApplicationSettings>(FileIO.ReadTextAsync(file).AsTask().Result)); } catch (Exception ex) { this.logging.LogMessage("JSON configuration file load failed " + ex.Message, LoggingLevel.Error); return; } // Log the Application build, shield information etc. LoggingFields appllicationBuildInformation = new LoggingFields(); #if DRAGINO appllicationBuildInformation.AddString("Shield", "DraginoLoRaGPSHat"); #endif #if ELECROW appllicationBuildInformation.AddString("Shield", "ElecrowRFM95IoTBoard"); #endif #if M2M appllicationBuildInformation.AddString("Shield", "M2M1ChannelLoRaWanGatewayShield"); #endif #if ELECTRONIC_TRICKS appllicationBuildInformation.AddString("Shield", "ElectronicTricksLoRaLoRaWANShield"); #endif #if UPUTRONICS_RPIZERO_CS0 appllicationBuildInformation.AddString("Shield", "UputronicsPiZeroLoRaExpansionBoardCS0"); #endif #if UPUTRONICS_RPIZERO_CS1 appllicationBuildInformation.AddString("Shield", "UputronicsPiZeroLoRaExpansionBoardCS1"); #endif #if UPUTRONICS_RPIPLUS_CS0 appllicationBuildInformation.AddString("Shield", "UputronicsPiPlusLoRaExpansionBoardCS0"); #endif #if UPUTRONICS_RPIPLUS_CS1 appllicationBuildInformation.AddString("Shield", "UputronicsPiPlusLoRaExpansionBoardCS1"); #endif #if ADAFRUIT_RADIO_BONNET appllicationBuildInformation.AddString("Shield", "AdafruitRadioBonnet"); #endif appllicationBuildInformation.AddString("Timezone", TimeZoneSettings.CurrentTimeZoneDisplayName); appllicationBuildInformation.AddString("OSVersion", Environment.OSVersion.VersionString); appllicationBuildInformation.AddString("MachineName", Environment.MachineName); // This is from the application manifest Package package = Package.Current; PackageId packageId = package.Id; PackageVersion version = packageId.Version; appllicationBuildInformation.AddString("ApplicationVersion", string.Format($"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}")); this.logging.LogEvent("Application starting", appllicationBuildInformation, LoggingLevel.Information); // Configure the AdaFruit API client LoggingFields adaFruitIOSettings = new LoggingFields(); if (!string.IsNullOrEmpty(this.applicationSettings.AdaFruitIOBaseUrl)) { this.adaFruitIOClient.BaseUrl = this.applicationSettings.AdaFruitIOBaseUrl; adaFruitIOSettings.AddString("BaseURL", this.applicationSettings.AdaFruitIOBaseUrl); } this.adaFruitIOClient.ApiKey = this.applicationSettings.AdaFruitIOApiKey; adaFruitIOSettings.AddString("APIKey", this.applicationSettings.AdaFruitIOApiKey); adaFruitIOSettings.AddString("UserName", this.applicationSettings.AdaFruitIOUserName); adaFruitIOSettings.AddString("GroupName", this.applicationSettings.AdaFruitIOGroupName); this.logging.LogEvent("AdaFruit.IO configuration", adaFruitIOSettings, LoggingLevel.Information); rfm9XDevice.OnReceive += Rfm9XDevice_OnReceive; rfm9XDevice.OnTransmit += Rfm9XDevice_OnTransmit; rfm9XDevice.Initialise(this.applicationSettings.Frequency, rxDoneignoreIfCrcMissing: true, rxDoneignoreIfCrcInvalid: true, paBoost: this.applicationSettings.PABoost, maxPower: this.applicationSettings.MaxPower, outputPower: this.applicationSettings.OutputPower, ocpOn: this.applicationSettings.OCPOn, ocpTrim: this.applicationSettings.OCPTrim, lnaGain: this.applicationSettings.LnaGain, lnaBoost: this.applicationSettings.LNABoost, bandwidth: this.applicationSettings.Bandwidth, codingRate: this.applicationSettings.CodingRate, implicitHeaderModeOn: this.applicationSettings.ImplicitHeaderModeOn, spreadingFactor: this.applicationSettings.SpreadingFactor, rxPayloadCrcOn: true, symbolTimeout: this.applicationSettings.SymbolTimeout, preambleLength: this.applicationSettings.PreambleLength, payloadLength: this.applicationSettings.PayloadLength, payloadMaxLength: this.applicationSettings.PayloadMaxLength, freqHoppingPeriod: this.applicationSettings.FreqHoppingPeriod, lowDataRateOptimize: this.applicationSettings.LowDataRateOptimize, ppmCorrection: this.applicationSettings.PpmCorrection, detectionOptimize: this.applicationSettings.DetectionOptimize, invertIQ: this.applicationSettings.InvertIQ, detectionThreshold: this.applicationSettings.DetectionThreshold, syncWord: this.applicationSettings.SyncWord ); #if DEBUG rfm9XDevice.RegisterDump(); #endif rfm9XDevice.Receive(Encoding.UTF8.GetBytes(this.applicationSettings.Address)); LoggingFields loRaSettings = new LoggingFields(); loRaSettings.AddString("Address", this.applicationSettings.Address); loRaSettings.AddDouble("Frequency", this.applicationSettings.Frequency); loRaSettings.AddBoolean("PABoost", this.applicationSettings.PABoost); loRaSettings.AddUInt8("MaxPower", this.applicationSettings.MaxPower); loRaSettings.AddUInt8("OutputPower", this.applicationSettings.OutputPower); loRaSettings.AddBoolean("OCPOn", this.applicationSettings.OCPOn); loRaSettings.AddUInt8("OCPTrim", this.applicationSettings.OCPTrim); loRaSettings.AddString("LnaGain", this.applicationSettings.LnaGain.ToString()); loRaSettings.AddBoolean("lnaBoost", this.applicationSettings.LNABoost); loRaSettings.AddString("codingRate", this.applicationSettings.CodingRate.ToString()); loRaSettings.AddString("implicitHeaderModeOn", applicationSettings.ImplicitHeaderModeOn.ToString()); loRaSettings.AddString("spreadingFactor", this.applicationSettings.SpreadingFactor.ToString()); loRaSettings.AddBoolean("rxPayloadCrcOn", true); loRaSettings.AddUInt8("symbolTimeout", this.applicationSettings.SymbolTimeout); loRaSettings.AddUInt8("preambleLength", this.applicationSettings.PreambleLength); loRaSettings.AddUInt8("payloadLength", this.applicationSettings.PayloadLength); loRaSettings.AddUInt8("payloadMaxLength", this.applicationSettings.PayloadMaxLength); loRaSettings.AddUInt8("freqHoppingPeriod", this.applicationSettings.FreqHoppingPeriod); loRaSettings.AddBoolean("lowDataRateOptimize", this.applicationSettings.LowDataRateOptimize); loRaSettings.AddUInt8("ppmCorrection", this.applicationSettings.PpmCorrection); loRaSettings.AddString("detectionOptimize", this.applicationSettings.DetectionOptimize.ToString()); loRaSettings.AddBoolean("invertIQ", this.applicationSettings.InvertIQ); loRaSettings.AddString("detectionThreshold", this.applicationSettings.DetectionThreshold.ToString()); loRaSettings.AddUInt8("SyncWord", this.applicationSettings.SyncWord); this.logging.LogEvent("LoRa configuration", loRaSettings, LoggingLevel.Information); this.deferral = taskInstance.GetDeferral(); }
private async void Rfm9XDevice_OnReceive(object sender, Rfm9XDevice.OnDataReceivedEventArgs e) { string addressBcdText; string messageBcdText; string messageText = ""; char[] sensorReadingSeparator = new char[] { ',' }; char[] sensorIdAndValueSeparator = new char[] { ' ' }; addressBcdText = BitConverter.ToString(e.Address); messageBcdText = BitConverter.ToString(e.Data); try { messageText = UTF8Encoding.UTF8.GetString(e.Data); } catch (Exception) { this.logging.LogMessage("Failure converting payload to text", LoggingLevel.Error); return; } #if DEBUG Debug.WriteLine(@"{0:HH:mm:ss}-RX From {1} PacketSnr {2:0.0} Packet RSSI {3}dBm RSSI {4}dBm = {5} byte message ""{6}""", DateTime.Now, addressBcdText, e.PacketSnr, e.PacketRssi, e.Rssi, e.Data.Length, messageText); #endif LoggingFields messagePayload = new LoggingFields(); messagePayload.AddInt32("AddressLength", e.Address.Length); messagePayload.AddString("Address-BCD", addressBcdText); messagePayload.AddInt32("Message-Length", e.Data.Length); messagePayload.AddString("Message-BCD", messageBcdText); messagePayload.AddString("Nessage-Unicode", messageText); messagePayload.AddDouble("Packet SNR", e.PacketSnr); messagePayload.AddInt32("Packet RSSI", e.PacketRssi); messagePayload.AddInt32("RSSI", e.Rssi); this.logging.LogEvent("Message Data", messagePayload, LoggingLevel.Verbose); // Check the address is not to short/long if (e.Address.Length < AddressLengthMinimum) { this.logging.LogMessage("From address too short", LoggingLevel.Warning); return; } if (e.Address.Length > MessageLengthMaximum) { this.logging.LogMessage("From address too long", LoggingLevel.Warning); return; } // Check the payload is not too short/long if (e.Data.Length < MessageLengthMinimum) { this.logging.LogMessage("Message too short to contain any data", LoggingLevel.Warning); return; } if (e.Data.Length > MessageLengthMaximum) { this.logging.LogMessage("Message too long to contain valid data", LoggingLevel.Warning); return; } // Adafruit IO is case sensitive & onlye does lower case ? string deviceId = addressBcdText.ToLower(); // Chop up the CSV text payload string[] sensorReadings = messageText.Split(sensorReadingSeparator, StringSplitOptions.RemoveEmptyEntries); if (sensorReadings.Length == 0) { this.logging.LogMessage("Payload contains no sensor readings", LoggingLevel.Warning); return; } Group_feed_data groupFeedData = new Group_feed_data(); LoggingFields sensorData = new LoggingFields(); sensorData.AddString("DeviceID", deviceId); // Chop up each sensor reading into an ID & value foreach (string sensorReading in sensorReadings) { string[] sensorIdAndValue = sensorReading.Split(sensorIdAndValueSeparator, StringSplitOptions.RemoveEmptyEntries); // Check that there is an id & value if (sensorIdAndValue.Length != 2) { this.logging.LogMessage("Sensor reading invalid format", LoggingLevel.Warning); return; } string sensorId = sensorIdAndValue[0].ToLower(); string value = sensorIdAndValue[1]; // Construct the sensor ID from SensordeviceID & Value ID groupFeedData.Feeds.Add(new Anonymous2() { Key = string.Format("{0}{1}", deviceId, sensorId), Value = value }); sensorData.AddString(sensorId, value); Debug.WriteLine(" Sensor {0}{1} Value {2}", deviceId, sensorId, value); } this.logging.LogEvent("Sensor readings", sensorData, LoggingLevel.Verbose); try { Debug.WriteLine(" CreateGroupDataAsync start"); await this.adaFruitIOClient.CreateGroupDataAsync(this.applicationSettings.AdaFruitIOUserName, this.applicationSettings.AdaFruitIOGroupName.ToLower(), groupFeedData); Debug.WriteLine(" CreateGroupDataAsync finish"); } catch (Exception ex) { Debug.WriteLine(" CreateGroupDataAsync failed {0}", ex.Message); this.logging.LogMessage("CreateGroupDataAsync failed " + ex.Message, LoggingLevel.Error); } }
/// <summary> /// This method demonstrates the LoggingChannel and LoggingActivity APIs. /// </summary> /// <param name="channel"> /// The channel to use for the demonstration. This channel may have been /// constructed using a Windows 8.1 constructor or a Windows 10 constructor. /// The same APIs are supported in both cases, but the ETL events will be /// formatted a bit differently depending on how the channel was constructed. /// </param> private void DemonstrateLogging(LoggingChannel channel) { // Whenever any ETW session changes the way it is listening to this // channel, the LoggingEnable event is fired. For example, this might // be called when a session begins listening, changes the level at // which it is listening, or stops listening. channel.LoggingEnabled += this.OnLoggingEnabled; // Log simple string events channel.LogMessage("Simple message"); // default level is Verbose channel.LogMessage("Simple error", LoggingLevel.Error); // Log simple string + integer events. channel.LogValuePair("Simple message", 123); // default level is Verbose channel.LogValuePair("Simple error", 456, LoggingLevel.Error); // The channel.Name property returns the name that was used when the // channel was constructed. When running in Windows 10 mode, the name // is already set as the provider name, so no LoggingChannelName is // automatically added to the event. channel.LogMessage(channel.Name); // The channel.Id property is new to Windows 10. channel.LogMessage(channel.Id.ToString()); // If you want to avoid the overhead of collecting data when nobody is // listening to your channel, check the Enabled property before logging. if (channel.Enabled) { channel.LogMessage(this.CollectExpensiveData()); } // The IsEnabled() method is exactly the same as the Enabled property, // except that it is a new Windows 10 API. if (channel.IsEnabled()) { channel.LogMessage(this.CollectExpensiveData()); } // If you want to only collect data if somebody is listening at a specific // level, you need to check both Enabled and Level. Note that the value of // the Level is unspecified when Enabled is false. if (channel.Enabled && channel.Level <= LoggingLevel.Warning) { channel.LogMessage(this.CollectExpensiveData(), LoggingLevel.Warning); } // The IsEnabled(LoggingLevel) method is a bit nicer than checking both // Enabled and Level, but it is only available on Windows 10 or later. if (channel.IsEnabled(LoggingLevel.Warning)) { channel.LogMessage(this.CollectExpensiveData(), LoggingLevel.Warning); } // You can also use IsEnabled to check for keywords. if (channel.IsEnabled(LoggingLevel.Information, 0x10)) { channel.LogMessage(this.CollectExpensiveData(), LoggingLevel.Information); } // Use LoggingFields with the LogEvent method to write complex events. var fields = new LoggingFields(); fields.AddDouble("pi", 3.14159); channel.LogEvent( "ComplexEvent", fields, LoggingLevel.Verbose, new LoggingOptions(0x10)); // Keywords = 0x10 // You can add any number of name-value pairs to a fields object, though // you may encounter ETW limitations if you add too many. For example, // ETW is limited to a maximum event size of 64KB, and the current // TraceLogging decoder can handle no more than 128 fields. // Performance optimization: You can reuse a LoggingFields object to // avoid unnecessary allocations. Don't forget to call Clear() // between uses, and don't try to share a LoggingFields object between // threads. fields.Clear(); fields.AddDateTime("Date", DateTimeOffset.Now); channel.LogEvent("Now", fields); fields.Clear(); // You can add a formatting hint to affect the way a value is decoded. // Not all combinations are useful, and the hint may be ignored. // For example, you can encode an MBCS string by writing a byte array // with a String hint. fields.AddUInt8Array( "AnsiString", new byte[] { 65, 66, 67, 49, 50, 51 }, // "ABC123" LoggingFieldFormat.String); // You can add "tag" bits to a field. These are user-defined bits that // can be used to communicate with an event processing tool. For example, // you might define a tag bit to indicate that a field contains private // data that should not be displayed on-screen. fields.AddString("Password", "12345", LoggingFieldFormat.Default, 0x10); // You can add a "structure" to an event. A structure is a name for a // group of fields. Structures can nest. Call BeginStruct to add a level // of nesting, and call EndStruct after the last field of the structure. fields.BeginStruct("Nested"); fields.AddInt16("Nested-1", 1); fields.AddInt16("Nested-2", 2); fields.BeginStruct("Nested-Nested"); fields.AddInt16("Nested-Nested-3", 3); fields.EndStruct(); fields.AddInt16("Nested-4", 4); fields.EndStruct(); // Advanced scenarios: you can use a LoggingOptions object to control // detailed event settings such as keywords, opcodes, and activity Ids. // These have their normal ETW semantics. You can also set event tags, // which are bit values that can be used to communicate with the event // processor. channel.LogEvent( "VeryComplexEvent", fields, LoggingLevel.Information, new LoggingOptions { Keywords = 0x123, Tags = 0x10 }); // Windows 10 introduces the ILoggingTarget interface. LoggingChannel // implements this interface. This interface allows components to accept // a logger as an parameter. this.DoSomething(channel); /* * If a LoggingActivity is created using a LoggingActivity constructor, * it will use Windows 8.1 semantics: * * - If an activity is destroyed (garbage-collected) without being closed * and the associated LoggingChannel is still open, the activity will * write a default Stop event. * - The default Stop event (written by the destructor or by the Close() * method) is encoded as a "simple" event. * * The 8.1 semantics are deprecated because the automatic generation of * a Stop event at garbage-collection can be misleading. The Stop event * is intended to mark the a precise point at which an activity is * completed, while the garbage-collection of an abandoned activity is * inherently imprecise and unpredictable. * * If a LoggingActivity is created using a StartActivity method, it will * use Windows 10 semantics: * * - If an activity is destroyed (garbage-collected) without being closed, * there will be no Stop event for the activity. * - The default Stop event (written by the Close() method) is encoded as * a TraceLogging event with name "ActivityClosed". */ // This activity is created with Windows 8.1 semantics. using (var a1 = new LoggingActivity("Activity1", channel)) { // The activity Start event is written by the LoggingActivity constructor. // You would do your activity's work here. // The activity Stop event is written when the activity is closed (disposed). // The Windows 10 LoggingActivity adds new methods for writing events // that are marked as associated with the activity. a1.LogEvent("Activity event"); // LoggingActivity also implements the ILoggingTarget interface, so you can // use either a channel or an activity as a logging target. this.DoSomething(a1); // The Windows 10 LoggingActivity adds new methods for creating nested activities. // Note that nested activities are always created with Windows 10 semantics, // even when nested under an activity that is using Windows 8.1 semantics. using (var a2 = a1.StartActivity("Activity2")) { // Nested task occurs here. // The Windows 10 LoggingActivity allows you to customize the Stop event. a2.StopActivity("Activity 2 stop"); } // Because a1 is using Windows 8.1 semantics, if we did not call Dispose(), // it would attempt to write a Stop event when it is garbage collected. // Writing Stop events during garbage collection is not useful, so be sure // to properly stop, close, or dispose activities. } // The Windows 10 StartActivity method creates a new activity, optionally with // specified fields and characteristics. // This activity is created with Windows 10 semantics. using (var a3 = channel.StartActivity("Activity3")) { // Because a3 is using Windows 10 semantics, if we did not call Dispose(), // there would be no Stop event (not even when the activity is garbage // collected). To get a Stop event, be sure to stop, close, or dispose the // activity. } }
public void Run(IBackgroundTaskInstance taskInstance) { StorageFolder localFolder = ApplicationData.Current.LocalFolder; try { // see if the configuration file is present if not copy minimal sample one from application directory if (localFolder.TryGetItemAsync(ConfigurationFilename).AsTask().Result == null) { StorageFile templateConfigurationfile = Package.Current.InstalledLocation.GetFileAsync(ConfigurationFilename).AsTask().Result; templateConfigurationfile.CopyAsync(localFolder, ConfigurationFilename).AsTask(); } // Load the settings from configuration file exit application if missing or invalid StorageFile file = localFolder.GetFileAsync(ConfigurationFilename).AsTask().Result; applicationSettings = (JsonConvert.DeserializeObject <ApplicationSettings>(FileIO.ReadTextAsync(file).AsTask().Result)); } catch (Exception ex) { this.logging.LogMessage("JSON configuration file load failed " + ex.Message, LoggingLevel.Error); return; } // Log the Application build, shield information etc. LoggingFields applicationBuildInformation = new LoggingFields(); #if DRAGINO applicationBuildInformation.AddString("Shield", "DraginoLoRaGPSHat"); #endif #if ELECROW applicationBuildInformation.AddString("Shield", "ElecrowRFM95IoTBoard"); #endif #if M2M applicationBuildInformation.AddString("Shield", "M2M1ChannelLoRaWanGatewayShield"); #endif #if ELECTRONIC_TRICKS applicationBuildInformation.AddString("Shield", "ElectronicTricksLoRaLoRaWANShield"); #endif #if UPUTRONICS_RPIZERO_CS0 applicationBuildInformation.AddString("Shield", "UputronicsPiZeroLoRaExpansionBoardCS0"); #endif #if UPUTRONICS_RPIZERO_CS1 applicationBuildInformation.AddString("Shield", "UputronicsPiZeroLoRaExpansionBoardCS1"); #endif #if UPUTRONICS_RPIPLUS_CS0 applicationBuildInformation.AddString("Shield", "UputronicsPiPlusLoRaExpansionBoardCS0"); #endif #if UPUTRONICS_RPIPLUS_CS1 applicationBuildInformation.AddString("Shield", "UputronicsPiPlusLoRaExpansionBoardCS1"); #endif #if ADAFRUIT_RADIO_BONNET applicationBuildInformation.AddString("Shield", "AdafruitRadioBonnet"); #endif #if PAYLOAD_TEXT applicationBuildInformation.AddString("PayloadProcessor", "Text"); #endif #if PAYLOAD_TEXT_COMA_SEPARATED_VALUES applicationBuildInformation.AddString("PayloadProcessor", "ComaSeperatedValues"); #endif #if PAYLOAD_BINARY_BINARY_CODED_DECIMAL applicationBuildInformation.AddString("PayloadProcessor", "BinaryCodedDecimal"); #endif #if PAYLOAD_BINARY_CAYENNE_LOW_POWER_PAYLOAD applicationBuildInformation.AddString("PayloadProcessor", "CayenneLowPowerPayload"); #endif applicationBuildInformation.AddString("Timezone", TimeZoneSettings.CurrentTimeZoneDisplayName); applicationBuildInformation.AddString("OSVersion", Environment.OSVersion.VersionString); applicationBuildInformation.AddString("MachineName", Environment.MachineName); // This is from the application manifest Package package = Package.Current; PackageId packageId = package.Id; PackageVersion version = packageId.Version; applicationBuildInformation.AddString("ApplicationVersion", string.Format($"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}")); this.logging.LogEvent("Application starting", applicationBuildInformation, LoggingLevel.Information); // Log the MQTT connection string and associated settings LoggingFields mqttClientInformation = new LoggingFields(); mqttClientInformation.AddString("UserName", this.applicationSettings.MqttUserName); mqttClientInformation.AddString("Password", this.applicationSettings.MqttPassword); mqttClientInformation.AddString("Server", this.applicationSettings.MqttServer); mqttClientInformation.AddString("ClientID", this.applicationSettings.MqttClientID); mqttClientInformation.AddString("PlatformSpecificConfiguration", this.applicationSettings.PlatformSpecificConfiguration); this.logging.LogEvent("MQTT client configuration", mqttClientInformation, LoggingLevel.Information); // Connect the MQTT broker so we are ready for messages var factory = new MqttFactory(); this.mqttClient = factory.CreateMqttClient(); // Wire up a handler for disconnect event for retry mqttClient.UseDisconnectedHandler(new MqttClientDisconnectedHandlerDelegate(e => MqttClient_Disconnected(e))); mqttClient.UseApplicationMessageReceivedHandler(new MqttApplicationMessageReceivedHandlerDelegate(e => MqttClient_ApplicationMessageReceived(e))); try { this.mqttOptions = new MqttClientOptionsBuilder() .WithClientId(applicationSettings.MqttClientID) .WithTcpServer(applicationSettings.MqttServer) .WithCredentials(applicationSettings.MqttUserName, applicationSettings.MqttPassword) .WithTls() .Build(); this.mqttClient.ConnectAsync(this.mqttOptions).Wait(); } catch (Exception ex) { mqttClientInformation.AddString("Exception", ex.ToString()); this.logging.LogMessage("MQTT Connect Async failed" + ex.Message, LoggingLevel.Error); return; } // Load up the message handler assembly try { Assembly assembly = Assembly.Load(applicationSettings.MessageHandlerAssembly); messageHandler = (IMessageHandler)assembly.CreateInstance("devMobile.Mqtt.IoTCore.FieldGateway.MessageHandler"); if (messageHandler == null) { this.logging.LogMessage($"MessageHandler assembly {applicationSettings.MessageHandlerAssembly} load failed", LoggingLevel.Error); return; } messageHandler.Initialise(logging, mqttClient, rfm9XDevice, applicationSettings.PlatformSpecificConfiguration); } catch (Exception ex) { mqttClientInformation.AddString("Exception", ex.ToString()); this.logging.LogMessage("MessageHandler configuration failed" + ex.Message, LoggingLevel.Error); return; } // Configure the LoRa module rfm9XDevice.OnReceive += Rfm9XDevice_OnReceive; rfm9XDevice.OnTransmit += Rfm9XDevice_OnTransmit; rfm9XDevice.Initialise(this.applicationSettings.Frequency, rxDoneignoreIfCrcMissing: true, rxDoneignoreIfCrcInvalid: true, paBoost: this.applicationSettings.PABoost, maxPower: this.applicationSettings.MaxPower, outputPower: this.applicationSettings.OutputPower, ocpOn: this.applicationSettings.OCPOn, ocpTrim: this.applicationSettings.OCPTrim, lnaGain: this.applicationSettings.LnaGain, lnaBoost: this.applicationSettings.LNABoost, bandwidth: this.applicationSettings.Bandwidth, codingRate: this.applicationSettings.CodingRate, implicitHeaderModeOn: this.applicationSettings.ImplicitHeaderModeOn, spreadingFactor: this.applicationSettings.SpreadingFactor, rxPayloadCrcOn: true, symbolTimeout: this.applicationSettings.SymbolTimeout, preambleLength: this.applicationSettings.PreambleLength, payloadLength: this.applicationSettings.PayloadLength, payloadMaxLength: this.applicationSettings.PayloadMaxLength, freqHoppingPeriod: this.applicationSettings.FreqHoppingPeriod, lowDataRateOptimize: this.applicationSettings.LowDataRateOptimize, ppmCorrection: this.applicationSettings.PpmCorrection, detectionOptimize: this.applicationSettings.DetectionOptimize, invertIQ: this.applicationSettings.InvertIQ, detectionThreshold: this.applicationSettings.DetectionThreshold, syncWord: this.applicationSettings.SyncWord ); #if DEBUG rfm9XDevice.RegisterDump(); #endif rfm9XDevice.Receive(Encoding.UTF8.GetBytes(this.applicationSettings.Address)); LoggingFields loRaSettings = new LoggingFields(); loRaSettings.AddString("Address", this.applicationSettings.Address); loRaSettings.AddDouble("Frequency", this.applicationSettings.Frequency); loRaSettings.AddBoolean("PABoost", this.applicationSettings.PABoost); loRaSettings.AddUInt8("MaxPower", this.applicationSettings.MaxPower); loRaSettings.AddUInt8("OutputPower", this.applicationSettings.OutputPower); loRaSettings.AddBoolean("OCPOn", this.applicationSettings.OCPOn); loRaSettings.AddUInt8("OCPTrim", this.applicationSettings.OCPTrim); loRaSettings.AddString("LnaGain", this.applicationSettings.LnaGain.ToString()); loRaSettings.AddBoolean("lnaBoost", this.applicationSettings.LNABoost); loRaSettings.AddString("codingRate", this.applicationSettings.CodingRate.ToString()); loRaSettings.AddString("implicitHeaderModeOn", applicationSettings.ImplicitHeaderModeOn.ToString()); loRaSettings.AddString("spreadingFactor", this.applicationSettings.SpreadingFactor.ToString()); loRaSettings.AddBoolean("rxPayloadCrcOn", true); loRaSettings.AddUInt8("symbolTimeout", this.applicationSettings.SymbolTimeout); loRaSettings.AddUInt8("preambleLength", this.applicationSettings.PreambleLength); loRaSettings.AddUInt8("payloadLength", this.applicationSettings.PayloadLength); loRaSettings.AddUInt8("payloadMaxLength", this.applicationSettings.PayloadMaxLength); loRaSettings.AddUInt8("freqHoppingPeriod", this.applicationSettings.FreqHoppingPeriod); loRaSettings.AddBoolean("lowDataRateOptimize", this.applicationSettings.LowDataRateOptimize); loRaSettings.AddUInt8("ppmCorrection", this.applicationSettings.PpmCorrection); loRaSettings.AddString("detectionOptimize", this.applicationSettings.DetectionOptimize.ToString()); loRaSettings.AddBoolean("invertIQ", this.applicationSettings.InvertIQ); loRaSettings.AddString("detectionThreshold", this.applicationSettings.DetectionThreshold.ToString()); loRaSettings.AddUInt8("SyncWord", this.applicationSettings.SyncWord); this.logging.LogEvent("LoRa configuration", loRaSettings, LoggingLevel.Information); this.deferral = taskInstance.GetDeferral(); }
/// <summary> /// This method demonstrates the LoggingChannel and LoggingActivity APIs. /// </summary> /// <param name="channel"> /// The channel to use for the demonstration. This channel may have been /// constructed using a Windows 8.1 constructor or a Windows 10 constructor. /// The same APIs are supported in both cases, but the ETL events will be /// formatted a bit differently depending on how the channel was constructed. /// </param> private void DemonstrateLogging(LoggingChannel channel) { // Whenever any ETW session changes the way it is listening to this // channel, the LoggingEnable event is fired. For example, this might // be called when a session begins listening, changes the level at // which it is listening, or stops listening. channel.LoggingEnabled += this.OnLoggingEnabled; // Log simple string events channel.LogMessage("Simple message"); // default level is Verbose channel.LogMessage("Simple error", LoggingLevel.Error); // Log simple string + integer events. channel.LogValuePair("Simple message", 123); // default level is Verbose channel.LogValuePair("Simple error", 456, LoggingLevel.Error); // The channel.Name property returns the name that was used when the // channel was constructed. When running in Windows 10 mode, the name // is already set as the provider name, so no LoggingChannelName is // automatically added to the event. channel.LogMessage(channel.Name); // The channel.Id property is new to Windows 10. channel.LogMessage(channel.Id.ToString()); // If you want to avoid the overhead of collecting data when nobody is // listening to your channel, check the Enabled property before logging. if (channel.Enabled) { channel.LogMessage(this.CollectExpensiveData()); } // The IsEnabled() method is exactly the same as the Enabled property, // except that it is a new Windows 10 API. if (channel.IsEnabled()) { channel.LogMessage(this.CollectExpensiveData()); } // If you want to only collect data if somebody is listening at a specific // level, you need to check both Enabled and Level. Note that the value of // the Level is unspecified when Enabled is false. if (channel.Enabled && channel.Level <= LoggingLevel.Warning) { channel.LogMessage(this.CollectExpensiveData(), LoggingLevel.Warning); } // The IsEnabled(LoggingLevel) method is a bit nicer than checking both // Enabled and Level, but it is only available on Windows 10 or later. if (channel.IsEnabled(LoggingLevel.Warning)) { channel.LogMessage(this.CollectExpensiveData(), LoggingLevel.Warning); } // You can also use IsEnabled to check for keywords. if (channel.IsEnabled(LoggingLevel.Information, 0x10)) { channel.LogMessage(this.CollectExpensiveData(), LoggingLevel.Information); } // Use LoggingFields with the LogEvent method to write complex events. var fields = new LoggingFields(); fields.AddDouble("pi", 3.14159); channel.LogEvent( "ComplexEvent", fields, LoggingLevel.Verbose, new LoggingOptions(0x10)); // Keywords = 0x10 // You can add any number of name-value pairs to a fields object, though // you may encounter ETW limitations if you add too many. For example, // ETW is limited to a maximum event size of 64KB, and the current // TraceLogging decoder can handle no more than 128 fields. // Performance optimization: You can reuse a LoggingFields object to // avoid unnecessary allocations. Don't forget to call Clear() // between uses, and don't try to share a LoggingFields object between // threads. fields.Clear(); fields.AddDateTime("Date", DateTimeOffset.Now); channel.LogEvent("Now", fields); fields.Clear(); // You can add a formatting hint to affect the way a value is decoded. // Not all combinations are useful, and the hint may be ignored. // For example, you can encode an MBCS string by writing a byte array // with a String hint. fields.AddUInt8Array( "AnsiString", new byte[] { 65, 66, 67, 49, 50, 51 }, // "ABC123" LoggingFieldFormat.String); // You can add "tag" bits to a field. These are user-defined bits that // can be used to communicate with an event processing tool. For example, // you might define a tag bit to indicate that a field contains private // data that should not be displayed on-screen. fields.AddString("Password", "12345", LoggingFieldFormat.Default, 0x10); // You can add a "structure" to an event. A structure is a name for a // group of fields. Structures can nest. Call BeginStruct to add a level // of nesting, and call EndStruct after the last field of the structure. fields.BeginStruct("Nested"); fields.AddInt16("Nested-1", 1); fields.AddInt16("Nested-2", 2); fields.BeginStruct("Nested-Nested"); fields.AddInt16("Nested-Nested-3", 3); fields.EndStruct(); fields.AddInt16("Nested-4", 4); fields.EndStruct(); // Advanced scenarios: you can use a LoggingOptions object to control // detailed event settings such as keywords, opcodes, and activity Ids. // These have their normal ETW semantics. You can also set event tags, // which are bit values that can be used to communicate with the event // processor. channel.LogEvent( "VeryComplexEvent", fields, LoggingLevel.Information, new LoggingOptions { Keywords = 0x123, Tags = 0x10 }); // Windows 10 introduces the ILoggingTarget interface. LoggingChannel // implements this interface. This interface allows components to accept // a logger as an parameter. this.DoSomething(channel); /* If a LoggingActivity is created using a LoggingActivity constructor, it will use Windows 8.1 semantics: - If an activity is destroyed (garbage-collected) without being closed and the associated LoggingChannel is still open, the activity will write a default Stop event. - The default Stop event (written by the destructor or by the Close() method) is encoded as a "simple" event. The 8.1 semantics are deprecated because the automatic generation of a Stop event at garbage-collection can be misleading. The Stop event is intended to mark the a precise point at which an activity is completed, while the garbage-collection of an abandoned activity is inherently imprecise and unpredictable. If a LoggingActivity is created using a StartActivity method, it will use Windows 10 semantics: - If an activity is destroyed (garbage-collected) without being closed, there will be no Stop event for the activity. - The default Stop event (written by the Close() method) is encoded as a TraceLogging event with name "ActivityClosed". */ // This activity is created with Windows 8.1 semantics. using (var a1 = new LoggingActivity("Activity1", channel)) { // The activity Start event is written by the LoggingActivity constructor. // You would do your activity's work here. // The activity Stop event is written when the activity is closed (disposed). // The Windows 10 LoggingActivity adds new methods for writing events // that are marked as associated with the activity. a1.LogEvent("Activity event"); // LoggingActivity also implements the ILoggingTarget interface, so you can // use either a channel or an activity as a logging target. this.DoSomething(a1); // The Windows 10 LoggingActivity adds new methods for creating nested activities. // Note that nested activities are always created with Windows 10 semantics, // even when nested under an activity that is using Windows 8.1 semantics. using (var a2 = a1.StartActivity("Activity2")) { // Nested task occurs here. // The Windows 10 LoggingActivity allows you to customize the Stop event. a2.StopActivity("Activity 2 stop"); } // Because a1 is using Windows 8.1 semantics, if we did not call Dispose(), // it would attempt to write a Stop event when it is garbage collected. // Writing Stop events during garbage collection is not useful, so be sure // to properly stop, close, or dispose activities. } // The Windows 10 StartActivity method creates a new activity, optionally with // specified fields and characteristics. // This activity is created with Windows 10 semantics. using (var a3 = channel.StartActivity("Activity3")) { // Because a3 is using Windows 10 semantics, if we did not call Dispose(), // there would be no Stop event (not even when the activity is garbage // collected). To get a Stop event, be sure to stop, close, or dispose the // activity. } }
private async void InterruptGpioPin_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args) { DateTime currentTime = DateTime.UtcNow; Debug.WriteLine($"Digital Input Interrupt {sender.PinNumber} triggered {args.Edge}"); if (args.Edge != this.interruptTriggerOn) { return; } // Check that enough time has passed for picture to be taken if ((currentTime - this.imageLastCapturedAtUtc) < this.debounceTimeout) { this.displayGpioPin.Write(GpioPinValue.High); this.displayOffTimer.Change(this.timerPeriodDetectIlluminated, this.timerPeriodInfinite); return; } this.imageLastCapturedAtUtc = currentTime; // Just incase - stop code being called while photo already in progress if (this.cameraBusy) { this.displayGpioPin.Write(GpioPinValue.High); this.displayOffTimer.Change(this.timerPeriodDetectIlluminated, this.timerPeriodInfinite); return; } this.cameraBusy = true; try { using (Windows.Storage.Streams.InMemoryRandomAccessStream captureStream = new Windows.Storage.Streams.InMemoryRandomAccessStream()) { this.mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), captureStream).AsTask().Wait(); captureStream.FlushAsync().AsTask().Wait(); captureStream.Seek(0); IStorageFile photoFile = await KnownFolders.PicturesLibrary.CreateFileAsync(ImageFilename, CreationCollisionOption.ReplaceExisting); ImageEncodingProperties imageProperties = ImageEncodingProperties.CreateJpeg(); await this.mediaCapture.CapturePhotoToStorageFileAsync(imageProperties, photoFile); IList <FaceAttributeType> returnfaceAttributes = new List <FaceAttributeType>(); returnfaceAttributes.Add(FaceAttributeType.Gender); returnfaceAttributes.Add(FaceAttributeType.Age); IList <DetectedFace> detectedFaces = await this.faceClient.Face.DetectWithStreamAsync(captureStream.AsStreamForRead(), returnFaceAttributes : returnfaceAttributes); Debug.WriteLine($"Count {detectedFaces.Count}"); if (detectedFaces.Count > 0) { this.displayGpioPin.Write(GpioPinValue.High); // Start the timer to turn the LED off this.displayOffTimer.Change(this.timerPeriodFaceIlluminated, this.timerPeriodInfinite); } LoggingFields imageInformation = new LoggingFields(); imageInformation.AddDateTime("TakenAtUTC", currentTime); imageInformation.AddInt32("Pin", sender.PinNumber); imageInformation.AddInt32("Faces", detectedFaces.Count); foreach (DetectedFace detectedFace in detectedFaces) { Debug.WriteLine("Face"); if (detectedFace.FaceId.HasValue) { imageInformation.AddGuid("FaceId", detectedFace.FaceId.Value); Debug.WriteLine($" Id:{detectedFace.FaceId.Value}"); } imageInformation.AddInt32("Left", detectedFace.FaceRectangle.Left); imageInformation.AddInt32("Width", detectedFace.FaceRectangle.Width); imageInformation.AddInt32("Top", detectedFace.FaceRectangle.Top); imageInformation.AddInt32("Height", detectedFace.FaceRectangle.Height); Debug.WriteLine($" L:{detectedFace.FaceRectangle.Left} W:{detectedFace.FaceRectangle.Width} T:{detectedFace.FaceRectangle.Top} H:{detectedFace.FaceRectangle.Height}"); if (detectedFace.FaceAttributes != null) { if (detectedFace.FaceAttributes.Gender.HasValue) { imageInformation.AddString("Gender", detectedFace.FaceAttributes.Gender.Value.ToString()); Debug.WriteLine($" Gender:{detectedFace.FaceAttributes.Gender.ToString()}"); } if (detectedFace.FaceAttributes.Age.HasValue) { imageInformation.AddDouble("Age", detectedFace.FaceAttributes.Age.Value); Debug.WriteLine($" Age:{detectedFace.FaceAttributes.Age.Value.ToString("F1")}"); } } } this.logging.LogEvent("Captured image processed by Cognitive Services", imageInformation); } } catch (Exception ex) { this.logging.LogMessage("Camera photo or save failed " + ex.Message, LoggingLevel.Error); } finally { this.cameraBusy = false; } }
public void Run(IBackgroundTaskInstance taskInstance) { StorageFolder localFolder = ApplicationData.Current.LocalFolder; try { // see if the configuration file is present if not copy minimal sample one from application directory if (localFolder.TryGetItemAsync(ConfigurationFilename).AsTask().Result == null) { StorageFile templateConfigurationfile = Package.Current.InstalledLocation.GetFileAsync(ConfigurationFilename).AsTask().Result; templateConfigurationfile.CopyAsync(localFolder, ConfigurationFilename).AsTask(); } // Load the settings from configuration file exit application if missing or invalid StorageFile file = localFolder.GetFileAsync(ConfigurationFilename).AsTask().Result; applicationSettings = (JsonConvert.DeserializeObject <ApplicationSettings>(FileIO.ReadTextAsync(file).AsTask().Result)); } catch (Exception ex) { this.logging.LogMessage("JSON configuration file load failed " + ex.Message, LoggingLevel.Error); return; } // Log the Application build, shield information etc. LoggingFields applicationBuildInformation = new LoggingFields(); #if DRAGINO applicationBuildInformation.AddString("Shield", "DraginoLoRaGPSHat"); #endif #if ELECROW applicationBuildInformation.AddString("Shield", "ElecrowRFM95IoTBoard"); #endif #if M2M applicationBuildInformation.AddString("Shield", "M2M1ChannelLoRaWanGatewayShield"); #endif #if ELECTRONIC_TRICKS applicationBuildInformation.AddString("Shield", "ElectronicTricksLoRaLoRaWANShield"); #endif #if UPUTRONICS_RPIZERO_CS0 applicationBuildInformation.AddString("Shield", "UputronicsPiZeroLoRaExpansionBoardCS0"); #endif #if UPUTRONICS_RPIZERO_CS1 applicationBuildInformation.AddString("Shield", "UputronicsPiZeroLoRaExpansionBoardCS1"); #endif #if UPUTRONICS_RPIPLUS_CS0 applicationBuildInformation.AddString("Shield", "UputronicsPiPlusLoRaExpansionBoardCS0"); #endif #if UPUTRONICS_RPIPLUS_CS1 applicationBuildInformation.AddString("Shield", "UputronicsPiPlusLoRaExpansionBoardCS1"); #endif #if ADAFRUIT_RADIO_BONNET applicationBuildInformation.AddString("Shield", "AdafruitRadioBonnet"); #endif #if CLOUD_DEVICE_BOND applicationBuildInformation.AddString("Bond", "Supported"); #else applicationBuildInformation.AddString("Bond", "NotSupported"); #endif #if CLOUD_DEVICE_PUSH applicationBuildInformation.AddString("Push", "Supported"); #else applicationBuildInformation.AddString("Push", "NotSupported"); #endif #if CLOUD_DEVICE_SEND applicationBuildInformation.AddString("Send", "Supported"); #else applicationBuildInformation.AddString("Send", "NotSupported"); #endif #if PAYLOAD_TEXT applicationBuildInformation.AddString("PayloadProcessor", "Text"); #endif #if PAYLOAD_TEXT_COMA_SEPARATED_VALUES applicationBuildInformation.AddString("PayloadProcessor", "ComaSeperatedValues"); #endif #if PAYLOAD_BINARY_BINARY_CODED_DECIMAL applicationBuildInformation.AddString("PayloadProcessor", "BinaryCodedDecimal"); #endif #if PAYLOAD_BINARY_CAYENNE_LOW_POWER_PAYLOAD applicationBuildInformation.AddString("PayloadProcessor", "CayenneLowPowerPayload"); #endif applicationBuildInformation.AddString("Timezone", TimeZoneSettings.CurrentTimeZoneDisplayName); applicationBuildInformation.AddString("OSVersion", Environment.OSVersion.VersionString); applicationBuildInformation.AddString("MachineName", Environment.MachineName); // This is from the application manifest Package package = Package.Current; PackageId packageId = package.Id; PackageVersion version = packageId.Version; applicationBuildInformation.AddString("ApplicationVersion", string.Format($"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}")); this.logging.LogEvent("Application starting", applicationBuildInformation, LoggingLevel.Information); try { #if DRAGINO rfm9XDevice = new Rfm9XDevice(ChipSelectPin.CS0, ChipSelectLine, ResetLine, InterruptLine); #endif #if M2M rfm9XDevice = new Rfm9XDevice(ChipSelectPin.CS0, ChipSelectLine, ResetLine, InterruptLine); #endif #if ELECROW rfm9XDevice = new Rfm9XDevice(ChipSelectPin.CS1, ResetLine, InterruptLine); #endif #if ELECTRONIC_TRICKS rfm9XDevice = new Rfm9XDevice(ChipSelectPin.CS0, ResetLine, InterruptLine); #endif #if UPUTRONICS_RPIZERO_CS0 rfm9XDevice = new Rfm9XDevice(ChipSelectPin.CS0, InterruptLine); #endif #if UPUTRONICS_RPIZERO_CS1 rfm9XDevice = new Rfm9XDevice(ChipSelectPin.CS1, InterruptLine); #endif #if UPUTRONICS_RPIPLUS_CS0 rfm9XDevice = new Rfm9XDevice(ChipSelectPin.CS0, InterruptLine); #endif #if UPUTRONICS_RPIPLUS_CS1 rfm9XDevice = new Rfm9XDevice(ChipSelectPin.CS1, InterruptLine); #endif #if ADAFRUIT_RADIO_BONNET rfm9XDevice = new Rfm9XDevice(ChipSelectPin.CS1, ResetLine, InterruptLine); #endif } catch (Exception ex) { this.logging.LogMessage("Hardware initialisation failed " + ex.Message, LoggingLevel.Error); return; } // Log the Azure connection string and associated settings LoggingFields azureIoTHubSettings = new LoggingFields(); azureIoTHubSettings.AddString("DeviceConnectionString", this.applicationSettings.AzureIoTHubDeviceConnectionString); azureIoTHubSettings.AddString("TransportType", this.applicationSettings.AzureIoTHubTransportType.ToString()); azureIoTHubSettings.AddString("SensorIDIsDeviceIDSensorID", this.applicationSettings.SensorIDIsDeviceIDSensorID.ToString()); this.logging.LogEvent("AzureIoTHub configuration", azureIoTHubSettings, LoggingLevel.Information); // Connect the IoT hub first so we are ready for any messages try { this.azureIoTHubClient = DeviceClient.CreateFromConnectionString(this.applicationSettings.AzureIoTHubDeviceConnectionString, this.applicationSettings.AzureIoTHubTransportType); } catch (Exception ex) { this.logging.LogMessage("IoT Hub connection failed " + ex.Message, LoggingLevel.Error); return; } try { TwinCollection reportedProperties; reportedProperties = new TwinCollection(); // This is from the OS reportedProperties["Timezone"] = TimeZoneSettings.CurrentTimeZoneDisplayName; reportedProperties["OSVersion"] = Environment.OSVersion.VersionString; reportedProperties["MachineName"] = Environment.MachineName; reportedProperties["ApplicationDisplayName"] = package.DisplayName; reportedProperties["ApplicationName"] = packageId.Name; reportedProperties["ApplicationVersion"] = string.Format($"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}"); // Unique identifier from the hardware SystemIdentificationInfo systemIdentificationInfo = SystemIdentification.GetSystemIdForPublisher(); using (DataReader reader = DataReader.FromBuffer(systemIdentificationInfo.Id)) { byte[] bytes = new byte[systemIdentificationInfo.Id.Length]; reader.ReadBytes(bytes); reportedProperties["SystemId"] = BitConverter.ToString(bytes); } azureIoTHubClient.UpdateReportedPropertiesAsync(reportedProperties).Wait(); } catch (Exception ex) { this.logging.LogMessage("IoT Hub updating reported properties failed " + ex.Message, LoggingLevel.Error); } // Wire up the field gateway restart method handler try { azureIoTHubClient.SetMethodHandlerAsync("Restart", RestartAsync, null); } catch (Exception ex) { this.logging.LogMessage("Azure IoT Hub Restart method handler setup failed " + ex.Message, LoggingLevel.Error); return; } #if CLOUD_DEVICE_BOND // Wire up the bond device method handler try { azureIoTHubClient.SetMethodHandlerAsync("DeviceBond", this.DeviceBondAsync, null); } catch (Exception ex) { this.logging.LogMessage("Azure IoT Hub Device Bond method handler setup failed " + ex.Message, LoggingLevel.Error); return; } #endif #if CLOUD_DEVICE_PUSH // Wire up the push message to device method handler try { this.azureIoTHubClient.SetMethodHandlerAsync("DevicePush", this.DevicePushAsync, null); } catch (Exception ex) { this.logging.LogMessage("Azure IoT Hub DevicePush method handler setup failed " + ex.Message, LoggingLevel.Error); return; } #endif #if CLOUD_DEVICE_SEND // Wire up the send message to device method handler try { this.azureIoTHubClient.SetMethodHandlerAsync("DeviceSend", this.DeviceSendAsync, null); } catch (Exception ex) { this.logging.LogMessage("Azure IoT Hub client DeviceSend method handler setup failed " + ex.Message, LoggingLevel.Error); return; } #endif // Configure the LoRa module rfm9XDevice.OnReceive += Rfm9XDevice_OnReceive; rfm9XDevice.OnTransmit += Rfm9XDevice_OnTransmit; rfm9XDevice.Initialise(this.applicationSettings.Frequency, rxDoneignoreIfCrcMissing: true, rxDoneignoreIfCrcInvalid: true, paBoost: this.applicationSettings.PABoost, maxPower: this.applicationSettings.MaxPower, outputPower: this.applicationSettings.OutputPower, ocpOn: this.applicationSettings.OCPOn, ocpTrim: this.applicationSettings.OCPTrim, lnaGain: this.applicationSettings.LnaGain, lnaBoost: this.applicationSettings.LNABoost, bandwidth: this.applicationSettings.Bandwidth, codingRate: this.applicationSettings.CodingRate, implicitHeaderModeOn: this.applicationSettings.ImplicitHeaderModeOn, spreadingFactor: this.applicationSettings.SpreadingFactor, rxPayloadCrcOn: true, symbolTimeout: this.applicationSettings.SymbolTimeout, preambleLength: this.applicationSettings.PreambleLength, payloadLength: this.applicationSettings.PayloadLength, payloadMaxLength: this.applicationSettings.PayloadMaxLength, freqHoppingPeriod: this.applicationSettings.FreqHoppingPeriod, lowDataRateOptimize: this.applicationSettings.LowDataRateOptimize, ppmCorrection: this.applicationSettings.PpmCorrection, detectionOptimize: this.applicationSettings.DetectionOptimize, invertIQ: this.applicationSettings.InvertIQ, detectionThreshold: this.applicationSettings.DetectionThreshold, syncWord: this.applicationSettings.SyncWord ); #if DEBUG rfm9XDevice.RegisterDump(); #endif rfm9XDevice.Receive(Encoding.UTF8.GetBytes(this.applicationSettings.Address)); LoggingFields loRaSettings = new LoggingFields(); loRaSettings.AddString("Address", this.applicationSettings.Address); loRaSettings.AddDouble("Frequency", this.applicationSettings.Frequency); loRaSettings.AddBoolean("PABoost", this.applicationSettings.PABoost); loRaSettings.AddUInt8("MaxPower", this.applicationSettings.MaxPower); loRaSettings.AddUInt8("OutputPower", this.applicationSettings.OutputPower); loRaSettings.AddBoolean("OCPOn", this.applicationSettings.OCPOn); loRaSettings.AddUInt8("OCPTrim", this.applicationSettings.OCPTrim); loRaSettings.AddString("LnaGain", this.applicationSettings.LnaGain.ToString()); loRaSettings.AddBoolean("lnaBoost", this.applicationSettings.LNABoost); loRaSettings.AddString("codingRate", this.applicationSettings.CodingRate.ToString()); loRaSettings.AddString("implicitHeaderModeOn", applicationSettings.ImplicitHeaderModeOn.ToString()); loRaSettings.AddString("spreadingFactor", this.applicationSettings.SpreadingFactor.ToString()); loRaSettings.AddBoolean("rxPayloadCrcOn", true); loRaSettings.AddUInt8("symbolTimeout", this.applicationSettings.SymbolTimeout); loRaSettings.AddUInt8("preambleLength", this.applicationSettings.PreambleLength); loRaSettings.AddUInt8("payloadLength", this.applicationSettings.PayloadLength); loRaSettings.AddUInt8("payloadMaxLength", this.applicationSettings.PayloadMaxLength); loRaSettings.AddUInt8("freqHoppingPeriod", this.applicationSettings.FreqHoppingPeriod); loRaSettings.AddBoolean("lowDataRateOptimize", this.applicationSettings.LowDataRateOptimize); loRaSettings.AddUInt8("ppmCorrection", this.applicationSettings.PpmCorrection); loRaSettings.AddString("detectionOptimize", this.applicationSettings.DetectionOptimize.ToString()); loRaSettings.AddBoolean("invertIQ", this.applicationSettings.InvertIQ); loRaSettings.AddString("detectionThreshold", this.applicationSettings.DetectionThreshold.ToString()); loRaSettings.AddUInt8("SyncWord", this.applicationSettings.SyncWord); this.logging.LogEvent("LoRa configuration", loRaSettings, LoggingLevel.Information); this.deferral = taskInstance.GetDeferral(); }
private async void InterruptGpioPin_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args) { DateTime currentTime = DateTime.UtcNow; Debug.WriteLine($"Digital Input Interrupt {sender.PinNumber} triggered {args.Edge}"); if (args.Edge != this.interruptTriggerOn) { return; } // Check that enough time has passed for picture to be taken if ((currentTime - this.imageLastCapturedAtUtc) < this.debounceTimeout) { this.displayGpioPin.Write(GpioPinValue.High); this.displayOffTimer.Change(this.timerPeriodDetectIlluminated, this.timerPeriodInfinite); return; } this.imageLastCapturedAtUtc = currentTime; // Just incase - stop code being called while photo already in progress if (this.cameraBusy) { this.displayGpioPin.Write(GpioPinValue.High); this.displayOffTimer.Change(this.timerPeriodDetectIlluminated, this.timerPeriodInfinite); return; } this.cameraBusy = true; try { using (Windows.Storage.Streams.InMemoryRandomAccessStream captureStream = new Windows.Storage.Streams.InMemoryRandomAccessStream()) { this.mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), captureStream).AsTask().Wait(); captureStream.FlushAsync().AsTask().Wait(); captureStream.Seek(0); IStorageFile photoFile = await KnownFolders.PicturesLibrary.CreateFileAsync(ImageFilename, CreationCollisionOption.ReplaceExisting); ImageEncodingProperties imageProperties = ImageEncodingProperties.CreateJpeg(); await this.mediaCapture.CapturePhotoToStorageFileAsync(imageProperties, photoFile); ImagePrediction imagePrediction = await this.customVisionClient.ClassifyImageAsync(this.projectId, this.publishedName, captureStream.AsStreamForRead()); Debug.WriteLine($"Prediction count {imagePrediction.Predictions.Count}"); LoggingFields imageInformation = new LoggingFields(); imageInformation.AddDateTime("TakenAtUTC", currentTime); imageInformation.AddInt32("Pin", sender.PinNumber); imageInformation.AddInt32("Predictions", imagePrediction.Predictions.Count); foreach (var prediction in imagePrediction.Predictions) { Debug.WriteLine($" Tag:{prediction.TagName} {prediction.Probability}"); imageInformation.AddDouble($"Tag:{prediction.TagName}", prediction.Probability); } this.logging.LogEvent("Captured image processed by Cognitive Services", imageInformation); } } catch (Exception ex) { this.logging.LogMessage("Camera photo or save failed " + ex.Message, LoggingLevel.Error); } finally { this.cameraBusy = false; } }
public void Run(IBackgroundTaskInstance taskInstance) { StorageFolder localFolder = ApplicationData.Current.LocalFolder; TimeSpan imageUpdateDue; TimeSpan imageUpdatePeriod; this.logging.LogEvent("Application starting"); // Log the Application build, OS version information etc. LoggingFields startupInformation = new LoggingFields(); startupInformation.AddString("Timezone", TimeZoneSettings.CurrentTimeZoneDisplayName); startupInformation.AddString("OSVersion", Environment.OSVersion.VersionString); startupInformation.AddString("MachineName", Environment.MachineName); // This is from the application manifest Package package = Package.Current; PackageId packageId = package.Id; PackageVersion version = packageId.Version; startupInformation.AddString("ApplicationVersion", string.Format($"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}")); try { // see if the configuration file is present if not copy minimal sample one from application directory if (localFolder.TryGetItemAsync(ConfigurationFilename).AsTask().Result == null) { StorageFile templateConfigurationfile = Package.Current.InstalledLocation.GetFileAsync(ConfigurationFilename).AsTask().Result; templateConfigurationfile.CopyAsync(localFolder, ConfigurationFilename).AsTask(); } IConfiguration configuration = new ConfigurationBuilder().AddJsonFile(Path.Combine(localFolder.Path, ConfigurationFilename), false, true).Build(); this.interruptPinNumber = int.Parse(configuration.GetSection("InterruptPinNumber").Value); startupInformation.AddInt32("Interrupt pin", this.interruptPinNumber); this.interruptTriggerOn = (GpioPinEdge)Enum.Parse(typeof(GpioPinEdge), configuration.GetSection("interruptTriggerOn").Value); startupInformation.AddString("Interrupt Trigger on", this.interruptTriggerOn.ToString()); this.displayPinNumber = int.Parse(configuration.GetSection("DisplayPinNumber").Value); startupInformation.AddInt32("Display pin", this.interruptPinNumber); this.azureIoTHubConnectionString = configuration.GetSection("AzureIoTHubConnectionString").Value; startupInformation.AddString("AzureIoTHubConnectionString", this.azureIoTHubConnectionString); this.transportType = (TransportType)Enum.Parse(typeof(TransportType), configuration.GetSection("TransportType").Value); startupInformation.AddString("TransportType", this.transportType.ToString()); } catch (Exception ex) { this.logging.LogMessage("JSON configuration file load or settings retrieval failed " + ex.Message, LoggingLevel.Error); return; } #region AzureIoT Hub connection string creation try { this.azureIoTHubClient = DeviceClient.CreateFromConnectionString(this.azureIoTHubConnectionString, this.transportType); } catch (Exception ex) { this.logging.LogMessage("AzureIOT Hub DeviceClient.CreateFromConnectionString failed " + ex.Message, LoggingLevel.Error); return; } #endregion #region Report device and application properties to AzureIoT Hub try { TwinCollection reportedProperties = new TwinCollection(); // This is from the OS reportedProperties["Timezone"] = TimeZoneSettings.CurrentTimeZoneDisplayName; reportedProperties["OSVersion"] = Environment.OSVersion.VersionString; reportedProperties["MachineName"] = Environment.MachineName; reportedProperties["ApplicationDisplayName"] = package.DisplayName; reportedProperties["ApplicationName"] = packageId.Name; reportedProperties["ApplicationVersion"] = string.Format($"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}"); // Unique identifier from the hardware SystemIdentificationInfo systemIdentificationInfo = SystemIdentification.GetSystemIdForPublisher(); using (DataReader reader = DataReader.FromBuffer(systemIdentificationInfo.Id)) { byte[] bytes = new byte[systemIdentificationInfo.Id.Length]; reader.ReadBytes(bytes); reportedProperties["SystemId"] = BitConverter.ToString(bytes); } this.azureIoTHubClient.UpdateReportedPropertiesAsync(reportedProperties).Wait(); } catch (Exception ex) { this.logging.LogMessage("Azure IoT Hub client UpdateReportedPropertiesAsync failed " + ex.Message, LoggingLevel.Error); return; } #endregion #region Retrieve device twin settings try { LoggingFields configurationInformation = new LoggingFields(); Twin deviceTwin = this.azureIoTHubClient.GetTwinAsync().GetAwaiter().GetResult(); if (!deviceTwin.Properties.Desired.Contains("ImageUpdateDue") || !TimeSpan.TryParse(deviceTwin.Properties.Desired["ImageUpdateDue"].value.ToString(), out imageUpdateDue)) { this.logging.LogMessage("DeviceTwin.Properties ImageUpdateDue setting missing or invalid format", LoggingLevel.Warning); return; } configurationInformation.AddTimeSpan("ImageUpdateDue", imageUpdateDue); if (!deviceTwin.Properties.Desired.Contains("ImageUpdatePeriod") || !TimeSpan.TryParse(deviceTwin.Properties.Desired["ImageUpdatePeriod"].value.ToString(), out imageUpdatePeriod)) { this.logging.LogMessage("DeviceTwin.Properties ImageUpdatePeriod setting missing or invalid format", LoggingLevel.Warning); return; } configurationInformation.AddTimeSpan("ImageUpdatePeriod", imageUpdatePeriod); if (!deviceTwin.Properties.Desired.Contains("ModelType") || (!Enum.TryParse(deviceTwin.Properties.Desired["ModelType"].value.ToString(), out modelType))) { this.logging.LogMessage("DeviceTwin.Properties ModelType setting missing or invalid format", LoggingLevel.Warning); return; } configurationInformation.AddString("ModelType", modelType.ToString()); if (!deviceTwin.Properties.Desired.Contains("ModelPublishedName") || (string.IsNullOrWhiteSpace(deviceTwin.Properties.Desired["ModelPublishedName"].value.ToString()))) { this.logging.LogMessage("DeviceTwin.Properties ModelPublishedName setting missing or invalid format", LoggingLevel.Warning); return; } modelPublishedName = deviceTwin.Properties.Desired["ModelPublishedName"].value.ToString(); configurationInformation.AddString("ModelPublishedName", modelPublishedName); if (!deviceTwin.Properties.Desired.Contains("ProjectID") || (!Guid.TryParse(deviceTwin.Properties.Desired["ProjectID"].value.ToString(), out projectId))) { this.logging.LogMessage("DeviceTwin.Properties ProjectId setting missing or invalid format", LoggingLevel.Warning); return; } configurationInformation.AddGuid("ProjectID", projectId); if (!deviceTwin.Properties.Desired.Contains("ProbabilityThreshold") || (!Double.TryParse(deviceTwin.Properties.Desired["ProbabilityThreshold"].value.ToString(), out probabilityThreshold))) { this.logging.LogMessage("DeviceTwin.Properties ProbabilityThreshold setting missing or invalid format", LoggingLevel.Warning); return; } configurationInformation.AddDouble("ProbabilityThreshold", probabilityThreshold); if (!deviceTwin.Properties.Desired.Contains("AzureCognitiveServicesEndpoint") || (string.IsNullOrWhiteSpace(deviceTwin.Properties.Desired["AzureCognitiveServicesEndpoint"].value.ToString()))) { this.logging.LogMessage("DeviceTwin.Properties AzureCognitiveServicesEndpoint setting missing or invalid format", LoggingLevel.Warning); return; } azureCognitiveServicesEndpoint = deviceTwin.Properties.Desired["AzureCognitiveServicesEndpoint"].value.ToString(); configurationInformation.AddString("AzureCognitiveServicesEndpoint", modelPublishedName); if (!deviceTwin.Properties.Desired.Contains("AzureCognitiveServicesSubscriptionKey") || (string.IsNullOrWhiteSpace(deviceTwin.Properties.Desired["AzureCognitiveServicesSubscriptionKey"].value.ToString()))) { this.logging.LogMessage("DeviceTwin.Properties AzureCognitiveServicesSubscriptionKey setting missing or invalid format", LoggingLevel.Warning); return; } azureCognitiveServicesSubscriptionKey = deviceTwin.Properties.Desired["AzureCognitiveServicesSubscriptionKey"].value.ToString(); configurationInformation.AddString("AzureCognitiveServicesSubscriptionKey", azureCognitiveServicesSubscriptionKey); if (!deviceTwin.Properties.Desired.Contains("DebounceTimeout") || !TimeSpan.TryParse(deviceTwin.Properties.Desired["DebounceTimeout"].value.ToString(), out debounceTimeout)) { this.logging.LogMessage("DeviceTwin.Properties DebounceTimeout setting missing or invalid format", LoggingLevel.Warning); return; } configurationInformation.AddTimeSpan("DebounceTimeout", debounceTimeout); this.logging.LogEvent("Configuration settings", configurationInformation); } catch (Exception ex) { this.logging.LogMessage("Azure IoT Hub client GetTwinAsync failed or property missing/invalid" + ex.Message, LoggingLevel.Error); return; } #endregion try { this.customVisionClient = new CustomVisionPredictionClient(new System.Net.Http.DelegatingHandler[] { }) { ApiKey = this.azureCognitiveServicesSubscriptionKey, Endpoint = this.azureCognitiveServicesEndpoint, }; } catch (Exception ex) { this.logging.LogMessage("Azure Cognitive Services Custom Vision Client configuration failed " + ex.Message, LoggingLevel.Error); return; } try { this.mediaCapture = new MediaCapture(); this.mediaCapture.InitializeAsync().AsTask().Wait(); } catch (Exception ex) { this.logging.LogMessage("Camera configuration failed " + ex.Message, LoggingLevel.Error); return; } this.displayOffTimer = new Timer(this.TimerCallback, null, Timeout.Infinite, Timeout.Infinite); #region Wire up interupt handler for image capture request if (this.interruptPinNumber != 0) { try { GpioController gpioController = GpioController.GetDefault(); this.interruptGpioPin = gpioController.OpenPin(this.interruptPinNumber); this.interruptGpioPin.SetDriveMode(GpioPinDriveMode.InputPullUp); this.interruptGpioPin.ValueChanged += this.InterruptGpioPin_ValueChanged; this.displayGpioPin = gpioController.OpenPin(this.displayPinNumber); this.displayGpioPin.SetDriveMode(GpioPinDriveMode.Output); this.displayGpioPin.Write(GpioPinValue.Low); } catch (Exception ex) { this.logging.LogMessage("Digital input configuration failed " + ex.Message, LoggingLevel.Error); return; } } #endregion #region Wire up command handler for image capture request try { this.azureIoTHubClient.SetMethodHandlerAsync("ImageCapture", this.ImageUpdateHandler, null); } catch (Exception ex) { this.logging.LogMessage("Azure IoT Hub client ImageCapture SetMethodHandlerAsync failed " + ex.Message, LoggingLevel.Error); return; } #endregion #region Wire up command handler for device reboot request try { this.azureIoTHubClient.SetMethodHandlerAsync("DeviceReboot", this.DeviceRebootAsync, null); } catch (Exception ex) { this.logging.LogMessage("Azure IoT Hub client DeviceReboot SetMethodHandlerAsync failed " + ex.Message, LoggingLevel.Error); return; } #endregion if ((imageUpdateDue != TimeSpan.MinValue) || (imageUpdatePeriod != TimeSpan.MinValue)) { this.imageUpdatetimer = new Timer(this.ImageUpdateTimerCallback, null, imageUpdateDue, imageUpdatePeriod); } this.logging.LogEvent("Application started", startupInformation); // enable task to continue running in background this.backgroundTaskDeferral = taskInstance.GetDeferral(); }
private async Task ImageUpdate(bool isCommand) { DateTime currentTime = DateTime.UtcNow; // Just incase - stop code being called while photo already in progress if (this.cameraBusy) { return; } this.cameraBusy = true; this.displayGpioPin.Write(GpioPinValue.High); // Check that enough time has passed for picture to be taken if ((currentTime - this.imageLastCapturedAtUtc) < this.debounceTimeout) { this.displayOffTimer.Change(this.timerPeriodDetectIlluminated, this.timerPeriodInfinite); return; } this.imageLastCapturedAtUtc = currentTime; try { ImagePrediction imagePrediction; using (Windows.Storage.Streams.InMemoryRandomAccessStream captureStream = new Windows.Storage.Streams.InMemoryRandomAccessStream()) { this.mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), captureStream).AsTask().Wait(); captureStream.FlushAsync().AsTask().Wait(); captureStream.Seek(0); IStorageFile photoFile = await KnownFolders.PicturesLibrary.CreateFileAsync(ImageFilename, CreationCollisionOption.ReplaceExisting); ImageEncodingProperties imageProperties = ImageEncodingProperties.CreateJpeg(); await this.mediaCapture.CapturePhotoToStorageFileAsync(imageProperties, photoFile); switch (modelType) { case ModelType.Classification: imagePrediction = await this.customVisionClient.ClassifyImageAsync(this.projectId, this.modelPublishedName, captureStream.AsStreamForRead()); break; case ModelType.Detection: imagePrediction = await this.customVisionClient.DetectImageAsync(this.projectId, this.modelPublishedName, captureStream.AsStreamForRead()); break; default: throw new ArgumentException("ModelType Invalid"); } Debug.WriteLine($"Prediction count {imagePrediction.Predictions.Count}"); } JObject telemetryDataPoint = new JObject(); LoggingFields imageInformation = new LoggingFields(); imageInformation.AddDateTime("TakenAtUTC", currentTime); imageInformation.AddBoolean("IsCommand", isCommand); imageInformation.AddDouble("Probability threshold", probabilityThreshold); imageInformation.AddInt32("Predictions", imagePrediction.Predictions.Count); // Display and log the results of the prediction foreach (var prediction in imagePrediction.Predictions) { Debug.WriteLine($" Tag:{prediction.TagName} {prediction.Probability}"); imageInformation.AddDouble($"Tag:{prediction.TagName}", prediction.Probability); } // Post process the predictions based on the type of model switch (modelType) { case ModelType.Classification: // Use only the tags above the specified minimum probability foreach (var prediction in imagePrediction.Predictions) { if (prediction.Probability >= probabilityThreshold) { // Display and log the individual tag probabilities Debug.WriteLine($" Tag valid:{prediction.TagName} {prediction.Probability:0.00}"); imageInformation.AddDouble($"Tag valid:{prediction.TagName}", prediction.Probability); telemetryDataPoint.Add(prediction.TagName, prediction.Probability); } } break; case ModelType.Detection: // Group the tags to get the count, include only the predictions above the specified minimum probability var groupedPredictions = from prediction in imagePrediction.Predictions where prediction.Probability >= probabilityThreshold group prediction by new { prediction.TagName } into newGroup select new { TagName = newGroup.Key.TagName, Count = newGroup.Count(), }; // Display and log the agregated predictions foreach (var prediction in groupedPredictions) { Debug.WriteLine($" Tag valid:{prediction.TagName} {prediction.Count}"); imageInformation.AddInt32($"Tag valid:{prediction.TagName}", prediction.Count); telemetryDataPoint.Add(prediction.TagName, prediction.Count); } break; default: throw new ArgumentException("ModelType Invalid"); } this.logging.LogEvent("Captured image processed by Cognitive Services", imageInformation); try { using (Message message = new Message(Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(telemetryDataPoint)))) { Debug.WriteLine(" {0:HH:mm:ss} AzureIoTHubClient SendEventAsync start", DateTime.UtcNow); await this.azureIoTHubClient.SendEventAsync(message); Debug.WriteLine(" {0:HH:mm:ss} AzureIoTHubClient SendEventAsync finish", DateTime.UtcNow); } this.logging.LogEvent("SendEventAsync payload", imageInformation, LoggingLevel.Information); } catch (Exception ex) { imageInformation.AddString("Exception", ex.ToString()); this.logging.LogEvent("SendEventAsync payload", imageInformation, LoggingLevel.Error); } } catch (Exception ex) { this.logging.LogMessage("Camera photo or save failed " + ex.Message, LoggingLevel.Error); } finally { this.displayGpioPin.Write(GpioPinValue.Low); this.cameraBusy = false; } }