aboutsummaryrefslogtreecommitdiffstats
path: root/app/utils
diff options
context:
space:
mode:
authorMitsuo Tokumori <[email protected]>2025-03-08 16:03:30 +0900
committerMitsuo Tokumori <[email protected]>2025-03-08 16:03:30 +0900
commit51163b167cce01af6101438e5e61145ad798f213 (patch)
tree9c8e75266cedfb205db175b0b2bc41b49df75cea /app/utils
parentd9af103b9a8aed86d6ac834f1240edfb2173ffa0 (diff)
downloadmasu-51163b167cce01af6101438e5e61145ad798f213.tar.gz
masu-51163b167cce01af6101438e5e61145ad798f213.tar.bz2
masu-51163b167cce01af6101438e5e61145ad798f213.zip
Restructure python code to be modular
The python code is now a package named app. app/models: db models app/routes: flask blueprints app/static: css, js app/templates: jinja html templates
Diffstat (limited to 'app/utils')
-rw-r--r--app/utils/block_weather.py66
1 files changed, 66 insertions, 0 deletions
diff --git a/app/utils/block_weather.py b/app/utils/block_weather.py
new file mode 100644
index 0000000..eec4e4a
--- /dev/null
+++ b/app/utils/block_weather.py
@@ -0,0 +1,66 @@
+"""
+Handle external requests and pre-process weather data
+
+Providers:
+* OpenWeather
+ Free Access on OpenWeather allows for some API calls, see
+ https://openweathermap.org/price
+"""
+
+import flask
+import requests
+import pandas as pd
+
+def get_current_weather(city: str) -> dict:
+ """https://openweathermap.org/current"""
+ pos = _get_position(city)
+ if not pos:
+ return None
+ url = f"http://api.openweathermap.org/data/2.5/weather?lat={pos['lat']}&lon={pos['lon']}&appid={flask.current_app.config['OPENWEATHER_API_KEY']}&units=metric"
+ data = requests.get(url).json()
+
+ data['summary'] = _format_current_weather(data)
+ # On icon URL codes: https://openweathermap.org/weather-conditions#Weather-Condition-Codes-2
+ data['icon_url'] = f"https://openweathermap.org/img/wn/{data['weather'][0]['icon']}.png"
+ return data
+
+
+def _format_current_weather(data: dict) -> str:
+ """final formatting should occur in HTML/JS, not here"""
+ ts = [data['dt'], data['sys']['sunrise'], data['sys']['sunset']]
+ ts = [pd.to_datetime(x + data['timezone'], unit='s') for x in ts]
+ s = f"""{data['name']}, {data['sys']['country']} ({ts[0]})
+{data['weather'][0]['description']}
+{data['main']['temp']}°C (feels like {data['main']['feels_like']}°C), humidity: {data['main']['humidity']}%, pressure: {data['main']['grnd_level']} hPa
+visibility: {data.get('visibility', 0)/1000:.1f}km
+wind: {data['wind']['speed']}m/s from {data['wind']['deg']}°N
+clouds: {data['clouds']['all']}%
+sunrise & sunset: {ts[1].strftime('%H:%M')}, {ts[2].strftime('%H:%M')}"""
+ return s
+
+
+def get_forecast(city: str) -> dict:
+ """https://openweathermap.org/forecast5"""
+ # 5 days, 3 hours forecast data
+ lat, lon = _get_position(city)
+ url = f"http://api.openweathermap.org/data/2.5/forecast?lat={lat}&lon={lon}&appid={flask.current_app.config['OPENWEATHER_API_KEY']}&units=metric"
+ data = requests.get(url).json()
+ return data
+
+
+def _get_position(name) -> dict:
+ """direct geocoding
+ name: City name, state code (only for the US) and country code divided by comma. Please use ISO 3166 country codes.
+
+ https://openweathermap.org/api/geocoding-api#direct
+ """
+ limit = 5
+ url = f"http://api.openweathermap.org/geo/1.0/direct?q={name}&limit={limit}&appid={flask.current_app.config['OPENWEATHER_API_KEY']}"
+ data = requests.get(url).json()
+ if not data:
+ return None
+ return data[0]
+
+
+def get_weathermap() -> dict:
+ """https://openweathermap.org/api/weathermaps"""