毎朝自動で体温を入力・送信してくれるプログラムを作る【備忘録】

# はじめに
初投稿です。
今回は、学校で毎日GoogleFormsで体温入力等をしないといけなくなって、めんどくｓ....
いや、入力する時間がないので、毎日6:00〜8:30の間にランダムで送信してくれて、しかも体温も36.4~36.6の間のどれかを送信してくれるプログラムを作ってみました。

# 実行環境
- Python3系
- discord.py
- requests
- [テスト用のForms](https://forms.gle/us77kUx2737KNahx7)

# 本題
作成にあたって、[こちら](https://admarimoin.hatenablog.com/entry/2018/11/19/002933)の記事を参考にしながら作りました。
あと、GoogleFormの質問の識別番号の取得は今回は割愛します。

### jsonファイルの作成
`form_url`には、送信をしたFormのURLを入れ、`entry`の中には、取得した質問の識別番号を入れていきます。
質問の数に合わせて、`ans_7`みたいに増やしていってください。
`output`の中には、質問に対する答えを書いていきます。`ans_1`と`ans_4`は毎日値が変わるので適当に値を入れてください。
ここでは、適当に`None`と入れています。


```json:cfg.json

{
    "form_url": "https://docs.google.com/forms/d/e/1FAIpQLSc93lIQ3Aob93cwjx6HSRbuC8V7NT59UfUPhlw6AlkGtZ6CXQ/",
    "entry": {
        "ans_1": 964244932,
        "ans_2": 888214820,
        "ans_3": 23055831,
        "ans_4": 10832147,
        "ans_5": 1720496078,
        "ans_6": 2017707777

    },
    "output":{
        "ans_1": "None",
        "ans_2": "2A",
        "ans_3": "8",
        "ans_4": "None",
        "ans_5": "元気です",
        "ans_6": "いない"
    }
}
```
jsonファイルの作成はこんな感じです。

### メインプログラムの作成
今回は、Discordと連携して、ちゃんと送信されたかなどのログを特定のDiscordチャンネルに送信していきます。
完成したプログラムはこんな感じになっています。

```python:bot.py
# -*- coding: utf-8 -*-
import discord
from discord import Embed
from discord.ext import tasks
from datetime import datetime
import os
import requests
import random
import json

TOKEN = os.environ["TOKEN"]
client = discord.Client(intents=discord.Intents.all())


# 次回送信予定時刻を06:00-8:30までの間でランダムに設定
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)

    setting_time = f"{setting_time_h:02}:{setting_time_m:02}"
    return setting_time


def set_tem():
    choice_list = ["３６．４", "３６．５", "３６．６"]
    choice_ans = random.choice(choice_list)  # 36.4-36.6までの間でランダムに選択
    return choice_ans


time_set = setting_time_set()  # 起動時に初回の次回送信時刻を設定
tem_set = set_tem()


# Embedの関数
async def template_embed(message, title, name_1, name_2, value_1, color, description=None):
    ch = client.get_channel(message)
    embed_time = datetime.now().strftime("%Y年%m月%d日-%H:%M")
    embed = Embed(title=title, description=description, color=color)
    embed.add_field(name=name_1, value=f"{value_1}", inline=True)
    embed.add_field(name=name_2, value=f"{tem_set}", inline=True)
    embed.set_footer(text=f"{embed_time}")
    await ch.send("<@ユーザーID>")
    await ch.send(embed=embed)


@client.event
async def on_ready():
    await template_embed(message=768274673984208926, title="起動ログ", name_1="次回の送信予定時刻", value_1=time_set,
                         name_2="送信予定の体温", color=discord.Color.orange())


@client.event
async def on_message(message):
    if message.content == "/reset":
        await reset(message)

    if message.content == "/now":
        await now(message)


async def reset(message):
    global time_set
    global tem_set

    time_set = setting_time_set()
    tem_set = set_tem()

    await template_embed(message=768274673984208926, title="リセットされました", name_1="次回の送信予定時刻", name_2="送信予定の体温",
                         value_1=time_set, color=discord.Color.purple())
    await template_embed(message=message.channel.id, title="リセットされました",  name_1="次回の送信予定時刻", name_2="送信予定の体温",
                         value_1=time_set, color=discord.Color.purple())


async def now(message):
    await template_embed(message=message.channel.id, title="現在の状況", name_1="次回の送信予定時刻", name_2="送信予定の体温",
                         value_1=time_set, color=discord.Color.greyple())


@tasks.loop(seconds=60)
async def loop():
    global time_set
    global tem_set

    now_t = datetime.now().strftime('%H:%M')
    print(f"現在の時刻：{now_t}／送信予定時刻：{time_set}／送信予定体温：{tem_set}")

    if now_t == time_set:  # 送信予定時刻になった？
        dt_now = datetime.now().strftime("%Y-%m-%d")  # 現在時刻を2020-01-01の形で取得、dt_nowに格納

        file_name = "cfg.json"
        with open(file_name, "r", encoding="utf-8")as f:
            cfg = json.load(f)
            cfg["output"]["ans_1"] = f"{dt_now}"
            cfg["output"]["ans_4"] = f"{tem_set}"

            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:
            await template_embed(message=768274673984208926, title="ログ情報", description=f"[URL]({res.url})",
                                 name_1="完了状態", name_2="送信された体温", value_1="成功しました", color=discord.Color.green())
        else:
            res.raise_for_status()
            await template_embed(message=768274673984208926, title="ログ情報", name_1="完了状態", name_2="送信予定だった体温",
                                 value_1="エラーが発生しました。", color=discord.Color.red())

    else:
        if now_t == "21:00":
            time_set = setting_time_set()
            tem_set = set_tem()
            await template_embed(message=768274673984208926, title="送信時刻更新のお知らせ", name_1="次回の送信予定時刻", name_2="送信予定の体温",
                                 value_1=time_set, color=discord.Color.blue())


loop.start()
client.run(TOKEN)
```


順を追って説明していきます。
まずは、この部分ですが、送信時間を6:00~8:30の間でランダムに発行して`setting_time`にreturnし、その後体温をランダムに選んで`choice_ans`にreturnしています。
その下の処理は、初回起動時に送信時刻と体温を設定しています。更にその下の処理は、Embedの生成処理を行っています。

```python
# 次回送信予定時刻を06:00-8:30までの間でランダムに設定
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)

    setting_time = f"{setting_time_h:02}:{setting_time_m:02}"
    return setting_time


def set_tem():
    choice_list = ["３６．４", "３６．５", "３６．６"]
    choice_ans = random.choice(choice_list)  # 36.4-36.6までの間でランダムに選択
    return choice_ans


time_set = setting_time_set()  # 起動時に初回の次回送信時刻を設定
tem_set = set_tem()


# Embedの関数
async def template_embed(message, title, name_1, name_2, value_1, color, description=None):
    ch = client.get_channel(message)
    embed_time = datetime.now().strftime("%Y年%m月%d日-%H:%M")
    embed = Embed(title=title, description=description, color=color)
    embed.add_field(name=name_1, value=f"{value_1}", inline=True)
    embed.add_field(name=name_2, value=f"{tem_set}", inline=True)
    embed.set_footer(text=f"{embed_time}")
    await ch.send("<@ユーザーID>")
    await ch.send(embed=embed)
```

### 次に
メイン処理の方を解説していきます。

```py

@client.event
async def on_ready():
    await template_embed(message=768274673984208926, title="起動ログ", name_1="次回の送信予定時刻", value_1=time_set,
                         name_2="送信予定の体温", color=discord.Color.orange())
```
起動時に、特定のチャンネルに起動ログを送信していきます。

```py
@client.event
async def on_message(message):
    if message.content == "/reset":
        await reset(message)

    if message.content == "/now":
        await now(message)


async def reset(message):
    global time_set
    global tem_set

    time_set = setting_time_set()
    tem_set = set_tem()

    await template_embed(message=768274673984208926, title="リセットされました", name_1="次回の送信予定時刻", name_2="送信予定の体温",
                         value_1=time_set, color=discord.Color.purple())
    await template_embed(message=message.channel.id, title="リセットされました",  name_1="次回の送信予定時刻", name_2="送信予定の体温",
                         value_1=time_set, color=discord.Color.purple())


async def now(message):
    await template_embed(message=message.channel.id, title="現在の状況", name_1="次回の送信予定時刻", name_2="送信予定の体温",
                         value_1=time_set, color=discord.Color.greyple())
```
ここでは、送信時間と体温をリセットできるリセットコマンドと、現在の状態を確認できるコマンドの処理です。

```py
@tasks.loop(seconds=60)
async def loop():
    global time_set
    global tem_set

    now_t = datetime.now().strftime('%H:%M')  # 現在時刻を取得
    print(f"現在の時刻：{now_t}／送信予定時刻：{time_set}／送信予定体温：{tem_set}")

    if now_t == time_set:  # 送信予定時刻になった？
        dt_now = datetime.now().strftime("%Y-%m-%d")  # 現在時刻を2020-01-01の形で取得、dt_nowに格納

        file_name = "cfg.json"
        with open(file_name, "r", encoding="utf-8")as f:
            cfg = json.load(f)
            cfg["output"]["ans_1"] = f"{dt_now}"  # 今日の年、月、日をans_1に上書き
            cfg["output"]["ans_4"] = f"{tem_set}"  # 体温をans_4に上書き

            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:  # 正常に送信された場合
            await template_embed(message=768274673984208926, title="ログ情報", description=f"[URL]({res.url})",
                                 name_1="完了状態", name_2="送信された体温", value_1="成功しました", color=discord.Color.green())
        else:  # 送信できなかった場合
            res.raise_for_status()
            await template_embed(message=768274673984208926, title="ログ情報", name_1="完了状態", name_2="送信予定だった体温",
                                 value_1="エラーが発生しました。", color=discord.Color.red())

    else:
        if now_t == "21:00":
            time_set = setting_time_set()
            tem_set = set_tem()
            await template_embed(message=768274673984208926, title="送信時刻更新のお知らせ", name_1="次回の送信予定時刻", name_2="送信予定の体温",
                                 value_1=time_set, color=discord.Color.blue())
```
ここでは、`tasks.loop()`を使用して60秒間隔に現在時刻と送信予定時刻の確認を行い、一致したら送信処理を行っています。
そして、一致しなかった場合は、現在時刻とリセット時刻が一致しているかを確認し、リセット時刻であればリセット処理をしています。

# 最後に

初投稿というのもあり、かなりグダグダですが、ご了承ください。
完成したコードは、[Github](https://github.com/MistyScene/AutoForms)に上げているので、使用する際はご自由に....
最後の方、かなり解説を省略したんですが、参考になれば幸いです。

※完全にネタ投稿です。実際に実行させるかさせないかは自己責任でお願いします。それによって先生に怒られたとしても責任は負いません。

# 参考
[Google Form自動回答Botでクソアンケートに勝つ(Python3)](https://admarimoin.hatenablog.com/entry/2018/11/19/002933)