Skip to content

Commit 8a773b0

Browse files
committed
v0.65.7: Fixed code typos and added CO2
1 parent 60a5bc3 commit 8a773b0

3 files changed

Lines changed: 93 additions & 89 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "umd-api"
7-
version = "0.65.6"
7+
version = "0.65.7"
88
description = "A package for accessing the UMD API in Python"
99
readme = "README.md"
1010
authors = [

umd_api/weather/forecast.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
class Forecast():
66

7-
def get_hourly_forecast():
7+
def get_hourly_forecast(self):
88
hourly_forecast = []
99
url = "https://weather.umd.edu/"
1010

@@ -43,7 +43,7 @@ def get_hourly_forecast():
4343
})
4444
return hourly_forecast
4545

46-
def get_weekly_forecast():
46+
def get_weekly_forecast(self):
4747
url = "https://weather.umd.edu/"
4848

4949
response = requests.get(url)

umd_api/weather/weather.py

Lines changed: 90 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -19,104 +19,50 @@ def get_weather_data(self, station="", start_time="", end_time=""):
1919
- If end_time is provided but no start_time → raises ValueError.
2020
2121
"""
22-
22+
2323
url = "https://weather.umd.edu/wordpress/wp-content/plugins/meso-fsct/functions/get-data.php"
24-
25-
station = station.lower()
26-
db = ""
27-
28-
current_data_flag = False
29-
30-
def validate_date_format(date_str):
31-
try:
32-
if date_str: # Only validate if the string is not empty
33-
datetime.strptime(date_str, '%m/%d/%y')
34-
except ValueError:
35-
raise ValueError(f"Invalid date format: {date_str}. Expected format: MM/DD/YY")
36-
37-
# Ensure start_time is provided if end_time is set
38-
if start_time == '' and end_time != '':
24+
25+
stations_db = {
26+
"": "mesoterp7DB", "atlantic": "mesoterp7DB", "golf": "mesoterp6DB",
27+
"vmh": "mesoterp1DB", "williams": "mesoterp8DB", "chem": "mesoterp3DB"
28+
}
29+
30+
if station.lower() not in stations_db:
31+
raise ValueError("Valid Station not Provided")
32+
33+
def to_timestamp(date_str):
34+
return int(datetime.strptime(date_str, '%m/%d/%y').replace(hour=0, minute=0, second=0).timestamp())
35+
36+
if end_time and not start_time:
3937
raise ValueError("Start Time Must be Provided")
40-
41-
# Validate date formats if they are provided
42-
if start_time != '':
43-
validate_date_format(start_time)
44-
if end_time != '':
45-
validate_date_format(end_time)
46-
47-
# Convert provided times to Unix timestamps
48-
if start_time != '' and end_time != '':
49-
start_time = int(datetime.strptime(start_time, '%m/%d/%y').replace(hour=0, minute=0, second=0).timestamp())
50-
end_time = int(datetime.strptime(end_time, '%m/%d/%y').replace(hour=0, minute=0, second=0).timestamp())
51-
elif start_time != '' and end_time == '':
52-
start_time = int(datetime.strptime(start_time, '%m/%d/%y').replace(hour=0, minute=0, second=0).timestamp())
53-
end_time = int(time())
54-
elif start_time == '' and end_time == '':
55-
current_data_flag = True
56-
57-
start_time = int(time()) - 120 # 2 minutes ago
58-
end_time = int(time()) # Now
59-
38+
39+
start_time = to_timestamp(start_time) if start_time else int(time()) - 120
40+
end_time = to_timestamp(end_time) if end_time else int(time())
41+
6042
if end_time <= start_time:
6143
raise ValueError("End time must be greater than Start time")
62-
63-
match station:
64-
case '':
65-
db = 'mesoterp7DB'
66-
case 'atlantic':
67-
db = "mesoterp7DB"
68-
case 'golf':
69-
db = "mesoterp6DB"
70-
case 'vmh':
71-
db = "mesoterp1DB"
72-
case 'williams':
73-
db = "mesoterp8DB"
74-
case 'chem':
75-
db = "mesoterp3DB"
76-
case _:
77-
raise ValueError("Valid Station not Provided")
78-
79-
80-
PAYLOAD = {
81-
"startms": start_time,
44+
45+
payload = {
46+
"startms": start_time,
8247
"endms": end_time,
83-
"db": db,
48+
"db": stations_db[station.lower()],
8449
"table": "archive",
8550
"cols": ["dateTime", "outTemp", "dewpoint", "barometer", "rainRate", "windSpeed", "windGust", "windDir"]
8651
}
87-
52+
8853
try:
89-
result = requests.post(url, json=PAYLOAD)
90-
result.raise_for_status() # Raise error for bad HTTP responses
91-
data = result.json().get('data')
92-
54+
response = requests.post(url, json=payload)
55+
response.raise_for_status()
56+
data = response.json().get("data")
57+
9358
if not data:
9459
raise ValueError("No data returned from the API")
95-
96-
result_dict = {}
97-
98-
if current_data_flag:
99-
result_dict = data[0]
100-
101-
for key in result_dict:
102-
try:
103-
result_dict[key] = float(result_dict[key])
104-
except (ValueError, TypeError):
105-
pass
106-
else:
107-
result_dict = data
108-
109-
for i in range(len(result_dict)):
110-
for key in result_dict[i]:
111-
try:
112-
result_dict[i][key] = float(result_dict[i][key])
113-
except (ValueError, TypeError):
114-
pass
115-
116-
return result_dict
117-
60+
61+
return [{k: float(v) if isinstance(v, (int, float, str)) and str(v).replace('.', '', 1).isdigit() else v for k, v in row.items()} for row in data]
62+
11863
except requests.exceptions.RequestException as e:
11964
raise RuntimeError(f"API request failed: {e}")
65+
12066

12167
def save_radar_gif(self, dir=""):
12268
"""
@@ -157,7 +103,7 @@ def save_radar_gif(self, dir=""):
157103
except OSError as e:
158104
print(f"Error saving file: {e}")
159105

