mcp-server-tempest 0.1.0__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.
@@ -0,0 +1,9 @@
1
+ from .server import mcp
2
+
3
+
4
+ def main():
5
+ mcp.run()
6
+
7
+
8
+ if __name__ == "__main__":
9
+ main()
@@ -0,0 +1,464 @@
1
+ from enum import Enum
2
+ from typing import Optional, List
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ # Enums for better type safety
7
+ class DeviceType(str, Enum):
8
+ TEMPEST = "ST" # Tempest outdoor sensor
9
+ HUB = "HB" # Hub
10
+
11
+
12
+ class Environment(str, Enum):
13
+ INDOOR = "indoor"
14
+ OUTDOOR = "outdoor"
15
+
16
+
17
+ class PressureTrend(str, Enum):
18
+ STEADY = "steady"
19
+ RISING = "rising"
20
+ FALLING = "falling"
21
+
22
+
23
+ class TemperatureUnit(str, Enum):
24
+ FAHRENHEIT = "f"
25
+ CELSIUS = "c"
26
+
27
+
28
+ class WindUnit(str, Enum):
29
+ MPH = "mph"
30
+ MPS = "mps" # meters per second
31
+ KPH = "kph"
32
+
33
+
34
+ class PressureUnit(str, Enum):
35
+ INHG = "inhg" # inches of mercury
36
+ MB = "mb" # millibars
37
+ HPA = "hpa" # hectopascals
38
+
39
+
40
+ class PrecipUnit(str, Enum):
41
+ INCHES = "in"
42
+ MILLIMETERS = "mm"
43
+
44
+
45
+ class DistanceUnit(str, Enum):
46
+ MILES = "mi"
47
+ KILOMETERS = "km"
48
+
49
+
50
+ class DirectionUnit(str, Enum):
51
+ CARDINAL = "cardinal"
52
+ DEGREES = "degrees"
53
+
54
+
55
+ class UnitSystem(str, Enum):
56
+ IMPERIAL = "imperial"
57
+ METRIC = "metric"
58
+
59
+
60
+ # Base Models
61
+ class APIStatus(BaseModel):
62
+ """API response status information"""
63
+
64
+ status_code: int = Field(description="Response status code (0 = SUCCESS)")
65
+ status_message: str = Field(description="Status message description")
66
+
67
+
68
+ class Units(BaseModel):
69
+ """Unit specifications for measurements"""
70
+
71
+ units_temp: TemperatureUnit = Field(description="Temperature units")
72
+ units_wind: WindUnit = Field(description="Wind speed units")
73
+ units_pressure: PressureUnit = Field(description="Pressure units")
74
+ units_precip: PrecipUnit = Field(description="Precipitation units")
75
+ units_distance: DistanceUnit = Field(description="Distance units")
76
+ units_direction: Optional[DirectionUnit] = Field(
77
+ None, description="Direction format"
78
+ )
79
+ units_other: UnitSystem = Field(description="General unit system")
80
+
81
+
82
+ class Location(BaseModel):
83
+ """Geographic location information"""
84
+
85
+ latitude: float = Field(description="Latitude coordinate")
86
+ longitude: float = Field(description="Longitude coordinate")
87
+ timezone: str = Field(
88
+ description="IANA timezone identifier", examples=["America/Los_Angeles"]
89
+ )
90
+ timezone_offset_minutes: int = Field(
91
+ description="UTC offset in minutes (negative for west of UTC)"
92
+ )
93
+
94
+
95
+ # Device Models
96
+ class DeviceMeta(BaseModel):
97
+ """Device-specific metadata"""
98
+
99
+ agl: float = Field(description="Height above ground level in meters")
100
+ environment: Environment = Field(description="Installation environment")
101
+ name: str = Field(description="Device name/serial number")
102
+ wifi_network_name: Optional[str] = Field(
103
+ None, description="Connected WiFi network name"
104
+ )
105
+
106
+
107
+ class DeviceSettings(BaseModel):
108
+ """Device-specific configuration settings"""
109
+
110
+ show_precip_final: Optional[bool] = Field(
111
+ None, description="Whether to show final precipitation values"
112
+ )
113
+
114
+
115
+ class Device(BaseModel):
116
+ """Weather station device information"""
117
+
118
+ device_id: int = Field(description="Unique device identifier")
119
+ device_type: DeviceType = Field(description="Type of device")
120
+ serial_number: Optional[str] = Field(
121
+ None, description="Device serial number (None if inactive)"
122
+ )
123
+ firmware_revision: str = Field(description="Current firmware version")
124
+ hardware_revision: str = Field(description="Hardware revision number")
125
+ device_meta: DeviceMeta = Field(description="Device-specific metadata")
126
+ device_settings: Optional[DeviceSettings] = Field(
127
+ None, description="Device configuration settings"
128
+ )
129
+
130
+
131
+ # Station Models
132
+ class StationMeta(BaseModel):
133
+ """Station metadata"""
134
+
135
+ elevation: float = Field(description="Station elevation in meters above sea level")
136
+ share_with_wf: bool = Field(description="Whether data is shared with WeatherFlow")
137
+ share_with_wu: bool = Field(
138
+ description="Whether data is shared with Weather Underground"
139
+ )
140
+
141
+
142
+ class StationItem(BaseModel):
143
+ """Station measurement item configuration"""
144
+
145
+ item: str = Field(
146
+ description="Type of measurement", examples=["air_temperature_humidity"]
147
+ )
148
+ station_id: int = Field(description="Associated station ID")
149
+ station_item_id: int = Field(description="Unique item identifier")
150
+ location_id: int = Field(description="Location identifier")
151
+ location_item_id: int = Field(description="Location-specific item identifier")
152
+ device_id: int = Field(description="Device providing this measurement")
153
+ sort: Optional[int] = Field(None, description="Display sort order")
154
+
155
+
156
+ class StationCapability(BaseModel):
157
+ """Station measurement capability"""
158
+
159
+ capability: str = Field(description="Measurement capability type")
160
+ device_id: int = Field(description="Device providing this capability")
161
+ environment: Environment = Field(description="Operating environment")
162
+ agl: Optional[float] = Field(
163
+ None, description="Height above ground level in meters"
164
+ )
165
+ show_precip_final: Optional[bool] = Field(
166
+ None, description="Precipitation display setting"
167
+ )
168
+
169
+
170
+ class WeatherStation(BaseModel):
171
+ """Complete weather station information"""
172
+
173
+ station_id: int = Field(description="Unique identifier for the weather station")
174
+ name: str = Field(
175
+ description="Internal name of the weather station", examples=["Seattle"]
176
+ )
177
+ public_name: str = Field(
178
+ description="Public display name of the station", examples=["Fairview Ave E"]
179
+ )
180
+ latitude: float = Field(description="Latitude coordinate of the station")
181
+ longitude: float = Field(description="Longitude coordinate of the station")
182
+ timezone: str = Field(
183
+ description="IANA timezone identifier", examples=["America/Los_Angeles"]
184
+ )
185
+ timezone_offset_minutes: int = Field(
186
+ description="UTC offset in minutes (negative for west of UTC)"
187
+ )
188
+ created_epoch: int = Field(
189
+ description="Unix timestamp when the station was created"
190
+ )
191
+ last_modified_epoch: int = Field(
192
+ description="Unix timestamp of last station modification"
193
+ )
194
+ is_local_mode: bool = Field(
195
+ description="Whether the station is operating in local mode"
196
+ )
197
+ station_meta: StationMeta = Field(description="Station metadata")
198
+ devices: List[Device] = Field(
199
+ description="Array of devices connected to the station"
200
+ )
201
+ station_items: List[StationItem] = Field(
202
+ description="Configuration of station measurement items"
203
+ )
204
+ capabilities: Optional[List[StationCapability]] = Field(
205
+ None, description="Station measurement capabilities"
206
+ )
207
+
208
+
209
+ # Weather/Forecast Models
210
+ class DailyForecast(BaseModel):
211
+ """Daily weather forecast"""
212
+
213
+ air_temp_high: float = Field(description="High temperature")
214
+ air_temp_low: float = Field(description="Low temperature")
215
+ day_num: int = Field(ge=1, le=31, description="Day of month")
216
+ day_start_local: int = Field(
217
+ description="Unix timestamp for start of day in local time"
218
+ )
219
+ month_num: int = Field(ge=1, le=12, description="Month number")
220
+ icon: str = Field(description="Weather icon identifier", examples=["clear-day"])
221
+ conditions: str = Field(
222
+ description="Weather conditions description", examples=["Clear"]
223
+ )
224
+ precip_probability: int = Field(
225
+ ge=0, le=100, description="Precipitation probability percentage"
226
+ )
227
+ precip_type: Optional[str] = Field(
228
+ None, description="Type of precipitation", examples=["rain"]
229
+ )
230
+ precip_icon: Optional[str] = Field(
231
+ None, description="Precipitation icon identifier"
232
+ )
233
+ sunrise: int = Field(description="Unix timestamp for sunrise")
234
+ sunset: int = Field(description="Unix timestamp for sunset")
235
+
236
+
237
+ class HourlyForecast(BaseModel):
238
+ """Hourly weather forecast"""
239
+
240
+ air_temperature: float = Field(description="Temperature")
241
+ local_day: int = Field(description="Local day")
242
+ local_hour: int = Field(ge=0, le=23, description="Local hour")
243
+ time: int = Field(description="Unix timestamp")
244
+ precip: float = Field(ge=0, description="Precipitation amount")
245
+ precip_probability: int = Field(
246
+ ge=0, le=100, description="Precipitation probability percentage"
247
+ )
248
+ precip_type: Optional[str] = Field(None, description="Type of precipitation")
249
+ relative_humidity: int = Field(
250
+ ge=0, le=100, description="Relative humidity percentage"
251
+ )
252
+ sea_level_pressure: float = Field(description="Atmospheric pressure")
253
+ wind_avg: float = Field(ge=0, description="Average wind speed")
254
+ wind_direction: float = Field(ge=0, le=360, description="Wind direction in degrees")
255
+ wind_direction_cardinal: str = Field(
256
+ description="Cardinal wind direction", examples=["NE"]
257
+ )
258
+ wind_gust: float = Field(ge=0, description="Wind gust speed")
259
+ conditions: str = Field(description="Weather conditions description")
260
+ icon: str = Field(description="Weather icon identifier")
261
+ feels_like: float = Field(description="Apparent temperature")
262
+ uv: float = Field(ge=0, description="UV index")
263
+
264
+
265
+ class CurrentConditions(BaseModel):
266
+ """Current weather conditions"""
267
+
268
+ air_temperature: float = Field(description="Current temperature")
269
+ conditions: str = Field(description="Current weather conditions")
270
+ feels_like: float = Field(description="Apparent temperature")
271
+ icon: str = Field(description="Current weather icon")
272
+ relative_humidity: int = Field(
273
+ ge=0, le=100, description="Current humidity percentage"
274
+ )
275
+ sea_level_pressure: float = Field(description="Current pressure")
276
+ wind_avg: float = Field(ge=0, description="Average wind speed")
277
+ wind_gust: float = Field(ge=0, description="Wind gust speed")
278
+ wind_direction: float = Field(ge=0, le=360, description="Wind direction in degrees")
279
+ wind_direction_cardinal: str = Field(description="Cardinal wind direction")
280
+ uv: int = Field(ge=0, description="Current UV index")
281
+ time: int = Field(description="Unix timestamp of observation")
282
+ # Additional measurements
283
+ solar_radiation: Optional[float] = Field(
284
+ None, description="Solar radiation intensity"
285
+ )
286
+ brightness: Optional[float] = Field(None, description="Light intensity in lux")
287
+ dew_point: Optional[float] = Field(None, description="Dew point temperature")
288
+ wet_bulb_temperature: Optional[float] = Field(
289
+ None, description="Wet bulb temperature"
290
+ )
291
+ # Lightning data
292
+ lightning_strike_last_epoch: Optional[int] = Field(
293
+ None, description="Unix timestamp of last lightning strike"
294
+ )
295
+ lightning_strike_last_distance: Optional[int] = Field(
296
+ None, description="Distance to last lightning strike"
297
+ )
298
+ lightning_strike_count: Optional[int] = Field(
299
+ None, description="Current lightning strike count"
300
+ )
301
+ lightning_strike_count_last_1hr: Optional[int] = Field(
302
+ None, description="Lightning strikes in last hour"
303
+ )
304
+ lightning_strike_count_last_3hr: Optional[int] = Field(
305
+ None, description="Lightning strikes in last 3 hours"
306
+ )
307
+ # Precipitation accumulations
308
+ precip_accum_last_1hr: Optional[float] = Field(
309
+ None, description="Precipitation accumulation in last hour"
310
+ )
311
+ precip_accum_local_day: Optional[float] = Field(
312
+ None, description="Precipitation accumulation for current local day"
313
+ )
314
+ precip_accum_local_yesterday: Optional[float] = Field(
315
+ None, description="Precipitation accumulation for yesterday"
316
+ )
317
+
318
+
319
+ class Forecast(BaseModel):
320
+ """Weather forecast data"""
321
+
322
+ daily: List[DailyForecast] = Field(description="10-day daily forecast")
323
+ hourly: List[HourlyForecast] = Field(description="Detailed hourly forecast")
324
+
325
+
326
+ # Observation Models
327
+ class WeatherObservation(BaseModel):
328
+ """Detailed weather observation"""
329
+
330
+ timestamp: int = Field(description="Unix timestamp of the observation")
331
+ air_temperature: float = Field(description="Current air temperature")
332
+ barometric_pressure: float = Field(description="Station barometric pressure")
333
+ station_pressure: float = Field(description="Station-level atmospheric pressure")
334
+ pressure_trend: PressureTrend = Field(description="Pressure trend")
335
+ sea_level_pressure: float = Field(
336
+ description="Sea level adjusted atmospheric pressure"
337
+ )
338
+ relative_humidity: int = Field(
339
+ ge=0, le=100, description="Relative humidity percentage"
340
+ )
341
+ precip: float = Field(ge=0, description="Current precipitation rate")
342
+ precip_accum_last_1hr: float = Field(
343
+ ge=0, description="Precipitation accumulation in last hour"
344
+ )
345
+ precip_accum_local_day: float = Field(
346
+ ge=0, description="Precipitation accumulation for current local day"
347
+ )
348
+ precip_accum_local_day_final: float = Field(
349
+ ge=0, description="Final precipitation total for current day"
350
+ )
351
+ precip_accum_local_yesterday: float = Field(
352
+ ge=0, description="Precipitation accumulation for yesterday"
353
+ )
354
+ precip_accum_local_yesterday_final: float = Field(
355
+ ge=0, description="Final precipitation total for yesterday"
356
+ )
357
+ precip_analysis_type_yesterday: int = Field(
358
+ description="Type of precipitation analysis for yesterday"
359
+ )
360
+ precip_minutes_local_day: int = Field(
361
+ ge=0, description="Minutes of precipitation today"
362
+ )
363
+ precip_minutes_local_yesterday: int = Field(
364
+ ge=0, description="Minutes of precipitation yesterday"
365
+ )
366
+ precip_minutes_local_yesterday_final: int = Field(
367
+ ge=0, description="Final minutes of precipitation yesterday"
368
+ )
369
+ wind_avg: float = Field(ge=0, description="Average wind speed")
370
+ wind_direction: int = Field(ge=0, le=360, description="Wind direction in degrees")
371
+ wind_gust: float = Field(ge=0, description="Wind gust speed")
372
+ wind_lull: float = Field(ge=0, description="Wind lull (minimum wind speed)")
373
+ solar_radiation: float = Field(ge=0, description="Solar radiation intensity")
374
+ uv: float = Field(ge=0, description="UV index")
375
+ brightness: float = Field(ge=0, description="Light intensity in lux")
376
+ lightning_strike_last_epoch: Optional[int] = Field(
377
+ None, description="Unix timestamp of last lightning strike"
378
+ )
379
+ lightning_strike_last_distance: Optional[int] = Field(
380
+ None, description="Distance to last lightning strike"
381
+ )
382
+ lightning_strike_count: int = Field(
383
+ ge=0, description="Current lightning strike count"
384
+ )
385
+ lightning_strike_count_last_1hr: int = Field(
386
+ ge=0, description="Lightning strikes in last hour"
387
+ )
388
+ lightning_strike_count_last_3hr: int = Field(
389
+ ge=0, description="Lightning strikes in last 3 hours"
390
+ )
391
+ feels_like: float = Field(
392
+ description="Apparent temperature (heat index or wind chill)"
393
+ )
394
+ heat_index: float = Field(description="Heat index temperature")
395
+ wind_chill: float = Field(description="Wind chill temperature")
396
+ dew_point: float = Field(description="Dew point temperature")
397
+ wet_bulb_temperature: float = Field(description="Wet bulb temperature")
398
+ wet_bulb_globe_temperature: float = Field(description="Wet bulb globe temperature")
399
+ delta_t: float = Field(
400
+ description="Delta T (difference between air temp and wet bulb temp)"
401
+ )
402
+ air_density: float = Field(description="Air density")
403
+
404
+
405
+ # Main Response Models
406
+ class StationsResponse(BaseModel):
407
+ """Response containing multiple weather stations"""
408
+
409
+ stations: List[WeatherStation] = Field(
410
+ description="Array of weather station objects"
411
+ )
412
+ status: APIStatus = Field(description="API response status information")
413
+
414
+
415
+ class StationResponse(WeatherStation):
416
+ """Response for a single weather station (inherits all WeatherStation fields)"""
417
+
418
+ pass
419
+
420
+
421
+ class ForecastResponse(BaseModel):
422
+ """Weather forecast response"""
423
+
424
+ forecast: Forecast = Field(description="Weather forecast data")
425
+ current_conditions: CurrentConditions = Field(
426
+ description="Real-time weather observations"
427
+ )
428
+ location_name: str = Field(
429
+ description="Name of the weather station location", examples=["Seattle"]
430
+ )
431
+ latitude: float = Field(description="Latitude coordinate of the station")
432
+ longitude: float = Field(description="Longitude coordinate of the station")
433
+ timezone: str = Field(
434
+ description="IANA timezone identifier", examples=["America/Los_Angeles"]
435
+ )
436
+ timezone_offset_minutes: int = Field(description="UTC offset in minutes")
437
+ units: Units = Field(description="Unit specifications for all measurements")
438
+
439
+
440
+ class ObservationResponse(BaseModel):
441
+ """Weather observation response"""
442
+
443
+ outdoor_keys: List[str] = Field(
444
+ description="List of available outdoor measurement field names"
445
+ )
446
+ obs: List[WeatherObservation] = Field(description="Array of observation records")
447
+ station_id: int = Field(description="Unique identifier for the weather station")
448
+ station_name: str = Field(
449
+ description="Name of the weather station", examples=["Seattle"]
450
+ )
451
+ public_name: str = Field(
452
+ description="Public display name of the station", examples=["Lake Union"]
453
+ )
454
+ latitude: float = Field(description="Latitude coordinate of the station")
455
+ longitude: float = Field(description="Longitude coordinate of the station")
456
+ elevation: float = Field(description="Elevation of the station in meters")
457
+ is_public: bool = Field(
458
+ description="Whether the station data is publicly accessible"
459
+ )
460
+ timezone: str = Field(
461
+ description="IANA timezone identifier", examples=["America/Los_Angeles"]
462
+ )
463
+ station_units: Units = Field(description="Unit specifications for all measurements")
464
+ status: APIStatus = Field(description="API response status information")
@@ -0,0 +1,25 @@
1
+ from weatherflow4py.api import WeatherFlowRestAPI
2
+
3
+
4
+ async def api_get_stations(token: str) -> dict:
5
+ async with WeatherFlowRestAPI(token) as api:
6
+ stations = await api.async_get_stations()
7
+ return stations.to_dict()
8
+
9
+
10
+ async def api_get_station_id(station_id: int, token: str) -> dict:
11
+ async with WeatherFlowRestAPI(token) as api:
12
+ station = await api.async_get_station(station_id=station_id)
13
+ return station[0].to_dict()
14
+
15
+
16
+ async def api_get_forecast(station_id: int, token: str) -> dict:
17
+ async with WeatherFlowRestAPI(token) as api:
18
+ forecast = await api.async_get_forecast(station_id=station_id)
19
+ return forecast.to_dict()
20
+
21
+
22
+ async def api_get_observation(station_id: int, token: str) -> dict:
23
+ async with WeatherFlowRestAPI(token) as api:
24
+ observation = await api.async_get_observation(station_id=station_id)
25
+ return observation.to_dict()