/// <summary> /// Retrieve historic weather datapoints from the Wunderground Api /// </summary> /// <param name="wunderGroundUrl">The Url of the Wunderground API</param> /// <param name="regionSubUrl">Sub Url of the region on the Wunderground weather API e.g. CA/San_Francisco</param> /// <param name="wundergroundApiKey">The Wunderground API Key</param> /// <param name="startDateTime">startDateTime</param> /// <param name="endDateTime">endDateTime</param> /// <param name="timeout">Optional Timeout value for the call</param> /// <returns>Historic weather datapoints from the Wunderground Api</returns> public List <Observation> GetHistoricWeatherData( string wunderGroundUrl, string regionSubUrl, string wundergroundApiKey, DateTime startDateTime, DateTime?endDateTime = null, TimeSpan?timeout = null) { const string SubUrl = "history_"; var currentDateTime = startDateTime; DateTime queryFinishDateTime = endDateTime ?? DateTime.UtcNow; var fullObservationsList = new List <Observation>(); while (currentDateTime.Date <= queryFinishDateTime) { var queryDateString = $"{currentDateTime:yyyyMMdd}"; var apiQueryUrl = $"{wunderGroundUrl}{wundergroundApiKey}/{SubUrl}{queryDateString}/q/{regionSubUrl}.json"; var webApiHelper = new WebApiSerializerHelper <RootObject>(); var response = this.apiInteractionHelper.ExecuteThrottledApiCall <WundergroundHistoricDataClasses.RootObject> (timeout, webApiHelper, apiQueryUrl, null, wundergroundApiKey, apiNameForThrottlingRecords); fullObservationsList.AddRange(response.history.observations); currentDateTime = currentDateTime.AddDays(1); } var processedObservationsList = this.AddConcreteDateTimeToHistoricWeatherDatapointList(fullObservationsList); return(processedObservationsList); }
/// <summary> /// Retrieve latest marginal carbon data for a given region from the WattTime API /// </summary> /// <param name="WattTimeUrl">URL of the Watt Time API</param> /// <param name="regionAbbreviation">Abbreviation for the required region (e.g. "PJM"). See https://api.watttime.org/faq/#where </param> /// <param name="WattTimeUsername">WattTime Username</param> /// <param name="WattTimePassword">WattTime Password</param> /// <param name="timeout">Optional Timeout value</param> /// <param name="startDateTime">startDateTime</param> /// <param name="endDateTime">endDateTime</param> /// <param name="customUrlParams">Optional customUrlParams to add to construct a custom query</param> /// <returns>The latest marginal carbon data for a given region from the WattTime API</returns> public List <MarginalCarbonResultV2Api> GetMarginalCarbonResults(string WattTimeUrl, string regionAbbreviation, string WattTimeUsername, string WattTimePassword, DateTime?startDateTime = null, DateTime?endDateTime = null, TimeSpan?timeout = null, string customUrlParams = null) { var resultsList = new List <MarginalCarbonResultV2Api>(); const string subUrl = "v2/data/"; var apiQueryUrl = $"{WattTimeUrl}{subUrl}"; string urlParameters = $"?ba={regionAbbreviation}&page_size=1000"; var authToken = RetrieveWattTimeAuthToken(WattTimeUrl, WattTimeUsername, WattTimePassword); var authTokenKey = authToken.Token; urlParameters = AppendOptionalWattTimeFormattedStartAndEndDateTimeParameters(startDateTime, endDateTime, urlParameters, true); if (customUrlParams != null) { urlParameters = customUrlParams.StartsWith("&") ? $"{urlParameters}{customUrlParams}" : $"{urlParameters}&{customUrlParams}"; } var webApiHelper = new WebApiSerializerHelper <List <MarginalCarbonResultV2Api> >(); var response = this.apiInteractionHelper.ExecuteThrottledApiCallWithBearerAuthToken <List <MarginalCarbonResultV2Api> >( timeout, webApiHelper, apiQueryUrl, urlParameters, authTokenKey, apiNameForThrottlingRecords); return(response); }
/// <summary> /// Make a call to an API with the given details, and apply the specified self-throttling method /// </summary> /// <typeparam name="T">Type to desearalize the data returned into</typeparam> /// <param name="timeout">Optional time to give up after</param> /// <param name="webApiHelper">WebApiSerializerHelper of a given type</param> /// <param name="apiQueryUrl">URL of the API</param> /// <param name="urlParameters">Optional paramaters for the API call</param> /// <param name="apiKey">Optional APIKey for the API</param> /// <param name="apiName">Optional Name of the API for logging</param> /// <returns>Results of the API call, desearilized into the given object type</returns> public T ExecuteThrottledApiCallWithBearerAuthToken <T>( TimeSpan?timeout, WebApiSerializerHelper <T> webApiHelper, string apiQueryUrl, string urlParameters, string bearerAuthToken = null, string apiName = null) { ExecuteSelfThrottlingPolicy(bearerAuthToken, apiName); var response = webApiHelper.GetHttpResponseContentAsType <T>(apiQueryUrl, urlParameters, bearerAuthToken, timeout).Result; return(response); }
/// <summary> /// Execute the given call against the Wunderground API with the response serialized into type T /// </summary> /// <typeparam name="T"></typeparam> /// <param name="wunderGroundUrl"></param> /// <param name="regionSubUrl"></param> /// <param name="wundergroundApiKey"></param> /// <param name="timeout"></param> /// <param name="SubUrl"></param> /// <returns></returns> private T ExecuteWunderApiCall <T>( string wunderGroundUrl, string regionSubUrl, string wundergroundApiKey, TimeSpan?timeout, string SubUrl) { var apiQueryUrl = $"{wunderGroundUrl}{wundergroundApiKey}/{SubUrl}/q/{regionSubUrl}.json"; var webApiHelper = new WebApiSerializerHelper <T>(); var response = this.apiInteractionHelper.ExecuteThrottledApiCall(timeout, webApiHelper, apiQueryUrl, null, wundergroundApiKey, apiNameForThrottlingRecords); return(response); }
/// <summary> /// Execute the given call against the Wunderground API with the response serialized into type T /// </summary> /// <typeparam name="T"></typeparam> /// <param name="wunderGroundUrl"></param> /// <param name="gpsLat"></param> /// <param name="gpsLong"></param> /// <param name="wundergroundApiKey"></param> /// <param name="timeout"></param> /// <returns></returns> private T ExecuteWundergroundGpsLookupApiCall <T>( string wunderGroundUrl, double gpsLat, double gpsLong, string wundergroundApiKey, TimeSpan?timeout) { var apiQueryUrl = $"{wunderGroundUrl}{wundergroundApiKey}/geolookup/q/{gpsLat},{gpsLong}.json"; var webApiHelper = new WebApiSerializerHelper <T>(); var response = this.apiInteractionHelper.ExecuteThrottledApiCall(timeout, webApiHelper, apiQueryUrl, null, wundergroundApiKey, apiNameForThrottlingRecords); return(response); }
/// <summary> /// Retrieve forecast weather datapoints from the Wunderground Api /// </summary> /// <param name="wunderGroundUrl">The Url of the Wunderground API</param> /// <param name="regionSubUrl">Sub Url of the region on the Wunderground weather API e.g. CA/San_Francisco</param> /// <param name="wundergroundApiKey">The Wunderground API Key</param> /// <param name="timeout">Optional Timeout value for the call</param> /// <returns>Forecast weather datapoints from the Wunderground Api</returns> public List <WundergroundThreeDayForecastSummaryDataClasses.Forecastday2> GetThreeDayForecastSummaryWeatherData( string wunderGroundUrl, string regionSubUrl, string wundergroundApiKey, TimeSpan?timeout = null) { const string SubUrl = "forecast"; var apiQueryUrl = $"{wunderGroundUrl}{wundergroundApiKey}/{SubUrl}/q/{regionSubUrl}.json"; var webApiHelper = new WebApiSerializerHelper <WundergroundThreeDayForecastSummaryDataClasses.RootObject>(); var response = this.apiInteractionHelper.ExecuteThrottledApiCall(timeout, webApiHelper, apiQueryUrl, null, wundergroundApiKey, apiNameForThrottlingRecords); var processedObservationsList = this.AddConcreteDateTimeToThreeDayWeatherForecastList(response.forecast.simpleforecast.forecastday); return(processedObservationsList); }
/// <summary> /// Retrieve latest marginal carbon data for a given region from the WattTime API /// </summary> /// <param name="WattTimeUrl">URL of the Watt Time API</param> /// <param name="regionAbbreviation">Abbreviation for the required region (e.g. "PJM"). See https://api.watttime.org/faq/#where </param> /// <param name="timeout">Optional Timeout value</param> /// <param name="startDateTime">startDateTime</param> /// <param name="endDateTime">endDateTime</param> /// <param name="wattTimeApiKey">>WattTime Api Key</param> /// <param name="customUrlParams">Optional customUrlParams to add to construct a custom query</param> /// <returns>The latest marginal carbon data for a given region from the WattTime API</returns> public List <MarginalCarbonResult.Result> GetMarginalCarbonResults(string WattTimeUrl, string regionAbbreviation, DateTime?startDateTime = null, DateTime?endDateTime = null, TimeSpan?timeout = null, string wattTimeApiKey = null, string customUrlParams = null) { var resultsList = new List <MarginalCarbonResult.Result>(); const string subUrl = "marginal/"; var apiQueryUrl = $"{WattTimeUrl}{subUrl}"; string urlParameters = $"?ba={regionAbbreviation}&page_size=1000"; urlParameters = AppendOptionalWattTimeFormattedStartAndEndDateTimeParameters(startDateTime, endDateTime, urlParameters); if (customUrlParams != null) { urlParameters = customUrlParams.StartsWith("&") ? $"{urlParameters}{customUrlParams}" : $"{urlParameters}&{customUrlParams}"; } var webApiHelper = new WebApiSerializerHelper <MarginalCarbonResult.RootObject>(); var response = this.apiInteractionHelper.ExecuteThrottledApiCall <MarginalCarbonResult.RootObject>( timeout, webApiHelper, apiQueryUrl, urlParameters, wattTimeApiKey, apiNameForThrottlingRecords); // Cycle through the next page until there are no more results resultsList = response.results; var nextPageUrl = response.next; while (nextPageUrl != null) { var furtherResults = this.apiInteractionHelper.ExecuteThrottledApiCall <MarginalCarbonResult.RootObject>( timeout, webApiHelper, nextPageUrl, null, wattTimeApiKey, apiNameForThrottlingRecords); resultsList.AddRange(furtherResults.results); nextPageUrl = furtherResults.next; } return(resultsList); }
/// <summary> /// Execute the given call against the Wunderground API with the response serialized into type T /// </summary> /// <typeparam name="T"></typeparam> /// <param name="wunderGroundUrl"></param> /// <param name="gpsLat"></param> /// <param name="gpsLong"></param> /// <param name="apiKey"></param> /// <param name="timeout"></param> /// <returns></returns> private T ExecuteDarkSkyGpsLookupApiCall <T>( string darkSkyUrl, string darkSkyApiKey, string subUrl, double gpsLat, double gpsLong, string apiKey, TimeSpan?timeout, string customParams = null) { var apiQueryUrl = $"{darkSkyUrl}{subUrl}/{darkSkyApiKey}/{gpsLat},{gpsLong}{customParams}"; var webApiHelper = new WebApiSerializerHelper <T>(); var response = this.apiInteractionHelper.ExecuteThrottledApiCall(timeout, webApiHelper, apiQueryUrl, null, apiKey, apiNameForThrottlingRecords); return(response); }
/// <summary> /// Retrieve latest Automated Emissions Reductions Index Result for a given region from the WattTime API /// </summary> /// <param name="WattTimeUrl">URL of the Watt Time API</param> /// <param name="regionAbbreviation">Abbreviation for the required region (e.g. "PJM"). See https://api.watttime.org/faq/#where </param> /// <param name="WattTimeUsername">WattTime Username</param> /// <param name="WattTimePassword">WattTime Password</param> /// <param name="timeout">Optional Timeout value</param> /// <returns></returns> public AutomatedEmissionsReductionsIndexResult GetCarbonEmissionsRelativeMeritResults(string WattTimeUrl, string regionAbbreviation, string WattTimeUsername, string WattTimePassword, TimeSpan?timeout = null) { //url: '/index/' // params = { // "ba":"CAISO_NP15", // "latitude":"", // "longitude":"", // "style": "rating", "percent", "switch" or "all". Default is "rating" // } // output: // { // "ba": "ERCOT", // "freq": 0.8008281904610115, // "market": "RTM", // "percent": 53, -- 0 is best, 100 is worst // "rating": 4, -- 0 is best, 5 is worst // "switch": 0, -- 1 = don't use power. 0 = use power. // "validFor": 277, // "validUntil": "2000-01-23T04:56:07.000+00:00" // } const string subUrl = "v2/index/"; var apiQueryUrl = $"{WattTimeUrl}{subUrl}"; string urlParameters = $"?ba={regionAbbreviation}&style=all&page_size=1000"; var authToken = RetrieveWattTimeAuthToken(WattTimeUrl, WattTimeUsername, WattTimePassword); var authTokenKey = authToken.Token; var webApiHelper = new WebApiSerializerHelper <AutomatedEmissionsReductionsIndexResult>(); var result = this.apiInteractionHelper.ExecuteThrottledApiCallWithBearerAuthToken <AutomatedEmissionsReductionsIndexResult>( timeout, webApiHelper, apiQueryUrl, urlParameters, authTokenKey, apiNameForThrottlingRecords); return(result); }
/// <summary> /// Make a call to an API with the given details, and apply the specified self-throttling method /// </summary> /// <typeparam name="T">Type to desearalize the data returned into</typeparam> /// <param name="timeout">Optional time to give up after</param> /// <param name="webApiHelper">WebApiSerializerHelper of a given type</param> /// <param name="apiQueryUrl">URL of the API</param> /// <param name="urlParameters">Optional paramaters for the API call</param> /// <param name="apiKey">Optional APIKey for the API</param> /// <param name="apiName">Optional Name of the API for logging</param> /// <returns>Results of the API call, desearilized into the given object type</returns> public T ExecuteThrottledApiCall <T>( TimeSpan?timeout, WebApiSerializerHelper <T> webApiHelper, string apiQueryUrl, string urlParameters, string apiKey = null, string apiName = null) { switch (_selfThrottlingMethod) { case SelfThrottlingMethod.InMemoryCallRecollection: // Check if we have hit our limit for number of calls to the API while (!this.VerifyInMemoryThrottledCallCanProceed()) { Logger.Information($"Delaying issueing call to {apiName} API to ensure API throttling isn't exceeded at {DateTime.UtcNow}", "ApiInteractionHelper: ExecuteThrottledApiCall()"); Thread.Sleep(500); } // Add this call to the call tracker this.recentApiCalls.Add(DateTime.UtcNow); break; case SelfThrottlingMethod.AzureTableStorageCallRecollection: // Check if we have hit our limit for number of calls to the API while (!this.VerifyAzureTableStorageThrottledCallCanProceed(apiKey, apiName)) { Logger.Information($"Delaying issueing call to {apiName} API to ensure API throttling isn't exceeded at {DateTime.UtcNow}", "ApiInteractionHelper: ExecuteThrottledApiCall()"); Thread.Sleep(500); } // Add this call to the call tracker AzureTableStorageHelper.LogApiCallToTableStorage(new ApiCallRecordTableEntity(apiKey, apiName)); break; case SelfThrottlingMethod.None: default: // Apply no throttling - proceed with call break; } var response = webApiHelper.GetHttpResponseContentAsType <T>(apiQueryUrl, urlParameters, timeout, apiKey).Result; return(response); }
/// <summary> /// Retrieve latest Generation Mix and System Wide Emissions data for a given region from the WattTime API /// </summary> /// <param name="WattTimeUrl">URL of the Watt Time API</param> /// <param name="regionAbbreviation">Abbreviation for the required region (e.g. "PJM"). See https://api.watttime.org/faq/#where </param> /// <param name="startDateTime">startDateTime</param> /// <param name="endDateTime">endDateTime</param> /// <param name="timeout">Optional Timeout value</param> /// <param name="wattTimeApiKey">WattTime Api Key</param> /// <returns>Latest Generation Mix and System Wide Emissions data for a given region from the WattTime API</returns> public List <GenerationMixResultList.Result> GetGenerationMixAndSystemWideEmissionsResults(string WattTimeUrl, string regionAbbreviation, DateTime?startDateTime = null, DateTime?endDateTime = null, TimeSpan?timeout = null, string wattTimeApiKey = null) { var resultsList = new List <GenerationMixResultList.Result>(); const string subUrl = "datapoints/"; var apiQueryUrl = $"{WattTimeUrl}{subUrl}"; string urlParameters = $"?ba={regionAbbreviation}&page_size=1000"; urlParameters = AppendOptionalWattTimeFormattedStartAndEndDateTimeParameters(startDateTime, endDateTime, urlParameters); var webApiHelper = new WebApiSerializerHelper <GenerationMixResultList.RootObject>(); var response = this.apiInteractionHelper.ExecuteThrottledApiCall <GenerationMixResultList.RootObject>( timeout, webApiHelper, apiQueryUrl, urlParameters, wattTimeApiKey, apiNameForThrottlingRecords); // Cycle through the next page until there are no more results resultsList = response.results; var nextPageUrl = response.next; while (nextPageUrl != null) { var furtherResults = this.apiInteractionHelper.ExecuteThrottledApiCall <GenerationMixResultList.RootObject>( timeout, webApiHelper, nextPageUrl, null, wattTimeApiKey, apiNameForThrottlingRecords); resultsList.AddRange(furtherResults.results); nextPageUrl = furtherResults.next; } return(resultsList); }
/// <summary> /// Retrieve historic weather datapoints from the Wunderground Api /// </summary> /// <param name="wunderGroundUrl">The Url of the Wunderground API</param> /// <param name="gpsLat">GPS Latitude</param> /// <param name="gpsLong">GPS Longtitude</param> /// <param name="wundergroundApiKey">The Wunderground API Key</param> /// <param name="startDateTime">startDateTime</param> /// <param name="endDateTime">endDateTime</param> /// <param name="timeout">Optional Timeout value for the call</param> /// <returns>Historic weather datapoints from the Wunderground Api</returns> public List <Observation> GetHistoricWeatherData( string wunderGroundUrl, double gpsLat, double gpsLong, string wundergroundApiKey, DateTime startDateTime, DateTime?endDateTime = null, TimeSpan?timeout = null) { const string SubUrl = "history_"; var currentDateTime = startDateTime; DateTime queryFinishDateTime = endDateTime ?? DateTime.UtcNow; var fullObservationsList = new List <Observation>(); string queryDateString = $"{currentDateTime:yyyyMMdd}"; var webApiHelper = new WebApiSerializerHelper <RootObject>(); // First, get the closest weather station to the given GPS Coordinates var gpsResponse = this.ExecuteWundergroundGpsLookupApiCall <GpsLookupClasses.RootObject>(wunderGroundUrl, gpsLat, gpsLong, wundergroundApiKey, timeout); string closestWeatherStationId = null; foreach (var nearbyStation in gpsResponse.location.nearby_weather_stations.pws.station) { closestWeatherStationId = $"pws:{nearbyStation.id}"; var apiQueryUrl = $"{wunderGroundUrl}{wundergroundApiKey}/{SubUrl}{queryDateString}/q/{closestWeatherStationId}.json"; var response = this.apiInteractionHelper.ExecuteThrottledApiCall <WundergroundHistoricDataClasses.RootObject>( timeout, webApiHelper, apiQueryUrl, null, wundergroundApiKey, this.apiNameForThrottlingRecords); fullObservationsList.AddRange(response.history.observations); if (fullObservationsList.Count > 0) { // This weather station does indeed have historic observations. We will use this one. currentDateTime = currentDateTime.AddDays(1); break; } } // Continue through all required dates with the weather station identified above while (currentDateTime.Date <= queryFinishDateTime) { queryDateString = $"{currentDateTime:yyyyMMdd}"; var apiQueryUrl = $"{wunderGroundUrl}{wundergroundApiKey}/{SubUrl}{queryDateString}/q/{closestWeatherStationId}.json"; var response = this.apiInteractionHelper.ExecuteThrottledApiCall <WundergroundHistoricDataClasses.RootObject>( timeout, webApiHelper, apiQueryUrl, null, wundergroundApiKey, this.apiNameForThrottlingRecords); fullObservationsList.AddRange(response.history.observations); currentDateTime = currentDateTime.AddDays(1); } var processedObservationsList = this.AddConcreteDateTimeToHistoricWeatherDatapointList(fullObservationsList); return(processedObservationsList); }