diff --git a/src/alembic/versions/2023_11_18_2152-78f98d411652_.py b/src/alembic/versions/2023_11_18_2152-78f98d411652_.py new file mode 100644 index 0000000..3c1a4ca --- /dev/null +++ b/src/alembic/versions/2023_11_18_2152-78f98d411652_.py @@ -0,0 +1,37 @@ +"""empty message + +Revision ID: 0ea1059c8f7c +Revises: 8bd32b7bb552 +Create Date: 2023-11-18 21:52:58.786979 + +""" +from typing import Sequence, Union + +import sqlalchemy as sa + +from alembic import op + + +# revision identifiers, used by Alembic. +revision: str = "0ea1059c8f7c" +down_revision: Union[str, None] = "8bd32b7bb552" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column("session", sa.Column("created_at", sa.DateTime(), nullable=False)) + op.add_column("session", sa.Column("weather_code", sa.Integer(), nullable=False)) + op.add_column("user", sa.Column("ido_longitude", sa.Float(), nullable=False)) + op.add_column("user", sa.Column("keido_latitude", sa.Float(), nullable=False)) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("user", "keido_latitude") + op.drop_column("user", "ido_longitude") + op.drop_column("session", "weather_code") + op.drop_column("session", "created_at") + # ### end Alembic commands ### diff --git a/src/kb_2315/backend/api/endpoints/calendar.py b/src/kb_2315/backend/api/endpoints/calendar.py index a5c8b89..804369b 100644 --- a/src/kb_2315/backend/api/endpoints/calendar.py +++ b/src/kb_2315/backend/api/endpoints/calendar.py @@ -4,8 +4,9 @@ from fastapi.responses import PlainTextResponse from icalendar import Calendar, Event -from kb_2315.backend.crud import crud_sensor, crud_session, crud_shoe +from kb_2315.backend.crud import crud_session, crud_shoe from kb_2315.backend.models import Session +from kb_2315.backend.weather.code2icon import weather_code2icon router = APIRouter() @@ -14,27 +15,32 @@ @router.get("/") def get_calendar(shoe_id: int | None = None) -> PlainTextResponse: JST = timezone(timedelta(hours=+9), "JST") + sessions: list[Session] = crud_session.search_session_by(shoe_id=shoe_id) - if shoe_id is None: - shoe_name: str = "靴" - sessions: list[Session] = crud_session.search_session_by() - else: - shoe_name = crud_shoe.search_shoe_by(shoe_id=shoe_id)[0].name - sessions = crud_session.search_session_by(shoe_id=shoe_id) + shoe_names: dict[int, str] = {} + + def _search_shoes(shoe_id: int | None) -> str: + if shoe_id is None: + return "靴" + elif shoe_id in shoe_names.keys(): + return shoe_names[shoe_id] + else: + shoe_names[shoe_id] = crud_shoe.search_shoe_by(shoe_id=shoe_id)[0].name + return shoe_names[shoe_id] cal: Calendar = Calendar() - cal["summary"] = f"{shoe_name} の乾燥記録" + cal["summary"] = f"{_search_shoes(shoe_id=shoe_id)} の乾燥記録" cal["scale"] = "GREGORIAN" cal["method"] = "PUBLISH" - cal["X-WR-CALNAME"] = f"{shoe_name} の乾燥記録" + cal["X-WR-CALNAME"] = f"{_search_shoes(shoe_id=shoe_id)} の乾燥記録" cal["X-WR-TIMEZONE"] = "Asia/Tokyo" for s in sessions: try: - last_time: datetime = crud_sensor.search_sensor_by(session_id=s.session_id)[0].time + last_time: datetime = s.created_at e: Event = Event( - SUMMARY=f"{crud_shoe.search_shoe_by(shoe_id= s.shoe_id)[0].name} を履いた", + SUMMARY=f"天気: { weather_code2icon(s.weather_code)}, {_search_shoes(shoe_id=s.shoe_id)} を履いた", DTSTART=datetime( last_time.year, last_time.month, last_time.day, time(7, 0).hour, time(7, 0).minute, tzinfo=JST ) diff --git a/src/kb_2315/backend/api/endpoints/session.py b/src/kb_2315/backend/api/endpoints/session.py index 8eb213c..98d87b5 100644 --- a/src/kb_2315/backend/api/endpoints/session.py +++ b/src/kb_2315/backend/api/endpoints/session.py @@ -3,7 +3,8 @@ from fastapi import APIRouter from kb_2315 import notify -from kb_2315.backend.crud import crud_session +from kb_2315.backend.crud import crud_session, crud_user +from kb_2315.backend.models import User from kb_2315.backend.schemas import schema_session from kb_2315.config import conf @@ -13,9 +14,17 @@ @router.get("/") def create_session(device_id: int) -> schema_session.create_session: - session_id: UUID = crud_session.add_session(device_id=device_id) - - notify.line.send_message(message=f"乾燥を開始しました\n{conf.host_url}/analyze/?session_id={session_id}\n\n靴を選んでください") - notify.line.shoe_select_carousel(session_id=session_id) + user: User = crud_user.search_user_by()[0] + + session_id: UUID = crud_session.add_session(user=user, device_id=device_id) + + notify.line.send_message( + message=f"乾燥を開始しました\n{conf.host_url}/analyze/?session_id={session_id}\n\n靴を選んでください", + send_to_id=user.line_channel_id, + ) + notify.line.shoe_select_carousel( + session_id=session_id, + send_to_id=user.line_channel_id, + ) return schema_session.create_session(session_id=session_id) diff --git a/src/kb_2315/backend/crud/crud_session.py b/src/kb_2315/backend/crud/crud_session.py index d18c393..0b251bd 100644 --- a/src/kb_2315/backend/crud/crud_session.py +++ b/src/kb_2315/backend/crud/crud_session.py @@ -2,17 +2,19 @@ from sqlalchemy.orm import Query -from kb_2315.backend.models import Session +from kb_2315.backend.models import Session, User +from kb_2315.backend.weather import api as weather_api from .base_crud import base_CRUD class CRUD_Session(base_CRUD): - def add_session(self, device_id: int, shoe_id: int | None = None) -> UUID: + def add_session(self, user: User, device_id: int, shoe_id: int | None = None) -> UUID: with self._Session() as session: new_session = Session() new_session.shoe_id = shoe_id new_session.device_id = device_id + new_session.weather_code = weather_api.get_weather_code(user.ido_longitude, user.keido_latitude) session.add(new_session) session.commit() diff --git a/src/kb_2315/backend/models/model_session.py b/src/kb_2315/backend/models/model_session.py index dc08b8f..a32e86e 100644 --- a/src/kb_2315/backend/models/model_session.py +++ b/src/kb_2315/backend/models/model_session.py @@ -1,8 +1,9 @@ import uuid +from datetime import datetime from typing import TYPE_CHECKING from uuid import UUID -from sqlalchemy import ForeignKey, Integer, Uuid +from sqlalchemy import DateTime, ForeignKey, Integer, Uuid from sqlalchemy.orm import Mapped, mapped_column, relationship from kb_2315.backend.db.base import Base @@ -21,4 +22,7 @@ class Session(Base): device_id: Mapped[int] = mapped_column(Integer, nullable=False) shoe_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("shoe.id"), nullable=True) + weather_code: Mapped[int] = mapped_column(Integer, nullable=False) + created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False) + sensors: Mapped[list[Sensor]] = relationship("Sensor", backref="event") diff --git a/src/kb_2315/backend/models/model_user.py b/src/kb_2315/backend/models/model_user.py index ac4d2f9..a15bdbd 100644 --- a/src/kb_2315/backend/models/model_user.py +++ b/src/kb_2315/backend/models/model_user.py @@ -1,4 +1,4 @@ -from sqlalchemy import Integer, String +from sqlalchemy import Float, Integer, String from sqlalchemy.orm import Mapped, mapped_column from kb_2315.backend.db.base import Base @@ -8,3 +8,6 @@ class User(Base): id: Mapped[int] = mapped_column(Integer, primary_key=True) name: Mapped[str] = mapped_column(String, default="Taro") line_channel_id: Mapped[str] = mapped_column(String, nullable=True) + + ido_longitude: Mapped[float] = mapped_column(Float, nullable=False) + keido_latitude: Mapped[float] = mapped_column(Float, nullable=False) diff --git a/src/kb_2315/backend/weather/api.py b/src/kb_2315/backend/weather/api.py new file mode 100644 index 0000000..5f64e5b --- /dev/null +++ b/src/kb_2315/backend/weather/api.py @@ -0,0 +1,15 @@ +import requests + + +def get_weather_code(ido_longitude: float, keido_latitude: float) -> int: + url: str = ( + f"https://api.open-meteo.com/v1/forecast?latitude={ido_longitude}&longitude={keido_latitude}" + "&timezone=Asia%2FTokyo&forecast_days¤t=weather_code" + ) + + try: + r = requests.get(url).json() + return r.get("daily").get("weather_code") + except Exception: + # 困ったら曇り + return 2 diff --git a/src/kb_2315/backend/weather/code2icon.py b/src/kb_2315/backend/weather/code2icon.py new file mode 100644 index 0000000..42b43ac --- /dev/null +++ b/src/kb_2315/backend/weather/code2icon.py @@ -0,0 +1,45 @@ +def weather_code2icon(weather_code: int) -> str: + """ + WMO 天気コードを4分類にする + https://open-meteo.com/en/docs + https://www.jodc.go.jp/data_format/weather-code_j.html#:~:text=%E7%8F%BE%E5%9C%A8%E5%A4%A9%E5%80%99(Present%20Weather)%20(WMO%20Code%204677) + """ + if weather_code in ["0", "1"]: + # 晴れ + return "☀" + + elif weather_code in ["2", "3"]: + # 曇り + return "☁" + + elif weather_code in [ + # 雨 + "45", + "48", + "51", + "53", + "55", + "56", + "57", + "61", + "63", + "65", + "66", + "67", + "80", + "81", + "82", + "95", + "96", + "99", + ]: + return "🌧" + + elif weather_code in ["71", "73", "75", "77", "85", "86"]: + # 雪 + return "🌨" + + # その他 + else: + # その他,曇りとする + return "☁"