160-
def get_weather_description():
106+
def get_weather_description(self):
161107
url = 'https://weather.umd.edu/'
162108

163109
response = requests.get(url)
@@ -175,3 +121,61 @@ def get_weather_description():
175121
else:
176122
raise requests.exceptions.HTTPError(f"Failed to fetch the webpage. Status code: {response.status_code}")
177123

124+
def get_co2_levels(self, start_time, end_time=None):
125+
126+
"""
127+
128+
Fetch CO2 levels from the API.
129+
130+
- `start_time` (str) must be provided in 'MM/DD/YY' format.
131+
- `end_time` (str, optional) defaults to the current time if not provided.
132+
- Start and end times must be at least one day apart.
133+
134+
"""
135+
136+
url = "https://weather.umd.edu/wordpress/wp-content/plugins/meso-fsct/functions/get-data.php"
137+
138+
def validate_date(date_str):
139+
try:
140+
return datetime.strptime(date_str, '%m/%d/%y')
141+
except ValueError:
142+
raise ValueError(f"Invalid date format: {date_str}. Expected format: MM/DD/YY")
143+
144+
start_dt = validate_date(start_time)
145+
end_dt = validate_date(end_time) if end_time else datetime.utcnow()
146+
147+
start_ts, end_ts = int(start_dt.timestamp()), int(end_dt.timestamp())
148+
149+
if end_ts <= start_ts:
150+
raise ValueError("End time must be greater than Start time")
151+
152+
if (end_ts - start_ts) < 86400:
153+
raise ValueError("Start to End range must be at least one day")
154+
155+
payload = {
156+
"start_timestamp": start_dt.strftime('%Y-%m-%d %H:%M:%S'),
157+
"end_timestamp": end_dt.strftime('%Y-%m-%d %H:%M:%S'),
158+
"db": "atl_co2",
159+
"table": "co2_readings",
160+
"cols": ["timestamp", "measurement_value"]
161+
}
162+
163+
try:
164+
response = requests.post(url, json=payload)
165+
response.raise_for_status()
166+
data = response.json().get('data', [])
167+
168+
if not data:
169+
raise ValueError("No data returned from the API")
170+
171+
for record in data:
172+
for key in record:
173+
try:
174+
record[key] = float(record[key])
175+
except (ValueError, TypeError):
176+
pass
177+
178+
return data
179+
180+
except requests.exceptions.RequestException as e:
181+
raise RuntimeError(f"API request failed: {e}")

0 commit comments

Comments
 (0)