private async Task RunQueryAggregateSeriesSample(TimeSeriesInsightsQueries queriesClient, TimeSeriesId tsId) { #region Snippet:TimeSeriesInsightsSampleQueryAggregateSeriesWithNumericVariable Console.WriteLine("\n\nQuery for the average temperature over the past 30 seconds, in 2-second time slots.\n"); var numericVariable = new NumericVariable( new TimeSeriesExpression("$event.Temperature"), new TimeSeriesExpression("avg($value)")); var requestOptions = new QueryAggregateSeriesRequestOptions(); requestOptions.InlineVariables["Temperature"] = numericVariable; requestOptions.ProjectedVariableNames.Add("Temperature"); TimeSeriesQueryAnalyzer aggregateSeriesQuery = queriesClient.CreateAggregateSeriesQuery( tsId, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(30), null, requestOptions); await foreach (TimeSeriesPoint point in aggregateSeriesQuery.GetResultsAsync()) { double?averageTemperature = point.GetNullableDouble("Temperature"); if (averageTemperature != null) { Console.WriteLine($"{point.Timestamp} - Average temperature: {averageTemperature}."); } } #endregion Snippet:TimeSeriesInsightsSampleQueryAggregateSeriesWithNumericVariable #region Snippet:TimeSeriesInsightsSampleQueryAggregateSeriesWithAggregateVariable Console.WriteLine("\n\nCount the number of temperature events over the past 3 minutes, in 1-minute time slots.\n"); // Get the count of events in 60-second time slots over the past 3 minutes DateTimeOffset endTime = DateTime.UtcNow; DateTimeOffset startTime = endTime.AddMinutes(-3); var aggregateVariable = new AggregateVariable( new TimeSeriesExpression("count()")); var countVariableName = "Count"; var aggregateSeriesRequestOptions = new QueryAggregateSeriesRequestOptions(); aggregateSeriesRequestOptions.InlineVariables[countVariableName] = aggregateVariable; aggregateSeriesRequestOptions.ProjectedVariableNames.Add(countVariableName); TimeSeriesQueryAnalyzer query = queriesClient.CreateAggregateSeriesQuery( tsId, startTime, endTime, TimeSpan.FromSeconds(60), aggregateSeriesRequestOptions); await foreach (TimeSeriesPoint point in query.GetResultsAsync()) { long?temperatureCount = (long?)point.GetValue(countVariableName); Console.WriteLine($"{point.Timestamp} - Temperature count: {temperatureCount}"); } #endregion Snippet:TimeSeriesInsightsSampleQueryAggregateSeriesWithAggregateVariable }
private async Task RunQuerySeriesSampleWithInlineVariables(TimeSeriesInsightsQueries queriesClient, TimeSeriesId tsId) { // Query for two series, one with the temperature values in Celsius and another in Fahrenheit #region Snippet:TimeSeriesInsightsSampleQuerySeriesWithInlineVariables Console.WriteLine("\n\nQuery for temperature series in Celsius and Fahrenheit over the past 10 minutes.\n"); var celsiusVariable = new NumericVariable( new TimeSeriesExpression("$event.Temperature"), new TimeSeriesExpression("avg($value)")); var fahrenheitVariable = new NumericVariable( new TimeSeriesExpression("$event.Temperature * 1.8 + 32"), new TimeSeriesExpression("avg($value)")); var querySeriesRequestOptions = new QuerySeriesRequestOptions(); querySeriesRequestOptions.InlineVariables["TemperatureInCelsius"] = celsiusVariable; querySeriesRequestOptions.InlineVariables["TemperatureInFahrenheit"] = fahrenheitVariable; TimeSeriesQueryAnalyzer seriesQuery = queriesClient.CreateSeriesQuery( tsId, TimeSpan.FromMinutes(10), null, querySeriesRequestOptions); await foreach (TimeSeriesPoint point in seriesQuery.GetResultsAsync()) { double?tempInCelsius = (double?)point.GetValue("TemperatureInCelsius"); double?tempInFahrenheit = (double?)point.GetValue("TemperatureInFahrenheit"); Console.WriteLine($"{point.Timestamp} - Average temperature in Celsius: {tempInCelsius}. Average temperature in Fahrenheit: {tempInFahrenheit}."); } #endregion Snippet:TimeSeriesInsightsSampleQuerySeriesWithInlineVariables }
public async Task TimeSeriesInsightsQuery_AggregateSeriesWithNumericVariable() { // Arrange TimeSeriesInsightsClient tsiClient = GetClient(); TimeSeriesInsightsModelSettings timeSeriesModelSettings = tsiClient.GetModelSettingsClient(); TimeSeriesInsightsInstances instancesClient = tsiClient.GetInstancesClient(); TimeSeriesInsightsQueries queriesClient = tsiClient.GetQueriesClient(); DeviceClient deviceClient = await GetDeviceClient().ConfigureAwait(false); // Figure out what the Time Series Id is composed of TimeSeriesModelSettings modelSettings = await timeSeriesModelSettings.GetAsync().ConfigureAwait(false); // Create a Time Series Id where the number of keys that make up the Time Series Id is fetched from Model Settings TimeSeriesId tsiId = await GetUniqueTimeSeriesInstanceIdAsync(instancesClient, modelSettings.TimeSeriesIdProperties.Count) .ConfigureAwait(false); try { // Send some events to the IoT hub with with a second between each event await QueryTestsHelper.SendEventsToHubAsync( deviceClient, tsiId, modelSettings.TimeSeriesIdProperties.ToArray(), 30) .ConfigureAwait(false); DateTimeOffset now = Recording.UtcNow; DateTimeOffset endTime = now.AddMinutes(10); DateTimeOffset startTime = now.AddMinutes(-10); var temperatureNumericVariable = new NumericVariable( new TimeSeriesExpression($"$event.{QueryTestsHelper.Temperature}"), new TimeSeriesExpression("avg($value)")); var queryAggregateSeriesRequestOptions = new QueryAggregateSeriesRequestOptions(); queryAggregateSeriesRequestOptions.InlineVariables[QueryTestsHelper.Temperature] = temperatureNumericVariable; queryAggregateSeriesRequestOptions.ProjectedVariableNames.Add(QueryTestsHelper.Temperature); // This retry logic was added as the TSI instance are not immediately available after creation await TestRetryHelper.RetryAsync <AsyncPageable <TimeSeriesPoint> >(async() => { TimeSeriesQueryAnalyzer queryAggregateSeriesPages = queriesClient.CreateAggregateSeriesQuery( tsiId, startTime, endTime, TimeSpan.FromSeconds(5), queryAggregateSeriesRequestOptions); var nonNullFound = false; await foreach (Page <TimeSeriesPoint> aggregateSeriesPage in queryAggregateSeriesPages.GetResultsAsync().AsPages()) { foreach (TimeSeriesPoint point in aggregateSeriesPage.Values) { point.GetUniquePropertyNames().Should().HaveCount(1).And.Contain((property) => property == QueryTestsHelper.Temperature); var value = (double?)point.GetValue(QueryTestsHelper.Temperature); if (value != null) { nonNullFound = true; } } nonNullFound.Should().BeTrue(); } queryAggregateSeriesPages.Progress.Should().Be(100); return(null); }, MaxNumberOfRetries, s_retryDelay); // Add an interpolated variable var linearInterpolationNumericVariable = new NumericVariable( new TimeSeriesExpression($"$event.{QueryTestsHelper.Temperature}"), new TimeSeriesExpression("left($value)")); linearInterpolationNumericVariable.Interpolation = new TimeSeriesInterpolation { Kind = InterpolationKind.Linear, Boundary = new InterpolationBoundary() { Span = TimeSpan.FromSeconds(1), }, }; const string linearInterpolation = "linearInterpolation"; queryAggregateSeriesRequestOptions.InlineVariables[linearInterpolation] = linearInterpolationNumericVariable; queryAggregateSeriesRequestOptions.ProjectedVariableNames.Add(linearInterpolation); await TestRetryHelper.RetryAsync <AsyncPageable <TimeSeriesPoint> >(async() => { TimeSeriesQueryAnalyzer queryAggregateSeriesPages = queriesClient.CreateAggregateSeriesQuery( tsiId, startTime, endTime, TimeSpan.FromSeconds(5), queryAggregateSeriesRequestOptions); await foreach (Page <TimeSeriesPoint> aggregateSeriesPage in queryAggregateSeriesPages.GetResultsAsync().AsPages()) { aggregateSeriesPage.Values.Should().HaveCountGreaterThan(0); foreach (var point in aggregateSeriesPage.Values) { point.GetUniquePropertyNames().Should().HaveCount(2) .And .Contain((property) => property == QueryTestsHelper.Temperature) .And .Contain((property) => property == linearInterpolation); } } return(null); }, MaxNumberOfRetries, s_retryDelay); // Send 2 events with a special condition that can be used later to query on IDictionary <string, object> messageBase = QueryTestsHelper.BuildMessageBase(modelSettings.TimeSeriesIdProperties.ToArray(), tsiId); messageBase[QueryTestsHelper.Temperature] = 1.2; messageBase[QueryTestsHelper.Humidity] = 3.4; string messageBody = JsonSerializer.Serialize(messageBase); var message = new Message(Encoding.ASCII.GetBytes(messageBody)) { ContentType = "application/json", ContentEncoding = "utf-8", }; Func <Task> sendEventAct = async() => await deviceClient.SendEventAsync(message).ConfigureAwait(false); sendEventAct.Should().NotThrow(); // Send it again sendEventAct.Should().NotThrow(); // Query for the two events with a filter queryAggregateSeriesRequestOptions.Filter = new TimeSeriesExpression("$event.Temperature.Double = 1.2"); await TestRetryHelper.RetryAsync <AsyncPageable <TimeSeriesPoint> >(async() => { TimeSeriesQueryAnalyzer queryAggregateSeriesPages = queriesClient.CreateAggregateSeriesQuery( tsiId, startTime, endTime, TimeSpan.FromSeconds(5), queryAggregateSeriesRequestOptions); var valueFound = false; await foreach (TimeSeriesPoint point in queryAggregateSeriesPages.GetResultsAsync()) { point.GetUniquePropertyNames().Should().HaveCount(2) .And .Contain((property) => property == QueryTestsHelper.Temperature) .And .Contain((property) => property == linearInterpolation); var value = (double?)point.GetValue(QueryTestsHelper.Temperature); if (value == 1.2) { valueFound = true; } } valueFound.Should().BeTrue(); return(null); }, MaxNumberOfRetries, s_retryDelay); } finally { deviceClient?.Dispose(); } }
public async Task TimeSeriesInsightsQuery_AggregateSeriesWithCategoricalVariable() { // Arrange TimeSeriesInsightsClient tsiClient = GetClient(); TimeSeriesInsightsModelSettings timeSeriesInsightsModelSettings = tsiClient.GetModelSettingsClient(); TimeSeriesInsightsInstances instancesClient = tsiClient.GetInstancesClient(); TimeSeriesInsightsQueries queriesClient = tsiClient.GetQueriesClient(); DeviceClient deviceClient = await GetDeviceClient().ConfigureAwait(false); // Figure out what the Time Series Id is composed of TimeSeriesModelSettings modelSettings = await timeSeriesInsightsModelSettings.GetAsync().ConfigureAwait(false); // Create a Time Series Id where the number of keys that make up the Time Series Id is fetched from Model Settings TimeSeriesId tsiId = await GetUniqueTimeSeriesInstanceIdAsync(instancesClient, modelSettings.TimeSeriesIdProperties.Count) .ConfigureAwait(false); try { // Send some events to the IoT hub with with a second between each event await QueryTestsHelper.SendEventsToHubAsync( deviceClient, tsiId, modelSettings.TimeSeriesIdProperties.ToArray(), 30) .ConfigureAwait(false); DateTimeOffset now = Recording.UtcNow; DateTimeOffset endTime = now.AddMinutes(10); DateTimeOffset startTime = now.AddMinutes(-10); var queryAggregateSeriesRequestOptions = new QueryAggregateSeriesRequestOptions(); var categoricalVariable = new CategoricalVariable( new TimeSeriesExpression($"tolong($event.{QueryTestsHelper.Temperature}.Double)"), new TimeSeriesDefaultCategory("N/A")); categoricalVariable.Categories.Add(new TimeSeriesAggregateCategory("good", new List <object> { 1 })); queryAggregateSeriesRequestOptions.InlineVariables["categorical"] = categoricalVariable; await TestRetryHelper.RetryAsync <AsyncPageable <TimeSeriesPoint> >(async() => { TimeSeriesQueryAnalyzer queryAggregateSeriesPages = queriesClient.CreateAggregateSeriesQuery( tsiId, startTime, endTime, TimeSpan.FromSeconds(5), queryAggregateSeriesRequestOptions); await foreach (TimeSeriesPoint point in queryAggregateSeriesPages.GetResultsAsync()) { point.GetUniquePropertyNames().Should().HaveCount(3) .And .Contain((property) => property == "categorical[good]") .And .Contain((property) => property == "categorical[N/A]"); } return(null); }, MaxNumberOfRetries, s_retryDelay); } finally { deviceClient?.Dispose(); } }
public async Task TimeSeriesInsightsQuery_AggregateSeriesWithAggregateVariable() { // Arrange TimeSeriesInsightsClient tsiClient = GetClient(); TimeSeriesInsightsModelSettings timeSeriesModelSettings = tsiClient.GetModelSettingsClient(); TimeSeriesInsightsInstances instancesClient = tsiClient.GetInstancesClient(); TimeSeriesInsightsQueries queriesClient = tsiClient.GetQueriesClient(); DeviceClient deviceClient = await GetDeviceClient().ConfigureAwait(false); // Figure out what the Time Series Id is composed of TimeSeriesModelSettings modelSettings = await timeSeriesModelSettings.GetAsync().ConfigureAwait(false); // Create a Time Series Id where the number of keys that make up the Time Series Id is fetched from Model Settings TimeSeriesId tsiId = await GetUniqueTimeSeriesInstanceIdAsync(instancesClient, modelSettings.TimeSeriesIdProperties.Count) .ConfigureAwait(false); try { // Send some events to the IoT hub with with a second between each event await QueryTestsHelper.SendEventsToHubAsync( deviceClient, tsiId, modelSettings.TimeSeriesIdProperties.ToArray(), 30) .ConfigureAwait(false); // Query for temperature events with two calculateions. First with the temperature value as is, and the second // with the temperature value multiplied by 2. DateTimeOffset now = Recording.UtcNow; DateTimeOffset endTime = now.AddMinutes(10); DateTimeOffset startTime = now.AddMinutes(-10); var aggregateVariable = new AggregateVariable( new TimeSeriesExpression("count()")); var queryAggregateSeriesRequestOptions = new QueryAggregateSeriesRequestOptions(); queryAggregateSeriesRequestOptions.InlineVariables["Count"] = aggregateVariable; queryAggregateSeriesRequestOptions.ProjectedVariableNames.Add("Count"); // This retry logic was added as the TSI instance are not immediately available after creation await TestRetryHelper.RetryAsync <AsyncPageable <TimeSeriesPoint> >(async() => { TimeSeriesQueryAnalyzer queryAggregateSeriesPages = queriesClient.CreateAggregateSeriesQuery( tsiId, startTime, endTime, TimeSpan.FromSeconds(5), queryAggregateSeriesRequestOptions); long?totalCount = 0; await foreach (TimeSeriesPoint point in queryAggregateSeriesPages.GetResultsAsync()) { var currentCount = (long?)point.GetValue("Count"); totalCount += currentCount; } totalCount.Should().Be(30); return(null); }, MaxNumberOfRetries, s_retryDelay); } finally { deviceClient?.Dispose(); } }
private async Task RunQuerySeriesSampleWithPreDefinedVariables(TimeSeriesInsightsClient client, TimeSeriesId tsId) { // Setup TimeSeriesInsightsInstances instancesClient = client.GetInstancesClient(); TimeSeriesInsightsTypes typesClient = client.GetTypesClient(); TimeSeriesInsightsQueries queriesClient = client.GetQueriesClient(); // First create the Time Series type along with the numeric variables var timeSeriesTypes = new List <TimeSeriesType>(); var celsiusVariable = new NumericVariable( new TimeSeriesExpression("$event.Temperature"), new TimeSeriesExpression("avg($value)")); var fahrenheitVariable = new NumericVariable( new TimeSeriesExpression("$event.Temperature * 1.8 + 32"), new TimeSeriesExpression("avg($value)")); var celsiusVariableName = "TemperatureInCelsius"; var fahrenheitVariableName = "TemperatureInFahrenheit"; var variables = new Dictionary <string, TimeSeriesVariable> { { celsiusVariableName, celsiusVariable }, { fahrenheitVariableName, fahrenheitVariable } }; timeSeriesTypes.Add(new TimeSeriesType("TemperatureSensor", variables) { Id = "TemperatureSensorTypeId" }); Response <TimeSeriesTypeOperationResult[]> createTypesResult = await typesClient .CreateOrReplaceAsync(timeSeriesTypes) .ConfigureAwait(false); if (createTypesResult.Value.First().Error != null) { Console.WriteLine($"\n\nFailed to create a Time Series Insights type. " + $"Error Message: '{createTypesResult.Value.First().Error.Message}.' " + $"Code: '{createTypesResult.Value.First().Error.Code}'."); } // Get the Time Series instance and replace its type with the one we just created Response <InstancesOperationResult[]> getInstanceResult = await instancesClient .GetByIdAsync(new List <TimeSeriesId> { tsId }); if (getInstanceResult.Value.First().Error != null) { Console.WriteLine($"\n\nFailed to retrieve Time Series instance with Id '{tsId}'. " + $"Error Message: '{getInstanceResult.Value.First().Error.Message}.' " + $"Code: '{getInstanceResult.Value.First().Error.Code}'."); } TimeSeriesInstance instanceToReplace = getInstanceResult.Value.First().Instance; instanceToReplace.TimeSeriesTypeId = createTypesResult.Value.First().TimeSeriesType.Id; Response <InstancesOperationResult[]> replaceInstanceResult = await instancesClient .ReplaceAsync(new List <TimeSeriesInstance> { instanceToReplace }); if (replaceInstanceResult.Value.First().Error != null) { Console.WriteLine($"\n\nFailed to retrieve Time Series instance with Id '{tsId}'. " + $"Error Message: '{replaceInstanceResult.Value.First().Error.Message}.' " + $"Code: '{replaceInstanceResult.Value.First().Error.Code}'."); } // Now that we set up the instance with the property type, query for the data #region Snippet:TimeSeriesInsightsSampleQuerySeries Console.WriteLine($"\n\nQuery for temperature series in Celsius and Fahrenheit over the past 10 minutes. " + $"The Time Series instance belongs to a type that has predefined numeric variable that represents the temperature " + $"in Celsuis, and a predefined numeric variable that represents the temperature in Fahrenheit.\n"); DateTimeOffset endTime = DateTime.UtcNow; DateTimeOffset startTime = endTime.AddMinutes(-10); TimeSeriesQueryAnalyzer seriesQuery = queriesClient.CreateSeriesQuery( tsId, startTime, endTime); await foreach (TimeSeriesPoint point in seriesQuery.GetResultsAsync()) { double?tempInCelsius = point.GetNullableDouble(celsiusVariableName); double?tempInFahrenheit = point.GetNullableDouble(fahrenheitVariableName); Console.WriteLine($"{point.Timestamp} - Average temperature in Celsius: {tempInCelsius}. " + $"Average temperature in Fahrenheit: {tempInFahrenheit}."); } #endregion Snippet:TimeSeriesInsightsSampleQuerySeries }
private async Task RunQueryEventsSample(TimeSeriesInsightsQueries queriesClient, TimeSeriesId tsId) { #region Snippet:TimeSeriesInsightsSampleQueryEvents Console.WriteLine("\n\nQuery for raw temperature events over the past 10 minutes.\n"); // Get events from last 10 minute DateTimeOffset endTime = DateTime.UtcNow; DateTimeOffset startTime = endTime.AddMinutes(-10); TimeSeriesQueryAnalyzer temperatureEventsQuery = queriesClient.CreateEventsQuery(tsId, startTime, endTime); await foreach (TimeSeriesPoint point in temperatureEventsQuery.GetResultsAsync()) { TimeSeriesValue temperatureValue = point.GetValue("Temperature"); // Figure out what is the underlying type for the time series value. Since you know your Time Series Insights // environment best, you probably do not need this logic and you can skip to directly casting to the proper // type. This logic demonstrates how you can figure out what type to cast to in the case where you are not // too familiar with the property type. if (temperatureValue.Type == typeof(double?)) { Console.WriteLine($"{point.Timestamp} - Temperature: {point.GetNullableDouble("Temperature")}"); } else if (temperatureValue.Type == typeof(int?)) { Console.WriteLine($"{point.Timestamp} - Temperature: {point.GetNullableInt("Temperature")}"); } else { Console.WriteLine("The type of the Time Series value for Temperature is not numeric."); } } #endregion Snippet:TimeSeriesInsightsSampleQueryEvents // Query for raw events using a time interval #region Snippet:TimeSeriesInsightsSampleQueryEventsUsingTimeSpan Console.WriteLine("\n\nQuery for raw humidity events over the past 30 seconds.\n"); TimeSeriesQueryAnalyzer humidityEventsQuery = queriesClient.CreateEventsQuery(tsId, TimeSpan.FromSeconds(30)); await foreach (TimeSeriesPoint point in humidityEventsQuery.GetResultsAsync()) { TimeSeriesValue humidityValue = point.GetValue("Humidity"); // Figure out what is the underlying type for the time series value. Since you know your Time Series Insights // environment best, you probably do not need this logic and you can skip to directly casting to the proper // type. This logic demonstrates how you can figure out what type to cast to in the case where you are not // too familiar with the property type. if (humidityValue.Type == typeof(double?)) { Console.WriteLine($"{point.Timestamp} - Humidity: {point.GetNullableDouble("Humidity")}"); } else if (humidityValue.Type == typeof(int?)) { Console.WriteLine($"{point.Timestamp} - Humidity: {point.GetNullableInt("Humidity")}"); } else { Console.WriteLine("The type of the Time Series value for Humidity is not numeric."); } } #endregion Snippet:TimeSeriesInsightsSampleQueryEventsUsingTimeSpan }
public async Task TimeSeriesInsightsQuery_GetEventsLifecycle() { // Arrange TimeSeriesInsightsClient tsiClient = GetClient(); TimeSeriesInsightsModelSettings timeSeriesModelSettings = tsiClient.GetModelSettingsClient(); TimeSeriesInsightsInstances instancesClient = tsiClient.GetInstancesClient(); TimeSeriesInsightsQueries queriesClient = tsiClient.GetQueriesClient(); DeviceClient deviceClient = await GetDeviceClient().ConfigureAwait(false); // Figure out what the Time Series Id is composed of TimeSeriesModelSettings modelSettings = await timeSeriesModelSettings.GetAsync().ConfigureAwait(false); // Create a Time Series Id where the number of keys that make up the Time Series Id is fetched from Model Settings TimeSeriesId tsiId = await GetUniqueTimeSeriesInstanceIdAsync(instancesClient, modelSettings.TimeSeriesIdProperties.Count) .ConfigureAwait(false); try { var initialEventsCount = 50; // Send some events to the IoT hub await QueryTestsHelper.SendEventsToHubAsync( deviceClient, tsiId, modelSettings.TimeSeriesIdProperties.ToArray(), initialEventsCount) .ConfigureAwait(false); // Act // Get events from last 10 minute DateTimeOffset now = Recording.UtcNow; DateTimeOffset endTime = now.AddMinutes(10); DateTimeOffset startTime = now.AddMinutes(-10); // This retry logic was added as the TSI instance are not immediately available after creation await TestRetryHelper.RetryAsync <AsyncPageable <TimeSeriesPoint> >(async() => { TimeSeriesQueryAnalyzer queryEventsPages = queriesClient.CreateEventsQuery(tsiId, startTime, endTime); var count = 0; await foreach (TimeSeriesPoint timeSeriesPoint in queryEventsPages.GetResultsAsync()) { count++; timeSeriesPoint.Timestamp.Should().BeAfter(startTime).And.BeBefore(endTime); var temperatureValue = timeSeriesPoint.GetNullableDouble(QueryTestsHelper.Temperature); temperatureValue.Should().NotBeNull(); var humidityValue = (double?)timeSeriesPoint.GetValue(QueryTestsHelper.Humidity); humidityValue.Should().NotBeNull(); } count.Should().Be(initialEventsCount); return(null); }, MaxNumberOfRetries, s_retryDelay); // Send 2 events with a special condition that can be used later to query on IDictionary <string, object> messageBase = QueryTestsHelper.BuildMessageBase( modelSettings.TimeSeriesIdProperties.ToArray(), tsiId); messageBase[QueryTestsHelper.Temperature] = 1.2; messageBase[QueryTestsHelper.Humidity] = 3.4; string messageBody = JsonSerializer.Serialize(messageBase); var message = new Message(Encoding.ASCII.GetBytes(messageBody)) { ContentType = "application/json", ContentEncoding = "utf-8", }; Func <Task> sendEventAct = async() => await deviceClient.SendEventAsync(message).ConfigureAwait(false); await sendEventAct.Should().NotThrowAsync(); // Send it again sendEventAct.Should().NotThrow(); // Query for the two events with a filter // Only project Temperature and one of the Id properties var queryRequestOptions = new QueryEventsRequestOptions { Filter = new TimeSeriesExpression("$event.Temperature.Double = 1.2"), Store = StoreType.WarmStore, }; queryRequestOptions.ProjectedProperties.Add( new TimeSeriesInsightsEventProperty { Name = QueryTestsHelper.Temperature, PropertyValueType = "Double", }); queryRequestOptions.ProjectedProperties.Add( new TimeSeriesInsightsEventProperty { Name = modelSettings.TimeSeriesIdProperties.First().Name, PropertyValueType = modelSettings.TimeSeriesIdProperties.First().PropertyType.ToString(), }); await TestRetryHelper.RetryAsync <AsyncPageable <TimeSeriesPoint> >(async() => { TimeSeriesQueryAnalyzer queryEventsPages = queriesClient.CreateEventsQuery(tsiId, startTime, endTime, queryRequestOptions); await foreach (Page <TimeSeriesPoint> page in queryEventsPages.GetResultsAsync().AsPages()) { page.Values.Should().HaveCount(2); foreach (TimeSeriesPoint point in page.Values) { var value = (double?)point.GetValue(QueryTestsHelper.Temperature); value.Should().Be(1.2); } } return(null); }, MaxNumberOfRetries, s_retryDelay); // Query for the two events with a filter, but only take 1 queryRequestOptions.MaxNumberOfEvents = 1; TimeSeriesQueryAnalyzer queryEventsPagesWithFilter = queriesClient.CreateEventsQuery(tsiId, startTime, endTime, queryRequestOptions); await foreach (Page <TimeSeriesPoint> page in queryEventsPagesWithFilter.GetResultsAsync().AsPages()) { page.Values.Should().HaveCount(1); } await TestRetryHelper.RetryAsync <AsyncPageable <TimeSeriesPoint> >(async() => { // Query for all the events using a timespan TimeSeriesQueryAnalyzer queryEventsPagesWithTimespan = queriesClient .CreateEventsQuery(tsiId, TimeSpan.FromMinutes(20), endTime); await foreach (Page <TimeSeriesPoint> page in queryEventsPagesWithTimespan.GetResultsAsync().AsPages()) { page.Values.Should().HaveCount(52); foreach (TimeSeriesPoint point in page.Values) { point.Timestamp.Should().BeAfter(startTime).And.BeBefore(endTime); var temperatureValue = (double?)point.GetValue(QueryTestsHelper.Temperature); temperatureValue.Should().NotBeNull(); var humidityValue = (double?)point.GetValue(QueryTestsHelper.Humidity); humidityValue.Should().NotBeNull(); } } return(null); }, MaxNumberOfRetries, s_retryDelay); } finally { deviceClient?.Dispose(); } }
public async Task TimeSeriesInsightsQuery_GetSeriesLifecycle() { // Arrange TimeSeriesInsightsClient tsiClient = GetClient(); TimeSeriesInsightsModelSettings timeSeriesModelSettings = tsiClient.GetModelSettingsClient(); TimeSeriesInsightsInstances instancesClient = tsiClient.GetInstancesClient(); TimeSeriesInsightsQueries queriesClient = tsiClient.GetQueriesClient(); DeviceClient deviceClient = await GetDeviceClient().ConfigureAwait(false); // Figure out what the Time Series Id is composed of TimeSeriesModelSettings modelSettings = await timeSeriesModelSettings.GetAsync().ConfigureAwait(false); // Create a Time Series Id where the number of keys that make up the Time Series Id is fetched from Model Settings TimeSeriesId tsiId = await GetUniqueTimeSeriesInstanceIdAsync(instancesClient, modelSettings.TimeSeriesIdProperties.Count) .ConfigureAwait(false); try { // Send some events to the IoT hub await QueryTestsHelper.SendEventsToHubAsync( deviceClient, tsiId, modelSettings.TimeSeriesIdProperties.ToArray(), 10) .ConfigureAwait(false); // Act // Query for temperature events with two calculations. First with the temperature value as is, and the second // with the temperature value multiplied by 2. DateTimeOffset now = Recording.UtcNow; DateTimeOffset endTime = now.AddMinutes(10); DateTimeOffset startTime = now.AddMinutes(-10); var temperatureNumericVariable = new NumericVariable( new TimeSeriesExpression($"$event.{QueryTestsHelper.Temperature}"), new TimeSeriesExpression("avg($value)")); var temperatureNumericVariableTimesTwo = new NumericVariable( new TimeSeriesExpression($"$event.{QueryTestsHelper.Temperature} * 2"), new TimeSeriesExpression("avg($value)")); var temperatureTimesTwoVariableName = $"{QueryTestsHelper.Temperature}TimesTwo"; var querySeriesRequestOptions = new QuerySeriesRequestOptions(); querySeriesRequestOptions.InlineVariables[QueryTestsHelper.Temperature] = temperatureNumericVariable; querySeriesRequestOptions.InlineVariables[temperatureTimesTwoVariableName] = temperatureNumericVariableTimesTwo; // This retry logic was added as the TSI instance are not immediately available after creation await TestRetryHelper.RetryAsync <AsyncPageable <TimeSeriesPoint> >(async() => { TimeSeriesQueryAnalyzer querySeriesEventsPages = queriesClient.CreateSeriesQuery( tsiId, startTime, endTime, querySeriesRequestOptions); await foreach (Page <TimeSeriesPoint> seriesEventsPage in querySeriesEventsPages.GetResultsAsync().AsPages()) { seriesEventsPage.Values.Should().HaveCount(10); for (int index = 0; index < seriesEventsPage.Values.Count; index++) { TimeSeriesPoint point = seriesEventsPage.Values[index]; point.Timestamp.Should().BeAfter(startTime).And.BeBefore(endTime); point.GetUniquePropertyNames().Should().HaveCount(3); point.GetUniquePropertyNames().Should().Contain((property) => property == QueryTestsHelper.Temperature) .And .Contain((property) => property == temperatureTimesTwoVariableName); // Assert that the values for the Temperature property is equal to the values for the other property, multiplied by 2 var temperatureTimesTwoValue = (double?)point.GetValue(temperatureTimesTwoVariableName); var temperatureValue = (double?)point.GetValue(QueryTestsHelper.Temperature); temperatureTimesTwoValue.Should().Be(temperatureValue * 2); } } return(null); }, MaxNumberOfRetries, s_retryDelay); // Query for all the series events using a timespan TimeSeriesQueryAnalyzer querySeriesEventsPagesWithTimespan = queriesClient .CreateSeriesQuery(tsiId, TimeSpan.FromMinutes(10), null, querySeriesRequestOptions); await foreach (Page <TimeSeriesPoint> seriesEventsPage in querySeriesEventsPagesWithTimespan.GetResultsAsync().AsPages()) { seriesEventsPage.Values.Should().HaveCount(10); foreach (TimeSeriesPoint point in seriesEventsPage.Values) { point.GetUniquePropertyNames().Should().HaveCount(3); } } // Query for temperature and humidity var humidityNumericVariable = new NumericVariable( new TimeSeriesExpression("$event.Humidity"), new TimeSeriesExpression("avg($value)")); querySeriesRequestOptions.InlineVariables[QueryTestsHelper.Humidity] = humidityNumericVariable; querySeriesRequestOptions.ProjectedVariableNames.Add(QueryTestsHelper.Temperature); querySeriesRequestOptions.ProjectedVariableNames.Add(QueryTestsHelper.Humidity); await TestRetryHelper.RetryAsync <AsyncPageable <TimeSeriesPoint> >(async() => { TimeSeriesQueryAnalyzer querySeriesEventsPages = queriesClient.CreateSeriesQuery(tsiId, startTime, endTime, querySeriesRequestOptions); await foreach (Page <TimeSeriesPoint> seriesEventsPage in querySeriesEventsPages.GetResultsAsync().AsPages()) { seriesEventsPage.Values.Should().HaveCount(10); foreach (TimeSeriesPoint point in seriesEventsPage.Values) { point.Timestamp.Should().BeAfter(startTime).And.BeBefore(endTime); point.GetUniquePropertyNames().Should().HaveCount(2) .And .Contain((property) => property == QueryTestsHelper.Temperature) .And .Contain((property) => property == QueryTestsHelper.Humidity); } } return(null); }, MaxNumberOfRetries, s_retryDelay); // Send 2 events with a special condition that can be used later to query on IDictionary <string, object> messageBase = QueryTestsHelper.BuildMessageBase(modelSettings.TimeSeriesIdProperties.ToArray(), tsiId); messageBase[QueryTestsHelper.Temperature] = 1.2; messageBase[QueryTestsHelper.Humidity] = 3.4; string messageBody = JsonSerializer.Serialize(messageBase); var message = new Message(Encoding.ASCII.GetBytes(messageBody)) { ContentType = "application/json", ContentEncoding = "utf-8", }; Func <Task> sendEventAct = async() => await deviceClient.SendEventAsync(message).ConfigureAwait(false); sendEventAct.Should().NotThrow(); // Send it again sendEventAct.Should().NotThrow(); // Query for the two events with a filter querySeriesRequestOptions.Filter = new TimeSeriesExpression("$event.Temperature.Double = 1.2"); await TestRetryHelper.RetryAsync <AsyncPageable <TimeSeriesPoint> >(async() => { TimeSeriesQueryAnalyzer querySeriesEventsPages = queriesClient.CreateSeriesQuery(tsiId, startTime, endTime, querySeriesRequestOptions); await foreach (Page <TimeSeriesPoint> seriesEventsPage in querySeriesEventsPages.GetResultsAsync().AsPages()) { seriesEventsPage.Values.Should().HaveCount(2); foreach (TimeSeriesPoint point in seriesEventsPage.Values) { point.GetUniquePropertyNames().Should().HaveCount(2); var temperatureValue = (double?)point.GetValue(QueryTestsHelper.Temperature); temperatureValue.Should().Be(1.2); } } return(null); }, MaxNumberOfRetries, s_retryDelay); // Query for the two events with a filter, but only take 1 querySeriesRequestOptions.MaxNumberOfEvents = 1; TimeSeriesQueryAnalyzer querySeriesEventsPagesWithFilter = queriesClient.CreateSeriesQuery(tsiId, startTime, endTime, querySeriesRequestOptions); await foreach (Page <TimeSeriesPoint> seriesEventsPage in querySeriesEventsPagesWithFilter.GetResultsAsync().AsPages()) { seriesEventsPage.Values.Should().HaveCount(1); } } finally { deviceClient?.Dispose(); } }