hkopenai.hk-climate-mcp-server 0.3.0__py3-none-any.whl → 0.4.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.
@@ -1,43 +1,6 @@
1
1
  """Hong Kong climate MCP Server package."""
2
- from .app import main
3
- from .tool_weather import (
4
- get_current_weather,
5
- get_9_day_weather_forecast,
6
- get_local_weather_forecast,
7
- get_weather_warning_summary,
8
- get_weather_warning_info,
9
- get_special_weather_tips,
10
- get_visibility_data,
11
- get_lightning_data,
12
- get_moon_times,
13
- get_hourly_tides,
14
- get_high_low_tides,
15
- get_sunrise_sunset_times,
16
- get_gregorian_lunar_calendar,
17
- get_daily_mean_temperature,
18
- get_daily_max_temperature,
19
- get_daily_min_temperature,
20
- get_weather_radiation_report
21
- )
2
+ from .server import main
3
+
22
4
 
23
5
  __version__ = "0.1.0"
24
- __all__ = [
25
- 'main',
26
- 'get_current_weather',
27
- 'get_9_day_weather_forecast',
28
- 'get_local_weather_forecast',
29
- 'get_weather_warning_summary',
30
- 'get_weather_warning_info',
31
- 'get_special_weather_tips',
32
- 'get_visibility_data',
33
- 'get_lightning_data',
34
- 'get_moon_times',
35
- 'get_hourly_tides',
36
- 'get_high_low_tides',
37
- 'get_sunrise_sunset_times',
38
- 'get_gregorian_lunar_calendar',
39
- 'get_daily_mean_temperature',
40
- 'get_daily_max_temperature',
41
- 'get_daily_min_temperature',
42
- 'get_weather_radiation_report'
43
- ]
6
+ __all__ = ['main']
@@ -1,4 +1,4 @@
1
- from hkopenai.hk_climate_mcp_server.app import main
1
+ from hkopenai.hk_climate_mcp_server.server import main
2
2
 
3
3
  if __name__ == "__main__":
4
4
  main()
@@ -1,8 +1,16 @@
1
1
  import argparse
2
2
  from fastmcp import FastMCP
3
- from hkopenai.hk_climate_mcp_server import tool_weather
4
3
  from typing import Dict, Annotated, Optional
5
4
  from pydantic import Field
5
+ from hkopenai.hk_climate_mcp_server.tools import astronomical
6
+ from hkopenai.hk_climate_mcp_server.tools import current_weather
7
+ from hkopenai.hk_climate_mcp_server.tools import forecast
8
+ from hkopenai.hk_climate_mcp_server.tools import lightning
9
+ from hkopenai.hk_climate_mcp_server.tools import radiation
10
+ from hkopenai.hk_climate_mcp_server.tools import temperature
11
+ from hkopenai.hk_climate_mcp_server.tools import tides
12
+ from hkopenai.hk_climate_mcp_server.tools import visibility
13
+ from hkopenai.hk_climate_mcp_server.tools import warnings
6
14
 
7
15
  def create_mcp_server():
8
16
  """Create and configure the HKO MCP server"""
@@ -12,49 +20,49 @@ def create_mcp_server():
12
20
  description="Get current weather observations, warnings, temperature, humidity and rainfall in Hong Kong from Hong Kong Observatory, with optional region or place in Hong Kong",
13
21
  )
14
22
  def get_current_weather(region: str = "Hong Kong Observatory") -> Dict:
15
- return tool_weather.get_current_weather(region)
23
+ return current_weather.get_current_weather(region)
16
24
 
17
25
  @mcp.tool(
18
26
  description="Get the 9-day weather forecast for Hong Kong including general situation, daily forecasts, sea and soil temperatures",
19
27
  )
20
28
  def get_9_day_weather_forecast(lang: str = "en") -> Dict:
21
- return tool_weather.get_9_day_weather_forecast(lang)
29
+ return forecast.get_9_day_weather_forecast(lang)
22
30
 
23
31
  @mcp.tool(
24
32
  description="Get local weather forecast for Hong Kong including forecast description, outlook and update time",
25
33
  )
26
34
  def get_local_weather_forecast(lang: str = "en") -> Dict:
27
- return tool_weather.get_local_weather_forecast(lang)
35
+ return forecast.get_local_weather_forecast(lang)
28
36
 
