Skip to content

Commit d3d8c45

Browse files
committed
Add NOAA Tides and Currents api
1 parent 7e41a93 commit d3d8c45

File tree

2 files changed

+122
-0
lines changed

2 files changed

+122
-0
lines changed

wetterdienst/provider/noaa/tc/__init__.py

Whitespace-only changes.
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import json
2+
from enum import Enum
3+
from typing import Optional, Tuple
4+
5+
import pandas as pd
6+
7+
from wetterdienst import Kind, Period, Provider, Resolution
8+
from wetterdienst.core.timeseries.request import TimeseriesRequest
9+
from wetterdienst.core.timeseries.values import TimeseriesValues
10+
from wetterdienst.metadata.columns import Columns
11+
from wetterdienst.metadata.datarange import DataRange
12+
from wetterdienst.metadata.period import PeriodType
13+
from wetterdienst.metadata.resolution import ResolutionType
14+
from wetterdienst.metadata.timezone import Timezone
15+
from wetterdienst.metadata.unit import UnitEnum, OriginUnit, SIUnit
16+
from wetterdienst.util.cache import CacheExpiry
17+
from wetterdienst.util.network import download_file
18+
from wetterdienst.util.parameter import DatasetTreeCore
19+
20+
21+
class NoaaTCParameter(DatasetTreeCore):
22+
class DYNAMIC(Enum):
23+
WATER_LEVEL = "water_level"
24+
25+
26+
class NoaaTCUnit(DatasetTreeCore):
27+
class DYNAMIC(UnitEnum):
28+
WATER_LEVEL = OriginUnit.METER.value, SIUnit.METER.value
29+
30+
31+
class NoaaTCResolution(Enum):
32+
DYNAMIC = Resolution.DYNAMIC.value
33+
34+
35+
36+
37+
class NoaaTCValues(TimeseriesValues):
38+
_data_tz = Timezone.DYNAMIC
39+
40+
_endpoint = (
41+
"https://api.tidesandcurrents.noaa.gov/api/prod/datagetter?station={station_id}&product={parameter}&"
42+
"begin_date={start_date}&end_date={end_date}&datum=navd&units=metric&time_zone=gmt&"
43+
"application=wetterdienst/https://github.com/earthobservations/wetterdienst&format=json"
44+
)
45+
46+
def _collect_station_parameter(self, station_id: str, parameter: Enum, dataset: Enum) -> pd.DataFrame:
47+
url = self._endpoint.format(
48+
station_id=station_id, parameter=parameter.value, start_date=self.sr.start_date.isoformat(), end_date=self.sr.end_date.isoformat()
49+
)
50+
51+
payload = download_file(url, CacheExpiry.FIVE_MINUTES)
52+
53+
df = pd.DataFrame.from_records(json.load(payload)["data"])
54+
55+
print(df)
56+
57+
58+
class NoaaTCRequest(TimeseriesRequest):
59+
_values = NoaaTCValues
60+
_tz = Timezone.USA
61+
_parameter_base = NoaaTCParameter
62+
_unit_base = NoaaTCUnit
63+
_has_tidy_data = True
64+
_has_datasets = False
65+
_data_range = DataRange.FIXED
66+
_period_base = Period.HISTORICAL
67+
_period_type = PeriodType.FIXED
68+
_resolution_type = ResolutionType.DYNAMIC
69+
_resolution_base = NoaaTCResolution
70+
_kind = Kind.OBSERVATION
71+
_provider = Provider.NOAA
72+
_endpoint = "https://api.tidesandcurrents.noaa.gov/mdapi/prod/webapi/stations.json?units=metric"
73+
74+
def __init__(self, parameter, start_date, end_date):
75+
super(NoaaTCRequest, self).__init__(
76+
parameter=parameter,
77+
resolution=Resolution.DYNAMIC,
78+
period=Period.HISTORICAL,
79+
start_date=start_date,
80+
end_date=end_date,
81+
)
82+
83+
def _all(self) -> pd.DataFrame:
84+
def _extract_ortho_msl(url):
85+
payload = download_file(url, self.settings, CacheExpiry.METAINDEX)
86+
87+
datum_dict = json.load(payload)
88+
89+
datum_msl = None
90+
if datum_dict["datums"]:
91+
datum_msl = [datum for datum in datum_dict["datums"] if datum["name"] == "MSL"]
92+
93+
datum_msl = datum_msl and datum_msl[0]["value"] or None
94+
95+
return datum_dict["OrthometricDatum"], datum_msl
96+
97+
payload = download_file(self._endpoint, self.settings, CacheExpiry.METAINDEX)
98+
99+
df = pd.DataFrame.from_records(json.load(payload)["stations"])
100+
101+
df = df.loc[:, ["id", "name", "state", "lat", "lng", "datums"]]
102+
103+
df.loc[:, ["orthodatum", "msl"]] = df.pop("datums").map(lambda x: x["self"]).map(_extract_ortho_msl).tolist()
104+
105+
df = df.loc[df.loc[:, "orthodatum"] == "NAVD88", :]
106+
107+
return df.rename(
108+
columns={
109+
"id": Columns.STATION_ID.value,
110+
"name": Columns.NAME.value,
111+
"state": Columns.STATE.value,
112+
"lat": Columns.LATITUDE.value,
113+
"lng": Columns.LONGITUDE.value,
114+
}
115+
)
116+
117+
118+
if __name__ == "__main__":
119+
request = NoaaTCRequest(parameter="water_level", start_date="1970-01-01", end_date="1970-01-02").all()
120+
print(request.df)
121+
values = next(request.values.query())
122+
print(values.df)

0 commit comments

Comments
 (0)