private static JsonPatch generatePatchForSensor(double value1, bool exists1, double value2 = -1, bool exists2 = false)
        {
            JsonPatch patch = new JsonPatch();

            if (value1 >= 0)
            {
                if (exists1)
                {
                    patch.AppendReplaceOp("/observationValue1", value1);
                }
                else
                {
                    patch.AppendAddOp("/observationValue1", value1);
                }
            }

            if (value2 >= 0)
            {
                if (exists2)
                {
                    patch.AppendReplaceOp("/observationValue2", value2);
                }
                else
                {
                    patch.AppendAddOp("/observationValue2", value2);
                }
            }

            return(patch);
        }
        private static JsonPatch generatePatchForComponent(double value, bool exists)
        {
            JsonPatch patch = new JsonPatch();

            if (exists)
            {
                patch.AppendReplaceOp("/computedHealth", value);
            }
            else
            {
                patch.AppendAddOp("/computedHealth", value);
            }

            return(patch);
        }
        private async static Task ProcessDataForDevice(JObject messageData, string deviceId, ILogger log)
        {
            deviceId = deviceId.Substring(deviceId.IndexOf('.') + 1);
            string         query = $"SELECT * FROM DigitalTwins T WHERE IS_OF_MODEL(T, 'dtmi:adt:chb:Sensor;1') AND T.deviceId = '{deviceId}'";
            IList <object> items = await executeQuery(query);

            double value1 = -1; double value2 = -1;

            if (messageData.ContainsKey("temperature"))
            {
                value1 = double.Parse((messageData["temperature"].ToString()));
            }
            else if (messageData.ContainsKey("no2"))
            {
                value1 = double.Parse((messageData["co"].ToString()));
                value2 = double.Parse((messageData["no2"].ToString()));
            }
            else if (messageData.ContainsKey("vehicles"))
            {
                value1 = double.Parse((messageData["vehicles"].ToString()));
                value2 = double.Parse((messageData["trucks"].ToString()));
            }
            else if (messageData.ContainsKey("accelerometer"))
            {
                value1 = double.Parse((messageData["deflection"].ToString()));
                value2 = double.Parse((messageData["accelerometer"].ToString()));
            }

            bool   exists1        = (items.First() as JObject).ContainsKey("observationValue1");
            bool   exists2        = (items.First() as JObject).ContainsKey("observationValue2");
            string dtId           = (items.First() as JObject)["$dtId"].ToString();
            string observedNodeId = (items.First() as JObject)["observes"].ToString();

            JsonPatch patch = generatePatchForSensor(value1, exists1, value2, exists2);

            try { await client.DigitalTwins.UpdateAsync(dtId, patch.Document); } catch {}

            updateHigherLevelTwin(observedNodeId, log);
        }
        private static async void updateHigherLevelTwin(string dtId, ILogger log)
        {
            string         query = $"SELECT * FROM DigitalTwins T WHERE IS_OF_MODEL(T, 'dtmi:adt:chb:Sensor;1') AND T.observes = '{dtId}'";
            IList <object> items = await executeQuery(query);

            double maxPercentage = 0;

            foreach (JObject sensor in items)
            {
                if (sensor["type"].ToString().Equals("Interior Thermometer"))
                {
                    double temperature = sensor.ContainsKey("observationValue1") ? double.Parse(sensor.GetValue("observationValue1").ToString()) : 0;
                    double percentage  = temperature / TEMPERATURE_UPPER_LIMIT;
                    maxPercentage = (percentage > maxPercentage) ? percentage : maxPercentage;
                }
                else if (sensor["type"].ToString().Equals("Baseline Air Sensor"))
                {
                    double co         = sensor.ContainsKey("observationValue1") ? double.Parse(sensor.GetValue("observationValue1").ToString()) : 0;
                    double percentage = co / CO_UPPER_LIMIT;
                    maxPercentage = (percentage > maxPercentage) ? percentage : maxPercentage;
                    double no2 = sensor.ContainsKey("observationValue2") ? double.Parse(sensor.GetValue("observationValue2").ToString()) : 0;
                    percentage    = no2 / NO2_UPPER_LIMIT;
                    maxPercentage = (percentage > maxPercentage) ? percentage : maxPercentage;
                }
                else if (sensor["type"].ToString().Equals("Exterior Thermometer"))
                {
                    double temperature = sensor.ContainsKey("observationValue1") ? double.Parse(sensor.GetValue("observationValue1").ToString()) : 0;
                    double percentage  = temperature / TEMPERATURE_UPPER_LIMIT;
                    maxPercentage = (percentage > maxPercentage) ? percentage : maxPercentage;
                }
                else if (sensor["type"].ToString().Equals("Tunnel Air Sensor"))
                {
                    double co         = sensor.ContainsKey("observationValue1") ? double.Parse(sensor.GetValue("observationValue1").ToString()) : 0;
                    double percentage = co / CO_UPPER_LIMIT;
                    maxPercentage = (percentage > maxPercentage) ? percentage : maxPercentage;
                    double no2 = sensor.ContainsKey("observationValue2") ? double.Parse(sensor.GetValue("observationValue2").ToString()) : 0;
                    percentage    = no2 / NO2_UPPER_LIMIT;
                    maxPercentage = (percentage > maxPercentage) ? percentage : maxPercentage;
                }
                else if (sensor["type"].ToString().Equals("Vehicle Counter"))
                {
                    double vehicleCount = sensor.ContainsKey("observationValue1") ? double.Parse(sensor.GetValue("observationValue1").ToString()) : 0;
                    double percentage   = vehicleCount / VEHICLE_UPPER_LIMIT;
                    maxPercentage = (percentage > maxPercentage) ? percentage : maxPercentage;
                    double truckCount = sensor.ContainsKey("observationValue2") ? double.Parse(sensor.GetValue("observationValue2").ToString()) : 0;
                    percentage    = truckCount / TRUCK_UPPER_LIMIT;
                    maxPercentage = (percentage > maxPercentage) ? percentage : maxPercentage;
                }
                else if (sensor["type"].ToString().Equals("Bridge Sensor"))
                {
                    double deflection = sensor.ContainsKey("observationValue1") ? double.Parse(sensor.GetValue("observationValue1").ToString()) : 0;
                    double percentage = deflection / DEFLECTION_UPPER_LIMIT;
                    maxPercentage = (percentage > maxPercentage) ? percentage : maxPercentage;
                    double vibration = sensor.ContainsKey("observationValue2") ? double.Parse(sensor.GetValue("observationValue2").ToString()) : 0;
                    percentage    = vibration / VIBRATION_UPPER_LIMIT;
                    maxPercentage = (percentage > maxPercentage) ? percentage : maxPercentage;
                }
            }

            query = $"SELECT * FROM DigitalTwins T WHERE T.$dtId = '{dtId}'";
            items = await executeQuery(query);

            if (items.Count > 0)
            {
                bool exists = (items.First() as JObject).ContainsKey("computedHealth");
                if (exists)
                {
                    if (double.Parse(((items.First() as JObject)["computedHealth"]).ToString()) == (maxPercentage * 100))
                    {
                        return;
                    }
                }
                log.LogInformation($"{adtInstanceUrl} COMPUTED HEALTH FOR {dtId}: {maxPercentage * 100}");
                JsonPatch patch = generatePatchForComponent(maxPercentage * 100, exists);
                try { await client.DigitalTwins.UpdateAsync(dtId, patch.Document); } catch {}
            }
        }