Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IEM ASOS Data #254

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions siphon/simplewebservice/iem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
""" Requests data from IEM asos.py"""

import requests
import datetime
import pandas as pd

from io import StringIO

from ..http_util import create_http_session


class IemAsos:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm. IEMAsos, 'IEMasos, IAStateASOS, IAStateasos? Not sure on fighting convention for readability. Thoughts @dopplershift ?

"""Handles data collection of ASOS data from IEM.

This handles the collection of ASOS data from the Iowa
Environmental Mesonet, via their asos.py request URL.

Attributes
----------
startDate : datetime
The starting date for the dataset
endDate : datetime
The ending date for the dataset
sites : list
Station IDs in the dataset
data : pandas.DataFrame
Pandas dataframe containing the IEM ASOS data

"""
def __init__(self, sites, startDate=None, endDate=None):
"""Initialize the IemAsos object.

Initialization will set the datetime objects and
start the data call

Parameters
----------
sites : list
List of station ID's to request data for
startDate : datetime
The start date as a datetime object
endDate : datetime
The end date as a datetime object
"""
if startDate is None:
self.startDate = datetime.datetime.now()
self.endDate = datetime.datetime.now()
elif endDate is None:
self.endDate = datetime.datetime.now()
self.startDate = startDate
else:
self.startDate = startDate
self.endDate = endDate

self.sites = sites
self.getData()

def getData(self):
""" Downloads IEM ASOS data """

# Build the URL
URL = 'http://mesonet.agron.iastate.edu/cgi-bin/request/asos.py?'

for site in self.sites:
URL = URL + '&station=' + site

URL = URL + '&data=all'

URL = URL + '&year1='+str(self.startDate.year)
URL = URL + '&month1='+str(self.startDate.month)
URL = URL + '&day1='+str(self.startDate.day)

URL = URL + '&year2='+str(self.endDate.year)
URL = URL + '&month2='+str(self.endDate.month)
URL = URL + '&day2='+str(self.endDate.day)

URL = URL + '&tz=Etc%2FUTC&format=onlycomma&latlon=yes&direct=no' \
'&report_type=1&report_type=2'

# Collect the data
try:
response = create_http_session().post(URL)
csvData = StringIO(response.text)
except requests.exceptions.Timeout:
raise IemAsosException('Connection Timeout')

# Process the data into a dataframe
'''
Convert the response text into a DataFrame. The index_col ensures that the first
column isn't used as a row identifier. This prevents the station IDs from being used
as row indices.
'''
df = pd.read_csv(csvData, header=0, sep=',', index_col=False)

# Strip whitespace from the column names
df.columns = df.columns.str.strip()

df['valid'] = pd.to_datetime(df['valid'], format="%Y-%m-%d %H:%M:%S")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind adding df.units = a dict of the units if possible here so it would work with our unit helper like we do with upper air data?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll take care of it!


self.data = df


class IemAsosException(Exception):
"""This class handles exceptions raised by the IemAsos class."""

pass
28 changes: 28 additions & 0 deletions siphon/tests/fixtures/iem_request
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
interactions:
- request:
body: null
headers:
Accept: ['*/*']
Accept-Encoding: ['gzip, deflate']
Connection: [keep-alive]
Content-Length: ['0']
User-Agent: [Siphon (0.6.0+62.gadab176.dirty)]
method: POST
uri: http://mesonet.agron.iastate.edu/cgi-bin/request/asos.py?&station=K&station=L&station=N&station=K&station=,&station=%20&station=K&station=G&station=S&station=O&station=,&station=%20&station=K&station=B&station=D&station=U&data=all&year1=2018&month1=1&day1=1&year2=2018&month2=1&day2=1&tz=Etc%2FUTC&format=onlycomma&latlon=yes&direct=no&report_type=1&report_type=2
response:
body: {string: 'station,valid,lon,lat,tmpf, dwpf, relh, drct, sknt, p01i, alti,
mslp, vsby, gust, skyc1, skyc2, skyc3, skyc4, skyl1, skyl2, skyl3, skyl4,
wxcodes, metar

'}
headers:
Access-Control-Allow-Origin: ['*']
Connection: [Keep-Alive]
Content-Type: [text/plain; charset=UTF-8]
Date: ['Fri, 26 Oct 2018 15:01:31 GMT']
Keep-Alive: ['timeout=5, max=100']
Server: [Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.2k-fips mod_fcgid/2.3.9
mod_wsgi/4.6.4 Python/3.6]
X-IEM-ServerID: [iemvs103.local]
status: {code: 200, message: OK}
version: 1
24 changes: 24 additions & 0 deletions siphon/tests/test_iem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""Test IEM Asos Data Downloading."""
from datetime import datetime

from siphon.simplewebservice.iem import IemAsos
from siphon.testing import get_recorder

recorder = get_recorder(__file__)


@recorder.use_cassette('iem_request')
def test_iem_download():
"""Test the downloading of IEM ASOS data"""
start = datetime(2018, 1, 1)
end = datetime(2018, 1, 1)

asosCall = IemAsos(['KLNK', 'KGSO', 'KBDU'], start, end)

stn1 = asosCall.data[(asosCall.data.station == 'GSO')]
stn2 = asosCall.data[(asosCall.data.station == 'LNK')]
stn3 = asosCall.data[(asosCall.data.station == 'BDU')]

assert stn1['station'][1] == 'GSO'
assert stn2['station'][1] == 'LNK'
assert stn3['station'][1] == 'BDU'