29
37
  @mcp.tool(
30
38
  description="Get weather warning summary for Hong Kong including warning messages and update time",
31
39
  )
32
40
  def get_weather_warning_summary(lang: str = "en") -> Dict:
33
- return tool_weather.get_weather_warning_summary(lang)
41
+ return warnings.get_weather_warning_summary(lang)
34
42
 
35
43
  @mcp.tool(
36
44
  description="Get detailed weather warning information for Hong Kong including warning statement and update time",
37
45
  )
38
46
  def get_weather_warning_info(lang: str = "en") -> Dict:
39
- return tool_weather.get_weather_warning_info(lang)
47
+ return warnings.get_weather_warning_info(lang)
40
48
 
41
49
  @mcp.tool(
42
50
  description="Get special weather tips for Hong Kong including tips list and update time",
43
51
  )
44
52
  def get_special_weather_tips(lang: str = "en") -> Dict:
45
- return tool_weather.get_special_weather_tips(lang)
53
+ return warnings.get_special_weather_tips(lang)
46
54
 
47
55
  @mcp.tool(
48
56
  description="Get latest 10-minute mean visibility data for Hong Kong",
49
57
  )
50
- def get_visibility_data(lang: str = "en", rformat: str = "json") -> Dict:
51
- return tool_weather.get_visibility_data(lang, rformat)
58
+ def get_visibility_data(lang: str = "en") -> Dict:
59
+ return visibility.get_visibility_data(lang)
52
60
 
53
61
  @mcp.tool(
54
62
  description="Get cloud-to-ground and cloud-to-cloud lightning count data",
55
63
  )
56
- def get_lightning_data(lang: str = "en", rformat: str = "json") -> Dict:
57
- return tool_weather.get_lightning_data(lang, rformat)
64
+ def get_lightning_data(lang: str = "en") -> Dict:
65
+ return lightning.get_lightning_data(lang)
58
66
 
59
67
  @mcp.tool(
60
68
  description="Get times of moonrise, moon transit and moonset",
@@ -63,15 +71,13 @@ def create_mcp_server():
63
71
  year: int,
64
72
  month: Optional[int] = None,
65
73
  day: Optional[int] = None,
66
- lang: str = "en",
67
- rformat: str = "json"
74
+ lang: str = "en"
68
75
  ) -> Dict:
