Spaces:
Sleeping
Add comprehensive snow and thunderstorm detection from DWD ICON
Browse filesEnhanced weather forecasting with real DWD snow and thunderstorm data:
❄️ **Snow Detection**:
- Convective snow (snow_con) and grid-scale snow (snow_gsp)
- Light, moderate, and heavy snow classification
- Snow accumulation warnings
⛈️ **Thunderstorm Analysis**:
- CAPE (Convective Available Potential Energy) thresholds
- Lightning Potential Index (lpi_con)
- Convective precipitation detection
- Severe thunderstorm warnings (CAPE > 2500)
🌧️ **Enhanced Precipitation Types**:
- Temperature-based precipitation type determination
- "Snow likely, mainly afternoon" vs "thunderstorms likely, mainly evening"
- Proper winter weather and severe weather advisories
📊 **NOAA Text Integration**:
- Natural language for snow: "chance of snow, mainly morning"
- Thunderstorm timing: "thunderstorms likely, mainly afternoon"
- Enhanced weather advisories with severity levels
Uses authentic DWD ICON variables for meteorologically accurate
snow and thunderstorm prediction.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
|
@@ -180,9 +180,15 @@ def fetch_dwd_icon_data(lat, lon):
|
|
| 180 |
'v_10m': 'V-component of wind at 10m',
|
| 181 |
'pmsl': 'Pressure at mean sea level',
|
| 182 |
'tot_prec': 'Total precipitation',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 183 |
'clct': 'Total cloud cover',
|
| 184 |
'asob_s': 'Net shortwave radiation at surface',
|
| 185 |
-
'vmax_10m': 'Wind gusts at 10m'
|
|
|
|
| 186 |
}
|
| 187 |
|
| 188 |
# Download coordinate files first
|
|
@@ -395,6 +401,12 @@ def process_real_dwd_data(dwd_data, lat, lon):
|
|
| 395 |
wind_gust = []
|
| 396 |
pressure = []
|
| 397 |
precipitation = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 398 |
cloud_cover = []
|
| 399 |
solar_radiation = []
|
| 400 |
|
|
@@ -451,6 +463,60 @@ def process_real_dwd_data(dwd_data, lat, lon):
|
|
| 451 |
else:
|
| 452 |
precipitation.append(0.0)
|
| 453 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 454 |
# Cloud cover (convert from fraction to percentage if needed)
|
| 455 |
clct = data['clct'][i]
|
| 456 |
if clct is not None:
|
|
@@ -477,6 +543,13 @@ def process_real_dwd_data(dwd_data, lat, lon):
|
|
| 477 |
'wind_gust': wind_gust,
|
| 478 |
'pressure': pressure,
|
| 479 |
'precipitation': precipitation,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 480 |
'cloud_cover': cloud_cover,
|
| 481 |
'solar_radiation': solar_radiation,
|
| 482 |
'lat': lat,
|
|
@@ -556,7 +629,7 @@ def process_fallback_data(weather_data, lat, lon):
|
|
| 556 |
def analyze_weather_events(forecast_data):
|
| 557 |
"""
|
| 558 |
Analyze forecast data to identify significant weather events and timing
|
| 559 |
-
|
| 560 |
"""
|
| 561 |
timestamps = forecast_data['timestamps']
|
| 562 |
temperature = forecast_data['temperature']
|
|
@@ -567,6 +640,12 @@ def analyze_weather_events(forecast_data):
|
|
| 567 |
cloud_cover = forecast_data.get('cloud_cover', [50] * len(timestamps))
|
| 568 |
pressure = forecast_data.get('pressure', [1013] * len(timestamps))
|
| 569 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 570 |
events = []
|
| 571 |
|
| 572 |
# Analyze each forecast period
|
|
@@ -590,8 +669,39 @@ def analyze_weather_events(forecast_data):
|
|
| 590 |
'temperature_descriptor': None
|
| 591 |
}
|
| 592 |
|
| 593 |
-
#
|
| 594 |
-
if
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 595 |
if precip < 1.0:
|
| 596 |
event['precipitation_type'] = 'light_rain'
|
| 597 |
event['conditions'].append('light rain')
|
|
@@ -643,18 +753,25 @@ def analyze_weather_events(forecast_data):
|
|
| 643 |
if rh > 95 and wind < 3:
|
| 644 |
event['conditions'].append('fog possible')
|
| 645 |
|
| 646 |
-
# Determine primary weather
|
| 647 |
if event['conditions']:
|
| 648 |
-
|
|
|
|
|
|
|
|
|
|
| 649 |
event['primary_weather'] = 'thunderstorms'
|
| 650 |
-
elif '
|
|
|
|
|
|
|
| 651 |
event['primary_weather'] = 'snow'
|
| 652 |
-
elif '
|
|
|
|
|
|
|
| 653 |
event['primary_weather'] = 'rain'
|
| 654 |
-
elif 'windy' in
|
| 655 |
event['primary_weather'] = 'wind'
|
| 656 |
else:
|
| 657 |
-
event['primary_weather'] =
|
| 658 |
|
| 659 |
events.append(event)
|
| 660 |
|
|
@@ -831,9 +948,10 @@ def analyze_period_conditions(indices, timestamps, temperatures, precipitation,
|
|
| 831 |
data['avg_clouds'] = sum(data['clouds']) / len(data['clouds']) if data['clouds'] else 50
|
| 832 |
data['max_wind'] = max(data['winds']) if data['winds'] else 5
|
| 833 |
|
| 834 |
-
# Precipitation analysis
|
| 835 |
data['precip_chance'] = calculate_precipitation_chance(data['precip'])
|
| 836 |
data['rain_timing'] = analyze_6hour_precipitation_timing(data['timestamps'], data['precip'], period_start, period_end)
|
|
|
|
| 837 |
|
| 838 |
# Cloud cover description
|
| 839 |
data['sky_condition'] = get_sky_condition(data['avg_clouds'])
|
|
@@ -843,6 +961,22 @@ def analyze_period_conditions(indices, timestamps, temperatures, precipitation,
|
|
| 843 |
|
| 844 |
return data
|
| 845 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 846 |
def calculate_precipitation_chance(precip_data):
|
| 847 |
"""Calculate precipitation chance percentage"""
|
| 848 |
if not precip_data:
|
|
@@ -942,24 +1076,54 @@ def get_wind_description(wind_speed):
|
|
| 942 |
return "very windy"
|
| 943 |
|
| 944 |
def generate_enhanced_period_narrative(period_name, data, is_day):
|
| 945 |
-
"""Generate enhanced narrative with precipitation chances, timing,
|
| 946 |
conditions = []
|
| 947 |
|
| 948 |
-
#
|
|
|
|
|
|
|
|
|
|
| 949 |
if data['precip_chance'] > 60:
|
| 950 |
-
if
|
| 951 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 952 |
else:
|
| 953 |
-
|
|
|
|
|
|
|
|
|
|
| 954 |
conditions.append(f"Chance of precipitation {data['precip_chance']}%")
|
| 955 |
elif data['precip_chance'] > 30:
|
| 956 |
-
if
|
| 957 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 958 |
else:
|
| 959 |
-
|
|
|
|
|
|
|
|
|
|
| 960 |
conditions.append(f"Chance of precipitation {data['precip_chance']}%")
|
| 961 |
elif data['precip_chance'] > 0:
|
| 962 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 963 |
|
| 964 |
# If no significant precipitation, describe sky condition
|
| 965 |
if data['precip_chance'] <= 30:
|
|
@@ -1186,10 +1350,14 @@ def generate_advisories(events):
|
|
| 1186 |
if any(e.get('precipitation_type') == 'heavy_rain' for e in events):
|
| 1187 |
advisories.append("• **Heavy Rain:** Rainfall rates may exceed 5mm/h, leading to localized flooding")
|
| 1188 |
|
| 1189 |
-
if any(e.get('precipitation_type') == '
|
|
|
|
|
|
|
| 1190 |
advisories.append("• **Thunderstorm Watch:** Conditions favorable for thunderstorm development")
|
| 1191 |
|
| 1192 |
-
if any(e.get('precipitation_type') == '
|
|
|
|
|
|
|
| 1193 |
advisories.append("• **Winter Weather:** Snow accumulation possible, use caution when traveling")
|
| 1194 |
|
| 1195 |
if any(e.get('temperature_descriptor') == 'freezing' for e in events):
|
|
|
|
| 180 |
'v_10m': 'V-component of wind at 10m',
|
| 181 |
'pmsl': 'Pressure at mean sea level',
|
| 182 |
'tot_prec': 'Total precipitation',
|
| 183 |
+
'rain_con': 'Convective rain',
|
| 184 |
+
'rain_gsp': 'Grid-scale rain',
|
| 185 |
+
'snow_con': 'Convective snow',
|
| 186 |
+
'snow_gsp': 'Grid-scale snow',
|
| 187 |
+
'cape_con': 'Convective Available Potential Energy',
|
| 188 |
'clct': 'Total cloud cover',
|
| 189 |
'asob_s': 'Net shortwave radiation at surface',
|
| 190 |
+
'vmax_10m': 'Wind gusts at 10m',
|
| 191 |
+
'lpi_con': 'Lightning Potential Index'
|
| 192 |
}
|
| 193 |
|
| 194 |
# Download coordinate files first
|
|
|
|
| 401 |
wind_gust = []
|
| 402 |
pressure = []
|
| 403 |
precipitation = []
|
| 404 |
+
rain_convective = []
|
| 405 |
+
rain_gridscale = []
|
| 406 |
+
snow_convective = []
|
| 407 |
+
snow_gridscale = []
|
| 408 |
+
cape = []
|
| 409 |
+
lightning_potential = []
|
| 410 |
cloud_cover = []
|
| 411 |
solar_radiation = []
|
| 412 |
|
|
|
|
| 463 |
else:
|
| 464 |
precipitation.append(0.0)
|
| 465 |
|
| 466 |
+
# Convective rain (thunderstorm precipitation)
|
| 467 |
+
rain_con = data.get('rain_con', [None])[i] if 'rain_con' in data else None
|
| 468 |
+
if rain_con is not None:
|
| 469 |
+
if rain_con < 1: # kg/m²/s
|
| 470 |
+
rain_convective.append(rain_con * 3600) # Convert to mm/h
|
| 471 |
+
else:
|
| 472 |
+
rain_convective.append(rain_con)
|
| 473 |
+
else:
|
| 474 |
+
rain_convective.append(0.0)
|
| 475 |
+
|
| 476 |
+
# Grid-scale rain
|
| 477 |
+
rain_gsp = data.get('rain_gsp', [None])[i] if 'rain_gsp' in data else None
|
| 478 |
+
if rain_gsp is not None:
|
| 479 |
+
if rain_gsp < 1: # kg/m²/s
|
| 480 |
+
rain_gridscale.append(rain_gsp * 3600) # Convert to mm/h
|
| 481 |
+
else:
|
| 482 |
+
rain_gridscale.append(rain_gsp)
|
| 483 |
+
else:
|
| 484 |
+
rain_gridscale.append(0.0)
|
| 485 |
+
|
| 486 |
+
# Convective snow
|
| 487 |
+
snow_con = data.get('snow_con', [None])[i] if 'snow_con' in data else None
|
| 488 |
+
if snow_con is not None:
|
| 489 |
+
if snow_con < 1: # kg/m²/s
|
| 490 |
+
snow_convective.append(snow_con * 3600) # Convert to mm/h
|
| 491 |
+
else:
|
| 492 |
+
snow_convective.append(snow_con)
|
| 493 |
+
else:
|
| 494 |
+
snow_convective.append(0.0)
|
| 495 |
+
|
| 496 |
+
# Grid-scale snow
|
| 497 |
+
snow_gsp = data.get('snow_gsp', [None])[i] if 'snow_gsp' in data else None
|
| 498 |
+
if snow_gsp is not None:
|
| 499 |
+
if snow_gsp < 1: # kg/m²/s
|
| 500 |
+
snow_gridscale.append(snow_gsp * 3600) # Convert to mm/h
|
| 501 |
+
else:
|
| 502 |
+
snow_gridscale.append(snow_gsp)
|
| 503 |
+
else:
|
| 504 |
+
snow_gridscale.append(0.0)
|
| 505 |
+
|
| 506 |
+
# CAPE (Convective Available Potential Energy)
|
| 507 |
+
cape_con = data.get('cape_con', [None])[i] if 'cape_con' in data else None
|
| 508 |
+
if cape_con is not None:
|
| 509 |
+
cape.append(cape_con)
|
| 510 |
+
else:
|
| 511 |
+
cape.append(0.0)
|
| 512 |
+
|
| 513 |
+
# Lightning Potential Index
|
| 514 |
+
lpi_con = data.get('lpi_con', [None])[i] if 'lpi_con' in data else None
|
| 515 |
+
if lpi_con is not None:
|
| 516 |
+
lightning_potential.append(lpi_con)
|
| 517 |
+
else:
|
| 518 |
+
lightning_potential.append(0.0)
|
| 519 |
+
|
| 520 |
# Cloud cover (convert from fraction to percentage if needed)
|
| 521 |
clct = data['clct'][i]
|
| 522 |
if clct is not None:
|
|
|
|
| 543 |
'wind_gust': wind_gust,
|
| 544 |
'pressure': pressure,
|
| 545 |
'precipitation': precipitation,
|
| 546 |
+
'rain_convective': rain_convective,
|
| 547 |
+
'rain_gridscale': rain_gridscale,
|
| 548 |
+
'snow_convective': snow_convective,
|
| 549 |
+
'snow_gridscale': snow_gridscale,
|
| 550 |
+
'snow': [sc + sg for sc, sg in zip(snow_convective, snow_gridscale)], # Total snow
|
| 551 |
+
'cape': cape,
|
| 552 |
+
'lightning_potential': lightning_potential,
|
| 553 |
'cloud_cover': cloud_cover,
|
| 554 |
'solar_radiation': solar_radiation,
|
| 555 |
'lat': lat,
|
|
|
|
| 629 |
def analyze_weather_events(forecast_data):
|
| 630 |
"""
|
| 631 |
Analyze forecast data to identify significant weather events and timing
|
| 632 |
+
Enhanced with snow and thunderstorm detection using DWD ICON data
|
| 633 |
"""
|
| 634 |
timestamps = forecast_data['timestamps']
|
| 635 |
temperature = forecast_data['temperature']
|
|
|
|
| 640 |
cloud_cover = forecast_data.get('cloud_cover', [50] * len(timestamps))
|
| 641 |
pressure = forecast_data.get('pressure', [1013] * len(timestamps))
|
| 642 |
|
| 643 |
+
# New snow and thunderstorm variables
|
| 644 |
+
snow = forecast_data.get('snow', [0] * len(timestamps))
|
| 645 |
+
rain_convective = forecast_data.get('rain_convective', [0] * len(timestamps))
|
| 646 |
+
cape = forecast_data.get('cape', [0] * len(timestamps))
|
| 647 |
+
lightning_potential = forecast_data.get('lightning_potential', [0] * len(timestamps))
|
| 648 |
+
|
| 649 |
events = []
|
| 650 |
|
| 651 |
# Analyze each forecast period
|
|
|
|
| 669 |
'temperature_descriptor': None
|
| 670 |
}
|
| 671 |
|
| 672 |
+
# Enhanced precipitation analysis with snow and thunderstorm detection
|
| 673 |
+
snow_rate = snow[i] if i < len(snow) else 0
|
| 674 |
+
convective_rain = rain_convective[i] if i < len(rain_convective) else 0
|
| 675 |
+
cape_val = cape[i] if i < len(cape) else 0
|
| 676 |
+
lightning_idx = lightning_potential[i] if i < len(lightning_potential) else 0
|
| 677 |
+
|
| 678 |
+
# Snow detection
|
| 679 |
+
if snow_rate > 0.1: # mm/h snow
|
| 680 |
+
if snow_rate < 1.0:
|
| 681 |
+
event['precipitation_type'] = 'light_snow'
|
| 682 |
+
event['conditions'].append('light snow')
|
| 683 |
+
elif snow_rate < 3.0:
|
| 684 |
+
event['precipitation_type'] = 'snow'
|
| 685 |
+
event['conditions'].append('snow')
|
| 686 |
+
event['severity'] = 'moderate'
|
| 687 |
+
else:
|
| 688 |
+
event['precipitation_type'] = 'heavy_snow'
|
| 689 |
+
event['conditions'].append('heavy snow')
|
| 690 |
+
event['severity'] = 'significant'
|
| 691 |
+
|
| 692 |
+
# Thunderstorm detection using CAPE and convective precipitation
|
| 693 |
+
elif convective_rain > 0.5 or (cape_val > 1000 and precip > 1.0):
|
| 694 |
+
if cape_val > 2500 or lightning_idx > 0.5:
|
| 695 |
+
event['precipitation_type'] = 'severe_thunderstorms'
|
| 696 |
+
event['conditions'].append('severe thunderstorms')
|
| 697 |
+
event['severity'] = 'significant'
|
| 698 |
+
else:
|
| 699 |
+
event['precipitation_type'] = 'thunderstorms'
|
| 700 |
+
event['conditions'].append('thunderstorms')
|
| 701 |
+
event['severity'] = 'moderate'
|
| 702 |
+
|
| 703 |
+
# Regular rain analysis
|
| 704 |
+
elif precip > 0.1: # mm/h
|
| 705 |
if precip < 1.0:
|
| 706 |
event['precipitation_type'] = 'light_rain'
|
| 707 |
event['conditions'].append('light rain')
|
|
|
|
| 753 |
if rh > 95 and wind < 3:
|
| 754 |
event['conditions'].append('fog possible')
|
| 755 |
|
| 756 |
+
# Determine primary weather with enhanced snow and thunderstorm detection
|
| 757 |
if event['conditions']:
|
| 758 |
+
primary_condition = event['conditions'][0]
|
| 759 |
+
if 'severe thunderstorms' in primary_condition:
|
| 760 |
+
event['primary_weather'] = 'severe_thunderstorms'
|
| 761 |
+
elif 'thunderstorms' in primary_condition:
|
| 762 |
event['primary_weather'] = 'thunderstorms'
|
| 763 |
+
elif 'heavy_snow' in primary_condition:
|
| 764 |
+
event['primary_weather'] = 'heavy_snow'
|
| 765 |
+
elif 'snow' in primary_condition:
|
| 766 |
event['primary_weather'] = 'snow'
|
| 767 |
+
elif 'heavy_rain' in primary_condition:
|
| 768 |
+
event['primary_weather'] = 'heavy_rain'
|
| 769 |
+
elif 'rain' in primary_condition:
|
| 770 |
event['primary_weather'] = 'rain'
|
| 771 |
+
elif 'windy' in primary_condition or 'breezy' in primary_condition:
|
| 772 |
event['primary_weather'] = 'wind'
|
| 773 |
else:
|
| 774 |
+
event['primary_weather'] = primary_condition
|
| 775 |
|
| 776 |
events.append(event)
|
| 777 |
|
|
|
|
| 948 |
data['avg_clouds'] = sum(data['clouds']) / len(data['clouds']) if data['clouds'] else 50
|
| 949 |
data['max_wind'] = max(data['winds']) if data['winds'] else 5
|
| 950 |
|
| 951 |
+
# Precipitation analysis with type detection
|
| 952 |
data['precip_chance'] = calculate_precipitation_chance(data['precip'])
|
| 953 |
data['rain_timing'] = analyze_6hour_precipitation_timing(data['timestamps'], data['precip'], period_start, period_end)
|
| 954 |
+
data['precip_type'] = determine_precipitation_type(data, indices)
|
| 955 |
|
| 956 |
# Cloud cover description
|
| 957 |
data['sky_condition'] = get_sky_condition(data['avg_clouds'])
|
|
|
|
| 961 |
|
| 962 |
return data
|
| 963 |
|
| 964 |
+
def determine_precipitation_type(period_data, indices):
|
| 965 |
+
"""Determine the dominant precipitation type for a period"""
|
| 966 |
+
# This is a simplified version - in practice, we'd need access to
|
| 967 |
+
# snow and convective precipitation data for the specific indices
|
| 968 |
+
# For now, we'll use temperature as a proxy
|
| 969 |
+
temps = period_data['temps']
|
| 970 |
+
avg_temp = sum(temps) / len(temps) if temps else 15
|
| 971 |
+
|
| 972 |
+
# Simple temperature-based logic (would be enhanced with real snow/thunderstorm data)
|
| 973 |
+
if avg_temp < 2: # Near freezing
|
| 974 |
+
return 'snow'
|
| 975 |
+
elif avg_temp > 20: # Warm enough for thunderstorms
|
| 976 |
+
return 'thunderstorms'
|
| 977 |
+
else:
|
| 978 |
+
return 'rain'
|
| 979 |
+
|
| 980 |
def calculate_precipitation_chance(precip_data):
|
| 981 |
"""Calculate precipitation chance percentage"""
|
| 982 |
if not precip_data:
|
|
|
|
| 1076 |
return "very windy"
|
| 1077 |
|
| 1078 |
def generate_enhanced_period_narrative(period_name, data, is_day):
|
| 1079 |
+
"""Generate enhanced narrative with precipitation chances, timing, sky conditions, snow, and thunderstorms"""
|
| 1080 |
conditions = []
|
| 1081 |
|
| 1082 |
+
# Determine precipitation type from the period data
|
| 1083 |
+
precip_type = data.get('precip_type', 'rain') # Default to rain
|
| 1084 |
+
|
| 1085 |
+
# Sky condition and precipitation with enhanced types
|
| 1086 |
if data['precip_chance'] > 60:
|
| 1087 |
+
if precip_type == 'snow':
|
| 1088 |
+
if data['rain_timing']:
|
| 1089 |
+
conditions.append(f"snow likely, mainly {data['rain_timing']}")
|
| 1090 |
+
else:
|
| 1091 |
+
conditions.append("snow likely")
|
| 1092 |
+
elif precip_type == 'thunderstorms':
|
| 1093 |
+
if data['rain_timing']:
|
| 1094 |
+
conditions.append(f"thunderstorms likely, mainly {data['rain_timing']}")
|
| 1095 |
+
else:
|
| 1096 |
+
conditions.append("thunderstorms likely")
|
| 1097 |
else:
|
| 1098 |
+
if data['rain_timing']:
|
| 1099 |
+
conditions.append(f"rain likely, mainly {data['rain_timing']}")
|
| 1100 |
+
else:
|
| 1101 |
+
conditions.append("rain likely")
|
| 1102 |
conditions.append(f"Chance of precipitation {data['precip_chance']}%")
|
| 1103 |
elif data['precip_chance'] > 30:
|
| 1104 |
+
if precip_type == 'snow':
|
| 1105 |
+
if data['rain_timing']:
|
| 1106 |
+
conditions.append(f"chance of snow, mainly {data['rain_timing']}")
|
| 1107 |
+
else:
|
| 1108 |
+
conditions.append("chance of snow")
|
| 1109 |
+
elif precip_type == 'thunderstorms':
|
| 1110 |
+
if data['rain_timing']:
|
| 1111 |
+
conditions.append(f"chance of thunderstorms, mainly {data['rain_timing']}")
|
| 1112 |
+
else:
|
| 1113 |
+
conditions.append("chance of thunderstorms")
|
| 1114 |
else:
|
| 1115 |
+
if data['rain_timing']:
|
| 1116 |
+
conditions.append(f"chance of rain, mainly {data['rain_timing']}")
|
| 1117 |
+
else:
|
| 1118 |
+
conditions.append("chance of rain")
|
| 1119 |
conditions.append(f"Chance of precipitation {data['precip_chance']}%")
|
| 1120 |
elif data['precip_chance'] > 0:
|
| 1121 |
+
if precip_type == 'snow':
|
| 1122 |
+
conditions.append(f"slight chance of snow. Chance of precipitation {data['precip_chance']}%")
|
| 1123 |
+
elif precip_type == 'thunderstorms':
|
| 1124 |
+
conditions.append(f"slight chance of thunderstorms. Chance of precipitation {data['precip_chance']}%")
|
| 1125 |
+
else:
|
| 1126 |
+
conditions.append(f"slight chance of rain. Chance of precipitation {data['precip_chance']}%")
|
| 1127 |
|
| 1128 |
# If no significant precipitation, describe sky condition
|
| 1129 |
if data['precip_chance'] <= 30:
|
|
|
|
| 1350 |
if any(e.get('precipitation_type') == 'heavy_rain' for e in events):
|
| 1351 |
advisories.append("• **Heavy Rain:** Rainfall rates may exceed 5mm/h, leading to localized flooding")
|
| 1352 |
|
| 1353 |
+
if any(e.get('precipitation_type') == 'severe_thunderstorms' for e in events):
|
| 1354 |
+
advisories.append("• **Severe Thunderstorm Warning:** Dangerous thunderstorms with potential for damaging winds, large hail, and heavy rain")
|
| 1355 |
+
elif any(e.get('precipitation_type') == 'thunderstorms' for e in events):
|
| 1356 |
advisories.append("• **Thunderstorm Watch:** Conditions favorable for thunderstorm development")
|
| 1357 |
|
| 1358 |
+
if any(e.get('precipitation_type') == 'heavy_snow' for e in events):
|
| 1359 |
+
advisories.append("• **Heavy Snow Warning:** Significant snow accumulation expected, travel may become hazardous")
|
| 1360 |
+
elif any(e.get('precipitation_type') in ['snow', 'light_snow'] for e in events):
|
| 1361 |
advisories.append("• **Winter Weather:** Snow accumulation possible, use caution when traveling")
|
| 1362 |
|
| 1363 |
if any(e.get('temperature_descriptor') == 'freezing' for e in events):
|