Raspiメモ

### 背景
RaspberryPiを運用し始めました。
以下のことを実現したい。
・イベントのメール配信
・配信の元ネタはSQLiteDBに登録されているイベント情報
・イベント情報が手動でWebのフォームから登録する

メール配信は、いろいろ調べたが、以下の所でいろいろ引っかかって
1. crontabの制限
1. サービス環境整備
1. タイマー関連


### 最終構成
1. python scheduleを使用
1. サービス使用

サービスの中身：
```YML
[Unit]
Description=JOB
After=network.target

[Service]
User=pi
WorkingDirectory=/home/pi/MatplotlibForFlask
Environment="PYTHONPATH=/home/pi/.local/lib/python3.9/site-packages"
ExecStart=/usr/bin/python3 /home/pi/MatplotlibForFlask/without_flask_app.py

[Install]
WantedBy=multi-user.target
```
更新したら以下のコマンドを実行し反映させる
```terminal
$ sudo systemctl daemon-reload
$ sudo systemctl restart job.service
```

配信用メインPG：
```py
#!/usr/bin/env python3
from flask_sqlalchemy import SQLAlchemy
from db_controller import Event_info, db
from flask import Flask
import os
from send_mail import pymail
from datetime import date
import schedule
import time

# 仮想のFlaskアプリケーションコンテキストを作成します。
class DummyApp(Flask):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.config.update({
            'SQLALCHEMY_DATABASE_URI': "sqlite:///" + os.path.join(
            os.getcwd(), "settings", "health_db.db"),
            'SQLALCHEMY_TRACK_MODIFICATIONS': False
        })

# Flask-SQLAlchemyを初期化します。
def initialize_sqlalchemy(app):
    db.init_app(app)

def clean_data(data):
    result = ''
    for d in data:
        # print(d.event_date)
        tmp = '【' + d.event_date.strftime("%Y-%m-%d") + '】\n【' + d.event_name + '】\n【' + d.discription +'】\n\n'
        result = result+tmp
    return result 


# データベースに接続します。
def connect_to_database():
    app = DummyApp(__name__)
    initialize_sqlalchemy(app)
    with app.app_context():
        db.create_all()
        # ここでデータベースを使用した操作を行います。
        res = Event_info.get_today_event()
        r = clean_data(res)
        ins = pymail()
        dt = date.today().strftime("%Y-%m-%d")
        ins.send_mail(f'【{dt}】のイベント情報:', r)


schedule.every().day.at("06:55").do(connect_to_database)

# データベースに接続します。
# connect_to_database()

while True:
    schedule.run_pending()
    time.sleep(1)

```

メール送信用：
```py
import smtplib
from email.mime.text import MIMEText
from settings import Sql_Param

class pymail:
    def __init__(self) -> None:
        self.app_password = Sql_Param.mail_passwd
        self.sender_email = Sql_Param.mail_from
        self.receiver_email = Sql_Param.mail_to

    def send_mail(self, subject, discription):
        #本文
        body = discription
        msg = MIMEText(body)
        #メールの件名
        msg["Subject"]=subject
        #あなたのGmailアドレス
        msg["From"]=self.sender_email
        #メールの送信先
        msg["To"]=self.receiver_email

        # SMTPサーバーに接続してメールを送信
        try:
            smtp_server = smtplib.SMTP_SSL("smtp.gmail.com", 465)
            smtp_server.login(self.sender_email, self.app_password)
            smtp_server.sendmail(self.sender_email, self.receiver_email, msg.as_string())
            smtp_server.quit()
            print("Email sent successfully!")
        except smtplib.SMTPAuthenticationError as e:
            print("SMTP Authentication Error:", e)
        except Exception as e:
            print("An error occurred:", e)

if __name__ == '__main__':
    ins = pymail()
    ins.send_mail('test','test body \n hello world...')
```
DB接続クラスは一部のみ

```py
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime, date, timedelta
from pytz import timezone
from sqlalchemy import case, func, cast, Integer
from werkzeug.security import generate_password_hash
from settings import Sql_Param

db = SQLAlchemy()


# ユーザテーブル定義
class User_info(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    regist_time = db.Column(
        db.DateTime,
        default=datetime.now(timezone("Asia/Tokyo")),
    )
    name = db.Column(db.String(100), nullable=False)
    mail_address = db.Column(db.String(255), unique=True, nullable=False)
    hash_key = db.Column(db.String(255), unique=True, nullable=False)
    is_admin = db.Column(db.Boolean, default=True)

    @classmethod
    def insert_data(cls, request):
        entry = cls(
            name=request.form.get('username'),
            mail_address=request.form.get('mail_address'),
            hash_key=generate_password_hash(request.form.get('password'), salt_length=8)
        )
        db.session.add(entry)
        db.session.commit()
        print("finish insert")
```

### 結論

これで任意のサイクルで任意のタイミングで任意の宛先にRaspberryPiから自動送信が可能となる

今後Line配信も考えている。返信したら、DBデータ更新できるようになったら、便利になる。
応用としては、
システムからメッセージ「薬飲んだ？」
「はい」と返信すると
DBが薬を飲んだことを記録できるようになったらうれしい。