現在の天気が雨でない場合に次の1時間の天気予報をチェックするように変更
# weather_check.py import location_utils2 import requests def get_weather_data(api_key, latitude, longitude): # OpenWeather One Call API の URL url = f"https://api.openweathermap.org/data/3.0/onecall?lat={latitude}&lon={longitude}&exclude=minutely,daily&appid={api_key}&units=metric" response = requests.get(url) return response.json() def check_for_rain(weather_data): hourly_forecast = weather_data.get('hourly', [])[:1] # 次の1時間の予報だけをチェック for hour in hourly_forecast: for weather in hour['weather']: if weather['main'] == 'Rain': return True return False # APIキーを設定 api_key = 'APIキー' # location_utils2から緯度と経度と天気をを取得 latitude, longitude, _ , weather_description = location_utils2.get_current_location_and_address() # 天気データを取得 weather_data = get_weather_data(api_key, latitude, longitude) # 雨が予報されているかどうかをチェック if check_for_rain(weather_data): print("Alert: Rain is expected within the next hour!") else: print("No rain expected in the next hour.")
のコードだと
雨が降っていても一時間後に雨なのかを調べてしまう
なので現在地の天気が雨でないのなら実行するようにする
なおこの判定は
# location_utils2.py import requests from geopy.geocoders import Nominatim def get_current_location_and_address(): # APIキーとZIPコードは予め設定しておく必要があります。 API_key = "APIキー" zip_place = "郵便番号,JP" # OpenWeatherMap API URL url = f"https://api.openweathermap.org/data/2.5/weather?zip={zip_place}&units=metric&lang=ja&appid={API_key}" # データの取得 response = requests.get(url) jsondata = response.json() # 緯度と経度の取得 latitude = jsondata['coord']['lat'] longitude = jsondata['coord']['lon'] #天気の取得 # weather_description = jsondata['weather'][0]['description'] weather_description = jsondata['weather'][0]['main'] # 住所の取得(オプショナル) geolocator = Nominatim(user_agent="geoapiExercises") location = geolocator.reverse((latitude, longitude), language='ja') address = location.address if location else None return latitude, longitude, address, weather_description
で郵便番号をもとに
現在地の緯度経度と天気を取得している
この時に
Mainだと英語で取得になるが
Descriptionだと日本語で詳細の天気になる
ただ詳細な天気だと小雨とか判定が面倒なので
とにかく雨であれば
main==rainの判定にできるので
Mainを判定基準にした
変更後のコードは
import location_utils2 import requests def get_weather_data(api_key, latitude, longitude): url = f"https://api.openweathermap.org/data/3.0/onecall?lat={latitude}&lon={longitude}&exclude=minutely,daily&appid={api_key}&units=metric" response = requests.get(url) return response.json() def check_for_rain(weather_data): hourly_forecast = weather_data.get('hourly', [])[:1] for hour in hourly_forecast: for weather in hour['weather']: if weather['main'] == 'Rain': return True return False api_key = 'APIキー' latitude, longitude, _, weather_description = location_utils2.get_current_location_and_address() # 現在の天気が雨でない場合にのみ次の1時間の雨の予報をチェック if weather_description != 'Rain': weather_data = get_weather_data(api_key, latitude, longitude) if check_for_rain(weather_data): print("Alert: Rain is expected within the next hour!") else: print("No rain expected in the next hour.") else: print("It is currently raining.")
次に音声を流れるように変更
今回も音声再生はpygameを使う
pygameライブラリを使って音声ファイルを再生しています。まず、pygame.mixerを初期化し、音声ファイルを読み込んで再生します。pygame.mixer.music.play()関数で音声を再生し、while pygame.mixer.music.get_busy()ループを使って音声が再生されている間は待機します。このスクリプトは、雨が予報されていない場合にのみ、次の1時間の雨の予報をチェックし、予報されていた場合に指定された音声ファイルを再生します
コードは
import location_utils2 import requests import pygame # Import pygame for audio playback def get_weather_data(api_key, latitude, longitude): url = f"https://api.openweathermap.org/data/3.0/onecall?lat={latitude}&lon={longitude}&exclude=minutely,daily&appid={api_key}&units=metric" response = requests.get(url) return response.json() def check_for_rain(weather_data): hourly_forecast = weather_data.get('hourly', [])[:1] for hour in hourly_forecast: for weather in hour['weather']: if weather['main'] == 'Rain': return True return False api_key = 'APIキー' latitude, longitude, _, weather_description = location_utils2.get_current_location_and_address() # 現在の天気が雨でない場合にのみ次の1時間の雨の予報をチェック if weather_description != 'Rain': weather_data = get_weather_data(api_key, latitude, longitude) if check_for_rain(weather_data): print("Alert: Rain is expected within the next hour!") pygame.mixer.init() # Initialize the mixer module pygame.mixer.music.load('voice.wav') # Load your sound file pygame.mixer.music.play() # Play the sound while pygame.mixer.music.get_busy(): # Wait for music to finish playing pygame.time.Clock().tick(10) else: print("No rain expected in the next hour.") else: print("It is currently raining.")
でOK
音声の部分は
python create_voice.py voice.txt 192.168.1.69:50021
で作成した音声を使用
次は顔認識したら実行するようにする
以前の
Weatheer や mail_voice などで使ったkao.pyとxmlファイルを使えばできるはず
ということでモジュール化する
weather_alert.py
として
# weather_alert.py import location_utils2 import requests import pygame def get_weather_data(api_key, latitude, longitude): url = f"https://api.openweathermap.org/data/3.0/onecall?lat={latitude}&lon={longitude}&exclude=minutely,daily&appid={api_key}&units=metric" response = requests.get(url) return response.json() def check_for_rain(weather_data): hourly_forecast = weather_data.get('hourly', [])[:1] for hour in hourly_forecast: for weather in hour['weather']: if weather['main'] == 'Rain': return True return False def check_and_alert(api_key): latitude, longitude, _, weather_description = location_utils2.get_current_location_and_address() if weather_description != 'Rain': weather_data = get_weather_data(api_key, latitude, longitude) if check_for_rain(weather_data): print("Alert: Rain is expected within the next hour!") pygame.mixer.init() pygame.mixer.music.load('voice.wav') pygame.mixer.music.play() while pygame.mixer.music.get_busy(): pygame.time.Clock().tick(10) else: print("No rain expected in the next hour.") else: print("It is currently raining.")
として保存
他で呼び出す時には
api_key = 'APIキー' check_and_alert(api_key)
というように加えればいい
なので
以前作成した kao.pyの中での処理を変更すればOK
その前に
config.iniを作成し
待機時間とAPIキーを記述しておく
とりあえず mail_voiceのものを使うので
cp ../mail_voice/*.xml . cp ../mail_voice/config.ini .
でコピー
config.iniを編集する
[Settings] detection_interval = 1800 #30分 [API_KEYS] OPENWEATHER_API_KEY = APIキー
としておく
次に kao.pyの編集
cp ../mail_voice/kao.py .
の後に編集する
import weather_alert
でインポート
# 設定を変数に格納 api_key = config['API_KEYS']['OPENWEATHER_API_KEY'] detection_interval = int(config['Settings']['detection_interval'])
そして天気の取得処理を追加
if lastTime is None or time.perf_counter() - lastTime > detection_interval: # 検出時刻更新 lastTime = time.perf_counter() weather_alert.check_and_alert(api_key)
とする
これで実行したら
File "/Users/snowpool/aw10s/rain_alert/kao.py", line 12, in <module> detection_interval = int(config['Settings']['detection_interval']) ValueError: invalid literal for int() with base 10: '1800 #30分'
となった
原因はコメント
これが原因でonfig[‘Settings’][‘detection_interval’] の値が 1800 #30分 という文字列であり、これを整数に変換しようとしてエラーが発生していることです。int() 関数は整数に変換できない文字列を受け取るとエラーを発生させます。
問題の原因は、config[‘Settings’][‘detection_interval’] の値が正しい整数値ではなく、その後にコメントが付いているためです。Pythonでは、int() 関数は文字列中の数字のみを整数として解釈します。
とのこと
interval_string = config['Settings']['detection_interval'] interval_without_comment = interval_string.split('#')[0].strip() detection_interval = int(interval_without_comment)
でコメントを消すこともできるらしいが
とりあえず余計なコメントは削除した
これで実行したら
Hello from the pygame community. https://www.pygame.org/contribute.html Traceback (most recent call last): File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/geopy/geocoders/base.py", line 368, in _call_geocoder result = self.adapter.get_json(url, timeout=timeout, headers=req_headers) File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/geopy/adapters.py", line 472, in get_json resp = self._request(url, timeout=timeout, headers=headers) File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/geopy/adapters.py", line 500, in _request raise AdapterHTTPError( geopy.adapters.AdapterHTTPError: Non-successful status code 403 The above exception was the direct cause of the following exception: Traceback (most recent call last): File "/Users/snowpool/aw10s/rain_alert/kao.py", line 41, in <module> weather_alert.check_and_alert(api_key) File "/Users/snowpool/aw10s/rain_alert/weather_alert.py", line 21, in check_and_alert latitude, longitude, _, weather_description = location_utils2.get_current_location_and_address() File "/Users/snowpool/aw10s/rain_alert/location_utils2.py", line 28, in get_current_location_and_address location = geolocator.reverse((latitude, longitude), language='ja') File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/geopy/geocoders/nominatim.py", line 372, in reverse return self._call_geocoder(url, callback, timeout=timeout) File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/geopy/geocoders/base.py", line 388, in _call_geocoder res = self._adapter_error_handler(error) File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/geopy/geocoders/base.py", line 411, in _adapter_error_handler raise exc_cls(str(error)) from error geopy.exc.GeocoderInsufficientPrivileges: Non-successful status code 403
となる
geopy ライブラリがジオコーディングサービスへのアクセスに失敗
が原因とのこと
住所の表示は不要で
緯度経度があれば問題ないため
住所表示機能を削除したら無事に動いた
とりあえず今回もコードを公開するのと同時に
Voicevoxのスクリプトも一緒にリポジトリに入れて公開する