tempestwx 0.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tempestwx/__init__.py +30 -0
- tempestwx/_auth/__init__.py +14 -0
- tempestwx/_auth/token.py +60 -0
- tempestwx/_client/__init__.py +9 -0
- tempestwx/_client/api/__init__.py +23 -0
- tempestwx/_client/api/tempest_home/better_forecast/__init__.py +7 -0
- tempestwx/_client/api/tempest_home/better_forecast/better_forecast.py +93 -0
- tempestwx/_client/api/tempest_home/observations/__init__.py +7 -0
- tempestwx/_client/api/tempest_home/observations/observations.py +241 -0
- tempestwx/_client/api/tempest_home/stations/__init__.py +7 -0
- tempestwx/_client/api/tempest_home/stations/stations.py +58 -0
- tempestwx/_client/api/tempest_home/stats/__init__.py +7 -0
- tempestwx/_client/api/tempest_home/stats/stats.py +48 -0
- tempestwx/_client/base.py +273 -0
- tempestwx/_client/client.py +182 -0
- tempestwx/_client/decorators/__init__.py +16 -0
- tempestwx/_client/decorators/error_handler.py +61 -0
- tempestwx/_client/decorators/request_handler.py +58 -0
- tempestwx/_client/processor.py +68 -0
- tempestwx/_http/__init__.py +64 -0
- tempestwx/_http/base.py +110 -0
- tempestwx/_http/client.py +251 -0
- tempestwx/_http/concrete.py +153 -0
- tempestwx/_http/error.py +151 -0
- tempestwx/_http/wrapper.py +52 -0
- tempestwx/_models/__init__.py +35 -0
- tempestwx/_models/_serializer.py +191 -0
- tempestwx/_models/better_forecast.py +40 -0
- tempestwx/_models/better_forecast_current_conditions.py +60 -0
- tempestwx/_models/better_forecast_daily_forecast.py +38 -0
- tempestwx/_models/better_forecast_forecast.py +24 -0
- tempestwx/_models/better_forecast_hourly_forecast.py +46 -0
- tempestwx/_models/better_forecast_units.py +41 -0
- tempestwx/_models/device.py +40 -0
- tempestwx/_models/device_meta.py +26 -0
- tempestwx/_models/device_observation.py +32 -0
- tempestwx/_models/device_observation_summary.py +40 -0
- tempestwx/_models/device_settings.py +22 -0
- tempestwx/_models/lightning_event.py +59 -0
- tempestwx/_models/obs_air.py +83 -0
- tempestwx/_models/obs_air_ext.py +110 -0
- tempestwx/_models/obs_sky.py +119 -0
- tempestwx/_models/obs_sky_ext.py +151 -0
- tempestwx/_models/obs_st.py +143 -0
- tempestwx/_models/obs_st_ext.py +191 -0
- tempestwx/_models/observation.py +92 -0
- tempestwx/_models/rapid_wind.py +59 -0
- tempestwx/_models/station.py +60 -0
- tempestwx/_models/station_item.py +28 -0
- tempestwx/_models/station_meta.py +23 -0
- tempestwx/_models/station_observation_latest.py +36 -0
- tempestwx/_models/station_observations.py +33 -0
- tempestwx/_models/station_set.py +24 -0
- tempestwx/_models/station_units.py +43 -0
- tempestwx/_models/stats_day.py +179 -0
- tempestwx/_models/stats_set.py +55 -0
- tempestwx/_models/status.py +38 -0
- tempestwx/_models/units_default.py +191 -0
- tempestwx/py.typed +1 -0
- tempestwx/settings.py +175 -0
- tempestwx/settings_loader.py +210 -0
- tempestwx/version.py +15 -0
- tempestwx-0.0.2.dist-info/METADATA +213 -0
- tempestwx-0.0.2.dist-info/RECORD +66 -0
- tempestwx-0.0.2.dist-info/WHEEL +4 -0
- tempestwx-0.0.2.dist-info/licenses/LICENSE +21 -0
tempestwx/__init__.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Tempest SDK for Python.
|
|
2
|
+
|
|
3
|
+
Primary entry points:
|
|
4
|
+
- ``Tempest`` - high-level synchronous client
|
|
5
|
+
- Settings helpers: ``Settings``, ``UnitsOverrides``, ``load_settings``,
|
|
6
|
+
``reload_settings``
|
|
7
|
+
|
|
8
|
+
The official Tempest API documentation: https://apidocs.tempestwx.com
|
|
9
|
+
|
|
10
|
+
Note: The top-level package intentionally exposes a narrow surface area.
|
|
11
|
+
HTTP primitives, error classes, and data models are available from their
|
|
12
|
+
subpackages (e.g., ``tempestwx._http`` and ``tempestwx._models``).
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from ._client import Tempest
|
|
16
|
+
from .settings import Settings, UnitsOverrides
|
|
17
|
+
from .settings_loader import load_settings, reload_settings
|
|
18
|
+
from .version import __version__
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
# Version
|
|
22
|
+
"__version__",
|
|
23
|
+
# Client
|
|
24
|
+
"Tempest",
|
|
25
|
+
# Settings helpers
|
|
26
|
+
"Settings",
|
|
27
|
+
"UnitsOverrides",
|
|
28
|
+
"load_settings",
|
|
29
|
+
"reload_settings",
|
|
30
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Authentication token management.
|
|
2
|
+
|
|
3
|
+
Provides token types and thread-safe token storage using ContextVars.
|
|
4
|
+
|
|
5
|
+
Clients typically interact with token management through the high-level
|
|
6
|
+
``Tempest`` client.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from .token import AccessToken, Token
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"AccessToken",
|
|
13
|
+
"Token",
|
|
14
|
+
]
|
tempestwx/_auth/token.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Access token abstractions for authentication.
|
|
2
|
+
|
|
3
|
+
This module provides the token handling infrastructure for authenticating
|
|
4
|
+
API requests. Currently supports Personal Access Tokens (PAT). OAuth flows
|
|
5
|
+
such as Authorization Code with PKCE are not yet implemented.
|
|
6
|
+
|
|
7
|
+
Classes:
|
|
8
|
+
AccessToken: Abstract base for token implementations.
|
|
9
|
+
Token: Concrete PAT implementation that extracts and stores bearer tokens.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from abc import ABC, abstractmethod
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class AccessToken(ABC):
|
|
19
|
+
"""Access Token base class."""
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def access_token(self) -> str:
|
|
24
|
+
"""Bearer token."""
|
|
25
|
+
raise NotImplementedError
|
|
26
|
+
|
|
27
|
+
def __str__(self) -> str:
|
|
28
|
+
"""Return the string representation of the Bearer token."""
|
|
29
|
+
return self.access_token
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Token(AccessToken):
|
|
33
|
+
"""Access Token implementation.
|
|
34
|
+
|
|
35
|
+
Represents a Personal Access Tokens (PAT).
|
|
36
|
+
OAuth Authorization Code (with PKCE) grant types are not yet supported.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(self, token_details: dict[str, Any]) -> None:
|
|
40
|
+
"""Initialize a Token from token details.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
token_details: Dictionary containing token information. Must include
|
|
44
|
+
an ``"access_token"`` key with the bearer token string.
|
|
45
|
+
|
|
46
|
+
Raises:
|
|
47
|
+
KeyError: If ``"access_token"`` key is missing from token_details.
|
|
48
|
+
"""
|
|
49
|
+
self._access_token: str = token_details["access_token"]
|
|
50
|
+
|
|
51
|
+
def __repr__(self) -> str:
|
|
52
|
+
options = [
|
|
53
|
+
f"access_token={self.access_token!r}",
|
|
54
|
+
]
|
|
55
|
+
return type(self).__name__ + "(" + ", ".join(options) + ")"
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def access_token(self) -> str:
|
|
59
|
+
"""Bearer token."""
|
|
60
|
+
return self._access_token
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""API endpoint implementations.
|
|
2
|
+
|
|
3
|
+
Organizes all Tempest API endpoint handlers by category:
|
|
4
|
+
- ``TempestBetterForecast`` - forecast data
|
|
5
|
+
- ``TempestObservations`` - observation data
|
|
6
|
+
- ``TempestStations`` - station metadata and configuration
|
|
7
|
+
- ``TempestStats`` - statistical summaries
|
|
8
|
+
|
|
9
|
+
Each endpoint class provides methods corresponding to official Tempest API
|
|
10
|
+
routes documented at https://apidocs.tempestwx.com
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from .tempest_home.better_forecast import TempestBetterForecast
|
|
14
|
+
from .tempest_home.observations import TempestObservations
|
|
15
|
+
from .tempest_home.stations import TempestStations
|
|
16
|
+
from .tempest_home.stats import TempestStats
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"TempestBetterForecast",
|
|
20
|
+
"TempestObservations",
|
|
21
|
+
"TempestStations",
|
|
22
|
+
"TempestStats",
|
|
23
|
+
]
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Better Forecast API endpoint implementation.
|
|
2
|
+
|
|
3
|
+
This module provides access to the Tempest Weather "Better Forecast" API,
|
|
4
|
+
which delivers AI-enhanced weather forecasts tailored to station locations.
|
|
5
|
+
Forecasts include current conditions, hourly predictions, and daily summaries
|
|
6
|
+
with customizable unit preferences.
|
|
7
|
+
|
|
8
|
+
API Reference:
|
|
9
|
+
https://apidocs.tempestwx.com/reference/get_better-forecast
|
|
10
|
+
|
|
11
|
+
Classes:
|
|
12
|
+
TempestBetterForecast: Client for retrieving enhanced weather forecasts.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from tempestwx._client.base import TempestBase
|
|
18
|
+
from tempestwx._client.decorators import make_request
|
|
19
|
+
from tempestwx._client.processor import model_instance
|
|
20
|
+
from tempestwx._models.better_forecast import BetterForecast
|
|
21
|
+
from tempestwx._models.units_default import (
|
|
22
|
+
TEMPEST_DEFAULT_UNITS,
|
|
23
|
+
UnitsDistance,
|
|
24
|
+
UnitsPrecip,
|
|
25
|
+
UnitsPressure,
|
|
26
|
+
UnitsTemp,
|
|
27
|
+
UnitsWind,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class TempestBetterForecast(TempestBase):
|
|
32
|
+
"""Better Forecast API endpoints."""
|
|
33
|
+
|
|
34
|
+
@make_request(model_instance(BetterForecast))
|
|
35
|
+
def forecast(
|
|
36
|
+
self,
|
|
37
|
+
station_id: int,
|
|
38
|
+
units_temp: UnitsTemp | str = TEMPEST_DEFAULT_UNITS.units_temp,
|
|
39
|
+
units_wind: UnitsWind | str = TEMPEST_DEFAULT_UNITS.units_wind,
|
|
40
|
+
units_pressure: UnitsPressure | str = TEMPEST_DEFAULT_UNITS.units_pressure,
|
|
41
|
+
units_precip: UnitsPrecip | str = TEMPEST_DEFAULT_UNITS.units_precip,
|
|
42
|
+
units_distance: UnitsDistance | str = TEMPEST_DEFAULT_UNITS.units_distance,
|
|
43
|
+
) -> BetterForecast:
|
|
44
|
+
"""Get current conditions and Better Forecast data for a station.
|
|
45
|
+
|
|
46
|
+
Wrapper for Tempest Weather API endpoint:
|
|
47
|
+
https://apidocs.tempestwx.com/reference/get_better-forecast
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
station_id: Unique station identifier. Must be a positive integer.
|
|
51
|
+
units_temp: Temperature units (allowed: 'c', 'f').
|
|
52
|
+
Defaults to 'c'.
|
|
53
|
+
units_wind: Wind units (allowed: 'mph', 'kph', 'kts', 'mps', 'bft',
|
|
54
|
+
'lfm'). Defaults to 'mps'.
|
|
55
|
+
units_pressure: Pressure units (allowed: 'mb', 'inhg', 'mmhg', 'hpa').
|
|
56
|
+
Defaults to 'mb'.
|
|
57
|
+
units_precip: Precipitation units (allowed: 'mm', 'cm', 'in').
|
|
58
|
+
Defaults to 'mm'.
|
|
59
|
+
units_distance: Distance units (allowed: 'km', 'mi').
|
|
60
|
+
Defaults to 'km'.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Current conditions plus Better Forecast.
|
|
64
|
+
|
|
65
|
+
Raises:
|
|
66
|
+
ValueError: If ``station_id`` is invalid or any unit parameter fails enum
|
|
67
|
+
validation.
|
|
68
|
+
"""
|
|
69
|
+
if station_id <= 0:
|
|
70
|
+
raise ValueError("station_id must be a positive integer.")
|
|
71
|
+
|
|
72
|
+
# Validate and convert all unit parameters
|
|
73
|
+
validated_temp = self._validate_enum_param("units_temp", units_temp, UnitsTemp)
|
|
74
|
+
validated_wind = self._validate_enum_param("units_wind", units_wind, UnitsWind)
|
|
75
|
+
validated_pressure = self._validate_enum_param(
|
|
76
|
+
"units_pressure", units_pressure, UnitsPressure
|
|
77
|
+
)
|
|
78
|
+
validated_precip = self._validate_enum_param(
|
|
79
|
+
"units_precip", units_precip, UnitsPrecip
|
|
80
|
+
)
|
|
81
|
+
validated_distance = self._validate_enum_param(
|
|
82
|
+
"units_distance", units_distance, UnitsDistance
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
return self._get( # type: ignore[no-any-return]
|
|
86
|
+
"better_forecast",
|
|
87
|
+
station_id=station_id,
|
|
88
|
+
units_temp=validated_temp.value,
|
|
89
|
+
units_wind=validated_wind.value,
|
|
90
|
+
units_pressure=validated_pressure.value,
|
|
91
|
+
units_precip=validated_precip.value,
|
|
92
|
+
units_distance=validated_distance.value,
|
|
93
|
+
)
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"""Observations API endpoint implementation.
|
|
2
|
+
|
|
3
|
+
This module provides access to historical and real-time weather observation data
|
|
4
|
+
from Tempest Weather stations and devices. It supports querying observations by:
|
|
5
|
+
|
|
6
|
+
- Station ID (aggregated multi-device data with time ranges)
|
|
7
|
+
- Device ID (raw device-level measurements)
|
|
8
|
+
- Latest observations (most recent readings for a station)
|
|
9
|
+
|
|
10
|
+
Observations include metrics like temperature, humidity, wind speed, pressure,
|
|
11
|
+
and precipitation. Data can be filtered by time range, bucketed by intervals,
|
|
12
|
+
and customized with unit preferences.
|
|
13
|
+
|
|
14
|
+
API Reference:
|
|
15
|
+
- Station observations: https://apidocs.tempestwx.com/reference/get_observations-stn-station-id-1
|
|
16
|
+
- Device observations: https://apidocs.tempestwx.com/reference/getobservationsbydeviceid
|
|
17
|
+
- Latest observations: https://apidocs.tempestwx.com/reference/getstationobservation
|
|
18
|
+
|
|
19
|
+
Classes:
|
|
20
|
+
TempestObservations: Client for retrieving weather observation data.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import re as _re
|
|
26
|
+
|
|
27
|
+
from tempestwx._client.base import TempestBase
|
|
28
|
+
from tempestwx._client.decorators import make_request
|
|
29
|
+
from tempestwx._client.processor import model_instance
|
|
30
|
+
from tempestwx._models.device_observation import DeviceObservation
|
|
31
|
+
from tempestwx._models.station_observation_latest import (
|
|
32
|
+
StationObservationLatest,
|
|
33
|
+
)
|
|
34
|
+
from tempestwx._models.station_observations import StationObservation
|
|
35
|
+
from tempestwx._models.units_default import (
|
|
36
|
+
TEMPEST_DEFAULT_UNITS,
|
|
37
|
+
Bucket,
|
|
38
|
+
Format,
|
|
39
|
+
UnitsDistance,
|
|
40
|
+
UnitsPrecip,
|
|
41
|
+
UnitsPressure,
|
|
42
|
+
UnitsTemp,
|
|
43
|
+
UnitsWind,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class TempestObservations(TempestBase):
|
|
48
|
+
"""Observations API endpoints."""
|
|
49
|
+
|
|
50
|
+
@make_request(model_instance(StationObservation))
|
|
51
|
+
def obs_station(
|
|
52
|
+
self,
|
|
53
|
+
station_id: int,
|
|
54
|
+
start_time: int | None = None,
|
|
55
|
+
end_time: int | None = None,
|
|
56
|
+
bucket: Bucket | int = TEMPEST_DEFAULT_UNITS.bucket.value,
|
|
57
|
+
obs_fields: str = "", # comma-separated observation field names
|
|
58
|
+
units_temp: UnitsTemp | str = TEMPEST_DEFAULT_UNITS.units_temp,
|
|
59
|
+
units_wind: UnitsWind | str = TEMPEST_DEFAULT_UNITS.units_wind,
|
|
60
|
+
units_pressure: UnitsPressure | str = (TEMPEST_DEFAULT_UNITS.units_pressure),
|
|
61
|
+
units_precip: UnitsPrecip | str = TEMPEST_DEFAULT_UNITS.units_precip,
|
|
62
|
+
units_distance: UnitsDistance | str = (TEMPEST_DEFAULT_UNITS.units_distance),
|
|
63
|
+
) -> StationObservation:
|
|
64
|
+
"""Get observations for a station (historical / range query).
|
|
65
|
+
|
|
66
|
+
Wrapper for Tempest Weather API endpoint:
|
|
67
|
+
https://apidocs.tempestwx.com/reference/get_observations-stn-station-id-1
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
station_id: Unique station identifier. Must be a positive integer.
|
|
71
|
+
start_time: Unix epoch seconds (UTC) for the beginning of the time range. If
|
|
72
|
+
provided must be > 0 and (if ``end_time`` given) <= ``end_time``.
|
|
73
|
+
end_time: Unix epoch seconds (UTC) for the end of the time range. If
|
|
74
|
+
provided must be > 0 and (if ``start_time`` given) >=
|
|
75
|
+
``start_time``.
|
|
76
|
+
bucket: Aggregation bucket size (minutes) accepted by the API. May be
|
|
77
|
+
either a ``Bucket`` enum member or its underlying integer value.
|
|
78
|
+
Defaults to 1 (no aggregation). Allowed values: 1, 5, 30, 180.
|
|
79
|
+
obs_fields: Comma separated list of observation field names to limit the
|
|
80
|
+
response. Field names must be in the allowed set published by the
|
|
81
|
+
API (e.g. "timestamp,air_temperature,wind_avg" - list subject to
|
|
82
|
+
API docs). Empty string requests all default fields.
|
|
83
|
+
units_temp: Temperature units (allowed: 'c', 'f').
|
|
84
|
+
Defaults to 'c'.
|
|
85
|
+
units_wind: Wind units (allowed: 'mph', 'kph', 'kts', 'mps', 'bft',
|
|
86
|
+
'lfm'). Defaults to 'mps'.
|
|
87
|
+
units_pressure: Pressure units (allowed: 'mb', 'inhg', 'mmhg', 'hpa').
|
|
88
|
+
Defaults to 'mb'.
|
|
89
|
+
units_precip: Precipitation units (allowed: 'mm', 'cm', 'in').
|
|
90
|
+
Defaults to 'mm'.
|
|
91
|
+
units_distance: Distance units (allowed: 'km', 'mi').
|
|
92
|
+
Defaults to 'km'.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
Station observations.
|
|
96
|
+
|
|
97
|
+
Raises:
|
|
98
|
+
ValueError: If any validation fails (invalid station_id, time range, bucket,
|
|
99
|
+
units or obs_fields).
|
|
100
|
+
"""
|
|
101
|
+
if station_id <= 0:
|
|
102
|
+
raise ValueError("station_id must be a positive integer.")
|
|
103
|
+
|
|
104
|
+
# Validate time range
|
|
105
|
+
if start_time is not None and start_time <= 0:
|
|
106
|
+
raise ValueError("start_time must be a positive Unix epoch seconds value.")
|
|
107
|
+
if end_time is not None and end_time <= 0:
|
|
108
|
+
raise ValueError("end_time must be a positive Unix epoch seconds value.")
|
|
109
|
+
if start_time is not None and end_time is not None and start_time > end_time:
|
|
110
|
+
raise ValueError("start_time cannot be greater than end_time.")
|
|
111
|
+
|
|
112
|
+
# Validate and convert all unit parameters
|
|
113
|
+
if isinstance(bucket, int):
|
|
114
|
+
bucket_for_validate: Bucket | str = Bucket(bucket)
|
|
115
|
+
else:
|
|
116
|
+
bucket_for_validate = bucket
|
|
117
|
+
|
|
118
|
+
validate_bucket = self._validate_enum_param(
|
|
119
|
+
"bucket", bucket_for_validate, Bucket
|
|
120
|
+
)
|
|
121
|
+
validated_temp = self._validate_enum_param("units_temp", units_temp, UnitsTemp)
|
|
122
|
+
validated_wind = self._validate_enum_param("units_wind", units_wind, UnitsWind)
|
|
123
|
+
validated_pressure = self._validate_enum_param(
|
|
124
|
+
"units_pressure", units_pressure, UnitsPressure
|
|
125
|
+
)
|
|
126
|
+
validated_precip = self._validate_enum_param(
|
|
127
|
+
"units_precip", units_precip, UnitsPrecip
|
|
128
|
+
)
|
|
129
|
+
validated_distance = self._validate_enum_param(
|
|
130
|
+
"units_distance", units_distance, UnitsDistance
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# Basic obs_fields validation
|
|
134
|
+
if obs_fields:
|
|
135
|
+
raw_fields = [f.strip() for f in obs_fields.split(",") if f.strip()]
|
|
136
|
+
if not raw_fields:
|
|
137
|
+
raise ValueError("obs_fields provided but no valid field names parsed.")
|
|
138
|
+
|
|
139
|
+
# Accept simple snake_case alphanum + underscore names
|
|
140
|
+
invalid = [f for f in raw_fields if not _re.fullmatch(r"[a-z0-9_]+", f)]
|
|
141
|
+
if invalid:
|
|
142
|
+
raise ValueError(
|
|
143
|
+
"Invalid field name(s) in obs_fields: "
|
|
144
|
+
f"{invalid}. Field names must be snake_case alphanumeric."
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
return self._get( # type: ignore[no-any-return]
|
|
148
|
+
f"observations/stn/{station_id}",
|
|
149
|
+
start_time=start_time,
|
|
150
|
+
end_time=end_time,
|
|
151
|
+
bucket=validate_bucket.value, # send raw integer expected by API
|
|
152
|
+
obs_fields=obs_fields,
|
|
153
|
+
units_temp=validated_temp,
|
|
154
|
+
units_wind=validated_wind,
|
|
155
|
+
units_pressure=validated_pressure,
|
|
156
|
+
units_precip=validated_precip,
|
|
157
|
+
units_distance=validated_distance,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
@make_request(model_instance(DeviceObservation))
|
|
161
|
+
def obs_device(
|
|
162
|
+
self,
|
|
163
|
+
device_id: int,
|
|
164
|
+
day_offset: int = 0,
|
|
165
|
+
time_start: int | None = None,
|
|
166
|
+
time_end: int | None = None,
|
|
167
|
+
format: Format | str | None = None,
|
|
168
|
+
) -> DeviceObservation:
|
|
169
|
+
"""Get observations for a specific device (e.g., Tempest sensor).
|
|
170
|
+
|
|
171
|
+
Wrapper for Tempest Weather API endpoint:
|
|
172
|
+
https://apidocs.tempestwx.com/reference/getobservationsbydeviceid
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
device_id: Unique device identifier. Must be positive.
|
|
176
|
+
day_offset: Day offset relative to today for which to retrieve observations.
|
|
177
|
+
API typically supports a small negative/positive window (e.g. 0 for
|
|
178
|
+
today, 1 for yesterday).
|
|
179
|
+
time_start: Unix epoch seconds (UTC) lower bound inside the chosen day (if
|
|
180
|
+
provided must be > 0). Must be <= ``time_end`` if both provided.
|
|
181
|
+
time_end: Unix epoch seconds (UTC) upper bound (if provided must be > 0).
|
|
182
|
+
format: Optional response format (e.g. "json" or "csv") if supported. Case
|
|
183
|
+
insensitive. If provided must be one of {"json","csv"}.
|
|
184
|
+
Format units (allowed: 'csv').
|
|
185
|
+
Defaults to JSON response if not provided.
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
Device observations.
|
|
189
|
+
|
|
190
|
+
Raises:
|
|
191
|
+
ValueError: If any input parameter fails validation.
|
|
192
|
+
"""
|
|
193
|
+
if device_id <= 0:
|
|
194
|
+
raise ValueError("device_id must be a positive integer.")
|
|
195
|
+
|
|
196
|
+
if time_start is not None and time_start <= 0:
|
|
197
|
+
raise ValueError("time_start must be a positive Unix epoch seconds value.")
|
|
198
|
+
if time_end is not None and time_end <= 0:
|
|
199
|
+
raise ValueError("time_end must be a positive Unix epoch seconds value.")
|
|
200
|
+
if time_start is not None and time_end is not None and time_start > time_end:
|
|
201
|
+
raise ValueError("time_start cannot be greater than time_end.")
|
|
202
|
+
|
|
203
|
+
if format is not None:
|
|
204
|
+
fmt = format.lower()
|
|
205
|
+
allowed_formats = {"csv"}
|
|
206
|
+
if fmt not in allowed_formats:
|
|
207
|
+
allowed = sorted(allowed_formats)
|
|
208
|
+
raise ValueError(f"Invalid format '{format}'. Allowed: {allowed}")
|
|
209
|
+
format = fmt
|
|
210
|
+
|
|
211
|
+
return self._get( # type: ignore[no-any-return]
|
|
212
|
+
f"observations/device/{device_id}",
|
|
213
|
+
day_offset=day_offset,
|
|
214
|
+
time_start=time_start,
|
|
215
|
+
time_end=time_end,
|
|
216
|
+
format=format,
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
@make_request(model_instance(StationObservationLatest))
|
|
220
|
+
def obs_station_latest(
|
|
221
|
+
self,
|
|
222
|
+
station_id: int,
|
|
223
|
+
) -> StationObservationLatest:
|
|
224
|
+
"""Get the latest observation snapshot for a station.
|
|
225
|
+
|
|
226
|
+
Wrapper for Tempest Weather API endpoint:
|
|
227
|
+
https://apidocs.tempestwx.com/reference/getstationobservation
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
station_id: Unique station identifier. Must be positive.
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
Latest Station observation
|
|
234
|
+
|
|
235
|
+
Raises:
|
|
236
|
+
ValueError: If ``station_id`` is invalid.
|
|
237
|
+
"""
|
|
238
|
+
if station_id <= 0:
|
|
239
|
+
raise ValueError("station_id must be a positive integer.")
|
|
240
|
+
|
|
241
|
+
return self._get(f"observations/station/{station_id}") # type: ignore[no-any-return]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Stations API endpoint implementation.
|
|
2
|
+
|
|
3
|
+
This module provides access to Tempest Weather station metadata, including
|
|
4
|
+
station details, device information, location coordinates, and configuration.
|
|
5
|
+
Stations represent physical locations with one or more weather devices that
|
|
6
|
+
collect atmospheric measurements.
|
|
7
|
+
|
|
8
|
+
API Reference:
|
|
9
|
+
- List all stations: https://apidocs.tempestwx.com/reference/get_stations
|
|
10
|
+
- Get station by ID: https://apidocs.tempestwx.com/reference/getstationbyid
|
|
11
|
+
|
|
12
|
+
Classes:
|
|
13
|
+
TempestStations: Client for retrieving station metadata and details.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from tempestwx._client.base import TempestBase
|
|
19
|
+
from tempestwx._client.decorators import make_request
|
|
20
|
+
from tempestwx._client.processor import model_instance
|
|
21
|
+
from tempestwx._models.station_set import StationSet
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TempestStations(TempestBase):
|
|
25
|
+
"""Stations API endpoints."""
|
|
26
|
+
|
|
27
|
+
@make_request(model_instance(StationSet))
|
|
28
|
+
def stations(self) -> StationSet:
|
|
29
|
+
"""Get metadata for all stations associated with the authenticated account.
|
|
30
|
+
|
|
31
|
+
Wrapper for Tempest Weather API endpoint:
|
|
32
|
+
https://apidocs.tempestwx.com/reference/get_stations
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
Station metadata.
|
|
36
|
+
"""
|
|
37
|
+
return self._get("stations") # type: ignore[no-any-return]
|
|
38
|
+
|
|
39
|
+
@make_request(model_instance(StationSet))
|
|
40
|
+
def station(self, station_id: int) -> StationSet:
|
|
41
|
+
"""Get metadata for a specific station.
|
|
42
|
+
|
|
43
|
+
Wrapper for Tempest Weather API endpoint:
|
|
44
|
+
https://apidocs.tempestwx.com/reference/getstationbyid
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
station_id: Unique station identifier. Must be a positive integer.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Station metadata for a single station.
|
|
51
|
+
|
|
52
|
+
Raises:
|
|
53
|
+
ValueError: If ``station_id`` is not positive.
|
|
54
|
+
"""
|
|
55
|
+
if station_id <= 0:
|
|
56
|
+
raise ValueError("station_id must be a positive integer.")
|
|
57
|
+
|
|
58
|
+
return self._get(f"stations/{station_id}") # type: ignore[no-any-return]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Stats API endpoint implementation.
|
|
2
|
+
|
|
3
|
+
This module provides access to statistical summaries of weather data for
|
|
4
|
+
Tempest Weather stations. Statistics include daily aggregations like min/max
|
|
5
|
+
temperatures, total precipitation, average wind speed, and other derived
|
|
6
|
+
metrics over time periods.
|
|
7
|
+
|
|
8
|
+
These summaries are useful for analyzing historical weather patterns and
|
|
9
|
+
trends without processing raw observation data.
|
|
10
|
+
|
|
11
|
+
API Reference:
|
|
12
|
+
https://apidocs.tempestwx.com/reference/get_stats-station-station-id
|
|
13
|
+
|
|
14
|
+
Classes:
|
|
15
|
+
TempestStats: Client for retrieving weather statistics and summaries.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from tempestwx._client.base import TempestBase
|
|
21
|
+
from tempestwx._client.decorators import make_request
|
|
22
|
+
from tempestwx._client.processor import model_instance
|
|
23
|
+
from tempestwx._models.stats_set import StatsSet
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class TempestStats(TempestBase):
|
|
27
|
+
"""Stats API endpoints."""
|
|
28
|
+
|
|
29
|
+
@make_request(model_instance(StatsSet))
|
|
30
|
+
def stats(self, station_id: int) -> StatsSet:
|
|
31
|
+
"""Get statistics for a specific station.
|
|
32
|
+
|
|
33
|
+
Wrapper for Tempest Weather API endpoint:
|
|
34
|
+
https://apidocs.tempestwx.com/reference/get_stats-station-station-id
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
station_id: Unique station identifier. Must be a positive integer.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Aggregated statistics for the station.
|
|
41
|
+
|
|
42
|
+
Raises:
|
|
43
|
+
ValueError: If ``station_id`` is not positive.
|
|
44
|
+
"""
|
|
45
|
+
if station_id <= 0:
|
|
46
|
+
raise ValueError("station_id must be a positive integer.")
|
|
47
|
+
|
|
48
|
+
return self._get(f"stats/station/{station_id}") # type: ignore[no-any-return]
|