Spaces:
Running
Running
| import time | |
| import requests | |
| import os | |
| import json | |
| from datetime import datetime, timedelta | |
| from zoneinfo import ZoneInfo | |
| BASE_URL = "https://desk-api.channel.io/desk/channels/227312" | |
| TARGET_GROUP_CHAT_ID = "536135" | |
| HEADERS = { | |
| "accept-language": "ja", | |
| "x-account": os.getenv("dmsendertoken") | |
| } | |
| JST = ZoneInfo("Asia/Tokyo") | |
| # ---------------- 天気コード ---------------- | |
| WEATHER_CODE_MAP = { | |
| 0: "☀️晴れ", | |
| 1: "☁️曇り", | |
| 2: "吹雪", | |
| 3: "砂嵐", | |
| 4: "🌫️霧", | |
| 5: "🌫️霧雨", | |
| 6: "🌧️雨", | |
| 7: "🌨️雪", | |
| 8: "🌦️シャワー", | |
| 9: "⛈️雷雨", | |
| } | |
| def format_weather_code(code: int) -> str: | |
| if code < 10: | |
| return WEATHER_CODE_MAP.get(code, str(code)) | |
| main = code // 10 | |
| sub = code % 10 | |
| main_str = WEATHER_CODE_MAP.get(main) | |
| sub_str = WEATHER_CODE_MAP.get(sub) | |
| if main_str and sub_str: | |
| return f"{main_str}、{sub_str}" | |
| return str(code) | |
| # ---------------- Channel 投稿 ---------------- | |
| def post_group_message(chat_id, body): | |
| url = f"{BASE_URL}/groups/{chat_id}/messages" | |
| r = requests.post(url, headers=HEADERS, json=body) | |
| r.raise_for_status() | |
| return r.json() | |
| # ---------------- 時報 ---------------- | |
| def create_time_signal_body(): | |
| now = datetime.now(JST) | |
| hour = now.hour | |
| if hour < 12: | |
| period = "午前" | |
| display_hour = hour if hour != 0 else 12 | |
| else: | |
| period = "午後" | |
| display_hour = hour - 12 if hour > 12 else 12 | |
| message = f"<b>時報</b>\n{period}{display_hour}時をお知らせします。" | |
| return { | |
| "requestId": f"desk-web-time-signal-{int(time.time())}", | |
| "blocks": [{"type": "text", "value": message}], | |
| } | |
| # ---------------- 天気予報 ---------------- | |
| def load_todoufuken(): | |
| with open("todoufuken.json", encoding="utf-8") as f: | |
| return json.load(f) | |
| def fetch_weather(todoufuken): | |
| lats = ",".join(str(p["lat"]) for p in todoufuken) | |
| lons = ",".join(str(p["lon"]) for p in todoufuken) | |
| url = ( | |
| "https://api.open-meteo.com/v1/forecast" | |
| f"?latitude={lats}" | |
| f"&longitude={lons}" | |
| "&hourly=relative_humidity_2m,apparent_temperature,temperature_2m," | |
| "precipitation_probability,weather_code" | |
| "&forecast_days=1" | |
| ) | |
| r = requests.get(url) | |
| r.raise_for_status() | |
| return r.json() | |
| def create_weather_body(): | |
| now = datetime.now(JST) | |
| today_7am = now.replace(hour=7, minute=0, second=0, microsecond=0) | |
| todoufuken = load_todoufuken() | |
| data = fetch_weather(todoufuken) | |
| lines = ["<b>☀️ 本日の天気予報(7時以降・1時間ごと)</b>"] | |
| for idx, pref in enumerate(todoufuken): | |
| hourly = data[idx]["hourly"] | |
| times = hourly["time"] | |
| lines.append(f"\n<b>{pref['name']}:</b>") | |
| for i, t in enumerate(times): | |
| t_jst = ( | |
| datetime.fromisoformat(t) | |
| .replace(tzinfo=ZoneInfo("UTC")) | |
| .astimezone(JST) | |
| ) | |
| if t_jst < today_7am: | |
| continue | |
| wc = hourly["weather_code"][i] | |
| at = hourly["apparent_temperature"][i] | |
| temp = hourly["temperature_2m"][i] | |
| pop = hourly["precipitation_probability"][i] | |
| rh = hourly["relative_humidity_2m"][i] | |
| wc_str = format_weather_code(wc) | |
| line = ( | |
| f" {t_jst.strftime('%H時')}:" | |
| f"{wc_str} " | |
| f"{at}℃ {temp}℃ {pop}% {rh}%" | |
| ) | |
| lines.append(line) | |
| return { | |
| "requestId": f"desk-web-weather-{int(time.time())}", | |
| "blocks": [{"type": "text", "value": "\n".join(lines)}], | |
| } | |
| # ---------------- メインループ ---------------- | |
| def main_loop(): | |
| while True: | |
| try: | |
| now = datetime.now(JST) | |
| # 毎正時の時報 | |
| if now.minute == 0: | |
| body = create_time_signal_body() | |
| post_group_message(TARGET_GROUP_CHAT_ID, body) | |
| # 午後2時9分に天気予報 | |
| if now.hour == 14 and now.minute == 20: | |
| body = create_weather_body() | |
| post_group_message(TARGET_GROUP_CHAT_ID, body) | |
| time.sleep(60) | |
| except Exception as e: | |
| print("Error:", e) | |
| time.sleep(10) | |
| if __name__ == "__main__": | |
| main_loop() |