🔖

【自動化計画#1】毎朝の体温入力を自動化してみる。

2021/07/17に公開

この記事が初めて書くので、色々と内容が粗いですがご了承あれ。

自動化計画其の一ということで、学校で毎朝体温をGoogleFormsに入力して、送信しなければいけなくなってしまい、超絶面倒くさいので、自動化しようと思います。(ちゃんと体温は計ってますよ?)

環境

言語:Python 3.8系
OS:Windows10(作成環境)/Ubuntu 20.04LTS(実行環境)
エディタ:Pycharm

ファイル構成

/Auto-Google-Forms
├ bot.py/メインコード
└ cfg.json/設定ファイル

本題

コード全体
main.py
# -*- coding: utf-8 -*-

import json
import os.path
import random
from datetime import datetime as dt

import requests
from discord import Client, Embed, Colour
from discord.ext import tasks
from dotenv import load_dotenv

client = Client()
ch = CHANNEL_ID #  ログを送信したいチャンネルIDを指定
load_dotenv()


def setting_time_set():
    setting_time_h = random.randint(6, 8)
    if setting_time_h == 8:
        setting_time_m = random.randint(0, 30)
    else:
        setting_time_m = random.randint(0, 59)

    return str(f"{setting_time_h:02}:{setting_time_m:02}")


def body_temperature_set():
    return random.choice(["36.4", "36.5", "36.6"])


async def send(bts):
    setting_file_path = "/home/seiwell/DiscordBot/Auto-Google-Forms/cfg.json"
    with open(setting_file_path, "r", encoding="utf-8")as f:
        cfg = json.load(f)
        cfg["output"]["ans_1"] = f"{dt.now().strftime('%Y-%m-%d')}"

        cfg["output"]["ans_3"] = f"{bts}"

        params = {"entry.{}".format(cfg["entry"][k]): cfg["output"][k] for k in cfg["entry"].keys()}
        res = requests.get(cfg["form_url"] + "formResponse", params=params)

        if res.status_code == 200:
            em = Embed(title="ログ情報", description=f"[URL]({res.url})", color=Colour.green())
            em.add_field(name="体温情報", value=bts)
            em.set_footer(text=f'{dt.now().strftime("%Y年%m月%d日-%H:%M")}')
            await client.get_channel(ch).send("<@343956207754805251>")
            await client.get_channel(ch).send(embed=em)

        else:
            res.raise_for_status()
            em = Embed(title="ログ情報", description="正常に送信できませんでした。", color=Colour.red())
            em.add_field(name="体温情報", value=bts)
            em.set_footer(text=f'{dt.now().strftime("%Y年%m月%d日-%H:%M")}')
            await client.get_channel(ch).send("<@343956207754805251>")
            await client.get_channel(ch).send(embed=em)

sts = setting_time_set()
bts = body_temperature_set()


@client.event
async def on_ready():
    em = Embed(title="起動ログ", color=Colour.orange())
    em.add_field(name="次回の送信予定日時", value=f"{sts}")
    em.add_field(name="送信予定の体温", value=f"{bts}")
    em.set_footer(text=f'{dt.now().strftime("%Y年%m月%d日-%H:%M")}')
    await client.get_channel(ch).send("<@343956207754805251>")
    await client.get_channel(ch).send(embed=em)


@client.event
async def on_message(message):
    if message.content == "/now_send":
        await send(bts=body_temperature_set())
        await message.channel.send(f"{message.author.mention}-> 送信完了")


@tasks.loop(seconds=60)
async def loop():
    global sts, bts

    now_time = dt.now().strftime('%H:%M')

    if now_time == "21:00":
        sts = setting_time_set()
        bts = body_temperature_set()

        em = Embed(title="送信時刻更新のお知らせ", color=Colour.blue())
        em.add_field(name="次回の送信予定時刻", value=sts)
        em.add_field(name="送信予定の体温", value=bts)
        em.set_footer(text=f'{dt.now().strftime("%Y年%m月%d日-%H:%M")}')
        await client.get_channel(ch).send("<@343956207754805251>")
        await client.get_channel(ch).send(embed=em)
        return

    elif now_time != sts:
        return

    await send(bts=bts)


loop.start()
client.run(os.environ['TOKEN'])

めちゃめちゃ粗削りになりますがある程度分割して解説していきます。

まずは、import関連。コメントアウトでなんのライブラリかを記載しておきます。

import json  # jsonファイル(今回はcfg.json)を扱うためのライブラリ
import os.path  # ファイルのpathを指定する際に使うライブリ
import random  # 後に出てくる体温をランダムで選ぶときに使うライブラリ
from datetime import datetime as dt  # 送信時間を決定する際に使うライブラリ

import requests  # GoogleFormsで送信を行うときに使うライブラリ
from discord import Client, Embed, Colour  # discordを使うために使うライブラリ
from discord.ext import tasks  # discord.pyに関連したライブラリ
from dotenv import load_dotenv  # 環境変数をファイルから読み込む際に使うライブラリ

次。

client = Client()  # おまじない
ch = CHANNEL_ID #  ログを送信したいチャンネルIDを指定
load_dotenv()  # 環境変数の設定ファイルを読み込み、反映

