iTranslated by AI
[Automation Project #1] Automating Daily Body Temperature Log Submission
This is my first article, so the content might be a bit rough, but please bear with me.
As part one of my automation project, I've decided to automate the task of submitting my daily body temperature via Google Forms for school. It’s incredibly tedious, so I’m going to automate it. (Don't worry, I am actually measuring my temperature!)
Environment
Language: Python 3.8 series
OS: Windows 10 (Development) / Ubuntu 20.04LTS (Execution)
Editor: PyCharm
File Structure
/Auto-Google-Forms
├ bot.py / Main code
└ cfg.json / Configuration file
Main Topic
Entire Code
# -*- 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 # Specify the channel ID where you want to send logs
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="Log Info", description=f"[URL]({res.url})", color=Colour.green())
em.add_field(name="Temperature Info", 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="Log Info", description="Could not send successfully.", color=Colour.red())
em.add_field(name="Temperature Info", 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="Startup Log", color=Colour.orange())
em.add_field(name="Next scheduled send time", value=f"{sts}")
em.add_field(name="Temperature to be sent", 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}-> Send complete")
@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="Notice: Send Time Updated", color=Colour.blue())
em.add_field(name="Next scheduled send time", value=sts)
em.add_field(name="Temperature to be sent", 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'])
It's going to be very rough, but I'll break it down and explain it in sections.
First, the imports. I've added comments to describe what each library is for.
import json # Library for handling JSON files (in this case, cfg.json)
import os.path # Library used for specifying file paths
import random # Library used for randomly choosing the body temperature later
from datetime import datetime as dt # Library used for determining the send time
import requests # Library used for sending requests to Google Forms
from discord import Client, Embed, Colour # Library for using Discord
from discord.ext import tasks # Library related to discord.py
from dotenv import load_dotenv # Library used for loading environment variables from a file
Next.
client = Client() # Standard boilerplate
ch = CHANNEL_ID # Specify the channel ID where you want to send logs
load_dotenv() # Load and apply environment variables from the configuration file
From here, I will explain properly.
This function generates a specific transmission time randomly and returns it.
In this case, it is set between 6:00 and 8:30, and I've used an if statement to restrict the minutes to 0-30 only when the hour is 8.
Also, the :02 in return str(f"{setting_time_h:02}:{setting_time_m:02}") is used to pad single digits with a leading zero to ensure they are two digits, making subsequent processing easier.
ex) 9 → 09 / 3 → 03
def setting_time_set():
setting_time_h = random.randint(6, 8) # Randomly select between 6 and 8
if setting_time_h == 8: # Handle the case for 8
setting_time_m = random.randint(0, 30) # Set between 0 and 30
else: # For other hours
setting_time_m = random.randint(0, 59) # Set between 0 and 59
return str(f"{setting_time_h:02}:{setting_time_m:02}")
This part is pretty straightforward.
It just randomly picks a temperature for the submission.
def body_temperature_set():
return random.choice(["36.4", "36.5", "36.6"])
Next.
It wouldn't be an exaggeration to say this is the main part of the program.
I'll explain it to some extent, and for the rest, I'll add comments.
I wrote this quite a while ago, so there are many parts I don't fully understand myself, but please bear with me.
async def send(bts):
setting_file_path = "/home/seiwell/DiscordBot/Auto-Google-Forms/cfg.json" # Specify the configuration file path
with open(setting_file_path, "r", encoding="utf-8")as f: # Open the file
cfg = json.load(f) # Load the JSON file
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()} # Try your best to decipher this.
res = requests.get(cfg["form_url"] + "formResponse", params=params) # Send
if res.status_code == 200: # If sent successfully, send to a specific Discord channel
em = Embed(title="Log Info", description=f"[URL]({res.url})", color=Colour.green())
em.add_field(name="Temperature Info", 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: # If some error occurs
res.raise_for_status()
em = Embed(title="Log Info", description="Could not send successfully.", color=Colour.red())
em.add_field(name="Temperature Info", 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() # I don't even know why I'm putting this in a variable here.
bts = body_temperature_set()
I'll explain these parts together.
When the program runs, it notifies a specific Discord channel of the next scheduled send time and temperature.
The next part is something I made so I could send it immediately with a command if I wanted to, but I've actually never used it even once...
@client.event
async def on_ready():
em = Embed(title="Startup Log", color=Colour.orange())
em.add_field(name="Next scheduled send date/time", value=f"{sts}")
em.add_field(name="Temperature to be sent", 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}-> Send complete")
Next is the second most important part.
Here, I use tasks.loop() to check every 60 seconds whether it's the send time or the reset time.
@tasks.loop(seconds=60)
async def loop():
global sts, bts
now_time = dt.now().strftime('%H:%M')
if now_time == "21:00": # Reset time check
sts = setting_time_set() # Reset process
bts = body_temperature_set() # Reset process
em = Embed(title="Notice: Send Time Updated", color=Colour.blue())
em.add_field(name="Next scheduled send time", value=sts)
em.add_field(name="Temperature to be sent", 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 if it's neither send time nor reset time
return
await send(bts=bts) # Otherwise
loop.start() # Start the loop process
client.run(os.environ['TOKEN']) # Start the Discord Bot
Conclusion
What did you think? I tried to explain it without going too deep or staying too shallow.
I know the code is quite messy, but I hope you'll overlook that...
References
Winning against crappy surveys with a Google Form auto-responder Bot (Python3)
Discussion