69
- return tool_weather.get_moon_times(
76
+ return astronomical.get_moon_times(
70
77
  year=year,
71
78
  month=month,
72
79
  day=day,
73
- lang=lang,
74
- rformat=rformat
80
+ lang=lang
75
81
  )
76
82
 
77
83
  @mcp.tool(
@@ -83,17 +89,15 @@ def create_mcp_server():
83
89
  month: Optional[int] = None,
84
90
  day: Optional[int] = None,
85
91
  hour: Optional[int] = None,
86
- lang: str = "en",
87
- rformat: str = "json"
92
+ lang: str = "en"
88
93
  ) -> Dict:
89
- return tool_weather.get_hourly_tides(
94
+ return tides.get_hourly_tides(
90
95
  station=station,
91
96
  year=year,
92
97
  month=month,
93
98
  day=day,
94
99
  hour=hour,
95
- lang=lang,
96
- rformat=rformat
100
+ lang=lang
97
101
  )
98
102
 
99
103
  @mcp.tool(
@@ -105,19 +109,23 @@ def create_mcp_server():
105
109
  month: Optional[int] = None,
106
110
  day: Optional[int] = None,
107
111
  hour: Optional[int] = None,
108
- lang: str = "en",
109
- rformat: str = "json"
112
+ lang: str = "en"
110
113
  ) -> Dict:
111
- return tool_weather.get_high_low_tides(
114
+ return tides.get_high_low_tides(
112
115
  station=station,
113
116
  year=year,
114
117
  month=month,
115
118
  day=day,
116
119
  hour=hour,
117
- lang=lang,
118
- rformat=rformat
120
+ lang=lang
119
121
  )
120
122
 
123
+ @mcp.tool(
124
+ description="Get a list of tide station codes and their corresponding names for tide reports in Hong Kong.",
125
+ )
126
+ def get_tide_station_codes(lang: str = "en") -> Dict:
127
+ return tides.get_tide_station_codes(lang)
128
+
121
129
  @mcp.tool(
122
130
  description="Get times of sunrise, sun transit and sunset for Hong Kong",
123
131
  )
@@ -125,15 +133,13 @@ def create_mcp_server():
125
133
  year: int,
126
134
  month: Optional[int] = None,
127
135
  day: Optional[int] = None,
128
- lang: str = "en",
129
- rformat: str = "json"
136
+ lang: str = "en"
130
137
  ) -> Dict:
131
- return tool_weather.get_sunrise_sunset_times(
138
+ return astronomical.get_sunrise_sunset_times(
132
139
  year=year,
133
140
  month=month,
134
141
  day=day,
135
- lang=lang,
136
- rformat=rformat
142
+ lang=lang
137
143
  )
138
144
 
139
145
  @mcp.tool(
@@ -143,15 +149,13 @@ def create_mcp_server():
143
149
  year: int,
144
150
  month: Optional[int] = None,
145
151
  day: Optional[int] = None,
146
- lang: str = "en",
147
- rformat: str = "json"
152
+ lang: str = "en"
148
153
  ) -> Dict:
149
- return tool_weather.get_gregorian_lunar_calendar(
154
+ return astronomical.get_gregorian_lunar_calendar(
150
155
  year=year,
151
156
  month=month,
152
157
  day=day,
153
- lang=lang,
154
- rformat=rformat
158
+ lang=lang
155
159
  )
156
160
 
157
161
  @mcp.tool(
@@ -161,15 +165,13 @@ def create_mcp_server():
161
165
  station: str,
162
166
  year: Optional[int] = None,
163
167
  month: Optional[int] = None,
164
- lang: str = "en",
165
- rformat: str = "json"
168
+ lang: str = "en"
166
169
  ) -> Dict:
167
- return tool_weather.get_daily_mean_temperature(
170
+ return temperature.get_daily_mean_temperature(
168
171
  station=station,
169
172
  year=year,
170
173
  month=month,
171
- lang=lang,
172
- rformat=rformat
174
+ lang=lang
173
175
  )
174
176
 
175
177
  @mcp.tool(
@@ -179,15 +181,13 @@ def create_mcp_server():
179
181
  station: str,
180
182
  year: Optional[int] = None,
181
183
  month: Optional[int] = None,
182
- lang: str = "en",
183
- rformat: str = "json"
184
+ lang: str = "en"
184
185
  ) -> Dict:
185
- return tool_weather.get_daily_max_temperature(
186
+ return temperature.get_daily_max_temperature(
186
187
  station=station,
187
188
  year=year,
188
189
  month=month,
189
- lang=lang,
190
- rformat=rformat
190
+ lang=lang
191
191
  )
192
192
 
193
193
  @mcp.tool(
@@ -197,32 +197,34 @@ def create_mcp_server():
197
197
  station: str,
198
198
  year: Optional[int] = None,
199
199
  month: Optional[int] = None,
200
- lang: str = "en",
201
- rformat: str = "json"
200
+ lang: str = "en"
202
201
  ) -> Dict:
203
- return tool_weather.get_daily_min_temperature(
202
+ return temperature.get_daily_min_temperature(
204
203
  station=station,
205
204
  year=year,
206
205
  month=month,
207
- lang=lang,
208
- rformat=rformat
206
+ lang=lang
209
207
  )
210
208
 
211
209
  @mcp.tool(
212
- description="Get weather and radiation level report for Hong Kong",
210
+ description="Get weather and radiation level report for Hong Kong. Date must be in YYYYMMDD format and should be yesterday or before. Station must be a valid code like 'HKO' for Hong Kong Observatory.",
213
211
  )
214
212
  def get_weather_radiation_report(
215
- date: Optional[str] = None,
216
- station: Optional[str] = None,
217
- lang: str = "en",
218
- rformat: str = "json"
213
+ date: Annotated[str, Field(description="Date in yyyyMMdd format, eg, 20250618")],
214
+ station: Annotated[str, Field(description="Station code in 3 characters in capital letters, eg, HKO")],
215
+ lang: Annotated[Optional[str], Field(description="Language (en/tc/sc)", json_schema_extra={"enum": ["en", "tc", "sc"]})] = 'en',
219
216
  ) -> Dict:
220
- return tool_weather.get_weather_radiation_report(
217
+ return radiation.get_weather_radiation_report(
221
218
  date=date,
222
219
  station=station,
223
- lang=lang,
224
- rformat=rformat
220
+ lang=lang or 'en'
225
221
  )
222
+
223
+ @mcp.tool(
224
+ description="Get a list of weather station codes and their corresponding names for radiation reports in Hong Kong.",
225
+ )
226
+ def get_radiation_station_codes(lang: str = "en") -> Dict:
227
+ return radiation.get_radiation_station_codes(lang)
226
228
 
227
229
  return mcp
228
230
 
@@ -0,0 +1,109 @@
1
+ import requests
2
+ from typing import Dict, Any, Optional
3
+
4
+ def get_moon_times(year: int, month: Optional[int] = None,
5
+ day: Optional[int] = None, lang: str = "en") -> Dict[str, Any]:
6
+ """
7
+ Get times of moonrise, moon transit and moonset.
8
+
9
+ Args:
10
+ year: Year (2018-2024)
11
+ month: Optional month (1-12)
12
+ day: Optional day (1-31)
13
+ lang: Language code (en/tc/sc, default: en)
14
+
15
+ Returns:
16
+ Dict containing moon times data with fields and data arrays
17
+ """
18
+ params = {
19
+ 'dataType': 'MRS',
20
+ 'lang': lang,
21
+ 'rformat': 'json',
22
+ 'year': year
23
+ }
24
+ if month: params['month'] = str(month)
25
+ if day: params['day'] = str(day)
26
+
27
+ response = requests.get(
28
+ 'https://data.weather.gov.hk/weatherAPI/opendata/opendata.php',
29
+ params=params
30
+ )
31
+ try:
32
+ response.raise_for_status()
33
+ return response.json()
34
+ except (requests.RequestException, ValueError) as e:
35
+ return {"error": f"Failed to fetch data: {str(e)}."}
36
+
37
+ def get_sunrise_sunset_times(
38
+ year: int,
39
+ month: Optional[int] = None,
40
+ day: Optional[int] = None,
41
+ lang: str = "en"
42
+ ) -> Dict[str, Any]:
43
+ """
44
+ Get times of sunrise, sun transit and sunset.
45
+
46
+ Args:
47
+ year: Year (2018-2024)
48
+ month: Optional month (1-12)
49
+ day: Optional day (1-31)
50
+ lang: Language code (en/tc/sc, default: en)
51
+
52
+ Returns:
53
+ Dict containing sun times data with fields and data arrays
54
+ """
55
+ params = {
56
+ 'dataType': 'SRS',
57
+ 'lang': lang,
58
+ 'rformat': 'json',
59
+ 'year': year
60
+ }
61
+ if month: params['month'] = str(month)
62
+ if day: params['day'] = str(day)
63
+
64
+ response = requests.get(
65
+ 'https://data.weather.gov.hk/weatherAPI/opendata/opendata.php',
66
+ params=params
67
+ )
68
+ try:
69
+ response.raise_for_status()
70
+ return response.json()
71
+ except (requests.RequestException, ValueError) as e:
72
+ return {"error": f"Failed to fetch data: {str(e)}."}
73
+
74
+ def get_gregorian_lunar_calendar(
75
+ year: int,
76
+ month: Optional[int] = None,
77
+ day: Optional[int] = None,
78
+ lang: str = "en"
79
+ ) -> Dict[str, Any]:
80
+ """
81
+ Get Gregorian-Lunar calendar conversion data.
82
+
83
+ Args:
84
+ year: Year (1901-2100)
85
+ month: Optional month (1-12)
86
+ day: Optional day (1-31)
87
+ lang: Language code (en/tc/sc, default: en)
88
+
89
+ Returns:
90
+ Dict containing calendar conversion data
91
+ """
92
+ params = {
93
+ 'dataType': 'GLC',
94
+ 'lang': lang,
95
+ 'rformat': 'json',
96
+ 'year': year
97
+ }
98
+ if month: params['month'] = str(month)
99
+ if day: params['day'] = str(day)
100
+
101
+ response = requests.get(
102
+ 'https://data.weather.gov.hk/weatherAPI/opendata/opendata.php',
103
+ params=params
104
+ )
105
+ try:
106
+ response.raise_for_status()
107
+ return response.json()
108
+ except (requests.RequestException, ValueError) as e:
109
+ return {"error": f"Failed to fetch data: {str(e)}."}
@@ -0,0 +1,106 @@
1
+ import requests
2
+ from typing import Dict
3
+
4
+ def get_current_weather(region: str = "Hong Kong Observatory", lang: str = "en") -> Dict:
5
+ """
6
+ Get current weather observations for a specific region in Hong Kong
7
+
8
+ Args:
9
+ region: The region to get weather for (default: "Hong Kong Observatory")
10
+ lang: Language code (en/tc/sc, default: en)
11
+
12
+ Returns:
13
+ Dict containing:
14
+ - warning: Current weather warnings
15
+ - temperature: Current temperature in Celsius
16
+ - humidity: Current humidity percentage
17
+ - rainfall: Current rainfall in mm
18
+ """
19
+ response = requests.get(
20
+ f"https://data.weather.gov.hk/weatherAPI/opendata/weather.php?dataType=rhrread&lang={lang}"
21
+ )
22
+ data = response.json()
23
+
24
+ # Handle warnings
25
+ warning = "No warning in force"
26
+ if "warningMessage" in data:
27
+ if isinstance(data["warningMessage"], list) and data["warningMessage"]:
28
+ warning = data["warningMessage"][0]
29
+ elif data["warningMessage"]: # Handle string case
30
+ warning = data["warningMessage"]
31
+
32
+ # Get default values from HKO data
33
+ default_temp = next(
34
+ (
35
+ t
36
+ for t in data.get("temperature", {}).get("data", [])
37
+ if t.get("place") == "Hong Kong Observatory"
38
+ ),
39
+ {"value": 25, "unit": "C", "recordTime": ""},
40
+ )
41
+ default_humidity = next(
42
+ (
43
+ h
44
+ for h in data.get("humidity", {}).get("data", [])
45
+ if h.get("place") == "Hong Kong Observatory"
46
+ ),
47
+ {"value": 60, "unit": "percent", "recordTime": ""},
48
+ )
49
+ # Find matching region temperature
50
+ temp_data = data.get("temperature", {}).get("data", [])
51
+ matched_temp = next(
52
+ (t for t in temp_data if t["place"].lower() == region.lower()),
53
+ {
54
+ "place": "Hong Kong Observatory",
55
+ "value": default_temp["value"],
56
+ "unit": default_temp["unit"],
57
+ },
58
+ )
59
+ matched_temp["recordTime"] = data["temperature"]["recordTime"]
60
+
61
+ # Get humidity
62
+ humidity = next(
63
+ (
64
+ h
65
+ for h in data.get("humidity", {}).get("data", [])
66
+ if h.get("place") == matched_temp["place"]
67
+ ),
68
+ default_humidity,
69
+ )
70
+ humidity["recordTime"] = data["humidity"]["recordTime"]
71
+
72
+ # Get rainfall (0 if no rain)
73
+ rainfall = 0
74
+ if "rainfall" in data:
75
+ rainfall = max(float(r.get("max", 0)) for r in data["rainfall"]["data"])
76
+ rainfall_start = data["rainfall"]["startTime"]
77
+ rainfall_end = data["rainfall"]["endTime"]
78
+
79
+ return {
80
+ "generalSituation": warning,
81
+ "weatherObservation": {
82
+ "temperature": {
83
+ "value": matched_temp["value"],
84
+ "unit": matched_temp["unit"],
85
+ "recordTime": matched_temp["recordTime"],
86
+ "place": matched_temp["place"]
87
+ },
88
+ "humidity": {
89
+ "value": humidity["value"],
90
+ "unit": humidity["unit"],
91
+ "recordTime": humidity["recordTime"],
92
+ "place": matched_temp["place"]
93
+ },
94
+ "rainfall": {
95
+ "value": rainfall,
96
+ "min": min(float(r.get("min", 0)) for r in data["rainfall"]["data"]),
97
+ "unit": "mm",
98
+ "startTime": rainfall_start,
99
+ "endTime": rainfall_end
100
+ },
101
+ "uvindex": data.get("uvindex", {})
102
+ },
103
+ "updateTime": data["updateTime"],
104
+ "icon": data.get("icon", []),
105
+ "iconUpdateTime": data.get("iconUpdateTime", "")
106
+ }
@@ -0,0 +1,82 @@
1
+ import requests
2
+ from typing import Dict, Any
3
+
4
+ def get_9_day_weather_forecast(lang: str = "en") -> Dict[str, Any]:
5
+ """
6
+ Get the 9-day weather forecast for Hong Kong.
7
+
8
+ Args:
9
+ lang: Language code (en/tc/sc, default: en)
10
+
11
+ Returns:
12
+ Dict containing:
13
+ - generalSituation: General weather situation
14
+ - weatherForecast: List of daily forecast dicts (date, week, wind, weather, temp/humidity, etc.)
15
+ - updateTime: Last update time
16
+ - seaTemp: Sea temperature info
17
+ - soilTemp: List of soil temperature info
18
+ """
19
+ url = f"https://data.weather.gov.hk/weatherAPI/opendata/weather.php?dataType=fnd&lang={lang}"
20
+ response = requests.get(url)
21
+ try:
22
+ response.raise_for_status()
23
+ data = response.json()
24
+ except (requests.RequestException, ValueError) as e:
25
+ return {"error": f"Failed to fetch data: {str(e)}."}
26
+
27
+ # Structure the output
28
+ forecast = {
29
+ "generalSituation": data.get("generalSituation", ""),
30
+ "weatherForecast": [],
31
+ "updateTime": data.get("updateTime", ""),
32
+ "seaTemp": data.get("seaTemp", {}),
33
+ "soilTemp": data.get("soilTemp", []),
34
+ }
35
+
36
+ # Extract 9-day forecast
37
+ for day in data.get("weatherForecast", []):
38
+ forecast["weatherForecast"].append({
39
+ "forecastDate": day.get("forecastDate", ""),
40
+ "week": day.get("week", ""),
41
+ "forecastWind": day.get("forecastWind", ""),
42
+ "forecastWeather": day.get("forecastWeather", ""),
43
+ "forecastMaxtemp": day.get("forecastMaxtemp", {}),
44
+ "forecastMintemp": day.get("forecastMintemp", {}),
45
+ "forecastMaxrh": day.get("forecastMaxrh", {}),
46
+ "forecastMinrh": day.get("forecastMinrh", {}),
47
+ "ForecastIcon": day.get("ForecastIcon", ""),
48
+ "PSR": day.get("PSR", ""),
49
+ })
50
+ return forecast
51
+
52
+ def get_local_weather_forecast(lang: str = "en") -> Dict[str, Any]:
53
+ """
54
+ Get local weather forecast for Hong Kong.
55
+
56
+ Args:
57
+ lang: Language code (en/tc/sc, default: en)
58
+
59
+ Returns:
60
+ Dict containing:
61
+ - forecastDesc: Forecast description
62
+ - outlook: Outlook forecast
63
+ - updateTime: Last update time
64
+ - forecastPeriod: Forecast period
65
+ - forecastDate: Forecast date
66
+ """
67
+ url = f"https://data.weather.gov.hk/weatherAPI/opendata/weather.php?dataType=flw&lang={lang}"
68
+ response = requests.get(url)
69
+ try:
70
+ response.raise_for_status()
71
+ data = response.json()
72
+ except (requests.RequestException, ValueError) as e:
73
+ return {"error": f"Failed to fetch data: {str(e)}."}
74
+
75
+ return {
76
+ "generalSituation": data.get("generalSituation", ""),
77
+ "forecastDesc": data.get("forecastDesc", ""),
78
+ "outlook": data.get("outlook", ""),
79
+ "updateTime": data.get("updateTime", ""),
80
+ "forecastPeriod": data.get("forecastPeriod", ""),
81
+ "forecastDate": data.get("forecastDate", ""),
82
+ }
@@ -0,0 +1,20 @@
1
+ import requests
2
+ from typing import Dict, Any
3
+
4
+ def get_lightning_data(lang: str = "en") -> Dict[str, Any]:
5
+ """
6
+ Get cloud-to-ground and cloud-to-cloud lightning count data.
7
+
8
+ Args:
9
+ lang: Language code (en/tc/sc, default: en)
10
+
11
+ Returns:
12
+ Dict containing lightning data with fields and data arrays
13
+ """
14
+ url = f"https://data.weather.gov.hk/weatherAPI/opendata/opendata.php?dataType=LHL&lang={lang}&rformat=json"
15
+ response = requests.get(url)
16
+ try:
17
+ response.raise_for_status()
18
+ return response.json()
19
+ except (requests.RequestException, ValueError) as e:
20
+ return {"error": f"Failed to fetch data: {str(e)}."}