ここからは、ちゃんと解説します。
この関数は、特定の送信時間をランダムで生成し、returnする関数となっています。
この場合、6:00〜8:30までに設定しており、8の場合だけ、0〜30になるようにifで8だけを弾いています。
また、return str(f"{setting_time_h:02}:{setting_time_m:02}"):02と書いてあるのは、一桁の場合は0詰めして二桁に調整し、後々処理が楽になるようにしています。
ex) 9 → 09/ 3 → 03

def setting_time_set():
    setting_time_h = random.randint(6, 8)  # 6〜8でランダムで選択
    if setting_time_h == 8:  # 8の場合だけ弾く
        setting_time_m = random.randint(0, 30)  # 0〜30にする
    else:  # それ以外
        setting_time_m = random.randint(0, 59)  # 0〜59にする

    return str(f"{setting_time_h:02}:{setting_time_m:02}")

ここらへんはそのまんまですね。
ランダムで送信時のランダムを選んでいるだけです。

def body_temperature_set():
    return random.choice(["36.4", "36.5", "36.6"])

次。
メインのプログラムといっても過言ではないです。
ある程度、解説しますが、それ以外はコメントに記載していきます。
作ったのが結構前なので、自分でもよくわかっていない部分が多々ありますがご了承あれ。

async def send(bts):
    setting_file_path = "/home/seiwell/DiscordBot/Auto-Google-Forms/cfg.json"  # 設定ファイルのpathを指定
    with open(setting_file_path, "r", encoding="utf-8")as f:  # ファイルを開く
        cfg = json.load(f)  # jsonファイルの読み込み
        cfg["output"]["ans_1"] = f"{dt.now().strftime('%Y-%m-%d')}"

        cfg["output"]["ans_3"] = f"{bts}"

        params = {"entry.{}".format(cfg["entry"][k]): cfg["output"][k] for k in cfg["entry"].keys()}  # 頑張って解読してみてね。
        res = requests.get(cfg["form_url"] + "formResponse", params=params)  # 送信

        if res.status_code == 200:  # 送信ができた場合、discordの特定のチャンネルに送信
            em = Embed(title="ログ情報", description=f"[URL]({res.url})", color=Colour.green())
            em.add_field(name="体温情報", value=bts)
            em.set_footer(text=f'{dt.now().strftime("%Y年%m月%d日-%H:%M")}')
            await client.get_channel(ch).send("<@343956207754805251>")
            await client.get_channel(ch).send(embed=em)

        else:  # 何らかのエラーが起きた場合
            res.raise_for_status()
            em = Embed(title="ログ情報", description="正常に送信できませんでした。", color=Colour.red())
            em.add_field(name="体温情報", value=bts)
            em.set_footer(text=f'{dt.now().strftime("%Y年%m月%d日-%H:%M")}')
            await client.get_channel(ch).send("<@343956207754805251>")
            await client.get_channel(ch).send(embed=em)

sts = setting_time_set()   # なんでここで変数に入れてるのか自分でもわからん。
bts = body_temperature_set()

ここは、まとめて説明していきます。
プログラム実行時に、discordの特定のチャンネルに、次回の送信時刻と体温を通知しています、
その次は、すぐに送信したいときに、コマンドで一発で送信されるようにしたやつですが、今まで一回も使ったことないです…

@client.event
async def on_ready():
    em = Embed(title="起動ログ", color=Colour.orange())
    em.add_field(name="次回の送信予定日時", value=f"{sts}")
    em.add_field(name="送信予定の体温", value=f"{bts}")
    em.set_footer(text=f'{dt.now().strftime("%Y年%m月%d日-%H:%M")}')
    await client.get_channel(ch).send("<@343956207754805251>")
    await client.get_channel(ch).send(embed=em)


@client.event
async def on_message(message):
    if message.content == "/now_send":
        await send(bts=body_temperature_set())
        await message.channel.send(f"{message.author.mention}-> 送信完了")

次は、二番目に重要ですね。
ここでは、tasks.loop()を使って、60秒間隔で、送信時刻&リセット時刻かを確認しています。

@tasks.loop(seconds=60)
async def loop():
    global sts, bts

    now_time = dt.now().strftime('%H:%M')

    if now_time == "21:00":  # リセット時刻の判定
        sts = setting_time_set()  # リセット処理
        bts = body_temperature_set()  # リセット処理

        em = Embed(title="送信時刻更新のお知らせ", color=Colour.blue())
        em.add_field(name="次回の送信予定時刻", value=sts)
        em.add_field(name="送信予定の体温", value=bts)
        em.set_footer(text=f'{dt.now().strftime("%Y年%m月%d日-%H:%M")}')
        await client.get_channel(ch).send("<@343956207754805251>")
        await client.get_channel(ch).send(embed=em)
        return

    elif now_time != sts:  # 送信時刻でもリセット時刻でもない場合はreturn
        return

    await send(bts=bts)  # それ以外


loop.start()  # ループ処理を開始
client.run(os.environ['TOKEN'])  # DiscordBotの起動

最後に

いかがでしたでしょうか。深くもなく浅すぎずもなく解説してみました。
結構、汚いコードだとは思いますが、そこはご愛嬌ということで。。。

参考

Google Form自動回答Botでクソアンケートに勝つ(Python3)

Discussion