背景
RaspberryPiを運用し始めました。
以下のことを実現したい。
・イベントのメール配信
・配信の元ネタはSQLiteDBに登録されているイベント情報
・イベント情報が手動でWebのフォームから登録する
メール配信は、いろいろ調べたが、以下の所でいろいろ引っかかって
- crontabの制限
- サービス環境整備
- タイマー関連
最終構成
- python scheduleを使用
- サービス使用
サービスの中身:
[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
更新したら以下のコマンドを実行し反映させる
$ sudo systemctl daemon-reload
$ sudo systemctl restart job.service
配信用メインPG:
#!/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)
メール送信用:
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接続クラスは一部のみ
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が薬を飲んだことを記録できるようになったらうれしい。