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); QueryAnalyzer 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"); QueryAnalyzer 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(); } }