Degree Days.net
Weather Data for Energy Saving
The .NET client library is stable, well tested, and well documented. It is the recommended way to access the API from C#, Visual Basic .NET, and other .NET languages.
The client library is in NuGet here, and you can find it in Visual Studio by searching for "DegreeDays" in the NuGet Package Manager.
MSDN-style documentation is at https://dotnet.degreedays.net/ and IntelliSense docs are bundled together with the NuGet package – you should get them automatically when you install via the NuGet Package Manager.
NuGet installation is the best option for most projects, but you can also download the client library directly: DegreeDaysApi.dll; and the XML docs for IntelliSense: DegreeDaysApi.xml.
The .NET client library is currently at version 1.4. For changes since earlier versions, please see the release history.
You'll need:
Here's a simple example showing how to fetch the latest 12 months of 65°F-base-temperature heating degree days for an automatically-selected weather station near US zip code 02633 (which is on Cape Cod so you can use the free test API account). The HDD figures are output to the command line:
// The free test account will work for locations on Cape Cod. Swap in your own // API access keys to fetch data for locations worldwide. DegreeDaysApi api = new DegreeDaysApi( new AccountKey("test-test-test"), new SecurityKey("test-test-test-test-test-test-test-test-test-test-test-test-test")); DatedDataSpec hddSpec = DataSpec.Dated( Calculation.HeatingDegreeDays(Temperature.Fahrenheit(65)), DatedBreakdown.Monthly(Period.LatestValues(12))); // Tip: add more DataSpec items to fetch e.g. CDD or hourly temperatures in the // same request. The API docs for GetLocationData have sample code showing how: // https://dotnet.degreedays.net/M_DegreeDays_Api_Data_DataApi_GetLocationData#2 LocationDataRequest request = new LocationDataRequest( Location.PostalCode("02633", "US"), new DataSpecs(hddSpec)); LocationDataResponse response = api.DataApi.GetLocationData(request); DatedDataSet hddData = response.DataSets.GetDated(hddSpec); foreach (DatedDataValue v in hddData.Values) { Console.Out.WriteLine(v.FirstDay + ": " + v.Value); }
' The free test account will work for locations on Cape Cod. Swap in your own ' API access keys to fetch data for locations worldwide. Dim api As New DegreeDaysApi( New AccountKey("test-test-test"), New SecurityKey("test-test-test-test-test-test-test-test-test-test-test-test-test")) Dim hddSpec As DatedDataSpec = DataSpec.Dated( Calculation.HeatingDegreeDays(Temperature.Fahrenheit(65)), DatedBreakdown.Monthly(Period.LatestValues(12))) ' Tip: add more DataSpec items to fetch e.g. CDD or hourly temperatures in the ' same request. The API docs for GetLocationData have sample code showing how: ' https://dotnet.degreedays.net/M_DegreeDays_Api_Data_DataApi_GetLocationData#2 Dim request As New LocationDataRequest( Location.PostalCode("02633", "US"), New DataSpecs(hddSpec)) Dim response As LocationDataResponse = api.DataApi.GetLocationData(request) Dim hddData As DatedDataSet = response.DataSets.GetDated(hddSpec) For Each v As DatedDataValue In hddData.Values Console.Out.WriteLine(v.FirstDay.ToString() & ": " & v.Value) Next
Bear in mind that this example is just a starting point...
LocationDataRequest
is highly configurable:There are multiple ways to specify the various components of the LocationDataRequest
:
// The Location can be a station ID, or a "geographic location" for which the // API will select the best weather station to use automatically: Location.StationId("KHYA"); Location.LongLat(new LongLat(-70.30563, 41.69547)); Location.PostalCode("02633", "US"); // Calculation: Calculation.HeatingDegreeDays(Temperature.Fahrenheit(65)); Calculation.CoolingDegreeDays(Temperature.Celsius(21.5)); // A TimeSeriesCalculation is for time-series data like hourly temperature data: TimeSeriesCalculation.HourlyTemperature(TemperatureUnit.Celsius); // Period of coverage: Period.LatestValues(12); Period.DayRange(new DayRange(new Day(2024, 1, 1), new Day(2024, 12, 31))); // By default you may get back less data than you requested if there aren't // enough records to generate a full set for your specified location. But you // can specify a minimum if you would rather have a failure than too little // data. For example, if you want 60 values but will accept 36+: Period.LatestValues(60).WithMinimumNumberOfValues(36); // Or if you want 10 specific years, and would rather a failure than anything less: Period.DayRange(new DayRange(new Day(2015, 1, 1), new Day(2024, 12, 31))) .WithMinimumDayRange(new DayRange(new Day(2015, 1, 1), new Day(2024, 12, 31))); // DatedBreakdown (using a period like those specified above): DatedBreakdown.Daily(period); DatedBreakdown.Weekly(period, DayOfWeek.Monday); // specifying firstDayOfWeek DatedBreakdown.Monthly(period); DatedBreakdown.Monthly(period, new StartOfMonth(5)); DatedBreakdown.Yearly(period); DatedBreakdown.Yearly(period, new StartOfYear(6, 22)); DatedBreakdown.Custom(DayRanges.Create( new DayRange(new Day(2024, 12, 15), new Day(2025, 1, 12)), new DayRange(new Day(2025, 1, 13), new Day(2025, 2, 17)), new DayRange(new Day(2025, 2, 24), new Day(2025, 3, 18)))); // All the DatedBreakdown types let you specify .withAllowPartialLatest(true) // so you can fetch time-series data that includes the current day so far. For // example: DatedBreakdown.Daily(period).WithAllowPartialLatest(true); // AverageBreakdown has just one type at present, which specifies an average of // the data for the full calendar years specified by the period: AverageBreakdown.FullYears(period); // A DataSpec is a specification for a set of data, made up of // Calculation/Period/Breakdown objects like those specified above: DataSpec.Dated(calculation, datedBreakdown); // for HDD or CDD DataSpec.Average(calculation, averageBreakdown); // for average HDD or CDD DataSpec.TimeSeries(timeSeriesCalculation, datedBreakdown); // for e.g. hourly temperature data // Putting all this together, here are a few example DataSpec items: DatedDataSpec hddSpec = DataSpec.Dated( Calculation.HeatingDegreeDays(Temperature.Fahrenheit(60)), DatedBreakdown.Monthly(Period.LatestValues(12))); DatedDataSpec cddSpec = DataSpec.Dated( Calculation.CoolingDegreeDays(Temperature.Celsius(21)), DatedBreakdown.Daily(Period.DayRange( new DayRange(new Day(2024, 1, 1), new Day(2024, 12, 31))))); AverageDataSpec averageHddSpec = DataSpec.Average( Calculation.HeatingDegreeDays(Temperature.Celsius(15.5)), AverageBreakdown.FullYears(Period.LatestValues(5))); TimeSeriesDataSpec hourlyTemperaturesSpec = DataSpec.TimeSeries( TimeSeriesCalculation.HourlyTemperature(TemperatureUnit.Fahrenheit), DatedBreakdown.Daily(Period.LatestValues(30))); TimeSeriesDataSpec hourlyTemperaturesIncludingTodaySpec = DataSpec.TimeSeries( TimeSeriesCalculation.HourlyTemperature(TemperatureUnit.Celsius), DatedBreakdown.Daily(Period.LatestValues(31)).WithAllowPartialLatest(true)); // DataSpec objects go into a DataSpecs object: new DataSpecs(hddSpec); // HDD only (with only one base temperature and breakdown) new DataSpecs(hddSpec, cddSpec); // HDD and CDD new DataSpecs(hddSpec, cddSpec, hourlyTemperaturesSpec); // HDD, CDD, and hourly temperature data new DataSpecs(listOfUpTo120DataSpecObjects); // e.g. HDD & CDD with a range of base temperatures or breakdowns
' The Location can be a station ID, or a "geographic location" for which the ' API will select the best weather station to use automatically: Location.StationId("KHYA") Location.LongLat(New LongLat(-70.30563, 41.69547)) Location.PostalCode("02633", "US") ' Calculation: Calculation.HeatingDegreeDays(Temperature.Fahrenheit(65)) Calculation.CoolingDegreeDays(Temperature.Celsius(21.5)) ' A TimeSeriesCalculation is for time-series data like hourly temperature data: TimeSeriesCalculation.HourlyTemperature(TemperatureUnit.Celsius) ' Period of coverage: Period.LatestValues(12) Period.DayRange(New DayRange(New Day(2024, 1, 1), New Day(2024, 12, 31))) ' By default you may get back less data than you requested if there aren't ' enough records to generate a full set for your specified location. But you ' can specify a minimum if you would rather have a failure than too little ' data. For example, if you want 60 values but will accept 36+: Period.LatestValues(60).WithMinimumNumberOfValues(36) ' Or if you want 10 specific years, and would rather a failure than anything less: Period.DayRange(New DayRange(New Day(2015, 1, 1), New Day(2024, 12, 31))) _ .WithMinimumDayRange(New DayRange(New Day(2015, 1, 1), New Day(2024, 12, 31))) ' DatedBreakdown (using a Period like those specified above): DatedBreakdown.Daily(somePeriod) DatedBreakdown.Weekly(somePeriod, DayOfWeek.Monday) ' specifying firstDayOfWeek DatedBreakdown.Monthly(somePeriod) DatedBreakdown.Monthly(somePeriod, New StartOfMonth(5)) DatedBreakdown.Yearly(somePeriod) DatedBreakdown.Yearly(somePeriod, New StartOfYear(6, 22)) DatedBreakdown.Custom(DayRanges.Create( New DayRange(New Day(2024, 12, 15), New Day(2025, 1, 12)), New DayRange(New Day(2025, 1, 13), New Day(2025, 2, 17)), New DayRange(New Day(2025, 2, 24), New Day(2025, 3, 18)))) ' All the DatedBreakdown types let you specify .WithAllowPartialLatest(True) ' so you can fetch time-series data that includes the current day so far. For ' example: DatedBreakdown.Daily(somePeriod).WithAllowPartialLatest(True) ' AverageBreakdown has just one type at present, which specifies an average of ' the data for the full calendar years specified by the period: AverageBreakdown.FullYears(somePeriod) ' A DataSpec is a specification for a set of data, made up of ' Calculation/Period/Breakdown objects like those specified above: DataSpec.Dated(someCalculation, someDatedBreakdown) ' for HDD or CDD DataSpec.Average(someCalculation, someAverageBreakdown) ' for average HDD or CDD DataSpec.TimeSeries(someTimeSeriesCalculation, someDatedBreakdown) ' for e.g. hourly temperature data ' Putting all this together, here are a few example DataSpec items: Dim hddSpec As DatedDataSpec = DataSpec.Dated( Calculation.HeatingDegreeDays(Temperature.Fahrenheit(60)), DatedBreakdown.Monthly(Period.LatestValues(12))) Dim cddSpec As DatedDataSpec = DataSpec.Dated( Calculation.CoolingDegreeDays(Temperature.Celsius(21)), DatedBreakdown.Daily(Period.DayRange( New DayRange(New Day(2024, 1, 1), New Day(2024, 12, 31))))) Dim averageHddSpec As AverageDataSpec = DataSpec.Average( Calculation.HeatingDegreeDays(Temperature.Celsius(15.5)), AverageBreakdown.FullYears(Period.LatestValues(5))) Dim hourlyTemperaturesSpec As TimeSeriesDataSpec = DataSpec.TimeSeries( TimeSeriesCalculation.HourlyTemperature(TemperatureUnit.Fahrenheit), DatedBreakdown.Daily(Period.LatestValues(30))) Dim hourlyTemperaturesIncludingTodaySpec As TimeSeriesDataSpec = DataSpec.TimeSeries( TimeSeriesCalculation.HourlyTemperature(TemperatureUnit.Celsius), DatedBreakdown.Daily(Period.LatestValues(31)).WithAllowPartialLatest(True)) ' DataSpec objects go into a DataSpecs object: Dim ds As DataSpecs ds = New DataSpecs(hddSpec) ' HDD only (with only one base temperature and breakdown) ds = New DataSpecs(hddSpec, cddSpec) ' HDD and CDD ds = New DataSpecs(hddSpec, cddSpec, hourlyTemperaturesSpec) ' HDD, CDD, and hourly temperature data ds = New DataSpecs(listOfUpTo120DataSpecObjects) ' e.g. HDD & CDD with a range of base temperatures or breakdowns
Note above how you can specify multiple sets of data (e.g. HDD, CDD, hourly temperature data) to be fetched in a single request. This is faster and uses fewer request units than making multiple requests for the same location. The second code sample in the docs for GetLocationData
shows how.
LocationDataResponse
contains more than just data:It also contains information about the weather station(s) used to generate the returned data. For example, if you request data for a geographic location initially, you might want to use the station ID to fetch updates later:
Console.Out.WriteLine(response.StationId);
Console.Out.WriteLine(response.StationId)
LocationInfoRequest
and two-stage data fetching:Except in name, LocationInfoRequest
looks exactly the same as LocationDataRequest
. Using it is almost identical too:
// Assuming location, dataSpecs, and api are already defined (see examples above) LocationInfoResponse locationInfoResponse = api.DataApi.GetLocationInfo(new LocationInfoRequest(location, dataSpecs)) Console.Out.WriteLine(locationInfoResponse.StationId)
' Assuming yourLocation, yourDataSpecs, and api are already defined (see examples above) Dim response As LocationInfoResponse = api.DataApi.GetLocationInfo( New LocationInfoRequest(yourLocation, yourDataSpecs)) Console.Out.WriteLine(response.StationId)
Each API request you make uses request units that count against your hourly rate limit. A big LocationDataRequest
can use a lot of request units, but a LocationInfoRequest
will only ever use one. See the sign-up page for more on request units and rate limits.
But LocationInfoResponse
does not contain any data (it has no DataSets
property)... It's typically used for two-stage data fetching, which can be useful if you are dealing with geographic locations (postal/zip codes, or longitude/latitude positions), but storing data by station ID (returned in every successful response). For this use-case, two-stage data fetching can help you save request units (see right) and improve the efficiency of your system by avoiding re-fetching data that you already have stored.
When you want to add a new location into your system (e.g. if a new user signs up with a new address), you can do the following:
LocationInfoRequest
with the geographic location and the specification of the data that you want. This will only take one request unit. You won't get any data back, but you should get the station ID that the system would use for an equivalent LocationDataRequest
. If you already have data stored for that station ID, use it and skip Stage 2; if not, proceed to Stage 2.LocationDataRequest
with the station ID from Stage 1. Using the station ID here (as opposed to the geographic location) saves you a request unit, thus offsetting the request unit used in Stage 1. But fetching data can still use a lot of request units – more the more data you fetch – so the efficiency of two-stage data fetching comes from skipping this Stage 2 fetch whenever possible.If none of your geographic locations share a weather station, two-stage data fetching will use exactly the same number of request units as simply fetching data for each geographic location. But two-stage data fetching will improve efficiency and save request units if/when you have enough geographic locations in your system that some of them end up sharing weather stations. If that is the case, two-stage data fetching can really help your system to scale well as more and more geographic locations are added in.
RegressionRequest
for advanced regression functionality:With RegressionRequest
you can send energy data to the API so it can test thousands of regressions and find the HDD and/or CDD base temperatures that give the best statistical fit. We cover this fully in our docs on the API's regression functionality.
Error handling would be important for production code:
The .NET client library tries its best to fail fast on invalid input. We'd rather give you an exception immediately than use up your rate limit with invalid API requests that are destined to fail.
This is mainly relevant if you are dealing with user input, particularly for:
Location.StationId(String)
;Location.PostalCode(String, String)
; andAccountKey
and SecurityKey
.All the methods/constructors listed above will throw a FormatException
(or subclass) if they are passed an ID, code, or key that is clearly invalid. If you are dealing with user input, you might want to catch those exceptions explicitly as a means of validation.
DegreeDaysApiException
)All the exceptions that can arise from a remote call to the API servers extend from DegreeDaysApiException
.
The methods that make a remote call to the API servers are accessible through DegreeDaysApi
. At present the only such methods are DataApi.GetLocationData(LocationDataRequest)
, DataApi.GetLocationInfo(LocationInfoRequest)
,
and RegressionApi.RunRegressions(RegressionRequest)
. For example:
DegreeDaysApi api = new DegreeDaysApi( new AccountKey(yourStringAccountKey), new SecurityKey(yourStringSecurityKey)); LocationDataResponse response = api.DataApi.GetLocationData(yourLocationDataRequest);
Dim api As New DegreeDaysApi( New AccountKey(yourStringAccountKey), New SecurityKey(yourStringSecurityKey)) Dim response As LocationDataResponse = api.DataApi.GetLocationData(yourLocationDataRequest)
getLocationData
, getLocationInfo
, and runRegressions
can throw a range of subclasses of DegreeDaysApiException
:
LocationException
– if the request fails because of problems relating to the specified Location
;ServiceException
– if the request fails because of a problem with the API service (sorry!);RateLimitException
– if you hit the rate limit for your account's plan, and need to wait a little while before it's reset (you can check .Metadata.RateLimit.MinutesToReset
on any successful response, or .ResponseMetadata.RateLimit.MinutesToReset
on any RateLimitException
to see how long it will be until the next reset);InvalidRequestException
– if the request that is sent to the API servers is invalid (e.g. if it is authenticated with invalid access keys);TransportException
– if there's a problem sending the request to the API servers, or a problem getting the API's response back;DegreeDaysApiException
– the superclass of all the exceptions listed above.There is also SourceDataException
(another subclass of DegreeDaysApiException
), which can be thrown by the GetXXX
methods on the DataSets
objects that come back in response to requests for data. For example:
try { DatedDataSet hddSet = response.DataSets.GetDated(hddSpec); } catch (SourceDataException e) { // hddSpec couldn't be fulfilled as there wasn't enough good temperature // data to calculate degree days covering the specified period. }
Try Dim hddSet As DatedDataSet = response.DataSets.GetDated(hddSpec) Catch e As SourceDataException ' hddSpec couldn't be fulfilled as there wasn't enough good temperature ' data to calculate degree days covering the specified period. End Try
Which, if any, of these exceptions you'll want to handle explicitly will depend on the nature of your application:
LocationException
explicitly so you can tell if a user entered an unrecognized or unsupported station ID or postal/zip code. But anything else might just be DegreeDaysApiException
as far as you are concerned – the request for data failed, and that might be all that matters.InvalidRequestException
explicitly so you can prompt the user to check their API access keys for typos.This isn't an error as such, but it's important to realize that, in certain circumstances, the API can return less data than you requested. For example, you might request 10 years of data for a certain weather station, but get only 5 years back if that's all the usable temperature data that the weather station has. Or you might request data up to and including yesterday, but get only data to the day before yesterday. (Note that you should never be able to get the data for yesterday until that day has finished in the location's local time zone, and it's best not to expect it until at least a couple of hours after that. More on update schedules here.)
There are clear rules about how and when the API can deliver less data than requested, and you can control this behaviour as well. See the documentation for DataApi.GetLocationData(LocationDataRequest)
to find out more.
We've built the API and the .NET client library for robustness and predictability:
null
/ Nothing
return a Nullable
type.null
/ Nothing
as an argument. Passing a null
/ Nothing
argument where it is not allowed will immediately result in an exception (fail fast).NaN
, 0, −1, 9999 etc.It is worth reading the higher-level integration guide for tips on the various approaches to integrating with the API. We have helped a lot of businesses integrate their software with our API so we are very familiar with the patterns that work well for common use cases.
There are separate docs covering the API's regression functionality.
The detailed .NET API docs explain every class, method, and property in the Python client library, along with detailed notes about the different request options, the types of response data, and the exceptions. It's the place to go for lower-level details on using the API from .NET.
© 2008–2025 BizEE Software – About | Contact | Privacy | Free Website | API | Integration Guide | API FAQ | API Sign-Up