/// <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);
        }
Exemplo n.º 2
0
        /// <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);
        }
Exemplo n.º 7
0
        /// <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);
        }
Exemplo n.º 9
0
        /// <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);
        }
Exemplo n.º 10
0
        /// <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);
        }
Exemplo n.º 11
0
        /// <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);
        }